@elliemae/ds-app-picker 3.70.0-next.6 → 3.70.0-next.60

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 (119) hide show
  1. package/dist/cjs/DSAppPicker.js +10 -141
  2. package/dist/cjs/DSAppPicker.js.map +3 -3
  3. package/dist/cjs/{utils.js → DSAppPickerCTX.js} +8 -25
  4. package/dist/cjs/DSAppPickerCTX.js.map +7 -0
  5. package/dist/cjs/config/useAppPicker.js +25 -8
  6. package/dist/cjs/config/useAppPicker.js.map +3 -3
  7. package/dist/cjs/config/useFocusTracker.js +104 -0
  8. package/dist/cjs/config/useFocusTracker.js.map +7 -0
  9. package/dist/cjs/config/useValidateProps.js +45 -0
  10. package/dist/cjs/config/useValidateProps.js.map +7 -0
  11. package/dist/cjs/constants/index.js +11 -1
  12. package/dist/cjs/constants/index.js.map +2 -2
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/package.json +1 -4
  15. package/dist/cjs/parts/AppPanel.js +152 -0
  16. package/dist/cjs/parts/AppPanel.js.map +7 -0
  17. package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js +94 -0
  18. package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js.map +7 -0
  19. package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +171 -0
  20. package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +7 -0
  21. package/dist/cjs/parts/AppPickerItem.js +104 -0
  22. package/dist/cjs/parts/AppPickerItem.js.map +7 -0
  23. package/dist/cjs/parts/AppSection.js +94 -0
  24. package/dist/cjs/parts/AppSection.js.map +7 -0
  25. package/dist/cjs/parts/Trigger.js +81 -0
  26. package/dist/cjs/parts/Trigger.js.map +7 -0
  27. package/dist/cjs/parts/shared-styles.js +44 -0
  28. package/dist/cjs/parts/shared-styles.js.map +7 -0
  29. package/dist/cjs/react-desc-prop-types.js +23 -7
  30. package/dist/cjs/react-desc-prop-types.js.map +2 -2
  31. package/dist/cjs/typescript-testing/slot-props.js +48 -0
  32. package/dist/cjs/typescript-testing/slot-props.js.map +7 -0
  33. package/dist/cjs/typescript-testing/typescript-app-picker-valid.js +13 -1
  34. package/dist/cjs/typescript-testing/typescript-app-picker-valid.js.map +2 -2
  35. package/dist/cjs/util/getChipId.js +36 -0
  36. package/dist/cjs/util/getChipId.js.map +7 -0
  37. package/dist/cjs/util/getChipRegionId.js +37 -0
  38. package/dist/cjs/util/getChipRegionId.js.map +7 -0
  39. package/dist/esm/DSAppPicker.js +10 -141
  40. package/dist/esm/DSAppPicker.js.map +3 -3
  41. package/dist/esm/DSAppPickerCTX.js +8 -0
  42. package/dist/esm/DSAppPickerCTX.js.map +7 -0
  43. package/dist/esm/config/useAppPicker.js +29 -13
  44. package/dist/esm/config/useAppPicker.js.map +3 -3
  45. package/dist/esm/config/useFocusTracker.js +74 -0
  46. package/dist/esm/config/useFocusTracker.js.map +7 -0
  47. package/dist/esm/config/useValidateProps.js +15 -0
  48. package/dist/esm/config/useValidateProps.js.map +7 -0
  49. package/dist/esm/constants/index.js +11 -1
  50. package/dist/esm/constants/index.js.map +2 -2
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/package.json +1 -4
  53. package/dist/esm/parts/AppPanel.js +127 -0
  54. package/dist/esm/parts/AppPanel.js.map +7 -0
  55. package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js +64 -0
  56. package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js.map +7 -0
  57. package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +141 -0
  58. package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +7 -0
  59. package/dist/esm/parts/AppPickerItem.js +74 -0
  60. package/dist/esm/parts/AppPickerItem.js.map +7 -0
  61. package/dist/esm/parts/AppSection.js +64 -0
  62. package/dist/esm/parts/AppSection.js.map +7 -0
  63. package/dist/esm/parts/Trigger.js +51 -0
  64. package/dist/esm/parts/Trigger.js.map +7 -0
  65. package/dist/esm/parts/shared-styles.js +14 -0
  66. package/dist/esm/parts/shared-styles.js.map +7 -0
  67. package/dist/esm/react-desc-prop-types.js +29 -8
  68. package/dist/esm/react-desc-prop-types.js.map +2 -2
  69. package/dist/esm/typescript-testing/slot-props.js +25 -0
  70. package/dist/esm/typescript-testing/slot-props.js.map +7 -0
  71. package/dist/esm/typescript-testing/typescript-app-picker-valid.js +13 -1
  72. package/dist/esm/typescript-testing/typescript-app-picker-valid.js.map +2 -2
  73. package/dist/esm/util/getChipId.js +6 -0
  74. package/dist/esm/util/getChipId.js.map +7 -0
  75. package/dist/esm/util/getChipRegionId.js +7 -0
  76. package/dist/esm/util/getChipRegionId.js.map +7 -0
  77. package/dist/types/DSAppPicker.d.ts +1 -2
  78. package/dist/types/DSAppPickerCTX.d.ts +6 -0
  79. package/dist/types/config/useAppPicker.d.ts +111 -92
  80. package/dist/types/config/useFocusTracker.d.ts +19 -0
  81. package/dist/types/config/useValidateProps.d.ts +3 -0
  82. package/dist/types/constants/index.d.ts +17 -7
  83. package/dist/types/parts/AppPanel.d.ts +2 -0
  84. package/dist/types/parts/AppPickerFloatingContext/AppPickerContent.d.ts +3 -0
  85. package/dist/types/parts/AppPickerFloatingContext/useAppPickerFloatingContext.d.ts +170 -0
  86. package/dist/types/parts/AppPickerItem.d.ts +11 -0
  87. package/dist/types/parts/AppSection.d.ts +6 -0
  88. package/dist/types/parts/Trigger.d.ts +13 -0
  89. package/dist/types/parts/shared-styles.d.ts +2 -0
  90. package/dist/types/react-desc-prop-types.d.ts +80 -9
  91. package/dist/types/util/getChipId.d.ts +2 -0
  92. package/dist/types/util/getChipRegionId.d.ts +1 -0
  93. package/package.json +19 -17
  94. package/dist/cjs/AppPickerImpl.js +0 -204
  95. package/dist/cjs/AppPickerImpl.js.map +0 -7
  96. package/dist/cjs/hooks/useKeepTrackButtons.js +0 -69
  97. package/dist/cjs/hooks/useKeepTrackButtons.js.map +0 -7
  98. package/dist/cjs/styles.js +0 -76
  99. package/dist/cjs/styles.js.map +0 -7
  100. package/dist/cjs/utils.js.map +0 -7
  101. package/dist/esm/AppPickerImpl.js +0 -174
  102. package/dist/esm/AppPickerImpl.js.map +0 -7
  103. package/dist/esm/hooks/useKeepTrackButtons.js +0 -39
  104. package/dist/esm/hooks/useKeepTrackButtons.js.map +0 -7
  105. package/dist/esm/styles.js +0 -46
  106. package/dist/esm/styles.js.map +0 -7
  107. package/dist/esm/utils.js +0 -25
  108. package/dist/esm/utils.js.map +0 -7
  109. package/dist/types/AppPickerImpl.d.ts +0 -11
  110. package/dist/types/hooks/useKeepTrackButtons.d.ts +0 -13
  111. package/dist/types/styles.d.ts +0 -7
  112. package/dist/types/tests/app-picker.a11y.test.d.ts +0 -1
  113. package/dist/types/tests/app-picker.data-testid.test.d.ts +0 -1
  114. package/dist/types/tests/app-picker.events.test.d.ts +0 -1
  115. package/dist/types/tests/app-picker.exports.test.d.ts +0 -1
  116. package/dist/types/tests/app-picker.get-owner-props.test.d.ts +0 -1
  117. package/dist/types/tests/app-picker.keyboard.test.d.ts +0 -1
  118. package/dist/types/typescript-testing/typescript-app-picker-valid.d.ts +0 -1
  119. package/dist/types/utils.d.ts +0 -14
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/util/getChipRegionId.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import { CHIP_REGION_PREFIX } from '../constants/index.js';\n\n// Maps a chipId (see getChipId) to its focus-region identifier. Standalone leaf util \u2014 depends only\n// on the constants module \u2014 so the hook and the parts can share it without importing through the\n// hook, keeping the dependency graph acyclic.\nexport const getChipRegionId = (chipId: string): string => `${CHIP_REGION_PREFIX}${chipId}`;\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,uBAAmC;AAK5B,MAAM,kBAAkB,CAAC,WAA2B,GAAG,mCAAkB,GAAG,MAAM;",
6
+ "names": []
7
+ }
@@ -1,153 +1,22 @@
1
1
  import * as React from "react";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { useState, useEffect, useMemo, useRef, useCallback } from "react";
4
- import { DSButtonV2 } from "@elliemae/ds-button-v2";
5
- import { mergeRefs, styled } from "@elliemae/ds-system";
6
3
  import { describe } from "@elliemae/ds-props-helpers";
7
- import { DSPopover } from "@elliemae/ds-legacy-popover";
8
- import AppPickerImpl from "./AppPickerImpl.js";
9
- import { DSAppPickerPropTypes } from "./react-desc-prop-types.js";
10
- import { DSAppPickerName, DSAppPickerSlots } from "./constants/index.js";
4
+ import React2 from "react";
11
5
  import { useAppPicker } from "./config/useAppPicker.js";
12
- const StyledButton = styled(DSButtonV2, { name: DSAppPickerName, slot: DSAppPickerSlots.BUTTON })``;
6
+ import { DSAppPickerName } from "./constants/index.js";
7
+ import { DSAppPickerContext } from "./DSAppPickerCTX.js";
8
+ import { AppPickerContent } from "./parts/AppPickerFloatingContext/AppPickerContent.js";
9
+ import { DSAppPickerPropTypesSchema } from "./react-desc-prop-types.js";
13
10
  const DSAppPicker = (props) => {
14
- const { propsWithDefault, ownerPropsConfig } = useAppPicker(props);
15
- const { getOwnerProps, getOwnerPropsArguments } = ownerPropsConfig;
16
- const {
17
- apps,
18
- customApps,
19
- sectionTitle,
20
- customSectionTitle,
21
- icon: Icon,
22
- renderTrigger,
23
- isOpen,
24
- onClose,
25
- actionRef,
26
- onKeyDown,
27
- onClick,
28
- onClickOutside,
29
- triggerRef
30
- } = propsWithDefault;
31
- const [open, setOpen] = useState(false);
32
- const [isOverflow, setIsOverflow] = useState(false);
33
- const wrapperRef = useRef(null);
34
- const defaultTriggerRef = useRef(null);
35
- const wasOpenedByKeyboardRef = useRef(false);
36
- useEffect(() => {
37
- if (actionRef && actionRef.current) {
38
- actionRef.current.focusToIndex = (index) => {
39
- if (wrapperRef.current) {
40
- const parent = wrapperRef.current;
41
- const buttons = [...parent.querySelectorAll("button")];
42
- buttons[index].focus();
43
- }
44
- };
45
- actionRef.current.focusWrapper = () => {
46
- wrapperRef.current?.focus();
47
- };
48
- }
49
- }, [actionRef, apps, customApps]);
50
- useEffect(() => {
51
- setTimeout(() => {
52
- if (wrapperRef.current) {
53
- const { scrollHeight, clientHeight } = wrapperRef.current;
54
- if (scrollHeight > clientHeight) return setIsOverflow(true);
55
- }
56
- return setIsOverflow(false);
57
- });
58
- }, [isOpen, open]);
59
- const handleOnClose = useCallback(() => {
60
- setOpen(false);
61
- onClose?.();
62
- }, [onClose]);
63
- const handleOnClickOutside = (e) => {
64
- setOpen(false);
65
- onClose?.();
66
- onClickOutside?.(e);
67
- };
68
- const AppPickerContent = useCallback(
69
- () => /* @__PURE__ */ jsx(
70
- AppPickerImpl,
71
- {
72
- ...getOwnerProps(),
73
- ...getOwnerPropsArguments(),
74
- apps,
75
- customApps,
76
- sectionTitle,
77
- customSectionTitle,
78
- close: handleOnClose,
79
- wrapperRef,
80
- onKeyDown,
81
- triggerRef: triggerRef || defaultTriggerRef,
82
- actionRef,
83
- triggerIsInternal: !renderTrigger,
84
- wasOpenedByKeyboardRef,
85
- isOverflow
86
- }
87
- ),
88
- [
89
- actionRef,
90
- apps,
91
- customApps,
92
- customSectionTitle,
93
- handleOnClose,
94
- isOverflow,
95
- onKeyDown,
96
- renderTrigger,
97
- sectionTitle,
98
- triggerRef,
99
- getOwnerProps,
100
- getOwnerPropsArguments
101
- ]
102
- );
103
- const RenderTrigger = useMemo(
104
- () => renderTrigger || (({ ref }) => /* @__PURE__ */ jsx(
105
- StyledButton,
106
- {
107
- "data-testid": "app-picker__button",
108
- id: "app-picker__button",
109
- buttonType: "icon",
110
- "aria-haspopup": "true",
111
- "aria-expanded": isOpen ?? open,
112
- "aria-label": "Application picker",
113
- innerRef: mergeRefs(ref, triggerRef || defaultTriggerRef),
114
- onClick: (e) => {
115
- wasOpenedByKeyboardRef.current = e.detail === 0;
116
- onClick?.(e);
117
- setOpen(true);
118
- },
119
- getOwnerProps,
120
- getOwnerPropsArguments,
121
- children: /* @__PURE__ */ jsx(Icon, {})
122
- }
123
- )),
124
- [Icon, getOwnerProps, getOwnerPropsArguments, isOpen, onClick, open, renderTrigger, triggerRef]
125
- );
126
- return /* @__PURE__ */ jsx(
127
- DSPopover,
128
- {
129
- content: /* @__PURE__ */ jsx(AppPickerContent, {}),
130
- isOpen: typeof isOpen === "boolean" ? isOpen : open,
131
- onClickOutside: handleOnClickOutside,
132
- placement: "bottom",
133
- interactionType: "click",
134
- renderTrigger: RenderTrigger,
135
- showArrow: true,
136
- style: {
137
- padding: "0",
138
- maxWidth: "1000px",
139
- width: "fit-content"
140
- }
141
- }
142
- );
11
+ const appPickerConfig = useAppPicker(props);
12
+ const ctx = React2.useMemo(() => ({ ...appPickerConfig }), [appPickerConfig]);
13
+ return /* @__PURE__ */ jsx(DSAppPickerContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx(AppPickerContent, {}) });
143
14
  };
144
15
  DSAppPicker.displayName = DSAppPickerName;
145
16
  const AppPickerWithSchema = describe(DSAppPicker);
146
- AppPickerWithSchema.propTypes = DSAppPickerPropTypes;
147
- var DSAppPicker_default = DSAppPicker;
17
+ AppPickerWithSchema.propTypes = DSAppPickerPropTypesSchema;
148
18
  export {
149
19
  AppPickerWithSchema,
150
- DSAppPicker,
151
- DSAppPicker_default as default
20
+ DSAppPicker
152
21
  };
153
22
  //# sourceMappingURL=DSAppPicker.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/DSAppPicker.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';\nimport { DSButtonV2 } from '@elliemae/ds-button-v2';\nimport { mergeRefs, styled } from '@elliemae/ds-system';\nimport { describe } from '@elliemae/ds-props-helpers';\n\nimport { DSPopover } from '@elliemae/ds-legacy-popover';\nimport AppPickerImpl from './AppPickerImpl.js';\nimport type { DSAppPickerT } from './react-desc-prop-types.js';\nimport { DSAppPickerPropTypes } from './react-desc-prop-types.js';\nimport { DSAppPickerName, DSAppPickerSlots } from './constants/index.js';\nimport { useAppPicker } from './config/useAppPicker.js';\n\nconst StyledButton = styled(DSButtonV2, { name: DSAppPickerName, slot: DSAppPickerSlots.BUTTON })``;\nconst DSAppPicker: React.ComponentType<DSAppPickerT.Props> = (props) => {\n const { propsWithDefault, ownerPropsConfig } = useAppPicker(props);\n\n const { getOwnerProps, getOwnerPropsArguments } = ownerPropsConfig;\n\n const {\n apps,\n customApps,\n sectionTitle,\n customSectionTitle,\n icon: Icon,\n renderTrigger,\n isOpen,\n onClose,\n actionRef,\n onKeyDown,\n onClick,\n onClickOutside,\n triggerRef,\n } = propsWithDefault;\n\n const [open, setOpen] = useState(false);\n const [isOverflow, setIsOverflow] = useState(false);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const defaultTriggerRef = useRef(null);\n const wasOpenedByKeyboardRef = useRef(false);\n\n useEffect(() => {\n if (actionRef && actionRef.current) {\n actionRef.current.focusToIndex = (index: number) => {\n if (wrapperRef.current) {\n const parent = wrapperRef.current;\n const buttons = [...parent.querySelectorAll('button')];\n buttons[index].focus();\n }\n };\n actionRef.current.focusWrapper = () => {\n wrapperRef.current?.focus();\n };\n }\n }, [actionRef, apps, customApps]);\n\n useEffect(() => {\n setTimeout(() => {\n if (wrapperRef.current) {\n const { scrollHeight, clientHeight } = wrapperRef.current;\n if (scrollHeight > clientHeight) return setIsOverflow(true);\n }\n return setIsOverflow(false);\n });\n }, [isOpen, open]);\n\n const handleOnClose = useCallback(() => {\n setOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleOnClickOutside = (e: React.MouseEvent) => {\n setOpen(false);\n onClose?.();\n onClickOutside?.(e);\n };\n\n const AppPickerContent = useCallback(\n () => (\n <AppPickerImpl\n {...getOwnerProps()}\n {...getOwnerPropsArguments()}\n apps={apps}\n customApps={customApps}\n sectionTitle={sectionTitle}\n customSectionTitle={customSectionTitle}\n close={handleOnClose}\n wrapperRef={wrapperRef}\n onKeyDown={onKeyDown}\n triggerRef={triggerRef || defaultTriggerRef}\n actionRef={actionRef}\n triggerIsInternal={!renderTrigger}\n wasOpenedByKeyboardRef={wasOpenedByKeyboardRef}\n isOverflow={isOverflow}\n />\n ),\n [\n actionRef,\n apps,\n customApps,\n customSectionTitle,\n handleOnClose,\n isOverflow,\n onKeyDown,\n renderTrigger,\n sectionTitle,\n triggerRef,\n getOwnerProps,\n getOwnerPropsArguments,\n ],\n );\n\n const RenderTrigger = useMemo(\n () =>\n renderTrigger ||\n (({ ref }: { ref: React.RefObject<HTMLButtonElement> }) => (\n <StyledButton\n data-testid=\"app-picker__button\"\n id=\"app-picker__button\"\n buttonType=\"icon\"\n aria-haspopup=\"true\"\n aria-expanded={isOpen ?? open}\n aria-label=\"Application picker\"\n innerRef={mergeRefs(ref, triggerRef || defaultTriggerRef)}\n onClick={(e: React.MouseEvent | React.KeyboardEvent) => {\n wasOpenedByKeyboardRef.current = e.detail === 0;\n onClick?.(e);\n setOpen(true);\n }}\n getOwnerProps={getOwnerProps}\n getOwnerPropsArguments={getOwnerPropsArguments}\n >\n <Icon />\n </StyledButton>\n )),\n [Icon, getOwnerProps, getOwnerPropsArguments, isOpen, onClick, open, renderTrigger, triggerRef],\n );\n\n return (\n <DSPopover\n content={<AppPickerContent />}\n isOpen={typeof isOpen === 'boolean' ? isOpen : open}\n onClickOutside={handleOnClickOutside}\n placement=\"bottom\"\n interactionType=\"click\"\n renderTrigger={RenderTrigger}\n showArrow\n style={{\n padding: '0',\n maxWidth: '1000px',\n width: 'fit-content',\n }}\n />\n );\n};\n\nDSAppPicker.displayName = DSAppPickerName;\nconst AppPickerWithSchema = describe(DSAppPicker);\nAppPickerWithSchema.propTypes = DSAppPickerPropTypes;\n\nexport { DSAppPicker, AppPickerWithSchema };\nexport default DSAppPicker;\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { describe } from '@elliemae/ds-props-helpers';\nimport React from 'react';\nimport { useAppPicker } from './config/useAppPicker.js';\nimport { DSAppPickerName } from './constants/index.js';\nimport { DSAppPickerContext, type DSAppPickerCTX } from './DSAppPickerCTX.js';\nimport { AppPickerContent } from './parts/AppPickerFloatingContext/AppPickerContent.js';\nimport type { DSAppPickerT } from './react-desc-prop-types.js';\nimport { DSAppPickerPropTypesSchema } from './react-desc-prop-types.js';\n\nconst DSAppPicker: React.ComponentType<DSAppPickerT.Props> = (props) => {\n const appPickerConfig = useAppPicker(props);\n const ctx: DSAppPickerCTX = React.useMemo(() => ({ ...appPickerConfig }), [appPickerConfig]);\n\n return (\n <DSAppPickerContext.Provider value={ctx}>\n <AppPickerContent />\n </DSAppPickerContext.Provider>\n );\n};\n\nDSAppPicker.displayName = DSAppPickerName;\nconst AppPickerWithSchema = describe(DSAppPicker);\nAppPickerWithSchema.propTypes = DSAppPickerPropTypesSchema;\n\nexport { AppPickerWithSchema, DSAppPicker };\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACejB;AAfN,SAAS,gBAAgB;AACzB,OAAOA,YAAW;AAClB,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,0BAA+C;AACxD,SAAS,wBAAwB;AAEjC,SAAS,kCAAkC;AAE3C,MAAM,cAAuD,CAAC,UAAU;AACtE,QAAM,kBAAkB,aAAa,KAAK;AAC1C,QAAM,MAAsBA,OAAM,QAAQ,OAAO,EAAE,GAAG,gBAAgB,IAAI,CAAC,eAAe,CAAC;AAE3F,SACE,oBAAC,mBAAmB,UAAnB,EAA4B,OAAO,KAClC,8BAAC,oBAAiB,GACpB;AAEJ;AAEA,YAAY,cAAc;AAC1B,MAAM,sBAAsB,SAAS,WAAW;AAChD,oBAAoB,YAAY;",
6
+ "names": ["React"]
7
7
  }
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+ import { createContext } from "react";
3
+ const defaultContext = {};
4
+ const DSAppPickerContext = createContext(defaultContext);
5
+ export {
6
+ DSAppPickerContext
7
+ };
8
+ //# sourceMappingURL=DSAppPickerCTX.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/DSAppPickerCTX.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { createContext } from 'react';\nimport type { useAppPicker } from './config/useAppPicker.js';\n\nexport interface DSAppPickerCTX extends ReturnType<typeof useAppPicker> {}\n\nconst defaultContext = {} as DSAppPickerCTX;\n\n/** Single source of truth for DSAppPicker's parts \u2014 props, owner-props config, floating-context\n * render state, and focus tracker. Replaces per-part prop drilling. */\nexport const DSAppPickerContext = createContext<DSAppPickerCTX>(defaultContext);\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,qBAAqB;AAK9B,MAAM,iBAAiB,CAAC;AAIjB,MAAM,qBAAqB,cAA8B,cAAc;",
6
+ "names": []
7
+ }
@@ -1,28 +1,44 @@
1
1
  import * as React from "react";
2
- import React2 from "react";
3
2
  import {
3
+ useGetGlobalAttributes,
4
+ useGetXstyledProps,
4
5
  useMemoMergePropsWithDefault,
5
- useOwnerProps,
6
- useValidateTypescriptPropTypes,
7
- getGlobalAttributes,
8
- getXstyledProps
6
+ useOwnerProps
9
7
  } from "@elliemae/ds-props-helpers";
10
- import { defaultProps, DSAppPickerPropTypes } from "../react-desc-prop-types.js";
11
- import { DSAppPickerName } from "../constants/index.js";
8
+ import React2, { useMemo, useRef, useState } from "react";
9
+ import { uid } from "uid";
10
+ import { defaultProps, DSAppPickerPropTypesSchema } from "../react-desc-prop-types.js";
11
+ import { useFocusTracker } from "./useFocusTracker.js";
12
+ import { useValidateProps } from "./useValidateProps.js";
12
13
  const useAppPicker = (props) => {
13
14
  const propsWithDefault = useMemoMergePropsWithDefault(props, defaultProps);
14
- useValidateTypescriptPropTypes(propsWithDefault, DSAppPickerPropTypes, DSAppPickerName);
15
- const ownerPropsConfig = useOwnerProps(propsWithDefault, { ...props });
16
- const globalAttributes = getGlobalAttributes(props);
17
- const xstyledProps = getXstyledProps(props);
15
+ useValidateProps(propsWithDefault, DSAppPickerPropTypesSchema);
16
+ const ownerPropsConfig = useOwnerProps(propsWithDefault, propsWithDefault);
17
+ const globalAttributes = useGetGlobalAttributes(props);
18
+ const xstyledProps = useGetXstyledProps(props);
19
+ const wasOpenedByKeyboardRef = useRef(false);
20
+ const { isOpen, apps, customApps, id } = propsWithDefault;
21
+ const [internalIsOpen, setInternalIsOpen] = useState(false);
22
+ const resolvedIsOpen = typeof isOpen === "boolean" ? isOpen : internalIsOpen;
23
+ const mountedOpenAutofocusPendingRef = useRef(resolvedIsOpen);
24
+ const allApps = useMemo(() => [...apps, ...customApps], [apps, customApps]);
25
+ const useFocusTrackerConfig = useMemo(() => ({ allApps }), [allApps]);
26
+ const focusTrackers = useFocusTracker(useFocusTrackerConfig);
27
+ const instanceUid = React2.useMemo(() => id || `ds-app-picker-${uid(5)}`, [id]);
18
28
  return React2.useMemo(
19
29
  () => ({
30
+ focusTrackers,
20
31
  propsWithDefault,
21
32
  ownerPropsConfig,
22
33
  globalAttributes,
23
- xstyledProps
34
+ xstyledProps,
35
+ wasOpenedByKeyboardRef,
36
+ mountedOpenAutofocusPendingRef,
37
+ resolvedIsOpen,
38
+ setInternalIsOpen,
39
+ instanceUid
24
40
  }),
25
- [propsWithDefault, ownerPropsConfig, globalAttributes, xstyledProps]
41
+ [focusTrackers, propsWithDefault, ownerPropsConfig, globalAttributes, xstyledProps, resolvedIsOpen, instanceUid]
26
42
  );
27
43
  };
28
44
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useAppPicker.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React from 'react';\nimport {\n useMemoMergePropsWithDefault,\n useOwnerProps,\n useValidateTypescriptPropTypes,\n getGlobalAttributes,\n getXstyledProps,\n} from '@elliemae/ds-props-helpers';\nimport { type DSAppPickerT, defaultProps, DSAppPickerPropTypes } from '../react-desc-prop-types.js';\nimport { DSAppPickerName } from '../constants/index.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 useValidateTypescriptPropTypes(propsWithDefault, DSAppPickerPropTypes, DSAppPickerName);\n // =============================================================================\n // GLOBAL ATTRIBUTES & XSTYLED PROPS\n // =============================================================================\n const ownerPropsConfig = useOwnerProps(propsWithDefault, { ...props });\n\n const globalAttributes = getGlobalAttributes<DSAppPickerT.Props>(props);\n const xstyledProps = getXstyledProps<DSAppPickerT.Props>(props);\n return React.useMemo(\n () => ({\n propsWithDefault,\n ownerPropsConfig,\n globalAttributes,\n xstyledProps,\n }),\n [propsWithDefault, ownerPropsConfig, globalAttributes, xstyledProps],\n );\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB,OAAOA,YAAW;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA4B,cAAc,4BAA4B;AACtE,SAAS,uBAAuB;AAEzB,MAAM,eAAe,CAAC,UAA8B;AAIzD,QAAM,mBAAmB,6BAAyD,OAAO,YAAY;AACrG,iCAA+B,kBAAkB,sBAAsB,eAAe;AAItF,QAAM,mBAAmB,cAAc,kBAAkB,EAAE,GAAG,MAAM,CAAC;AAErE,QAAM,mBAAmB,oBAAwC,KAAK;AACtE,QAAM,eAAe,gBAAoC,KAAK;AAC9D,SAAOA,OAAM;AAAA,IACX,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,kBAAkB,kBAAkB,YAAY;AAAA,EACrE;AACF;",
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;",
6
6
  "names": ["React"]
7
7
  }
@@ -0,0 +1,74 @@
1
+ import * as React from "react";
2
+ import { useCallback, useMemo, useRef, useState } from "react";
3
+ import { APP_PICKER_REGION_FOCUSES } from "../constants/index.js";
4
+ import { getChipId } from "../util/getChipId.js";
5
+ import { getChipRegionId } from "../util/getChipRegionId.js";
6
+ const useFocusTracker = (config) => {
7
+ const { allApps } = config;
8
+ const firstFocusableIdx = useMemo(() => allApps.findIndex((app) => !app.disabled), [allApps]);
9
+ const lastFocusableIdx = useMemo(() => allApps.reduce((acc, app, i) => !app.disabled ? i : acc, -1), [allApps]);
10
+ const [focusRegion, setFocusRegion] = useState(APP_PICKER_REGION_FOCUSES.RESET);
11
+ const firstFocusableRef = useRef(null);
12
+ const lastFocusableRef = useRef(null);
13
+ const trackFocusChip = useCallback((chipId) => {
14
+ setFocusRegion(getChipRegionId(chipId));
15
+ }, []);
16
+ const trackFocusRegionReset = useCallback(() => {
17
+ setFocusRegion(APP_PICKER_REGION_FOCUSES.RESET);
18
+ }, []);
19
+ const trackFocusTrigger = useCallback(() => {
20
+ setFocusRegion(APP_PICKER_REGION_FOCUSES.TRIGGER);
21
+ }, []);
22
+ const trackFocusPanel = useCallback(() => {
23
+ setFocusRegion(APP_PICKER_REGION_FOCUSES.PANEL);
24
+ }, []);
25
+ const trackFocusSelectedItem = useCallback(() => {
26
+ const selectedIdx = allApps.findIndex((app) => app.selected);
27
+ const index = selectedIdx !== -1 ? selectedIdx : allApps.findIndex((app) => !app.disabled);
28
+ if (index !== -1) setFocusRegion(getChipRegionId(getChipId(allApps[index], index)));
29
+ }, [allApps]);
30
+ const trackFocusFirstItem = useCallback(() => {
31
+ if (firstFocusableIdx !== -1) {
32
+ setFocusRegion(getChipRegionId(getChipId(allApps[firstFocusableIdx], firstFocusableIdx)));
33
+ }
34
+ }, [firstFocusableIdx, allApps]);
35
+ const trackFocusItemAtIndex = useCallback(
36
+ (index) => {
37
+ const target = allApps[index];
38
+ if (target) setFocusRegion(getChipRegionId(getChipId(target, index)));
39
+ },
40
+ [allApps]
41
+ );
42
+ return useMemo(
43
+ () => ({
44
+ firstFocusableIdx,
45
+ lastFocusableIdx,
46
+ focusRegion,
47
+ firstFocusableRef,
48
+ lastFocusableRef,
49
+ trackFocusChip,
50
+ trackFocusRegionReset,
51
+ trackFocusTrigger,
52
+ trackFocusPanel,
53
+ trackFocusSelectedItem,
54
+ trackFocusFirstItem,
55
+ trackFocusItemAtIndex
56
+ }),
57
+ [
58
+ firstFocusableIdx,
59
+ lastFocusableIdx,
60
+ focusRegion,
61
+ trackFocusChip,
62
+ trackFocusRegionReset,
63
+ trackFocusTrigger,
64
+ trackFocusPanel,
65
+ trackFocusSelectedItem,
66
+ trackFocusFirstItem,
67
+ trackFocusItemAtIndex
68
+ ]
69
+ );
70
+ };
71
+ export {
72
+ useFocusTracker
73
+ };
74
+ //# sourceMappingURL=useFocusTracker.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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;",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ import { useValidateTypescriptPropTypes } from "@elliemae/ds-props-helpers";
3
+ import { DSAppPickerName } from "../constants/index.js";
4
+ const useValidateProps = (props, propTypes) => {
5
+ useValidateTypescriptPropTypes(props, propTypes, DSAppPickerName);
6
+ if (!props.apps.length && !props.customApps.length) {
7
+ throw new Error(
8
+ `[${DSAppPickerName}] At least one of "apps" or "customApps" must contain items. Providing both as empty arrays renders an empty picker.`
9
+ );
10
+ }
11
+ };
12
+ export {
13
+ useValidateProps
14
+ };
15
+ //# sourceMappingURL=useValidateProps.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useValidateProps.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { useValidateTypescriptPropTypes } from '@elliemae/ds-props-helpers';\nimport type { ValidationMap } from '@elliemae/ds-props-helpers';\nimport { type DSAppPickerT } from '../react-desc-prop-types.js';\nimport { DSAppPickerName } from '../constants/index.js';\n\nexport const useValidateProps = (props: DSAppPickerT.InternalProps, propTypes: ValidationMap<unknown>): void => {\n useValidateTypescriptPropTypes(props, propTypes, DSAppPickerName);\n\n if (!props.apps.length && !props.customApps.length) {\n throw new Error(\n `[${DSAppPickerName}] At least one of \"apps\" or \"customApps\" must contain items. ` +\n `Providing both as empty arrays renders an empty picker.`,\n );\n }\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,sCAAsC;AAG/C,SAAS,uBAAuB;AAEzB,MAAM,mBAAmB,CAAC,OAAmC,cAA4C;AAC9G,iCAA+B,OAAO,WAAW,eAAe;AAEhE,MAAI,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,WAAW,QAAQ;AAClD,UAAM,IAAI;AAAA,MACR,IAAI,eAAe;AAAA,IAErB;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -1,14 +1,22 @@
1
1
  import * as React from "react";
2
2
  import { slotObjectToDataTestIds } from "@elliemae/ds-system";
3
3
  const DSAppPickerName = "DSApppicker";
4
+ const APP_PICKER_REGION_FOCUSES = {
5
+ RESET: "",
6
+ TRIGGER: "trigger",
7
+ PANEL: "panel"
8
+ };
9
+ const CHIP_REGION_PREFIX = "chip-";
4
10
  const DSAppPickerSlots = {
5
11
  ROOT: "root",
12
+ GROUP: "group",
6
13
  ITEM: "item",
7
14
  TITLE: "title",
8
15
  SEPARATOR: "separator",
9
16
  ROW: "row",
10
17
  CHIP: "chip",
11
- BUTTON: "button"
18
+ BUTTON: "button",
19
+ FLOATING_WRAPPER: "floating-wrapper"
12
20
  };
13
21
  const DSAppPickerDataTestIds = {
14
22
  ...slotObjectToDataTestIds(DSAppPickerName, DSAppPickerSlots),
@@ -16,6 +24,8 @@ const DSAppPickerDataTestIds = {
16
24
  BUTTON: "app-picker__button"
17
25
  };
18
26
  export {
27
+ APP_PICKER_REGION_FOCUSES,
28
+ CHIP_REGION_PREFIX,
19
29
  DSAppPickerDataTestIds,
20
30
  DSAppPickerName,
21
31
  DSAppPickerSlots
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/constants/index.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { slotObjectToDataTestIds } from '@elliemae/ds-system';\n\nexport const DSAppPickerName = 'DSApppicker';\n\nexport const DSAppPickerSlots = {\n ROOT: 'root',\n ITEM: 'item',\n TITLE: 'title',\n SEPARATOR: 'separator',\n ROW: 'row',\n CHIP: 'chip',\n BUTTON: 'button',\n};\n\nexport const DSAppPickerDataTestIds = {\n ...(slotObjectToDataTestIds(DSAppPickerName, DSAppPickerSlots) as Record<keyof typeof DSAppPickerSlots, string>),\n CHIP: 'app-picker__chip',\n BUTTON: 'app-picker__button',\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,+BAA+B;AAEjC,MAAM,kBAAkB;AAExB,MAAM,mBAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,KAAK;AAAA,EACL,MAAM;AAAA,EACN,QAAQ;AACV;AAEO,MAAM,yBAAyB;AAAA,EACpC,GAAI,wBAAwB,iBAAiB,gBAAgB;AAAA,EAC7D,MAAM;AAAA,EACN,QAAQ;AACV;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { slotObjectToDataTestIds } from '@elliemae/ds-system';\n\n// DEV-001: triple-p \"DSApppicker\" is the legacy public name. Renaming would break consumers.\n// See KNOWN_INTENTIONAL_DEVIATIONS.md.\nexport const DSAppPickerName = 'DSApppicker';\n\n// we are naming this with the ${component_name}_region_focuses convention to namespace & avoid errors on duplicate exports variables in aggregators\nexport const APP_PICKER_REGION_FOCUSES = {\n RESET: '',\n TRIGGER: 'trigger',\n PANEL: 'panel',\n} as const;\n\n// Prefix for the per-chip focus-region identifiers (see getChipRegionId in src/util).\nexport const CHIP_REGION_PREFIX = 'chip-';\n\n// we are naming this with the ${component_name}_slots convention to namespace & avoid errors on duplicate exports variables in aggregators\nexport const DSAppPickerSlots = {\n ROOT: 'root',\n GROUP: 'group',\n ITEM: 'item',\n TITLE: 'title',\n SEPARATOR: 'separator',\n ROW: 'row',\n CHIP: 'chip',\n BUTTON: 'button',\n FLOATING_WRAPPER: 'floating-wrapper',\n} as const;\n\n// Layer 2 legacy data-testid overrides:\n// CHIP and BUTTON predate the slot naming scheme; existing QA selectors must keep matching.\n// See project_compatibility.md (legacy data-testid 3-layer override pattern).\nexport const DSAppPickerDataTestIds = {\n ...(slotObjectToDataTestIds(DSAppPickerName, DSAppPickerSlots) as Record<keyof typeof DSAppPickerSlots, string>),\n CHIP: 'app-picker__chip',\n BUTTON: 'app-picker__button',\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,+BAA+B;AAIjC,MAAM,kBAAkB;AAGxB,MAAM,4BAA4B;AAAA,EACvC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,OAAO;AACT;AAGO,MAAM,qBAAqB;AAG3B,MAAM,mBAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,WAAW;AAAA,EACX,KAAK;AAAA,EACL,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,kBAAkB;AACpB;AAKO,MAAM,yBAAyB;AAAA,EACpC,GAAI,wBAAwB,iBAAiB,gBAAgB;AAAA,EAC7D,MAAM;AAAA,EACN,QAAQ;AACV;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/index.tsx"],
3
+ "sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../src/index.ts"],
4
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
5
  "mappings": "AAAA,YAAY,WAAW;ACAvB,SAAS,aAAa,2BAA2B;AACjD,SAAS,iBAAiB,kBAAkB,8BAA8B;",
6
6
  "names": []
@@ -3,8 +3,5 @@
3
3
  "sideEffects": [
4
4
  "*.css",
5
5
  "*.scss"
6
- ],
7
- "publishConfig": {
8
- "access": "public"
9
- }
6
+ ]
10
7
  }
@@ -0,0 +1,127 @@
1
+ import * as React from "react";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { Grid } from "@elliemae/ds-grid";
4
+ import { useFocusTrap } from "@elliemae/ds-hooks-focus-trap";
5
+ import { styled } from "@elliemae/ds-system";
6
+ import React2, { memo, useCallback, useContext, useEffect } from "react";
7
+ import {
8
+ APP_PICKER_REGION_FOCUSES,
9
+ DSAppPickerDataTestIds,
10
+ DSAppPickerName,
11
+ DSAppPickerSlots
12
+ } from "../constants/index.js";
13
+ import { DSAppPickerContext } from "../DSAppPickerCTX.js";
14
+ import { AppSection } from "./AppSection.js";
15
+ import { StyledListItemFullRow } from "./shared-styles.js";
16
+ const StyledWrapper = styled(Grid, { name: DSAppPickerName, slot: DSAppPickerSlots.ROOT })`
17
+ background-color: ${({ theme }) => theme.colors.neutral["000"]};
18
+ min-width: 308px;
19
+ min-height: 110px;
20
+ max-height: 449px;
21
+ width: 308px;
22
+ overflow-y: auto;
23
+ overflow-x: hidden;
24
+ /* Baseline 2024: reserve scrollbar gutter so the layout doesn't shift between overflow/no-overflow.
25
+ Replaces a JS isOverflow detection effect that toggled right padding. */
26
+ scrollbar-gutter: stable;
27
+ margin: 0;
28
+ padding: 0 0 8px 16px;
29
+ &:focus {
30
+ outline: none;
31
+ }
32
+ `;
33
+ const StyledSeparator = styled("hr", { name: DSAppPickerName, slot: DSAppPickerSlots.SEPARATOR })`
34
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral[300]};
35
+ border-bottom: none;
36
+ width: 100%;
37
+ margin: 8px 0 0 0;
38
+ `;
39
+ const wrapperGridLayout = {
40
+ cols: ["repeat(3, 92px)"],
41
+ // Row tracks are intentionally auto-sized:
42
+ // - title row picks up its own typography height
43
+ // - chip rows expand when `wrapText` causes a chip to wrap onto a second line (Reflow story)
44
+ // - separator row picks up its own 1px height + margin
45
+ rows: ["auto"]
46
+ };
47
+ const useExecOnceAfterFirstRender = (callback) => {
48
+ const hasExecutedRef = React2.useRef(false);
49
+ const executeInitialFocusRef = React2.useRef(callback);
50
+ executeInitialFocusRef.current = callback;
51
+ useEffect(() => {
52
+ if (!hasExecutedRef.current) {
53
+ executeInitialFocusRef.current();
54
+ hasExecutedRef.current = true;
55
+ }
56
+ }, []);
57
+ };
58
+ const useMountedOpenAutofocusNuance = ({
59
+ pendingRef,
60
+ triggerIsInternal,
61
+ trackFocusPanel,
62
+ trackFocusFirstItem
63
+ }) => {
64
+ useExecOnceAfterFirstRender(() => {
65
+ if (!pendingRef.current) return;
66
+ pendingRef.current = false;
67
+ if (triggerIsInternal) trackFocusPanel();
68
+ else trackFocusFirstItem();
69
+ });
70
+ };
71
+ const AppPanelBase = () => {
72
+ const {
73
+ propsWithDefault: { customApps, renderTrigger, onKeyDown },
74
+ ownerPropsConfig,
75
+ globalAttributes,
76
+ xstyledProps,
77
+ mountedOpenAutofocusPendingRef,
78
+ focusTrackers: { focusRegion, firstFocusableRef, lastFocusableRef, trackFocusPanel, trackFocusFirstItem }
79
+ } = useContext(DSAppPickerContext);
80
+ const triggerIsInternal = !renderTrigger;
81
+ const { wrap, onClick, onKeyDown: onKeyDownGlobal, ...safeGlobalAttributes } = globalAttributes;
82
+ useMountedOpenAutofocusNuance({
83
+ pendingRef: mountedOpenAutofocusPendingRef,
84
+ triggerIsInternal,
85
+ trackFocusPanel,
86
+ trackFocusFirstItem
87
+ });
88
+ const isWrapperFocused = focusRegion === APP_PICKER_REGION_FOCUSES.PANEL;
89
+ const handleWrapperRef = useCallback(
90
+ (node) => {
91
+ if (node && isWrapperFocused) node.focus();
92
+ },
93
+ [isWrapperFocused]
94
+ );
95
+ const handleOnKeyDown = useFocusTrap({
96
+ firstElementRef: firstFocusableRef,
97
+ lastElementRef: lastFocusableRef,
98
+ onKeyDown
99
+ });
100
+ return /* @__PURE__ */ jsxs(
101
+ StyledWrapper,
102
+ {
103
+ innerRef: handleWrapperRef,
104
+ "data-testid": DSAppPickerDataTestIds.ROOT,
105
+ cols: wrapperGridLayout.cols,
106
+ rows: wrapperGridLayout.rows,
107
+ tabIndex: -1,
108
+ ...ownerPropsConfig,
109
+ ...safeGlobalAttributes,
110
+ ...xstyledProps,
111
+ onKeyDown: handleOnKeyDown,
112
+ children: [
113
+ /* @__PURE__ */ jsx(AppSection, {}),
114
+ customApps.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
115
+ /* @__PURE__ */ jsx(StyledListItemFullRow, { "data-testid": DSAppPickerDataTestIds.ROW, ...ownerPropsConfig, children: /* @__PURE__ */ jsx(StyledSeparator, { "data-testid": DSAppPickerDataTestIds.SEPARATOR, ...ownerPropsConfig }) }),
116
+ /* @__PURE__ */ jsx(AppSection, { isCustomApps: true })
117
+ ] })
118
+ ]
119
+ }
120
+ );
121
+ };
122
+ const AppPanel = memo(AppPanelBase);
123
+ AppPanel.displayName = "DSAppPicker.AppPanel";
124
+ export {
125
+ AppPanel
126
+ };
127
+ //# sourceMappingURL=AppPanel.js.map