@elliemae/ds-app-picker 3.70.0-next.7 → 3.70.0-next.71

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 (132) hide show
  1. package/dist/cjs/DSAppPicker.js +10 -141
  2. package/dist/cjs/DSAppPicker.js.map +3 -3
  3. package/dist/cjs/{utils.js → DSAppPickerCTX.js} +8 -25
  4. package/dist/cjs/DSAppPickerCTX.js.map +7 -0
  5. package/dist/cjs/config/useAppPicker.js +25 -8
  6. package/dist/cjs/config/useAppPicker.js.map +3 -3
  7. package/dist/cjs/config/useFocusTracker.js +104 -0
  8. package/dist/cjs/config/useFocusTracker.js.map +7 -0
  9. package/dist/cjs/config/useValidateProps.js +63 -0
  10. package/dist/cjs/config/useValidateProps.js.map +7 -0
  11. package/dist/cjs/constants/index.js +11 -1
  12. package/dist/cjs/constants/index.js.map +2 -2
  13. package/dist/cjs/index.js +8 -1
  14. package/dist/cjs/index.js.map +3 -3
  15. package/dist/cjs/package.json +1 -4
  16. package/dist/cjs/parts/AppPanel.js +143 -0
  17. package/dist/cjs/parts/AppPanel.js.map +7 -0
  18. package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js +104 -0
  19. package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js.map +7 -0
  20. package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +195 -0
  21. package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +7 -0
  22. package/dist/cjs/parts/AppPickerItem.js +104 -0
  23. package/dist/cjs/parts/AppPickerItem.js.map +7 -0
  24. package/dist/cjs/parts/AppSection.js +95 -0
  25. package/dist/cjs/parts/AppSection.js.map +7 -0
  26. package/dist/cjs/parts/Trigger.js +83 -0
  27. package/dist/cjs/parts/Trigger.js.map +7 -0
  28. package/dist/cjs/parts/shared-styles.js +44 -0
  29. package/dist/cjs/parts/shared-styles.js.map +7 -0
  30. package/dist/cjs/react-desc-prop-types.js +28 -8
  31. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  32. package/dist/cjs/typescript-testing/slot-props.js +48 -0
  33. package/dist/cjs/typescript-testing/slot-props.js.map +7 -0
  34. package/dist/cjs/typescript-testing/typescript-app-picker-valid.js +15 -2
  35. package/dist/cjs/typescript-testing/typescript-app-picker-valid.js.map +2 -2
  36. package/dist/cjs/util/getChipId.js +36 -0
  37. package/dist/cjs/util/getChipId.js.map +7 -0
  38. package/dist/cjs/util/getChipRegionId.js +37 -0
  39. package/dist/cjs/util/getChipRegionId.js.map +7 -0
  40. package/dist/cjs/util/getDSAppPickerContractProps.js +38 -0
  41. package/dist/cjs/util/getDSAppPickerContractProps.js.map +7 -0
  42. package/dist/cjs/util/instanceIds.js +42 -0
  43. package/dist/cjs/util/instanceIds.js.map +7 -0
  44. package/dist/esm/DSAppPicker.js +10 -141
  45. package/dist/esm/DSAppPicker.js.map +3 -3
  46. package/dist/esm/DSAppPickerCTX.js +8 -0
  47. package/dist/esm/DSAppPickerCTX.js.map +7 -0
  48. package/dist/esm/config/useAppPicker.js +29 -13
  49. package/dist/esm/config/useAppPicker.js.map +3 -3
  50. package/dist/esm/config/useFocusTracker.js +74 -0
  51. package/dist/esm/config/useFocusTracker.js.map +7 -0
  52. package/dist/esm/config/useValidateProps.js +33 -0
  53. package/dist/esm/config/useValidateProps.js.map +7 -0
  54. package/dist/esm/constants/index.js +11 -1
  55. package/dist/esm/constants/index.js.map +2 -2
  56. package/dist/esm/index.js +13 -1
  57. package/dist/esm/index.js.map +3 -3
  58. package/dist/esm/package.json +1 -4
  59. package/dist/esm/parts/AppPanel.js +118 -0
  60. package/dist/esm/parts/AppPanel.js.map +7 -0
  61. package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js +74 -0
  62. package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js.map +7 -0
  63. package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +165 -0
  64. package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +7 -0
  65. package/dist/esm/parts/AppPickerItem.js +74 -0
  66. package/dist/esm/parts/AppPickerItem.js.map +7 -0
  67. package/dist/esm/parts/AppSection.js +65 -0
  68. package/dist/esm/parts/AppSection.js.map +7 -0
  69. package/dist/esm/parts/Trigger.js +53 -0
  70. package/dist/esm/parts/Trigger.js.map +7 -0
  71. package/dist/esm/parts/shared-styles.js +14 -0
  72. package/dist/esm/parts/shared-styles.js.map +7 -0
  73. package/dist/esm/react-desc-prop-types.js +34 -9
  74. package/dist/esm/react-desc-prop-types.js.map +2 -2
  75. package/dist/esm/typescript-testing/slot-props.js +25 -0
  76. package/dist/esm/typescript-testing/slot-props.js.map +7 -0
  77. package/dist/esm/typescript-testing/typescript-app-picker-valid.js +15 -2
  78. package/dist/esm/typescript-testing/typescript-app-picker-valid.js.map +2 -2
  79. package/dist/esm/util/getChipId.js +6 -0
  80. package/dist/esm/util/getChipId.js.map +7 -0
  81. package/dist/esm/util/getChipRegionId.js +7 -0
  82. package/dist/esm/util/getChipRegionId.js.map +7 -0
  83. package/dist/esm/util/getDSAppPickerContractProps.js +8 -0
  84. package/dist/esm/util/getDSAppPickerContractProps.js.map +7 -0
  85. package/dist/esm/util/instanceIds.js +12 -0
  86. package/dist/esm/util/instanceIds.js.map +7 -0
  87. package/dist/types/DSAppPicker.d.ts +1 -2
  88. package/dist/types/DSAppPickerCTX.d.ts +6 -0
  89. package/dist/types/config/useAppPicker.d.ts +111 -92
  90. package/dist/types/config/useFocusTracker.d.ts +19 -0
  91. package/dist/types/config/useValidateProps.d.ts +3 -0
  92. package/dist/types/constants/index.d.ts +17 -7
  93. package/dist/types/index.d.ts +2 -0
  94. package/dist/types/parts/AppPanel.d.ts +2 -0
  95. package/dist/types/parts/AppPickerFloatingContext/AppPickerContent.d.ts +3 -0
  96. package/dist/types/parts/AppPickerFloatingContext/useAppPickerFloatingContext.d.ts +171 -0
  97. package/dist/types/parts/AppPickerItem.d.ts +11 -0
  98. package/dist/types/parts/AppSection.d.ts +6 -0
  99. package/dist/types/parts/Trigger.d.ts +14 -0
  100. package/dist/types/parts/shared-styles.d.ts +2 -0
  101. package/dist/types/react-desc-prop-types.d.ts +112 -9
  102. package/dist/types/util/getChipId.d.ts +2 -0
  103. package/dist/types/util/getChipRegionId.d.ts +1 -0
  104. package/dist/types/util/getDSAppPickerContractProps.d.ts +37 -0
  105. package/dist/types/util/instanceIds.d.ts +11 -0
  106. package/package.json +22 -19
  107. package/dist/cjs/AppPickerImpl.js +0 -204
  108. package/dist/cjs/AppPickerImpl.js.map +0 -7
  109. package/dist/cjs/hooks/useKeepTrackButtons.js +0 -69
  110. package/dist/cjs/hooks/useKeepTrackButtons.js.map +0 -7
  111. package/dist/cjs/styles.js +0 -76
  112. package/dist/cjs/styles.js.map +0 -7
  113. package/dist/cjs/utils.js.map +0 -7
  114. package/dist/esm/AppPickerImpl.js +0 -174
  115. package/dist/esm/AppPickerImpl.js.map +0 -7
  116. package/dist/esm/hooks/useKeepTrackButtons.js +0 -39
  117. package/dist/esm/hooks/useKeepTrackButtons.js.map +0 -7
  118. package/dist/esm/styles.js +0 -46
  119. package/dist/esm/styles.js.map +0 -7
  120. package/dist/esm/utils.js +0 -25
  121. package/dist/esm/utils.js.map +0 -7
  122. package/dist/types/AppPickerImpl.d.ts +0 -11
  123. package/dist/types/hooks/useKeepTrackButtons.d.ts +0 -13
  124. package/dist/types/styles.d.ts +0 -7
  125. package/dist/types/tests/app-picker.a11y.test.d.ts +0 -1
  126. package/dist/types/tests/app-picker.data-testid.test.d.ts +0 -1
  127. package/dist/types/tests/app-picker.events.test.d.ts +0 -1
  128. package/dist/types/tests/app-picker.exports.test.d.ts +0 -1
  129. package/dist/types/tests/app-picker.get-owner-props.test.d.ts +0 -1
  130. package/dist/types/tests/app-picker.keyboard.test.d.ts +0 -1
  131. package/dist/types/typescript-testing/typescript-app-picker-valid.d.ts +0 -1
  132. package/dist/types/utils.d.ts +0 -14
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var AppPanel_exports = {};
30
+ __export(AppPanel_exports, {
31
+ AppPanel: () => AppPanel
32
+ });
33
+ module.exports = __toCommonJS(AppPanel_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_jsx_runtime = require("react/jsx-runtime");
36
+ var import_ds_grid = require("@elliemae/ds-grid");
37
+ var import_ds_hooks_focus_trap = require("@elliemae/ds-hooks-focus-trap");
38
+ var import_ds_system = require("@elliemae/ds-system");
39
+ var import_react = __toESM(require("react"));
40
+ var import_constants = require("../constants/index.js");
41
+ var import_DSAppPickerCTX = require("../DSAppPickerCTX.js");
42
+ var import_AppSection = require("./AppSection.js");
43
+ var import_shared_styles = require("./shared-styles.js");
44
+ const StyledWrapper = (0, import_ds_system.styled)(import_ds_grid.Grid, { name: import_constants.DSAppPickerName, slot: import_constants.DSAppPickerSlots.ROOT })`
45
+ background-color: ${({ theme }) => theme.colors.neutral["000"]};
46
+ min-width: 308px;
47
+ min-height: 110px;
48
+ max-height: 449px;
49
+ width: 308px;
50
+ overflow-y: auto;
51
+ overflow-x: hidden;
52
+ /* Baseline 2024: reserve scrollbar gutter so the layout doesn't shift between overflow/no-overflow.
53
+ Replaces a JS isOverflow detection effect that toggled right padding. */
54
+ scrollbar-gutter: stable;
55
+ margin: 0;
56
+ padding: 0 0 8px 16px;
57
+ &:focus {
58
+ outline: none;
59
+ }
60
+ `;
61
+ const StyledSeparator = (0, import_ds_system.styled)("hr", { name: import_constants.DSAppPickerName, slot: import_constants.DSAppPickerSlots.SEPARATOR })`
62
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral[300]};
63
+ border-bottom: none;
64
+ width: 100%;
65
+ margin: 8px 0 0 0;
66
+ `;
67
+ const wrapperGridLayout = {
68
+ cols: ["repeat(3, 92px)"],
69
+ // Row tracks are intentionally auto-sized:
70
+ // - title row picks up its own typography height
71
+ // - chip rows expand when `wrapText` causes a chip to wrap onto a second line (Reflow story)
72
+ // - separator row picks up its own 1px height + margin
73
+ rows: ["auto"]
74
+ };
75
+ const useExecOnceAfterFirstRender = (callback) => {
76
+ const hasExecutedRef = import_react.default.useRef(false);
77
+ const executeInitialFocusRef = import_react.default.useRef(callback);
78
+ executeInitialFocusRef.current = callback;
79
+ (0, import_react.useEffect)(() => {
80
+ if (!hasExecutedRef.current) {
81
+ executeInitialFocusRef.current();
82
+ hasExecutedRef.current = true;
83
+ }
84
+ }, []);
85
+ };
86
+ const useMountedOpenAutofocusNuance = ({ pendingRef, trackFocusPanel }) => {
87
+ useExecOnceAfterFirstRender(() => {
88
+ if (!pendingRef.current) return;
89
+ pendingRef.current = false;
90
+ trackFocusPanel();
91
+ });
92
+ };
93
+ const AppPanelBase = () => {
94
+ const {
95
+ propsWithDefault: { customApps, onKeyDown },
96
+ ownerPropsConfig,
97
+ globalAttributes,
98
+ xstyledProps,
99
+ mountedOpenAutofocusPendingRef,
100
+ focusTrackers: { focusRegion, firstFocusableRef, lastFocusableRef, trackFocusPanel }
101
+ } = (0, import_react.useContext)(import_DSAppPickerCTX.DSAppPickerContext);
102
+ const { wrap, onClick, onKeyDown: onKeyDownGlobal, ...safeGlobalAttributes } = globalAttributes;
103
+ useMountedOpenAutofocusNuance({
104
+ pendingRef: mountedOpenAutofocusPendingRef,
105
+ trackFocusPanel
106
+ });
107
+ const isWrapperFocused = focusRegion === import_constants.APP_PICKER_REGION_FOCUSES.PANEL;
108
+ const handleWrapperRef = (0, import_react.useCallback)(
109
+ (node) => {
110
+ if (node && isWrapperFocused) node.focus();
111
+ },
112
+ [isWrapperFocused]
113
+ );
114
+ const handleOnKeyDown = (0, import_ds_hooks_focus_trap.useFocusTrap)({
115
+ firstElementRef: firstFocusableRef,
116
+ lastElementRef: lastFocusableRef,
117
+ onKeyDown
118
+ });
119
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
120
+ StyledWrapper,
121
+ {
122
+ innerRef: handleWrapperRef,
123
+ "data-testid": import_constants.DSAppPickerDataTestIds.ROOT,
124
+ cols: wrapperGridLayout.cols,
125
+ rows: wrapperGridLayout.rows,
126
+ tabIndex: -1,
127
+ ...ownerPropsConfig,
128
+ ...safeGlobalAttributes,
129
+ ...xstyledProps,
130
+ onKeyDown: handleOnKeyDown,
131
+ children: [
132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_AppSection.AppSection, {}),
133
+ customApps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
134
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_shared_styles.StyledListItemFullRow, { "data-testid": import_constants.DSAppPickerDataTestIds.ROW, ...ownerPropsConfig, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StyledSeparator, { "data-testid": import_constants.DSAppPickerDataTestIds.SEPARATOR, ...ownerPropsConfig }) }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_AppSection.AppSection, { isCustomApps: true })
136
+ ] })
137
+ ]
138
+ }
139
+ );
140
+ };
141
+ const AppPanel = (0, import_react.memo)(AppPanelBase);
142
+ AppPanel.displayName = "DSAppPicker.AppPanel";
143
+ //# sourceMappingURL=AppPanel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/parts/AppPanel.tsx", "../../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import { Grid } from '@elliemae/ds-grid';\nimport { useFocusTrap } from '@elliemae/ds-hooks-focus-trap';\nimport { styled } from '@elliemae/ds-system';\nimport React, { memo, useCallback, useContext, useEffect } from 'react';\nimport {\n APP_PICKER_REGION_FOCUSES,\n DSAppPickerDataTestIds,\n DSAppPickerName,\n DSAppPickerSlots,\n} from '../constants/index.js';\nimport { DSAppPickerContext } from '../DSAppPickerCTX.js';\nimport { AppSection } from './AppSection.js';\nimport { StyledListItemFullRow } from './shared-styles.js';\n\nconst StyledWrapper = styled(Grid, { name: DSAppPickerName, slot: DSAppPickerSlots.ROOT })`\n background-color: ${({ theme }) => theme.colors.neutral['000']};\n min-width: 308px;\n min-height: 110px;\n max-height: 449px;\n width: 308px;\n overflow-y: auto;\n overflow-x: hidden;\n /* Baseline 2024: reserve scrollbar gutter so the layout doesn't shift between overflow/no-overflow.\n Replaces a JS isOverflow detection effect that toggled right padding. */\n scrollbar-gutter: stable;\n margin: 0;\n padding: 0 0 8px 16px;\n &:focus {\n outline: none;\n }\n`;\n\nconst StyledSeparator = styled('hr', { name: DSAppPickerName, slot: DSAppPickerSlots.SEPARATOR })`\n border-top: 1px solid ${({ theme }) => theme.colors.neutral[300]};\n border-bottom: none;\n width: 100%;\n margin: 8px 0 0 0;\n`;\n\nconst wrapperGridLayout = {\n cols: ['repeat(3, 92px)'],\n // Row tracks are intentionally auto-sized:\n // - title row picks up its own typography height\n // - chip rows expand when `wrapText` causes a chip to wrap onto a second line (Reflow story)\n // - separator row picks up its own 1px height + margin\n rows: ['auto'],\n};\n\nconst useExecOnceAfterFirstRender = (callback: () => void) => {\n const hasExecutedRef = React.useRef(false);\n const executeInitialFocusRef = React.useRef(callback);\n executeInitialFocusRef.current = callback;\n useEffect(() => {\n if (!hasExecutedRef.current) {\n executeInitialFocusRef.current();\n hasExecutedRef.current = true;\n }\n }, []);\n};\n\ntype MountedOpenAutofocusNuanceConfig = {\n pendingRef: React.MutableRefObject<boolean>;\n trackFocusPanel: () => void;\n};\n\n/**\n * NUANCE \u2014 the single case that initial-focus-on-open (useAppPickerFloatingContext's onOpen) cannot\n * cover: DSAppPicker rendered ALREADY open (declarative `isOpen` at mount, no user interaction).\n * That open is not a transition, so `onOpen` never fires for it. This mount-time hook seeds the panel\n * wrapper, which is what a pointer open seeds too: there was no gesture at all here, so the\n * keyboard-only \"land on the selected app\" rule does not apply, and the panel is the target that gets\n * the dialog announced. `pendingRef` is true only when the component started open and is flipped\n * false on first consume, so a later controlled reopen \u2014 a real transition handled by `onOpen` \u2014\n * does not double-seed. Every user-driven open (click/keyboard) is a transition handled by `onOpen`,\n * NOT here.\n *\n * REMOVABILITY: if the team decides declarative-open should not autofocus, delete this hook and its\n * call, and flip the \"rendered already-open \u2026 focuses the panel wrapper\" assertions in\n * DSAppPicker.keyboard.test.js. Nothing else depends on it.\n */\nconst useMountedOpenAutofocusNuance = ({ pendingRef, trackFocusPanel }: MountedOpenAutofocusNuanceConfig) => {\n useExecOnceAfterFirstRender(() => {\n if (!pendingRef.current) return;\n pendingRef.current = false;\n trackFocusPanel();\n });\n};\n\nconst AppPanelBase = () => {\n const {\n propsWithDefault: { customApps, onKeyDown },\n ownerPropsConfig,\n globalAttributes,\n xstyledProps,\n mountedOpenAutofocusPendingRef,\n focusTrackers: { focusRegion, firstFocusableRef, lastFocusableRef, trackFocusPanel },\n } = useContext(DSAppPickerContext);\n\n // Global attributes are spread here, on the panel root, which is this component's root for the purpose\n // of the Dimsum convention that global attributes land on the styled root (see project_slots.md \u2014 it is\n // gate 2 of `data-dimsum-parent-slot`, and a component spreading them on an inner control is treated as\n // a defect, not a variant).\n //\n // There is no element containing both the trigger and the floating panel, so \"root\" has to be chosen\n // rather than read off the tree. The panel is the right choice, and not merely the larger one: the\n // floating context, the sections and the chips are what this component actually is, while the trigger is\n // the replaceable part \u2014 `TriggerComponent` already lets a consumer supply their own, and the direction\n // ds-menu-button points at (a behavioural layer wrapping arbitrary children, with the menu as its own\n // part) would make it fully app-owned. The panel stays the root through that change; a trigger-rooted\n // choice would not survive it.\n //\n // `wrap`, `onClick`, and `onKeyDown` are filtered out because they collide with the public component API\n // (which uses these for different semantics).\n const { wrap, onClick, onKeyDown: onKeyDownGlobal, ...safeGlobalAttributes } = globalAttributes;\n\n // ---------------------------------------------------------------------------\n // Initial focus on panel open.\n // ---------------------------------------------------------------------------\n // User-driven opens (click/keyboard) are open transitions, seeded by\n // useAppPickerFloatingContext's onOpen. The one case that isn't a transition \u2014 being rendered\n // already-open (declarative `isOpen` at mount) \u2014 is covered here, scoped to exactly that.\n useMountedOpenAutofocusNuance({\n pendingRef: mountedOpenAutofocusPendingRef,\n trackFocusPanel,\n });\n\n // ---------------------------------------------------------------------------\n // Panel wrapper \u2014 tracker-driven focus for the mouse-open announcement path.\n // handleWrapperRef gets a new reference when isWrapperFocused changes \u2192 React\n // re-invokes the callback with the DOM node \u2192 node.focus() fires.\n // ---------------------------------------------------------------------------\n const isWrapperFocused = focusRegion === APP_PICKER_REGION_FOCUSES.PANEL;\n\n const handleWrapperRef = useCallback(\n (node: HTMLElement | null) => {\n if (node && isWrapperFocused) node.focus();\n },\n [isWrapperFocused],\n );\n\n // Default Escape-close/refocus is handled declaratively by useFloatingContext\n // (see useAppPickerFloatingContext's closeOnEscape/onEscape wiring) whenever there is no consumer\n // onKeyDown \u2014 a consumer-provided onKeyDown takes over keydown handling entirely.\n const handleOnKeyDown = useFocusTrap({\n firstElementRef: firstFocusableRef,\n lastElementRef: lastFocusableRef,\n onKeyDown,\n });\n\n // The panel root carries NO aria-label: it is a roleless element (generic role does not support\n // an accessible name, so any label here is dropped by assistive tech). The component's accessible\n // name lives on the dialog \u2014 see AppPickerContent's role=\"dialog\" + aria-labelledby.\n return (\n <StyledWrapper\n innerRef={handleWrapperRef}\n data-testid={DSAppPickerDataTestIds.ROOT}\n cols={wrapperGridLayout.cols}\n rows={wrapperGridLayout.rows}\n // when opening the dialog via mouse, the focus is programmatically assigned here via handleWrapperRef, -1 allows .focus() to work\n tabIndex={-1}\n {...ownerPropsConfig}\n {...safeGlobalAttributes}\n {...xstyledProps}\n onKeyDown={handleOnKeyDown}\n >\n <AppSection />\n {customApps.length > 0 && (\n <>\n <StyledListItemFullRow data-testid={DSAppPickerDataTestIds.ROW} {...ownerPropsConfig}>\n <StyledSeparator data-testid={DSAppPickerDataTestIds.SEPARATOR} {...ownerPropsConfig} />\n </StyledListItemFullRow>\n <AppSection isCustomApps />\n </>\n )}\n </StyledWrapper>\n );\n};\n\nexport const AppPanel = memo(AppPanelBase);\nAppPanel.displayName = 'DSAppPicker.AppPanel';\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADqKjB;AArKN,qBAAqB;AACrB,iCAA6B;AAC7B,uBAAuB;AACvB,mBAAgE;AAChE,uBAKO;AACP,4BAAmC;AACnC,wBAA2B;AAC3B,2BAAsC;AAEtC,MAAM,oBAAgB,yBAAO,qBAAM,EAAE,MAAM,kCAAiB,MAAM,kCAAiB,KAAK,CAAC;AAAA,sBACnE,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBhE,MAAM,sBAAkB,yBAAO,MAAM,EAAE,MAAM,kCAAiB,MAAM,kCAAiB,UAAU,CAAC;AAAA,0BACtE,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ,GAAG,CAAC;AAAA;AAAA;AAAA;AAAA;AAMlE,MAAM,oBAAoB;AAAA,EACxB,MAAM,CAAC,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxB,MAAM,CAAC,MAAM;AACf;AAEA,MAAM,8BAA8B,CAAC,aAAyB;AAC5D,QAAM,iBAAiB,aAAAA,QAAM,OAAO,KAAK;AACzC,QAAM,yBAAyB,aAAAA,QAAM,OAAO,QAAQ;AACpD,yBAAuB,UAAU;AACjC,8BAAU,MAAM;AACd,QAAI,CAAC,eAAe,SAAS;AAC3B,6BAAuB,QAAQ;AAC/B,qBAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,CAAC;AACP;AAsBA,MAAM,gCAAgC,CAAC,EAAE,YAAY,gBAAgB,MAAwC;AAC3G,8BAA4B,MAAM;AAChC,QAAI,CAAC,WAAW,QAAS;AACzB,eAAW,UAAU;AACrB,oBAAgB;AAAA,EAClB,CAAC;AACH;AAEA,MAAM,eAAe,MAAM;AACzB,QAAM;AAAA,IACJ,kBAAkB,EAAE,YAAY,UAAU;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,EAAE,aAAa,mBAAmB,kBAAkB,gBAAgB;AAAA,EACrF,QAAI,yBAAW,wCAAkB;AAiBjC,QAAM,EAAE,MAAM,SAAS,WAAW,iBAAiB,GAAG,qBAAqB,IAAI;AAQ/E,gCAA8B;AAAA,IAC5B,YAAY;AAAA,IACZ;AAAA,EACF,CAAC;AAOD,QAAM,mBAAmB,gBAAgB,2CAA0B;AAEnE,QAAM,uBAAmB;AAAA,IACvB,CAAC,SAA6B;AAC5B,UAAI,QAAQ,iBAAkB,MAAK,MAAM;AAAA,IAC3C;AAAA,IACA,CAAC,gBAAgB;AAAA,EACnB;AAKA,QAAM,sBAAkB,yCAAa;AAAA,IACnC,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB;AAAA,EACF,CAAC;AAKD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV,eAAa,wCAAuB;AAAA,MACpC,MAAM,kBAAkB;AAAA,MACxB,MAAM,kBAAkB;AAAA,MAExB,UAAU;AAAA,MACT,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACJ,WAAW;AAAA,MAEX;AAAA,oDAAC,gCAAW;AAAA,QACX,WAAW,SAAS,KACnB,4EACE;AAAA,sDAAC,8CAAsB,eAAa,wCAAuB,KAAM,GAAG,kBAClE,sDAAC,mBAAgB,eAAa,wCAAuB,WAAY,GAAG,kBAAkB,GACxF;AAAA,UACA,4CAAC,gCAAW,cAAY,MAAC;AAAA,WAC3B;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEO,MAAM,eAAW,mBAAK,YAAY;AACzC,SAAS,cAAc;",
6
+ "names": ["React"]
7
+ }
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var AppPickerContent_exports = {};
30
+ __export(AppPickerContent_exports, {
31
+ AppPickerContent: () => AppPickerContent
32
+ });
33
+ module.exports = __toCommonJS(AppPickerContent_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_jsx_runtime = require("react/jsx-runtime");
36
+ var import_ds_floating_context = require("@elliemae/ds-floating-context");
37
+ var import_ds_system = require("@elliemae/ds-system");
38
+ var import_react = require("react");
39
+ var import_constants = require("../../constants/index.js");
40
+ var import_DSAppPickerCTX = require("../../DSAppPickerCTX.js");
41
+ var import_instanceIds = require("../../util/instanceIds.js");
42
+ var import_AppPanel = require("../AppPanel.js");
43
+ var import_Trigger = require("../Trigger.js");
44
+ var import_useAppPickerFloatingContext = require("./useAppPickerFloatingContext.js");
45
+ const StyledAppPickerFloating = (0, import_ds_system.styled)(import_ds_floating_context.FloatingWrapper, {
46
+ name: import_constants.DSAppPickerName,
47
+ slot: import_constants.DSAppPickerSlots.FLOATING_WRAPPER
48
+ })``;
49
+ const AppPickerContent = () => {
50
+ const {
51
+ ownerPropsConfig,
52
+ propsWithDefault,
53
+ focusTrackers,
54
+ openIntentRef,
55
+ resolvedIsOpen,
56
+ setInternalIsOpen,
57
+ instanceUid
58
+ } = (0, import_react.useContext)(import_DSAppPickerCTX.DSAppPickerContext);
59
+ const {
60
+ floatingStyles,
61
+ arrowStyles,
62
+ floatingContext,
63
+ floatingInnerRef,
64
+ handleTriggerRef,
65
+ handleTriggerClick,
66
+ handleTriggerKeyDown
67
+ } = (0, import_useAppPickerFloatingContext.useAppPickerFloatingContext)({
68
+ propsWithDefault,
69
+ focusTrackers,
70
+ openIntentRef,
71
+ resolvedIsOpen,
72
+ setInternalIsOpen
73
+ });
74
+ const dialogLabelId = (0, import_instanceIds.getIdForAppPickerTrigger)(instanceUid);
75
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
76
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
77
+ import_Trigger.Trigger,
78
+ {
79
+ handleTriggerRef,
80
+ handleTriggerClick,
81
+ handleTriggerKeyDown,
82
+ dialogLabelId
83
+ }
84
+ ),
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
86
+ StyledAppPickerFloating,
87
+ {
88
+ innerRef: floatingInnerRef,
89
+ isOpen: resolvedIsOpen,
90
+ floatingStyles,
91
+ context: floatingContext,
92
+ getOwnerProps: ownerPropsConfig.getOwnerProps,
93
+ getOwnerPropsArguments: ownerPropsConfig.getOwnerPropsArguments,
94
+ role: "dialog",
95
+ "aria-labelledby": dialogLabelId,
96
+ children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_AppPanel.AppPanel, {}),
98
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_floating_context.PopoverArrow, { ...arrowStyles })
99
+ ]
100
+ }
101
+ )
102
+ ] });
103
+ };
104
+ //# sourceMappingURL=AppPickerContent.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/parts/AppPickerFloatingContext/AppPickerContent.tsx", "../../../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import { FloatingWrapper, PopoverArrow } from '@elliemae/ds-floating-context';\nimport { styled } from '@elliemae/ds-system';\nimport React, { useContext } from 'react';\nimport { DSAppPickerName, DSAppPickerSlots } from '../../constants/index.js';\nimport { DSAppPickerContext } from '../../DSAppPickerCTX.js';\nimport type { DSAppPickerT } from '../../react-desc-prop-types.js';\nimport { getIdForAppPickerTrigger } from '../../util/instanceIds.js';\nimport { AppPanel } from '../AppPanel.js';\nimport { Trigger } from '../Trigger.js';\nimport { useAppPickerFloatingContext } from './useAppPickerFloatingContext.js';\n\nconst StyledAppPickerFloating = styled(FloatingWrapper, {\n name: DSAppPickerName,\n slot: DSAppPickerSlots.FLOATING_WRAPPER,\n})``;\n\nexport const AppPickerContent: React.ComponentType<DSAppPickerT.Props> = () => {\n const {\n ownerPropsConfig,\n propsWithDefault,\n focusTrackers,\n openIntentRef,\n resolvedIsOpen,\n setInternalIsOpen,\n instanceUid,\n } = useContext(DSAppPickerContext);\n const {\n floatingStyles,\n arrowStyles,\n floatingContext,\n floatingInnerRef,\n handleTriggerRef,\n handleTriggerClick,\n handleTriggerKeyDown,\n } = useAppPickerFloatingContext({\n propsWithDefault,\n focusTrackers,\n openIntentRef,\n resolvedIsOpen,\n setInternalIsOpen,\n });\n\n // Suffix owned by util/instanceIds \u2014 never composed inline, so consumers and this call site cannot\n // drift apart. `getIdForAppPickerTrigger` is the exported counterpart.\n const dialogLabelId = getIdForAppPickerTrigger(instanceUid);\n\n return (\n <>\n <Trigger\n handleTriggerRef={handleTriggerRef}\n handleTriggerClick={handleTriggerClick}\n handleTriggerKeyDown={handleTriggerKeyDown}\n dialogLabelId={dialogLabelId}\n />\n <StyledAppPickerFloating\n innerRef={floatingInnerRef}\n isOpen={resolvedIsOpen}\n floatingStyles={floatingStyles}\n context={floatingContext}\n getOwnerProps={ownerPropsConfig.getOwnerProps}\n getOwnerPropsArguments={ownerPropsConfig.getOwnerPropsArguments}\n role=\"dialog\"\n aria-labelledby={dialogLabelId}\n >\n <AppPanel />\n <PopoverArrow {...arrowStyles} />\n </StyledAppPickerFloating>\n </>\n );\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;AD+CnB;AA/CJ,iCAA8C;AAC9C,uBAAuB;AACvB,mBAAkC;AAClC,uBAAkD;AAClD,4BAAmC;AAEnC,yBAAyC;AACzC,sBAAyB;AACzB,qBAAwB;AACxB,yCAA4C;AAE5C,MAAM,8BAA0B,yBAAO,4CAAiB;AAAA,EACtD,MAAM;AAAA,EACN,MAAM,kCAAiB;AACzB,CAAC;AAEM,MAAM,mBAA4D,MAAM;AAC7E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,yBAAW,wCAAkB;AACjC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,gEAA4B;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,oBAAgB,6CAAyB,WAAW;AAE1D,SACE,4EACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,QAAQ;AAAA,QACR;AAAA,QACA,SAAS;AAAA,QACT,eAAe,iBAAiB;AAAA,QAChC,wBAAwB,iBAAiB;AAAA,QACzC,MAAK;AAAA,QACL,mBAAiB;AAAA,QAEjB;AAAA,sDAAC,4BAAS;AAAA,UACV,4CAAC,2CAAc,GAAG,aAAa;AAAA;AAAA;AAAA,IACjC;AAAA,KACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var useAppPickerFloatingContext_exports = {};
30
+ __export(useAppPickerFloatingContext_exports, {
31
+ useAppPickerFloatingContext: () => useAppPickerFloatingContext
32
+ });
33
+ module.exports = __toCommonJS(useAppPickerFloatingContext_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_ds_floating_context = require("@elliemae/ds-floating-context");
36
+ var import_react = require("react");
37
+ const useAppPickerFloatingContext = (appPickerConfig) => {
38
+ const { propsWithDefault, focusTrackers, openIntentRef, resolvedIsOpen, setInternalIsOpen } = appPickerConfig;
39
+ const {
40
+ onOpen,
41
+ onClose,
42
+ actionRef,
43
+ onClick,
44
+ onClickOutside,
45
+ onKeyDown,
46
+ triggerRef,
47
+ isOpen,
48
+ openAndFocusOnArrowKeys
49
+ } = propsWithDefault;
50
+ const isControlled = typeof isOpen === "boolean";
51
+ const { trackFocusSelectedItem, trackFocusSelectedOrLastItem, trackFocusItemAtIndex, trackFocusPanel } = focusTrackers;
52
+ const defaultTriggerRef = (0, import_react.useRef)(null);
53
+ const handleClickOutside = (0, import_react.useCallback)(
54
+ (e) => {
55
+ if (!isControlled) onClose?.({ reason: "click-outside", event: e });
56
+ setInternalIsOpen(false);
57
+ onClickOutside?.(e);
58
+ },
59
+ [isControlled, onClose, setInternalIsOpen, onClickOutside]
60
+ );
61
+ const handleScopedEscape = (0, import_react.useCallback)(
62
+ (event) => {
63
+ if (!isControlled) onClose?.({ reason: "escape", event });
64
+ setInternalIsOpen(false);
65
+ },
66
+ [isControlled, onClose, setInternalIsOpen]
67
+ );
68
+ const handleFloatingClose = (0, import_react.useCallback)(
69
+ (info) => {
70
+ if (info.reason === "controlled-flip" && isControlled) onClose?.({ reason: "controlled" });
71
+ },
72
+ [isControlled, onClose]
73
+ );
74
+ const handleFloatingOpen = (0, import_react.useCallback)(
75
+ (info) => {
76
+ if (openIntentRef.current === "keyboard-first") trackFocusSelectedItem();
77
+ else if (openIntentRef.current === "keyboard-last") trackFocusSelectedOrLastItem();
78
+ else trackFocusPanel();
79
+ if (info.reason === "controlled-flip" && isControlled) onOpen?.({ reason: "controlled" });
80
+ },
81
+ [openIntentRef, trackFocusSelectedItem, trackFocusSelectedOrLastItem, trackFocusPanel, isControlled, onOpen]
82
+ );
83
+ const floatingContextConfig = (0, import_react.useMemo)(
84
+ () => ({
85
+ placement: "bottom",
86
+ // Arrow tip is ~6.1px above the panel top (arrowPlacementBase16 ≈ 17.5px, tip at 11.4px from box top).
87
+ // 4px spec gap → 4 + 6.1 ≈ 10px offset.
88
+ customOffset: [0, 10],
89
+ externallyControlledIsOpen: resolvedIsOpen,
90
+ withoutAnimation: true,
91
+ onClickOutside: handleClickOutside,
92
+ /*
93
+ * Two conditions, and the second is a safety gate rather than a preference.
94
+ *
95
+ * `!onKeyDown` — a consumer who supplies onKeyDown owns the key entirely, so useFloatingContext
96
+ * neither routes the Escape to onEscape (see handleScopedEscape) nor returns focus to the trigger.
97
+ *
98
+ * `!isControlled` — `returnFocusToReference` is true below, and the hook applies it on a scoped
99
+ * Escape regardless of who owns the open state. For a controlled picker `handleScopedEscape`'s
100
+ * `setInternalIsOpen(false)` is inert, so leaving this on would move focus to the trigger while
101
+ * the consumer's panel is still open: focus outside an open dialog. A controlled consumer owns
102
+ * the close, so they own the Escape and the refocus that goes with it.
103
+ */
104
+ closeOnEscape: !onKeyDown && !isControlled,
105
+ onClose: handleFloatingClose,
106
+ onEscape: handleScopedEscape,
107
+ onOpen: handleFloatingOpen,
108
+ returnFocusToReference: true,
109
+ externalReferenceElement: triggerRef?.current || defaultTriggerRef.current
110
+ }),
111
+ [
112
+ handleClickOutside,
113
+ handleScopedEscape,
114
+ handleFloatingClose,
115
+ handleFloatingOpen,
116
+ isControlled,
117
+ onKeyDown,
118
+ resolvedIsOpen,
119
+ triggerRef
120
+ ]
121
+ );
122
+ const {
123
+ refs: floatingRefs,
124
+ floatingStyles,
125
+ arrowStyles,
126
+ context: floatingContext
127
+ } = (0, import_ds_floating_context.useFloatingContext)(floatingContextConfig);
128
+ const handleTriggerRef = (0, import_react.useCallback)(
129
+ (node) => {
130
+ defaultTriggerRef.current = node;
131
+ floatingRefs.setReference(node);
132
+ if (triggerRef) {
133
+ triggerRef.current = node;
134
+ }
135
+ },
136
+ [floatingRefs, triggerRef]
137
+ );
138
+ const handleActionRef = (0, import_react.useCallback)(
139
+ (node) => {
140
+ if (node && actionRef?.current) {
141
+ actionRef.current.focusToIndex = (index) => {
142
+ trackFocusItemAtIndex(index);
143
+ };
144
+ actionRef.current.focusWrapper = () => {
145
+ trackFocusPanel();
146
+ };
147
+ actionRef.current.focusSelectedOrFirstAvailable = () => {
148
+ trackFocusSelectedItem();
149
+ };
150
+ }
151
+ },
152
+ [actionRef, trackFocusItemAtIndex, trackFocusPanel, trackFocusSelectedItem]
153
+ );
154
+ const floatingInnerRef = (0, import_react.useCallback)(
155
+ (node) => {
156
+ floatingRefs.setFloating(node);
157
+ handleActionRef(node);
158
+ },
159
+ [floatingRefs.setFloating, handleActionRef]
160
+ );
161
+ const handleTriggerClick = (0, import_react.useCallback)(
162
+ (e) => {
163
+ openIntentRef.current = e.detail === 0 ? "keyboard-first" : "pointer";
164
+ onClick?.(e);
165
+ if (!isControlled) {
166
+ if (resolvedIsOpen) onClose?.({ reason: "trigger-toggle", event: e });
167
+ else onOpen?.({ reason: "trigger", event: e });
168
+ }
169
+ setInternalIsOpen((prev) => !prev);
170
+ },
171
+ [onClick, openIntentRef, setInternalIsOpen, isControlled, resolvedIsOpen, onClose, onOpen]
172
+ );
173
+ const handleTriggerKeyDown = (0, import_react.useCallback)(
174
+ (e) => {
175
+ if (!openAndFocusOnArrowKeys) return;
176
+ if (e.code !== "ArrowDown" && e.code !== "ArrowUp") return;
177
+ if (resolvedIsOpen) return;
178
+ e.preventDefault();
179
+ openIntentRef.current = e.code === "ArrowDown" ? "keyboard-first" : "keyboard-last";
180
+ if (!isControlled) onOpen?.({ reason: "trigger", event: e });
181
+ setInternalIsOpen(true);
182
+ },
183
+ [openAndFocusOnArrowKeys, resolvedIsOpen, openIntentRef, isControlled, onOpen, setInternalIsOpen]
184
+ );
185
+ return {
186
+ floatingStyles,
187
+ arrowStyles,
188
+ floatingContext,
189
+ handleTriggerRef,
190
+ handleTriggerClick,
191
+ handleTriggerKeyDown,
192
+ floatingInnerRef
193
+ };
194
+ };
195
+ //# sourceMappingURL=useAppPickerFloatingContext.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/parts/AppPickerFloatingContext/useAppPickerFloatingContext.ts", "../../../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import { useFloatingContext, type DSHookFloatingContextT } from '@elliemae/ds-floating-context';\nimport type React from 'react';\nimport { useCallback, useMemo, useRef } from 'react';\nimport type { useAppPicker } from '../../config/useAppPicker.js';\nimport type { DSAppPickerT } from '../../react-desc-prop-types.js';\n\n/**\n * useAppPickerFloatingContext \u2014 the single point that wires DSAppPicker to\n * `@elliemae/ds-floating-context`'s `useFloatingContext`.\n *\n * WHAT IT DOES (as a black box):\n * AppPicker can be used in two very different ways:\n * - Controlled: the consumer supplies `isOpen` and drives the open/close transition.\n * \u2514\u2192 AppPicker can't be event-based as the flip might originate from any cause and we don't own the business logic\n * \u2514\u2192 we need to ensure WCAG embedded behaviours (focus, Escape, click-outside) are wired to the consumer's `isOpen` flip.\n * - Uncontrolled: the consumer does not supply `isOpen` and AppPicker owns the full flows, we only notify the consumer of the transition and its cause.\n *\n * The AppPicker and this file in particular serves as the one place that coordinates the two different ways to use the component and wires with the useFloatingContext hook.\n * This files owns:\n * - Focus management relative to open/close transitions (initial focus on open, return focus to trigger on close)\n * - Escape key handling (scoped to the panel and trigger)\n * - Click-outside handling (panel and trigger)\n * - Imperative focus API via actionRef\n * - Controlled/Uncontrolled forks and differences in event notification (eager vs controlled-flip)\n * - OnOpen and OnClose notification to the consumer with the correct reason and event (if any)\n *\n * IMPORTANT:\n * Parts of the flow/logic required in this file is offloaded to useFloatingContext internal assumptions and logics.\n * Changes to useFloatingContext may break the flows in this file, or alter them in ways that are not obvious, the two are closely coupled.\n *\n * DATA / EVENT FLOW\n *\n * Two concerns run in parallel and must not be conflated: (A) what makes the panel show/hide and take\n * focus, and (B) how the consumer is told it opened/closed. They have different origins.\n *\n * (A) PANEL VISIBILITY + FOCUS \u2014 useFloatingContext internal co-ownership of the flow.\n *\n * a user action \u2502 \u2502 isOpen prop flip\n * (trigger click / scoped Escape / click outside) \u2502 \u2502 (not a traceable user action, but the consumer's own flip)\n * uncontrolled - flips the internal flag \u2502 \u2502 controlled - AppPicker's own flip is inert, consumer drives it\n * \u2502\n * \u25BC\n * resolvedIsOpen changes\n * \u2502\n * \u25BC\n * useFloatingContext (externallyControlledIsOpen) detects the transition\n * \u2502\n * \u25BC\n * on open \u2502 \u2502 on close\n * handleFloatingOpen \u2502 \u2502 focus is only restored after a SCOPED ESCAPE:\n * AppPicker business logic seeds initial focus \u2502 \u2502 useFloatingContext returns focus to the trigger\n * \u2502 \u2502 (returnFocusToReference). Click-outside / toggle\n * \u2502 \u2502 / controlled closes do NOT move focus, and\n * \u2502 \u2502 handleFloatingClose only NOTIFIES (see (B)).\n * \u2502\n * \u25BC\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 visibility + focus are delivered to final user as expected \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n *\n * (B) CONSUMER NOTIFICATION\n * Each flow below is the UNCONTROLLED path, where AppPicker owns the transition and can name the true cause.\n * The controlled equivalent for every trigger is stated once at the end.\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 OPENING TRIGGERS FLOWS \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * TRIGGER CLICK (uncontrolled)\n * trigger click\n * user clicks the internal trigger, panel closed\n * \u2502\n * \u25BC\n * handleTriggerClick\n * ( flips the flag and wires the visual and focus Flow (A) above )\n * \u2502\n * \u25BC\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 onOpen { reason: 'trigger', event } \u2502 fired EAGERLY, when the event is triggered\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ------------------------------------------------------------------------------------------------------------------------\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 CLOSING TRIGGERS FLOWS \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * KEYBOARD ESCAPE (uncontrolled)\n * Escape within the panel DOM tree or the trigger\n * scoped Escape (routed only while closeOnEscape, i.e. no consumer onKeyDown)\n * \u2502\n * \u25BC\n * onEscape \u2192 handleScopedEscape\n * ( flips the flag and wires the visual and focus Flow (A) above )\n * \u2502\n * \u25BC\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 onClose { reason: 'escape', event } \u2502 fired EAGERLY, when the event is triggered\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n *\n * CLICK OUTSIDE (uncontrolled)\n * Click outside the panel DOM tree and the trigger\n * useFloatingContext detects a pointer press outside the panel + trigger\n * \u2502\n * \u25BC\n * handleClickOutside\n * ( flips the flag and wires the visual and focus Flow (A) above )\n * \u2502\n * \u25BC\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 onClose { reason: 'click-outside', event } \u2502 fired EAGERLY, when the event is triggered\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n *\n * CLICK ON TRIGGER (uncontrolled, while internal state is open)\n * trigger click while open\n * user clicks the internal trigger, panel open\n * \u2502\n * \u25BC\n * handleTriggerClick\n * ( flips the flag and wires the visual and focus Flow (A) above )\n * \u2502\n * \u25BC\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 onClose { reason: 'trigger-toggle', event } \u2502 fired EAGERLY, when the event is triggered\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ------------------------------------------------------------------------------------------------------------------------\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 CONTROLLED OPEN & CLOSE FLOWS \u2502\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * AppPicker's own flip is inert;\n * We can't fire EAGERLY and we can't track an originating event, there may be NONE\n * The consumer's `isOpen` flip is reacted to by useFloatingContext, which fires onOpen / onClose with reason 'controlled-flip'\n * We wire the visual and focus Flow (A) above, and then notify the consumer with reason 'controlled' (no event)\n * \u2502\n * \u25BC\n * \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n * \u2502 onOpen { reason: 'controlled' } \u2502 no event\n * \u2502 onClose { reason: 'controlled' } \u2502 a prop flip is not a traceable user action\n * \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n * ------------------------------------------------------------------------------------------------------------------------\n *\n * Eager (uncontrolled) and controlled-flip paths are mutually exclusive on `isControlled`.\n * the consumer is notified exactly once per transition \u2014 never twice.\n * On Escape specifically\n * closeOnEscape is false whenever the picker is controlled (and whenever a consumer supplies onKeyDown)\n * \u2514\u2192 AppPicker's onEscape never runs \u2014\n * \u2514\u2192 the close arrives purely by listening to the flag transition\n * ------------------------------------------------------------------------------------------------------------------------\n * A nuance for an edge case:\n *\n * Declarative mount-open (rendered already-open).\n * useFloatingContext fires no onOpen for it (it did not transition to open, it started open),\n * \u2514\u2192 neither the focus-seed (A) nor the notification (B) runs\n * AppPanel compensates this locally via useMountedOpenAutofocusNuance, it needs to be seen if this is even desired or should be removed\n * ------------------------------------------------------------------------------------------------------------------------\n */\n\ntype ConfiguredAppPickerCtx = ReturnType<typeof useAppPicker>;\n\ntype AppPickerFloatingContextConfig = {\n propsWithDefault: DSAppPickerT.InternalProps;\n focusTrackers: ConfiguredAppPickerCtx['focusTrackers'];\n openIntentRef: ConfiguredAppPickerCtx['openIntentRef'];\n // Open state is owned by useAppPicker (lifted so useFocusTracker can seed focus in the same fiber).\n // This hook reads the resolved value for positioning and flips it through the setter to close/toggle.\n resolvedIsOpen: ConfiguredAppPickerCtx['resolvedIsOpen'];\n setInternalIsOpen: ConfiguredAppPickerCtx['setInternalIsOpen'];\n};\n\nexport const useAppPickerFloatingContext = (appPickerConfig: AppPickerFloatingContextConfig) => {\n const { propsWithDefault, focusTrackers, openIntentRef, resolvedIsOpen, setInternalIsOpen } = appPickerConfig;\n const {\n onOpen,\n onClose,\n actionRef,\n onClick,\n onClickOutside,\n onKeyDown,\n triggerRef,\n isOpen,\n openAndFocusOnArrowKeys,\n } = propsWithDefault;\n // Controlled when the consumer supplies `isOpen`. This decides who owns a transition: uncontrolled,\n // AppPicker's own handlers own it and report the specific event-carrying reason eagerly; controlled,\n // AppPicker's own flips are inert and the consumer drives open/close via the prop (reason 'controlled').\n const isControlled = typeof isOpen === 'boolean';\n\n const { trackFocusSelectedItem, trackFocusSelectedOrLastItem, trackFocusItemAtIndex, trackFocusPanel } =\n focusTrackers;\n\n const defaultTriggerRef = useRef<HTMLButtonElement>(null);\n\n // Uncontrolled close \u2014 see file header (B) \"CLICK OUTSIDE\". Also forwards the raw event to onClickOutside.\n const handleClickOutside = useCallback(\n (e: MouseEvent | TouchEvent) => {\n if (!isControlled) onClose?.({ reason: 'click-outside', event: e });\n setInternalIsOpen(false);\n onClickOutside?.(e as MouseEvent);\n },\n [isControlled, onClose, setInternalIsOpen, onClickOutside],\n );\n\n // onEscape target \u2014 see file header (B) \"KEYBOARD ESCAPE\". Scoped Escape only; gated by closeOnEscape\n // (`!onKeyDown`, see the config below).\n const handleScopedEscape = useCallback(\n (event: KeyboardEvent) => {\n if (!isControlled) onClose?.({ reason: 'escape', event });\n setInternalIsOpen(false);\n },\n [isControlled, onClose, setInternalIsOpen],\n );\n\n // Controlled close notify \u2014 see file header \"CONTROLLED OPEN & CLOSE FLOWS\". The guard also filters\n // out a non-scoped Escape, which reaches here as reason 'interaction' (not 'controlled-flip').\n const handleFloatingClose = useCallback(\n (info: DSHookFloatingContextT.OpenChange) => {\n if (info.reason === 'controlled-flip' && isControlled) onClose?.({ reason: 'controlled' });\n },\n [isControlled, onClose],\n );\n\n // Open transition \u2014 see file header (A) (focus) + \"CONTROLLED OPEN & CLOSE FLOWS\" (notify). Seeds\n // initial focus (targets stated in the block comment inside, which is the authority) and, when\n // controlled, notifies the consumer. Mount-open is not a transition, so this never fires for it (AppPanel's\n // useMountedOpenAutofocusNuance handles that one case).\n const handleFloatingOpen = useCallback(\n (info: DSHookFloatingContextT.OpenChange) => {\n /*\n * Initial focus on open, decided by HOW the picker was opened and by nothing else:\n *\n * keyboard (Enter/Space) \u2192 the selected app, falling back to the first available one\n * pointer (real click/tap) \u2192 the panel wrapper\n *\n * Neither branch depends on who rendered the trigger, because in both cases the landing spot is the\n * picker's own element:\n *\n * - \"A keyboard open lands on the current selection\" is stated by `trackFocusSelectedItem`, by the\n * public `actionRef.focusSelectedOrFirstAvailable`, and by the `aria-current` marking of the\n * selected chip.\n * - \"A pointer open lands on the panel\" exists as a explicit design preference that has never been marked explicitly as A11y violating,\n * and as such, we have no strong reason to oppose the preference yet. This is subject to review the moment any A11y concern is raised.\n *\n * `openIntentRef` is written by the two handlers that own an activation \u2014 `handleTriggerClick` from\n * the click's `detail === 0`, and `handleTriggerKeyDown` from the arrow key. That makes this a genuine\n * pointer-vs-keyboard split rather than the generic click semantic: Enter/Space on a <button> also\n * fires a click, and it counts as keyboard here.\n *\n * Reading a single value is the point. Every landing is decided here, so no other code path can write\n * a competing focus intent and have the two race.\n */\n if (openIntentRef.current === 'keyboard-first') trackFocusSelectedItem();\n else if (openIntentRef.current === 'keyboard-last') trackFocusSelectedOrLastItem();\n else trackFocusPanel();\n if (info.reason === 'controlled-flip' && isControlled) onOpen?.({ reason: 'controlled' });\n },\n [openIntentRef, trackFocusSelectedItem, trackFocusSelectedOrLastItem, trackFocusPanel, isControlled, onOpen],\n );\n\n const floatingContextConfig = useMemo(\n () =>\n ({\n placement: 'bottom',\n // Arrow tip is ~6.1px above the panel top (arrowPlacementBase16 \u2248 17.5px, tip at 11.4px from box top).\n // 4px spec gap \u2192 4 + 6.1 \u2248 10px offset.\n customOffset: [0, 10],\n externallyControlledIsOpen: resolvedIsOpen,\n withoutAnimation: true,\n onClickOutside: handleClickOutside,\n /*\n * Two conditions, and the second is a safety gate rather than a preference.\n *\n * `!onKeyDown` \u2014 a consumer who supplies onKeyDown owns the key entirely, so useFloatingContext\n * neither routes the Escape to onEscape (see handleScopedEscape) nor returns focus to the trigger.\n *\n * `!isControlled` \u2014 `returnFocusToReference` is true below, and the hook applies it on a scoped\n * Escape regardless of who owns the open state. For a controlled picker `handleScopedEscape`'s\n * `setInternalIsOpen(false)` is inert, so leaving this on would move focus to the trigger while\n * the consumer's panel is still open: focus outside an open dialog. A controlled consumer owns\n * the close, so they own the Escape and the refocus that goes with it.\n */\n closeOnEscape: !onKeyDown && !isControlled,\n onClose: handleFloatingClose,\n onEscape: handleScopedEscape,\n onOpen: handleFloatingOpen,\n returnFocusToReference: true,\n externalReferenceElement: triggerRef?.current || defaultTriggerRef.current,\n }) as DSHookFloatingContextT.Props,\n [\n handleClickOutside,\n handleScopedEscape,\n handleFloatingClose,\n handleFloatingOpen,\n isControlled,\n onKeyDown,\n resolvedIsOpen,\n triggerRef,\n ],\n );\n\n const {\n refs: floatingRefs,\n floatingStyles,\n arrowStyles,\n context: floatingContext,\n } = useFloatingContext(floatingContextConfig);\n\n const handleTriggerRef = useCallback<React.RefCallback<HTMLButtonElement>>(\n (node) => {\n (defaultTriggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;\n floatingRefs.setReference(node);\n if (triggerRef) {\n (triggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;\n }\n },\n [floatingRefs, triggerRef],\n );\n\n // Populates the consumer's actionRef with imperative focus methods. Fires on mount with the panel\n // node. Every method routes through the focus tracker \u2014 no DOM queries.\n const handleActionRef = useCallback<React.RefCallback<HTMLDivElement>>(\n (node) => {\n if (node && actionRef?.current) {\n actionRef.current.focusToIndex = (index: number) => {\n trackFocusItemAtIndex(index);\n };\n actionRef.current.focusWrapper = () => {\n trackFocusPanel();\n };\n actionRef.current.focusSelectedOrFirstAvailable = () => {\n trackFocusSelectedItem();\n };\n }\n },\n [actionRef, trackFocusItemAtIndex, trackFocusPanel, trackFocusSelectedItem],\n );\n\n const floatingInnerRef = useCallback<React.RefCallback<HTMLDivElement>>(\n (node) => {\n (floatingRefs.setFloating as React.RefCallback<HTMLDivElement>)(node);\n handleActionRef(node);\n },\n [floatingRefs.setFloating, handleActionRef],\n );\n\n const handleTriggerClick = useCallback(\n (e: React.MouseEvent | React.KeyboardEvent) => {\n // detail === 0 \u21D2 keyboard activation (Enter/Space), not a pointer. handleFloatingOpen reads\n // this on the next open transition to pick keyboard-vs-pointer initial focus.\n openIntentRef.current = (e as React.MouseEvent).detail === 0 ? 'keyboard-first' : 'pointer';\n onClick?.(e);\n // Uncontrolled eager notify \u2014 see file header (B) \"TRIGGER CLICK\" / \"CLICK ON TRIGGER\".\n // `resolvedIsOpen` is the pre-flip value: open \u21D2 this click closes (trigger-toggle), else opens.\n if (!isControlled) {\n if (resolvedIsOpen) onClose?.({ reason: 'trigger-toggle', event: e });\n else onOpen?.({ reason: 'trigger', event: e });\n }\n setInternalIsOpen((prev) => !prev);\n },\n [onClick, openIntentRef, setInternalIsOpen, isControlled, resolvedIsOpen, onClose, onOpen],\n );\n\n /*\n * Trigger keydown \u2014 the arrow-key open, gated on `openAndFocusOnArrowKeys`.\n *\n * This exists as its own handler rather than being folded into handleTriggerClick because a key press is\n * not a click: handleTriggerClick derives keyboard-vs-pointer from the click's `detail`, which is a\n * property of clicks. Routing a keydown through it would work by accident and read as a lie at the call\n * site. Both handlers write the same single `openIntentRef`, so there is still one place that decides the\n * landing \u2014 see handleFloatingOpen.\n *\n * ArrowDown \u2192 the selection, else the FIRST available item.\n * ArrowUp \u2192 the selection, else the LAST available item.\n *\n * Only opens; never closes or toggles. An arrow key on the trigger while the panel is already open is\n * ignored, because focus is inside the panel by then and re-seeding would yank it back.\n *\n * Enter and Space are deliberately absent: the built-in trigger is a native <button>, so the browser\n * turns those into a click and they arrive through handleTriggerClick. A consumer's TriggerComponent that\n * is also a real button gets the same for free.\n *\n * `preventDefault` stops the page from scrolling on a key that is being used to open a widget.\n *\n * Returns nothing, like any event handler. A trigger that keeps the picker CONTROLLED makes\n * `setInternalIsOpen` inert and has to run its own open for ArrowDown/ArrowUp \u2014 see\n * ds-global-header's TriggerDefaultComponent. Changing which keys are handled here means changing it\n * there too.\n */\n const handleTriggerKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (!openAndFocusOnArrowKeys) return;\n if (e.code !== 'ArrowDown' && e.code !== 'ArrowUp') return;\n if (resolvedIsOpen) return;\n\n e.preventDefault();\n openIntentRef.current = e.code === 'ArrowDown' ? 'keyboard-first' : 'keyboard-last';\n if (!isControlled) onOpen?.({ reason: 'trigger', event: e });\n setInternalIsOpen(true);\n },\n [openAndFocusOnArrowKeys, resolvedIsOpen, openIntentRef, isControlled, onOpen, setInternalIsOpen],\n );\n\n return {\n floatingStyles,\n arrowStyles,\n floatingContext,\n handleTriggerRef,\n handleTriggerClick,\n handleTriggerKeyDown,\n floatingInnerRef,\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,iCAAgE;AAEhE,mBAA6C;AAkKtC,MAAM,8BAA8B,CAAC,oBAAoD;AAC9F,QAAM,EAAE,kBAAkB,eAAe,eAAe,gBAAgB,kBAAkB,IAAI;AAC9F,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAIJ,QAAM,eAAe,OAAO,WAAW;AAEvC,QAAM,EAAE,wBAAwB,8BAA8B,uBAAuB,gBAAgB,IACnG;AAEF,QAAM,wBAAoB,qBAA0B,IAAI;AAGxD,QAAM,yBAAqB;AAAA,IACzB,CAAC,MAA+B;AAC9B,UAAI,CAAC,aAAc,WAAU,EAAE,QAAQ,iBAAiB,OAAO,EAAE,CAAC;AAClE,wBAAkB,KAAK;AACvB,uBAAiB,CAAe;AAAA,IAClC;AAAA,IACA,CAAC,cAAc,SAAS,mBAAmB,cAAc;AAAA,EAC3D;AAIA,QAAM,yBAAqB;AAAA,IACzB,CAAC,UAAyB;AACxB,UAAI,CAAC,aAAc,WAAU,EAAE,QAAQ,UAAU,MAAM,CAAC;AACxD,wBAAkB,KAAK;AAAA,IACzB;AAAA,IACA,CAAC,cAAc,SAAS,iBAAiB;AAAA,EAC3C;AAIA,QAAM,0BAAsB;AAAA,IAC1B,CAAC,SAA4C;AAC3C,UAAI,KAAK,WAAW,qBAAqB,aAAc,WAAU,EAAE,QAAQ,aAAa,CAAC;AAAA,IAC3F;AAAA,IACA,CAAC,cAAc,OAAO;AAAA,EACxB;AAMA,QAAM,yBAAqB;AAAA,IACzB,CAAC,SAA4C;AAwB3C,UAAI,cAAc,YAAY,iBAAkB,wBAAuB;AAAA,eAC9D,cAAc,YAAY,gBAAiB,8BAA6B;AAAA,UAC5E,iBAAgB;AACrB,UAAI,KAAK,WAAW,qBAAqB,aAAc,UAAS,EAAE,QAAQ,aAAa,CAAC;AAAA,IAC1F;AAAA,IACA,CAAC,eAAe,wBAAwB,8BAA8B,iBAAiB,cAAc,MAAM;AAAA,EAC7G;AAEA,QAAM,4BAAwB;AAAA,IAC5B,OACG;AAAA,MACC,WAAW;AAAA;AAAA;AAAA,MAGX,cAAc,CAAC,GAAG,EAAE;AAAA,MACpB,4BAA4B;AAAA,MAC5B,kBAAkB;AAAA,MAClB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAahB,eAAe,CAAC,aAAa,CAAC;AAAA,MAC9B,SAAS;AAAA,MACT,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,wBAAwB;AAAA,MACxB,0BAA0B,YAAY,WAAW,kBAAkB;AAAA,IACrE;AAAA,IACF;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM;AAAA,IACJ,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EACX,QAAI,+CAAmB,qBAAqB;AAE5C,QAAM,uBAAmB;AAAA,IACvB,CAAC,SAAS;AACR,MAAC,kBAAuE,UAAU;AAClF,mBAAa,aAAa,IAAI;AAC9B,UAAI,YAAY;AACd,QAAC,WAAgE,UAAU;AAAA,MAC7E;AAAA,IACF;AAAA,IACA,CAAC,cAAc,UAAU;AAAA,EAC3B;AAIA,QAAM,sBAAkB;AAAA,IACtB,CAAC,SAAS;AACR,UAAI,QAAQ,WAAW,SAAS;AAC9B,kBAAU,QAAQ,eAAe,CAAC,UAAkB;AAClD,gCAAsB,KAAK;AAAA,QAC7B;AACA,kBAAU,QAAQ,eAAe,MAAM;AACrC,0BAAgB;AAAA,QAClB;AACA,kBAAU,QAAQ,gCAAgC,MAAM;AACtD,iCAAuB;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,WAAW,uBAAuB,iBAAiB,sBAAsB;AAAA,EAC5E;AAEA,QAAM,uBAAmB;AAAA,IACvB,CAAC,SAAS;AACR,MAAC,aAAa,YAAkD,IAAI;AACpE,sBAAgB,IAAI;AAAA,IACtB;AAAA,IACA,CAAC,aAAa,aAAa,eAAe;AAAA,EAC5C;AAEA,QAAM,yBAAqB;AAAA,IACzB,CAAC,MAA8C;AAG7C,oBAAc,UAAW,EAAuB,WAAW,IAAI,mBAAmB;AAClF,gBAAU,CAAC;AAGX,UAAI,CAAC,cAAc;AACjB,YAAI,eAAgB,WAAU,EAAE,QAAQ,kBAAkB,OAAO,EAAE,CAAC;AAAA,YAC/D,UAAS,EAAE,QAAQ,WAAW,OAAO,EAAE,CAAC;AAAA,MAC/C;AACA,wBAAkB,CAAC,SAAS,CAAC,IAAI;AAAA,IACnC;AAAA,IACA,CAAC,SAAS,eAAe,mBAAmB,cAAc,gBAAgB,SAAS,MAAM;AAAA,EAC3F;AA4BA,QAAM,2BAAuB;AAAA,IAC3B,CAAC,MAA2B;AAC1B,UAAI,CAAC,wBAAyB;AAC9B,UAAI,EAAE,SAAS,eAAe,EAAE,SAAS,UAAW;AACpD,UAAI,eAAgB;AAEpB,QAAE,eAAe;AACjB,oBAAc,UAAU,EAAE,SAAS,cAAc,mBAAmB;AACpE,UAAI,CAAC,aAAc,UAAS,EAAE,QAAQ,WAAW,OAAO,EAAE,CAAC;AAC3D,wBAAkB,IAAI;AAAA,IACxB;AAAA,IACA,CAAC,yBAAyB,gBAAgB,eAAe,cAAc,QAAQ,iBAAiB;AAAA,EAClG;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }