@elliemae/ds-app-picker 3.70.0-next.61 → 3.70.0-next.62

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 (48) hide show
  1. package/dist/cjs/config/useAppPicker.js +2 -2
  2. package/dist/cjs/config/useAppPicker.js.map +2 -2
  3. package/dist/cjs/config/useFocusTracker.js +7 -7
  4. package/dist/cjs/config/useFocusTracker.js.map +2 -2
  5. package/dist/cjs/index.js +3 -1
  6. package/dist/cjs/index.js.map +2 -2
  7. package/dist/cjs/parts/AppPanel.js +5 -14
  8. package/dist/cjs/parts/AppPanel.js.map +2 -2
  9. package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js +12 -3
  10. package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js.map +2 -2
  11. package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +46 -22
  12. package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +2 -2
  13. package/dist/cjs/parts/Trigger.js +3 -1
  14. package/dist/cjs/parts/Trigger.js.map +2 -2
  15. package/dist/cjs/react-desc-prop-types.js +5 -1
  16. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  17. package/dist/cjs/typescript-testing/typescript-app-picker-valid.js +2 -1
  18. package/dist/cjs/typescript-testing/typescript-app-picker-valid.js.map +2 -2
  19. package/dist/cjs/util/getDSAppPickerContractProps.js +38 -0
  20. package/dist/cjs/util/getDSAppPickerContractProps.js.map +7 -0
  21. package/dist/esm/config/useAppPicker.js +2 -2
  22. package/dist/esm/config/useAppPicker.js.map +2 -2
  23. package/dist/esm/config/useFocusTracker.js +7 -7
  24. package/dist/esm/config/useFocusTracker.js.map +2 -2
  25. package/dist/esm/index.js +3 -1
  26. package/dist/esm/index.js.map +2 -2
  27. package/dist/esm/parts/AppPanel.js +5 -14
  28. package/dist/esm/parts/AppPanel.js.map +2 -2
  29. package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js +12 -3
  30. package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js.map +2 -2
  31. package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +46 -22
  32. package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +2 -2
  33. package/dist/esm/parts/Trigger.js +3 -1
  34. package/dist/esm/parts/Trigger.js.map +2 -2
  35. package/dist/esm/react-desc-prop-types.js +5 -1
  36. package/dist/esm/react-desc-prop-types.js.map +2 -2
  37. package/dist/esm/typescript-testing/typescript-app-picker-valid.js +2 -1
  38. package/dist/esm/typescript-testing/typescript-app-picker-valid.js.map +2 -2
  39. package/dist/esm/util/getDSAppPickerContractProps.js +8 -0
  40. package/dist/esm/util/getDSAppPickerContractProps.js.map +7 -0
  41. package/dist/types/config/useAppPicker.d.ts +2 -2
  42. package/dist/types/config/useFocusTracker.d.ts +1 -1
  43. package/dist/types/index.d.ts +1 -0
  44. package/dist/types/parts/AppPickerFloatingContext/useAppPickerFloatingContext.d.ts +3 -2
  45. package/dist/types/parts/Trigger.d.ts +1 -0
  46. package/dist/types/react-desc-prop-types.d.ts +32 -0
  47. package/dist/types/util/getDSAppPickerContractProps.d.ts +37 -0
  48. package/package.json +15 -14
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/parts/Trigger.tsx", "../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["import { DSButtonV3 } from '@elliemae/ds-button-v2';\nimport { styled } from '@elliemae/ds-system';\nimport React, { useContext } from 'react';\nimport { DSAppPickerDataTestIds, DSAppPickerName, DSAppPickerSlots } from '../constants/index.js';\nimport { DSAppPickerContext } from '../DSAppPickerCTX.js';\nimport type { useAppPickerFloatingContext } from './AppPickerFloatingContext/useAppPickerFloatingContext.js';\n\n// DSButtonV3 sizes itself with `min-height` (height stays `auto`) so multi-line labels can grow.\n// As a side effect, when the trigger is a direct grid/flex child of a consumer layout with the\n// default `align-items: stretch`, it stretches to fill the container height (PUI-18354 regression:\n// the legacy DSButtonV2 trigger used a fixed `height` and did not stretch). `height: fit-content`\n// pins the trigger to its intrinsic size \u2014 mirroring the button's own `width: fit-content` \u2014 so it\n// stays ~28px regardless of layout context.\nconst StyledButton = styled(DSButtonV3, { name: DSAppPickerName, slot: DSAppPickerSlots.BUTTON })`\n height: fit-content;\n`;\n\ntype UseAppPickerFloatingContextT = ReturnType<typeof useAppPickerFloatingContext>;\ntype FloatingContextDictatedProps = {\n handleTriggerRef: UseAppPickerFloatingContextT['handleTriggerRef'];\n handleTriggerClick: UseAppPickerFloatingContextT['handleTriggerClick'];\n dialogLabelId: string;\n};\n\nexport const Trigger = (PropsFromFloatingContext: FloatingContextDictatedProps) => {\n const { handleTriggerRef, handleTriggerClick, dialogLabelId } = PropsFromFloatingContext;\n const {\n propsWithDefault: { icon: Icon, renderTrigger, TriggerComponent },\n ownerPropsConfig,\n } = useContext(DSAppPickerContext);\n\n // Precedence: TriggerComponent > renderTrigger > the built-in button. TriggerComponent wins when\n // both custom APIs are supplied \u2014 it is the one that receives `dialogLabelId`, so preferring\n // renderTrigger here would drop the dialog's accessible name.\n if (TriggerComponent) {\n return (\n <TriggerComponent\n innerRef={handleTriggerRef}\n id={dialogLabelId}\n onClick={handleTriggerClick}\n aria-haspopup=\"dialog\"\n />\n );\n }\n\n if (renderTrigger) {\n // DEPRECATED (v4.x) \u2014 see DEV-002. Plain function call (not a React element) preserves the\n // legacy DSPopover render-prop contract: consumers receive `ref` as a regular prop, no\n // forwardRef required. The contract has no channel for `dialogLabelId`, so on this path naming\n // the dialog is the consumer's: put an id on the trigger element and inject the matching\n // aria-labelledby through the FLOATING_WRAPPER slot (or pass `id` to DSAppPicker, which makes\n // the generated id predictable). Covered by DSAppPicker.renderTrigger-ioc-aria-labelledby.test.js.\n return renderTrigger({ ref: handleTriggerRef });\n }\n return (\n <StyledButton\n data-testid={DSAppPickerDataTestIds.BUTTON}\n id={dialogLabelId}\n buttonType=\"icon\"\n aria-haspopup=\"dialog\"\n aria-label=\"Application picker\"\n innerRef={handleTriggerRef}\n onClick={handleTriggerClick}\n getOwnerProps={ownerPropsConfig.getOwnerProps}\n getOwnerPropsArguments={ownerPropsConfig.getOwnerPropsArguments}\n >\n <Icon />\n </StyledButton>\n );\n};\n\nTrigger.displayName = 'DSAppPicker.Trigger';\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADoCjB;AApCN,0BAA2B;AAC3B,uBAAuB;AACvB,mBAAkC;AAClC,uBAA0E;AAC1E,4BAAmC;AASnC,MAAM,mBAAe,yBAAO,gCAAY,EAAE,MAAM,kCAAiB,MAAM,kCAAiB,OAAO,CAAC;AAAA;AAAA;AAWzF,MAAM,UAAU,CAAC,6BAA2D;AACjF,QAAM,EAAE,kBAAkB,oBAAoB,cAAc,IAAI;AAChE,QAAM;AAAA,IACJ,kBAAkB,EAAE,MAAM,MAAM,eAAe,iBAAiB;AAAA,IAChE;AAAA,EACF,QAAI,yBAAW,wCAAkB;AAKjC,MAAI,kBAAkB;AACpB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,iBAAc;AAAA;AAAA,IAChB;AAAA,EAEJ;AAEA,MAAI,eAAe;AAOjB,WAAO,cAAc,EAAE,KAAK,iBAAiB,CAAC;AAAA,EAChD;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,wCAAuB;AAAA,MACpC,IAAI;AAAA,MACJ,YAAW;AAAA,MACX,iBAAc;AAAA,MACd,cAAW;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,MACT,eAAe,iBAAiB;AAAA,MAChC,wBAAwB,iBAAiB;AAAA,MAEzC,sDAAC,QAAK;AAAA;AAAA,EACR;AAEJ;AAEA,QAAQ,cAAc;",
4
+ "sourcesContent": ["import { DSButtonV3 } from '@elliemae/ds-button-v2';\nimport { styled } from '@elliemae/ds-system';\nimport React, { useContext } from 'react';\nimport { DSAppPickerDataTestIds, DSAppPickerName, DSAppPickerSlots } from '../constants/index.js';\nimport { DSAppPickerContext } from '../DSAppPickerCTX.js';\nimport type { useAppPickerFloatingContext } from './AppPickerFloatingContext/useAppPickerFloatingContext.js';\n\n// DSButtonV3 sizes itself with `min-height` (height stays `auto`) so multi-line labels can grow.\n// As a side effect, when the trigger is a direct grid/flex child of a consumer layout with the\n// default `align-items: stretch`, it stretches to fill the container height (PUI-18354 regression:\n// the legacy DSButtonV2 trigger used a fixed `height` and did not stretch). `height: fit-content`\n// pins the trigger to its intrinsic size \u2014 mirroring the button's own `width: fit-content` \u2014 so it\n// stays ~28px regardless of layout context.\nconst StyledButton = styled(DSButtonV3, { name: DSAppPickerName, slot: DSAppPickerSlots.BUTTON })`\n height: fit-content;\n`;\n\ntype UseAppPickerFloatingContextT = ReturnType<typeof useAppPickerFloatingContext>;\ntype FloatingContextDictatedProps = {\n handleTriggerRef: UseAppPickerFloatingContextT['handleTriggerRef'];\n handleTriggerClick: UseAppPickerFloatingContextT['handleTriggerClick'];\n handleTriggerKeyDown: UseAppPickerFloatingContextT['handleTriggerKeyDown'];\n dialogLabelId: string;\n};\n\nexport const Trigger = (PropsFromFloatingContext: FloatingContextDictatedProps) => {\n const { handleTriggerRef, handleTriggerClick, handleTriggerKeyDown, dialogLabelId } = PropsFromFloatingContext;\n const {\n propsWithDefault: { icon: Icon, renderTrigger, TriggerComponent },\n ownerPropsConfig,\n } = useContext(DSAppPickerContext);\n\n // Precedence: TriggerComponent > renderTrigger > the built-in button. TriggerComponent wins when\n // both custom APIs are supplied \u2014 it is the one that receives `dialogLabelId`, so preferring\n // renderTrigger here would drop the dialog's accessible name.\n if (TriggerComponent) {\n return (\n <TriggerComponent\n innerRef={handleTriggerRef}\n id={dialogLabelId}\n onClick={handleTriggerClick}\n onKeyDown={handleTriggerKeyDown}\n aria-haspopup=\"dialog\"\n />\n );\n }\n\n if (renderTrigger) {\n // DEPRECATED (v4.x) \u2014 see DEV-002. Plain function call (not a React element) preserves the\n // legacy DSPopover render-prop contract: consumers receive `ref` as a regular prop, no\n // forwardRef required. The contract has no channel for `dialogLabelId`, so on this path naming\n // the dialog is the consumer's: put an id on the trigger element and inject the matching\n // aria-labelledby through the FLOATING_WRAPPER slot (or pass `id` to DSAppPicker, which makes\n // the generated id predictable). Covered by DSAppPicker.renderTrigger-ioc-aria-labelledby.test.js.\n return renderTrigger({ ref: handleTriggerRef });\n }\n return (\n <StyledButton\n data-testid={DSAppPickerDataTestIds.BUTTON}\n id={dialogLabelId}\n buttonType=\"icon\"\n aria-haspopup=\"dialog\"\n aria-label=\"Application picker\"\n innerRef={handleTriggerRef}\n onClick={handleTriggerClick}\n onKeyDown={handleTriggerKeyDown}\n getOwnerProps={ownerPropsConfig.getOwnerProps}\n getOwnerPropsArguments={ownerPropsConfig.getOwnerPropsArguments}\n >\n <Icon />\n </StyledButton>\n );\n};\n\nTrigger.displayName = 'DSAppPicker.Trigger';\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADqCjB;AArCN,0BAA2B;AAC3B,uBAAuB;AACvB,mBAAkC;AAClC,uBAA0E;AAC1E,4BAAmC;AASnC,MAAM,mBAAe,yBAAO,gCAAY,EAAE,MAAM,kCAAiB,MAAM,kCAAiB,OAAO,CAAC;AAAA;AAAA;AAYzF,MAAM,UAAU,CAAC,6BAA2D;AACjF,QAAM,EAAE,kBAAkB,oBAAoB,sBAAsB,cAAc,IAAI;AACtF,QAAM;AAAA,IACJ,kBAAkB,EAAE,MAAM,MAAM,eAAe,iBAAiB;AAAA,IAChE;AAAA,EACF,QAAI,yBAAW,wCAAkB;AAKjC,MAAI,kBAAkB;AACpB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,WAAW;AAAA,QACX,iBAAc;AAAA;AAAA,IAChB;AAAA,EAEJ;AAEA,MAAI,eAAe;AAOjB,WAAO,cAAc,EAAE,KAAK,iBAAiB,CAAC;AAAA,EAChD;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa,wCAAuB;AAAA,MACpC,IAAI;AAAA,MACJ,YAAW;AAAA,MACX,iBAAc;AAAA,MACd,cAAW;AAAA,MACX,UAAU;AAAA,MACV,SAAS;AAAA,MACT,WAAW;AAAA,MACX,eAAe,iBAAiB;AAAA,MAChC,wBAAwB,iBAAiB;AAAA,MAEzC,sDAAC,QAAK;AAAA;AAAA,EACR;AAEJ;AAEA,QAAQ,cAAc;",
6
6
  "names": []
7
7
  }
@@ -43,7 +43,8 @@ const defaultProps = {
43
43
  customApps: [],
44
44
  sectionTitle: "APPLICATIONS",
45
45
  customSectionTitle: "CUSTOM APPLICATIONS",
46
- icon: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_icons.MenuPicker, { color: ["brand-primary", "700"], size: "m" })
46
+ icon: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_icons.MenuPicker, { color: ["brand-primary", "700"], size: "m" }),
47
+ openAndFocusOnArrowKeys: false
47
48
  };
48
49
  const DSAppPickerPropTypes = {
49
50
  ...(0, import_ds_props_helpers.getPropsPerSlotPropTypes)(import_constants.DSAppPickerName, import_constants.DSAppPickerSlots),
@@ -58,6 +59,9 @@ const DSAppPickerPropTypes = {
58
59
  sectionTitle: import_ds_props_helpers.PropTypes.string.description("main section title").defaultValue("APPLICATIONS"),
59
60
  customSectionTitle: import_ds_props_helpers.PropTypes.string.description("custom section title").defaultValue("CUSTOM APPLICATIONS"),
60
61
  icon: import_ds_props_helpers.PropTypes.func.description("trigger button s icon").defaultValue(import_ds_icons.MenuPicker),
62
+ openAndFocusOnArrowKeys: import_ds_props_helpers.PropTypes.bool.description(
63
+ "Opt in to arrow-key opening on the trigger. ArrowDown opens and focuses the selected application, falling back to the first available one; ArrowUp opens and focuses the selected application, falling back to the last available one. The picker owns the whole flow \u2014 no key handler, no isOpen wiring and no actionRef needed. Independent of actionRef, which remains the imperative handle for moving focus from your own logic."
64
+ ).defaultValue(false),
61
65
  renderTrigger: import_ds_props_helpers.PropTypes.func.description(
62
66
  "Custom trigger, called as a plain function with { ref }. Superseded by TriggerComponent: this render-prop cannot receive the id that the panel's aria-labelledby points at, so the dialog is left without an accessible name. TriggerComponent takes precedence when both are supplied."
63
67
  ).deprecated({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/react-desc-prop-types.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable @typescript-eslint/no-empty-interface */\nimport React from 'react';\nimport { MenuPicker } from '@elliemae/ds-icons';\nimport type { SvgIconT } from '@elliemae/ds-icons';\nimport type { GlobalAttributesT, XstyledProps, DSPropTypesSchema, ValidationMap } from '@elliemae/ds-props-helpers';\nimport {\n PropTypes,\n getPropsPerSlotPropTypes,\n globalAttributesPropTypes,\n xstyledPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport type { TypescriptHelpersT } from '@elliemae/ds-typescript-helpers';\nimport { DSAppPickerName, DSAppPickerSlots } from './constants/index.js';\n\nexport declare namespace DSAppPickerT {\n export interface AppItem {\n label: string;\n icon: React.ComponentType<{ className: string; size: string }>;\n onClick?: (e: React.MouseEvent, item: AppItem) => void | null;\n disabled?: boolean;\n applyAriaDisabled?: boolean;\n id?: string;\n selected?: boolean;\n wrapText?: boolean;\n }\n\n export type ActionRef = React.MutableRefObject<{\n focusToIndex?: (index: number) => void;\n focusSelectedOrFirstAvailable?: () => void;\n focusWrapper: () => void;\n }>;\n\n /**\n * Why the panel opened. `trigger` carries the activating event and fires synchronously in the\n * trigger's click handler (AppPicker owns the open). `controlled` fires when the consumer flips\n * the `isOpen` prop themselves \u2014 no event, delivered when that flip takes effect.\n */\n export type OpenChange =\n { reason: 'trigger'; event: React.MouseEvent | React.KeyboardEvent } | { reason: 'controlled' };\n\n /**\n * Why the panel closed. The event-carrying reasons fire synchronously from the handler that owns\n * the close (AppPicker in uncontrolled mode): `escape` (a scoped Escape), `click-outside`, and\n * `trigger-toggle` (the trigger clicked while open). `controlled` fires when the consumer flips the\n * `isOpen` prop themselves \u2014 no event, delivered when that flip takes effect.\n */\n export type CloseChange =\n | { reason: 'escape'; event: KeyboardEvent }\n | { reason: 'click-outside'; event: MouseEvent | TouchEvent }\n | { reason: 'trigger-toggle'; event: React.MouseEvent | React.KeyboardEvent }\n | { reason: 'controlled' };\n\n export interface RequiredProps {}\n\n export type SlotFunctionArguments = {\n dsApppickerRoot: () => object;\n dsApppickerGroup: () => object;\n dsApppickerItem: () => object;\n dsApppickerTitle: () => object;\n dsApppickerSeparator: () => object;\n dsApppickerRow: () => object;\n dsApppickerChip: () => object;\n dsApppickerButton: () => object;\n dsApppickerFloatingWrapper: () => object;\n };\n\n export interface DefaultProps {\n apps: AppItem[];\n customApps: AppItem[];\n sectionTitle: string;\n customSectionTitle: string;\n icon: React.ComponentType<SvgIconT.Props>;\n }\n\n interface RenderTriggerProp {\n ref: React.RefCallback<HTMLButtonElement>;\n [key: string]: unknown;\n }\n\n /**\n * Props handed to a `TriggerComponent`. This is the only trigger API that participates in the\n * dialog's accessible-name wiring: `id` is the element the panel's `aria-labelledby` points at,\n * so a TriggerComponent that drops it leaves the dialog unnamed.\n *\n * `innerRef`, not `ref`, deliberately: under React 18 a `ref` passed through JSX is consumed by\n * the fiber and never reaches a plain function component's props unless it is wrapped in\n * `forwardRef`. `innerRef` is the established Dimsum convention (see `ds-system`'s styled\n * components) and keeps `forwardRef` optional for the consumer \u2014 which is the same ergonomic\n * concern that produced DEV-002, solved here without the plain-function call.\n */\n export interface TriggerComponentProps {\n innerRef: React.RefCallback<HTMLButtonElement>;\n id: string;\n onClick: (e: React.MouseEvent | React.KeyboardEvent) => void;\n 'aria-haspopup': 'dialog';\n }\n\n export interface OptionalProps extends TypescriptHelpersT.PropsForGlobalOnSlots<\n typeof DSAppPickerName,\n typeof DSAppPickerSlots\n > {\n onOpen?: (info: OpenChange) => void;\n onClose?: (info: CloseChange) => void;\n onClick?: (e: React.MouseEvent | React.KeyboardEvent) => void;\n onClickOutside?: (e: MouseEvent | React.MouseEvent) => void;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n actionRef?: ActionRef;\n /**\n * @deprecated v4.x \u2014 use `TriggerComponent`. `renderTrigger` receives only `ref` and cannot be\n * given the id the dialog's `aria-labelledby` points at, so the panel is left without an\n * accessible name. See DEV-002 in KNOWN_INTENTIONAL_DEVIATIONS.md.\n */\n renderTrigger?: (props: RenderTriggerProp) => React.ReactElement | null;\n /**\n * Custom trigger, rendered as a real React element so it owns its own fiber. Takes precedence\n * over `renderTrigger` when both are supplied.\n */\n TriggerComponent?: React.ComponentType<TriggerComponentProps>;\n isOpen?: boolean;\n triggerRef?: React.RefObject<HTMLButtonElement>;\n }\n\n export interface Props\n extends\n Partial<DefaultProps>,\n OptionalProps,\n Omit<GlobalAttributesT<HTMLDivElement>, keyof DefaultProps | keyof OptionalProps | keyof XstyledProps>,\n XstyledProps,\n RequiredProps {}\n\n export interface InternalProps\n extends\n DefaultProps,\n OptionalProps,\n Omit<GlobalAttributesT<HTMLDivElement>, keyof DefaultProps | keyof OptionalProps | keyof XstyledProps>,\n XstyledProps,\n RequiredProps {}\n}\n\nexport const defaultProps: DSAppPickerT.DefaultProps = {\n apps: [],\n customApps: [],\n sectionTitle: 'APPLICATIONS',\n customSectionTitle: 'CUSTOM APPLICATIONS',\n icon: () => <MenuPicker color={['brand-primary', '700']} size=\"m\" />,\n};\n\n// =============================================================================\n// PropTypes\n// =============================================================================\n\nexport const DSAppPickerPropTypes: DSPropTypesSchema<DSAppPickerT.Props> = {\n ...getPropsPerSlotPropTypes(DSAppPickerName, DSAppPickerSlots),\n ...globalAttributesPropTypes,\n ...xstyledPropTypes,\n apps: PropTypes.array\n .description(\n 'Main items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]. ' +\n 'Conditionally required: at least one of \"apps\" or \"customApps\" must contain items \u2014 a picker with ' +\n 'nothing to pick has no purpose, so providing both empty throws.',\n )\n .defaultValue([]),\n customApps: PropTypes.array\n .description(\n 'Custom items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]. ' +\n 'Conditionally required: at least one of \"apps\" or \"customApps\" must contain items \u2014 a picker with ' +\n 'nothing to pick has no purpose, so providing both empty throws.',\n )\n .defaultValue([]),\n sectionTitle: PropTypes.string.description('main section title').defaultValue('APPLICATIONS'),\n customSectionTitle: PropTypes.string.description('custom section title').defaultValue('CUSTOM APPLICATIONS'),\n icon: PropTypes.func.description('trigger button s icon').defaultValue(MenuPicker),\n renderTrigger: PropTypes.func\n .description(\n 'Custom trigger, called as a plain function with { ref }. Superseded by TriggerComponent: this ' +\n \"render-prop cannot receive the id that the panel's aria-labelledby points at, so the dialog \" +\n 'is left without an accessible name. TriggerComponent takes precedence when both are supplied.',\n )\n .deprecated({\n version: '4.x',\n message: 'Use \"TriggerComponent\" instead \u2014 it receives the id required for the dialog accessible name.',\n }),\n TriggerComponent: PropTypes.func.description(\n 'Custom trigger rendered as a React element. Receives { innerRef, id, onClick, aria-haspopup }; ' +\n 'the id must be applied to the focusable trigger element for the panel to have an accessible name. ' +\n 'Takes precedence over the deprecated renderTrigger when both are supplied.',\n ),\n actionRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]).description(\n 'Ref containing a focusToIndex method. This method allows you to focus any App inside the AppPicker.',\n ),\n isOpen: PropTypes.bool.description('Wether the AppPicker should be open or not.'),\n onOpen: PropTypes.func.description(\n 'Callback when the AppPicker opens; receives { reason: \"trigger\" | \"controlled\", event? }.',\n ),\n onClose: PropTypes.func.description(\n 'Callback when the AppPicker closes; receives { reason: \"escape\" | \"click-outside\" | \"trigger-toggle\" | \"controlled\", event? }.',\n ),\n onKeyDown: PropTypes.func.description('OnKeyDown handler callback.'),\n onClick: PropTypes.func.description('Custom onClick for Trigger component.'),\n onClickOutside: PropTypes.func.description('Callback event when the user clicks outside the App Picker.'),\n triggerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]).description(\n 'Ref to the trigger button.',\n ),\n};\n\nexport const DSAppPickerPropTypesSchema = DSAppPickerPropTypes as unknown as ValidationMap<DSAppPickerT.Props>;\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADgJT;AA9Id,sBAA2B;AAG3B,8BAKO;AAEP,uBAAkD;AA+H3C,MAAM,eAA0C;AAAA,EACrD,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM,4CAAC,8BAAW,OAAO,CAAC,iBAAiB,KAAK,GAAG,MAAK,KAAI;AACpE;AAMO,MAAM,uBAA8D;AAAA,EACzE,OAAG,kDAAyB,kCAAiB,iCAAgB;AAAA,EAC7D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,MAAM,kCAAU,MACb;AAAA,IACC;AAAA,EAGF,EACC,aAAa,CAAC,CAAC;AAAA,EAClB,YAAY,kCAAU,MACnB;AAAA,IACC;AAAA,EAGF,EACC,aAAa,CAAC,CAAC;AAAA,EAClB,cAAc,kCAAU,OAAO,YAAY,oBAAoB,EAAE,aAAa,cAAc;AAAA,EAC5F,oBAAoB,kCAAU,OAAO,YAAY,sBAAsB,EAAE,aAAa,qBAAqB;AAAA,EAC3G,MAAM,kCAAU,KAAK,YAAY,uBAAuB,EAAE,aAAa,0BAAU;AAAA,EACjF,eAAe,kCAAU,KACtB;AAAA,IACC;AAAA,EAGF,EACC,WAAW;AAAA,IACV,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AAAA,EACH,kBAAkB,kCAAU,KAAK;AAAA,IAC/B;AAAA,EAGF;AAAA,EACA,WAAW,kCAAU,UAAU,CAAC,kCAAU,MAAM,kCAAU,MAAM,EAAE,SAAS,kCAAU,IAAI,CAAC,CAAC,CAAC,EAAE;AAAA,IAC5F;AAAA,EACF;AAAA,EACA,QAAQ,kCAAU,KAAK,YAAY,6CAA6C;AAAA,EAChF,QAAQ,kCAAU,KAAK;AAAA,IACrB;AAAA,EACF;AAAA,EACA,SAAS,kCAAU,KAAK;AAAA,IACtB;AAAA,EACF;AAAA,EACA,WAAW,kCAAU,KAAK,YAAY,6BAA6B;AAAA,EACnE,SAAS,kCAAU,KAAK,YAAY,uCAAuC;AAAA,EAC3E,gBAAgB,kCAAU,KAAK,YAAY,6DAA6D;AAAA,EACxG,YAAY,kCAAU,UAAU,CAAC,kCAAU,MAAM,kCAAU,MAAM,EAAE,SAAS,kCAAU,IAAI,CAAC,CAAC,CAAC,EAAE;AAAA,IAC7F;AAAA,EACF;AACF;AAEO,MAAM,6BAA6B;",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-empty-interface */\nimport React from 'react';\nimport { MenuPicker } from '@elliemae/ds-icons';\nimport type { SvgIconT } from '@elliemae/ds-icons';\nimport type { GlobalAttributesT, XstyledProps, DSPropTypesSchema, ValidationMap } from '@elliemae/ds-props-helpers';\nimport {\n PropTypes,\n getPropsPerSlotPropTypes,\n globalAttributesPropTypes,\n xstyledPropTypes,\n} from '@elliemae/ds-props-helpers';\nimport type { TypescriptHelpersT } from '@elliemae/ds-typescript-helpers';\nimport { DSAppPickerName, DSAppPickerSlots } from './constants/index.js';\n\nexport declare namespace DSAppPickerT {\n export interface AppItem {\n label: string;\n icon: React.ComponentType<{ className: string; size: string }>;\n onClick?: (e: React.MouseEvent, item: AppItem) => void | null;\n disabled?: boolean;\n applyAriaDisabled?: boolean;\n id?: string;\n selected?: boolean;\n wrapText?: boolean;\n }\n\n export type ActionRef = React.MutableRefObject<{\n focusToIndex?: (index: number) => void;\n focusSelectedOrFirstAvailable?: () => void;\n focusWrapper: () => void;\n }>;\n\n /**\n * Why the panel opened. `trigger` carries the activating event and fires synchronously in the\n * trigger's click handler (AppPicker owns the open). `controlled` fires when the consumer flips\n * the `isOpen` prop themselves \u2014 no event, delivered when that flip takes effect.\n */\n export type OpenChange =\n { reason: 'trigger'; event: React.MouseEvent | React.KeyboardEvent } | { reason: 'controlled' };\n\n /**\n * Why the panel closed. The event-carrying reasons fire synchronously from the handler that owns\n * the close (AppPicker in uncontrolled mode): `escape` (a scoped Escape), `click-outside`, and\n * `trigger-toggle` (the trigger clicked while open). `controlled` fires when the consumer flips the\n * `isOpen` prop themselves \u2014 no event, delivered when that flip takes effect.\n */\n export type CloseChange =\n | { reason: 'escape'; event: KeyboardEvent }\n | { reason: 'click-outside'; event: MouseEvent | TouchEvent }\n | { reason: 'trigger-toggle'; event: React.MouseEvent | React.KeyboardEvent }\n | { reason: 'controlled' };\n\n export interface RequiredProps {}\n\n export type SlotFunctionArguments = {\n dsApppickerRoot: () => object;\n dsApppickerGroup: () => object;\n dsApppickerItem: () => object;\n dsApppickerTitle: () => object;\n dsApppickerSeparator: () => object;\n dsApppickerRow: () => object;\n dsApppickerChip: () => object;\n dsApppickerButton: () => object;\n dsApppickerFloatingWrapper: () => object;\n };\n\n export interface DefaultProps {\n apps: AppItem[];\n customApps: AppItem[];\n sectionTitle: string;\n customSectionTitle: string;\n icon: React.ComponentType<SvgIconT.Props>;\n /**\n * Opt in to arrow-key opening on the trigger: ArrowDown opens and focuses the selected application\n * (the first available one when nothing is selected), ArrowUp opens and focuses the selected\n * application (the last available one when nothing is selected).\n *\n * The picker owns this flow end to end \u2014 a consumer does not wire a key handler, drive `isOpen`, or\n * reach through `actionRef` to place the focus. Defaults to `false`, so it is purely additive: a\n * picker that does not opt in behaves exactly as before, with the arrow keys doing nothing on the\n * trigger.\n *\n * Independent of `actionRef`, which stays the imperative handle for a consumer to move focus from\n * their own business logic at any time.\n */\n openAndFocusOnArrowKeys: boolean;\n }\n\n interface RenderTriggerProp {\n ref: React.RefCallback<HTMLButtonElement>;\n [key: string]: unknown;\n }\n\n /**\n * Props handed to a `TriggerComponent`. This is the only trigger API that participates in the\n * dialog's accessible-name wiring: `id` is the element the panel's `aria-labelledby` points at,\n * so a TriggerComponent that drops it leaves the dialog unnamed.\n *\n * `innerRef`, not `ref`, deliberately: under React 18 a `ref` passed through JSX is consumed by\n * the fiber and never reaches a plain function component's props unless it is wrapped in\n * `forwardRef`. `innerRef` is the established Dimsum convention (see `ds-system`'s styled\n * components) and keeps `forwardRef` optional for the consumer \u2014 which is the same ergonomic\n * concern that produced DEV-002, solved here without the plain-function call.\n */\n export interface TriggerComponentProps {\n innerRef: React.RefCallback<HTMLButtonElement>;\n id: string;\n onClick: (e: React.MouseEvent | React.KeyboardEvent) => void;\n /**\n * Attach to the trigger element alongside `onClick`. It is what implements\n * `openAndFocusOnArrowKeys`, and it is a keydown handler in its own right \u2014 never route a keydown\n * through `onClick` to get the same effect: `onClick` infers keyboard activation from the click's\n * `detail`, which is a property of clicks, not of key presses.\n *\n * Harmless to attach when `openAndFocusOnArrowKeys` is false \u2014 it ignores every key in that case.\n *\n * The keys it acts on are ArrowDown and ArrowUp. A trigger that drives its own `isOpen` \u2014 which makes\n * the picker's internal flip inert \u2014 has to open on those same two keys itself.\n */\n onKeyDown: (e: React.KeyboardEvent) => void;\n 'aria-haspopup': 'dialog';\n }\n\n /**\n * How the pending open was triggered, which is the only input to where initial focus lands:\n * `pointer` \u2192 the panel \u00B7 `keyboard-first` \u2192 the selection, else the first available item \u00B7\n * `keyboard-last` \u2192 the selection, else the last available item.\n */\n export type OpenIntent = 'pointer' | 'keyboard-first' | 'keyboard-last';\n\n export interface OptionalProps extends TypescriptHelpersT.PropsForGlobalOnSlots<\n typeof DSAppPickerName,\n typeof DSAppPickerSlots\n > {\n onOpen?: (info: OpenChange) => void;\n onClose?: (info: CloseChange) => void;\n onClick?: (e: React.MouseEvent | React.KeyboardEvent) => void;\n onClickOutside?: (e: MouseEvent | React.MouseEvent) => void;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n actionRef?: ActionRef;\n /**\n * @deprecated v4.x \u2014 use `TriggerComponent`. `renderTrigger` receives only `ref` and cannot be\n * given the id the dialog's `aria-labelledby` points at, so the panel is left without an\n * accessible name. See DEV-002 in KNOWN_INTENTIONAL_DEVIATIONS.md.\n */\n renderTrigger?: (props: RenderTriggerProp) => React.ReactElement | null;\n /**\n * Custom trigger, rendered as a real React element so it owns its own fiber. Takes precedence\n * over `renderTrigger` when both are supplied.\n */\n TriggerComponent?: React.ComponentType<TriggerComponentProps>;\n isOpen?: boolean;\n triggerRef?: React.RefObject<HTMLButtonElement>;\n }\n\n export interface Props\n extends\n Partial<DefaultProps>,\n OptionalProps,\n Omit<GlobalAttributesT<HTMLDivElement>, keyof DefaultProps | keyof OptionalProps | keyof XstyledProps>,\n XstyledProps,\n RequiredProps {}\n\n export interface InternalProps\n extends\n DefaultProps,\n OptionalProps,\n Omit<GlobalAttributesT<HTMLDivElement>, keyof DefaultProps | keyof OptionalProps | keyof XstyledProps>,\n XstyledProps,\n RequiredProps {}\n}\n\nexport const defaultProps: DSAppPickerT.DefaultProps = {\n apps: [],\n customApps: [],\n sectionTitle: 'APPLICATIONS',\n customSectionTitle: 'CUSTOM APPLICATIONS',\n icon: () => <MenuPicker color={['brand-primary', '700']} size=\"m\" />,\n openAndFocusOnArrowKeys: false,\n};\n\n// =============================================================================\n// PropTypes\n// =============================================================================\n\nexport const DSAppPickerPropTypes: DSPropTypesSchema<DSAppPickerT.Props> = {\n ...getPropsPerSlotPropTypes(DSAppPickerName, DSAppPickerSlots),\n ...globalAttributesPropTypes,\n ...xstyledPropTypes,\n apps: PropTypes.array\n .description(\n 'Main items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]. ' +\n 'Conditionally required: at least one of \"apps\" or \"customApps\" must contain items \u2014 a picker with ' +\n 'nothing to pick has no purpose, so providing both empty throws.',\n )\n .defaultValue([]),\n customApps: PropTypes.array\n .description(\n 'Custom items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]. ' +\n 'Conditionally required: at least one of \"apps\" or \"customApps\" must contain items \u2014 a picker with ' +\n 'nothing to pick has no purpose, so providing both empty throws.',\n )\n .defaultValue([]),\n sectionTitle: PropTypes.string.description('main section title').defaultValue('APPLICATIONS'),\n customSectionTitle: PropTypes.string.description('custom section title').defaultValue('CUSTOM APPLICATIONS'),\n icon: PropTypes.func.description('trigger button s icon').defaultValue(MenuPicker),\n openAndFocusOnArrowKeys: PropTypes.bool\n .description(\n 'Opt in to arrow-key opening on the trigger. ArrowDown opens and focuses the selected application, ' +\n 'falling back to the first available one; ArrowUp opens and focuses the selected application, falling ' +\n 'back to the last available one. The picker owns the whole flow \u2014 no key handler, no isOpen wiring and ' +\n 'no actionRef needed. Independent of actionRef, which remains the imperative handle for moving focus ' +\n 'from your own logic.',\n )\n .defaultValue(false),\n renderTrigger: PropTypes.func\n .description(\n 'Custom trigger, called as a plain function with { ref }. Superseded by TriggerComponent: this ' +\n \"render-prop cannot receive the id that the panel's aria-labelledby points at, so the dialog \" +\n 'is left without an accessible name. TriggerComponent takes precedence when both are supplied.',\n )\n .deprecated({\n version: '4.x',\n message: 'Use \"TriggerComponent\" instead \u2014 it receives the id required for the dialog accessible name.',\n }),\n TriggerComponent: PropTypes.func.description(\n 'Custom trigger rendered as a React element. Receives { innerRef, id, onClick, aria-haspopup }; ' +\n 'the id must be applied to the focusable trigger element for the panel to have an accessible name. ' +\n 'Takes precedence over the deprecated renderTrigger when both are supplied.',\n ),\n actionRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]).description(\n 'Ref containing a focusToIndex method. This method allows you to focus any App inside the AppPicker.',\n ),\n isOpen: PropTypes.bool.description('Wether the AppPicker should be open or not.'),\n onOpen: PropTypes.func.description(\n 'Callback when the AppPicker opens; receives { reason: \"trigger\" | \"controlled\", event? }.',\n ),\n onClose: PropTypes.func.description(\n 'Callback when the AppPicker closes; receives { reason: \"escape\" | \"click-outside\" | \"trigger-toggle\" | \"controlled\", event? }.',\n ),\n onKeyDown: PropTypes.func.description('OnKeyDown handler callback.'),\n onClick: PropTypes.func.description('Custom onClick for Trigger component.'),\n onClickOutside: PropTypes.func.description('Callback event when the user clicks outside the App Picker.'),\n triggerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]).description(\n 'Ref to the trigger button.',\n ),\n};\n\nexport const DSAppPickerPropTypesSchema = DSAppPickerPropTypes as unknown as ValidationMap<DSAppPickerT.Props>;\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADiLT;AA/Kd,sBAA2B;AAG3B,8BAKO;AAEP,uBAAkD;AAgK3C,MAAM,eAA0C;AAAA,EACrD,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM,4CAAC,8BAAW,OAAO,CAAC,iBAAiB,KAAK,GAAG,MAAK,KAAI;AAAA,EAClE,yBAAyB;AAC3B;AAMO,MAAM,uBAA8D;AAAA,EACzE,OAAG,kDAAyB,kCAAiB,iCAAgB;AAAA,EAC7D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,MAAM,kCAAU,MACb;AAAA,IACC;AAAA,EAGF,EACC,aAAa,CAAC,CAAC;AAAA,EAClB,YAAY,kCAAU,MACnB;AAAA,IACC;AAAA,EAGF,EACC,aAAa,CAAC,CAAC;AAAA,EAClB,cAAc,kCAAU,OAAO,YAAY,oBAAoB,EAAE,aAAa,cAAc;AAAA,EAC5F,oBAAoB,kCAAU,OAAO,YAAY,sBAAsB,EAAE,aAAa,qBAAqB;AAAA,EAC3G,MAAM,kCAAU,KAAK,YAAY,uBAAuB,EAAE,aAAa,0BAAU;AAAA,EACjF,yBAAyB,kCAAU,KAChC;AAAA,IACC;AAAA,EAKF,EACC,aAAa,KAAK;AAAA,EACrB,eAAe,kCAAU,KACtB;AAAA,IACC;AAAA,EAGF,EACC,WAAW;AAAA,IACV,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AAAA,EACH,kBAAkB,kCAAU,KAAK;AAAA,IAC/B;AAAA,EAGF;AAAA,EACA,WAAW,kCAAU,UAAU,CAAC,kCAAU,MAAM,kCAAU,MAAM,EAAE,SAAS,kCAAU,IAAI,CAAC,CAAC,CAAC,EAAE;AAAA,IAC5F;AAAA,EACF;AAAA,EACA,QAAQ,kCAAU,KAAK,YAAY,6CAA6C;AAAA,EAChF,QAAQ,kCAAU,KAAK;AAAA,IACrB;AAAA,EACF;AAAA,EACA,SAAS,kCAAU,KAAK;AAAA,IACtB;AAAA,EACF;AAAA,EACA,WAAW,kCAAU,KAAK,YAAY,6BAA6B;AAAA,EACnE,SAAS,kCAAU,KAAK,YAAY,uCAAuC;AAAA,EAC3E,gBAAgB,kCAAU,KAAK,YAAY,6DAA6D;AAAA,EACxG,YAAY,kCAAU,UAAU,CAAC,kCAAU,MAAM,kCAAU,MAAM,EAAE,SAAS,kCAAU,IAAI,CAAC,CAAC,CAAC,EAAE;AAAA,IAC7F;AAAA,EACF;AACF;AAEO,MAAM,6BAA6B;",
6
6
  "names": []
7
7
  }
@@ -48,7 +48,8 @@ const testCompleteDefaults = {
48
48
  customApps: [],
49
49
  sectionTitle: "",
50
50
  customSectionTitle: "",
51
- icon: () => null
51
+ icon: () => null,
52
+ openAndFocusOnArrowKeys: false
52
53
  };
53
54
  const testInternalProps = {
54
55
  ...testOptionalProps,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/typescript-testing/typescript-app-picker-valid.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */\nimport { DSAppPicker } from '../index.js';\nimport type { DSAppPickerT } from '../index.js';\n\n// test we expose the namespace and the namespace follows our deliverable conventions\ntype ComponentPropsForApp = DSAppPickerT.Props;\ntype ComponentPropsInternals = DSAppPickerT.InternalProps;\ntype ComponentPropsDefaultProps = DSAppPickerT.DefaultProps;\ntype ComponentPropsOptionalProps = DSAppPickerT.OptionalProps;\ntype ComponentPropsRequiredProps = DSAppPickerT.RequiredProps;\n\nconst testOptionalProps: ComponentPropsOptionalProps = {};\nconst testRequiredProps: ComponentPropsRequiredProps = {};\n\n// difference Props and InternalProps is that InternalProps has all the default props filled in\n// Props allows for partial defaults\nconst testPartialDefaults: Partial<ComponentPropsDefaultProps> = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n};\n\nconst testProps: ComponentPropsForApp = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testPartialDefaults,\n};\nconst testPropsAsSyntax = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testPartialDefaults,\n} as ComponentPropsForApp;\n// InternalProps requires all defaults to be filled in\nconst testCompleteDefaults: Required<ComponentPropsDefaultProps> = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n};\n\nconst testInternalProps: ComponentPropsInternals = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testCompleteDefaults,\n};\nconst testInternalPropsAsSyntax = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testCompleteDefaults,\n} as ComponentPropsInternals;\n\n// using the explicit type definition, if there is an error, it will be marked on the key that is wrong\nconst testExplicitDefinition: ComponentPropsForApp = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n};\n\n// using the \"as\" syntax, if there is an error, it will be marking the whole object as wrong because it is not compatible with the type\nconst testInferedTypeCompatibility = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n} as ComponentPropsForApp;\n\n// TriggerComponent is typed as a real component, so its props arrive through the fiber. The exported\n// TriggerComponentProps type is what a consumer annotates their own trigger with \u2014 if that type stops\n// being reachable from the namespace, or its members change shape, this stops compiling.\nconst CustomTrigger: React.ComponentType<DSAppPickerT.TriggerComponentProps> = ({ innerRef, id, onClick, ...rest }) => (\n <button ref={innerRef} id={id} onClick={onClick} type=\"button\" {...rest}>\n Open apps\n </button>\n);\n\n// A consumer may also declare the trigger inline without naming the props type; both must compile.\nconst testTriggerComponentProp: ComponentPropsOptionalProps = {\n TriggerComponent: CustomTrigger,\n};\n\nconst ExampleUsageComponent = () => (\n <>\n {/* works with explicitly casted props, all syntaxes */}\n <DSAppPicker {...testExplicitDefinition} />\n <DSAppPicker {...testInferedTypeCompatibility} />\n {/* works with inline values */}\n <DSAppPicker apps={[]} customApps={[]} sectionTitle=\"\" customSectionTitle=\"\" icon={() => null} />\n {/* multiple auto inference works */}\n <DSAppPicker apps={[]} customApps={[]} sectionTitle=\"\" customSectionTitle=\"\" icon={() => null} />\n {/* works with partial defaults */}\n {/* TriggerComponent \u2014 the supported custom trigger API */}\n <DSAppPicker apps={[]} TriggerComponent={CustomTrigger} />\n <DSAppPicker {...testTriggerComponentProp} apps={[]} />\n {/* renderTrigger \u2014 deprecated (v4.x) but must still type-check until removal */}\n <DSAppPicker apps={[]} renderTrigger={({ ref }) => <button ref={ref} type=\"button\" aria-label=\"banana\" />} />\n </>\n);\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA,YAAuB;AC4ErB;AA3EF,eAA4B;AAU5B,MAAM,oBAAiD,CAAC;AACxD,MAAM,oBAAiD,CAAC;AAIxD,MAAM,sBAA2D;AAAA,EAC/D,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAEA,MAAM,YAAkC;AAAA,EACtC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AACA,MAAM,oBAAoB;AAAA,EACxB,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,MAAM,uBAA6D;AAAA,EACjE,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAEA,MAAM,oBAA6C;AAAA,EACjD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AACA,MAAM,4BAA4B;AAAA,EAChC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAGA,MAAM,yBAA+C;AAAA,EACnD,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAGA,MAAM,+BAA+B;AAAA,EACnC,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAKA,MAAM,gBAAyE,CAAC,EAAE,UAAU,IAAI,SAAS,GAAG,KAAK,MAC/G,4CAAC,YAAO,KAAK,UAAU,IAAQ,SAAkB,MAAK,UAAU,GAAG,MAAM,uBAEzE;AAIF,MAAM,2BAAwD;AAAA,EAC5D,kBAAkB;AACpB;AAEA,MAAM,wBAAwB,MAC5B,4EAEE;AAAA,8CAAC,wBAAa,GAAG,wBAAwB;AAAA,EACzC,4CAAC,wBAAa,GAAG,8BAA8B;AAAA,EAE/C,4CAAC,wBAAY,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,cAAa,IAAG,oBAAmB,IAAG,MAAM,MAAM,MAAM;AAAA,EAE/F,4CAAC,wBAAY,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,cAAa,IAAG,oBAAmB,IAAG,MAAM,MAAM,MAAM;AAAA,EAG/F,4CAAC,wBAAY,MAAM,CAAC,GAAG,kBAAkB,eAAe;AAAA,EACxD,4CAAC,wBAAa,GAAG,0BAA0B,MAAM,CAAC,GAAG;AAAA,EAErD,4CAAC,wBAAY,MAAM,CAAC,GAAG,eAAe,CAAC,EAAE,IAAI,MAAM,4CAAC,YAAO,KAAU,MAAK,UAAS,cAAW,UAAS,GAAI;AAAA,GAC7G;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */\nimport { DSAppPicker } from '../index.js';\nimport type { DSAppPickerT } from '../index.js';\n\n// test we expose the namespace and the namespace follows our deliverable conventions\ntype ComponentPropsForApp = DSAppPickerT.Props;\ntype ComponentPropsInternals = DSAppPickerT.InternalProps;\ntype ComponentPropsDefaultProps = DSAppPickerT.DefaultProps;\ntype ComponentPropsOptionalProps = DSAppPickerT.OptionalProps;\ntype ComponentPropsRequiredProps = DSAppPickerT.RequiredProps;\n\nconst testOptionalProps: ComponentPropsOptionalProps = {};\nconst testRequiredProps: ComponentPropsRequiredProps = {};\n\n// difference Props and InternalProps is that InternalProps has all the default props filled in\n// Props allows for partial defaults\nconst testPartialDefaults: Partial<ComponentPropsDefaultProps> = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n};\n\nconst testProps: ComponentPropsForApp = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testPartialDefaults,\n};\nconst testPropsAsSyntax = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testPartialDefaults,\n} as ComponentPropsForApp;\n// InternalProps requires all defaults to be filled in\nconst testCompleteDefaults: Required<ComponentPropsDefaultProps> = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n openAndFocusOnArrowKeys: false,\n};\n\nconst testInternalProps: ComponentPropsInternals = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testCompleteDefaults,\n};\nconst testInternalPropsAsSyntax = {\n ...testOptionalProps,\n ...testRequiredProps,\n ...testCompleteDefaults,\n} as ComponentPropsInternals;\n\n// using the explicit type definition, if there is an error, it will be marked on the key that is wrong\nconst testExplicitDefinition: ComponentPropsForApp = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n};\n\n// using the \"as\" syntax, if there is an error, it will be marking the whole object as wrong because it is not compatible with the type\nconst testInferedTypeCompatibility = {\n apps: [],\n customApps: [],\n sectionTitle: '',\n customSectionTitle: '',\n icon: () => null,\n} as ComponentPropsForApp;\n\n// TriggerComponent is typed as a real component, so its props arrive through the fiber. The exported\n// TriggerComponentProps type is what a consumer annotates their own trigger with \u2014 if that type stops\n// being reachable from the namespace, or its members change shape, this stops compiling.\nconst CustomTrigger: React.ComponentType<DSAppPickerT.TriggerComponentProps> = ({ innerRef, id, onClick, ...rest }) => (\n <button ref={innerRef} id={id} onClick={onClick} type=\"button\" {...rest}>\n Open apps\n </button>\n);\n\n// A consumer may also declare the trigger inline without naming the props type; both must compile.\nconst testTriggerComponentProp: ComponentPropsOptionalProps = {\n TriggerComponent: CustomTrigger,\n};\n\nconst ExampleUsageComponent = () => (\n <>\n {/* works with explicitly casted props, all syntaxes */}\n <DSAppPicker {...testExplicitDefinition} />\n <DSAppPicker {...testInferedTypeCompatibility} />\n {/* works with inline values */}\n <DSAppPicker apps={[]} customApps={[]} sectionTitle=\"\" customSectionTitle=\"\" icon={() => null} />\n {/* multiple auto inference works */}\n <DSAppPicker apps={[]} customApps={[]} sectionTitle=\"\" customSectionTitle=\"\" icon={() => null} />\n {/* works with partial defaults */}\n {/* TriggerComponent \u2014 the supported custom trigger API */}\n <DSAppPicker apps={[]} TriggerComponent={CustomTrigger} />\n <DSAppPicker {...testTriggerComponentProp} apps={[]} />\n {/* renderTrigger \u2014 deprecated (v4.x) but must still type-check until removal */}\n <DSAppPicker apps={[]} renderTrigger={({ ref }) => <button ref={ref} type=\"button\" aria-label=\"banana\" />} />\n </>\n);\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA,YAAuB;AC6ErB;AA5EF,eAA4B;AAU5B,MAAM,oBAAiD,CAAC;AACxD,MAAM,oBAAiD,CAAC;AAIxD,MAAM,sBAA2D;AAAA,EAC/D,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAEA,MAAM,YAAkC;AAAA,EACtC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AACA,MAAM,oBAAoB;AAAA,EACxB,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,MAAM,uBAA6D;AAAA,EACjE,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AAAA,EACZ,yBAAyB;AAC3B;AAEA,MAAM,oBAA6C;AAAA,EACjD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AACA,MAAM,4BAA4B;AAAA,EAChC,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAGA,MAAM,yBAA+C;AAAA,EACnD,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAGA,MAAM,+BAA+B;AAAA,EACnC,MAAM,CAAC;AAAA,EACP,YAAY,CAAC;AAAA,EACb,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,MAAM,MAAM;AACd;AAKA,MAAM,gBAAyE,CAAC,EAAE,UAAU,IAAI,SAAS,GAAG,KAAK,MAC/G,4CAAC,YAAO,KAAK,UAAU,IAAQ,SAAkB,MAAK,UAAU,GAAG,MAAM,uBAEzE;AAIF,MAAM,2BAAwD;AAAA,EAC5D,kBAAkB;AACpB;AAEA,MAAM,wBAAwB,MAC5B,4EAEE;AAAA,8CAAC,wBAAa,GAAG,wBAAwB;AAAA,EACzC,4CAAC,wBAAa,GAAG,8BAA8B;AAAA,EAE/C,4CAAC,wBAAY,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,cAAa,IAAG,oBAAmB,IAAG,MAAM,MAAM,MAAM;AAAA,EAE/F,4CAAC,wBAAY,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,cAAa,IAAG,oBAAmB,IAAG,MAAM,MAAM,MAAM;AAAA,EAG/F,4CAAC,wBAAY,MAAM,CAAC,GAAG,kBAAkB,eAAe;AAAA,EACxD,4CAAC,wBAAa,GAAG,0BAA0B,MAAM,CAAC,GAAG;AAAA,EAErD,4CAAC,wBAAY,MAAM,CAAC,GAAG,eAAe,CAAC,EAAE,IAAI,MAAM,4CAAC,YAAO,KAAU,MAAK,UAAS,cAAW,UAAS,GAAI;AAAA,GAC7G;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,38 @@
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 getDSAppPickerContractProps_exports = {};
30
+ __export(getDSAppPickerContractProps_exports, {
31
+ getDSAppPickerContractProps: () => getDSAppPickerContractProps
32
+ });
33
+ module.exports = __toCommonJS(getDSAppPickerContractProps_exports);
34
+ var React = __toESM(require("react"));
35
+ var import_ds_props_helpers = require("@elliemae/ds-props-helpers");
36
+ var import_react_desc_prop_types = require("../react-desc-prop-types.js");
37
+ const getDSAppPickerContractProps = (props) => (0, import_ds_props_helpers.getContractProps)(props, import_react_desc_prop_types.DSAppPickerPropTypes);
38
+ //# sourceMappingURL=getDSAppPickerContractProps.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/util/getDSAppPickerContractProps.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import { getContractProps } from '@elliemae/ds-props-helpers';\nimport { DSAppPickerPropTypes, type DSAppPickerT } from '../react-desc-prop-types.js';\n\n/**\n * Filters an arbitrary object down to the props DSAppPicker actually accepts.\n *\n * **Who this is for.** Components that wrap DSAppPicker and receive its props indirectly \u2014 as a\n * configuration object from their own consumer rather than as JSX props.\n *\n * The canonical case is `ds-global-header`, whose `toolbar` config carries a `componentProps` object for\n * the `ds-app-picker` item type. Such a wrapper cannot spread that object blindly: its config type is\n * DSAppPicker's props *plus* the wrapper's own \u2014 `triggerOnClick` there \u2014 and those must not leak into\n * DSAppPicker.\n *\n * Do not swap this for a hand-listed set of forwardable keys. A hand-list has no way to fail when the\n * contract grows: the new prop type-checks at the call site, is dropped silently at runtime, and nothing\n * reports it. Deriving the set from the contract is what makes that class of bug impossible.\n *\n * **Why a utility instead of exporting the schema.** `DSAppPickerPropTypes` is internal. It exists to\n * drive prop validation and the Storybook props table; that it also happens to describe the exact set\n * of forwardable props is a convenience today, not a promise. Exposing the schema would weld those\n * concerns together and make every future change to it a public API change. Exposing this utility\n * instead means the public commitment is only \"you get the props DSAppPicker accepts\" \u2014 if the two\n * ever need to diverge, only this function changes.\n *\n * Anything the contract does not declare is discarded. Arbitrary `data-*` attributes are kept (a\n * supported consumer surface no schema can enumerate).\n *\n * `undefined` vs `null` \u2014 see `getContractProps` for the implemented rule and the React precedent it\n * follows. In short: `undefined` is dropped (\"I am not defining this, you decide\" \u2014 the wrapper's\n * default stands), `null` is forwarded (\"I am explicitly asking for nothing\") and is then judged by\n * DSAppPicker's own strictly-typed contract, which rejects it for props whose declared type does not\n * admit null. To disable a handler, pass an explicit no-op (`() => {}`) \u2014 it honours the type and\n * states the intent unambiguously.\n *\n * @param props - the object to filter, typically a wrapper's `componentProps` configuration\n * @returns a new object containing only props DSAppPicker declares\n */\nexport const getDSAppPickerContractProps = (props: object): Partial<DSAppPickerT.Props> =>\n getContractProps<DSAppPickerT.Props>(props, DSAppPickerPropTypes);\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,8BAAiC;AACjC,mCAAwD;AAqCjD,MAAM,8BAA8B,CAAC,cAC1C,0CAAqC,OAAO,iDAAoB;",
6
+ "names": []
7
+ }
@@ -16,7 +16,7 @@ const useAppPicker = (props) => {
16
16
  const ownerPropsConfig = useOwnerProps(propsWithDefault, propsWithDefault);
17
17
  const globalAttributes = useGetGlobalAttributes(props);
18
18
  const xstyledProps = useGetXstyledProps(props);
19
- const wasOpenedByKeyboardRef = useRef(false);
19
+ const openIntentRef = useRef("pointer");
20
20
  const { isOpen, apps, customApps, id } = propsWithDefault;
21
21
  const [internalIsOpen, setInternalIsOpen] = useState(false);
22
22
  const resolvedIsOpen = typeof isOpen === "boolean" ? isOpen : internalIsOpen;
@@ -32,7 +32,7 @@ const useAppPicker = (props) => {
32
32
  ownerPropsConfig,
33
33
  globalAttributes,
34
34
  xstyledProps,
35
- wasOpenedByKeyboardRef,
35
+ openIntentRef,
36
36
  mountedOpenAutofocusPendingRef,
37
37
  resolvedIsOpen,
38
38
  setInternalIsOpen,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useAppPicker.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import {\n useGetGlobalAttributes,\n useGetXstyledProps,\n useMemoMergePropsWithDefault,\n useOwnerProps,\n} from '@elliemae/ds-props-helpers';\nimport React, { useMemo, useRef, useState } from 'react';\nimport { uid } from 'uid';\nimport { type DSAppPickerT, defaultProps, DSAppPickerPropTypesSchema } from '../react-desc-prop-types.js';\nimport { useFocusTracker } from './useFocusTracker.js';\nimport { useValidateProps } from './useValidateProps.js';\n\nexport const useAppPicker = (props: DSAppPickerT.Props) => {\n // =============================================================================\n // MERGE WITH DEFAULT AND VALIDATE PROPS\n // =============================================================================\n const propsWithDefault = useMemoMergePropsWithDefault<DSAppPickerT.InternalProps>(props, defaultProps);\n useValidateProps(propsWithDefault, DSAppPickerPropTypesSchema);\n // =============================================================================\n // GLOBAL ATTRIBUTES & XSTYLED PROPS\n // =============================================================================\n // Use propsWithDefault (stable, deep-comparison memoized) instead of { ...props }\n // to prevent getOwnerPropsArguments from creating a new object reference every render.\n const ownerPropsConfig = useOwnerProps(propsWithDefault, propsWithDefault);\n\n const globalAttributes = useGetGlobalAttributes<DSAppPickerT.Props>(props);\n const xstyledProps = useGetXstyledProps<DSAppPickerT.Props>(props);\n // =============================================================================\n // Specific component state and logics\n // =============================================================================\n const wasOpenedByKeyboardRef = useRef(false);\n\n // \"Is the panel open\" is top-level component state. `isOpen` (controlled) takes precedence over\n // the internal state when provided. resolvedIsOpen feeds useFloatingContext's\n // externallyControlledIsOpen; initial-focus-on-open is driven off useFloatingContext's onOpen\n // (which fires on that transition), so the focus tracker itself stays a pure region tracker with\n // no open-state awareness.\n const { isOpen, apps, customApps, id } = propsWithDefault;\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const resolvedIsOpen = typeof isOpen === 'boolean' ? isOpen : internalIsOpen;\n\n // Was DSAppPicker rendered already-open at mount (declarative `isOpen`, before any user\n // interaction)? Such an open is not a transition, so useAppPickerFloatingContext's onOpen seed\n // never fires for it \u2014 AppPanel's useMountedOpenAutofocusNuance consumes this to seed that one\n // case. Captured once; the nuance flips it false after consuming so a later controlled reopen\n // (a real transition, handled by onOpen) doesn't re-trigger it.\n const mountedOpenAutofocusPendingRef = useRef(resolvedIsOpen);\n\n const allApps = useMemo(() => [...apps, ...customApps], [apps, customApps]);\n const useFocusTrackerConfig = useMemo(() => ({ allApps }), [allApps]);\n const focusTrackers = useFocusTracker(useFocusTrackerConfig);\n\n const instanceUid = React.useMemo(() => id || `ds-app-picker-${uid(5)}`, [id]);\n\n return React.useMemo(\n () => ({\n focusTrackers,\n propsWithDefault,\n ownerPropsConfig,\n globalAttributes,\n xstyledProps,\n wasOpenedByKeyboardRef,\n mountedOpenAutofocusPendingRef,\n resolvedIsOpen,\n setInternalIsOpen,\n instanceUid,\n }),\n [focusTrackers, propsWithDefault, ownerPropsConfig, globalAttributes, xstyledProps, resolvedIsOpen, instanceUid],\n );\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAOA,UAAS,SAAS,QAAQ,gBAAgB;AACjD,SAAS,WAAW;AACpB,SAA4B,cAAc,kCAAkC;AAC5E,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAE1B,MAAM,eAAe,CAAC,UAA8B;AAIzD,QAAM,mBAAmB,6BAAyD,OAAO,YAAY;AACrG,mBAAiB,kBAAkB,0BAA0B;AAM7D,QAAM,mBAAmB,cAAc,kBAAkB,gBAAgB;AAEzE,QAAM,mBAAmB,uBAA2C,KAAK;AACzE,QAAM,eAAe,mBAAuC,KAAK;AAIjE,QAAM,yBAAyB,OAAO,KAAK;AAO3C,QAAM,EAAE,QAAQ,MAAM,YAAY,GAAG,IAAI;AACzC,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,iBAAiB,OAAO,WAAW,YAAY,SAAS;AAO9D,QAAM,iCAAiC,OAAO,cAAc;AAE5D,QAAM,UAAU,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAG,UAAU,GAAG,CAAC,MAAM,UAAU,CAAC;AAC1E,QAAM,wBAAwB,QAAQ,OAAO,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC;AACpE,QAAM,gBAAgB,gBAAgB,qBAAqB;AAE3D,QAAM,cAAcA,OAAM,QAAQ,MAAM,MAAM,iBAAiB,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAE7E,SAAOA,OAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,eAAe,kBAAkB,kBAAkB,kBAAkB,cAAc,gBAAgB,WAAW;AAAA,EACjH;AACF;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import {\n useGetGlobalAttributes,\n useGetXstyledProps,\n useMemoMergePropsWithDefault,\n useOwnerProps,\n} from '@elliemae/ds-props-helpers';\nimport React, { useMemo, useRef, useState } from 'react';\nimport { uid } from 'uid';\nimport { type DSAppPickerT, defaultProps, DSAppPickerPropTypesSchema } from '../react-desc-prop-types.js';\nimport { useFocusTracker } from './useFocusTracker.js';\nimport { useValidateProps } from './useValidateProps.js';\n\nexport const useAppPicker = (props: DSAppPickerT.Props) => {\n // =============================================================================\n // MERGE WITH DEFAULT AND VALIDATE PROPS\n // =============================================================================\n const propsWithDefault = useMemoMergePropsWithDefault<DSAppPickerT.InternalProps>(props, defaultProps);\n useValidateProps(propsWithDefault, DSAppPickerPropTypesSchema);\n // =============================================================================\n // GLOBAL ATTRIBUTES & XSTYLED PROPS\n // =============================================================================\n // Use propsWithDefault (stable, deep-comparison memoized) instead of { ...props }\n // to prevent getOwnerPropsArguments from creating a new object reference every render.\n const ownerPropsConfig = useOwnerProps(propsWithDefault, propsWithDefault);\n\n const globalAttributes = useGetGlobalAttributes<DSAppPickerT.Props>(props);\n const xstyledProps = useGetXstyledProps<DSAppPickerT.Props>(props);\n // =============================================================================\n // Specific component state and logics\n // =============================================================================\n /*\n * HOW the pending open was triggered, which is the only input to where initial focus lands.\n *\n * A union rather than a boolean because there are three landings, not two: a pointer open goes to the\n * panel, ArrowDown-style keyboard activation goes to the selection or the FIRST item, and ArrowUp goes to\n * the selection or the LAST one. Keeping it as one value means there is exactly one thing to read in\n * handleFloatingOpen, so nothing else can end up writing a competing focus intent.\n */\n const openIntentRef = useRef<DSAppPickerT.OpenIntent>('pointer');\n\n // \"Is the panel open\" is top-level component state. `isOpen` (controlled) takes precedence over\n // the internal state when provided. resolvedIsOpen feeds useFloatingContext's\n // externallyControlledIsOpen; initial-focus-on-open is driven off useFloatingContext's onOpen\n // (which fires on that transition), so the focus tracker itself stays a pure region tracker with\n // no open-state awareness.\n const { isOpen, apps, customApps, id } = propsWithDefault;\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const resolvedIsOpen = typeof isOpen === 'boolean' ? isOpen : internalIsOpen;\n\n // Was DSAppPicker rendered already-open at mount (declarative `isOpen`, before any user\n // interaction)? Such an open is not a transition, so useAppPickerFloatingContext's onOpen seed\n // never fires for it \u2014 AppPanel's useMountedOpenAutofocusNuance consumes this to seed that one\n // case. Captured once; the nuance flips it false after consuming so a later controlled reopen\n // (a real transition, handled by onOpen) doesn't re-trigger it.\n const mountedOpenAutofocusPendingRef = useRef(resolvedIsOpen);\n\n const allApps = useMemo(() => [...apps, ...customApps], [apps, customApps]);\n const useFocusTrackerConfig = useMemo(() => ({ allApps }), [allApps]);\n const focusTrackers = useFocusTracker(useFocusTrackerConfig);\n\n const instanceUid = React.useMemo(() => id || `ds-app-picker-${uid(5)}`, [id]);\n\n return React.useMemo(\n () => ({\n focusTrackers,\n propsWithDefault,\n ownerPropsConfig,\n globalAttributes,\n xstyledProps,\n openIntentRef,\n mountedOpenAutofocusPendingRef,\n resolvedIsOpen,\n setInternalIsOpen,\n instanceUid,\n }),\n [focusTrackers, propsWithDefault, ownerPropsConfig, globalAttributes, xstyledProps, resolvedIsOpen, instanceUid],\n );\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAOA,UAAS,SAAS,QAAQ,gBAAgB;AACjD,SAAS,WAAW;AACpB,SAA4B,cAAc,kCAAkC;AAC5E,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAE1B,MAAM,eAAe,CAAC,UAA8B;AAIzD,QAAM,mBAAmB,6BAAyD,OAAO,YAAY;AACrG,mBAAiB,kBAAkB,0BAA0B;AAM7D,QAAM,mBAAmB,cAAc,kBAAkB,gBAAgB;AAEzE,QAAM,mBAAmB,uBAA2C,KAAK;AACzE,QAAM,eAAe,mBAAuC,KAAK;AAYjE,QAAM,gBAAgB,OAAgC,SAAS;AAO/D,QAAM,EAAE,QAAQ,MAAM,YAAY,GAAG,IAAI;AACzC,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,iBAAiB,OAAO,WAAW,YAAY,SAAS;AAO9D,QAAM,iCAAiC,OAAO,cAAc;AAE5D,QAAM,UAAU,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAG,UAAU,GAAG,CAAC,MAAM,UAAU,CAAC;AAC1E,QAAM,wBAAwB,QAAQ,OAAO,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC;AACpE,QAAM,gBAAgB,gBAAgB,qBAAqB;AAE3D,QAAM,cAAcA,OAAM,QAAQ,MAAM,MAAM,iBAAiB,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAE7E,SAAOA,OAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,eAAe,kBAAkB,kBAAkB,kBAAkB,cAAc,gBAAgB,WAAW;AAAA,EACjH;AACF;",
6
6
  "names": ["React"]
7
7
  }
@@ -27,11 +27,11 @@ const useFocusTracker = (config) => {
27
27
  const index = selectedIdx !== -1 ? selectedIdx : allApps.findIndex((app) => !app.disabled);
28
28
  if (index !== -1) setFocusRegion(getChipRegionId(getChipId(allApps[index], index)));
29
29
  }, [allApps]);
30
- const trackFocusFirstItem = useCallback(() => {
31
- if (firstFocusableIdx !== -1) {
32
- setFocusRegion(getChipRegionId(getChipId(allApps[firstFocusableIdx], firstFocusableIdx)));
33
- }
34
- }, [firstFocusableIdx, allApps]);
30
+ const trackFocusSelectedOrLastItem = useCallback(() => {
31
+ const selectedIdx = allApps.findIndex((app) => app.selected);
32
+ const index = selectedIdx !== -1 ? selectedIdx : lastFocusableIdx;
33
+ if (index !== -1) setFocusRegion(getChipRegionId(getChipId(allApps[index], index)));
34
+ }, [allApps, lastFocusableIdx]);
35
35
  const trackFocusItemAtIndex = useCallback(
36
36
  (index) => {
37
37
  const target = allApps[index];
@@ -51,7 +51,7 @@ const useFocusTracker = (config) => {
51
51
  trackFocusTrigger,
52
52
  trackFocusPanel,
53
53
  trackFocusSelectedItem,
54
- trackFocusFirstItem,
54
+ trackFocusSelectedOrLastItem,
55
55
  trackFocusItemAtIndex
56
56
  }),
57
57
  [
@@ -63,7 +63,7 @@ const useFocusTracker = (config) => {
63
63
  trackFocusTrigger,
64
64
  trackFocusPanel,
65
65
  trackFocusSelectedItem,
66
- trackFocusFirstItem,
66
+ trackFocusSelectedOrLastItem,
67
67
  trackFocusItemAtIndex
68
68
  ]
69
69
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useFocusTracker.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useCallback, useMemo, useRef, useState } from 'react';\nimport { APP_PICKER_REGION_FOCUSES } from '../constants/index.js';\nimport type { DSAppPickerT } from '../react-desc-prop-types.js';\nimport { getChipId } from '../util/getChipId.js';\nimport { getChipRegionId } from '../util/getChipRegionId.js';\n\ntype FocusTrackerConfigT = {\n allApps: DSAppPickerT.AppItem[];\n};\n\nexport const useFocusTracker = (config: FocusTrackerConfigT) => {\n const { allApps } = config;\n\n // Flat indices of the first/last non-disabled item, used to mark the focus-trap edges.\n // AppSection passes isFirstFocusable/isLastFocusable to AppPickerItem, which sets\n // firstFocusableRef/lastFocusableRef when its innerRef fires.\n const firstFocusableIdx = useMemo(() => allApps.findIndex((app) => !app.disabled), [allApps]);\n const lastFocusableIdx = useMemo(() => allApps.reduce((acc, app, i) => (!app.disabled ? i : acc), -1), [allApps]);\n\n const [focusRegion, setFocusRegion] = useState<string>(APP_PICKER_REGION_FOCUSES.RESET);\n\n // DOM refs for the first and last focusable chips \u2014 set by AppPickerItem's innerRef.\n // Used by useFocusTrap in AppPanel so the focus trap needs no DOM query.\n const firstFocusableRef = useRef<HTMLElement | null>(null);\n const lastFocusableRef = useRef<HTMLElement | null>(null);\n\n const trackFocusChip = useCallback((chipId: string) => {\n setFocusRegion(getChipRegionId(chipId));\n }, []);\n\n const trackFocusRegionReset = useCallback(() => {\n setFocusRegion(APP_PICKER_REGION_FOCUSES.RESET);\n }, []);\n\n const trackFocusTrigger = useCallback(() => {\n setFocusRegion(APP_PICKER_REGION_FOCUSES.TRIGGER);\n }, []);\n\n const trackFocusPanel = useCallback(() => {\n setFocusRegion(APP_PICKER_REGION_FOCUSES.PANEL);\n }, []);\n\n const trackFocusSelectedItem = useCallback(() => {\n const selectedIdx = allApps.findIndex((app) => app.selected);\n const index = selectedIdx !== -1 ? selectedIdx : allApps.findIndex((app) => !app.disabled);\n if (index !== -1) setFocusRegion(getChipRegionId(getChipId(allApps[index], index)));\n }, [allApps]);\n\n const trackFocusFirstItem = useCallback(() => {\n if (firstFocusableIdx !== -1) {\n setFocusRegion(getChipRegionId(getChipId(allApps[firstFocusableIdx], firstFocusableIdx)));\n }\n }, [firstFocusableIdx, allApps]);\n\n const trackFocusItemAtIndex = useCallback(\n (index: number) => {\n const target = allApps[index];\n if (target) setFocusRegion(getChipRegionId(getChipId(target, index)));\n },\n [allApps],\n );\n\n return useMemo(\n () => ({\n firstFocusableIdx,\n lastFocusableIdx,\n focusRegion,\n firstFocusableRef,\n lastFocusableRef,\n trackFocusChip,\n trackFocusRegionReset,\n trackFocusTrigger,\n trackFocusPanel,\n trackFocusSelectedItem,\n trackFocusFirstItem,\n trackFocusItemAtIndex,\n }),\n [\n firstFocusableIdx,\n lastFocusableIdx,\n focusRegion,\n trackFocusChip,\n trackFocusRegionReset,\n trackFocusTrigger,\n trackFocusPanel,\n trackFocusSelectedItem,\n trackFocusFirstItem,\n trackFocusItemAtIndex,\n ],\n );\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,SAAS,QAAQ,gBAAgB;AACvD,SAAS,iCAAiC;AAE1C,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAMzB,MAAM,kBAAkB,CAAC,WAAgC;AAC9D,QAAM,EAAE,QAAQ,IAAI;AAKpB,QAAM,oBAAoB,QAAQ,MAAM,QAAQ,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,OAAO,CAAC;AAC5F,QAAM,mBAAmB,QAAQ,MAAM,QAAQ,OAAO,CAAC,KAAK,KAAK,MAAO,CAAC,IAAI,WAAW,IAAI,KAAM,EAAE,GAAG,CAAC,OAAO,CAAC;AAEhH,QAAM,CAAC,aAAa,cAAc,IAAI,SAAiB,0BAA0B,KAAK;AAItF,QAAM,oBAAoB,OAA2B,IAAI;AACzD,QAAM,mBAAmB,OAA2B,IAAI;AAExD,QAAM,iBAAiB,YAAY,CAAC,WAAmB;AACrD,mBAAe,gBAAgB,MAAM,CAAC;AAAA,EACxC,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAwB,YAAY,MAAM;AAC9C,mBAAe,0BAA0B,KAAK;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,QAAM,oBAAoB,YAAY,MAAM;AAC1C,mBAAe,0BAA0B,OAAO;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,YAAY,MAAM;AACxC,mBAAe,0BAA0B,KAAK;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,QAAM,yBAAyB,YAAY,MAAM;AAC/C,UAAM,cAAc,QAAQ,UAAU,CAAC,QAAQ,IAAI,QAAQ;AAC3D,UAAM,QAAQ,gBAAgB,KAAK,cAAc,QAAQ,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ;AACzF,QAAI,UAAU,GAAI,gBAAe,gBAAgB,UAAU,QAAQ,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,EACpF,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,sBAAsB,YAAY,MAAM;AAC5C,QAAI,sBAAsB,IAAI;AAC5B,qBAAe,gBAAgB,UAAU,QAAQ,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;AAAA,IAC1F;AAAA,EACF,GAAG,CAAC,mBAAmB,OAAO,CAAC;AAE/B,QAAM,wBAAwB;AAAA,IAC5B,CAAC,UAAkB;AACjB,YAAM,SAAS,QAAQ,KAAK;AAC5B,UAAI,OAAQ,gBAAe,gBAAgB,UAAU,QAAQ,KAAK,CAAC,CAAC;AAAA,IACtE;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useCallback, useMemo, useRef, useState } from 'react';\nimport { APP_PICKER_REGION_FOCUSES } from '../constants/index.js';\nimport type { DSAppPickerT } from '../react-desc-prop-types.js';\nimport { getChipId } from '../util/getChipId.js';\nimport { getChipRegionId } from '../util/getChipRegionId.js';\n\ntype FocusTrackerConfigT = {\n allApps: DSAppPickerT.AppItem[];\n};\n\nexport const useFocusTracker = (config: FocusTrackerConfigT) => {\n const { allApps } = config;\n\n // Flat indices of the first/last non-disabled item, used to mark the focus-trap edges.\n // AppSection passes isFirstFocusable/isLastFocusable to AppPickerItem, which sets\n // firstFocusableRef/lastFocusableRef when its innerRef fires.\n const firstFocusableIdx = useMemo(() => allApps.findIndex((app) => !app.disabled), [allApps]);\n const lastFocusableIdx = useMemo(() => allApps.reduce((acc, app, i) => (!app.disabled ? i : acc), -1), [allApps]);\n\n const [focusRegion, setFocusRegion] = useState<string>(APP_PICKER_REGION_FOCUSES.RESET);\n\n // DOM refs for the first and last focusable chips \u2014 set by AppPickerItem's innerRef.\n // Used by useFocusTrap in AppPanel so the focus trap needs no DOM query.\n const firstFocusableRef = useRef<HTMLElement | null>(null);\n const lastFocusableRef = useRef<HTMLElement | null>(null);\n\n const trackFocusChip = useCallback((chipId: string) => {\n setFocusRegion(getChipRegionId(chipId));\n }, []);\n\n const trackFocusRegionReset = useCallback(() => {\n setFocusRegion(APP_PICKER_REGION_FOCUSES.RESET);\n }, []);\n\n const trackFocusTrigger = useCallback(() => {\n setFocusRegion(APP_PICKER_REGION_FOCUSES.TRIGGER);\n }, []);\n\n const trackFocusPanel = useCallback(() => {\n setFocusRegion(APP_PICKER_REGION_FOCUSES.PANEL);\n }, []);\n\n const trackFocusSelectedItem = useCallback(() => {\n const selectedIdx = allApps.findIndex((app) => app.selected);\n const index = selectedIdx !== -1 ? selectedIdx : allApps.findIndex((app) => !app.disabled);\n if (index !== -1) setFocusRegion(getChipRegionId(getChipId(allApps[index], index)));\n }, [allApps]);\n\n // ArrowUp's counterpart to trackFocusSelectedItem. Same first clause \u2014 the selection wins \u2014 but the\n // fallback is the LAST available item rather than the first, because \"open upwards\" lands at the end.\n const trackFocusSelectedOrLastItem = useCallback(() => {\n const selectedIdx = allApps.findIndex((app) => app.selected);\n const index = selectedIdx !== -1 ? selectedIdx : lastFocusableIdx;\n if (index !== -1) setFocusRegion(getChipRegionId(getChipId(allApps[index], index)));\n }, [allApps, lastFocusableIdx]);\n\n const trackFocusItemAtIndex = useCallback(\n (index: number) => {\n const target = allApps[index];\n if (target) setFocusRegion(getChipRegionId(getChipId(target, index)));\n },\n [allApps],\n );\n\n return useMemo(\n () => ({\n firstFocusableIdx,\n lastFocusableIdx,\n focusRegion,\n firstFocusableRef,\n lastFocusableRef,\n trackFocusChip,\n trackFocusRegionReset,\n trackFocusTrigger,\n trackFocusPanel,\n trackFocusSelectedItem,\n trackFocusSelectedOrLastItem,\n trackFocusItemAtIndex,\n }),\n [\n firstFocusableIdx,\n lastFocusableIdx,\n focusRegion,\n trackFocusChip,\n trackFocusRegionReset,\n trackFocusTrigger,\n trackFocusPanel,\n trackFocusSelectedItem,\n trackFocusSelectedOrLastItem,\n trackFocusItemAtIndex,\n ],\n );\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,SAAS,QAAQ,gBAAgB;AACvD,SAAS,iCAAiC;AAE1C,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAMzB,MAAM,kBAAkB,CAAC,WAAgC;AAC9D,QAAM,EAAE,QAAQ,IAAI;AAKpB,QAAM,oBAAoB,QAAQ,MAAM,QAAQ,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,OAAO,CAAC;AAC5F,QAAM,mBAAmB,QAAQ,MAAM,QAAQ,OAAO,CAAC,KAAK,KAAK,MAAO,CAAC,IAAI,WAAW,IAAI,KAAM,EAAE,GAAG,CAAC,OAAO,CAAC;AAEhH,QAAM,CAAC,aAAa,cAAc,IAAI,SAAiB,0BAA0B,KAAK;AAItF,QAAM,oBAAoB,OAA2B,IAAI;AACzD,QAAM,mBAAmB,OAA2B,IAAI;AAExD,QAAM,iBAAiB,YAAY,CAAC,WAAmB;AACrD,mBAAe,gBAAgB,MAAM,CAAC;AAAA,EACxC,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAwB,YAAY,MAAM;AAC9C,mBAAe,0BAA0B,KAAK;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,QAAM,oBAAoB,YAAY,MAAM;AAC1C,mBAAe,0BAA0B,OAAO;AAAA,EAClD,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,YAAY,MAAM;AACxC,mBAAe,0BAA0B,KAAK;AAAA,EAChD,GAAG,CAAC,CAAC;AAEL,QAAM,yBAAyB,YAAY,MAAM;AAC/C,UAAM,cAAc,QAAQ,UAAU,CAAC,QAAQ,IAAI,QAAQ;AAC3D,UAAM,QAAQ,gBAAgB,KAAK,cAAc,QAAQ,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ;AACzF,QAAI,UAAU,GAAI,gBAAe,gBAAgB,UAAU,QAAQ,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,EACpF,GAAG,CAAC,OAAO,CAAC;AAIZ,QAAM,+BAA+B,YAAY,MAAM;AACrD,UAAM,cAAc,QAAQ,UAAU,CAAC,QAAQ,IAAI,QAAQ;AAC3D,UAAM,QAAQ,gBAAgB,KAAK,cAAc;AACjD,QAAI,UAAU,GAAI,gBAAe,gBAAgB,UAAU,QAAQ,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,EACpF,GAAG,CAAC,SAAS,gBAAgB,CAAC;AAE9B,QAAM,wBAAwB;AAAA,IAC5B,CAAC,UAAkB;AACjB,YAAM,SAAS,QAAQ,KAAK;AAC5B,UAAI,OAAQ,gBAAe,gBAAgB,UAAU,QAAQ,KAAK,CAAC,CAAC;AAAA,IACtE;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
package/dist/esm/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import * as React from "react";
2
2
  import { DSAppPicker, AppPickerWithSchema } from "./DSAppPicker.js";
3
3
  import { DSAppPickerName, DSAppPickerSlots, DSAppPickerDataTestIds } from "./constants/index.js";
4
+ import { getDSAppPickerContractProps } from "./util/getDSAppPickerContractProps.js";
4
5
  export {
5
6
  AppPickerWithSchema,
6
7
  DSAppPicker,
7
8
  DSAppPickerDataTestIds,
8
9
  DSAppPickerName,
9
- DSAppPickerSlots
10
+ DSAppPickerSlots,
11
+ getDSAppPickerContractProps
10
12
  };
11
13
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/index.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "export { DSAppPicker, AppPickerWithSchema } from './DSAppPicker.js';\nexport { DSAppPickerName, DSAppPickerSlots, DSAppPickerDataTestIds } from './constants/index.js';\nexport type { DSAppPickerT } from './react-desc-prop-types.js';\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,2BAA2B;AACjD,SAAS,iBAAiB,kBAAkB,8BAA8B;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "export { DSAppPicker, AppPickerWithSchema } from './DSAppPicker.js';\nexport { DSAppPickerName, DSAppPickerSlots, DSAppPickerDataTestIds } from './constants/index.js';\nexport { getDSAppPickerContractProps } from './util/getDSAppPickerContractProps.js';\nexport type { DSAppPickerT } from './react-desc-prop-types.js';\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,2BAA2B;AACjD,SAAS,iBAAiB,kBAAkB,8BAA8B;AAC1E,SAAS,mCAAmC;",
6
6
  "names": []
7
7
  }
@@ -55,35 +55,26 @@ const useExecOnceAfterFirstRender = (callback) => {
55
55
  }
56
56
  }, []);
57
57
  };
58
- const useMountedOpenAutofocusNuance = ({
59
- pendingRef,
60
- triggerIsInternal,
61
- trackFocusPanel,
62
- trackFocusFirstItem
63
- }) => {
58
+ const useMountedOpenAutofocusNuance = ({ pendingRef, trackFocusPanel }) => {
64
59
  useExecOnceAfterFirstRender(() => {
65
60
  if (!pendingRef.current) return;
66
61
  pendingRef.current = false;
67
- if (triggerIsInternal) trackFocusPanel();
68
- else trackFocusFirstItem();
62
+ trackFocusPanel();
69
63
  });
70
64
  };
71
65
  const AppPanelBase = () => {
72
66
  const {
73
- propsWithDefault: { customApps, renderTrigger, onKeyDown },
67
+ propsWithDefault: { customApps, onKeyDown },
74
68
  ownerPropsConfig,
75
69
  globalAttributes,
76
70
  xstyledProps,
77
71
  mountedOpenAutofocusPendingRef,
78
- focusTrackers: { focusRegion, firstFocusableRef, lastFocusableRef, trackFocusPanel, trackFocusFirstItem }
72
+ focusTrackers: { focusRegion, firstFocusableRef, lastFocusableRef, trackFocusPanel }
79
73
  } = useContext(DSAppPickerContext);
80
- const triggerIsInternal = !renderTrigger;
81
74
  const { wrap, onClick, onKeyDown: onKeyDownGlobal, ...safeGlobalAttributes } = globalAttributes;
82
75
  useMountedOpenAutofocusNuance({
83
76
  pendingRef: mountedOpenAutofocusPendingRef,
84
- triggerIsInternal,
85
- trackFocusPanel,
86
- trackFocusFirstItem
77
+ trackFocusPanel
87
78
  });
88
79
  const isWrapperFocused = focusRegion === APP_PICKER_REGION_FOCUSES.PANEL;
89
80
  const handleWrapperRef = useCallback(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/parts/AppPanel.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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 triggerIsInternal: boolean;\n trackFocusPanel: () => void;\n trackFocusFirstItem: () => 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 same\n * initial focus a user-driven open would (panel wrapper for the internal trigger, first item for an\n * external renderTrigger). `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\" assertion in\n * DSAppPicker.keyboard.test.js. Nothing else depends on it.\n */\nconst useMountedOpenAutofocusNuance = ({\n pendingRef,\n triggerIsInternal,\n trackFocusPanel,\n trackFocusFirstItem,\n}: MountedOpenAutofocusNuanceConfig) => {\n useExecOnceAfterFirstRender(() => {\n if (!pendingRef.current) return;\n pendingRef.current = false;\n if (triggerIsInternal) trackFocusPanel();\n else trackFocusFirstItem();\n });\n};\n\nconst AppPanelBase = () => {\n const {\n propsWithDefault: { customApps, renderTrigger, onKeyDown },\n ownerPropsConfig,\n globalAttributes,\n xstyledProps,\n mountedOpenAutofocusPendingRef,\n focusTrackers: { focusRegion, firstFocusableRef, lastFocusableRef, trackFocusPanel, trackFocusFirstItem },\n } = useContext(DSAppPickerContext);\n const triggerIsInternal = !renderTrigger;\n\n // Global attributes are spread onto the panel root because there is no shared wrapper that\n // contains both the floating panel and the trigger. `wrap`, `onClick`, and `onKeyDown` are\n // filtered out because they collide with the public component API (which uses these for\n // 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 triggerIsInternal,\n trackFocusPanel,\n trackFocusFirstItem,\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"],
5
- "mappings": "AAAA,YAAY,WAAW;ACoKjB,SAEE,UAFF,KAEE,YAFF;AApKN,SAAS,YAAY;AACrB,SAAS,oBAAoB;AAC7B,SAAS,cAAc;AACvB,OAAOA,UAAS,MAAM,aAAa,YAAY,iBAAiB;AAChE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,6BAA6B;AAEtC,MAAM,gBAAgB,OAAO,MAAM,EAAE,MAAM,iBAAiB,MAAM,iBAAiB,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,kBAAkB,OAAO,MAAM,EAAE,MAAM,iBAAiB,MAAM,iBAAiB,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,iBAAiBA,OAAM,OAAO,KAAK;AACzC,QAAM,yBAAyBA,OAAM,OAAO,QAAQ;AACpD,yBAAuB,UAAU;AACjC,YAAU,MAAM;AACd,QAAI,CAAC,eAAe,SAAS;AAC3B,6BAAuB,QAAQ;AAC/B,qBAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,CAAC;AACP;AAuBA,MAAM,gCAAgC,CAAC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwC;AACtC,8BAA4B,MAAM;AAChC,QAAI,CAAC,WAAW,QAAS;AACzB,eAAW,UAAU;AACrB,QAAI,kBAAmB,iBAAgB;AAAA,QAClC,qBAAoB;AAAA,EAC3B,CAAC;AACH;AAEA,MAAM,eAAe,MAAM;AACzB,QAAM;AAAA,IACJ,kBAAkB,EAAE,YAAY,eAAe,UAAU;AAAA,IACzD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe,EAAE,aAAa,mBAAmB,kBAAkB,iBAAiB,oBAAoB;AAAA,EAC1G,IAAI,WAAW,kBAAkB;AACjC,QAAM,oBAAoB,CAAC;AAM3B,QAAM,EAAE,MAAM,SAAS,WAAW,iBAAiB,GAAG,qBAAqB,IAAI;AAQ/E,gCAA8B;AAAA,IAC5B,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAOD,QAAM,mBAAmB,gBAAgB,0BAA0B;AAEnE,QAAM,mBAAmB;AAAA,IACvB,CAAC,SAA6B;AAC5B,UAAI,QAAQ,iBAAkB,MAAK,MAAM;AAAA,IAC3C;AAAA,IACA,CAAC,gBAAgB;AAAA,EACnB;AAKA,QAAM,kBAAkB,aAAa;AAAA,IACnC,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB;AAAA,EACF,CAAC;AAKD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV,eAAa,uBAAuB;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,4BAAC,cAAW;AAAA,QACX,WAAW,SAAS,KACnB,iCACE;AAAA,8BAAC,yBAAsB,eAAa,uBAAuB,KAAM,GAAG,kBAClE,8BAAC,mBAAgB,eAAa,uBAAuB,WAAY,GAAG,kBAAkB,GACxF;AAAA,UACA,oBAAC,cAAW,cAAY,MAAC;AAAA,WAC3B;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEO,MAAM,WAAW,KAAK,YAAY;AACzC,SAAS,cAAc;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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 onto the panel root because there is no shared wrapper that\n // contains both the floating panel and the trigger. `wrap`, `onClick`, and `onKeyDown` are\n // filtered out because they collide with the public component API (which uses these for\n // 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"],
5
+ "mappings": "AAAA,YAAY,WAAW;AC0JjB,SAEE,UAFF,KAEE,YAFF;AA1JN,SAAS,YAAY;AACrB,SAAS,oBAAoB;AAC7B,SAAS,cAAc;AACvB,OAAOA,UAAS,MAAM,aAAa,YAAY,iBAAiB;AAChE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,6BAA6B;AAEtC,MAAM,gBAAgB,OAAO,MAAM,EAAE,MAAM,iBAAiB,MAAM,iBAAiB,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,kBAAkB,OAAO,MAAM,EAAE,MAAM,iBAAiB,MAAM,iBAAiB,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,iBAAiBA,OAAM,OAAO,KAAK;AACzC,QAAM,yBAAyBA,OAAM,OAAO,QAAQ;AACpD,yBAAuB,UAAU;AACjC,YAAU,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,IAAI,WAAW,kBAAkB;AAMjC,QAAM,EAAE,MAAM,SAAS,WAAW,iBAAiB,GAAG,qBAAqB,IAAI;AAQ/E,gCAA8B;AAAA,IAC5B,YAAY;AAAA,IACZ;AAAA,EACF,CAAC;AAOD,QAAM,mBAAmB,gBAAgB,0BAA0B;AAEnE,QAAM,mBAAmB;AAAA,IACvB,CAAC,SAA6B;AAC5B,UAAI,QAAQ,iBAAkB,MAAK,MAAM;AAAA,IAC3C;AAAA,IACA,CAAC,gBAAgB;AAAA,EACnB;AAKA,QAAM,kBAAkB,aAAa;AAAA,IACnC,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB;AAAA,EACF,CAAC;AAKD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV,eAAa,uBAAuB;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,4BAAC,cAAW;AAAA,QACX,WAAW,SAAS,KACnB,iCACE;AAAA,8BAAC,yBAAsB,eAAa,uBAAuB,KAAM,GAAG,kBAClE,8BAAC,mBAAgB,eAAa,uBAAuB,WAAY,GAAG,kBAAkB,GACxF;AAAA,UACA,oBAAC,cAAW,cAAY,MAAC;AAAA,WAC3B;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEO,MAAM,WAAW,KAAK,YAAY;AACzC,SAAS,cAAc;",
6
6
  "names": ["React"]
7
7
  }
@@ -17,15 +17,23 @@ const AppPickerContent = () => {
17
17
  ownerPropsConfig,
18
18
  propsWithDefault,
19
19
  focusTrackers,
20
- wasOpenedByKeyboardRef,
20
+ openIntentRef,
21
21
  resolvedIsOpen,
22
22
  setInternalIsOpen,
23
23
  instanceUid
24
24
  } = useContext(DSAppPickerContext);
25
- const { floatingStyles, arrowStyles, floatingContext, floatingInnerRef, handleTriggerRef, handleTriggerClick } = useAppPickerFloatingContext({
25
+ const {
26
+ floatingStyles,
27
+ arrowStyles,
28
+ floatingContext,
29
+ floatingInnerRef,
30
+ handleTriggerRef,
31
+ handleTriggerClick,
32
+ handleTriggerKeyDown
33
+ } = useAppPickerFloatingContext({
26
34
  propsWithDefault,
27
35
  focusTrackers,
28
- wasOpenedByKeyboardRef,
36
+ openIntentRef,
29
37
  resolvedIsOpen,
30
38
  setInternalIsOpen
31
39
  });
@@ -36,6 +44,7 @@ const AppPickerContent = () => {
36
44
  {
37
45
  handleTriggerRef,
38
46
  handleTriggerClick,
47
+ handleTriggerKeyDown,
39
48
  dialogLabelId
40
49
  }
41
50
  ),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../scripts/build/transpile/react-shim.js", "../../../../src/parts/AppPickerFloatingContext/AppPickerContent.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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 { 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 wasOpenedByKeyboardRef,\n resolvedIsOpen,\n setInternalIsOpen,\n instanceUid,\n } = useContext(DSAppPickerContext);\n const { floatingStyles, arrowStyles, floatingContext, floatingInnerRef, handleTriggerRef, handleTriggerClick } =\n useAppPickerFloatingContext({\n propsWithDefault,\n focusTrackers,\n wasOpenedByKeyboardRef,\n resolvedIsOpen,\n setInternalIsOpen,\n });\n\n const dialogLabelId = `${instanceUid}-dialog-trigger-btn`;\n\n return (\n <>\n <Trigger\n handleTriggerRef={handleTriggerRef}\n handleTriggerClick={handleTriggerClick}\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"],
5
- "mappings": "AAAA,YAAY,WAAW;ACqCnB,mBACE,KAKA,YANF;AArCJ,SAAS,iBAAiB,oBAAoB;AAC9C,SAAS,cAAc;AACvB,SAAgB,kBAAkB;AAClC,SAAS,iBAAiB,wBAAwB;AAClD,SAAS,0BAA0B;AAEnC,SAAS,gBAAgB;AACzB,SAAS,eAAe;AACxB,SAAS,mCAAmC;AAE5C,MAAM,0BAA0B,OAAO,iBAAiB;AAAA,EACtD,MAAM;AAAA,EACN,MAAM,iBAAiB;AACzB,CAAC;AAEM,MAAM,mBAA4D,MAAM;AAC7E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,WAAW,kBAAkB;AACjC,QAAM,EAAE,gBAAgB,aAAa,iBAAiB,kBAAkB,kBAAkB,mBAAmB,IAC3G,4BAA4B;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAEH,QAAM,gBAAgB,GAAG,WAAW;AAEpC,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;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,8BAAC,YAAS;AAAA,UACV,oBAAC,gBAAc,GAAG,aAAa;AAAA;AAAA;AAAA,IACjC;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "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 { 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 const dialogLabelId = `${instanceUid}-dialog-trigger-btn`;\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"],
5
+ "mappings": "AAAA,YAAY,WAAW;AC4CnB,mBACE,KAMA,YAPF;AA5CJ,SAAS,iBAAiB,oBAAoB;AAC9C,SAAS,cAAc;AACvB,SAAgB,kBAAkB;AAClC,SAAS,iBAAiB,wBAAwB;AAClD,SAAS,0BAA0B;AAEnC,SAAS,gBAAgB;AACzB,SAAS,eAAe;AACxB,SAAS,mCAAmC;AAE5C,MAAM,0BAA0B,OAAO,iBAAiB;AAAA,EACtD,MAAM;AAAA,EACN,MAAM,iBAAiB;AACzB,CAAC;AAEM,MAAM,mBAA4D,MAAM;AAC7E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,WAAW,kBAAkB;AACjC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,4BAA4B;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,GAAG,WAAW;AAEpC,SACE,iCACE;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,8BAAC,YAAS;AAAA,UACV,oBAAC,gBAAc,GAAG,aAAa;AAAA;AAAA;AAAA,IACjC;AAAA,KACF;AAEJ;",
6
6
  "names": []
7
7
  }