@lmb-it/kitsconcerto-native 0.1.256 → 0.1.258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/apps/mobile/src/Core/Dropdown/index.cjs +64 -23
  2. package/apps/mobile/src/Core/Dropdown/index.cjs.map +1 -1
  3. package/apps/mobile/src/Core/Dropdown/index.js +66 -25
  4. package/apps/mobile/src/Core/Dropdown/index.js.map +1 -1
  5. package/apps/mobile/src/Core/Dropdown/panelGeometry.cjs +43 -0
  6. package/apps/mobile/src/Core/Dropdown/panelGeometry.cjs.map +1 -0
  7. package/apps/mobile/src/Core/Dropdown/panelGeometry.js +38 -0
  8. package/apps/mobile/src/Core/Dropdown/panelGeometry.js.map +1 -0
  9. package/apps/mobile/src/Core/MultiSelect/index.cjs +21 -2
  10. package/apps/mobile/src/Core/MultiSelect/index.cjs.map +1 -1
  11. package/apps/mobile/src/Core/MultiSelect/index.js +21 -2
  12. package/apps/mobile/src/Core/MultiSelect/index.js.map +1 -1
  13. package/form/controls/Checkbox/checkbox.cjs +1 -1
  14. package/form/controls/Checkbox/checkbox.cjs.map +1 -1
  15. package/form/controls/Checkbox/checkbox.js +1 -1
  16. package/form/controls/Checkbox/checkbox.js.map +1 -1
  17. package/form/inputs/InputTextarea/index.cjs +6 -1
  18. package/form/inputs/InputTextarea/index.cjs.map +1 -1
  19. package/form/inputs/InputTextarea/index.js +6 -1
  20. package/form/inputs/InputTextarea/index.js.map +1 -1
  21. package/form/inputs/Slider/index.cjs +6 -3
  22. package/form/inputs/Slider/index.cjs.map +1 -1
  23. package/form/inputs/Slider/index.js +6 -3
  24. package/form/inputs/Slider/index.js.map +1 -1
  25. package/form/selects/Dropdown/index.cjs +5 -1
  26. package/form/selects/Dropdown/index.cjs.map +1 -1
  27. package/form/selects/Dropdown/index.js +5 -1
  28. package/form/selects/Dropdown/index.js.map +1 -1
  29. package/form/selects/ListBox/index.cjs +6 -2
  30. package/form/selects/ListBox/index.cjs.map +1 -1
  31. package/form/selects/ListBox/index.js +6 -2
  32. package/form/selects/ListBox/index.js.map +1 -1
  33. package/form/selects/MultiSelect/index.cjs +5 -1
  34. package/form/selects/MultiSelect/index.cjs.map +1 -1
  35. package/form/selects/MultiSelect/index.js +5 -1
  36. package/form/selects/MultiSelect/index.js.map +1 -1
  37. package/index.d.ts +2 -0
  38. package/locale/ar.json.cjs +3 -0
  39. package/locale/ar.json.cjs.map +1 -1
  40. package/locale/ar.json.js +3 -1
  41. package/locale/ar.json.js.map +1 -1
  42. package/locale/en.json.cjs +3 -0
  43. package/locale/en.json.cjs.map +1 -1
  44. package/locale/en.json.js +3 -1
  45. package/locale/en.json.js.map +1 -1
  46. package/package.json +1 -1
  47. package/packages/types/src/Theme/defaultTheme.cjs +7 -1
  48. package/packages/types/src/Theme/defaultTheme.cjs.map +1 -1
  49. package/packages/types/src/Theme/defaultTheme.js +7 -1
  50. package/packages/types/src/Theme/defaultTheme.js.map +1 -1
@@ -84,6 +84,7 @@ require('../RadioButton/index.cjs');
84
84
  require('../Input/index.cjs');
85
85
  require('../Input/Field.cjs');
86
86
  require('../Input/Slot.cjs');
87
+ var panelGeometry = require('./panelGeometry.cjs');
87
88
 
88
89
  const getLabel = (item, optionLabel) => {
89
90
  if (!item) return "";
@@ -135,7 +136,15 @@ function Dropdown({
135
136
  highlightOnSelect = true,
136
137
  filter,
137
138
  filterBy,
139
+ // ⚠️ THESE TWO ENGLISH LITERALS ARE A LAST RESORT, NOT A
140
+ // TRANSLATION. The KitsConcerto wrapper always passes the
141
+ // reader's own sentence; these only apply when this component
142
+ // is used directly from `apps/mobile`, and they exist so a
143
+ // panel can never render a blank search box or an empty
144
+ // "no results" line. Recorded as English fallbacks.
138
145
  emptyFilterMessage = "No results found",
146
+ filterPlaceholder = "Search...",
147
+ isRTL = false,
139
148
  itemTemplate,
140
149
  valueTemplate,
141
150
  panelFooterTemplate,
@@ -154,6 +163,19 @@ function Dropdown({
154
163
  const [filterQuery, setFilterQuery] = React.useState("");
155
164
  const [triggerLayout, setTriggerLayout] = React.useState(null);
156
165
  const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
166
+ const [keyboardHeight, setKeyboardHeight] = React.useState(0);
167
+ React.useEffect(() => {
168
+ const showEvent = reactNative.Platform.OS === "ios" ? "keyboardWillChangeFrame" : "keyboardDidShow";
169
+ const hideEvent = reactNative.Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
170
+ const onShow = (event) => setKeyboardHeight(event?.endCoordinates?.height ?? 0);
171
+ const onHide = () => setKeyboardHeight(0);
172
+ const showSub = reactNative.Keyboard.addListener(showEvent, onShow);
173
+ const hideSub = reactNative.Keyboard.addListener(hideEvent, onHide);
174
+ return () => {
175
+ showSub.remove();
176
+ hideSub.remove();
177
+ };
178
+ }, []);
157
179
  const { viewStyle: externalViewStyle, textStyle: externalTextStyle } = splitStyle(externalStyle);
158
180
  const colors = {
159
181
  border: t("border") || t("gray.300"),
@@ -326,16 +348,14 @@ function Dropdown({
326
348
  onRequestClose: close,
327
349
  children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { style: styles.popoverOverlay, onPress: close, children: triggerLayout && (() => {
328
350
  const screen = reactNative.Dimensions.get("window");
329
- const PANEL_MAX_HEIGHT = 260;
330
- const GAP = 4;
331
- const spaceBelow = screen.height - (triggerLayout.y + triggerLayout.height) - insets.bottom;
332
- const spaceAbove = triggerLayout.y - insets.top;
333
- const openUp = spaceBelow < PANEL_MAX_HEIGHT && spaceAbove > spaceBelow;
334
- const maxHeight = Math.min(
335
- PANEL_MAX_HEIGHT,
336
- openUp ? spaceAbove - GAP : spaceBelow - GAP
337
- );
338
- const top = openUp ? triggerLayout.y - maxHeight - GAP : triggerLayout.y + triggerLayout.height + GAP;
351
+ const { top, maxHeight } = panelGeometry.computePanelGeometry({
352
+ screenHeight: screen.height,
353
+ insetTop: insets.top,
354
+ insetBottom: insets.bottom,
355
+ keyboardHeight,
356
+ triggerY: triggerLayout.y,
357
+ triggerHeight: triggerLayout.height
358
+ });
339
359
  return /* @__PURE__ */ jsxRuntime.jsxs(
340
360
  reactNative.View,
341
361
  {
@@ -357,20 +377,29 @@ function Dropdown({
357
377
  {
358
378
  value: filterQuery,
359
379
  onChangeText: setFilterQuery,
360
- placeholder: "Search...",
380
+ placeholder: filterPlaceholder,
361
381
  placeholderTextColor: colors.placeholder,
362
- style: [styles.filterInput, {
363
- borderColor: colors.filterBorder,
364
- backgroundColor: colors.filterBg,
365
- color: colors.filterText
366
- }],
382
+ style: [
383
+ styles.filterInput,
384
+ {
385
+ borderColor: colors.filterBorder,
386
+ backgroundColor: colors.filterBg,
387
+ color: colors.filterText
388
+ },
389
+ // Every other input in this library names its own edge
390
+ // and direction from the reader's language. Leaving
391
+ // these unset let the platform decide, so the field
392
+ // followed the process layout direction instead of the
393
+ // person reading it.
394
+ isRTL ? styles.filterRtl : styles.filterLtr
395
+ ],
367
396
  autoFocus: true
368
397
  }
369
398
  ) }),
370
399
  /* @__PURE__ */ jsxRuntime.jsx(
371
400
  reactNative.FlatList,
372
401
  {
373
- style: { flex: 1 },
402
+ style: { flexGrow: 0, flexShrink: 1 },
374
403
  contentContainerStyle: { paddingBottom: 12 },
375
404
  data: filteredData,
376
405
  keyExtractor: (item, i) => item?.__group ? `group-${i}` : `item-${i}`,
@@ -398,13 +427,17 @@ function Dropdown({
398
427
  {
399
428
  value: filterQuery,
400
429
  onChangeText: setFilterQuery,
401
- placeholder: "Search...",
430
+ placeholder: filterPlaceholder,
402
431
  placeholderTextColor: colors.placeholder,
403
- style: [styles.filterInput, {
404
- borderColor: colors.filterBorder,
405
- backgroundColor: colors.filterBg,
406
- color: colors.filterText
407
- }],
432
+ style: [
433
+ styles.filterInput,
434
+ {
435
+ borderColor: colors.filterBorder,
436
+ backgroundColor: colors.filterBg,
437
+ color: colors.filterText
438
+ },
439
+ isRTL ? styles.filterRtl : styles.filterLtr
440
+ ],
408
441
  autoFocus: true
409
442
  }
410
443
  ) }),
@@ -483,6 +516,14 @@ const styles = reactNative.StyleSheet.create({
483
516
  borderWidth: 1,
484
517
  borderRadius: 4
485
518
  },
519
+ filterLtr: {
520
+ textAlign: "left",
521
+ writingDirection: "ltr"
522
+ },
523
+ filterRtl: {
524
+ textAlign: "right",
525
+ writingDirection: "rtl"
526
+ },
486
527
  emptyContainer: {
487
528
  padding: 16,
488
529
  alignItems: "center"
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../../../../../../apps/mobile/src/Core/Dropdown/index.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useRef, useState, type ChangeEvent } from \"react\";\nimport {\n Dimensions,\n FlatList,\n Keyboard,\n Modal,\n Pressable,\n ScrollView,\n TouchableOpacity,\n View,\n StyleSheet, Text, TextInput\n} from \"react-native\";\nimport { useSafeAreaInsets } from \"react-native-safe-area-context\";\nimport { Input, InputField, type VirtualScrollerOptions } from \"../../\";\nimport { resolveThemeTokenForNative } from '../../Factory/helpers/style';\n\n/* ---------------------------------------------\n Types (PrimeReact-compatible)\n---------------------------------------------- */\n\nexport interface DropdownChangeEvent<T = any> {\n originalEvent?: any;\n value: T | null;\n}\n\n\nexport interface DropdownProps<T = any> {\n value?: T | null;\n options?: T[];\n\n onChange?: (e: ChangeEvent<T>, item:any) => void;\n\n optionLabel?: string;\n optionValue?: string;\n\n placeholder?: string;\n disabled?: boolean;\n editable?: boolean;\n loading?: boolean;\n showClear?: boolean;\n isModal?: boolean;\n\n checkmark?: boolean;\n highlightOnSelect?: boolean;\n\n filter?: boolean;\n filterBy?: string;\n emptyFilterMessage?: string;\n\n itemTemplate?: (item: T) => React.ReactNode;\n valueTemplate?: (value: T | null) => React.ReactNode;\n panelFooterTemplate?: () => React.ReactNode;\n\n optionGroupLabel?: string;\n optionGroupChildren?: string;\n optionGroupTemplate?: (group: any) => React.ReactNode;\n\n virtualScrollerOptions?: VirtualScrollerOptions;\n\n invalid?: boolean;\n testID?: string;\n style?: import('react-native').ViewStyle;\n}\n\n/* ---------------------------------------------\n Helpers\n---------------------------------------------- */\n\nconst getLabel = (item: any, optionLabel?: string) => {\n if (!item) return \"\";\n if (!optionLabel) return String(item);\n return String(item[optionLabel]);\n};\n\nconst getValue = (item: any, optionValue?: string) => {\n if (!item) return null;\n if (!optionValue) return item;\n return item[optionValue];\n};\n\nconst t = resolveThemeTokenForNative;\n\nconst TEXT_STYLE_KEYS = new Set([\n 'fontSize', 'fontFamily', 'fontWeight', 'fontStyle',\n 'color', 'letterSpacing', 'lineHeight', 'textAlign',\n 'textDecorationLine', 'textTransform',\n]);\n\nfunction splitStyle(combined?: any): { viewStyle?: any; textStyle?: any } {\n if (!combined) return {};\n const view: Record<string, any> = {};\n const text: Record<string, any> = {};\n for (const [k, v] of Object.entries(combined)) {\n if (TEXT_STYLE_KEYS.has(k)) text[k] = v;\n else view[k] = v;\n }\n return {\n viewStyle: Object.keys(view).length ? view : undefined,\n textStyle: Object.keys(text).length ? text : undefined,\n };\n}\n\n/* ---------------------------------------------\n Component\n---------------------------------------------- */\n\nexport default function Dropdown<T = any>({\n value,\n options = [],\n onChange,\n\n optionLabel,\n optionValue,\n\n placeholder,\n disabled,\n editable,\n isModal = false,\n\n checkmark,\n highlightOnSelect = true,\n\n filter,\n filterBy,\n emptyFilterMessage = 'No results found',\n\n itemTemplate,\n valueTemplate,\n panelFooterTemplate,\n\n optionGroupLabel,\n optionGroupChildren,\n optionGroupTemplate,\n\n virtualScrollerOptions,\n\n invalid,\n testID,\n style: externalStyle,\n }: DropdownProps<T>) {\n const inputRef = useRef<any>(null);\n const triggerRef = useRef<View>(null);\n const [open, setOpen] = useState(false);\n const [inputText, setInputText] = useState(\"\");\n const [filterQuery, setFilterQuery] = useState(\"\");\n const [triggerLayout, setTriggerLayout] = useState<{\n x: number; y: number; width: number; height: number;\n } | null>(null);\n const insets = useSafeAreaInsets();\n\n const { viewStyle: externalViewStyle, textStyle: externalTextStyle } = splitStyle(externalStyle);\n\n const colors = {\n border: t('border') || t('gray.300'),\n borderInvalid: t('danger') || t('red.500'),\n bg: t('surface-card') || '#fff',\n text: t('text') || t('gray.800'),\n placeholder: t('text-secondary') || t('gray.400'),\n optionSelected: t('highlight-bg') || t('gray.100'),\n groupBg: t('surface-ground') || t('gray.50'),\n filterBorder: t('border') || t('gray.200'),\n filterBg: t('surface-ground') || t('gray.50'),\n filterText: t('text') || t('gray.800'),\n emptyText: t('text-secondary') || t('gray.400'),\n primary: t('primary'),\n };\n\n /* ---------------------------------------------\n Derived\n ---------------------------------------------- */\n\n const selectedItem = useMemo(() => {\n if (value == null) return null;\n // Search through group children when grouped\n if (optionGroupChildren) {\n for (const group of options as any[]) {\n const children = group[optionGroupChildren];\n if (Array.isArray(children)) {\n const found = children.find((c: any) => getValue(c, optionValue) === value);\n if (found) return found;\n }\n }\n return null;\n }\n return options.find(\n (o) => getValue(o, optionValue) === value\n ) ?? null;\n }, [value, options, optionValue, optionGroupChildren]);\n\n /* ---------------------------------------------\n Open / Close\n ---------------------------------------------- */\n\n const toggle = () => {\n if (disabled) return;\n Keyboard.dismiss();\n if (open) {\n setOpen(false);\n return;\n }\n setFilterQuery(\"\");\n // Measure trigger position in window so the popover can be rendered\n // inside a Modal (escaping any parent ScrollView) at the correct anchor.\n triggerRef.current?.measureInWindow((x, y, width, height) => {\n setTriggerLayout({ x, y, width, height });\n setOpen(true);\n });\n };\n\n const close = () => setOpen(false);\n\n /* ---------------------------------------------\n Selection\n ---------------------------------------------- */\n\n const selectItem = (item: T) => {\n const newValue = getValue(item, optionValue);\n\n if (!onChange) return;\n\n const syntheticEvent = {\n target: {\n value: newValue,\n },\n } as React.ChangeEvent<any>;\n\n onChange(syntheticEvent, item);\n\n setOpen(false);\n };\n\n /* ---------------------------------------------\n Render item\n ---------------------------------------------- */\n\n const renderItem = useCallback(\n (item: any, index: number) => {\n if (!item) {\n return null;\n }\n\n // Group header\n if (item.__group) {\n return (\n <Text key={`group-${index}`} style={[styles.groupLabel, { backgroundColor: colors.groupBg }]}>\n {optionGroupLabel ? item.group?.[optionGroupLabel] : \"\"}\n </Text>\n );\n }\n\n const selected =\n value != null &&\n getValue(item, optionValue) === value;\n\n let content: React.ReactElement;\n\n if (itemTemplate) {\n const rendered = itemTemplate(item);\n\n content = React.isValidElement(rendered) ? (\n rendered\n ) : (\n <Text>{String(rendered ?? \"\")}</Text>\n );\n } else {\n content = (\n <Text style={[{ color: colors.text }, externalTextStyle && { fontSize: externalTextStyle.fontSize }]}>\n {getLabel(item, optionLabel)}\n </Text>\n );\n }\n\n return (\n <Pressable\n key={`item-${index}`}\n onPress={() => selectItem(item)}\n style={[\n styles.option,\n selected && highlightOnSelect && { backgroundColor: colors.optionSelected },\n ]}\n >\n {content}\n {checkmark && selected && <Text>✓</Text>}\n </Pressable>\n );\n },\n [\n value,\n optionValue,\n optionLabel,\n itemTemplate,\n optionGroupLabel,\n checkmark,\n highlightOnSelect,\n ]\n );\n\n\n /* ---------------------------------------------\n Group flattening\n ---------------------------------------------- */\n\n const flatData = useMemo(() => {\n if (!optionGroupLabel || !optionGroupChildren) {\n return options;\n }\n\n const out: any[] = [];\n options.forEach((g: any) => {\n out.push({ __group: true, group: g });\n g[optionGroupChildren]?.forEach((c: any) => out.push(c));\n });\n return out;\n }, [options]);\n\n /* ---------------------------------------------\n Filter\n ---------------------------------------------- */\n\n const filteredData = useMemo(() => {\n if (!filter || !filterQuery) return flatData;\n const q = filterQuery.toLowerCase();\n const key = filterBy || optionLabel;\n\n return flatData.filter((entry: any) => {\n // Keep group headers\n if (entry.__group) return true;\n const label = getLabel(entry, key);\n return label.toLowerCase().includes(q);\n });\n }, [flatData, filter, filterQuery, filterBy, optionLabel]);\n\n /* ---------------------------------------------\n Display value\n ---------------------------------------------- */\n\n const displayValue = valueTemplate\n ? valueTemplate(selectedItem)\n : selectedItem\n ? getLabel(selectedItem, optionLabel)\n : \"\";\n\n /* ---------------------------------------------\n Render\n ---------------------------------------------- */\n\n return (\n <View style={styles.container} testID={testID}>\n <Pressable\n ref={triggerRef as any}\n style={[\n styles.control,\n { borderColor: colors.border, backgroundColor: colors.bg },\n invalid && { borderColor: colors.borderInvalid },\n disabled && styles.disabled,\n externalViewStyle,\n ]}\n onPress={toggle}\n >\n {editable ? (\n <Input style={styles.input}>\n <InputField\n ref={inputRef}\n value={inputText}\n onChangeText={setInputText}\n placeholder={placeholder}\n editable={!disabled}\n />\n </Input>\n ) : (\n <Text\n numberOfLines={1}\n style={[\n // Fill the trigger row and left-align the value/placeholder so it\n // doesn't read as centred (the row is justify=space-between, so the\n // arrow stays pinned right).\n { flex: 1, textAlign: \"left\" as const },\n displayValue ? { color: colors.text } : { color: colors.placeholder },\n externalTextStyle,\n !displayValue && { color: colors.placeholder },\n ]}>\n {displayValue || placeholder}\n </Text>\n )}\n\n <Text style={[{ color: colors.text }, externalTextStyle]}>▾</Text>\n </Pressable>\n\n {!isModal && (\n <Modal\n visible={open && !!triggerLayout}\n transparent\n animationType=\"none\"\n onRequestClose={close}\n >\n <Pressable style={styles.popoverOverlay} onPress={close}>\n {triggerLayout && (() => {\n const screen = Dimensions.get('window');\n const PANEL_MAX_HEIGHT = 260;\n const GAP = 4;\n const spaceBelow =\n screen.height - (triggerLayout.y + triggerLayout.height) - insets.bottom;\n const spaceAbove = triggerLayout.y - insets.top;\n const openUp = spaceBelow < PANEL_MAX_HEIGHT && spaceAbove > spaceBelow;\n const maxHeight = Math.min(\n PANEL_MAX_HEIGHT,\n openUp ? spaceAbove - GAP : spaceBelow - GAP,\n );\n const top = openUp\n ? triggerLayout.y - maxHeight - GAP\n : triggerLayout.y + triggerLayout.height + GAP;\n\n return (\n <View\n style={[\n styles.popoverPanel,\n {\n top,\n left: triggerLayout.x,\n width: triggerLayout.width,\n maxHeight,\n borderColor: colors.border,\n backgroundColor: colors.bg,\n },\n ]}\n onStartShouldSetResponder={() => true}\n >\n {filter && (\n <View style={[styles.filterContainer, { borderBottomColor: colors.filterBorder }]}>\n <TextInput\n value={filterQuery}\n onChangeText={setFilterQuery}\n placeholder=\"Search...\"\n placeholderTextColor={colors.placeholder}\n style={[styles.filterInput, {\n borderColor: colors.filterBorder,\n backgroundColor: colors.filterBg,\n color: colors.filterText,\n }]}\n autoFocus\n />\n </View>\n )}\n <FlatList\n style={{ flex: 1 }}\n contentContainerStyle={{ paddingBottom: 12 }}\n data={filteredData}\n keyExtractor={(item: any, i: number) =>\n item?.__group ? `group-${i}` : `item-${i}`\n }\n renderItem={({ item, index }) => renderItem(item, index)}\n keyboardShouldPersistTaps=\"handled\"\n showsHorizontalScrollIndicator={false}\n ListEmptyComponent={\n filterQuery ? (\n <View style={styles.emptyContainer}>\n <Text style={[styles.emptyText, { color: colors.emptyText }]}>{emptyFilterMessage}</Text>\n </View>\n ) : null\n }\n />\n {panelFooterTemplate?.()}\n </View>\n );\n })()}\n </Pressable>\n </Modal>\n )}\n\n {isModal && (\n <Modal visible={open} transparent animationType=\"fade\">\n <Pressable style={styles.modalOverlay} onPress={close}>\n <View\n style={[styles.modalPanel, { backgroundColor: colors.bg }]}\n onStartShouldSetResponder={() => true}\n >\n {filter && (\n <View style={[styles.filterContainer, { borderBottomColor: colors.filterBorder }]}>\n <TextInput\n value={filterQuery}\n onChangeText={setFilterQuery}\n placeholder=\"Search...\"\n placeholderTextColor={colors.placeholder}\n style={[styles.filterInput, {\n borderColor: colors.filterBorder,\n backgroundColor: colors.filterBg,\n color: colors.filterText,\n }]}\n autoFocus\n />\n </View>\n )}\n <FlatList\n data={filteredData}\n keyExtractor={(item: any, i: number) =>\n item?.__group ? `group-${i}` : `item-${i}`\n }\n renderItem={({ item, index }) => renderItem(item, index)}\n nestedScrollEnabled\n keyboardShouldPersistTaps=\"handled\"\n style={{ flex: 1 }}\n contentContainerStyle={{ paddingBottom: 12 }}\n ListEmptyComponent={\n filterQuery ? (\n <View style={styles.emptyContainer}>\n <Text style={[styles.emptyText, { color: colors.emptyText }]}>{emptyFilterMessage}</Text>\n </View>\n ) : null\n }\n />\n {panelFooterTemplate?.()}\n </View>\n </Pressable>\n </Modal>\n )}\n </View>\n );\n}\n\n/* ---------------------------------------------\n Styles (layout only — colors applied inline via theme tokens)\n---------------------------------------------- */\n\nconst styles = StyleSheet.create({\n container: {\n width: \"100%\",\n position: \"relative\" as const,\n },\n control: {\n flexDirection: \"row\" as const,\n alignItems: \"center\" as const,\n justifyContent: \"space-between\" as const,\n borderWidth: 1,\n borderRadius: 6,\n paddingHorizontal: 10,\n paddingVertical: 10,\n },\n disabled: {\n opacity: 0.5,\n },\n option: {\n paddingHorizontal: 12,\n paddingVertical: 10,\n flexDirection: \"row\" as const,\n justifyContent: \"space-between\" as const,\n alignItems: \"center\" as const,\n },\n groupLabel: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n fontWeight: \"600\" as const,\n },\n input: {\n flex: 1,\n },\n panel: {\n position: \"absolute\" as const,\n top: \"100%\",\n left: 0,\n right: 0,\n marginTop: 4,\n borderWidth: 1,\n borderRadius: 6,\n maxHeight: 260,\n overflow: \"hidden\" as const,\n zIndex: 9999,\n },\n filterContainer: {\n paddingHorizontal: 8,\n paddingVertical: 6,\n borderBottomWidth: 1,\n },\n filterInput: {\n fontSize: 14,\n paddingHorizontal: 8,\n paddingVertical: 6,\n borderWidth: 1,\n borderRadius: 4,\n },\n emptyContainer: {\n padding: 16,\n alignItems: 'center' as const,\n },\n emptyText: {\n fontSize: 14,\n },\n popoverOverlay: {\n flex: 1,\n backgroundColor: 'transparent',\n },\n popoverPanel: {\n position: 'absolute' as const,\n borderWidth: 1,\n borderRadius: 6,\n overflow: 'hidden' as const,\n elevation: 8,\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.15,\n shadowRadius: 8,\n },\n modalOverlay: {\n flex: 1,\n backgroundColor: 'rgba(0,0,0,0.4)',\n justifyContent: 'center' as const,\n },\n modalPanel: {\n margin: 24,\n maxHeight: '70%',\n borderRadius: 12,\n overflow: 'hidden' as const,\n },\n});\n"],"names":["resolveThemeTokenForNative","useRef","useState","useSafeAreaInsets","useMemo","Keyboard","useCallback","jsx","Text","jsxs","Pressable","View","Input","InputField","Modal","Dimensions","TextInput","FlatList","StyleSheet"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../../../../../../apps/mobile/src/Core/Dropdown/index.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState, type ChangeEvent } from \"react\";\nimport {\n Dimensions,\n FlatList,\n Keyboard,\n Modal,\n Platform,\n Pressable,\n ScrollView,\n TouchableOpacity,\n View,\n StyleSheet, Text, TextInput\n} from \"react-native\";\nimport { useSafeAreaInsets } from \"react-native-safe-area-context\";\nimport { Input, InputField, type VirtualScrollerOptions } from \"../../\";\nimport { resolveThemeTokenForNative } from '../../Factory/helpers/style';\nimport { computePanelGeometry } from './panelGeometry';\n\n/* ---------------------------------------------\n Types (PrimeReact-compatible)\n---------------------------------------------- */\n\nexport interface DropdownChangeEvent<T = any> {\n originalEvent?: any;\n value: T | null;\n}\n\n\nexport interface DropdownProps<T = any> {\n value?: T | null;\n options?: T[];\n\n onChange?: (e: ChangeEvent<T>, item:any) => void;\n\n optionLabel?: string;\n optionValue?: string;\n\n placeholder?: string;\n disabled?: boolean;\n editable?: boolean;\n loading?: boolean;\n showClear?: boolean;\n isModal?: boolean;\n\n checkmark?: boolean;\n highlightOnSelect?: boolean;\n\n filter?: boolean;\n filterBy?: string;\n emptyFilterMessage?: string;\n /**\n * Placeholder for the panel's filter field.\n *\n * ⛔ THIS COMPONENT CANNOT TRANSLATE. It lives in `apps/mobile`, which\n * `packages/ui` imports — the reverse import would be a cycle between the two\n * workspaces. So the sentence is resolved by the KitsConcerto wrapper, which\n * has `useLanguage()`, and arrives here already written, exactly as\n * `emptyFilterMessage` does.\n */\n filterPlaceholder?: string;\n /**\n * Which way the reader reads, from the wrapper's `useLanguage().isRTL`.\n *\n * ⛔ NOT `I18nManager.isRTL`. That is the PROCESS layout direction, which a\n * consumer can force at boot and which does not change when the reader\n * switches language. The filter field follows the interface language, like\n * every other input in this library.\n */\n isRTL?: boolean;\n\n itemTemplate?: (item: T) => React.ReactNode;\n valueTemplate?: (value: T | null) => React.ReactNode;\n panelFooterTemplate?: () => React.ReactNode;\n\n optionGroupLabel?: string;\n optionGroupChildren?: string;\n optionGroupTemplate?: (group: any) => React.ReactNode;\n\n virtualScrollerOptions?: VirtualScrollerOptions;\n\n invalid?: boolean;\n testID?: string;\n style?: import('react-native').ViewStyle;\n}\n\n/* ---------------------------------------------\n Helpers\n---------------------------------------------- */\n\nconst getLabel = (item: any, optionLabel?: string) => {\n if (!item) return \"\";\n if (!optionLabel) return String(item);\n return String(item[optionLabel]);\n};\n\nconst getValue = (item: any, optionValue?: string) => {\n if (!item) return null;\n if (!optionValue) return item;\n return item[optionValue];\n};\n\nconst t = resolveThemeTokenForNative;\n\nconst TEXT_STYLE_KEYS = new Set([\n 'fontSize', 'fontFamily', 'fontWeight', 'fontStyle',\n 'color', 'letterSpacing', 'lineHeight', 'textAlign',\n 'textDecorationLine', 'textTransform',\n]);\n\nfunction splitStyle(combined?: any): { viewStyle?: any; textStyle?: any } {\n if (!combined) return {};\n const view: Record<string, any> = {};\n const text: Record<string, any> = {};\n for (const [k, v] of Object.entries(combined)) {\n if (TEXT_STYLE_KEYS.has(k)) text[k] = v;\n else view[k] = v;\n }\n return {\n viewStyle: Object.keys(view).length ? view : undefined,\n textStyle: Object.keys(text).length ? text : undefined,\n };\n}\n\n/* ---------------------------------------------\n Component\n---------------------------------------------- */\n\nexport default function Dropdown<T = any>({\n value,\n options = [],\n onChange,\n\n optionLabel,\n optionValue,\n\n placeholder,\n disabled,\n editable,\n isModal = false,\n\n checkmark,\n highlightOnSelect = true,\n\n filter,\n filterBy,\n // ⚠️ THESE TWO ENGLISH LITERALS ARE A LAST RESORT, NOT A\n // TRANSLATION. The KitsConcerto wrapper always passes the\n // reader's own sentence; these only apply when this component\n // is used directly from `apps/mobile`, and they exist so a\n // panel can never render a blank search box or an empty\n // \"no results\" line. Recorded as English fallbacks.\n emptyFilterMessage = 'No results found',\n filterPlaceholder = 'Search...',\n isRTL = false,\n\n itemTemplate,\n valueTemplate,\n panelFooterTemplate,\n\n optionGroupLabel,\n optionGroupChildren,\n optionGroupTemplate,\n\n virtualScrollerOptions,\n\n invalid,\n testID,\n style: externalStyle,\n }: DropdownProps<T>) {\n const inputRef = useRef<any>(null);\n const triggerRef = useRef<View>(null);\n const [open, setOpen] = useState(false);\n const [inputText, setInputText] = useState(\"\");\n const [filterQuery, setFilterQuery] = useState(\"\");\n const [triggerLayout, setTriggerLayout] = useState<{\n x: number; y: number; width: number; height: number;\n } | null>(null);\n const insets = useSafeAreaInsets();\n const [keyboardHeight, setKeyboardHeight] = useState(0);\n\n /* The filter field inside the panel carries `autoFocus`, so on a filtered\n dropdown the keyboard is already rising by the time the panel lays out.\n Without this the panel is sized against the raw screen height and hands\n itself space the keyboard is about to take.\n\n iOS reports the frame before the animation so the panel settles in one\n step; Android has no `Will` events and reports after. */\n useEffect(() => {\n const showEvent = Platform.OS === 'ios' ? 'keyboardWillChangeFrame' : 'keyboardDidShow';\n const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';\n\n const onShow = (event: any) => setKeyboardHeight(event?.endCoordinates?.height ?? 0);\n const onHide = () => setKeyboardHeight(0);\n\n const showSub = Keyboard.addListener(showEvent as any, onShow);\n const hideSub = Keyboard.addListener(hideEvent as any, onHide);\n\n return () => {\n showSub.remove();\n hideSub.remove();\n };\n }, []);\n\n const { viewStyle: externalViewStyle, textStyle: externalTextStyle } = splitStyle(externalStyle);\n\n const colors = {\n border: t('border') || t('gray.300'),\n borderInvalid: t('danger') || t('red.500'),\n bg: t('surface-card') || '#fff',\n text: t('text') || t('gray.800'),\n placeholder: t('text-secondary') || t('gray.400'),\n optionSelected: t('highlight-bg') || t('gray.100'),\n groupBg: t('surface-ground') || t('gray.50'),\n filterBorder: t('border') || t('gray.200'),\n filterBg: t('surface-ground') || t('gray.50'),\n filterText: t('text') || t('gray.800'),\n emptyText: t('text-secondary') || t('gray.400'),\n primary: t('primary'),\n };\n\n /* ---------------------------------------------\n Derived\n ---------------------------------------------- */\n\n const selectedItem = useMemo(() => {\n if (value == null) return null;\n // Search through group children when grouped\n if (optionGroupChildren) {\n for (const group of options as any[]) {\n const children = group[optionGroupChildren];\n if (Array.isArray(children)) {\n const found = children.find((c: any) => getValue(c, optionValue) === value);\n if (found) return found;\n }\n }\n return null;\n }\n return options.find(\n (o) => getValue(o, optionValue) === value\n ) ?? null;\n }, [value, options, optionValue, optionGroupChildren]);\n\n /* ---------------------------------------------\n Open / Close\n ---------------------------------------------- */\n\n const toggle = () => {\n if (disabled) return;\n Keyboard.dismiss();\n if (open) {\n setOpen(false);\n return;\n }\n setFilterQuery(\"\");\n // Measure trigger position in window so the popover can be rendered\n // inside a Modal (escaping any parent ScrollView) at the correct anchor.\n triggerRef.current?.measureInWindow((x, y, width, height) => {\n setTriggerLayout({ x, y, width, height });\n setOpen(true);\n });\n };\n\n const close = () => setOpen(false);\n\n /* ---------------------------------------------\n Selection\n ---------------------------------------------- */\n\n const selectItem = (item: T) => {\n const newValue = getValue(item, optionValue);\n\n if (!onChange) return;\n\n const syntheticEvent = {\n target: {\n value: newValue,\n },\n } as React.ChangeEvent<any>;\n\n onChange(syntheticEvent, item);\n\n setOpen(false);\n };\n\n /* ---------------------------------------------\n Render item\n ---------------------------------------------- */\n\n const renderItem = useCallback(\n (item: any, index: number) => {\n if (!item) {\n return null;\n }\n\n // Group header\n if (item.__group) {\n return (\n <Text key={`group-${index}`} style={[styles.groupLabel, { backgroundColor: colors.groupBg }]}>\n {optionGroupLabel ? item.group?.[optionGroupLabel] : \"\"}\n </Text>\n );\n }\n\n const selected =\n value != null &&\n getValue(item, optionValue) === value;\n\n let content: React.ReactElement;\n\n if (itemTemplate) {\n const rendered = itemTemplate(item);\n\n content = React.isValidElement(rendered) ? (\n rendered\n ) : (\n <Text>{String(rendered ?? \"\")}</Text>\n );\n } else {\n content = (\n <Text style={[{ color: colors.text }, externalTextStyle && { fontSize: externalTextStyle.fontSize }]}>\n {getLabel(item, optionLabel)}\n </Text>\n );\n }\n\n return (\n <Pressable\n key={`item-${index}`}\n onPress={() => selectItem(item)}\n style={[\n styles.option,\n selected && highlightOnSelect && { backgroundColor: colors.optionSelected },\n ]}\n >\n {content}\n {checkmark && selected && <Text>✓</Text>}\n </Pressable>\n );\n },\n [\n value,\n optionValue,\n optionLabel,\n itemTemplate,\n optionGroupLabel,\n checkmark,\n highlightOnSelect,\n ]\n );\n\n\n /* ---------------------------------------------\n Group flattening\n ---------------------------------------------- */\n\n const flatData = useMemo(() => {\n if (!optionGroupLabel || !optionGroupChildren) {\n return options;\n }\n\n const out: any[] = [];\n options.forEach((g: any) => {\n out.push({ __group: true, group: g });\n g[optionGroupChildren]?.forEach((c: any) => out.push(c));\n });\n return out;\n }, [options]);\n\n /* ---------------------------------------------\n Filter\n ---------------------------------------------- */\n\n const filteredData = useMemo(() => {\n if (!filter || !filterQuery) return flatData;\n const q = filterQuery.toLowerCase();\n const key = filterBy || optionLabel;\n\n return flatData.filter((entry: any) => {\n // Keep group headers\n if (entry.__group) return true;\n const label = getLabel(entry, key);\n return label.toLowerCase().includes(q);\n });\n }, [flatData, filter, filterQuery, filterBy, optionLabel]);\n\n /* ---------------------------------------------\n Display value\n ---------------------------------------------- */\n\n const displayValue = valueTemplate\n ? valueTemplate(selectedItem)\n : selectedItem\n ? getLabel(selectedItem, optionLabel)\n : \"\";\n\n /* ---------------------------------------------\n Render\n ---------------------------------------------- */\n\n return (\n <View style={styles.container} testID={testID}>\n <Pressable\n ref={triggerRef as any}\n style={[\n styles.control,\n { borderColor: colors.border, backgroundColor: colors.bg },\n invalid && { borderColor: colors.borderInvalid },\n disabled && styles.disabled,\n externalViewStyle,\n ]}\n onPress={toggle}\n >\n {editable ? (\n <Input style={styles.input}>\n <InputField\n ref={inputRef}\n value={inputText}\n onChangeText={setInputText}\n placeholder={placeholder}\n editable={!disabled}\n />\n </Input>\n ) : (\n <Text\n numberOfLines={1}\n style={[\n // Fill the trigger row and left-align the value/placeholder so it\n // doesn't read as centred (the row is justify=space-between, so the\n // arrow stays pinned right).\n { flex: 1, textAlign: \"left\" as const },\n displayValue ? { color: colors.text } : { color: colors.placeholder },\n externalTextStyle,\n !displayValue && { color: colors.placeholder },\n ]}>\n {displayValue || placeholder}\n </Text>\n )}\n\n <Text style={[{ color: colors.text }, externalTextStyle]}>▾</Text>\n </Pressable>\n\n {!isModal && (\n <Modal\n visible={open && !!triggerLayout}\n transparent\n animationType=\"none\"\n onRequestClose={close}\n >\n <Pressable style={styles.popoverOverlay} onPress={close}>\n {triggerLayout && (() => {\n const screen = Dimensions.get('window');\n const { top, maxHeight } = computePanelGeometry({\n screenHeight: screen.height,\n insetTop: insets.top,\n insetBottom: insets.bottom,\n keyboardHeight,\n triggerY: triggerLayout.y,\n triggerHeight: triggerLayout.height,\n });\n\n return (\n <View\n style={[\n styles.popoverPanel,\n {\n top,\n left: triggerLayout.x,\n width: triggerLayout.width,\n maxHeight,\n borderColor: colors.border,\n backgroundColor: colors.bg,\n },\n ]}\n onStartShouldSetResponder={() => true}\n >\n {filter && (\n <View style={[styles.filterContainer, { borderBottomColor: colors.filterBorder }]}>\n <TextInput\n value={filterQuery}\n onChangeText={setFilterQuery}\n placeholder={filterPlaceholder}\n placeholderTextColor={colors.placeholder}\n style={[styles.filterInput, {\n borderColor: colors.filterBorder,\n backgroundColor: colors.filterBg,\n color: colors.filterText,\n },\n // Every other input in this library names its own edge\n // and direction from the reader's language. Leaving\n // these unset let the platform decide, so the field\n // followed the process layout direction instead of the\n // person reading it.\n isRTL ? styles.filterRtl : styles.filterLtr]}\n autoFocus\n />\n </View>\n )}\n {/* `flexShrink` rather than `flex: 1`: the panel is sized by\n `maxHeight`, not a fixed height, so the list has to be\n allowed to grow with its content up to that ceiling and\n then scroll inside it. `flex: 1` sets flexBasis 0, which\n contributes nothing to a shrink-wrapping parent. */}\n <FlatList\n style={{ flexGrow: 0, flexShrink: 1 }}\n contentContainerStyle={{ paddingBottom: 12 }}\n data={filteredData}\n keyExtractor={(item: any, i: number) =>\n item?.__group ? `group-${i}` : `item-${i}`\n }\n renderItem={({ item, index }) => renderItem(item, index)}\n keyboardShouldPersistTaps=\"handled\"\n showsHorizontalScrollIndicator={false}\n ListEmptyComponent={\n filterQuery ? (\n <View style={styles.emptyContainer}>\n <Text style={[styles.emptyText, { color: colors.emptyText }]}>{emptyFilterMessage}</Text>\n </View>\n ) : null\n }\n />\n {panelFooterTemplate?.()}\n </View>\n );\n })()}\n </Pressable>\n </Modal>\n )}\n\n {isModal && (\n <Modal visible={open} transparent animationType=\"fade\">\n <Pressable style={styles.modalOverlay} onPress={close}>\n <View\n style={[styles.modalPanel, { backgroundColor: colors.bg }]}\n onStartShouldSetResponder={() => true}\n >\n {filter && (\n <View style={[styles.filterContainer, { borderBottomColor: colors.filterBorder }]}>\n <TextInput\n value={filterQuery}\n onChangeText={setFilterQuery}\n placeholder={filterPlaceholder}\n placeholderTextColor={colors.placeholder}\n style={[styles.filterInput, {\n borderColor: colors.filterBorder,\n backgroundColor: colors.filterBg,\n color: colors.filterText,\n },\n isRTL ? styles.filterRtl : styles.filterLtr]}\n autoFocus\n />\n </View>\n )}\n <FlatList\n data={filteredData}\n keyExtractor={(item: any, i: number) =>\n item?.__group ? `group-${i}` : `item-${i}`\n }\n renderItem={({ item, index }) => renderItem(item, index)}\n nestedScrollEnabled\n keyboardShouldPersistTaps=\"handled\"\n style={{ flex: 1 }}\n contentContainerStyle={{ paddingBottom: 12 }}\n ListEmptyComponent={\n filterQuery ? (\n <View style={styles.emptyContainer}>\n <Text style={[styles.emptyText, { color: colors.emptyText }]}>{emptyFilterMessage}</Text>\n </View>\n ) : null\n }\n />\n {panelFooterTemplate?.()}\n </View>\n </Pressable>\n </Modal>\n )}\n </View>\n );\n}\n\n/* ---------------------------------------------\n Styles (layout only — colors applied inline via theme tokens)\n---------------------------------------------- */\n\nconst styles = StyleSheet.create({\n container: {\n width: \"100%\",\n position: \"relative\" as const,\n },\n control: {\n flexDirection: \"row\" as const,\n alignItems: \"center\" as const,\n justifyContent: \"space-between\" as const,\n borderWidth: 1,\n borderRadius: 6,\n paddingHorizontal: 10,\n paddingVertical: 10,\n },\n disabled: {\n opacity: 0.5,\n },\n option: {\n paddingHorizontal: 12,\n paddingVertical: 10,\n flexDirection: \"row\" as const,\n justifyContent: \"space-between\" as const,\n alignItems: \"center\" as const,\n },\n groupLabel: {\n paddingHorizontal: 12,\n paddingVertical: 8,\n fontWeight: \"600\" as const,\n },\n input: {\n flex: 1,\n },\n panel: {\n position: \"absolute\" as const,\n top: \"100%\",\n left: 0,\n right: 0,\n marginTop: 4,\n borderWidth: 1,\n borderRadius: 6,\n maxHeight: 260,\n overflow: \"hidden\" as const,\n zIndex: 9999,\n },\n filterContainer: {\n paddingHorizontal: 8,\n paddingVertical: 6,\n borderBottomWidth: 1,\n },\n filterInput: {\n fontSize: 14,\n paddingHorizontal: 8,\n paddingVertical: 6,\n borderWidth: 1,\n borderRadius: 4,\n },\n filterLtr: {\n textAlign: 'left' as const,\n writingDirection: 'ltr' as const,\n },\n filterRtl: {\n textAlign: 'right' as const,\n writingDirection: 'rtl' as const,\n },\n emptyContainer: {\n padding: 16,\n alignItems: 'center' as const,\n },\n emptyText: {\n fontSize: 14,\n },\n popoverOverlay: {\n flex: 1,\n backgroundColor: 'transparent',\n },\n popoverPanel: {\n position: 'absolute' as const,\n borderWidth: 1,\n borderRadius: 6,\n overflow: 'hidden' as const,\n elevation: 8,\n shadowColor: '#000',\n shadowOffset: { width: 0, height: 2 },\n shadowOpacity: 0.15,\n shadowRadius: 8,\n },\n modalOverlay: {\n flex: 1,\n backgroundColor: 'rgba(0,0,0,0.4)',\n justifyContent: 'center' as const,\n },\n modalPanel: {\n margin: 24,\n maxHeight: '70%',\n borderRadius: 12,\n overflow: 'hidden' as const,\n },\n});\n"],"names":["resolveThemeTokenForNative","useRef","useState","useSafeAreaInsets","useEffect","Platform","Keyboard","useMemo","useCallback","jsx","Text","jsxs","Pressable","View","Input","InputField","Modal","Dimensions","computePanelGeometry","TextInput","FlatList","StyleSheet"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import React, { useRef, useState, useMemo, useCallback } from 'react';
3
- import { Text, Pressable, View, Modal, Dimensions, TextInput, FlatList, Keyboard, StyleSheet } from 'react-native';
2
+ import React, { useRef, useState, useEffect, useMemo, useCallback } from 'react';
3
+ import { Platform, Keyboard, Text, Pressable, View, Modal, Dimensions, TextInput, FlatList, StyleSheet } from 'react-native';
4
4
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
5
5
  import '../../ui/accordion/index.js';
6
6
  import '../../ui/actionsheet/index.js';
@@ -80,6 +80,7 @@ import '../RadioButton/index.js';
80
80
  import '../Input/index.js';
81
81
  import '../Input/Field.js';
82
82
  import '../Input/Slot.js';
83
+ import { computePanelGeometry } from './panelGeometry.js';
83
84
 
84
85
  const getLabel = (item, optionLabel) => {
85
86
  if (!item) return "";
@@ -131,7 +132,15 @@ function Dropdown({
131
132
  highlightOnSelect = true,
132
133
  filter,
133
134
  filterBy,
135
+ // ⚠️ THESE TWO ENGLISH LITERALS ARE A LAST RESORT, NOT A
136
+ // TRANSLATION. The KitsConcerto wrapper always passes the
137
+ // reader's own sentence; these only apply when this component
138
+ // is used directly from `apps/mobile`, and they exist so a
139
+ // panel can never render a blank search box or an empty
140
+ // "no results" line. Recorded as English fallbacks.
134
141
  emptyFilterMessage = "No results found",
142
+ filterPlaceholder = "Search...",
143
+ isRTL = false,
135
144
  itemTemplate,
136
145
  valueTemplate,
137
146
  panelFooterTemplate,
@@ -150,6 +159,19 @@ function Dropdown({
150
159
  const [filterQuery, setFilterQuery] = useState("");
151
160
  const [triggerLayout, setTriggerLayout] = useState(null);
152
161
  const insets = useSafeAreaInsets();
162
+ const [keyboardHeight, setKeyboardHeight] = useState(0);
163
+ useEffect(() => {
164
+ const showEvent = Platform.OS === "ios" ? "keyboardWillChangeFrame" : "keyboardDidShow";
165
+ const hideEvent = Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
166
+ const onShow = (event) => setKeyboardHeight(event?.endCoordinates?.height ?? 0);
167
+ const onHide = () => setKeyboardHeight(0);
168
+ const showSub = Keyboard.addListener(showEvent, onShow);
169
+ const hideSub = Keyboard.addListener(hideEvent, onHide);
170
+ return () => {
171
+ showSub.remove();
172
+ hideSub.remove();
173
+ };
174
+ }, []);
153
175
  const { viewStyle: externalViewStyle, textStyle: externalTextStyle } = splitStyle(externalStyle);
154
176
  const colors = {
155
177
  border: t("border") || t("gray.300"),
@@ -322,16 +344,14 @@ function Dropdown({
322
344
  onRequestClose: close,
323
345
  children: /* @__PURE__ */ jsx(Pressable, { style: styles.popoverOverlay, onPress: close, children: triggerLayout && (() => {
324
346
  const screen = Dimensions.get("window");
325
- const PANEL_MAX_HEIGHT = 260;
326
- const GAP = 4;
327
- const spaceBelow = screen.height - (triggerLayout.y + triggerLayout.height) - insets.bottom;
328
- const spaceAbove = triggerLayout.y - insets.top;
329
- const openUp = spaceBelow < PANEL_MAX_HEIGHT && spaceAbove > spaceBelow;
330
- const maxHeight = Math.min(
331
- PANEL_MAX_HEIGHT,
332
- openUp ? spaceAbove - GAP : spaceBelow - GAP
333
- );
334
- const top = openUp ? triggerLayout.y - maxHeight - GAP : triggerLayout.y + triggerLayout.height + GAP;
347
+ const { top, maxHeight } = computePanelGeometry({
348
+ screenHeight: screen.height,
349
+ insetTop: insets.top,
350
+ insetBottom: insets.bottom,
351
+ keyboardHeight,
352
+ triggerY: triggerLayout.y,
353
+ triggerHeight: triggerLayout.height
354
+ });
335
355
  return /* @__PURE__ */ jsxs(
336
356
  View,
337
357
  {
@@ -353,20 +373,29 @@ function Dropdown({
353
373
  {
354
374
  value: filterQuery,
355
375
  onChangeText: setFilterQuery,
356
- placeholder: "Search...",
376
+ placeholder: filterPlaceholder,
357
377
  placeholderTextColor: colors.placeholder,
358
- style: [styles.filterInput, {
359
- borderColor: colors.filterBorder,
360
- backgroundColor: colors.filterBg,
361
- color: colors.filterText
362
- }],
378
+ style: [
379
+ styles.filterInput,
380
+ {
381
+ borderColor: colors.filterBorder,
382
+ backgroundColor: colors.filterBg,
383
+ color: colors.filterText
384
+ },
385
+ // Every other input in this library names its own edge
386
+ // and direction from the reader's language. Leaving
387
+ // these unset let the platform decide, so the field
388
+ // followed the process layout direction instead of the
389
+ // person reading it.
390
+ isRTL ? styles.filterRtl : styles.filterLtr
391
+ ],
363
392
  autoFocus: true
364
393
  }
365
394
  ) }),
366
395
  /* @__PURE__ */ jsx(
367
396
  FlatList,
368
397
  {
369
- style: { flex: 1 },
398
+ style: { flexGrow: 0, flexShrink: 1 },
370
399
  contentContainerStyle: { paddingBottom: 12 },
371
400
  data: filteredData,
372
401
  keyExtractor: (item, i) => item?.__group ? `group-${i}` : `item-${i}`,
@@ -394,13 +423,17 @@ function Dropdown({
394
423
  {
395
424
  value: filterQuery,
396
425
  onChangeText: setFilterQuery,
397
- placeholder: "Search...",
426
+ placeholder: filterPlaceholder,
398
427
  placeholderTextColor: colors.placeholder,
399
- style: [styles.filterInput, {
400
- borderColor: colors.filterBorder,
401
- backgroundColor: colors.filterBg,
402
- color: colors.filterText
403
- }],
428
+ style: [
429
+ styles.filterInput,
430
+ {
431
+ borderColor: colors.filterBorder,
432
+ backgroundColor: colors.filterBg,
433
+ color: colors.filterText
434
+ },
435
+ isRTL ? styles.filterRtl : styles.filterLtr
436
+ ],
404
437
  autoFocus: true
405
438
  }
406
439
  ) }),
@@ -479,6 +512,14 @@ const styles = StyleSheet.create({
479
512
  borderWidth: 1,
480
513
  borderRadius: 4
481
514
  },
515
+ filterLtr: {
516
+ textAlign: "left",
517
+ writingDirection: "ltr"
518
+ },
519
+ filterRtl: {
520
+ textAlign: "right",
521
+ writingDirection: "rtl"
522
+ },
482
523
  emptyContainer: {
483
524
  padding: 16,
484
525
  alignItems: "center"