@fluentui-copilot/react-prompt-listbox 0.0.4 → 0.2.0
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/CHANGELOG.json +95 -1
- package/CHANGELOG.md +30 -1
- package/dist/index.d.ts +18 -63
- package/lib/components/PromptListbox/usePromptListboxStyles.styles.js +9 -6
- package/lib/components/PromptListbox/usePromptListboxStyles.styles.js.map +1 -1
- package/lib/components/PromptOption/usePromptOption.js +0 -5
- package/lib/components/PromptOption/usePromptOption.js.map +1 -1
- package/lib/components/PromptOption/usePromptOptionStyles.styles.js +22 -13
- package/lib/components/PromptOption/usePromptOptionStyles.styles.js.map +1 -1
- package/lib/components/utils/PromptListboxFunctionality.types.js.map +1 -1
- package/lib/components/utils/dropdownKeyActions.js +21 -5
- package/lib/components/utils/dropdownKeyActions.js.map +1 -1
- package/lib/components/utils/{useComboboxPositioning.js → useListboxPositioning.js} +3 -2
- package/lib/components/utils/useListboxPositioning.js.map +1 -0
- package/lib/components/utils/usePromptListboxFunctionality.js +28 -36
- package/lib/components/utils/usePromptListboxFunctionality.js.map +1 -1
- package/lib/components/utils/useTriggerKeyDown.js +31 -11
- package/lib/components/utils/useTriggerKeyDown.js.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/plugins/CursorPositionPlugin.js +43 -0
- package/lib/plugins/CursorPositionPlugin.js.map +1 -0
- package/lib-commonjs/components/PromptListbox/usePromptListboxStyles.styles.js +11 -20
- package/lib-commonjs/components/PromptListbox/usePromptListboxStyles.styles.js.map +1 -1
- package/lib-commonjs/components/PromptOption/usePromptOption.js +0 -3
- package/lib-commonjs/components/PromptOption/usePromptOption.js.map +1 -1
- package/lib-commonjs/components/PromptOption/usePromptOptionStyles.styles.js +33 -54
- package/lib-commonjs/components/PromptOption/usePromptOptionStyles.styles.js.map +1 -1
- package/lib-commonjs/components/utils/PromptListboxFunctionality.types.js.map +1 -1
- package/lib-commonjs/components/utils/dropdownKeyActions.js +19 -5
- package/lib-commonjs/components/utils/dropdownKeyActions.js.map +1 -1
- package/lib-commonjs/components/utils/{useComboboxPositioning.js → useListboxPositioning.js} +5 -4
- package/lib-commonjs/components/utils/useListboxPositioning.js.map +1 -0
- package/lib-commonjs/components/utils/usePromptListboxFunctionality.js +30 -34
- package/lib-commonjs/components/utils/usePromptListboxFunctionality.js.map +1 -1
- package/lib-commonjs/components/utils/useTriggerKeyDown.js +27 -10
- package/lib-commonjs/components/utils/useTriggerKeyDown.js.map +1 -1
- package/lib-commonjs/index.js +0 -4
- package/lib-commonjs/index.js.map +1 -1
- package/lib-commonjs/plugins/CursorPositionPlugin.js +54 -0
- package/lib-commonjs/plugins/CursorPositionPlugin.js.map +1 -0
- package/package.json +17 -18
- package/lib/components/utils/useComboboxPositioning.js.map +0 -1
- package/lib/plugins/TextCursorPositionPlugin.js +0 -44
- package/lib/plugins/TextCursorPositionPlugin.js.map +0 -1
- package/lib-commonjs/components/utils/useComboboxPositioning.js.map +0 -1
- package/lib-commonjs/plugins/TextCursorPositionPlugin.js +0 -52
- package/lib-commonjs/plugins/TextCursorPositionPlugin.js.map +0 -1
|
@@ -25,22 +25,11 @@ const promptOptionClassNames = {
|
|
|
25
25
|
*/ const useStyles = (0, _reactcomponents.__styles)({
|
|
26
26
|
root: {
|
|
27
27
|
Bt984gj: "f122n59",
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"f16jpd5f",
|
|
34
|
-
"f1aa9q02"
|
|
35
|
-
],
|
|
36
|
-
B7oj6ja: [
|
|
37
|
-
"f1jar5jt",
|
|
38
|
-
"fyu767a"
|
|
39
|
-
],
|
|
40
|
-
Btl43ni: [
|
|
41
|
-
"fyu767a",
|
|
42
|
-
"f1jar5jt"
|
|
43
|
-
],
|
|
28
|
+
Beyfa6y: 0,
|
|
29
|
+
Bbmb7ep: 0,
|
|
30
|
+
Btl43ni: 0,
|
|
31
|
+
B7oj6ja: 0,
|
|
32
|
+
Dimara: "ft85np5",
|
|
44
33
|
sj55zd: "f19n0e5",
|
|
45
34
|
i8kkvl: "f1ufnopg",
|
|
46
35
|
Bceei9c: "f1k6fduh",
|
|
@@ -48,16 +37,11 @@ const promptOptionClassNames = {
|
|
|
48
37
|
Bahqtrf: "fk6fouc",
|
|
49
38
|
Be2twd7: "fkhj508",
|
|
50
39
|
Bg96gwp: "f1i3iumi",
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Byoj8tv: "f1tdddsa",
|
|
57
|
-
uwmqm3: [
|
|
58
|
-
"f1f5gg8d",
|
|
59
|
-
"f1vdfbxk"
|
|
60
|
-
],
|
|
40
|
+
Byoj8tv: 0,
|
|
41
|
+
uwmqm3: 0,
|
|
42
|
+
z189sj: 0,
|
|
43
|
+
z8tnut: 0,
|
|
44
|
+
B0ocmuz: "fm5eomj",
|
|
61
45
|
qhf8xq: "f10pi13n",
|
|
62
46
|
Jwef8y: "f1knas48",
|
|
63
47
|
Bi91k9c: "feu1g3u",
|
|
@@ -99,22 +83,11 @@ const promptOptionClassNames = {
|
|
|
99
83
|
"f1dbet5w",
|
|
100
84
|
"fobu5kn"
|
|
101
85
|
],
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
"f1scq65d",
|
|
108
|
-
"ftb4b3e"
|
|
109
|
-
],
|
|
110
|
-
Bqougee: [
|
|
111
|
-
"f2me9eq",
|
|
112
|
-
"fgk4qqi"
|
|
113
|
-
],
|
|
114
|
-
Beitzug: [
|
|
115
|
-
"fgk4qqi",
|
|
116
|
-
"f2me9eq"
|
|
117
|
-
],
|
|
86
|
+
Fffuxt: 0,
|
|
87
|
+
Bttcd12: 0,
|
|
88
|
+
Beitzug: 0,
|
|
89
|
+
Bqougee: 0,
|
|
90
|
+
B86i8pi: "f1kurthe",
|
|
118
91
|
Bhijsxg: "fwq15dy",
|
|
119
92
|
kktds4: "f1pb3wry",
|
|
120
93
|
Bmau3bo: [
|
|
@@ -137,10 +110,12 @@ const promptOptionClassNames = {
|
|
|
137
110
|
}, {
|
|
138
111
|
d: [
|
|
139
112
|
".f122n59{align-items:center;}",
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
113
|
+
[
|
|
114
|
+
".ft85np5{border-radius:var(--borderRadiusMedium);}",
|
|
115
|
+
{
|
|
116
|
+
p: -1
|
|
117
|
+
}
|
|
118
|
+
],
|
|
144
119
|
".f19n0e5{color:var(--colorNeutralForeground1);}",
|
|
145
120
|
".f1ufnopg{column-gap:var(--spacingHorizontalXS);}",
|
|
146
121
|
".f1k6fduh{cursor:pointer;}",
|
|
@@ -148,10 +123,12 @@ const promptOptionClassNames = {
|
|
|
148
123
|
".fk6fouc{font-family:var(--fontFamilyBase);}",
|
|
149
124
|
".fkhj508{font-size:var(--fontSizeBase300);}",
|
|
150
125
|
".f1i3iumi{line-height:var(--lineHeightBase300);}",
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
126
|
+
[
|
|
127
|
+
".fm5eomj{padding:var(--spacingVerticalSNudge) var(--spacingHorizontalS);}",
|
|
128
|
+
{
|
|
129
|
+
p: -1
|
|
130
|
+
}
|
|
131
|
+
],
|
|
155
132
|
".f10pi13n{position:relative;}",
|
|
156
133
|
".f11vrvdw[data-activedescendant-focusvisible]::after{content:\"\";}",
|
|
157
134
|
".f17hxjb7[data-activedescendant-focusvisible]::after{position:absolute;}",
|
|
@@ -169,10 +146,12 @@ const promptOptionClassNames = {
|
|
|
169
146
|
".fobu5kn[data-activedescendant-focusvisible]::after{border-right-color:var(--colorStrokeFocus2);}",
|
|
170
147
|
".f1dbet5w[data-activedescendant-focusvisible]::after{border-left-color:var(--colorStrokeFocus2);}",
|
|
171
148
|
".f1ap9jj5[data-activedescendant-focusvisible]::after{border-bottom-color:var(--colorStrokeFocus2);}",
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
149
|
+
[
|
|
150
|
+
".f1kurthe[data-activedescendant-focusvisible]::after{border-radius:var(--borderRadiusMedium);}",
|
|
151
|
+
{
|
|
152
|
+
p: -1
|
|
153
|
+
}
|
|
154
|
+
],
|
|
176
155
|
".fwq15dy[data-activedescendant-focusvisible]::after{top:-2px;}",
|
|
177
156
|
".f1pb3wry[data-activedescendant-focusvisible]::after{bottom:-2px;}",
|
|
178
157
|
".ftjv2f4[data-activedescendant-focusvisible]::after{left:-2px;}",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["usePromptOptionStyles.styles.ts"],"sourcesContent":["import { makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components';\nimport { ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from '@fluentui/react-aria';\nimport type { PromptOptionSlots, PromptOptionState } from './PromptOption.types';\nimport type { SlotClassNames } from '@fluentui/react-components';\n\nexport const promptOptionClassNames: SlotClassNames<PromptOptionSlots> = {\n root: 'fai-PromptOption',\n};\n\n/**\n * Styles for the root slot\n */\nconst useStyles = makeStyles({\n root: {\n alignItems: 'center',\n
|
|
1
|
+
{"version":3,"sources":["usePromptOptionStyles.styles.ts"],"sourcesContent":["import { makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components';\nimport { ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE } from '@fluentui/react-aria';\nimport type { PromptOptionSlots, PromptOptionState } from './PromptOption.types';\nimport type { SlotClassNames } from '@fluentui/react-components';\n\nexport const promptOptionClassNames: SlotClassNames<PromptOptionSlots> = {\n root: 'fai-PromptOption',\n};\n\n/**\n * Styles for the root slot\n */\nconst useStyles = makeStyles({\n root: {\n alignItems: 'center',\n borderRadius: tokens.borderRadiusMedium,\n color: tokens.colorNeutralForeground1,\n columnGap: tokens.spacingHorizontalXS,\n cursor: 'pointer',\n display: 'flex',\n fontFamily: tokens.fontFamilyBase,\n fontSize: tokens.fontSizeBase300,\n lineHeight: tokens.lineHeightBase300,\n padding: `${tokens.spacingVerticalSNudge} ${tokens.spacingHorizontalS}`,\n position: 'relative',\n\n ':hover': {\n backgroundColor: tokens.colorNeutralBackground1Hover,\n color: tokens.colorNeutralForeground1Hover,\n },\n\n ':active': {\n backgroundColor: tokens.colorNeutralBackground1Pressed,\n color: tokens.colorNeutralForeground1Pressed,\n },\n },\n\n active: {\n [`[${ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE}]::after`]: {\n content: '\"\"',\n position: 'absolute',\n pointerEvents: 'none',\n zIndex: 1,\n\n ...shorthands.border(tokens.strokeWidthThick, `solid`, tokens.colorStrokeFocus2),\n borderRadius: tokens.borderRadiusMedium,\n\n top: '-2px',\n bottom: '-2px',\n left: '-2px',\n right: '-2px',\n },\n },\n\n disabled: {\n color: tokens.colorNeutralForegroundDisabled,\n\n ':hover': {\n backgroundColor: tokens.colorTransparentBackground,\n color: tokens.colorNeutralForegroundDisabled,\n },\n\n ':active': {\n backgroundColor: tokens.colorTransparentBackground,\n color: tokens.colorNeutralForegroundDisabled,\n },\n\n '@media (forced-colors: active)': {\n color: 'GrayText',\n },\n },\n});\n\n/**\n * Apply styling to the PromptOption slots based on the state\n */\nexport const usePromptOptionStyles_unstable = (state: PromptOptionState): PromptOptionState => {\n 'use no memo';\n\n const { disabled } = state;\n const styles = useStyles();\n state.root.className = mergeClasses(\n promptOptionClassNames.root,\n styles.root,\n styles.active,\n disabled && styles.disabled,\n state.root.className,\n );\n\n return state;\n};\n"],"names":["promptOptionClassNames","root","__styles","alignItems","borderRadius","color","columnGap","cursor","display","fontFamily","fontSize","lineHeight","padding","position","backgroundColor","qhf8xq","active","ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE","content","top","bottom","left","right","f0sref","disabled","colorNeutralForegroundDisabled","tokens","colorTransparentBackground","Bhijsxg","kktds4","Bmau3bo","sj55zd","Jwef8y","styles","state","ecr2s2","lj723h"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;;;;;;;;IAKaA,sBAAAA;eAAAA;;;;;;iCALwC;AAK9C,MAAMA,yBAA4D;UACvEC;AACF;AAEA;;CAEC,SAECA,YAAMC,IAAAA,yBAAA,EAAA;UACJC;iBACAC;iBACAC;iBACAC;iBACAC;iBACAC;gBACAC;gBACAC;gBACAC;iBACAC;gBACAC;iBAEA;iBACEC;iBACAT;iBACF;gBAEA;gBACES;gBACAT;iBACF;QACFU,QAAA;QAEAC,QAAQ;iBACDC;gBACHC;gBACAL;;;iBAIA;gBACAT;gBAEAe;gBACAC;iBACAC;iBACAC;YAAAA;YAAO;SAAA;iBACT;QACFC,QAAA;YAAA;YAAA;SAAA;QAEAC,SAAAA;iBACEnB;YAAAA;YAAcoB;SAAAA;gBAEd;gBACEX;YAAAA;YAAAA;SAAiBY;iBACjBrB;iBACF;YAAA;YAAA;SAAA;iBAEA;iBACES;YAAAA;YAAAA;SAAwBa;gBACxBtB;iBACF;iBAEA;iBACEA;iBACF;QACFuB,SAAA;QACFC,QAAA;QAEAC,SAAA;YAAA;YAAA;SAAA;;;;;IAEC;cAEC;QAEAC,QAAQP;QACRQ,QAAMC;QACNC,SAAMjC;QAQNkC,QAAOD;QACPE,QAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["PromptListboxFunctionality.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { PromptListboxProps } from '../../components/PromptListbox';\nimport type { PositioningShorthand } from '@fluentui/react-components';\nimport type { EventData, EventHandler } from '@fluentui/react-utilities';\nimport type { EditorInputProps } from '@fluentui-copilot/react-editor-input';\n\n// Note: While we are removing multiselect, we are keeping the logic and disabling it\n// in case it's needed in the future.\nexport type ProcessedPromptListboxProps = Partial<\n Omit<PromptListboxProps, 'activeDescendantController' | 'multiselect'>\n> & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ref?: React.MutableRefObject<any>;\n};\n\nexport type UsePromptListboxFunctionality = {\n /**\n * Component to be rendered in the Input component. This should be passed to the listbox prop.\n */\n promptListbox: JSX.Element;\n /**\n * Props to be spread in the PromptInput, these props are needed for the keyboard behavior to\n * work correctly.\n */\n triggerProps: {\n ref: React.RefObject<HTMLSpanElement>;\n /**\n * Whether the listbox is being used to go through options or the user is currently typing.\n */\n isInSelectionMode: boolean;\n } & Required<Pick<EditorInputProps, 'onBlur' | 'onFocus' | 'onKeyDown'>>;\n /**\n * Ref used to point which element the listbox should be anchored to. Most use cases\n * will provide this prop to the PromptInput's EditorInput (since this is the root slot,\n * this is provided directly to the component and not the slot).\n *\n * Note: If the containerRef is the same as the trigger, the ref provided in triggerProps needs\n * to be merged with this one using `useMergedRefs(containerRef, triggerProps.ref);`\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n containerRef: React.MutableRefObject<any>;\n /**\n * Plugin used to tell where the cursor is in the EditorInput, this is important for the\n * keyboard behavior. This should be passed as children in the PromptInput.\n */\n cursorPositionPlugin: JSX.Element;\n};\n\nexport type UsePromptListboxFunctionalityParams = {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: EventHandler<OnOpenChangeData>;\n positioning?: PositioningShorthand;\n\n /**\n * Callback to call when the selection mode (selecting an action vs typing) changes.\n */\n onSelectionModeChange?: (isInSelectionMode: boolean) => void;\n\n /**\n * Props to be passed to the ListboxComponent\n */\n listboxProps?: ProcessedPromptListboxProps;\n\n /**\n * Whether the listbox's width should take all the available space or only\n * the required space.\n *\n * @default false\n */\n fluid?: boolean;\n};\n\nexport type OnOpenChangeData = (\n | EventData<'click', React.MouseEvent<HTMLSpanElement>>\n | EventData<'focus', React.FocusEvent<HTMLSpanElement>>\n | EventData<'keyboard', React.KeyboardEvent<HTMLSpanElement>>\n) & {\n open: boolean;\n};\n"],"names":[],"rangeMappings":"","mappings":""}
|
|
1
|
+
{"version":3,"sources":["PromptListboxFunctionality.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { PromptListboxProps } from '../../components/PromptListbox';\nimport type { PositioningShorthand } from '@fluentui/react-components';\nimport type { EventData, EventHandler } from '@fluentui/react-utilities';\nimport type { EditorInputProps } from '@fluentui-copilot/react-editor-input';\n\n// Note: While we are removing multiselect, we are keeping the logic and disabling it\n// in case it's needed in the future.\nexport type ProcessedPromptListboxProps = Partial<\n Omit<PromptListboxProps, 'activeDescendantController' | 'multiselect'>\n> & {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ref?: React.MutableRefObject<any>;\n};\n\nexport type UsePromptListboxFunctionality = {\n /**\n * Component to be rendered in the Input component. This should be passed to the listbox prop.\n */\n promptListbox: JSX.Element;\n /**\n * Props to be spread in the PromptInput, these props are needed for the keyboard behavior to\n * work correctly.\n */\n triggerProps: {\n ref: React.RefObject<HTMLSpanElement>;\n /**\n * Whether the listbox is being used to go through options or the user is currently typing.\n */\n isInSelectionMode: boolean;\n } & Required<Pick<EditorInputProps, 'onBlur' | 'onFocus' | 'onKeyDown'>>;\n /**\n * Ref used to point which element the listbox should be anchored to. Most use cases\n * will provide this prop to the PromptInput's EditorInput (since this is the root slot,\n * this is provided directly to the component and not the slot).\n *\n * Note: If the containerRef is the same as the trigger, the ref provided in triggerProps needs\n * to be merged with this one using `useMergedRefs(containerRef, triggerProps.ref);`\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n containerRef: React.MutableRefObject<any>;\n /**\n * Plugin used to tell where the cursor is in the EditorInput, this is important for the\n * keyboard behavior. This should be passed as children in the PromptInput.\n */\n cursorPositionPlugin: JSX.Element;\n};\n\nexport type UsePromptListboxFunctionalityParams = {\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: EventHandler<OnOpenChangeData>;\n positioning?: PositioningShorthand;\n\n /**\n * Callback to call when the selection mode (selecting an action vs typing) changes.\n */\n onSelectionModeChange?: (isInSelectionMode: boolean) => void;\n\n /**\n * Props to be passed to the ListboxComponent\n */\n listboxProps?: ProcessedPromptListboxProps;\n\n /**\n * Whether the listbox's width should take all the available space or only\n * the required space.\n *\n * @default false\n */\n fluid?: boolean;\n\n /**\n * Whether to allow reaching the listbox options by arrowing up at the start of the input.\n * Note, this prop is meant to be used with the following positioning props:\n * ```ts\n * usePromptListboxFunctionality({\n * positioning: {\n * position: 'above',\n * fallbackPositions: ['above']\n * }\n * });\n * ```\n * This is useful when using PromptListbox with other components such as ChatInput since\n * the input will always stay at the bottom therefore the listbox would always get cut.\n *\n * @default false\n */\n allowArrowUpNavigation?: boolean;\n};\n\nexport type OnOpenChangeData = (\n | EventData<'click', React.MouseEvent<HTMLSpanElement>>\n | EventData<'focus', React.FocusEvent<HTMLSpanElement>>\n | EventData<'keyboard', React.KeyboardEvent<HTMLSpanElement>>\n) & {\n open: boolean;\n};\n"],"names":[],"rangeMappings":"","mappings":""}
|
|
@@ -14,7 +14,7 @@ Object.defineProperty(exports, "getDropdownActionFromKey", {
|
|
|
14
14
|
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
|
|
15
15
|
const _keyboardkeys = /*#__PURE__*/ _interop_require_wildcard._(require("@fluentui/keyboard-keys"));
|
|
16
16
|
function getDropdownActionFromKey(e, options) {
|
|
17
|
-
const {
|
|
17
|
+
const { cursorPosition, allowArrowUpNavigation, isInSelectionMode } = options;
|
|
18
18
|
const code = e.key;
|
|
19
19
|
const { altKey, ctrlKey, key, metaKey } = e;
|
|
20
20
|
// typing action occurs whether open or closed
|
|
@@ -26,17 +26,31 @@ function getDropdownActionFromKey(e, options) {
|
|
|
26
26
|
return 'CloseSelect';
|
|
27
27
|
}
|
|
28
28
|
// navigation interactions
|
|
29
|
+
const atStart = allowArrowUpNavigation && (cursorPosition === 'start' || cursorPosition === 'start-end');
|
|
30
|
+
const atEnd = cursorPosition === 'end' || cursorPosition === 'start-end';
|
|
29
31
|
if (code === _keyboardkeys.ArrowDown) {
|
|
30
|
-
|
|
32
|
+
if (atEnd) {
|
|
33
|
+
return 'Next';
|
|
34
|
+
} else if (atStart && isInSelectionMode) {
|
|
35
|
+
return 'Next';
|
|
36
|
+
}
|
|
37
|
+
return 'Type';
|
|
31
38
|
}
|
|
32
39
|
if (code === _keyboardkeys.ArrowUp) {
|
|
33
|
-
|
|
40
|
+
if (atEnd && isInSelectionMode) {
|
|
41
|
+
return 'Previous';
|
|
42
|
+
} else if (atStart && !isInSelectionMode) {
|
|
43
|
+
return 'Next';
|
|
44
|
+
} else if (atStart && isInSelectionMode) {
|
|
45
|
+
return 'Previous';
|
|
46
|
+
}
|
|
47
|
+
return 'Type';
|
|
34
48
|
}
|
|
35
49
|
if (code === _keyboardkeys.Home) {
|
|
36
|
-
return 'First';
|
|
50
|
+
return atEnd || atStart ? 'First' : 'Type';
|
|
37
51
|
}
|
|
38
52
|
if (code === _keyboardkeys.End) {
|
|
39
|
-
return 'Last';
|
|
53
|
+
return atEnd || atStart ? 'Last' : 'Type';
|
|
40
54
|
}
|
|
41
55
|
if (code === _keyboardkeys.PageUp) {
|
|
42
56
|
return 'PageUp';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["dropdownKeyActions.ts"],"sourcesContent":["/**\n * Note, this is mainly brought from Fluent UI, only removed the closing and\n * opening logic since that's not needed for this use case.\n */\n\nimport * as keys from '@fluentui/keyboard-keys';\nimport type * as React from 'react';\n\n/**\n * enum of actions available in any type of managed dropdown control\n * e.g. combobox, select, datepicker, menu\n */\nexport type DropdownActions =\n | 'CloseSelect'\n | 'First'\n | 'Last'\n | 'Next'\n | 'None'\n | 'PageDown'\n | 'PageUp'\n | 'Previous'\n | 'Select'\n | 'Tab'\n | 'Type';\n\nexport interface DropdownActionOptions {\n open?: boolean;\n multiselect?: boolean;\n
|
|
1
|
+
{"version":3,"sources":["dropdownKeyActions.ts"],"sourcesContent":["/**\n * Note, this is mainly brought from Fluent UI, only removed the closing and\n * opening logic since that's not needed for this use case.\n */\n\nimport * as keys from '@fluentui/keyboard-keys';\nimport type * as React from 'react';\nimport type { CursorPosition } from '../../plugins/CursorPositionPlugin';\n\n/**\n * enum of actions available in any type of managed dropdown control\n * e.g. combobox, select, datepicker, menu\n */\nexport type DropdownActions =\n | 'CloseSelect'\n | 'First'\n | 'Last'\n | 'Next'\n | 'None'\n | 'PageDown'\n | 'PageUp'\n | 'Previous'\n | 'Select'\n | 'Tab'\n | 'Type';\n\nexport interface DropdownActionOptions {\n open?: boolean;\n multiselect?: boolean;\n cursorPosition: CursorPosition;\n allowArrowUpNavigation: boolean;\n isInSelectionMode: boolean;\n}\n\n/**\n * Converts a keyboard interaction into a defined action\n */\nexport function getDropdownActionFromKey(\n e: KeyboardEvent | React.KeyboardEvent,\n options: DropdownActionOptions,\n): DropdownActions {\n const { cursorPosition, allowArrowUpNavigation, isInSelectionMode } = options;\n const code = e.key;\n const { altKey, ctrlKey, key, metaKey } = e;\n\n // typing action occurs whether open or closed\n if (key.length === 1 && code !== keys.Space && !altKey && !ctrlKey && !metaKey) {\n return 'Type';\n }\n\n // select or close actions\n if ((code === keys.ArrowUp && altKey) || code === keys.Enter) {\n return 'CloseSelect';\n }\n\n // navigation interactions\n const atStart = allowArrowUpNavigation && (cursorPosition === 'start' || cursorPosition === 'start-end');\n const atEnd = cursorPosition === 'end' || cursorPosition === 'start-end';\n if (code === keys.ArrowDown) {\n if (atEnd) {\n return 'Next';\n } else if (atStart && isInSelectionMode) {\n return 'Next';\n }\n return 'Type';\n }\n if (code === keys.ArrowUp) {\n if (atEnd && isInSelectionMode) {\n return 'Previous';\n } else if (atStart && !isInSelectionMode) {\n return 'Next';\n } else if (atStart && isInSelectionMode) {\n return 'Previous';\n }\n return 'Type';\n }\n if (code === keys.Home) {\n return atEnd || atStart ? 'First' : 'Type';\n }\n if (code === keys.End) {\n return atEnd || atStart ? 'Last' : 'Type';\n }\n if (code === keys.PageUp) {\n return 'PageUp';\n }\n if (code === keys.PageDown) {\n return 'PageDown';\n }\n if (code === keys.Tab) {\n return 'Tab';\n }\n\n // if nothing matched, return none\n return 'None';\n}\n"],"names":["cursorPosition","keys","allowArrowUpNavigation","isInSelectionMode","code","e","key","altKey","metaKey","ArrowDown","Space","ctrlKey","atStart","ArrowUp","Enter","atEnd","Home","End","PageUp"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;CAGC;;;;+BAsCSA;;;eAAAA;;;;wEApCEC;AAoCV,SAAQD,yBAAgBE,CAAAA,EAAAA,OAAsB;UAC9C,EACAF,cAAc,EAEdE,sBAAA,EACAC,iBAAc;UAEdC,OAAAC,EAAAC,GAAA;UAEA,EACAC,MAAKH,SACH,EACFE,GAAA,EAEAE,OAAA,KACAH;kDAC0CL;QAC1CM,IAAIF,MAAAA,KAASH,KAAKQ,SAAWR,cAAAS,KAAA,IAAA,CAAAH,UAAA,CAAAI,WAAA,CAAAH,SAAA;eAC3B;;8BAEWI;iBACTX,cAAOY,OAAA,IAAAN,UAAAH,SAAAH,cAAAa,KAAA,EAAA;eACT;;8BAEF;UACIV,UAASH,0BAAcD,CAAAA,mBAAA,WAAAA,mBAAA,WAAA;UACzBe,QAAIA,mBAASZ,SAAmBH,mBAAA;iBAC9BC,cAAOQ,SAAA,EAAA;YACTM,OAAO;mBACL;eACF,IAAOH,WAAIA,mBAAWT;mBACpB;;eAEF;;QAEFC,SAAIA,cAASH,OAAS,EAAE;YACtBc,SAAOA,mBAAmB;YAC5B,OAAA;QACA,OAAIX,IAAAA,WAAiB,CAAED,mBAAA;mBACrB;QACF,OAAA,IAAAS,WAAAT,mBAAA;YACA,OAAIC;;QAEJ,OAAA;;iBAESH,cAAAe,IAAA,EAAA;QACT,OAAAD,SAAAH,UAAA,UAAA;;iBAESX,cAAAgB,GAAA,EAAA;QACT,OAAAF,SAAAH,UAAA,SAAA;;QAGAR,SAAOH,cAAAiB,MAAA,EAAA;QACT,OAAA"}
|
package/lib-commonjs/components/utils/{useComboboxPositioning.js → useListboxPositioning.js}
RENAMED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
Object.defineProperty(exports, "
|
|
6
|
+
Object.defineProperty(exports, "useListboxPositioning", {
|
|
7
7
|
enumerable: true,
|
|
8
8
|
get: function() {
|
|
9
|
-
return
|
|
9
|
+
return useListboxPositioning;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
const _reactpositioning = require("@fluentui/react-positioning");
|
|
13
|
-
function
|
|
13
|
+
function useListboxPositioning(props) {
|
|
14
14
|
const { positioning, fluid } = props;
|
|
15
15
|
const fallbackPositions = [
|
|
16
16
|
'below'
|
|
@@ -25,6 +25,7 @@ function useComboboxPositioning(props) {
|
|
|
25
25
|
},
|
|
26
26
|
fallbackPositions: fallbackPositions,
|
|
27
27
|
matchTargetSize: fluid ? 'width' : undefined,
|
|
28
|
+
autoSize: true,
|
|
28
29
|
...(0, _reactpositioning.resolvePositioningShorthand)(positioning)
|
|
29
30
|
};
|
|
30
31
|
const { targetRef, containerRef } = (0, _reactpositioning.usePositioning)(popperOptions);
|
|
@@ -32,4 +33,4 @@ function useComboboxPositioning(props) {
|
|
|
32
33
|
containerRef,
|
|
33
34
|
targetRef
|
|
34
35
|
];
|
|
35
|
-
} //# sourceMappingURL=
|
|
36
|
+
} //# sourceMappingURL=useListboxPositioning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["useListboxPositioning.ts"],"sourcesContent":["// Brought from Fluent UI\n\nimport { resolvePositioningShorthand, usePositioning } from '@fluentui/react-positioning';\nimport type * as React from 'react';\nimport type { ComboboxBaseProps } from '@fluentui/react-combobox';\nimport type { UsePromptListboxFunctionalityParams } from './PromptListboxFunctionality.types';\nimport type { PositioningShorthandValue } from '@fluentui/react-positioning';\n\nexport function useListboxPositioning(\n props: ComboboxBaseProps & Required<Pick<UsePromptListboxFunctionalityParams, 'fluid'>>,\n): [\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n listboxRef: React.MutableRefObject<any>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n triggerRef: React.MutableRefObject<any>,\n] {\n const { positioning, fluid } = props;\n\n const fallbackPositions: PositioningShorthandValue[] = ['below'];\n\n // popper options\n const popperOptions = {\n position: 'below' as const,\n align: 'start' as const,\n offset: { crossAxis: 0, mainAxis: 2 },\n fallbackPositions: fallbackPositions,\n matchTargetSize: fluid ? ('width' as const) : undefined,\n autoSize: true,\n ...resolvePositioningShorthand(positioning),\n };\n\n const { targetRef, containerRef } = usePositioning(popperOptions);\n\n return [containerRef, targetRef];\n}\n"],"names":["useListboxPositioning","props","positioning","fallbackPositions","popperOptions","position","align","offset","crossAxis","mainAxis","matchTargetSize","fluid","undefined","resolvePositioningShorthand","containerRef","targetRef","usePositioning"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,yBAAyB;;;;;+BAQTA;;;eAAAA;;;kCAN4C;AAMrD,SAASA,sBACdC,KAAuF;UAOvF,EAEAC,WAAMC,OAAkD,KAAQF;UAEhEE,oBAAiB;QAAA;KAAA;qBACXC;UACJC,gBAAU;kBACVC;eACAC;gBAAUC;uBAAcC;sBAAY;;2BAEpCC;yBACUC,QAAA,UAAAC;kBACPC;QACL,GAAAA,IAAAA,6CAAA,EAAAX,YAAA;;UAIA,WAAQY,cAAcC,KAAUC,IAAAA,gCAAA,EAAAZ;IAClC,OAAA;QAAAU;QAAAC;KAAA"}
|
|
@@ -12,17 +12,15 @@ const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildc
|
|
|
12
12
|
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
13
13
|
const _reactaria = require("@fluentui/react-aria");
|
|
14
14
|
const _reactutilities = require("@fluentui/react-utilities");
|
|
15
|
-
const
|
|
16
|
-
const _TextCursorPositionPlugin = require("../../plugins/TextCursorPositionPlugin");
|
|
15
|
+
const _CursorPositionPlugin = require("../../plugins/CursorPositionPlugin");
|
|
17
16
|
const _useOptionCollection = require("./useOptionCollection");
|
|
18
17
|
const _useSelection = require("./useSelection");
|
|
19
|
-
const
|
|
20
|
-
const _useComboboxPositioning = require("./useComboboxPositioning");
|
|
18
|
+
const _useListboxPositioning = require("./useListboxPositioning");
|
|
21
19
|
const _useTriggerKeyDown = require("./useTriggerKeyDown");
|
|
22
20
|
const _PromptListbox = require("../PromptListbox");
|
|
23
21
|
const _PromptOption = require("../PromptOption");
|
|
24
22
|
function usePromptListboxFunctionality(params) {
|
|
25
|
-
const { positioning, onOpenChange, onSelectionModeChange, listboxProps, fluid = false } = params;
|
|
23
|
+
const { positioning, onOpenChange, onSelectionModeChange, listboxProps, fluid = false, allowArrowUpNavigation = false } = params;
|
|
26
24
|
const { listboxRef: activeDescendantListboxRef, activeParentRef, controller: activeDescendantController } = (0, _reactaria.useActiveDescendant)({
|
|
27
25
|
matchOption: (el)=>el.classList.contains(_PromptOption.promptOptionClassNames.root)
|
|
28
26
|
});
|
|
@@ -32,13 +30,26 @@ function usePromptListboxFunctionality(params) {
|
|
|
32
30
|
const { selectOption } = selectionState;
|
|
33
31
|
const optionCollection = (0, _useOptionCollection.useOptionCollection)();
|
|
34
32
|
const { getOptionById } = optionCollection;
|
|
35
|
-
const [
|
|
33
|
+
const [cursorPosition, setCursorPosition] = _react.useState('end');
|
|
36
34
|
const [isInSelectionMode, setIsInSelectionMode] = _react.useState(false);
|
|
37
35
|
const [open, setOpen] = (0, _reactutilities.useControllableState)({
|
|
38
36
|
state: params.open,
|
|
39
37
|
defaultState: params.defaultOpen,
|
|
40
38
|
initialState: false
|
|
41
39
|
});
|
|
40
|
+
const setSelectionMode = _react.useCallback((selectionMode)=>{
|
|
41
|
+
if (selectionMode === false) {
|
|
42
|
+
activeDescendantController.blur();
|
|
43
|
+
setHideActiveDescendant(true);
|
|
44
|
+
} else {
|
|
45
|
+
setHideActiveDescendant(false);
|
|
46
|
+
}
|
|
47
|
+
setIsInSelectionMode(selectionMode);
|
|
48
|
+
onSelectionModeChange === null || onSelectionModeChange === void 0 ? void 0 : onSelectionModeChange(selectionMode);
|
|
49
|
+
}, [
|
|
50
|
+
activeDescendantController,
|
|
51
|
+
onSelectionModeChange
|
|
52
|
+
]);
|
|
42
53
|
const onBlur = (event)=>{
|
|
43
54
|
setOpen(false);
|
|
44
55
|
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(event, {
|
|
@@ -46,6 +57,7 @@ function usePromptListboxFunctionality(params) {
|
|
|
46
57
|
type: 'focus',
|
|
47
58
|
open: false
|
|
48
59
|
});
|
|
60
|
+
setSelectionMode(false);
|
|
49
61
|
};
|
|
50
62
|
const onFocus = (event)=>{
|
|
51
63
|
if (event.target === event.currentTarget) {
|
|
@@ -57,50 +69,34 @@ function usePromptListboxFunctionality(params) {
|
|
|
57
69
|
});
|
|
58
70
|
}
|
|
59
71
|
};
|
|
60
|
-
const cursorPositionPlugin = /*#__PURE__*/ _react.createElement(
|
|
61
|
-
|
|
72
|
+
const cursorPositionPlugin = /*#__PURE__*/ _react.createElement(_CursorPositionPlugin.CursorPositionPlugin, {
|
|
73
|
+
setCursorPosition: setCursorPosition
|
|
62
74
|
});
|
|
63
75
|
const onListboxBlur = _react.useCallback(()=>{
|
|
64
|
-
|
|
76
|
+
setSelectionMode(false);
|
|
65
77
|
onSelectionModeChange === null || onSelectionModeChange === void 0 ? void 0 : onSelectionModeChange(false);
|
|
66
78
|
}, [
|
|
67
|
-
onSelectionModeChange
|
|
79
|
+
onSelectionModeChange,
|
|
80
|
+
setSelectionMode
|
|
68
81
|
]);
|
|
69
82
|
// handle combobox keyboard interaction
|
|
70
83
|
const onKeyDown = (0, _useTriggerKeyDown.useTriggerKeydown)({
|
|
71
84
|
...optionCollection,
|
|
85
|
+
allowArrowUpNavigation,
|
|
72
86
|
activeDescendantController,
|
|
73
87
|
getOptionById,
|
|
74
88
|
onBlur: onListboxBlur,
|
|
75
89
|
selectOption,
|
|
76
|
-
|
|
90
|
+
cursorPosition,
|
|
77
91
|
open,
|
|
78
|
-
multiselect: false
|
|
92
|
+
multiselect: false,
|
|
93
|
+
isInSelectionMode,
|
|
94
|
+
setSelectionMode
|
|
79
95
|
});
|
|
80
96
|
// NVDA and JAWS have bugs that suppress reading the input value text when aria-activedescendant is set
|
|
81
97
|
// To prevent this, we clear the HTML attribute (but save the state) when a user presses left/right arrows
|
|
82
98
|
// ref: https://github.com/microsoft/fluentui/issues/26359#issuecomment-1397759888
|
|
83
99
|
const [hideActiveDescendant, setHideActiveDescendant] = _react.useState(false);
|
|
84
|
-
/**
|
|
85
|
-
* Freeform combobox should not select
|
|
86
|
-
*/ const onInputTriggerKeyDown = (0, _reactutilities.useEventCallback)((event)=>{
|
|
87
|
-
// update typing state to true if the user is typing
|
|
88
|
-
const action = (0, _dropdownKeyActions.getDropdownActionFromKey)(event, {
|
|
89
|
-
open,
|
|
90
|
-
multiselect: false,
|
|
91
|
-
isInLastPosition
|
|
92
|
-
});
|
|
93
|
-
if (event.key === _keyboardkeys.ArrowLeft || event.key === _keyboardkeys.ArrowRight || !isInLastPosition && (event.key === _keyboardkeys.ArrowDown || event.key === _keyboardkeys.ArrowUp) || action === 'Type' && isInLastPosition || action === 'Type') {
|
|
94
|
-
activeDescendantController.blur();
|
|
95
|
-
setHideActiveDescendant(true);
|
|
96
|
-
setIsInSelectionMode(false);
|
|
97
|
-
onSelectionModeChange === null || onSelectionModeChange === void 0 ? void 0 : onSelectionModeChange(false);
|
|
98
|
-
} else if (action === 'Next' || action === 'Previous' || action === 'First' || action === 'Last' || action === 'PageUp' || action === 'PageDown') {
|
|
99
|
-
setHideActiveDescendant(false);
|
|
100
|
-
setIsInSelectionMode(true);
|
|
101
|
-
onSelectionModeChange === null || onSelectionModeChange === void 0 ? void 0 : onSelectionModeChange(true);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
100
|
_react.useEffect(()=>{
|
|
105
101
|
if (hideActiveDescendant) {
|
|
106
102
|
var _triggerRef_current;
|
|
@@ -114,7 +110,7 @@ function usePromptListboxFunctionality(params) {
|
|
|
114
110
|
}, [
|
|
115
111
|
hideActiveDescendant
|
|
116
112
|
]);
|
|
117
|
-
const [comboboxPopupRef, comboboxTargetRef] = (0,
|
|
113
|
+
const [comboboxPopupRef, comboboxTargetRef] = (0, _useListboxPositioning.useListboxPositioning)({
|
|
118
114
|
positioning,
|
|
119
115
|
fluid
|
|
120
116
|
});
|
|
@@ -142,7 +138,7 @@ function usePromptListboxFunctionality(params) {
|
|
|
142
138
|
ref: triggerRef,
|
|
143
139
|
onBlur,
|
|
144
140
|
onFocus,
|
|
145
|
-
onKeyDown
|
|
141
|
+
onKeyDown,
|
|
146
142
|
isInSelectionMode
|
|
147
143
|
},
|
|
148
144
|
containerRef: comboboxTargetRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["usePromptListboxFunctionality.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useActiveDescendant } from '@fluentui/react-aria';\nimport {
|
|
1
|
+
{"version":3,"sources":["usePromptListboxFunctionality.tsx"],"sourcesContent":["import * as React from 'react';\nimport { useActiveDescendant } from '@fluentui/react-aria';\nimport { useControllableState, useMergedRefs } from '@fluentui/react-utilities';\nimport { CursorPositionPlugin } from '../../plugins/CursorPositionPlugin';\nimport { useOptionCollection } from './useOptionCollection';\nimport { useSelection } from './useSelection';\nimport { useListboxPositioning } from './useListboxPositioning';\nimport { useTriggerKeydown } from './useTriggerKeyDown';\nimport { PromptListbox } from '../PromptListbox';\nimport { promptOptionClassNames } from '../PromptOption';\nimport type { CursorPosition } from '../../plugins/CursorPositionPlugin';\nimport type {\n UsePromptListboxFunctionalityParams,\n UsePromptListboxFunctionality,\n} from './PromptListboxFunctionality.types';\n\nexport function usePromptListboxFunctionality(\n params: UsePromptListboxFunctionalityParams,\n): UsePromptListboxFunctionality {\n const {\n positioning,\n onOpenChange,\n onSelectionModeChange,\n listboxProps,\n fluid = false,\n allowArrowUpNavigation = false,\n } = params;\n const {\n listboxRef: activeDescendantListboxRef,\n activeParentRef,\n controller: activeDescendantController,\n } = useActiveDescendant<HTMLSpanElement, HTMLDivElement>({\n matchOption: el => el.classList.contains(promptOptionClassNames.root),\n });\n // useMergedRefs to normalize the ref into a React.RefObject type\n const triggerRef = useMergedRefs(activeParentRef);\n const selectionState = useSelection(listboxProps ?? {});\n const { selectOption } = selectionState;\n const optionCollection = useOptionCollection();\n const { getOptionById } = optionCollection;\n const [cursorPosition, setCursorPosition] = React.useState<CursorPosition>('end');\n const [isInSelectionMode, setIsInSelectionMode] = React.useState(false);\n const [open, setOpen] = useControllableState({\n state: params.open,\n defaultState: params.defaultOpen,\n initialState: false,\n });\n\n const setSelectionMode = React.useCallback(\n (selectionMode: boolean) => {\n if (selectionMode === false) {\n activeDescendantController.blur();\n setHideActiveDescendant(true);\n } else {\n setHideActiveDescendant(false);\n }\n\n setIsInSelectionMode(selectionMode);\n onSelectionModeChange?.(selectionMode);\n },\n [activeDescendantController, onSelectionModeChange],\n );\n\n const onBlur = (event: React.FocusEvent<HTMLSpanElement>) => {\n setOpen(false);\n onOpenChange?.(event, { event, type: 'focus', open: false });\n setSelectionMode(false);\n };\n\n const onFocus = (event: React.FocusEvent<HTMLSpanElement>) => {\n if (event.target === event.currentTarget) {\n setOpen(true);\n onOpenChange?.(event, { event, type: 'focus', open: true });\n }\n };\n\n const cursorPositionPlugin = <CursorPositionPlugin setCursorPosition={setCursorPosition} />;\n\n const onListboxBlur = React.useCallback(() => {\n setSelectionMode(false);\n onSelectionModeChange?.(false);\n }, [onSelectionModeChange, setSelectionMode]);\n\n // handle combobox keyboard interaction\n const onKeyDown = useTriggerKeydown({\n ...optionCollection,\n allowArrowUpNavigation,\n activeDescendantController,\n getOptionById,\n onBlur: onListboxBlur,\n selectOption,\n cursorPosition,\n open,\n multiselect: false,\n isInSelectionMode,\n setSelectionMode,\n });\n\n // NVDA and JAWS have bugs that suppress reading the input value text when aria-activedescendant is set\n // To prevent this, we clear the HTML attribute (but save the state) when a user presses left/right arrows\n // ref: https://github.com/microsoft/fluentui/issues/26359#issuecomment-1397759888\n const [hideActiveDescendant, setHideActiveDescendant] = React.useState(false);\n\n React.useEffect(() => {\n if (hideActiveDescendant) {\n triggerRef.current?.removeAttribute('aria-activedescendant');\n }\n // We only want to run this when the hideActiveDescendant changes, if the triggerRef\n // is undefined, there's no need to remove theAttribute and we shouldn't be adding\n // refs as dependencies since it can blow up the number of runs.\n // eslint-disable-next-line react-compiler/react-compiler\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hideActiveDescendant]);\n\n const [comboboxPopupRef, comboboxTargetRef] = useListboxPositioning({ positioning, fluid });\n\n const listboxMergedRef = useMergedRefs(comboboxPopupRef, activeDescendantListboxRef, listboxProps?.ref);\n const listbox = React.useMemo(() => {\n return (\n <PromptListbox\n open={open}\n {...listboxProps}\n {...optionCollection}\n {...selectionState}\n ref={listboxMergedRef}\n activeDescendantController={activeDescendantController}\n />\n );\n }, [activeDescendantController, listboxMergedRef, listboxProps, open, optionCollection, selectionState]);\n\n return {\n promptListbox: listbox,\n triggerProps: {\n ref: triggerRef,\n onBlur,\n onFocus,\n onKeyDown,\n isInSelectionMode,\n },\n containerRef: comboboxTargetRef,\n cursorPositionPlugin,\n };\n}\n"],"names":["usePromptListboxFunctionality","params","positioning","listboxRef","matchOption","onSelectionModeChange","listboxProps","fluid","triggerRef","allowArrowUpNavigation","useSelection","getOptionById","optionCollection","activeParentRef","cursorPosition","controller","isInSelectionMode","setIsInSelectionMode","useActiveDescendant","open","classList","contains","promptOptionClassNames","root","useMergedRefs","selectionState","setSelectionMode","useCallback","selectionMode","activeDescendantController","useOptionCollection","React","useState","defaultOpen","initialState","onBlur","onOpenChange","event","blur","currentTarget","type","cursorPositionPlugin","onListboxBlur","createElement","CursorPositionPlugin","selectOption","multiselect","hideActiveDescendant","setHideActiveDescendant","useEffect","_triggerRef_current","current","removeAttribute","activeDescendantListboxRef","listboxMergedRef","promptListbox","triggerProps","containerRef"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAgBgBA;;;eAAAA;;;;iEAhBO;2BACa;gCACgB;sCACf;qCACD;8BACP;uCACS;mCACJ;+BACJ;8BACS;AAOhC,SAASA,8BACdC,MAA2C;UAE3C,EAQAC,WACEC,cAIAC,EACFC,qBAAA,EACAC,YAAA,EACAC,QAAMC,KAAAA,EACNC,yBAAuBC,KAAAA,KACvBT;UACA,EACAE,YAAQQ,0BAAkBC,EAC1BC,eAAOC,EACPC,YAAOC,0BAAmBC,KAC1BC,IAAAA,8BAAqB,EAAA;qBACZjB,CAAAA,KAAOkB,GAAIC,SAAA,CAAAC,QAAA,CAAAC,oCAAA,CAAAC,IAAA;;qEAEJ;UAChBf,aAAAgB,IAAAA,6BAAA,EAAAX;UAEAY,iBAAMC,IAAAA,0BAAyBC,EAAAA,iBAC5BC,QAAAA,iBAAAA,KAAAA,IAAAA,eAAAA,CAAAA;UACC,cACEC;UAEFjB,mBAAOkB,IAAAA,wCAAA;yBAEP;UAGAzB,CAAAA,gBAAAA,kBAAAA,GAAAA,OAAAA,QAAAA,CAAAA;UAEF,CAAAW,mBAAAC,qBAAA,GAAAc,OAAAC,QAAA,CAAA;UAACH,CAAAA,MAAAA,QAAAA,GAAAA,IAAAA,oCAAAA,EAAAA;eAA4BxB,OAAAA,IAAAA;sBAAsBJ,OAAAgC,WAAA;QAGrDC,cAAMC;;UAEJC,mBAAAA,OAAAA,WAAAA,CAAAA,CAAAA;8BAAwBC,OAAAA;uCAAaC,IAAA;oCAAe;eAAM;oCACzC;QACnB;QAEArB,qBAAiBoB;kCACMA,QAAME,0BAAe,KAAA,IAAA,KAAA,IAAAlC,sBAAAuB;;;QAChCvB;KAAA;mBACR+B,CAAAA;;yBAA+BI,QAAMJ,iBAAA,KAAA,IAAA,KAAA,IAAAA,aAAAC,OAAA;;kBAAoB;kBAC3D;QACF;QAEAX,iBAAMe;;;QAEN,IAAAJ,MAAMK,MAAAA,KAAAA,MAAgBX,aAAkB,EAAA;oBACtCL;6BACArB,QAAAA,iBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,aAAAA,OAAAA;gBACCgC;gBAAChC,MAAAA;gBAAuBqB,MAAAA;YAAiB;QAE5C;;UAEEe,uBAAmB,WAAA,GAAAV,OAAAY,aAAA,CAAAC,0CAAA,EAAA;2BACnBnC;;UAEAE,gBAAAA,OAAAA,WAAAA,CAAAA;yBACQ+B;kCACRG,QAAAA,0BAAAA,KAAAA,IAAAA,KAAAA,IAAAA,sBAAAA;;;QACA/B;KAAAA;2CACAK;UACA2B,YAAAA,IAAAA,oCAAa,EAAA;2BACb9B;;QAEFa;QAEAlB;QACAwB,QAAAO;QACAG;QACA/B;QAEAiB;qBACMgB;;;;2GAGgF;8GACF;sFAClB;UAChE,CAAAA,sBAAAC,wBAAA,GAAAjB,OAAyDC,QAAA,CAAA;WACzDiB,SAAA,CAAA;QACF,IAAGF,sBAAA;gBAACA;YAAqBG,CAAAA,sBAAA1C,WAAA2C,OAAA,MAAA,QAAAD,wBAAA,KAAA,IAAA,KAAA,IAAAA,oBAAAE,eAAA,CAAA;QAEzB;wFAAsElD;sFAAaK;IAAM,gEAAA;IAEzF,yDAAyD8C;IACzD,uDAA8B;;;KAC5B;6BAEUlC,kBAAAA,GAAAA,IAAAA,4CAAAA,EAAAA;;;;6BAIDmC,IAAAA,6BAAAA,EAAAA,kBAAAA,4BAAAA,iBAAAA,QAAAA,iBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,aAAAA,GAAAA;oBACLzB,OAAAA,OAAAA,CAAAA;;YAGNV,MAAGA;eAACU,YAAAA;eAA4ByB,gBAAAA;eAAkBhD,cAAAA;iBAAca;wCAAMP;;OAAiC;QAAAiB;QAAAyB;QAAAhD;QAAAa;QAAAP;QAAAa;KAAA;WAEvG;uBACE8B;sBACAC;;;;;;;sBAOAC;;;AAGJ"}
|
|
@@ -17,8 +17,9 @@ const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
|
17
17
|
const _reacttabster = require("@fluentui/react-tabster");
|
|
18
18
|
const _reactutilities = require("@fluentui/react-utilities");
|
|
19
19
|
const _dropdownKeyActions = require("./dropdownKeyActions");
|
|
20
|
+
const _keyboardkeys = require("@fluentui/keyboard-keys");
|
|
20
21
|
function useTriggerKeydown(options) {
|
|
21
|
-
const { activeDescendantController, getOptionById, selectOption, multiselect, open,
|
|
22
|
+
const { activeDescendantController, getOptionById, selectOption, multiselect, open, cursorPosition, onBlur, allowArrowUpNavigation, isInSelectionMode, setSelectionMode } = options;
|
|
22
23
|
const getActiveOption = _react.useCallback(()=>{
|
|
23
24
|
const activeOptionId = activeDescendantController.active();
|
|
24
25
|
return activeOptionId ? getOptionById(activeOptionId) : undefined;
|
|
@@ -65,12 +66,19 @@ function useTriggerKeydown(options) {
|
|
|
65
66
|
const action = (0, _dropdownKeyActions.getDropdownActionFromKey)(e, {
|
|
66
67
|
open,
|
|
67
68
|
multiselect,
|
|
68
|
-
|
|
69
|
+
cursorPosition,
|
|
70
|
+
allowArrowUpNavigation,
|
|
71
|
+
isInSelectionMode
|
|
69
72
|
});
|
|
70
73
|
const activeOption = getActiveOption();
|
|
71
74
|
const firstOption = activeDescendantController.first({
|
|
72
75
|
passive: true
|
|
73
76
|
});
|
|
77
|
+
if (e.key === _keyboardkeys.ArrowLeft || e.key === _keyboardkeys.ArrowRight || action === 'Type') {
|
|
78
|
+
setSelectionMode(false);
|
|
79
|
+
} else if (action === 'Next' || action === 'Previous' || action === 'First' || action === 'Last' || action === 'PageUp' || action === 'PageDown') {
|
|
80
|
+
setSelectionMode(true);
|
|
81
|
+
}
|
|
74
82
|
switch(action){
|
|
75
83
|
case 'Last':
|
|
76
84
|
case 'First':
|
|
@@ -81,14 +89,7 @@ function useTriggerKeydown(options) {
|
|
|
81
89
|
e.preventDefault();
|
|
82
90
|
break;
|
|
83
91
|
case 'Previous':
|
|
84
|
-
|
|
85
|
-
// this means we were in the first option and we are "leaving" the listbox
|
|
86
|
-
if ((activeOption === null || activeOption === void 0 ? void 0 : activeOption.id) === firstOption) {
|
|
87
|
-
blur();
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
} else if (activeOption) {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
}
|
|
92
|
+
e.preventDefault();
|
|
92
93
|
break;
|
|
93
94
|
case 'Next':
|
|
94
95
|
e.preventDefault();
|
|
@@ -98,18 +99,33 @@ function useTriggerKeydown(options) {
|
|
|
98
99
|
switch(action){
|
|
99
100
|
case 'First':
|
|
100
101
|
first();
|
|
102
|
+
if (!isInSelectionMode) {
|
|
103
|
+
setSelectionMode(true);
|
|
104
|
+
}
|
|
101
105
|
break;
|
|
102
106
|
case 'Last':
|
|
103
107
|
last();
|
|
108
|
+
if (!isInSelectionMode) {
|
|
109
|
+
setSelectionMode(true);
|
|
110
|
+
}
|
|
104
111
|
break;
|
|
105
112
|
case 'Next':
|
|
106
113
|
next(activeOption);
|
|
114
|
+
if (!isInSelectionMode) {
|
|
115
|
+
setSelectionMode(true);
|
|
116
|
+
}
|
|
107
117
|
break;
|
|
108
118
|
case 'Previous':
|
|
119
|
+
// when active option is the first option and the action was "Previous",
|
|
120
|
+
// this means we were in the first option and we are "leaving" the listbox
|
|
109
121
|
if (activeOption && activeOption.id !== firstOption) {
|
|
110
122
|
previous(activeOption);
|
|
123
|
+
if (!isInSelectionMode) {
|
|
124
|
+
setSelectionMode(true);
|
|
125
|
+
}
|
|
111
126
|
} else {
|
|
112
127
|
blur();
|
|
128
|
+
setSelectionMode(false);
|
|
113
129
|
}
|
|
114
130
|
break;
|
|
115
131
|
case 'PageDown':
|
|
@@ -121,6 +137,7 @@ function useTriggerKeydown(options) {
|
|
|
121
137
|
case 'CloseSelect':
|
|
122
138
|
if (!multiselect && !(activeOption === null || activeOption === void 0 ? void 0 : activeOption.disabled)) {
|
|
123
139
|
blur();
|
|
140
|
+
setSelectionMode(false);
|
|
124
141
|
}
|
|
125
142
|
// fallthrough
|
|
126
143
|
case 'Select':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["useTriggerKeyDown.ts"],"sourcesContent":["/**\n * Note, this is mainly brought from Fluent UI, only removed the closing and\n * opening logic since that's not needed for this use case and added the bluring\n * functionality.\n */\n\nimport * as React from 'react';\nimport { useSetKeyboardNavigation } from '@fluentui/react-tabster';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from './dropdownKeyActions';\nimport type { ActiveDescendantImperativeRef } from '@fluentui/react-aria';\nimport type { OptionCollectionState, OptionValue } from './OptionCollection.types';\nimport type { SelectionProps, SelectionState } from './Selection.types';\n\nexport function useTriggerKeydown(\n options: {\n activeDescendantController: ActiveDescendantImperativeRef;\n
|
|
1
|
+
{"version":3,"sources":["useTriggerKeyDown.ts"],"sourcesContent":["/**\n * Note, this is mainly brought from Fluent UI, only removed the closing and\n * opening logic since that's not needed for this use case and added the bluring\n * functionality.\n */\n\nimport * as React from 'react';\nimport { useSetKeyboardNavigation } from '@fluentui/react-tabster';\nimport { useEventCallback } from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from './dropdownKeyActions';\nimport { ArrowLeft, ArrowRight } from '@fluentui/keyboard-keys';\nimport type { ActiveDescendantImperativeRef } from '@fluentui/react-aria';\nimport type { OptionCollectionState, OptionValue } from './OptionCollection.types';\nimport type { SelectionProps, SelectionState } from './Selection.types';\nimport type { CursorPosition } from '../../plugins/CursorPositionPlugin';\n\nexport function useTriggerKeydown(\n options: {\n activeDescendantController: ActiveDescendantImperativeRef;\n cursorPosition: CursorPosition;\n open: boolean;\n onBlur: () => void;\n allowArrowUpNavigation: boolean;\n isInSelectionMode: boolean;\n setSelectionMode: (selectionMode: boolean) => void;\n } & OptionCollectionState &\n Pick<SelectionProps, 'multiselect'> &\n Pick<SelectionState, 'selectOption'>,\n) {\n const {\n activeDescendantController,\n getOptionById,\n selectOption,\n multiselect,\n open,\n cursorPosition,\n onBlur,\n allowArrowUpNavigation,\n isInSelectionMode,\n setSelectionMode,\n } = options;\n\n const getActiveOption = React.useCallback(() => {\n const activeOptionId = activeDescendantController.active();\n return activeOptionId ? getOptionById(activeOptionId) : undefined;\n }, [activeDescendantController, getOptionById]);\n\n const first = () => {\n activeDescendantController.first();\n };\n\n const last = () => {\n activeDescendantController.last();\n };\n\n const blur = () => {\n activeDescendantController.blur();\n onBlur();\n };\n\n const next = (activeOption: OptionValue | undefined) => {\n if (activeOption) {\n activeDescendantController.next();\n } else {\n activeDescendantController.first();\n }\n };\n\n const previous = (activeOption: OptionValue | undefined) => {\n if (activeOption) {\n activeDescendantController.prev();\n } else {\n activeDescendantController.first();\n }\n };\n\n const pageUp = () => {\n for (let i = 0; i < 10; i++) {\n activeDescendantController.prev();\n }\n };\n\n const pageDown = () => {\n for (let i = 0; i < 10; i++) {\n activeDescendantController.next();\n }\n };\n\n const setKeyboardNavigation = useSetKeyboardNavigation();\n return useEventCallback((e: React.KeyboardEvent<HTMLSpanElement>) => {\n const action = getDropdownActionFromKey(e, {\n open,\n multiselect,\n cursorPosition,\n allowArrowUpNavigation,\n isInSelectionMode,\n });\n const activeOption = getActiveOption();\n const firstOption = activeDescendantController.first({ passive: true });\n\n if (e.key === ArrowLeft || e.key === ArrowRight || action === 'Type') {\n setSelectionMode(false);\n } else if (\n action === 'Next' ||\n action === 'Previous' ||\n action === 'First' ||\n action === 'Last' ||\n action === 'PageUp' ||\n action === 'PageDown'\n ) {\n setSelectionMode(true);\n }\n\n switch (action) {\n case 'Last':\n case 'First':\n case 'PageDown':\n case 'PageUp':\n case 'CloseSelect':\n case 'Select':\n e.preventDefault();\n break;\n case 'Previous':\n e.preventDefault();\n break;\n case 'Next':\n e.preventDefault();\n break;\n }\n\n setKeyboardNavigation(true);\n\n switch (action) {\n case 'First':\n first();\n if (!isInSelectionMode) {\n setSelectionMode(true);\n }\n break;\n case 'Last':\n last();\n if (!isInSelectionMode) {\n setSelectionMode(true);\n }\n break;\n case 'Next':\n next(activeOption);\n if (!isInSelectionMode) {\n setSelectionMode(true);\n }\n break;\n case 'Previous':\n // when active option is the first option and the action was \"Previous\",\n // this means we were in the first option and we are \"leaving\" the listbox\n if (activeOption && activeOption.id !== firstOption) {\n previous(activeOption);\n if (!isInSelectionMode) {\n setSelectionMode(true);\n }\n } else {\n blur();\n setSelectionMode(false);\n }\n break;\n case 'PageDown':\n pageDown();\n break;\n case 'PageUp':\n pageUp();\n break;\n case 'CloseSelect':\n if (!multiselect && !activeOption?.disabled) {\n blur();\n setSelectionMode(false);\n }\n // fallthrough\n case 'Select':\n activeOption && selectOption(e, activeOption);\n break;\n case 'Tab':\n !multiselect && activeOption && selectOption(e, activeOption);\n break;\n }\n });\n}\n"],"names":["useTriggerKeydown","React","options","activeDescendantController","activeOptionId","multiselect","getOptionById","allowArrowUpNavigation","setSelectionMode","active","blur","undefined","onBlur","first","last","activeOption","next","previous","i","prev","pageUp","setKeyboardNavigation","useSetKeyboardNavigation","open","cursorPosition","useEventCallback","action","firstOption","getActiveOption","ArrowLeft","e","key","ArrowRight","preventDefault","isInSelectionMode","id","pageDown","disabled"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;CAIC;;;;+BAYeA;;;eAAAA;;;;iEAVJC;8BAC6B;gCACR;oCACQ;8BACH;AAM/B,SAASD,kBACdE,OAUsC;UAEtC,EAaAC,0BAAwBF,eAChBG,cACCA,EACTC,WAAG,MAACF,gBAA4BG,QAAc,EAE9CC,sBAAc,mBACZJ,EACFK,gBAAA,KAEAN;UACEC,kBAAAA,OAAAA,WAA+B,CAAA;QACjC,MAAAC,iBAAAD,2BAAAM,MAAA;QAEA,OAAMC,iBAAOJ,cAAAF,kBAAAO;;;QACXR;KAA+B;UAC/BS,QAAAA;QACFT,2BAAAU,KAAA;;UAGEC,OAAIC;mCACFZ,IAAAA;;iBAEAA;mCACFO,IAAA;QACFE;;UAGEI,OAAID,CAAAA;0BACFZ;uCACKa,IAAA;;uCAEPH,KAAA;QACF;;UAGEI,WAASC,CAAAA;0BACPf;uCACFgB,IAAA;QACF,OAAA;YAEAhB,2BAAiBU,KAAA;;;UAGfO,SAAA;QACF,IAAA,IAAAF,IAAA,GAAAA,IAAA,IAAAA,IAAA;YAEAf,2BAAMkB,IAAwBC;QAC9B;;qBAEIC;gBACAlB,IAAAA,GAAAA,IAAAA,IAAAA,IAAAA;uCACAmB,IAAAA;;;UAGFH,wBAAAC,IAAAA,sCAAA;WACAG,IAAAA,gCAAMV,EAAAA,CAAAA;cACNW,SAAMC,IAAAA,4CAAcxB,EAAAA,GAAAA;;;;;;;cAapBY,eAAAa;cAEAD,cAAQD,2BAAAA,KAAAA,CAAAA;qBACN;;iBAEA,KAAKG,uBAAA,IAAAC,EAAAC,GAAA,KAAAC,wBAAA,IAAAN,WAAA,QAAA;6BACA;mBACLA,WAAK,UAAAA,WAAA,cAAAA,WAAA,WAAAA,WAAA,UAAAA,WAAA,YAAAA,WAAA,YAAA;6BACA;;;;;;;;;gBASPI,EAAAG,cAAA;gBAEAZ;iBAEA;gCACO;;;gCAGDb;;;8BAGC;;;;wCAIH;qCACA;;;;;wCAKA;qCACA;;;;;wCAKWO;qCACJmB;;;;wFAILxB;0FACiB;oCACnBK,aAAAoB,EAAA,KAAAR,aAAA;6BACAZ;wBACF,CAAAmB,mBAAK;yCACHE;;uBAEF;;qCAEE;;;;;;;;;;oBAUF,CAAA/B,eAAK,CAAAU,CAAAA,iBAAA,QAAAA,iBAAA,KAAA,IAAA,KAAA,IAAAA,aAAAsB,QAAA,GAAA;;qCAEH;gBACJ;YACF,cAAA;YACF,KAAA"}
|
package/lib-commonjs/index.js
CHANGED
|
@@ -15,9 +15,6 @@ _export(exports, {
|
|
|
15
15
|
PromptOption: function() {
|
|
16
16
|
return _PromptOption.PromptOption;
|
|
17
17
|
},
|
|
18
|
-
TextCursorPositionPlugin: function() {
|
|
19
|
-
return _TextCursorPositionPlugin.TextCursorPositionPlugin;
|
|
20
|
-
},
|
|
21
18
|
promptListboxClassNames: function() {
|
|
22
19
|
return _PromptListbox.promptListboxClassNames;
|
|
23
20
|
},
|
|
@@ -48,6 +45,5 @@ _export(exports, {
|
|
|
48
45
|
});
|
|
49
46
|
const _PromptListbox = require("./PromptListbox");
|
|
50
47
|
const _usePromptListboxFunctionality = require("./components/utils/usePromptListboxFunctionality");
|
|
51
|
-
const _TextCursorPositionPlugin = require("./plugins/TextCursorPositionPlugin");
|
|
52
48
|
const _PromptOption = require("./PromptOption");
|
|
53
49
|
//# sourceMappingURL=index.js.map
|