1- import * as React from 'react' ;
2- import { useRef , useState } from 'react' ;
3-
4- export type DropdownProps = {
5- /** Extra class name to add to dropdown frame */
6- className ?: string ;
7- headerClassName ?: string ;
8- /** Element(s) to show in the drop-down element (only visible when expanded). */
9- children : React . ReactNode ;
10- /** Text to show in the text field (always visible). */
11- text : string ;
12- form ?: boolean ;
13- } ;
1+ import { DropdownFrameProps , DropdownProps , DropdownRowProps } from 'flashpoint-launcher-renderer' ;
2+ import React , { Activity , useEffect , useMemo , useRef , useState } from 'react' ;
143
154// A text element, with a drop-down element that can be shown/hidden.
16- export function Dropdown ( props : DropdownProps ) {
5+ export function DropdownFrame ( { children , form , text , className , headerClassName } : DropdownFrameProps ) {
176 // Hooks
187 const [ expanded , setExpanded ] = useState < boolean > ( false ) ;
198 const dropdownRef = useRef < HTMLDivElement > ( null ) ;
@@ -29,39 +18,137 @@ export function Dropdown(props: DropdownProps) {
2918 }
3019 } ;
3120
32- React . useEffect ( ( ) => {
21+ useEffect ( ( ) => {
3322 // Add event listener to handle clicks outside the dropdown
3423 document . addEventListener ( 'mousedown' , handleClickOutside ) ;
3524
3625 // Cleanup the event listener on component unmount
3726 return ( ) => {
3827 document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
3928 } ;
40- } ) ;
29+ } , [ ] ) ;
4130
42- const baseClass = props . form ? 'simple-dropdown-form' : 'simple-dropdown' ;
31+ const baseClass = form ? 'simple-dropdown-form' : 'simple-dropdown' ;
4332
4433 // Render
4534 return (
4635 < div
47- className = { `${ baseClass } ${ props . className } ` }
36+ className = { `${ baseClass } ${ className } ` }
4837 onClick = { onToggleExpanded } >
4938 < div
50- className = { `${ baseClass } __select-box ${ props . headerClassName } ` }
39+ className = { `${ baseClass } __select-box ${ headerClassName } ` }
5140 tabIndex = { 0 } >
5241 < div className = { `${ baseClass } __select-text` } >
53- { props . text }
42+ { text }
5443 </ div >
5544 < div className = { `${ baseClass } __select-icon` } />
5645 </ div >
5746 < div
5847 className = { `${ baseClass } __content` + ( expanded ? '' : ` ${ baseClass } __content--hidden` ) }
5948 ref = { dropdownRef }
6049 onClick = { ( e ) => e . stopPropagation ( ) } >
61- { expanded && (
62- props . children
63- ) }
50+ < Activity mode = { expanded ? 'visible' : 'hidden' } >
51+ { children }
52+ </ Activity >
6453 </ div >
6554 </ div >
6655 ) ;
6756}
57+
58+ // A text element, with a drop-down element that can be shown/hidden.
59+ export function Dropdown < T > ( { rowCount, rowRenderer : RowRenderer , rowProps, form, text, className, headerClassName } : DropdownProps < T > ) {
60+ // Hooks
61+ const [ expanded , setExpanded ] = useState < boolean > ( false ) ;
62+ const dropdownRef = useRef < HTMLDivElement > ( null ) ;
63+
64+ const onToggleExpanded = ( ) => {
65+ setExpanded ( ! expanded ) ;
66+ } ;
67+
68+ // Close dropdown when clicking outside of it
69+ const handleClickOutside = ( event : any ) => {
70+ if ( dropdownRef . current && ! dropdownRef . current . contains ( event . target ) ) {
71+ setExpanded ( false ) ;
72+ }
73+ } ;
74+
75+ useEffect ( ( ) => {
76+ // Add event listener to handle clicks outside the dropdown
77+ document . addEventListener ( 'mousedown' , handleClickOutside ) ;
78+
79+ // Cleanup the event listener on component unmount
80+ return ( ) => {
81+ document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
82+ } ;
83+ } , [ ] ) ;
84+
85+ const baseClass = form ? 'simple-dropdown-form' : 'simple-dropdown' ;
86+
87+ const rows = useMemo ( ( ) => {
88+ const rows = [ ] ;
89+ for ( let i = 0 ; i < rowCount ; i ++ ) {
90+ rows . push (
91+ < RowRenderer key = { i } index = { i } { ...rowProps } />
92+ ) ;
93+ }
94+ return rows ;
95+ } , [ RowRenderer , rowCount , rowProps ] ) ;
96+
97+ // Render
98+ return (
99+ < div
100+ className = { `${ baseClass } ${ className } ` }
101+ onClick = { onToggleExpanded } >
102+ < div
103+ className = { `${ baseClass } __select-box ${ headerClassName } ` }
104+ tabIndex = { 0 } >
105+ < div className = { `${ baseClass } __select-text` } >
106+ { text }
107+ </ div >
108+ < div className = { `${ baseClass } __select-icon` } />
109+ </ div >
110+ < div
111+ className = { `${ baseClass } __content` + ( expanded ? '' : ` ${ baseClass } __content--hidden` ) }
112+ ref = { dropdownRef }
113+ onClick = { ( e ) => e . stopPropagation ( ) } >
114+ < Activity mode = { expanded ? 'visible' : 'hidden' } >
115+ { rows }
116+ </ Activity >
117+ </ div >
118+ </ div >
119+ ) ;
120+ }
121+
122+ export type DropdownCheckboxRowProps < T > = {
123+ labels : T [ ] ,
124+ labelRenderer ?: ( props : { label : T , index : number } ) => React . JSX . Element ;
125+ onToggle : ( index : number ) => void ;
126+ isChecked : ( index : number ) => boolean ;
127+ }
128+
129+ export function DropdownCheckboxRow < T > ( {
130+ labels, labelRenderer : LabelRenderer , onToggle, isChecked, index
131+ } : DropdownRowProps < DropdownCheckboxRowProps < T > > ) {
132+ const label = labels [ index ] ;
133+
134+ return (
135+ < label
136+ key = { index }
137+ className = 'log-page__dropdown-item' >
138+ < div className = 'simple-center' >
139+ < input
140+ type = 'checkbox'
141+ checked = { isChecked ( index ) }
142+ onChange = { ( ) => onToggle ( index ) }
143+ className = 'simple-center__vertical-inner' />
144+ </ div >
145+ < div className = 'simple-center' >
146+ < p className = 'simple-center__vertical-inner log-page__dropdown-item-text' >
147+ { LabelRenderer ?
148+ < LabelRenderer label = { label } index = { index } /> :
149+ String ( label ) }
150+ </ p >
151+ </ div >
152+ </ label >
153+ ) ;
154+ }
0 commit comments