@elliemae/ds-app-picker 3.9.1-rc.8 → 3.9.1
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.
- package/dist/cjs/AppPickerImpl.js +30 -40
- package/dist/cjs/AppPickerImpl.js.map +2 -2
- package/dist/cjs/DSAppPicker.js +38 -19
- package/dist/cjs/DSAppPicker.js.map +2 -2
- package/dist/cjs/hooks/useKeepTrackButtons.js +60 -0
- package/dist/cjs/hooks/useKeepTrackButtons.js.map +7 -0
- package/dist/cjs/propTypes.js.map +2 -2
- package/dist/cjs/styles.js.map +1 -1
- package/dist/cjs/types/AppPickerTypes.js.map +1 -1
- package/dist/cjs/utils.js +8 -0
- package/dist/cjs/utils.js.map +2 -2
- package/dist/esm/AppPickerImpl.js +31 -41
- package/dist/esm/AppPickerImpl.js.map +2 -2
- package/dist/esm/DSAppPicker.js +39 -20
- package/dist/esm/DSAppPicker.js.map +2 -2
- package/dist/esm/hooks/useKeepTrackButtons.js +34 -0
- package/dist/esm/hooks/useKeepTrackButtons.js.map +7 -0
- package/dist/esm/propTypes.js.map +2 -2
- package/dist/esm/styles.js.map +1 -1
- package/dist/esm/utils.js +8 -0
- package/dist/esm/utils.js.map +2 -2
- package/package.json +8 -8
|
@@ -33,6 +33,7 @@ var import_react = require("react");
|
|
|
33
33
|
var import_ds_chip = require("@elliemae/ds-chip");
|
|
34
34
|
var import_utils = require("./utils");
|
|
35
35
|
var import_styles = require("./styles");
|
|
36
|
+
var import_useKeepTrackButtons = require("./hooks/useKeepTrackButtons");
|
|
36
37
|
const AppPickerImpl = ({
|
|
37
38
|
apps = [],
|
|
38
39
|
customApps = [],
|
|
@@ -42,27 +43,12 @@ const AppPickerImpl = ({
|
|
|
42
43
|
wrapperRef,
|
|
43
44
|
onKeyDown,
|
|
44
45
|
triggerRef,
|
|
45
|
-
isOverflow
|
|
46
|
+
isOverflow,
|
|
47
|
+
actionRef,
|
|
48
|
+
wasOpenedByKeyboardRef,
|
|
49
|
+
triggerIsInternal
|
|
46
50
|
}) => {
|
|
47
|
-
const allFocusableButtons = (0,
|
|
48
|
-
const selectedButton = (0, import_react.useRef)(null);
|
|
49
|
-
(0, import_react.useEffect)(() => {
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
wrapperRef?.current?.querySelectorAll("button").forEach((e, index) => {
|
|
52
|
-
if (!e.hasAttribute("disabled")) {
|
|
53
|
-
allFocusableButtons?.current?.push(e);
|
|
54
|
-
}
|
|
55
|
-
if (e.getAttribute("aria-selected") === "true") {
|
|
56
|
-
selectedButton.current = index;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
if (selectedButton.current) {
|
|
60
|
-
wrapperRef?.current?.querySelectorAll("button")[selectedButton.current].focus();
|
|
61
|
-
} else {
|
|
62
|
-
allFocusableButtons?.current[0]?.focus();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
}, [wrapperRef]);
|
|
51
|
+
const { allFocusableButtons } = (0, import_useKeepTrackButtons.useKeepTrackButtons)(wrapperRef, wasOpenedByKeyboardRef, actionRef, triggerIsInternal);
|
|
66
52
|
const handleKeyDown = (0, import_react.useCallback)(
|
|
67
53
|
(e) => {
|
|
68
54
|
switch (e.key) {
|
|
@@ -85,7 +71,7 @@ const AppPickerImpl = ({
|
|
|
85
71
|
break;
|
|
86
72
|
}
|
|
87
73
|
},
|
|
88
|
-
[close, triggerRef]
|
|
74
|
+
[allFocusableButtons, close, triggerRef]
|
|
89
75
|
);
|
|
90
76
|
const handleOnClick = (0, import_react.useCallback)(
|
|
91
77
|
(app) => (e) => {
|
|
@@ -104,11 +90,15 @@ const AppPickerImpl = ({
|
|
|
104
90
|
},
|
|
105
91
|
[onKeyDown, close]
|
|
106
92
|
);
|
|
107
|
-
const
|
|
93
|
+
const totalAppsLength = (0, import_react.useMemo)(() => apps.length + customApps.length, [apps.length, customApps.length]);
|
|
108
94
|
const buildRows = (0, import_react.useCallback)(
|
|
109
|
-
(appList, prevIndex
|
|
110
|
-
|
|
95
|
+
(appList, prevIndex, title) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {
|
|
96
|
+
children: appList.map((app, index) => {
|
|
111
97
|
const { label, disabled, selected, icon: Icon, id } = app;
|
|
98
|
+
const IconComp = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, {
|
|
99
|
+
className: "app-picker__icon",
|
|
100
|
+
size: "m"
|
|
101
|
+
});
|
|
112
102
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styles.StyledListItem, {
|
|
113
103
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_chip.DSChip, {
|
|
114
104
|
onClick: handleOnClick(app),
|
|
@@ -119,28 +109,25 @@ const AppPickerImpl = ({
|
|
|
119
109
|
selected,
|
|
120
110
|
"aria-selected": selected,
|
|
121
111
|
id,
|
|
122
|
-
"aria-label": `${label}. ${title} (${index + prevIndex} of ${
|
|
123
|
-
icon:
|
|
124
|
-
className: "app-picker__icon",
|
|
125
|
-
size: "m"
|
|
126
|
-
}),
|
|
112
|
+
"aria-label": `${label}. ${title} (${index + prevIndex} of ${totalAppsLength})`,
|
|
113
|
+
icon: IconComp,
|
|
127
114
|
label
|
|
128
115
|
}, index)
|
|
129
116
|
});
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
117
|
+
})
|
|
118
|
+
}),
|
|
119
|
+
[handleKeyDown, handleOnClick, totalAppsLength]
|
|
120
|
+
);
|
|
121
|
+
const AppsRows = (0, import_react.useMemo)(() => buildRows(apps, 1, sectionTitle), [apps, buildRows, sectionTitle]);
|
|
122
|
+
const CustomRows = (0, import_react.useMemo)(
|
|
123
|
+
() => buildRows(customApps, apps.length, customSectionTitle),
|
|
124
|
+
[apps.length, buildRows, customApps, customSectionTitle]
|
|
136
125
|
);
|
|
137
|
-
const AppsRows = (0, import_react.useMemo)(() => buildRows(apps, 1, sectionTitle), []);
|
|
138
|
-
const CustomRows = (0, import_react.useMemo)(() => buildRows(customApps, apps.length, customSectionTitle), []);
|
|
139
126
|
const layout = (0, import_react.useMemo)(() => {
|
|
140
127
|
const cols = ["repeat(3, 92px)"];
|
|
141
128
|
let appsRows = 0;
|
|
142
129
|
let customRows = 0;
|
|
143
|
-
|
|
130
|
+
const rows = [];
|
|
144
131
|
if (apps.length > 0) {
|
|
145
132
|
appsRows = apps.length / 3;
|
|
146
133
|
rows.push("68px", `repeat(${appsRows}, 68px})`);
|
|
@@ -154,14 +141,17 @@ const AppPickerImpl = ({
|
|
|
154
141
|
cols
|
|
155
142
|
};
|
|
156
143
|
}, [apps.length, customApps.length]);
|
|
144
|
+
const convertedTypeReference = wrapperRef;
|
|
157
145
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_styles.StyledWrapper, {
|
|
158
|
-
|
|
146
|
+
forwardedAs: "ul",
|
|
147
|
+
ref: convertedTypeReference,
|
|
159
148
|
onKeyDown: handleOnKeyDownWrapper,
|
|
160
149
|
"data-testid": "app-picker__wrapper",
|
|
161
150
|
isOverflow,
|
|
162
151
|
cols: layout.cols,
|
|
163
152
|
rows: layout.rows,
|
|
164
|
-
|
|
153
|
+
tabIndex: -1,
|
|
154
|
+
"aria-label": `Application picker, ${sectionTitle} (${apps.length} apps)${customApps.length > 0 ? `, ${customSectionTitle} (${customApps.length} apps)` : ""}`,
|
|
165
155
|
children: [
|
|
166
156
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styles.StyledListItemFullRow, {
|
|
167
157
|
"aria-hidden": true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/AppPickerImpl.tsx", "../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable react/prop-types */\n/* eslint-disable react/no-array-index-key */\n/* eslint-disable max-lines */\nimport React, {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB;AAGA,
|
|
4
|
+
"sourcesContent": ["/* eslint-disable react/prop-types */\n/* eslint-disable react/no-array-index-key */\n/* eslint-disable max-lines */\nimport React, { useCallback, useMemo } from 'react';\nimport { DSChip } from '@elliemae/ds-chip';\nimport { keys } from './utils';\nimport { AppItemType, DSAppPickerImplType } from './types/AppPickerTypes';\nimport { StyledWrapper, StyledSeparator, StyledListItemFullRow, StyledListItem, StyledTitle } from './styles';\nimport { useKeepTrackButtons } from './hooks/useKeepTrackButtons';\n\nconst AppPickerImpl: DSAppPickerImplType = ({\n apps = [],\n customApps = [],\n sectionTitle = 'APPLICATIONS',\n customSectionTitle = 'CUSTOM APPLICATIONS',\n close = () => null,\n wrapperRef,\n onKeyDown,\n triggerRef,\n isOverflow,\n actionRef,\n wasOpenedByKeyboardRef,\n triggerIsInternal,\n}) => {\n const { allFocusableButtons } = useKeepTrackButtons(wrapperRef, wasOpenedByKeyboardRef, actionRef, triggerIsInternal);\n\n // eslint-disable-next-line max-statements\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case keys.ESC:\n triggerRef?.current?.focus();\n close();\n break;\n case keys.TAB:\n if (e.shiftKey) {\n if (e.target === allFocusableButtons.current[0]) {\n e.preventDefault();\n allFocusableButtons?.current[allFocusableButtons.current.length - 1]?.focus();\n }\n } else if (e.target === allFocusableButtons.current[allFocusableButtons.current.length - 1]) {\n e.preventDefault();\n allFocusableButtons?.current[0]?.focus();\n }\n break;\n default:\n break;\n }\n },\n [allFocusableButtons, close, triggerRef],\n );\n\n const handleOnClick = useCallback(\n (app: AppItemType) => (e: React.MouseEvent) => {\n if (app.onClick) app.onClick(e, app);\n },\n [],\n );\n\n const handleOnKeyDownWrapper = useCallback(\n (e: React.KeyboardEvent) => {\n if (onKeyDown) onKeyDown(e);\n if (!onKeyDown && e.key === keys.ESC) {\n close();\n }\n },\n [onKeyDown, close],\n );\n\n const totalAppsLength = useMemo(() => apps.length + customApps.length, [apps.length, customApps.length]);\n\n const buildRows = useCallback(\n (appList: AppItemType[], prevIndex: number, title: string): JSX.Element => (\n <>\n {appList.map((app, index) => {\n const { label, disabled, selected, icon: Icon, id } = app;\n\n // eslint-disable-next-line react/no-unstable-nested-components\n const IconComp = () => <Icon className=\"app-picker__icon\" size=\"m\" />;\n\n return (\n <StyledListItem>\n <DSChip\n key={index}\n onClick={handleOnClick(app)}\n onKeyDown={handleKeyDown}\n data-testid=\"app-picker__chip\"\n aria-disabled={disabled}\n disabled={disabled}\n selected={selected}\n aria-selected={selected}\n id={id}\n aria-label={`${label}. ${title} (${index + prevIndex} of ${totalAppsLength})`}\n icon={IconComp}\n label={label}\n />\n </StyledListItem>\n );\n })}\n </>\n ),\n [handleKeyDown, handleOnClick, totalAppsLength],\n );\n\n const AppsRows = useMemo(() => buildRows(apps, 1, sectionTitle), [apps, buildRows, sectionTitle]);\n const CustomRows = useMemo(\n () => buildRows(customApps, apps.length, customSectionTitle),\n [apps.length, buildRows, customApps, customSectionTitle],\n );\n\n const layout = useMemo(() => {\n const cols = ['repeat(3, 92px)'];\n let appsRows = 0;\n let customRows = 0;\n const rows = [];\n if (apps.length > 0) {\n appsRows = apps.length / 3;\n rows.push('68px', `repeat(${appsRows}, 68px})`);\n }\n if (customApps.length > 0) {\n customRows = customApps.length / 3;\n rows.push('9px', '68px', `repeat(${customRows}, 68px})`);\n }\n return {\n rows,\n cols,\n };\n }, [apps.length, customApps.length]);\n\n // Needed just for typescript reasons\n const convertedTypeReference = wrapperRef as unknown as React.RefObject<HTMLDivElement> &\n React.RefObject<HTMLUListElement>;\n\n return (\n <StyledWrapper\n forwardedAs=\"ul\"\n ref={convertedTypeReference}\n onKeyDown={handleOnKeyDownWrapper}\n data-testid=\"app-picker__wrapper\"\n isOverflow={isOverflow}\n cols={layout.cols}\n rows={layout.rows}\n tabIndex={-1}\n aria-label={`Application picker, ${sectionTitle} (${apps.length} apps)${\n customApps.length > 0 ? `, ${customSectionTitle} (${customApps.length} apps)` : ''\n }`}\n >\n <StyledListItemFullRow aria-hidden>\n <StyledTitle data-testid=\"app-picker__main-title\">{sectionTitle}</StyledTitle>\n </StyledListItemFullRow>\n {AppsRows}\n {customApps.length > 0 && (\n <>\n <StyledListItemFullRow aria-hidden>\n <StyledSeparator />\n </StyledListItemFullRow>\n <StyledListItemFullRow aria-hidden>\n <StyledTitle data-testid=\"app-picker__custom-title\">{customSectionTitle}</StyledTitle>\n </StyledListItemFullRow>\n {CustomRows}\n </>\n )}\n </StyledWrapper>\n );\n};\n\nexport default AppPickerImpl;\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cjs/DSAppPicker.js
CHANGED
|
@@ -60,6 +60,7 @@ const DSAppPicker = ({
|
|
|
60
60
|
const [isOverflow, setIsOverflow] = (0, import_react.useState)(false);
|
|
61
61
|
const wrapperRef = (0, import_react.useRef)(null);
|
|
62
62
|
const defaultTriggerRef = (0, import_react.useRef)(null);
|
|
63
|
+
const wasOpenedByKeyboardRef = (0, import_react.useRef)(false);
|
|
63
64
|
(0, import_react.useEffect)(() => {
|
|
64
65
|
if (actionRef && actionRef.current) {
|
|
65
66
|
actionRef.current.focusToIndex = (index) => {
|
|
@@ -69,6 +70,9 @@ const DSAppPicker = ({
|
|
|
69
70
|
buttons[index].focus();
|
|
70
71
|
}
|
|
71
72
|
};
|
|
73
|
+
actionRef.current.focusWrapper = () => {
|
|
74
|
+
wrapperRef.current?.focus();
|
|
75
|
+
};
|
|
72
76
|
}
|
|
73
77
|
}, [actionRef, apps, customApps]);
|
|
74
78
|
(0, import_react.useEffect)(() => {
|
|
@@ -81,38 +85,53 @@ const DSAppPicker = ({
|
|
|
81
85
|
return setIsOverflow(false);
|
|
82
86
|
});
|
|
83
87
|
}, [isOpen, open]);
|
|
84
|
-
const handleOnClose = () => {
|
|
85
|
-
|
|
86
|
-
setOpen(isOpen);
|
|
87
|
-
} else {
|
|
88
|
-
setOpen(false);
|
|
89
|
-
}
|
|
88
|
+
const handleOnClose = (0, import_react.useCallback)(() => {
|
|
89
|
+
setOpen(false);
|
|
90
90
|
onClose();
|
|
91
|
-
};
|
|
91
|
+
}, [onClose]);
|
|
92
92
|
const handleOnClickOutside = (e) => {
|
|
93
93
|
setOpen(false);
|
|
94
94
|
onClose();
|
|
95
95
|
onClickOutside(e);
|
|
96
96
|
};
|
|
97
|
-
const AppPickerContent = (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
const AppPickerContent = (0, import_react.useCallback)(
|
|
98
|
+
() => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_AppPickerImpl.default, {
|
|
99
|
+
apps,
|
|
100
|
+
customApps,
|
|
101
|
+
sectionTitle,
|
|
102
|
+
customSectionTitle,
|
|
103
|
+
close: handleOnClose,
|
|
104
|
+
wrapperRef,
|
|
105
|
+
onKeyDown,
|
|
106
|
+
triggerRef: triggerRef || defaultTriggerRef,
|
|
107
|
+
actionRef,
|
|
108
|
+
triggerIsInternal: !renderTrigger,
|
|
109
|
+
wasOpenedByKeyboardRef,
|
|
110
|
+
isOverflow
|
|
111
|
+
}),
|
|
112
|
+
[
|
|
113
|
+
actionRef,
|
|
114
|
+
apps,
|
|
115
|
+
customApps,
|
|
116
|
+
customSectionTitle,
|
|
117
|
+
handleOnClose,
|
|
118
|
+
isOverflow,
|
|
119
|
+
onKeyDown,
|
|
120
|
+
renderTrigger,
|
|
121
|
+
sectionTitle,
|
|
122
|
+
triggerRef
|
|
123
|
+
]
|
|
124
|
+
);
|
|
108
125
|
const RenderTrigger = renderTrigger || (({ ref }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ds_button.DSButtonV2, {
|
|
109
126
|
"data-testid": "app-picker__button",
|
|
110
127
|
id: "app-picker__button",
|
|
111
128
|
buttonType: "icon",
|
|
112
129
|
"aria-haspopup": "true",
|
|
113
|
-
"aria-expanded":
|
|
130
|
+
"aria-expanded": isOpen ?? open,
|
|
131
|
+
"aria-label": "Application picker",
|
|
114
132
|
innerRef: (0, import_ds_utilities.mergeRefs)(ref, defaultTriggerRef),
|
|
115
133
|
onClick: (e) => {
|
|
134
|
+
wasOpenedByKeyboardRef.current = e.detail === 0;
|
|
116
135
|
onClick(e);
|
|
117
136
|
setOpen(true);
|
|
118
137
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/DSAppPicker.tsx", "../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB;
|
|
4
|
+
"sourcesContent": ["/* eslint-disable react/no-unused-prop-types */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { MenuPicker } from '@elliemae/ds-icons';\nimport { DSButtonV2 } from '@elliemae/ds-button';\nimport { describe, mergeRefs } from '@elliemae/ds-utilities';\nimport DSPopover from '@elliemae/ds-popover';\nimport AppPickerImpl from './AppPickerImpl';\nimport { propTypes } from './propTypes';\nimport type { DSAppPickerType } from './types/AppPickerTypes';\n\nconst DSAppPicker: DSAppPickerType = ({\n apps = [],\n customApps = [],\n sectionTitle = 'APPLICATIONS',\n customSectionTitle = 'CUSTOM APPLICATIONS',\n icon: Icon = () => <MenuPicker color={['brand-primary', '700']} size=\"m\" />,\n renderTrigger,\n isOpen,\n onClose = () => null,\n actionRef,\n onKeyDown,\n onClick = () => null,\n onClickOutside = () => null,\n triggerRef,\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 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 ],\n );\n\n const RenderTrigger =\n renderTrigger ||\n (({ ref }: { ref: React.RefObject<HTMLButtonElement> }) => (\n <DSButtonV2\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, defaultTriggerRef)}\n onClick={(e: React.MouseEvent) => {\n wasOpenedByKeyboardRef.current = e.detail === 0;\n onClick(e);\n setOpen(true);\n }}\n >\n <Icon />\n </DSButtonV2>\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 = 'DSAppPicker';\nconst AppPickerWithSchema = describe(DSAppPicker);\nAppPickerWithSchema.propTypes = propTypes;\n\nexport { DSAppPicker, AppPickerWithSchema };\nexport default DSAppPicker;\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB;AACA,mBAAgE;AAChE,sBAA2B;AAC3B,uBAA2B;AAC3B,0BAAoC;AACpC,wBAAsB;AACtB,2BAA0B;AAC1B,uBAA0B;AAG1B,MAAM,cAA+B,CAAC;AAAA,EACpC,OAAO,CAAC;AAAA,EACR,aAAa,CAAC;AAAA,EACd,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,MAAM,OAAO,MAAM,4CAAC;AAAA,IAAW,OAAO,CAAC,iBAAiB,KAAK;AAAA,IAAG,MAAK;AAAA,GAAI;AAAA,EACzE;AAAA,EACA;AAAA,EACA,UAAU,MAAM;AAAA,EAChB;AAAA,EACA;AAAA,EACA,UAAU,MAAM;AAAA,EAChB,iBAAiB,MAAM;AAAA,EACvB;AACF,MAAM;AACJ,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,iBAAa,qBAAuB,IAAI;AAC9C,QAAM,wBAAoB,qBAAO,IAAI;AACrC,QAAM,6BAAyB,qBAAO,KAAK;AAE3C,8BAAU,MAAM;AACd,QAAI,aAAa,UAAU,SAAS;AAClC,gBAAU,QAAQ,eAAe,CAAC,UAAkB;AAClD,YAAI,WAAW,SAAS;AACtB,gBAAM,SAAS,WAAW;AAC1B,gBAAM,UAAU,CAAC,GAAG,OAAO,iBAAiB,QAAQ,CAAC;AACrD,kBAAQ,OAAO,MAAM;AAAA,QACvB;AAAA,MACF;AACA,gBAAU,QAAQ,eAAe,MAAM;AACrC,mBAAW,SAAS,MAAM;AAAA,MAC5B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,WAAW,MAAM,UAAU,CAAC;AAEhC,8BAAU,MAAM;AACd,eAAW,MAAM;AACf,UAAI,WAAW,SAAS;AACtB,cAAM,EAAE,cAAc,aAAa,IAAI,WAAW;AAClD,YAAI,eAAe;AAAc,iBAAO,cAAc,IAAI;AAAA,MAC5D;AACA,aAAO,cAAc,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,IAAI,CAAC;AAEjB,QAAM,oBAAgB,0BAAY,MAAM;AACtC,YAAQ,KAAK;AACb,YAAQ;AAAA,EACV,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,uBAAuB,CAAC,MAAwB;AACpD,YAAQ,KAAK;AACb,YAAQ;AACR,mBAAe,CAAC;AAAA,EAClB;AAEA,QAAM,uBAAmB;AAAA,IACvB,MACE,4CAAC,qBAAAA,SAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,YAAY,cAAc;AAAA,MAC1B;AAAA,MACA,mBAAmB,CAAC;AAAA,MACpB;AAAA,MACA;AAAA,KACF;AAAA,IAEF;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,gBACJ,kBACC,CAAC,EAAE,IAAI,MACN,4CAAC;AAAA,IACC,eAAY;AAAA,IACZ,IAAG;AAAA,IACH,YAAW;AAAA,IACX,iBAAc;AAAA,IACd,iBAAe,UAAU;AAAA,IACzB,cAAW;AAAA,IACX,cAAU,+BAAU,KAAK,iBAAiB;AAAA,IAC1C,SAAS,CAAC,MAAwB;AAChC,6BAAuB,UAAU,EAAE,WAAW;AAC9C,cAAQ,CAAC;AACT,cAAQ,IAAI;AAAA,IACd;AAAA,IAEA,sDAAC,QAAK;AAAA,GACR;AAGJ,SACE,4CAAC,kBAAAC,SAAA;AAAA,IACC,SAAS,4CAAC,oBAAiB;AAAA,IAC3B,QAAQ,OAAO,WAAW,YAAY,SAAS;AAAA,IAC/C,gBAAgB;AAAA,IAChB,WAAU;AAAA,IACV,iBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,WAAS;AAAA,IACT,OAAO;AAAA,MACL,SAAS;AAAA,MACT,UAAU;AAAA,MACV,OAAO;AAAA,IACT;AAAA,GACF;AAEJ;AAEA,YAAY,cAAc;AAC1B,MAAM,0BAAsB,8BAAS,WAAW;AAChD,oBAAoB,YAAY;AAGhC,IAAO,sBAAQ;",
|
|
6
6
|
"names": ["AppPickerImpl", "DSPopover"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
var useKeepTrackButtons_exports = {};
|
|
26
|
+
__export(useKeepTrackButtons_exports, {
|
|
27
|
+
useKeepTrackButtons: () => useKeepTrackButtons
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(useKeepTrackButtons_exports);
|
|
30
|
+
var React = __toESM(require("react"));
|
|
31
|
+
var import_react = require("react");
|
|
32
|
+
var import_utils = require("../utils");
|
|
33
|
+
const useKeepTrackButtons = (wrapperRef, wasOpenedByKeyboardRef, actionRef, triggerIsInternal) => {
|
|
34
|
+
const allFocusableButtons = (0, import_react.useRef)([]);
|
|
35
|
+
const selectedButton = (0, import_react.useRef)(null);
|
|
36
|
+
(0, import_react.useEffect)(() => {
|
|
37
|
+
if (actionRef && actionRef.current) {
|
|
38
|
+
actionRef.current.focusSelectedOrFirstAvailable = () => setTimeout(() => (0, import_utils.focusSelectedOrFirstAvailable)(wrapperRef, allFocusableButtons, selectedButton));
|
|
39
|
+
}
|
|
40
|
+
}, [actionRef, wrapperRef]);
|
|
41
|
+
(0, import_react.useEffect)(() => {
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
wrapperRef?.current?.querySelectorAll("button").forEach((e, index) => {
|
|
44
|
+
if (!e.hasAttribute("disabled")) {
|
|
45
|
+
allFocusableButtons?.current?.push(e);
|
|
46
|
+
}
|
|
47
|
+
if (e.getAttribute("aria-selected") === "true") {
|
|
48
|
+
selectedButton.current = index;
|
|
49
|
+
}
|
|
50
|
+
if (wasOpenedByKeyboardRef.current || !triggerIsInternal) {
|
|
51
|
+
(0, import_utils.focusSelectedOrFirstAvailable)(wrapperRef, allFocusableButtons, selectedButton);
|
|
52
|
+
} else {
|
|
53
|
+
wrapperRef.current?.focus();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}, [wasOpenedByKeyboardRef, wrapperRef, triggerIsInternal]);
|
|
58
|
+
return { allFocusableButtons, selectedButton };
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=useKeepTrackButtons.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/hooks/useKeepTrackButtons.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
+
"sourcesContent": ["import React, { useEffect, useRef } from 'react';\nimport { focusSelectedOrFirstAvailable } from '../utils';\nimport { ActionRef } from '../types/AppPickerTypes';\n\nexport const useKeepTrackButtons = (\n wrapperRef: React.RefObject<HTMLDivElement>,\n wasOpenedByKeyboardRef: React.MutableRefObject<boolean>,\n actionRef?: ActionRef,\n triggerIsInternal?: boolean,\n) => {\n const allFocusableButtons = useRef<HTMLButtonElement[]>([]);\n const selectedButton = useRef<number | null>(null);\n\n useEffect(() => {\n if (actionRef && actionRef.current) {\n actionRef.current.focusSelectedOrFirstAvailable = () =>\n setTimeout(() => focusSelectedOrFirstAvailable(wrapperRef, allFocusableButtons, selectedButton));\n }\n }, [actionRef, wrapperRef]);\n\n useEffect(() => {\n setTimeout(() => {\n wrapperRef?.current?.querySelectorAll('button').forEach((e, index) => {\n if (!e.hasAttribute('disabled')) {\n allFocusableButtons?.current?.push(e);\n }\n if (e.getAttribute('aria-selected') === 'true') {\n selectedButton.current = index;\n }\n if (wasOpenedByKeyboardRef.current || !triggerIsInternal) {\n focusSelectedOrFirstAvailable(wrapperRef, allFocusableButtons, selectedButton);\n } else {\n wrapperRef.current?.focus();\n }\n });\n });\n }, [wasOpenedByKeyboardRef, wrapperRef, triggerIsInternal]);\n\n return { allFocusableButtons, selectedButton };\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADAvB,mBAAyC;AACzC,mBAA8C;AAGvC,MAAM,sBAAsB,CACjC,YACA,wBACA,WACA,sBACG;AACH,QAAM,0BAAsB,qBAA4B,CAAC,CAAC;AAC1D,QAAM,qBAAiB,qBAAsB,IAAI;AAEjD,8BAAU,MAAM;AACd,QAAI,aAAa,UAAU,SAAS;AAClC,gBAAU,QAAQ,gCAAgC,MAChD,WAAW,UAAM,4CAA8B,YAAY,qBAAqB,cAAc,CAAC;AAAA,IACnG;AAAA,EACF,GAAG,CAAC,WAAW,UAAU,CAAC;AAE1B,8BAAU,MAAM;AACd,eAAW,MAAM;AACf,kBAAY,SAAS,iBAAiB,QAAQ,EAAE,QAAQ,CAAC,GAAG,UAAU;AACpE,YAAI,CAAC,EAAE,aAAa,UAAU,GAAG;AAC/B,+BAAqB,SAAS,KAAK,CAAC;AAAA,QACtC;AACA,YAAI,EAAE,aAAa,eAAe,MAAM,QAAQ;AAC9C,yBAAe,UAAU;AAAA,QAC3B;AACA,YAAI,uBAAuB,WAAW,CAAC,mBAAmB;AACxD,0DAA8B,YAAY,qBAAqB,cAAc;AAAA,QAC/E,OAAO;AACL,qBAAW,SAAS,MAAM;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH,GAAG,CAAC,wBAAwB,YAAY,iBAAiB,CAAC;AAE1D,SAAO,EAAE,qBAAqB,eAAe;AAC/C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/propTypes.tsx", "../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["import { PropTypes } from '@elliemae/ds-utilities';\nimport { MenuPicker } from '@elliemae/ds-icons';\n\nexport const propTypes = {\n apps: PropTypes.array.description(\n 'Main items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ).isRequired,\n customApps: PropTypes.array.description(\n 'Custom items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ),\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.description('Custom trigger component.'),\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 onClose: PropTypes.func.description('Callback function when the AppPicker closes'),\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}
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
|
4
|
+
"sourcesContent": ["import { WeakValidationMap } from 'react';\nimport { PropTypes } from '@elliemae/ds-utilities';\nimport { MenuPicker } from '@elliemae/ds-icons';\n\nexport const propTypes = {\n apps: PropTypes.array.description(\n 'Main items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ).isRequired,\n customApps: PropTypes.array.description(\n 'Custom items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ),\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.description('Custom trigger component.'),\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 onClose: PropTypes.func.description('Callback function when the AppPicker closes'),\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} as WeakValidationMap<unknown>;\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADCvB,0BAA0B;AAC1B,sBAA2B;AAEpB,MAAM,YAAY;AAAA,EACvB,MAAM,8BAAU,MAAM;AAAA,IACpB;AAAA,EACF,EAAE;AAAA,EACF,YAAY,8BAAU,MAAM;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,cAAc,8BAAU,OAAO,YAAY,oBAAoB,EAAE,aAAa,cAAc;AAAA,EAC5F,oBAAoB,8BAAU,OAAO,YAAY,sBAAsB,EAAE,aAAa,qBAAqB;AAAA,EAC3G,MAAM,8BAAU,KAAK,YAAY,uBAAuB,EAAE,aAAa,0BAAU;AAAA,EACjF,eAAe,8BAAU,KAAK,YAAY,2BAA2B;AAAA,EACrE,WAAW,8BAAU,UAAU,CAAC,8BAAU,MAAM,8BAAU,MAAM,EAAE,SAAS,8BAAU,IAAI,CAAC,CAAC,CAAC,EAAE;AAAA,IAC5F;AAAA,EACF;AAAA,EACA,QAAQ,8BAAU,KAAK,YAAY,6CAA6C;AAAA,EAChF,SAAS,8BAAU,KAAK,YAAY,6CAA6C;AAAA,EACjF,WAAW,8BAAU,KAAK,YAAY,6BAA6B;AAAA,EACnE,SAAS,8BAAU,KAAK,YAAY,uCAAuC;AAAA,EAC3E,gBAAgB,8BAAU,KAAK,YAAY,6DAA6D;AAC1G;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cjs/styles.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/styles.tsx", "../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable max-lines */\nimport { styled } from '@elliemae/ds-system';\nimport { Grid } from '@elliemae/ds-grid';\n\nexport const StyledWrapper = styled(Grid, { name: 'DS-AppPicker', slot: 'root' })
|
|
4
|
+
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable max-lines */\nimport { styled } from '@elliemae/ds-system';\nimport { Grid } from '@elliemae/ds-grid';\n\nexport const StyledWrapper = styled(Grid, { name: 'DS-AppPicker', slot: 'root' })<{ isOverflow: boolean }>`\n align-items: center;\n min-width: 308px;\n min-height: 110px;\n max-height: 449px;\n width: 308px;\n overflow-y: auto;\n overflow-x: hidden;\n margin: 0;\n padding: ${({ isOverflow }) => (isOverflow ? '0 0 8px 16px' : '0 16px 8px 16px')};\n &:focus {\n outline: none;\n }\n`;\n\nexport const StyledListItem = styled.li`\n list-style: none;\n`;\n\nexport const StyledListItemFullRow = styled.li`\n list-style: none;\n grid-column: 1/4;\n`;\n\nexport const StyledTitle = styled('h3', { name: 'DS-AppPicker', slot: 'title' })`\n color: ${({ theme }) => theme.colors.neutral[700]};\n font-size: ${({ theme }) => theme.fontSizes.value[400]};\n font-weight: ${({ theme }) => theme.fontWeights.semibold};\n margin: 12px 0 8px 0;\n line-height: 1.385;\n text-transform: uppercase;\n`;\n\nexport const StyledSeparator = styled('hr', { name: 'DS-AppPicker', slot: 'separator' })`\n border-top: 1px solid ${({ theme }) => theme.colors.neutral[100]};\n border-bottom: none;\n width: 99%;\n margin: 8px 0 0 0;\n`;\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADEvB,uBAAuB;AACvB,qBAAqB;AAEd,MAAM,oBAAgB,yBAAO,qBAAM,EAAE,MAAM,gBAAgB,MAAM,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aASnE,CAAC,EAAE,WAAW,MAAO,aAAa,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAMzD,MAAM,iBAAiB,wBAAO;AAAA;AAAA;AAI9B,MAAM,wBAAwB,wBAAO;AAAA;AAAA;AAAA;AAKrC,MAAM,kBAAc,yBAAO,MAAM,EAAE,MAAM,gBAAgB,MAAM,QAAQ,CAAC;AAAA,WACpE,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ;AAAA,eAChC,CAAC,EAAE,MAAM,MAAM,MAAM,UAAU,MAAM;AAAA,iBACnC,CAAC,EAAE,MAAM,MAAM,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAM3C,MAAM,sBAAkB,yBAAO,MAAM,EAAE,MAAM,gBAAgB,MAAM,YAAY,CAAC;AAAA,0BAC7D,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/types/AppPickerTypes.tsx", "../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["import type { SvgIconType } from '@elliemae/ds-icons';\n\nexport interface AppItemType {\n label: string;\n icon: React.ComponentType<{ className: string; size: string }>;\n onClick?: () => void | null;\n disabled?: boolean;\n id?: string;\n selected?: boolean;\n}\n\nexport interface AppPickerPropsType {\n apps: AppItemType[];\n customApps: AppItemType[];\n sectionTitle: string;\n customSectionTitle: string;\n icon: SvgIconType;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n actionRef?:
|
|
4
|
+
"sourcesContent": ["import type { SvgIconType } from '@elliemae/ds-icons';\nimport React from 'react';\n\nexport interface AppItemType {\n label: string;\n icon: React.ComponentType<{ className: string; size: string }>;\n onClick?: (e: React.MouseEvent, item: AppItemType) => void | null;\n disabled?: boolean;\n id?: string;\n selected?: boolean;\n}\n\nexport type ActionRef = React.MutableRefObject<{\n focusToIndex?: (index: number) => void;\n focusSelectedOrFirstAvailable?: () => void;\n focusWrapper: () => void;\n}>;\n\nexport interface AppPickerPropsType {\n apps: AppItemType[];\n customApps: AppItemType[];\n sectionTitle: string;\n customSectionTitle: string;\n icon: SvgIconType;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n actionRef?: ActionRef;\n onClick?: (e: React.MouseEvent) => void;\n onClickOutside?: (e: React.MouseEvent) => void;\n renderTrigger?: React.ComponentType<unknown>;\n isOpen?: boolean;\n onClose?: () => void;\n triggerRef?: React.RefObject<HTMLButtonElement>;\n}\n\nexport interface AppPickerImplProps {\n apps: AppItemType[];\n customApps: AppItemType[];\n sectionTitle: string;\n customSectionTitle: string;\n close?: () => void;\n onKeyDown?: (e: React.KeyboardEvent) => void;\n wrapperRef: React.RefObject<HTMLDivElement>;\n triggerRef: React.RefObject<HTMLElement>;\n actionRef?: ActionRef;\n isOverflow: boolean;\n triggerIsInternal: boolean;\n wasOpenedByKeyboardRef: React.MutableRefObject<boolean>;\n}\n\nexport type DSAppPickerImplType = React.ComponentType<AppPickerImplProps>;\nexport type DSAppPickerType = React.ComponentType<AppPickerPropsType>;\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;ACAA,YAAuB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cjs/utils.js
CHANGED
|
@@ -24,6 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
25
|
var utils_exports = {};
|
|
26
26
|
__export(utils_exports, {
|
|
27
|
+
focusSelectedOrFirstAvailable: () => focusSelectedOrFirstAvailable,
|
|
27
28
|
keys: () => keys
|
|
28
29
|
});
|
|
29
30
|
module.exports = __toCommonJS(utils_exports);
|
|
@@ -40,4 +41,11 @@ const keys = {
|
|
|
40
41
|
HOME: "Home",
|
|
41
42
|
END: "End"
|
|
42
43
|
};
|
|
44
|
+
const focusSelectedOrFirstAvailable = (wrapperRef, allFocusableButtonsRef, selectedButtonRef) => {
|
|
45
|
+
if (selectedButtonRef.current !== null) {
|
|
46
|
+
wrapperRef?.current?.querySelectorAll("button")[selectedButtonRef.current].focus();
|
|
47
|
+
} else {
|
|
48
|
+
allFocusableButtonsRef?.current[0]?.focus();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
43
51
|
//# sourceMappingURL=utils.js.map
|
package/dist/cjs/utils.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils.tsx", "../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
|
4
|
+
"sourcesContent": ["import React from 'react';\n\nexport const keys = {\n LEFT: 'ArrowLeft',\n UP: 'ArrowUp',\n RIGHT: 'ArrowRight',\n DOWN: 'ArrowDown',\n ENTER: 'Enter',\n SPACE: '',\n TAB: 'Tab',\n ESC: 'Escape',\n HOME: 'Home',\n END: 'End',\n};\n\nexport const focusSelectedOrFirstAvailable = (\n wrapperRef: React.RefObject<HTMLDivElement>,\n allFocusableButtonsRef: React.MutableRefObject<HTMLButtonElement[]>,\n selectedButtonRef: React.MutableRefObject<number | null>,\n) => {\n if (selectedButtonRef.current !== null) {\n wrapperRef?.current?.querySelectorAll('button')[selectedButtonRef.current].focus();\n } else {\n allFocusableButtonsRef?.current[0]?.focus();\n }\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADEhB,MAAM,OAAO;AAAA,EAClB,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AACP;AAEO,MAAM,gCAAgC,CAC3C,YACA,wBACA,sBACG;AACH,MAAI,kBAAkB,YAAY,MAAM;AACtC,gBAAY,SAAS,iBAAiB,QAAQ,EAAE,kBAAkB,SAAS,MAAM;AAAA,EACnF,OAAO;AACL,4BAAwB,QAAQ,IAAI,MAAM;AAAA,EAC5C;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useMemo } from "react";
|
|
4
4
|
import { DSChip } from "@elliemae/ds-chip";
|
|
5
5
|
import { keys } from "./utils";
|
|
6
6
|
import { StyledWrapper, StyledSeparator, StyledListItemFullRow, StyledListItem, StyledTitle } from "./styles";
|
|
7
|
+
import { useKeepTrackButtons } from "./hooks/useKeepTrackButtons";
|
|
7
8
|
const AppPickerImpl = ({
|
|
8
9
|
apps = [],
|
|
9
10
|
customApps = [],
|
|
@@ -13,27 +14,12 @@ const AppPickerImpl = ({
|
|
|
13
14
|
wrapperRef,
|
|
14
15
|
onKeyDown,
|
|
15
16
|
triggerRef,
|
|
16
|
-
isOverflow
|
|
17
|
+
isOverflow,
|
|
18
|
+
actionRef,
|
|
19
|
+
wasOpenedByKeyboardRef,
|
|
20
|
+
triggerIsInternal
|
|
17
21
|
}) => {
|
|
18
|
-
const allFocusableButtons =
|
|
19
|
-
const selectedButton = useRef(null);
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
setTimeout(() => {
|
|
22
|
-
wrapperRef?.current?.querySelectorAll("button").forEach((e, index) => {
|
|
23
|
-
if (!e.hasAttribute("disabled")) {
|
|
24
|
-
allFocusableButtons?.current?.push(e);
|
|
25
|
-
}
|
|
26
|
-
if (e.getAttribute("aria-selected") === "true") {
|
|
27
|
-
selectedButton.current = index;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
if (selectedButton.current) {
|
|
31
|
-
wrapperRef?.current?.querySelectorAll("button")[selectedButton.current].focus();
|
|
32
|
-
} else {
|
|
33
|
-
allFocusableButtons?.current[0]?.focus();
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}, [wrapperRef]);
|
|
22
|
+
const { allFocusableButtons } = useKeepTrackButtons(wrapperRef, wasOpenedByKeyboardRef, actionRef, triggerIsInternal);
|
|
37
23
|
const handleKeyDown = useCallback(
|
|
38
24
|
(e) => {
|
|
39
25
|
switch (e.key) {
|
|
@@ -56,7 +42,7 @@ const AppPickerImpl = ({
|
|
|
56
42
|
break;
|
|
57
43
|
}
|
|
58
44
|
},
|
|
59
|
-
[close, triggerRef]
|
|
45
|
+
[allFocusableButtons, close, triggerRef]
|
|
60
46
|
);
|
|
61
47
|
const handleOnClick = useCallback(
|
|
62
48
|
(app) => (e) => {
|
|
@@ -75,11 +61,15 @@ const AppPickerImpl = ({
|
|
|
75
61
|
},
|
|
76
62
|
[onKeyDown, close]
|
|
77
63
|
);
|
|
78
|
-
const
|
|
64
|
+
const totalAppsLength = useMemo(() => apps.length + customApps.length, [apps.length, customApps.length]);
|
|
79
65
|
const buildRows = useCallback(
|
|
80
|
-
(appList, prevIndex
|
|
81
|
-
|
|
66
|
+
(appList, prevIndex, title) => /* @__PURE__ */ jsx(Fragment, {
|
|
67
|
+
children: appList.map((app, index) => {
|
|
82
68
|
const { label, disabled, selected, icon: Icon, id } = app;
|
|
69
|
+
const IconComp = () => /* @__PURE__ */ jsx(Icon, {
|
|
70
|
+
className: "app-picker__icon",
|
|
71
|
+
size: "m"
|
|
72
|
+
});
|
|
83
73
|
return /* @__PURE__ */ jsx(StyledListItem, {
|
|
84
74
|
children: /* @__PURE__ */ jsx(DSChip, {
|
|
85
75
|
onClick: handleOnClick(app),
|
|
@@ -90,28 +80,25 @@ const AppPickerImpl = ({
|
|
|
90
80
|
selected,
|
|
91
81
|
"aria-selected": selected,
|
|
92
82
|
id,
|
|
93
|
-
"aria-label": `${label}. ${title} (${index + prevIndex} of ${
|
|
94
|
-
icon:
|
|
95
|
-
className: "app-picker__icon",
|
|
96
|
-
size: "m"
|
|
97
|
-
}),
|
|
83
|
+
"aria-label": `${label}. ${title} (${index + prevIndex} of ${totalAppsLength})`,
|
|
84
|
+
icon: IconComp,
|
|
98
85
|
label
|
|
99
86
|
}, index)
|
|
100
87
|
});
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
88
|
+
})
|
|
89
|
+
}),
|
|
90
|
+
[handleKeyDown, handleOnClick, totalAppsLength]
|
|
91
|
+
);
|
|
92
|
+
const AppsRows = useMemo(() => buildRows(apps, 1, sectionTitle), [apps, buildRows, sectionTitle]);
|
|
93
|
+
const CustomRows = useMemo(
|
|
94
|
+
() => buildRows(customApps, apps.length, customSectionTitle),
|
|
95
|
+
[apps.length, buildRows, customApps, customSectionTitle]
|
|
107
96
|
);
|
|
108
|
-
const AppsRows = useMemo(() => buildRows(apps, 1, sectionTitle), []);
|
|
109
|
-
const CustomRows = useMemo(() => buildRows(customApps, apps.length, customSectionTitle), []);
|
|
110
97
|
const layout = useMemo(() => {
|
|
111
98
|
const cols = ["repeat(3, 92px)"];
|
|
112
99
|
let appsRows = 0;
|
|
113
100
|
let customRows = 0;
|
|
114
|
-
|
|
101
|
+
const rows = [];
|
|
115
102
|
if (apps.length > 0) {
|
|
116
103
|
appsRows = apps.length / 3;
|
|
117
104
|
rows.push("68px", `repeat(${appsRows}, 68px})`);
|
|
@@ -125,14 +112,17 @@ const AppPickerImpl = ({
|
|
|
125
112
|
cols
|
|
126
113
|
};
|
|
127
114
|
}, [apps.length, customApps.length]);
|
|
115
|
+
const convertedTypeReference = wrapperRef;
|
|
128
116
|
return /* @__PURE__ */ jsxs(StyledWrapper, {
|
|
129
|
-
|
|
117
|
+
forwardedAs: "ul",
|
|
118
|
+
ref: convertedTypeReference,
|
|
130
119
|
onKeyDown: handleOnKeyDownWrapper,
|
|
131
120
|
"data-testid": "app-picker__wrapper",
|
|
132
121
|
isOverflow,
|
|
133
122
|
cols: layout.cols,
|
|
134
123
|
rows: layout.rows,
|
|
135
|
-
|
|
124
|
+
tabIndex: -1,
|
|
125
|
+
"aria-label": `Application picker, ${sectionTitle} (${apps.length} apps)${customApps.length > 0 ? `, ${customSectionTitle} (${customApps.length} apps)` : ""}`,
|
|
136
126
|
children: [
|
|
137
127
|
/* @__PURE__ */ jsx(StyledListItemFullRow, {
|
|
138
128
|
"aria-hidden": true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../scripts/build/transpile/react-shim.js", "../../src/AppPickerImpl.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable react/prop-types */\n/* eslint-disable react/no-array-index-key */\n/* eslint-disable max-lines */\nimport React, {
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACAvB;AAGA,SAAgB,
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable react/prop-types */\n/* eslint-disable react/no-array-index-key */\n/* eslint-disable max-lines */\nimport React, { useCallback, useMemo } from 'react';\nimport { DSChip } from '@elliemae/ds-chip';\nimport { keys } from './utils';\nimport { AppItemType, DSAppPickerImplType } from './types/AppPickerTypes';\nimport { StyledWrapper, StyledSeparator, StyledListItemFullRow, StyledListItem, StyledTitle } from './styles';\nimport { useKeepTrackButtons } from './hooks/useKeepTrackButtons';\n\nconst AppPickerImpl: DSAppPickerImplType = ({\n apps = [],\n customApps = [],\n sectionTitle = 'APPLICATIONS',\n customSectionTitle = 'CUSTOM APPLICATIONS',\n close = () => null,\n wrapperRef,\n onKeyDown,\n triggerRef,\n isOverflow,\n actionRef,\n wasOpenedByKeyboardRef,\n triggerIsInternal,\n}) => {\n const { allFocusableButtons } = useKeepTrackButtons(wrapperRef, wasOpenedByKeyboardRef, actionRef, triggerIsInternal);\n\n // eslint-disable-next-line max-statements\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case keys.ESC:\n triggerRef?.current?.focus();\n close();\n break;\n case keys.TAB:\n if (e.shiftKey) {\n if (e.target === allFocusableButtons.current[0]) {\n e.preventDefault();\n allFocusableButtons?.current[allFocusableButtons.current.length - 1]?.focus();\n }\n } else if (e.target === allFocusableButtons.current[allFocusableButtons.current.length - 1]) {\n e.preventDefault();\n allFocusableButtons?.current[0]?.focus();\n }\n break;\n default:\n break;\n }\n },\n [allFocusableButtons, close, triggerRef],\n );\n\n const handleOnClick = useCallback(\n (app: AppItemType) => (e: React.MouseEvent) => {\n if (app.onClick) app.onClick(e, app);\n },\n [],\n );\n\n const handleOnKeyDownWrapper = useCallback(\n (e: React.KeyboardEvent) => {\n if (onKeyDown) onKeyDown(e);\n if (!onKeyDown && e.key === keys.ESC) {\n close();\n }\n },\n [onKeyDown, close],\n );\n\n const totalAppsLength = useMemo(() => apps.length + customApps.length, [apps.length, customApps.length]);\n\n const buildRows = useCallback(\n (appList: AppItemType[], prevIndex: number, title: string): JSX.Element => (\n <>\n {appList.map((app, index) => {\n const { label, disabled, selected, icon: Icon, id } = app;\n\n // eslint-disable-next-line react/no-unstable-nested-components\n const IconComp = () => <Icon className=\"app-picker__icon\" size=\"m\" />;\n\n return (\n <StyledListItem>\n <DSChip\n key={index}\n onClick={handleOnClick(app)}\n onKeyDown={handleKeyDown}\n data-testid=\"app-picker__chip\"\n aria-disabled={disabled}\n disabled={disabled}\n selected={selected}\n aria-selected={selected}\n id={id}\n aria-label={`${label}. ${title} (${index + prevIndex} of ${totalAppsLength})`}\n icon={IconComp}\n label={label}\n />\n </StyledListItem>\n );\n })}\n </>\n ),\n [handleKeyDown, handleOnClick, totalAppsLength],\n );\n\n const AppsRows = useMemo(() => buildRows(apps, 1, sectionTitle), [apps, buildRows, sectionTitle]);\n const CustomRows = useMemo(\n () => buildRows(customApps, apps.length, customSectionTitle),\n [apps.length, buildRows, customApps, customSectionTitle],\n );\n\n const layout = useMemo(() => {\n const cols = ['repeat(3, 92px)'];\n let appsRows = 0;\n let customRows = 0;\n const rows = [];\n if (apps.length > 0) {\n appsRows = apps.length / 3;\n rows.push('68px', `repeat(${appsRows}, 68px})`);\n }\n if (customApps.length > 0) {\n customRows = customApps.length / 3;\n rows.push('9px', '68px', `repeat(${customRows}, 68px})`);\n }\n return {\n rows,\n cols,\n };\n }, [apps.length, customApps.length]);\n\n // Needed just for typescript reasons\n const convertedTypeReference = wrapperRef as unknown as React.RefObject<HTMLDivElement> &\n React.RefObject<HTMLUListElement>;\n\n return (\n <StyledWrapper\n forwardedAs=\"ul\"\n ref={convertedTypeReference}\n onKeyDown={handleOnKeyDownWrapper}\n data-testid=\"app-picker__wrapper\"\n isOverflow={isOverflow}\n cols={layout.cols}\n rows={layout.rows}\n tabIndex={-1}\n aria-label={`Application picker, ${sectionTitle} (${apps.length} apps)${\n customApps.length > 0 ? `, ${customSectionTitle} (${customApps.length} apps)` : ''\n }`}\n >\n <StyledListItemFullRow aria-hidden>\n <StyledTitle data-testid=\"app-picker__main-title\">{sectionTitle}</StyledTitle>\n </StyledListItemFullRow>\n {AppsRows}\n {customApps.length > 0 && (\n <>\n <StyledListItemFullRow aria-hidden>\n <StyledSeparator />\n </StyledListItemFullRow>\n <StyledListItemFullRow aria-hidden>\n <StyledTitle data-testid=\"app-picker__custom-title\">{customSectionTitle}</StyledTitle>\n </StyledListItemFullRow>\n {CustomRows}\n </>\n )}\n </StyledWrapper>\n );\n};\n\nexport default AppPickerImpl;\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACAvB;AAGA,SAAgB,aAAa,eAAe;AAC5C,SAAS,cAAc;AACvB,SAAS,YAAY;AAErB,SAAS,eAAe,iBAAiB,uBAAuB,gBAAgB,mBAAmB;AACnG,SAAS,2BAA2B;AAEpC,MAAM,gBAAqC,CAAC;AAAA,EAC1C,OAAO,CAAC;AAAA,EACR,aAAa,CAAC;AAAA,EACd,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,QAAQ,MAAM;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,oBAAoB,IAAI,oBAAoB,YAAY,wBAAwB,WAAW,iBAAiB;AAGpH,QAAM,gBAAgB;AAAA,IACpB,CAAC,MAA2B;AAC1B,cAAQ,EAAE;AAAA,aACH,KAAK;AACR,sBAAY,SAAS,MAAM;AAC3B,gBAAM;AACN;AAAA,aACG,KAAK;AACR,cAAI,EAAE,UAAU;AACd,gBAAI,EAAE,WAAW,oBAAoB,QAAQ,IAAI;AAC/C,gBAAE,eAAe;AACjB,mCAAqB,QAAQ,oBAAoB,QAAQ,SAAS,IAAI,MAAM;AAAA,YAC9E;AAAA,UACF,WAAW,EAAE,WAAW,oBAAoB,QAAQ,oBAAoB,QAAQ,SAAS,IAAI;AAC3F,cAAE,eAAe;AACjB,iCAAqB,QAAQ,IAAI,MAAM;AAAA,UACzC;AACA;AAAA;AAEA;AAAA;AAAA,IAEN;AAAA,IACA,CAAC,qBAAqB,OAAO,UAAU;AAAA,EACzC;AAEA,QAAM,gBAAgB;AAAA,IACpB,CAAC,QAAqB,CAAC,MAAwB;AAC7C,UAAI,IAAI;AAAS,YAAI,QAAQ,GAAG,GAAG;AAAA,IACrC;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,yBAAyB;AAAA,IAC7B,CAAC,MAA2B;AAC1B,UAAI;AAAW,kBAAU,CAAC;AAC1B,UAAI,CAAC,aAAa,EAAE,QAAQ,KAAK,KAAK;AACpC,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,WAAW,KAAK;AAAA,EACnB;AAEA,QAAM,kBAAkB,QAAQ,MAAM,KAAK,SAAS,WAAW,QAAQ,CAAC,KAAK,QAAQ,WAAW,MAAM,CAAC;AAEvG,QAAM,YAAY;AAAA,IAChB,CAAC,SAAwB,WAAmB,UAC1C;AAAA,MACG,kBAAQ,IAAI,CAAC,KAAK,UAAU;AAC3B,cAAM,EAAE,OAAO,UAAU,UAAU,MAAM,MAAM,GAAG,IAAI;AAGtD,cAAM,WAAW,MAAM,oBAAC;AAAA,UAAK,WAAU;AAAA,UAAmB,MAAK;AAAA,SAAI;AAEnE,eACE,oBAAC;AAAA,UACC,8BAAC;AAAA,YAEC,SAAS,cAAc,GAAG;AAAA,YAC1B,WAAW;AAAA,YACX,eAAY;AAAA,YACZ,iBAAe;AAAA,YACf;AAAA,YACA;AAAA,YACA,iBAAe;AAAA,YACf;AAAA,YACA,cAAY,GAAG,UAAU,UAAU,QAAQ,gBAAgB;AAAA,YAC3D,MAAM;AAAA,YACN;AAAA,aAXK,KAYP;AAAA,SACF;AAAA,MAEJ,CAAC;AAAA,KACH;AAAA,IAEF,CAAC,eAAe,eAAe,eAAe;AAAA,EAChD;AAEA,QAAM,WAAW,QAAQ,MAAM,UAAU,MAAM,GAAG,YAAY,GAAG,CAAC,MAAM,WAAW,YAAY,CAAC;AAChG,QAAM,aAAa;AAAA,IACjB,MAAM,UAAU,YAAY,KAAK,QAAQ,kBAAkB;AAAA,IAC3D,CAAC,KAAK,QAAQ,WAAW,YAAY,kBAAkB;AAAA,EACzD;AAEA,QAAM,SAAS,QAAQ,MAAM;AAC3B,UAAM,OAAO,CAAC,iBAAiB;AAC/B,QAAI,WAAW;AACf,QAAI,aAAa;AACjB,UAAM,OAAO,CAAC;AACd,QAAI,KAAK,SAAS,GAAG;AACnB,iBAAW,KAAK,SAAS;AACzB,WAAK,KAAK,QAAQ,UAAU,kBAAkB;AAAA,IAChD;AACA,QAAI,WAAW,SAAS,GAAG;AACzB,mBAAa,WAAW,SAAS;AACjC,WAAK,KAAK,OAAO,QAAQ,UAAU,oBAAoB;AAAA,IACzD;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,KAAK,QAAQ,WAAW,MAAM,CAAC;AAGnC,QAAM,yBAAyB;AAG/B,SACE,qBAAC;AAAA,IACC,aAAY;AAAA,IACZ,KAAK;AAAA,IACL,WAAW;AAAA,IACX,eAAY;AAAA,IACZ;AAAA,IACA,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,UAAU;AAAA,IACV,cAAY,uBAAuB,iBAAiB,KAAK,eACvD,WAAW,SAAS,IAAI,KAAK,uBAAuB,WAAW,iBAAiB;AAAA,IAGlF;AAAA,0BAAC;AAAA,QAAsB,eAAW;AAAA,QAChC,8BAAC;AAAA,UAAY,eAAY;AAAA,UAA0B;AAAA,SAAa;AAAA,OAClE;AAAA,MACC;AAAA,MACA,WAAW,SAAS,KACnB;AAAA,QACE;AAAA,8BAAC;AAAA,YAAsB,eAAW;AAAA,YAChC,8BAAC,mBAAgB;AAAA,WACnB;AAAA,UACA,oBAAC;AAAA,YAAsB,eAAW;AAAA,YAChC,8BAAC;AAAA,cAAY,eAAY;AAAA,cAA4B;AAAA,aAAmB;AAAA,WAC1E;AAAA,UACC;AAAA;AAAA,OACH;AAAA;AAAA,GAEJ;AAEJ;AAEA,IAAO,wBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/esm/DSAppPicker.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect, useRef } from "react";
|
|
3
|
+
import { useState, useEffect, useRef, useCallback } from "react";
|
|
4
4
|
import { MenuPicker } from "@elliemae/ds-icons";
|
|
5
5
|
import { DSButtonV2 } from "@elliemae/ds-button";
|
|
6
6
|
import { describe, mergeRefs } from "@elliemae/ds-utilities";
|
|
@@ -29,6 +29,7 @@ const DSAppPicker = ({
|
|
|
29
29
|
const [isOverflow, setIsOverflow] = useState(false);
|
|
30
30
|
const wrapperRef = useRef(null);
|
|
31
31
|
const defaultTriggerRef = useRef(null);
|
|
32
|
+
const wasOpenedByKeyboardRef = useRef(false);
|
|
32
33
|
useEffect(() => {
|
|
33
34
|
if (actionRef && actionRef.current) {
|
|
34
35
|
actionRef.current.focusToIndex = (index) => {
|
|
@@ -38,6 +39,9 @@ const DSAppPicker = ({
|
|
|
38
39
|
buttons[index].focus();
|
|
39
40
|
}
|
|
40
41
|
};
|
|
42
|
+
actionRef.current.focusWrapper = () => {
|
|
43
|
+
wrapperRef.current?.focus();
|
|
44
|
+
};
|
|
41
45
|
}
|
|
42
46
|
}, [actionRef, apps, customApps]);
|
|
43
47
|
useEffect(() => {
|
|
@@ -50,38 +54,53 @@ const DSAppPicker = ({
|
|
|
50
54
|
return setIsOverflow(false);
|
|
51
55
|
});
|
|
52
56
|
}, [isOpen, open]);
|
|
53
|
-
const handleOnClose = () => {
|
|
54
|
-
|
|
55
|
-
setOpen(isOpen);
|
|
56
|
-
} else {
|
|
57
|
-
setOpen(false);
|
|
58
|
-
}
|
|
57
|
+
const handleOnClose = useCallback(() => {
|
|
58
|
+
setOpen(false);
|
|
59
59
|
onClose();
|
|
60
|
-
};
|
|
60
|
+
}, [onClose]);
|
|
61
61
|
const handleOnClickOutside = (e) => {
|
|
62
62
|
setOpen(false);
|
|
63
63
|
onClose();
|
|
64
64
|
onClickOutside(e);
|
|
65
65
|
};
|
|
66
|
-
const AppPickerContent = (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
const AppPickerContent = useCallback(
|
|
67
|
+
() => /* @__PURE__ */ jsx(AppPickerImpl, {
|
|
68
|
+
apps,
|
|
69
|
+
customApps,
|
|
70
|
+
sectionTitle,
|
|
71
|
+
customSectionTitle,
|
|
72
|
+
close: handleOnClose,
|
|
73
|
+
wrapperRef,
|
|
74
|
+
onKeyDown,
|
|
75
|
+
triggerRef: triggerRef || defaultTriggerRef,
|
|
76
|
+
actionRef,
|
|
77
|
+
triggerIsInternal: !renderTrigger,
|
|
78
|
+
wasOpenedByKeyboardRef,
|
|
79
|
+
isOverflow
|
|
80
|
+
}),
|
|
81
|
+
[
|
|
82
|
+
actionRef,
|
|
83
|
+
apps,
|
|
84
|
+
customApps,
|
|
85
|
+
customSectionTitle,
|
|
86
|
+
handleOnClose,
|
|
87
|
+
isOverflow,
|
|
88
|
+
onKeyDown,
|
|
89
|
+
renderTrigger,
|
|
90
|
+
sectionTitle,
|
|
91
|
+
triggerRef
|
|
92
|
+
]
|
|
93
|
+
);
|
|
77
94
|
const RenderTrigger = renderTrigger || (({ ref }) => /* @__PURE__ */ jsx(DSButtonV2, {
|
|
78
95
|
"data-testid": "app-picker__button",
|
|
79
96
|
id: "app-picker__button",
|
|
80
97
|
buttonType: "icon",
|
|
81
98
|
"aria-haspopup": "true",
|
|
82
|
-
"aria-expanded":
|
|
99
|
+
"aria-expanded": isOpen ?? open,
|
|
100
|
+
"aria-label": "Application picker",
|
|
83
101
|
innerRef: mergeRefs(ref, defaultTriggerRef),
|
|
84
102
|
onClick: (e) => {
|
|
103
|
+
wasOpenedByKeyboardRef.current = e.detail === 0;
|
|
85
104
|
onClick(e);
|
|
86
105
|
setOpen(true);
|
|
87
106
|
},
|
|
@@ -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", "
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACAvB;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable react/no-unused-prop-types */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { MenuPicker } from '@elliemae/ds-icons';\nimport { DSButtonV2 } from '@elliemae/ds-button';\nimport { describe, mergeRefs } from '@elliemae/ds-utilities';\nimport DSPopover from '@elliemae/ds-popover';\nimport AppPickerImpl from './AppPickerImpl';\nimport { propTypes } from './propTypes';\nimport type { DSAppPickerType } from './types/AppPickerTypes';\n\nconst DSAppPicker: DSAppPickerType = ({\n apps = [],\n customApps = [],\n sectionTitle = 'APPLICATIONS',\n customSectionTitle = 'CUSTOM APPLICATIONS',\n icon: Icon = () => <MenuPicker color={['brand-primary', '700']} size=\"m\" />,\n renderTrigger,\n isOpen,\n onClose = () => null,\n actionRef,\n onKeyDown,\n onClick = () => null,\n onClickOutside = () => null,\n triggerRef,\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 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 ],\n );\n\n const RenderTrigger =\n renderTrigger ||\n (({ ref }: { ref: React.RefObject<HTMLButtonElement> }) => (\n <DSButtonV2\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, defaultTriggerRef)}\n onClick={(e: React.MouseEvent) => {\n wasOpenedByKeyboardRef.current = e.detail === 0;\n onClick(e);\n setOpen(true);\n }}\n >\n <Icon />\n </DSButtonV2>\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 = 'DSAppPicker';\nconst AppPickerWithSchema = describe(DSAppPicker);\nAppPickerWithSchema.propTypes = propTypes;\n\nexport { DSAppPicker, AppPickerWithSchema };\nexport default DSAppPicker;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { focusSelectedOrFirstAvailable } from "../utils";
|
|
4
|
+
const useKeepTrackButtons = (wrapperRef, wasOpenedByKeyboardRef, actionRef, triggerIsInternal) => {
|
|
5
|
+
const allFocusableButtons = useRef([]);
|
|
6
|
+
const selectedButton = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (actionRef && actionRef.current) {
|
|
9
|
+
actionRef.current.focusSelectedOrFirstAvailable = () => setTimeout(() => focusSelectedOrFirstAvailable(wrapperRef, allFocusableButtons, selectedButton));
|
|
10
|
+
}
|
|
11
|
+
}, [actionRef, wrapperRef]);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
wrapperRef?.current?.querySelectorAll("button").forEach((e, index) => {
|
|
15
|
+
if (!e.hasAttribute("disabled")) {
|
|
16
|
+
allFocusableButtons?.current?.push(e);
|
|
17
|
+
}
|
|
18
|
+
if (e.getAttribute("aria-selected") === "true") {
|
|
19
|
+
selectedButton.current = index;
|
|
20
|
+
}
|
|
21
|
+
if (wasOpenedByKeyboardRef.current || !triggerIsInternal) {
|
|
22
|
+
focusSelectedOrFirstAvailable(wrapperRef, allFocusableButtons, selectedButton);
|
|
23
|
+
} else {
|
|
24
|
+
wrapperRef.current?.focus();
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}, [wasOpenedByKeyboardRef, wrapperRef, triggerIsInternal]);
|
|
29
|
+
return { allFocusableButtons, selectedButton };
|
|
30
|
+
};
|
|
31
|
+
export {
|
|
32
|
+
useKeepTrackButtons
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=useKeepTrackButtons.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../scripts/build/transpile/react-shim.js", "../../../src/hooks/useKeepTrackButtons.tsx"],
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React, { useEffect, useRef } from 'react';\nimport { focusSelectedOrFirstAvailable } from '../utils';\nimport { ActionRef } from '../types/AppPickerTypes';\n\nexport const useKeepTrackButtons = (\n wrapperRef: React.RefObject<HTMLDivElement>,\n wasOpenedByKeyboardRef: React.MutableRefObject<boolean>,\n actionRef?: ActionRef,\n triggerIsInternal?: boolean,\n) => {\n const allFocusableButtons = useRef<HTMLButtonElement[]>([]);\n const selectedButton = useRef<number | null>(null);\n\n useEffect(() => {\n if (actionRef && actionRef.current) {\n actionRef.current.focusSelectedOrFirstAvailable = () =>\n setTimeout(() => focusSelectedOrFirstAvailable(wrapperRef, allFocusableButtons, selectedButton));\n }\n }, [actionRef, wrapperRef]);\n\n useEffect(() => {\n setTimeout(() => {\n wrapperRef?.current?.querySelectorAll('button').forEach((e, index) => {\n if (!e.hasAttribute('disabled')) {\n allFocusableButtons?.current?.push(e);\n }\n if (e.getAttribute('aria-selected') === 'true') {\n selectedButton.current = index;\n }\n if (wasOpenedByKeyboardRef.current || !triggerIsInternal) {\n focusSelectedOrFirstAvailable(wrapperRef, allFocusableButtons, selectedButton);\n } else {\n wrapperRef.current?.focus();\n }\n });\n });\n }, [wasOpenedByKeyboardRef, wrapperRef, triggerIsInternal]);\n\n return { allFocusableButtons, selectedButton };\n};\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACAvB,SAAgB,WAAW,cAAc;AACzC,SAAS,qCAAqC;AAGvC,MAAM,sBAAsB,CACjC,YACA,wBACA,WACA,sBACG;AACH,QAAM,sBAAsB,OAA4B,CAAC,CAAC;AAC1D,QAAM,iBAAiB,OAAsB,IAAI;AAEjD,YAAU,MAAM;AACd,QAAI,aAAa,UAAU,SAAS;AAClC,gBAAU,QAAQ,gCAAgC,MAChD,WAAW,MAAM,8BAA8B,YAAY,qBAAqB,cAAc,CAAC;AAAA,IACnG;AAAA,EACF,GAAG,CAAC,WAAW,UAAU,CAAC;AAE1B,YAAU,MAAM;AACd,eAAW,MAAM;AACf,kBAAY,SAAS,iBAAiB,QAAQ,EAAE,QAAQ,CAAC,GAAG,UAAU;AACpE,YAAI,CAAC,EAAE,aAAa,UAAU,GAAG;AAC/B,+BAAqB,SAAS,KAAK,CAAC;AAAA,QACtC;AACA,YAAI,EAAE,aAAa,eAAe,MAAM,QAAQ;AAC9C,yBAAe,UAAU;AAAA,QAC3B;AACA,YAAI,uBAAuB,WAAW,CAAC,mBAAmB;AACxD,wCAA8B,YAAY,qBAAqB,cAAc;AAAA,QAC/E,OAAO;AACL,qBAAW,SAAS,MAAM;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH,GAAG,CAAC,wBAAwB,YAAY,iBAAiB,CAAC;AAE1D,SAAO,EAAE,qBAAqB,eAAe;AAC/C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../scripts/build/transpile/react-shim.js", "../../src/propTypes.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { PropTypes } from '@elliemae/ds-utilities';\nimport { MenuPicker } from '@elliemae/ds-icons';\n\nexport const propTypes = {\n apps: PropTypes.array.description(\n 'Main items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ).isRequired,\n customApps: PropTypes.array.description(\n 'Custom items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ),\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.description('Custom trigger component.'),\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 onClose: PropTypes.func.description('Callback function when the AppPicker closes'),\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}
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import { WeakValidationMap } from 'react';\nimport { PropTypes } from '@elliemae/ds-utilities';\nimport { MenuPicker } from '@elliemae/ds-icons';\n\nexport const propTypes = {\n apps: PropTypes.array.description(\n 'Main items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ).isRequired,\n customApps: PropTypes.array.description(\n 'Custom items. Format: [{ label:string, icon:component, onClick:func, disabled:bool, selected:bool }]',\n ),\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.description('Custom trigger component.'),\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 onClose: PropTypes.func.description('Callback function when the AppPicker closes'),\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} as WeakValidationMap<unknown>;\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACCvB,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAEpB,MAAM,YAAY;AAAA,EACvB,MAAM,UAAU,MAAM;AAAA,IACpB;AAAA,EACF,EAAE;AAAA,EACF,YAAY,UAAU,MAAM;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,cAAc,UAAU,OAAO,YAAY,oBAAoB,EAAE,aAAa,cAAc;AAAA,EAC5F,oBAAoB,UAAU,OAAO,YAAY,sBAAsB,EAAE,aAAa,qBAAqB;AAAA,EAC3G,MAAM,UAAU,KAAK,YAAY,uBAAuB,EAAE,aAAa,UAAU;AAAA,EACjF,eAAe,UAAU,KAAK,YAAY,2BAA2B;AAAA,EACrE,WAAW,UAAU,UAAU,CAAC,UAAU,MAAM,UAAU,MAAM,EAAE,SAAS,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE;AAAA,IAC5F;AAAA,EACF;AAAA,EACA,QAAQ,UAAU,KAAK,YAAY,6CAA6C;AAAA,EAChF,SAAS,UAAU,KAAK,YAAY,6CAA6C;AAAA,EACjF,WAAW,UAAU,KAAK,YAAY,6BAA6B;AAAA,EACnE,SAAS,UAAU,KAAK,YAAY,uCAAuC;AAAA,EAC3E,gBAAgB,UAAU,KAAK,YAAY,6DAA6D;AAC1G;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/esm/styles.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../scripts/build/transpile/react-shim.js", "../../src/styles.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable max-lines */\nimport { styled } from '@elliemae/ds-system';\nimport { Grid } from '@elliemae/ds-grid';\n\nexport const StyledWrapper = styled(Grid, { name: 'DS-AppPicker', slot: 'root' })
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable max-lines */\nimport { styled } from '@elliemae/ds-system';\nimport { Grid } from '@elliemae/ds-grid';\n\nexport const StyledWrapper = styled(Grid, { name: 'DS-AppPicker', slot: 'root' })<{ isOverflow: boolean }>`\n align-items: center;\n min-width: 308px;\n min-height: 110px;\n max-height: 449px;\n width: 308px;\n overflow-y: auto;\n overflow-x: hidden;\n margin: 0;\n padding: ${({ isOverflow }) => (isOverflow ? '0 0 8px 16px' : '0 16px 8px 16px')};\n &:focus {\n outline: none;\n }\n`;\n\nexport const StyledListItem = styled.li`\n list-style: none;\n`;\n\nexport const StyledListItemFullRow = styled.li`\n list-style: none;\n grid-column: 1/4;\n`;\n\nexport const StyledTitle = styled('h3', { name: 'DS-AppPicker', slot: 'title' })`\n color: ${({ theme }) => theme.colors.neutral[700]};\n font-size: ${({ theme }) => theme.fontSizes.value[400]};\n font-weight: ${({ theme }) => theme.fontWeights.semibold};\n margin: 12px 0 8px 0;\n line-height: 1.385;\n text-transform: uppercase;\n`;\n\nexport const StyledSeparator = styled('hr', { name: 'DS-AppPicker', slot: 'separator' })`\n border-top: 1px solid ${({ theme }) => theme.colors.neutral[100]};\n border-bottom: none;\n width: 99%;\n margin: 8px 0 0 0;\n`;\n"],
|
|
5
5
|
"mappings": "AAAA,YAAY,WAAW;ACEvB,SAAS,cAAc;AACvB,SAAS,YAAY;AAEd,MAAM,gBAAgB,OAAO,MAAM,EAAE,MAAM,gBAAgB,MAAM,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aASnE,CAAC,EAAE,WAAW,MAAO,aAAa,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAMzD,MAAM,iBAAiB,OAAO;AAAA;AAAA;AAI9B,MAAM,wBAAwB,OAAO;AAAA;AAAA;AAAA;AAKrC,MAAM,cAAc,OAAO,MAAM,EAAE,MAAM,gBAAgB,MAAM,QAAQ,CAAC;AAAA,WACpE,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ;AAAA,eAChC,CAAC,EAAE,MAAM,MAAM,MAAM,UAAU,MAAM;AAAA,iBACnC,CAAC,EAAE,MAAM,MAAM,MAAM,YAAY;AAAA;AAAA;AAAA;AAAA;AAM3C,MAAM,kBAAkB,OAAO,MAAM,EAAE,MAAM,gBAAgB,MAAM,YAAY,CAAC;AAAA,0BAC7D,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/esm/utils.js
CHANGED
|
@@ -11,7 +11,15 @@ const keys = {
|
|
|
11
11
|
HOME: "Home",
|
|
12
12
|
END: "End"
|
|
13
13
|
};
|
|
14
|
+
const focusSelectedOrFirstAvailable = (wrapperRef, allFocusableButtonsRef, selectedButtonRef) => {
|
|
15
|
+
if (selectedButtonRef.current !== null) {
|
|
16
|
+
wrapperRef?.current?.querySelectorAll("button")[selectedButtonRef.current].focus();
|
|
17
|
+
} else {
|
|
18
|
+
allFocusableButtonsRef?.current[0]?.focus();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
14
21
|
export {
|
|
22
|
+
focusSelectedOrFirstAvailable,
|
|
15
23
|
keys
|
|
16
24
|
};
|
|
17
25
|
//# sourceMappingURL=utils.js.map
|
package/dist/esm/utils.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../scripts/build/transpile/react-shim.js", "../../src/utils.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
4
|
+
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import React from 'react';\n\nexport const keys = {\n LEFT: 'ArrowLeft',\n UP: 'ArrowUp',\n RIGHT: 'ArrowRight',\n DOWN: 'ArrowDown',\n ENTER: 'Enter',\n SPACE: '',\n TAB: 'Tab',\n ESC: 'Escape',\n HOME: 'Home',\n END: 'End',\n};\n\nexport const focusSelectedOrFirstAvailable = (\n wrapperRef: React.RefObject<HTMLDivElement>,\n allFocusableButtonsRef: React.MutableRefObject<HTMLButtonElement[]>,\n selectedButtonRef: React.MutableRefObject<number | null>,\n) => {\n if (selectedButtonRef.current !== null) {\n wrapperRef?.current?.querySelectorAll('button')[selectedButtonRef.current].focus();\n } else {\n allFocusableButtonsRef?.current[0]?.focus();\n }\n};\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,WAAW;ACEhB,MAAM,OAAO;AAAA,EAClB,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AACP;AAEO,MAAM,gCAAgC,CAC3C,YACA,wBACA,sBACG;AACH,MAAI,kBAAkB,YAAY,MAAM;AACtC,gBAAY,SAAS,iBAAiB,QAAQ,EAAE,kBAAkB,SAAS,MAAM;AAAA,EACnF,OAAO;AACL,4BAAwB,QAAQ,IAAI,MAAM;AAAA,EAC5C;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-app-picker",
|
|
3
|
-
"version": "3.9.1
|
|
3
|
+
"version": "3.9.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - App Picker",
|
|
6
6
|
"files": [
|
|
@@ -59,13 +59,13 @@
|
|
|
59
59
|
"indent": 4
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@elliemae/ds-button": "3.9.1
|
|
63
|
-
"@elliemae/ds-chip": "3.9.1
|
|
64
|
-
"@elliemae/ds-grid": "3.9.1
|
|
65
|
-
"@elliemae/ds-icons": "3.9.1
|
|
66
|
-
"@elliemae/ds-popover": "3.9.1
|
|
67
|
-
"@elliemae/ds-system": "3.9.1
|
|
68
|
-
"@elliemae/ds-utilities": "3.9.1
|
|
62
|
+
"@elliemae/ds-button": "3.9.1",
|
|
63
|
+
"@elliemae/ds-chip": "3.9.1",
|
|
64
|
+
"@elliemae/ds-grid": "3.9.1",
|
|
65
|
+
"@elliemae/ds-icons": "3.9.1",
|
|
66
|
+
"@elliemae/ds-popover": "3.9.1",
|
|
67
|
+
"@elliemae/ds-system": "3.9.1",
|
|
68
|
+
"@elliemae/ds-utilities": "3.9.1"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@testing-library/jest-dom": "~5.16.4",
|