@lmb-it/kitsconcerto-native 0.1.261 → 0.1.262

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.
@@ -29,8 +29,7 @@ const overlayAnimations = {
29
29
  // overshoot. Exit: timed slide-down.
30
30
  sheet: {
31
31
  enter: { damping: 30, stiffness: 400, mass: 1 },
32
- exitDuration: 150
33
- },
32
+ exitDuration: 150},
34
33
  // ── Toast ────────────────────────────────────────────────
35
34
  // One element owns the entrance: FadeInUp/FadeInDown animate opacity AND
36
35
  // translateY together, so there is no second concurrent layer to desync.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../src/animations/index.ts"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════════════\n * Overlay animation tuning — EDIT THIS FILE TO CONTROL ALL OVERLAY MOTION\n * ════════════════════════════════════════════════════════════════════════\n *\n * Every in/out animation value used by the animated overlay components on\n * React Native (reanimated) lives here. Change a number and it updates\n * everywhere that animation is used — no need to touch the component files.\n *\n * Consumed by (native):\n * • components/overlay/Dialog/index.native.tsx\n * • components/overlay/ConfirmDialog/index.native.tsx\n * • components/overlay/Toast/index.native.tsx\n *\n * Two kinds of value:\n * • spring → reanimated `.springify().damping(d).stiffness(s)` (+ optional `.delay`)\n * - damping ↓ lower = bouncier, longer settle\n * - stiffness ↑ higher = snappier, faster\n * • duration → milliseconds for `.duration(ms)` (timing-based fade/slide)\n */\n\nexport interface ISpringConfig {\n /** reanimated `.damping()` — lower = bouncier / slower to settle. */\n damping: number;\n /** reanimated `.stiffness()` — higher = snappier / faster. */\n stiffness: number;\n /** reanimated `.mass()` — heavier = slower / more inertia. Defaults to 1. */\n mass?: number;\n /** reanimated `.delay()` in ms — wait before the animation starts. */\n delay?: number;\n}\n\nexport interface IOverlayAnimations {\n /** Dimmed backdrop behind every overlay (fade in/out). */\n scrim: { enterDuration: number; exitDuration: number };\n /** Centered Dialog panel (zoom-in spring in, timed zoom-out). */\n dialog: { enter: ISpringConfig; exitDuration: number };\n /** Confirm: centered panel, its floating icon bubble, and the content-only/prompt panel. */\n confirm: { enter: ISpringConfig; icon: ISpringConfig; content: ISpringConfig; exitDuration: number };\n /** Bottom sheet shared by Dialog & Confirm (slide-up spring in, timed slide-down out). */\n sheet: { enter: ISpringConfig; exitDuration: number };\n /** Toast — single merged fade+slide entrance, timed exit, re-layout, keyboard gap. */\n toast: {\n enter: ISpringConfig;\n exitDuration: number;\n layoutDuration: number;\n keyboardGap: number;\n };\n}\n\nexport const overlayAnimations: IOverlayAnimations = {\n // ── Backdrop / scrim ─────────────────────────────────────\n scrim: {\n enterDuration: 120,\n exitDuration: 100,\n },\n\n // ── Centered Dialog panel ────────────────────────────────\n // Enter: critically-ish damped spring — snappy but settles cleanly (no\n // ringing). Exit: timing-based zoom-out (springs are enter-only).\n dialog: {\n enter: { damping: 26, stiffness: 420, mass: 1 },\n exitDuration: 120,\n },\n\n // ── Confirm dialog ───────────────────────────────────────\n confirm: {\n /** Centered confirm panel pop. */\n enter: { damping: 26, stiffness: 420, mass: 1 },\n /** Floating severity-icon bubble — pops in slightly after the panel. */\n icon: { damping: 26, stiffness: 420, mass: 1, delay: 60 },\n /** Content-only / prompt panel (no header/buttons chrome). */\n content: { damping: 26, stiffness: 420, mass: 1 },\n /** Timed zoom-out for the confirm center/content panels. */\n exitDuration: 120,\n },\n\n // ── Bottom sheet (Dialog + Confirm, position=\"bottom\") ───\n // Slightly heavier damping/lower stiffness so the sheet glides up without\n // overshoot. Exit: timed slide-down.\n sheet: {\n enter: { damping: 30, stiffness: 400, mass: 1 },\n exitDuration: 150,\n },\n\n // ── Toast ────────────────────────────────────────────────\n // One element owns the entrance: FadeInUp/FadeInDown animate opacity AND\n // translateY together, so there is no second concurrent layer to desync.\n toast: {\n /** Merged fade+slide entrance (position-appropriate direction). */\n enter: { damping: 30, stiffness: 400, mass: 1 },\n /** Timed fade+slide out. */\n exitDuration: 120,\n /** Re-positioning when toasts stack/unstack. */\n layoutDuration: 150,\n /** Gap (pt) kept between a bottom toast and the keyboard when it opens. */\n keyboardGap: 8,\n },\n};\n\nexport default overlayAnimations;\n"],"names":[],"mappings":";;AAkDO,MAAM,iBAAA,GAAwC;AAAA;AAAA,EAEjD,KAAA,EAAO;AAAA,IACH,aAAA,EAAe,GAAA;AAAA,IACf,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA,EAAQ;AAAA,IACJ,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA,EAGA,OAAA,EAAS;AAAA;AAAA,IAEL,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,IAAA,EAAM,EAAE,OAAA,EAAS,EAAA,EAAI,WAAW,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,EAAA,EAAG;AAAA;AAAA,IAExD,SAAS,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAEhD,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA,IACH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA;AAAA,IAEH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,YAAA,EAAc,GAAA;AAAA;AAAA,IAEd,cAAA,EAAgB,GAAA;AAAA;AAAA,IAEhB,WAAA,EAAa;AAAA;AAErB;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../src/animations/index.ts"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════════════\n * Overlay animation tuning — EDIT THIS FILE TO CONTROL ALL OVERLAY MOTION\n * ════════════════════════════════════════════════════════════════════════\n *\n * Every in/out animation value used by the animated overlay components on\n * React Native (reanimated) lives here. Change a number and it updates\n * everywhere that animation is used — no need to touch the component files.\n *\n * Consumed by (native):\n * • components/overlay/Dialog/index.native.tsx\n * • components/overlay/ConfirmDialog/index.native.tsx\n * • components/overlay/Toast/index.native.tsx\n *\n * Two kinds of value:\n * • spring → reanimated `.springify().damping(d).stiffness(s)` (+ optional `.delay`)\n * - damping ↓ lower = bouncier, longer settle\n * - stiffness ↑ higher = snappier, faster\n * • duration → milliseconds for `.duration(ms)` (timing-based fade/slide)\n */\n\nexport interface ISpringConfig {\n /** reanimated `.damping()` — lower = bouncier / slower to settle. */\n damping: number;\n /** reanimated `.stiffness()` — higher = snappier / faster. */\n stiffness: number;\n /** reanimated `.mass()` — heavier = slower / more inertia. Defaults to 1. */\n mass?: number;\n /** reanimated `.delay()` in ms — wait before the animation starts. */\n delay?: number;\n}\n\nexport interface IOverlayAnimations {\n /** Dimmed backdrop behind every overlay (fade in/out). */\n scrim: { enterDuration: number; exitDuration: number };\n /** Centered Dialog panel (zoom-in spring in, timed zoom-out). */\n dialog: { enter: ISpringConfig; exitDuration: number };\n /** Confirm: centered panel, its floating icon bubble, and the content-only/prompt panel. */\n confirm: { enter: ISpringConfig; icon: ISpringConfig; content: ISpringConfig; exitDuration: number };\n /**\n * Bottom sheet shared by Dialog & Confirm (slide-up spring in, timed\n * slide-down out).\n *\n * `keepMotionWhenReduced` asks Reanimated to run this one even when the\n * reader has iOS \"Reduce Motion\" on — see the note beside the value.\n */\n sheet: { enter: ISpringConfig; exitDuration: number; keepMotionWhenReduced: boolean };\n /** Toast — single merged fade+slide entrance, timed exit, re-layout, keyboard gap. */\n toast: {\n enter: ISpringConfig;\n exitDuration: number;\n layoutDuration: number;\n keyboardGap: number;\n };\n}\n\nexport const overlayAnimations: IOverlayAnimations = {\n // ── Backdrop / scrim ─────────────────────────────────────\n scrim: {\n enterDuration: 120,\n exitDuration: 100,\n },\n\n // ── Centered Dialog panel ────────────────────────────────\n // Enter: critically-ish damped spring — snappy but settles cleanly (no\n // ringing). Exit: timing-based zoom-out (springs are enter-only).\n dialog: {\n enter: { damping: 26, stiffness: 420, mass: 1 },\n exitDuration: 120,\n },\n\n // ── Confirm dialog ───────────────────────────────────────\n confirm: {\n /** Centered confirm panel pop. */\n enter: { damping: 26, stiffness: 420, mass: 1 },\n /** Floating severity-icon bubble — pops in slightly after the panel. */\n icon: { damping: 26, stiffness: 420, mass: 1, delay: 60 },\n /** Content-only / prompt panel (no header/buttons chrome). */\n content: { damping: 26, stiffness: 420, mass: 1 },\n /** Timed zoom-out for the confirm center/content panels. */\n exitDuration: 120,\n },\n\n // ── Bottom sheet (Dialog + Confirm, position=\"bottom\") ───\n // Slightly heavier damping/lower stiffness so the sheet glides up without\n // overshoot. Exit: timed slide-down.\n sheet: {\n enter: { damping: 30, stiffness: 400, mass: 1 },\n exitDuration: 150,\n /*\n * ⛔ REDUCE MOTION TURNS THIS OFF, AND THAT READS AS A FADE. Reanimated\n * honours iOS \"Reduce Motion\" by default: the entering/exiting\n * animation is skipped and the panel simply appears, so the only thing\n * left moving is the scrim's opacity. Measured on an iPhone 16 Pro\n * simulator, sheet top edge per frame at 30fps:\n * Reduce Motion OFF — 1924 → 1302 → 898 → 683 → 655 px\n * Reduce Motion ON — 655 in a single frame\n * That second row is exactly the \"it still fades\" report.\n *\n * A bottom sheet is kept moving because the platform keeps it moving:\n * iOS's own sheets still slide up under Reduce Motion — what that\n * setting removes is parallax and zoom, not the presentation of a\n * sheet. The centred Dialog's ZoomIn and the scrim's fade are NOT\n * overridden; they stay on the system default.\n */\n keepMotionWhenReduced: true,\n },\n\n // ── Toast ────────────────────────────────────────────────\n // One element owns the entrance: FadeInUp/FadeInDown animate opacity AND\n // translateY together, so there is no second concurrent layer to desync.\n toast: {\n /** Merged fade+slide entrance (position-appropriate direction). */\n enter: { damping: 30, stiffness: 400, mass: 1 },\n /** Timed fade+slide out. */\n exitDuration: 120,\n /** Re-positioning when toasts stack/unstack. */\n layoutDuration: 150,\n /** Gap (pt) kept between a bottom toast and the keyboard when it opens. */\n keyboardGap: 8,\n },\n};\n\nexport default overlayAnimations;\n"],"names":[],"mappings":";;AAwDO,MAAM,iBAAA,GAAwC;AAAA;AAAA,EAEjD,KAAA,EAAO;AAAA,IACH,aAAA,EAAe,GAAA;AAAA,IACf,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA,EAAQ;AAAA,IACJ,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA,EAGA,OAAA,EAAS;AAAA;AAAA,IAEL,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,IAAA,EAAM,EAAE,OAAA,EAAS,EAAA,EAAI,WAAW,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,EAAA,EAAG;AAAA;AAAA,IAExD,SAAS,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAEhD,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA,IACH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc,GAkBlB,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA;AAAA,IAEH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,YAAA,EAAc,GAAA;AAAA;AAAA,IAEd,cAAA,EAAgB,GAAA;AAAA;AAAA,IAEhB,WAAA,EAAa;AAAA;AAErB;;;;"}
@@ -27,8 +27,7 @@ const overlayAnimations = {
27
27
  // overshoot. Exit: timed slide-down.
28
28
  sheet: {
29
29
  enter: { damping: 30, stiffness: 400, mass: 1 },
30
- exitDuration: 150
31
- },
30
+ exitDuration: 150},
32
31
  // ── Toast ────────────────────────────────────────────────
33
32
  // One element owns the entrance: FadeInUp/FadeInDown animate opacity AND
34
33
  // translateY together, so there is no second concurrent layer to desync.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/animations/index.ts"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════════════\n * Overlay animation tuning — EDIT THIS FILE TO CONTROL ALL OVERLAY MOTION\n * ════════════════════════════════════════════════════════════════════════\n *\n * Every in/out animation value used by the animated overlay components on\n * React Native (reanimated) lives here. Change a number and it updates\n * everywhere that animation is used — no need to touch the component files.\n *\n * Consumed by (native):\n * • components/overlay/Dialog/index.native.tsx\n * • components/overlay/ConfirmDialog/index.native.tsx\n * • components/overlay/Toast/index.native.tsx\n *\n * Two kinds of value:\n * • spring → reanimated `.springify().damping(d).stiffness(s)` (+ optional `.delay`)\n * - damping ↓ lower = bouncier, longer settle\n * - stiffness ↑ higher = snappier, faster\n * • duration → milliseconds for `.duration(ms)` (timing-based fade/slide)\n */\n\nexport interface ISpringConfig {\n /** reanimated `.damping()` — lower = bouncier / slower to settle. */\n damping: number;\n /** reanimated `.stiffness()` — higher = snappier / faster. */\n stiffness: number;\n /** reanimated `.mass()` — heavier = slower / more inertia. Defaults to 1. */\n mass?: number;\n /** reanimated `.delay()` in ms — wait before the animation starts. */\n delay?: number;\n}\n\nexport interface IOverlayAnimations {\n /** Dimmed backdrop behind every overlay (fade in/out). */\n scrim: { enterDuration: number; exitDuration: number };\n /** Centered Dialog panel (zoom-in spring in, timed zoom-out). */\n dialog: { enter: ISpringConfig; exitDuration: number };\n /** Confirm: centered panel, its floating icon bubble, and the content-only/prompt panel. */\n confirm: { enter: ISpringConfig; icon: ISpringConfig; content: ISpringConfig; exitDuration: number };\n /** Bottom sheet shared by Dialog & Confirm (slide-up spring in, timed slide-down out). */\n sheet: { enter: ISpringConfig; exitDuration: number };\n /** Toast — single merged fade+slide entrance, timed exit, re-layout, keyboard gap. */\n toast: {\n enter: ISpringConfig;\n exitDuration: number;\n layoutDuration: number;\n keyboardGap: number;\n };\n}\n\nexport const overlayAnimations: IOverlayAnimations = {\n // ── Backdrop / scrim ─────────────────────────────────────\n scrim: {\n enterDuration: 120,\n exitDuration: 100,\n },\n\n // ── Centered Dialog panel ────────────────────────────────\n // Enter: critically-ish damped spring — snappy but settles cleanly (no\n // ringing). Exit: timing-based zoom-out (springs are enter-only).\n dialog: {\n enter: { damping: 26, stiffness: 420, mass: 1 },\n exitDuration: 120,\n },\n\n // ── Confirm dialog ───────────────────────────────────────\n confirm: {\n /** Centered confirm panel pop. */\n enter: { damping: 26, stiffness: 420, mass: 1 },\n /** Floating severity-icon bubble — pops in slightly after the panel. */\n icon: { damping: 26, stiffness: 420, mass: 1, delay: 60 },\n /** Content-only / prompt panel (no header/buttons chrome). */\n content: { damping: 26, stiffness: 420, mass: 1 },\n /** Timed zoom-out for the confirm center/content panels. */\n exitDuration: 120,\n },\n\n // ── Bottom sheet (Dialog + Confirm, position=\"bottom\") ───\n // Slightly heavier damping/lower stiffness so the sheet glides up without\n // overshoot. Exit: timed slide-down.\n sheet: {\n enter: { damping: 30, stiffness: 400, mass: 1 },\n exitDuration: 150,\n },\n\n // ── Toast ────────────────────────────────────────────────\n // One element owns the entrance: FadeInUp/FadeInDown animate opacity AND\n // translateY together, so there is no second concurrent layer to desync.\n toast: {\n /** Merged fade+slide entrance (position-appropriate direction). */\n enter: { damping: 30, stiffness: 400, mass: 1 },\n /** Timed fade+slide out. */\n exitDuration: 120,\n /** Re-positioning when toasts stack/unstack. */\n layoutDuration: 150,\n /** Gap (pt) kept between a bottom toast and the keyboard when it opens. */\n keyboardGap: 8,\n },\n};\n\nexport default overlayAnimations;\n"],"names":[],"mappings":"AAkDO,MAAM,iBAAA,GAAwC;AAAA;AAAA,EAEjD,KAAA,EAAO;AAAA,IACH,aAAA,EAAe,GAAA;AAAA,IACf,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA,EAAQ;AAAA,IACJ,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA,EAGA,OAAA,EAAS;AAAA;AAAA,IAEL,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,IAAA,EAAM,EAAE,OAAA,EAAS,EAAA,EAAI,WAAW,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,EAAA,EAAG;AAAA;AAAA,IAExD,SAAS,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAEhD,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA,IACH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA;AAAA,IAEH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,YAAA,EAAc,GAAA;AAAA;AAAA,IAEd,cAAA,EAAgB,GAAA;AAAA;AAAA,IAEhB,WAAA,EAAa;AAAA;AAErB;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/animations/index.ts"],"sourcesContent":["/**\n * ════════════════════════════════════════════════════════════════════════\n * Overlay animation tuning — EDIT THIS FILE TO CONTROL ALL OVERLAY MOTION\n * ════════════════════════════════════════════════════════════════════════\n *\n * Every in/out animation value used by the animated overlay components on\n * React Native (reanimated) lives here. Change a number and it updates\n * everywhere that animation is used — no need to touch the component files.\n *\n * Consumed by (native):\n * • components/overlay/Dialog/index.native.tsx\n * • components/overlay/ConfirmDialog/index.native.tsx\n * • components/overlay/Toast/index.native.tsx\n *\n * Two kinds of value:\n * • spring → reanimated `.springify().damping(d).stiffness(s)` (+ optional `.delay`)\n * - damping ↓ lower = bouncier, longer settle\n * - stiffness ↑ higher = snappier, faster\n * • duration → milliseconds for `.duration(ms)` (timing-based fade/slide)\n */\n\nexport interface ISpringConfig {\n /** reanimated `.damping()` — lower = bouncier / slower to settle. */\n damping: number;\n /** reanimated `.stiffness()` — higher = snappier / faster. */\n stiffness: number;\n /** reanimated `.mass()` — heavier = slower / more inertia. Defaults to 1. */\n mass?: number;\n /** reanimated `.delay()` in ms — wait before the animation starts. */\n delay?: number;\n}\n\nexport interface IOverlayAnimations {\n /** Dimmed backdrop behind every overlay (fade in/out). */\n scrim: { enterDuration: number; exitDuration: number };\n /** Centered Dialog panel (zoom-in spring in, timed zoom-out). */\n dialog: { enter: ISpringConfig; exitDuration: number };\n /** Confirm: centered panel, its floating icon bubble, and the content-only/prompt panel. */\n confirm: { enter: ISpringConfig; icon: ISpringConfig; content: ISpringConfig; exitDuration: number };\n /**\n * Bottom sheet shared by Dialog & Confirm (slide-up spring in, timed\n * slide-down out).\n *\n * `keepMotionWhenReduced` asks Reanimated to run this one even when the\n * reader has iOS \"Reduce Motion\" on — see the note beside the value.\n */\n sheet: { enter: ISpringConfig; exitDuration: number; keepMotionWhenReduced: boolean };\n /** Toast — single merged fade+slide entrance, timed exit, re-layout, keyboard gap. */\n toast: {\n enter: ISpringConfig;\n exitDuration: number;\n layoutDuration: number;\n keyboardGap: number;\n };\n}\n\nexport const overlayAnimations: IOverlayAnimations = {\n // ── Backdrop / scrim ─────────────────────────────────────\n scrim: {\n enterDuration: 120,\n exitDuration: 100,\n },\n\n // ── Centered Dialog panel ────────────────────────────────\n // Enter: critically-ish damped spring — snappy but settles cleanly (no\n // ringing). Exit: timing-based zoom-out (springs are enter-only).\n dialog: {\n enter: { damping: 26, stiffness: 420, mass: 1 },\n exitDuration: 120,\n },\n\n // ── Confirm dialog ───────────────────────────────────────\n confirm: {\n /** Centered confirm panel pop. */\n enter: { damping: 26, stiffness: 420, mass: 1 },\n /** Floating severity-icon bubble — pops in slightly after the panel. */\n icon: { damping: 26, stiffness: 420, mass: 1, delay: 60 },\n /** Content-only / prompt panel (no header/buttons chrome). */\n content: { damping: 26, stiffness: 420, mass: 1 },\n /** Timed zoom-out for the confirm center/content panels. */\n exitDuration: 120,\n },\n\n // ── Bottom sheet (Dialog + Confirm, position=\"bottom\") ───\n // Slightly heavier damping/lower stiffness so the sheet glides up without\n // overshoot. Exit: timed slide-down.\n sheet: {\n enter: { damping: 30, stiffness: 400, mass: 1 },\n exitDuration: 150,\n /*\n * ⛔ REDUCE MOTION TURNS THIS OFF, AND THAT READS AS A FADE. Reanimated\n * honours iOS \"Reduce Motion\" by default: the entering/exiting\n * animation is skipped and the panel simply appears, so the only thing\n * left moving is the scrim's opacity. Measured on an iPhone 16 Pro\n * simulator, sheet top edge per frame at 30fps:\n * Reduce Motion OFF — 1924 → 1302 → 898 → 683 → 655 px\n * Reduce Motion ON — 655 in a single frame\n * That second row is exactly the \"it still fades\" report.\n *\n * A bottom sheet is kept moving because the platform keeps it moving:\n * iOS's own sheets still slide up under Reduce Motion — what that\n * setting removes is parallax and zoom, not the presentation of a\n * sheet. The centred Dialog's ZoomIn and the scrim's fade are NOT\n * overridden; they stay on the system default.\n */\n keepMotionWhenReduced: true,\n },\n\n // ── Toast ────────────────────────────────────────────────\n // One element owns the entrance: FadeInUp/FadeInDown animate opacity AND\n // translateY together, so there is no second concurrent layer to desync.\n toast: {\n /** Merged fade+slide entrance (position-appropriate direction). */\n enter: { damping: 30, stiffness: 400, mass: 1 },\n /** Timed fade+slide out. */\n exitDuration: 120,\n /** Re-positioning when toasts stack/unstack. */\n layoutDuration: 150,\n /** Gap (pt) kept between a bottom toast and the keyboard when it opens. */\n keyboardGap: 8,\n },\n};\n\nexport default overlayAnimations;\n"],"names":[],"mappings":"AAwDO,MAAM,iBAAA,GAAwC;AAAA;AAAA,EAEjD,KAAA,EAAO;AAAA,IACH,aAAA,EAAe,GAAA;AAAA,IACf,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAA,EAAQ;AAAA,IACJ,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA,EAGA,OAAA,EAAS;AAAA;AAAA,IAEL,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,IAAA,EAAM,EAAE,OAAA,EAAS,EAAA,EAAI,WAAW,GAAA,EAAK,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,EAAA,EAAG;AAAA;AAAA,IAExD,SAAS,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAEhD,YAAA,EAAc;AAAA,GAClB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA,IACH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA,IAC9C,YAAA,EAAc,GAkBlB,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA;AAAA,IAEH,OAAO,EAAE,OAAA,EAAS,IAAI,SAAA,EAAW,GAAA,EAAK,MAAM,CAAA,EAAE;AAAA;AAAA,IAE9C,YAAA,EAAc,GAAA;AAAA;AAAA,IAEd,cAAA,EAAgB,GAAA;AAAA;AAAA,IAEhB,WAAA,EAAa;AAAA;AAErB;;;;"}
@@ -150,6 +150,7 @@ function Dropdown({
150
150
  emptyFilterMessage = "No results found",
151
151
  filterPlaceholder = "Search...",
152
152
  isRTL = false,
153
+ fontFamily,
153
154
  popup = false,
154
155
  renderPopup,
155
156
  popupTitle,
@@ -243,9 +244,16 @@ function Dropdown({
243
244
  content = React.isValidElement(rendered) ? rendered : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children: String(rendered ?? "") });
244
245
  } else {
245
246
  content = /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
246
- { color: colors.text, fontSize: optionFontSize() },
247
- // A consumer-supplied size still wins over the scale.
248
- externalTextStyle && externalTextStyle.fontSize ? { fontSize: externalTextStyle.fontSize } : null
247
+ {
248
+ color: colors.text,
249
+ fontSize: optionFontSize(),
250
+ fontFamily
251
+ },
252
+ /* The row starts at the reader's edge. A label that opens with a
253
+ flag — "🇦🇺 +61 (AU)" — then puts the flag where an Arabic reader
254
+ starts reading, which is the right. Left unset the row inherited,
255
+ and the flag sat on the far side of the row from the reader. */
256
+ isRTL ? styles.optionRtl : styles.optionLtr
249
257
  ], children: getLabel(item, optionLabel) });
250
258
  }
251
259
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -254,6 +262,15 @@ function Dropdown({
254
262
  onPress: () => selectItem(item),
255
263
  style: [
256
264
  styles.option,
265
+ /* ⛔ `textAlign` ALONE CANNOT MOVE THIS ROW. The row is a flex row
266
+ and the label shrink-wraps, so the line box is only as wide as
267
+ its glyphs and aligning text inside it changes nothing — the box
268
+ itself still sits at the row's start. The process layout stays
269
+ LTR (the reader's language is a KitsConcerto concern, not
270
+ `I18nManager`), so `flex-start` is the left. Reversing the row is
271
+ what actually moves the label, and the checkmark, to the edge an
272
+ Arabic reader starts from. */
273
+ isRTL && styles.optionRowRtl,
257
274
  selected && highlightOnSelect && { backgroundColor: colors.optionSelected }
258
275
  ],
259
276
  children: [
@@ -309,7 +326,8 @@ function Dropdown({
309
326
  {
310
327
  borderColor: colors.filterBorder,
311
328
  backgroundColor: colors.filterBg,
312
- color: colors.filterText
329
+ color: colors.filterText,
330
+ fontFamily
313
331
  },
314
332
  // Every other input in this library names its own edge and
315
333
  // direction from the reader's language. Leaving these unset let the
@@ -330,7 +348,7 @@ function Dropdown({
330
348
  renderItem: ({ item, index }) => renderItem(item, index),
331
349
  keyboardShouldPersistTaps: "handled",
332
350
  showsHorizontalScrollIndicator: false,
333
- ListEmptyComponent: filterQuery ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.emptyContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.emptyText, { color: colors.emptyText }], children: emptyFilterMessage }) }) : null
351
+ ListEmptyComponent: filterQuery ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles.emptyContainer, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles.emptyText, { color: colors.emptyText, fontFamily }], children: emptyFilterMessage }) }) : null
334
352
  }
335
353
  ),
336
354
  panelFooterTemplate?.()
@@ -482,6 +500,22 @@ const styles = reactNative.StyleSheet.create({
482
500
  paddingVertical: 6,
483
501
  borderBottomWidth: 1
484
502
  },
503
+ optionLtr: {
504
+ // `flex: 1` makes the line box span the row, so `textAlign` has something
505
+ // to align within. Without it the box hugs the glyphs and alignment is a
506
+ // no-op.
507
+ flex: 1,
508
+ textAlign: "left",
509
+ writingDirection: "ltr"
510
+ },
511
+ optionRowRtl: {
512
+ flexDirection: "row-reverse"
513
+ },
514
+ optionRtl: {
515
+ flex: 1,
516
+ textAlign: "right",
517
+ writingDirection: "rtl"
518
+ },
485
519
  listFill: {
486
520
  flex: 1
487
521
  },
@@ -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, toNativeValue } from '../../Factory/helpers/style';\nimport { useKeyboardHeight } from '../../Factory/helpers/useKeyboardHeight';\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 * Open the options in a popup that owns the screen instead of a panel\n * anchored to the trigger.\n *\n * ⛔ THE ANCHOR IS THE PROBLEM THIS ESCAPES. An anchored panel can never be\n * taller than the gap between the trigger and the keyboard, and a field in\n * the middle of a form has ~190pt of gap on a 874pt phone — a search box and\n * four rows. Sizing that gap correctly does not make it big. The popup takes\n * a fixed share of the window instead, so where the field sits stops\n * mattering.\n *\n * Default false: every existing consumer keeps the anchored panel.\n */\n popup?: boolean;\n /**\n * Supplies the popup's container. Injected by the KitsConcerto wrapper\n * because the container is this library's `KitsDialogControlled`, which\n * lives in `packages/ui` — and `packages/ui` imports THIS file, so importing\n * it back would be a cycle between the two workspaces.\n *\n * Without it `popup` falls back to the anchored panel rather than rendering\n * nothing.\n */\n renderPopup?: (args: {\n visible: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n }) => React.ReactNode;\n /** Title for the popup header. The wrapper passes the field's label. */\n popupTitle?: React.ReactNode;\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\n/**\n * Option-row text size, taken from the theme's own scale rather than picked.\n *\n * The rows used to set no `fontSize` at all, so they fell through to React\n * Native's default of 14 — which happens to equal the scale's `sm` step, by\n * coincidence rather than intent. `md` is the scale's body size and one step\n * up. `$fontSizes.md` resolves to '1rem' and `toNativeValue` turns that into\n * 16; the `?? 16` is the same number spelled out, for the case where a\n * consumer's theme does not declare the step.\n */\nconst optionFontSize = (): number => {\n const resolved = toNativeValue(resolveThemeTokenForNative('$fontSizes.md'));\n return typeof resolved === 'number' ? resolved : 16;\n};\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 popup = false,\n renderPopup,\n popupTitle,\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 = useKeyboardHeight();\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={[\n { color: colors.text, fontSize: optionFontSize() },\n // A consumer-supplied size still wins over the scale.\n externalTextStyle && externalTextStyle.fontSize ? { fontSize: externalTextStyle.fontSize } : null,\n ]}>\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 Panel body — the search field and the list\n ---------------------------------------------- */\n\n /*\n * ⛔ ONE BODY, THREE CONTAINERS. The anchored panel and the centred modal\n * each carried their own copy of this markup, which is why the hardcoded\n * \"Search...\" had to be found and fixed twice. The popup would have made it\n * three. The containers differ; what is inside them does not.\n *\n * `fill` is the one real difference. In the anchored panel the container has\n * a `maxHeight` and no height, so the list must shrink-wrap its content up\n * to that ceiling (`flexShrink`). In the popup and the centred modal the\n * container has a real height, so the list takes what is left (`flex: 1`).\n */\n const panelBody = (fill: boolean, autoFocusFilter: boolean) => (\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 and\n // direction from the reader's language. Leaving these unset let the\n // platform decide, so the field followed the process layout\n // direction instead of the person reading it.\n isRTL ? styles.filterRtl : styles.filterLtr]}\n /* ⛔ THE ANCHORED PANEL KEEPS ITS AUTOFOCUS — changing it would\n change behaviour for every consumer that has not opted in. In\n the popup the list is already the whole point and is fully\n visible, so the keyboard waits to be asked for: one tap on the\n field raises it, and until then the list has the whole sheet. */\n autoFocus={autoFocusFilter}\n />\n </View>\n )}\n <FlatList\n style={fill ? styles.listFill : styles.listShrink}\n contentContainerStyle={styles.listContent}\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 </>\n );\n\n /* ---------------------------------------------\n Render\n ---------------------------------------------- */\n\n const usePopup = popup && typeof renderPopup === 'function';\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 {!usePopup && !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 {panelBody(false, true)}\n </View>\n );\n })()}\n </Pressable>\n </Modal>\n )}\n\n {!usePopup && 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 {panelBody(true, true)}\n </View>\n </Pressable>\n </Modal>\n )}\n\n {/* Popup — the container comes from the wrapper (this library's own\n Dialog in sheet position); everything inside it is the same body the\n other two containers render. */}\n {usePopup && renderPopup!({\n visible: open,\n onClose: close,\n title: popupTitle,\n children: panelBody(true, false),\n })}\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 listFill: {\n flex: 1,\n },\n // The anchored panel is sized by `maxHeight` with no height, so the list has\n // to grow with its content up to that ceiling and then scroll inside it.\n // `flex: 1` sets flexBasis 0, which contributes nothing to a shrink-wrapping\n // parent.\n listShrink: {\n flexGrow: 0,\n flexShrink: 1,\n },\n listContent: {\n paddingBottom: 12,\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","toNativeValue","useRef","useState","useSafeAreaInsets","useKeyboardHeight","useMemo","Keyboard","useCallback","jsx","Text","jsxs","Pressable","Fragment","View","TextInput","FlatList","Input","InputField","Modal","Dimensions","computePanelGeometry","StyleSheet"],"mappings":"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"}
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, toNativeValue } from '../../Factory/helpers/style';\nimport { useKeyboardHeight } from '../../Factory/helpers/useKeyboardHeight';\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 * Open the options in a popup that owns the screen instead of a panel\n * anchored to the trigger.\n *\n * ⛔ THE ANCHOR IS THE PROBLEM THIS ESCAPES. An anchored panel can never be\n * taller than the gap between the trigger and the keyboard, and a field in\n * the middle of a form has ~190pt of gap on a 874pt phone — a search box and\n * four rows. Sizing that gap correctly does not make it big. The popup takes\n * a fixed share of the window instead, so where the field sits stops\n * mattering.\n *\n * Default false: every existing consumer keeps the anchored panel.\n */\n popup?: boolean;\n /**\n * Supplies the popup's container. Injected by the KitsConcerto wrapper\n * because the container is this library's `KitsDialogControlled`, which\n * lives in `packages/ui` — and `packages/ui` imports THIS file, so importing\n * it back would be a cycle between the two workspaces.\n *\n * Without it `popup` falls back to the anchored panel rather than rendering\n * nothing.\n */\n renderPopup?: (args: {\n visible: boolean;\n onClose: () => void;\n title?: React.ReactNode;\n children: React.ReactNode;\n }) => React.ReactNode;\n /** Title for the popup header. The wrapper passes the field's label. */\n popupTitle?: React.ReactNode;\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 * Font family the consuming app's theme names for body text, resolved by the\n * KitsConcerto wrapper with `useThemedFont('body')`.\n *\n * ⛔ React Native does NOT cascade `fontFamily` through View parents, so\n * every text sink has to set it. The panel's rows and its search field set\n * none, which is why an app that swaps in its own face — AlphaMatch loads\n * Noto Kufi Arabic for its Arabic readers — saw that face everywhere except\n * inside the picker.\n */\n fontFamily?: 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\n/**\n * Option-row text size, taken from the theme's own scale rather than picked.\n *\n * The rows used to set no `fontSize` at all, so they fell through to React\n * Native's default of 14 — which happens to equal the scale's `sm` step, by\n * coincidence rather than intent. `md` is the scale's body size and one step\n * up. `$fontSizes.md` resolves to '1rem' and `toNativeValue` turns that into\n * 16; the `?? 16` is the same number spelled out, for the case where a\n * consumer's theme does not declare the step.\n */\nconst optionFontSize = (): number => {\n const resolved = toNativeValue(resolveThemeTokenForNative('$fontSizes.md'));\n return typeof resolved === 'number' ? resolved : 16;\n};\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 fontFamily,\n popup = false,\n renderPopup,\n popupTitle,\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 = useKeyboardHeight();\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={[\n {\n color: colors.text,\n fontSize: optionFontSize(),\n fontFamily,\n },\n /* The row starts at the reader's edge. A label that opens with a\n flag — \"🇦🇺 +61 (AU)\" — then puts the flag where an Arabic reader\n starts reading, which is the right. Left unset the row inherited,\n and the flag sat on the far side of the row from the reader. */\n isRTL ? styles.optionRtl : styles.optionLtr,\n ]}>\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 /* ⛔ `textAlign` ALONE CANNOT MOVE THIS ROW. The row is a flex row\n and the label shrink-wraps, so the line box is only as wide as\n its glyphs and aligning text inside it changes nothing — the box\n itself still sits at the row's start. The process layout stays\n LTR (the reader's language is a KitsConcerto concern, not\n `I18nManager`), so `flex-start` is the left. Reversing the row is\n what actually moves the label, and the checkmark, to the edge an\n Arabic reader starts from. */\n isRTL && styles.optionRowRtl,\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 Panel body — the search field and the list\n ---------------------------------------------- */\n\n /*\n * ⛔ ONE BODY, THREE CONTAINERS. The anchored panel and the centred modal\n * each carried their own copy of this markup, which is why the hardcoded\n * \"Search...\" had to be found and fixed twice. The popup would have made it\n * three. The containers differ; what is inside them does not.\n *\n * `fill` is the one real difference. In the anchored panel the container has\n * a `maxHeight` and no height, so the list must shrink-wrap its content up\n * to that ceiling (`flexShrink`). In the popup and the centred modal the\n * container has a real height, so the list takes what is left (`flex: 1`).\n */\n const panelBody = (fill: boolean, autoFocusFilter: boolean) => (\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 fontFamily,\n },\n // Every other input in this library names its own edge and\n // direction from the reader's language. Leaving these unset let the\n // platform decide, so the field followed the process layout\n // direction instead of the person reading it.\n isRTL ? styles.filterRtl : styles.filterLtr]}\n /* ⛔ THE ANCHORED PANEL KEEPS ITS AUTOFOCUS — changing it would\n change behaviour for every consumer that has not opted in. In\n the popup the list is already the whole point and is fully\n visible, so the keyboard waits to be asked for: one tap on the\n field raises it, and until then the list has the whole sheet. */\n autoFocus={autoFocusFilter}\n />\n </View>\n )}\n <FlatList\n style={fill ? styles.listFill : styles.listShrink}\n contentContainerStyle={styles.listContent}\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, fontFamily }]}>{emptyFilterMessage}</Text>\n </View>\n ) : null\n }\n />\n {panelFooterTemplate?.()}\n </>\n );\n\n /* ---------------------------------------------\n Render\n ---------------------------------------------- */\n\n const usePopup = popup && typeof renderPopup === 'function';\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 {!usePopup && !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 {panelBody(false, true)}\n </View>\n );\n })()}\n </Pressable>\n </Modal>\n )}\n\n {!usePopup && 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 {panelBody(true, true)}\n </View>\n </Pressable>\n </Modal>\n )}\n\n {/* Popup — the container comes from the wrapper (this library's own\n Dialog in sheet position); everything inside it is the same body the\n other two containers render. */}\n {usePopup && renderPopup!({\n visible: open,\n onClose: close,\n title: popupTitle,\n children: panelBody(true, false),\n })}\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 optionLtr: {\n // `flex: 1` makes the line box span the row, so `textAlign` has something\n // to align within. Without it the box hugs the glyphs and alignment is a\n // no-op.\n flex: 1,\n textAlign: 'left' as const,\n writingDirection: 'ltr' as const,\n },\n optionRowRtl: {\n flexDirection: 'row-reverse' as const,\n },\n optionRtl: {\n flex: 1,\n textAlign: 'right' as const,\n writingDirection: 'rtl' as const,\n },\n listFill: {\n flex: 1,\n },\n // The anchored panel is sized by `maxHeight` with no height, so the list has\n // to grow with its content up to that ceiling and then scroll inside it.\n // `flex: 1` sets flexBasis 0, which contributes nothing to a shrink-wrapping\n // parent.\n listShrink: {\n flexGrow: 0,\n flexShrink: 1,\n },\n listContent: {\n paddingBottom: 12,\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","toNativeValue","useRef","useState","useSafeAreaInsets","useKeyboardHeight","useMemo","Keyboard","useCallback","jsx","Text","jsxs","Pressable","Fragment","View","TextInput","FlatList","Input","InputField","Modal","Dimensions","computePanelGeometry","StyleSheet"],"mappings":"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"}
@@ -146,6 +146,7 @@ function Dropdown({
146
146
  emptyFilterMessage = "No results found",
147
147
  filterPlaceholder = "Search...",
148
148
  isRTL = false,
149
+ fontFamily,
149
150
  popup = false,
150
151
  renderPopup,
151
152
  popupTitle,
@@ -239,9 +240,16 @@ function Dropdown({
239
240
  content = React.isValidElement(rendered) ? rendered : /* @__PURE__ */ jsx(Text, { children: String(rendered ?? "") });
240
241
  } else {
241
242
  content = /* @__PURE__ */ jsx(Text, { style: [
242
- { color: colors.text, fontSize: optionFontSize() },
243
- // A consumer-supplied size still wins over the scale.
244
- externalTextStyle && externalTextStyle.fontSize ? { fontSize: externalTextStyle.fontSize } : null
243
+ {
244
+ color: colors.text,
245
+ fontSize: optionFontSize(),
246
+ fontFamily
247
+ },
248
+ /* The row starts at the reader's edge. A label that opens with a
249
+ flag — "🇦🇺 +61 (AU)" — then puts the flag where an Arabic reader
250
+ starts reading, which is the right. Left unset the row inherited,
251
+ and the flag sat on the far side of the row from the reader. */
252
+ isRTL ? styles.optionRtl : styles.optionLtr
245
253
  ], children: getLabel(item, optionLabel) });
246
254
  }
247
255
  return /* @__PURE__ */ jsxs(
@@ -250,6 +258,15 @@ function Dropdown({
250
258
  onPress: () => selectItem(item),
251
259
  style: [
252
260
  styles.option,
261
+ /* ⛔ `textAlign` ALONE CANNOT MOVE THIS ROW. The row is a flex row
262
+ and the label shrink-wraps, so the line box is only as wide as
263
+ its glyphs and aligning text inside it changes nothing — the box
264
+ itself still sits at the row's start. The process layout stays
265
+ LTR (the reader's language is a KitsConcerto concern, not
266
+ `I18nManager`), so `flex-start` is the left. Reversing the row is
267
+ what actually moves the label, and the checkmark, to the edge an
268
+ Arabic reader starts from. */
269
+ isRTL && styles.optionRowRtl,
253
270
  selected && highlightOnSelect && { backgroundColor: colors.optionSelected }
254
271
  ],
255
272
  children: [
@@ -305,7 +322,8 @@ function Dropdown({
305
322
  {
306
323
  borderColor: colors.filterBorder,
307
324
  backgroundColor: colors.filterBg,
308
- color: colors.filterText
325
+ color: colors.filterText,
326
+ fontFamily
309
327
  },
310
328
  // Every other input in this library names its own edge and
311
329
  // direction from the reader's language. Leaving these unset let the
@@ -326,7 +344,7 @@ function Dropdown({
326
344
  renderItem: ({ item, index }) => renderItem(item, index),
327
345
  keyboardShouldPersistTaps: "handled",
328
346
  showsHorizontalScrollIndicator: false,
329
- ListEmptyComponent: filterQuery ? /* @__PURE__ */ jsx(View, { style: styles.emptyContainer, children: /* @__PURE__ */ jsx(Text, { style: [styles.emptyText, { color: colors.emptyText }], children: emptyFilterMessage }) }) : null
347
+ ListEmptyComponent: filterQuery ? /* @__PURE__ */ jsx(View, { style: styles.emptyContainer, children: /* @__PURE__ */ jsx(Text, { style: [styles.emptyText, { color: colors.emptyText, fontFamily }], children: emptyFilterMessage }) }) : null
330
348
  }
331
349
  ),
332
350
  panelFooterTemplate?.()
@@ -478,6 +496,22 @@ const styles = StyleSheet.create({
478
496
  paddingVertical: 6,
479
497
  borderBottomWidth: 1
480
498
  },
499
+ optionLtr: {
500
+ // `flex: 1` makes the line box span the row, so `textAlign` has something
501
+ // to align within. Without it the box hugs the glyphs and alignment is a
502
+ // no-op.
503
+ flex: 1,
504
+ textAlign: "left",
505
+ writingDirection: "ltr"
506
+ },
507
+ optionRowRtl: {
508
+ flexDirection: "row-reverse"
509
+ },
510
+ optionRtl: {
511
+ flex: 1,
512
+ textAlign: "right",
513
+ writingDirection: "rtl"
514
+ },
481
515
  listFill: {
482
516
  flex: 1
483
517
  },