@elliemae/ds-app-picker 3.70.0-next.52 → 3.70.0-next.54
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/DSAppPicker.js +6 -64
- package/dist/cjs/DSAppPicker.js.map +3 -3
- package/dist/cjs/DSAppPickerCTX.js +2 -22
- package/dist/cjs/DSAppPickerCTX.js.map +2 -2
- package/dist/cjs/config/useAppPicker.js +19 -5
- package/dist/cjs/config/useAppPicker.js.map +2 -2
- package/dist/cjs/config/useFocusTracker.js +24 -35
- package/dist/cjs/config/useFocusTracker.js.map +2 -2
- package/dist/cjs/constants/index.js +2 -0
- package/dist/cjs/constants/index.js.map +2 -2
- package/dist/cjs/parts/AppPanel.js +60 -43
- package/dist/cjs/parts/AppPanel.js.map +3 -3
- package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js +83 -0
- package/dist/cjs/parts/AppPickerFloatingContext/AppPickerContent.js.map +7 -0
- package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +171 -0
- package/dist/cjs/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +7 -0
- package/dist/cjs/parts/AppPickerItem.js +6 -10
- package/dist/cjs/parts/AppPickerItem.js.map +2 -2
- package/dist/cjs/parts/AppSection.js +2 -0
- package/dist/cjs/parts/AppSection.js.map +2 -2
- package/dist/cjs/parts/Trigger.js +14 -8
- package/dist/cjs/parts/Trigger.js.map +2 -2
- package/dist/cjs/parts/style.js +1 -7
- package/dist/cjs/parts/style.js.map +2 -2
- package/dist/cjs/react-desc-prop-types.js +6 -1
- package/dist/cjs/react-desc-prop-types.js.map +2 -2
- package/dist/cjs/util/getChipId.js +36 -0
- package/dist/cjs/util/getChipId.js.map +7 -0
- package/dist/cjs/util/getChipRegionId.js +37 -0
- package/dist/cjs/util/getChipRegionId.js.map +7 -0
- package/dist/esm/DSAppPicker.js +7 -65
- package/dist/esm/DSAppPicker.js.map +3 -3
- package/dist/esm/DSAppPickerCTX.js +2 -22
- package/dist/esm/DSAppPickerCTX.js.map +2 -2
- package/dist/esm/config/useAppPicker.js +22 -8
- package/dist/esm/config/useAppPicker.js.map +2 -2
- package/dist/esm/config/useFocusTracker.js +23 -34
- package/dist/esm/config/useFocusTracker.js.map +2 -2
- package/dist/esm/constants/index.js +2 -0
- package/dist/esm/constants/index.js.map +2 -2
- package/dist/esm/parts/AppPanel.js +61 -44
- package/dist/esm/parts/AppPanel.js.map +3 -3
- package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js +53 -0
- package/dist/esm/parts/AppPickerFloatingContext/AppPickerContent.js.map +7 -0
- package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js +141 -0
- package/dist/esm/parts/AppPickerFloatingContext/useAppPickerFloatingContext.js.map +7 -0
- package/dist/esm/parts/AppPickerItem.js +5 -9
- package/dist/esm/parts/AppPickerItem.js.map +2 -2
- package/dist/esm/parts/AppSection.js +2 -0
- package/dist/esm/parts/AppSection.js.map +2 -2
- package/dist/esm/parts/Trigger.js +15 -9
- package/dist/esm/parts/Trigger.js.map +2 -2
- package/dist/esm/parts/style.js +1 -7
- package/dist/esm/parts/style.js.map +2 -2
- package/dist/esm/react-desc-prop-types.js +6 -1
- package/dist/esm/react-desc-prop-types.js.map +2 -2
- package/dist/esm/util/getChipId.js +6 -0
- package/dist/esm/util/getChipId.js.map +7 -0
- package/dist/esm/util/getChipRegionId.js +7 -0
- package/dist/esm/util/getChipRegionId.js.map +7 -0
- package/dist/types/DSAppPicker.d.ts +1 -1
- package/dist/types/DSAppPickerCTX.d.ts +6 -17
- package/dist/types/config/useAppPicker.d.ts +109 -91
- package/dist/types/config/useFocusTracker.d.ts +10 -6
- package/dist/types/constants/index.d.ts +1 -0
- package/dist/types/parts/AppPanel.d.ts +1 -8
- package/dist/types/parts/AppPickerFloatingContext/AppPickerContent.d.ts +3 -0
- package/dist/types/parts/AppPickerFloatingContext/useAppPickerFloatingContext.d.ts +170 -0
- package/dist/types/parts/AppPickerItem.d.ts +1 -0
- package/dist/types/parts/Trigger.d.ts +10 -14
- package/dist/types/parts/style.d.ts +0 -1
- package/dist/types/react-desc-prop-types.d.ts +31 -1
- package/dist/types/util/getChipId.d.ts +2 -0
- package/dist/types/util/getChipRegionId.d.ts +1 -0
- package/package.json +13 -14
- package/dist/cjs/config/useAppPickerBehavior.js +0 -156
- package/dist/cjs/config/useAppPickerBehavior.js.map +0 -7
- package/dist/esm/config/useAppPickerBehavior.js +0 -126
- package/dist/esm/config/useAppPickerBehavior.js.map +0 -7
- package/dist/types/config/useAppPickerBehavior.d.ts +0 -39
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { useAppPicker } from '../../config/useAppPicker.js';
|
|
3
|
+
import type { DSAppPickerT } from '../../react-desc-prop-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* useAppPickerFloatingContext — the single point that wires DSAppPicker to
|
|
6
|
+
* `@elliemae/ds-floating-context`'s `useFloatingContext`.
|
|
7
|
+
*
|
|
8
|
+
* WHAT IT DOES (as a black box):
|
|
9
|
+
* AppPicker can be used in two very different ways:
|
|
10
|
+
* - Controlled: the consumer supplies `isOpen` and drives the open/close transition.
|
|
11
|
+
* └→ AppPicker can't be event-based as the flip might originate from any cause and we don't own the business logic
|
|
12
|
+
* └→ we need to ensure WCAG embedded behaviours (focus, Escape, click-outside) are wired to the consumer's `isOpen` flip.
|
|
13
|
+
* - Uncontrolled: the consumer does not supply `isOpen` and AppPicker owns the full flows, we only notify the consumer of the transition and its cause.
|
|
14
|
+
*
|
|
15
|
+
* The AppPicker and this file in particular serves as the one place that coordinates the two different ways to use the component and wires with the useFloatingContext hook.
|
|
16
|
+
* This files owns:
|
|
17
|
+
* - Focus management relative to open/close transitions (initial focus on open, return focus to trigger on close)
|
|
18
|
+
* - Escape key handling (scoped to the panel and trigger)
|
|
19
|
+
* - Click-outside handling (panel and trigger)
|
|
20
|
+
* - Imperative focus API via actionRef
|
|
21
|
+
* - Controlled/Uncontrolled forks and differences in event notification (eager vs controlled-flip)
|
|
22
|
+
* - OnOpen and OnClose notification to the consumer with the correct reason and event (if any)
|
|
23
|
+
*
|
|
24
|
+
* IMPORTANT:
|
|
25
|
+
* Parts of the flow/logic required in this file is offloaded to useFloatingContext internal assumptions and logics.
|
|
26
|
+
* Changes to useFloatingContext may break the flows in this file, or alter them in ways that are not obvious, the two are closely coupled.
|
|
27
|
+
*
|
|
28
|
+
* DATA / EVENT FLOW
|
|
29
|
+
*
|
|
30
|
+
* Two concerns run in parallel and must not be conflated: (A) what makes the panel show/hide and take
|
|
31
|
+
* focus, and (B) how the consumer is told it opened/closed. They have different origins.
|
|
32
|
+
*
|
|
33
|
+
* (A) PANEL VISIBILITY + FOCUS — useFloatingContext internal co-ownership of the flow.
|
|
34
|
+
*
|
|
35
|
+
* a user action │ │ isOpen prop flip
|
|
36
|
+
* (trigger click / scoped Escape / click outside) │ │ (not a traceable user action, but the consumer's own flip)
|
|
37
|
+
* uncontrolled - flips the internal flag │ │ controlled - AppPicker's own flip is inert, consumer drives it
|
|
38
|
+
* │
|
|
39
|
+
* ▼
|
|
40
|
+
* resolvedIsOpen changes
|
|
41
|
+
* │
|
|
42
|
+
* ▼
|
|
43
|
+
* useFloatingContext (externallyControlledIsOpen) detects the transition
|
|
44
|
+
* │
|
|
45
|
+
* ▼
|
|
46
|
+
* on open │ │ on close
|
|
47
|
+
* handleFloatingOpen │ │ focus is only restored after a SCOPED ESCAPE:
|
|
48
|
+
* AppPicker business logic seeds initial focus │ │ useFloatingContext returns focus to the trigger
|
|
49
|
+
* │ │ (returnFocusToReference). Click-outside / toggle
|
|
50
|
+
* │ │ / controlled closes do NOT move focus, and
|
|
51
|
+
* │ │ handleFloatingClose only NOTIFIES (see (B)).
|
|
52
|
+
* │
|
|
53
|
+
* ▼
|
|
54
|
+
* ┌─────────────────────────────────────────────────────────────┐
|
|
55
|
+
* │ visibility + focus are delivered to final user as expected │
|
|
56
|
+
* └─────────────────────────────────────────────────────────────┘
|
|
57
|
+
*
|
|
58
|
+
* (B) CONSUMER NOTIFICATION
|
|
59
|
+
* Each flow below is the UNCONTROLLED path, where AppPicker owns the transition and can name the true cause.
|
|
60
|
+
* The controlled equivalent for every trigger is stated once at the end.
|
|
61
|
+
* ┌────────────────────────┐
|
|
62
|
+
* │ OPENING TRIGGERS FLOWS │
|
|
63
|
+
* └────────────────────────┘
|
|
64
|
+
* TRIGGER CLICK (uncontrolled)
|
|
65
|
+
* trigger click
|
|
66
|
+
* user clicks the internal trigger, panel closed
|
|
67
|
+
* │
|
|
68
|
+
* ▼
|
|
69
|
+
* handleTriggerClick
|
|
70
|
+
* ( flips the flag and wires the visual and focus Flow (A) above )
|
|
71
|
+
* │
|
|
72
|
+
* ▼
|
|
73
|
+
* ┌──────────────────────────────────────────────┐
|
|
74
|
+
* │ onOpen { reason: 'trigger', event } │ fired EAGERLY, when the event is triggered
|
|
75
|
+
* └──────────────────────────────────────────────┘
|
|
76
|
+
* ------------------------------------------------------------------------------------------------------------------------
|
|
77
|
+
* ┌────────────────────────┐
|
|
78
|
+
* │ CLOSING TRIGGERS FLOWS │
|
|
79
|
+
* └────────────────────────┘
|
|
80
|
+
* KEYBOARD ESCAPE (uncontrolled)
|
|
81
|
+
* Escape within the panel DOM tree or the trigger
|
|
82
|
+
* scoped Escape (routed only while closeOnEscape, i.e. no consumer onKeyDown)
|
|
83
|
+
* │
|
|
84
|
+
* ▼
|
|
85
|
+
* onEscape → handleScopedEscape
|
|
86
|
+
* ( flips the flag and wires the visual and focus Flow (A) above )
|
|
87
|
+
* │
|
|
88
|
+
* ▼
|
|
89
|
+
* ┌──────────────────────────────────────────────┐
|
|
90
|
+
* │ onClose { reason: 'escape', event } │ fired EAGERLY, when the event is triggered
|
|
91
|
+
* └──────────────────────────────────────────────┘
|
|
92
|
+
*
|
|
93
|
+
* CLICK OUTSIDE (uncontrolled)
|
|
94
|
+
* Click outside the panel DOM tree and the trigger
|
|
95
|
+
* useFloatingContext detects a pointer press outside the panel + trigger
|
|
96
|
+
* │
|
|
97
|
+
* ▼
|
|
98
|
+
* handleClickOutside
|
|
99
|
+
* ( flips the flag and wires the visual and focus Flow (A) above )
|
|
100
|
+
* │
|
|
101
|
+
* ▼
|
|
102
|
+
* ┌──────────────────────────────────────────────┐
|
|
103
|
+
* │ onClose { reason: 'click-outside', event } │ fired EAGERLY, when the event is triggered
|
|
104
|
+
* └──────────────────────────────────────────────┘
|
|
105
|
+
*
|
|
106
|
+
* CLICK ON TRIGGER (uncontrolled, while internal state is open)
|
|
107
|
+
* trigger click while open
|
|
108
|
+
* user clicks the internal trigger, panel open
|
|
109
|
+
* │
|
|
110
|
+
* ▼
|
|
111
|
+
* handleTriggerClick
|
|
112
|
+
* ( flips the flag and wires the visual and focus Flow (A) above )
|
|
113
|
+
* │
|
|
114
|
+
* ▼
|
|
115
|
+
* ┌──────────────────────────────────────────────┐
|
|
116
|
+
* │ onClose { reason: 'trigger-toggle', event } │ fired EAGERLY, when the event is triggered
|
|
117
|
+
* └──────────────────────────────────────────────┘
|
|
118
|
+
* ------------------------------------------------------------------------------------------------------------------------
|
|
119
|
+
* ┌──────────────────────────────────┐
|
|
120
|
+
* │ CONTROLLED OPEN & CLOSE FLOWS │
|
|
121
|
+
* └──────────────────────────────────┘
|
|
122
|
+
* AppPicker's own flip is inert;
|
|
123
|
+
* We can't fire EAGERLY and we can't track an originating event, there may be NONE
|
|
124
|
+
* The consumer's `isOpen` flip is reacted to by useFloatingContext, which fires onOpen / onClose with reason 'controlled-flip'
|
|
125
|
+
* We wire the visual and focus Flow (A) above, and then notify the consumer with reason 'controlled' (no event)
|
|
126
|
+
* │
|
|
127
|
+
* ▼
|
|
128
|
+
* ┌──────────────────────────────────────────────┐
|
|
129
|
+
* │ onOpen { reason: 'controlled' } │ no event
|
|
130
|
+
* │ onClose { reason: 'controlled' } │ a prop flip is not a traceable user action
|
|
131
|
+
* └──────────────────────────────────────────────┘
|
|
132
|
+
* ------------------------------------------------------------------------------------------------------------------------
|
|
133
|
+
*
|
|
134
|
+
* Eager (uncontrolled) and controlled-flip paths are mutually exclusive on `isControlled`.
|
|
135
|
+
* the consumer is notified exactly once per transition — never twice.
|
|
136
|
+
* On Escape specifically
|
|
137
|
+
* a controlled consumer supplies onKeyDown, so closeOnEscape is false in useFloatingContext
|
|
138
|
+
* └→ AppPicker's onEscape never runs —
|
|
139
|
+
* └→ the close arrives purely by listening to the flag transition
|
|
140
|
+
* ------------------------------------------------------------------------------------------------------------------------
|
|
141
|
+
* A nuance for an edge case:
|
|
142
|
+
*
|
|
143
|
+
* Declarative mount-open (rendered already-open).
|
|
144
|
+
* useFloatingContext fires no onOpen for it (it did not transition to open, it started open),
|
|
145
|
+
* └→ neither the focus-seed (A) nor the notification (B) runs
|
|
146
|
+
* AppPanel compensates this locally via useMountedOpenAutofocusNuance, it needs to be seen if this is even desired or should be removed
|
|
147
|
+
* ------------------------------------------------------------------------------------------------------------------------
|
|
148
|
+
*/
|
|
149
|
+
type ConfiguredAppPickerCtx = ReturnType<typeof useAppPicker>;
|
|
150
|
+
type AppPickerFloatingContextConfig = {
|
|
151
|
+
propsWithDefault: DSAppPickerT.InternalProps;
|
|
152
|
+
focusTrackers: ConfiguredAppPickerCtx['focusTrackers'];
|
|
153
|
+
wasOpenedByKeyboardRef: ConfiguredAppPickerCtx['wasOpenedByKeyboardRef'];
|
|
154
|
+
resolvedIsOpen: ConfiguredAppPickerCtx['resolvedIsOpen'];
|
|
155
|
+
setInternalIsOpen: ConfiguredAppPickerCtx['setInternalIsOpen'];
|
|
156
|
+
};
|
|
157
|
+
export declare const useAppPickerFloatingContext: (appPickerConfig: AppPickerFloatingContextConfig) => {
|
|
158
|
+
floatingStyles: React.CSSProperties;
|
|
159
|
+
arrowStyles: import("@elliemae/ds-floating-context/dist/types/parts/PopoverArrow.js").PopoverArrowT;
|
|
160
|
+
floatingContext: {
|
|
161
|
+
withoutPortal: boolean;
|
|
162
|
+
withoutAnimation: boolean;
|
|
163
|
+
portalDOMContainer: HTMLElement | undefined;
|
|
164
|
+
animationDuration: number;
|
|
165
|
+
};
|
|
166
|
+
handleTriggerRef: (instance: HTMLButtonElement | null) => void | React.DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof React.DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES];
|
|
167
|
+
handleTriggerClick: (e: React.MouseEvent | React.KeyboardEvent) => void;
|
|
168
|
+
floatingInnerRef: (instance: HTMLDivElement | null) => void | React.DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof React.DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES];
|
|
169
|
+
};
|
|
170
|
+
export {};
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
onClick: (e: React.MouseEvent | React.KeyboardEvent) => void;
|
|
12
|
-
renderTrigger?: DSAppPickerT.OptionalProps['renderTrigger'];
|
|
13
|
-
}
|
|
14
|
-
export declare const Trigger: React.FC<TriggerProps>;
|
|
1
|
+
import type { useAppPickerFloatingContext } from './AppPickerFloatingContext/useAppPickerFloatingContext.js';
|
|
2
|
+
type UseAppPickerFloatingContextT = ReturnType<typeof useAppPickerFloatingContext>;
|
|
3
|
+
type FloatingContextDictatedProps = {
|
|
4
|
+
handleTriggerRef: UseAppPickerFloatingContextT['handleTriggerRef'];
|
|
5
|
+
handleTriggerClick: UseAppPickerFloatingContextT['handleTriggerClick'];
|
|
6
|
+
};
|
|
7
|
+
export declare const Trigger: {
|
|
8
|
+
(PropsFromFloatingContext: FloatingContextDictatedProps): import("react/jsx-runtime.js").JSX.Element | null;
|
|
9
|
+
displayName: string;
|
|
10
|
+
};
|
|
15
11
|
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare const StyledAppPickerFloating: import("styled-components").StyledComponent<import("react").ComponentType<import("@elliemae/ds-floating-context").DSFloatingWrapperT.Props>, import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<import("react").ComponentType<import("@elliemae/ds-floating-context").DSFloatingWrapperT.Props>>, never>;
|
|
2
1
|
export declare const StyledWrapper: import("styled-components").StyledComponent<import("react").ForwardRefExoticComponent<import("@elliemae/ds-grid").DSGridT.Props & import("react").RefAttributes<HTMLDivElement>>, import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<import("react").ForwardRefExoticComponent<import("@elliemae/ds-grid").DSGridT.Props & import("react").RefAttributes<HTMLDivElement>>>, never>;
|
|
3
2
|
export declare const StyledListItem: import("styled-components").StyledComponent<"li", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"li">, never>;
|
|
4
3
|
export declare const StyledListItemFullRow: import("styled-components").StyledComponent<"li", import("@elliemae/ds-system").Theme, object & import("@elliemae/ds-system").OwnerInterface & import("@elliemae/ds-system").InnerRefInterface<"li">, never>;
|
|
@@ -22,6 +22,35 @@ export declare namespace DSAppPickerT {
|
|
|
22
22
|
focusSelectedOrFirstAvailable?: () => void;
|
|
23
23
|
focusWrapper: () => void;
|
|
24
24
|
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Why the panel opened. `trigger` carries the activating event and fires synchronously in the
|
|
27
|
+
* trigger's click handler (AppPicker owns the open). `controlled` fires when the consumer flips
|
|
28
|
+
* the `isOpen` prop themselves — no event, delivered when that flip takes effect.
|
|
29
|
+
*/
|
|
30
|
+
type OpenChange = {
|
|
31
|
+
reason: 'trigger';
|
|
32
|
+
event: React.MouseEvent | React.KeyboardEvent;
|
|
33
|
+
} | {
|
|
34
|
+
reason: 'controlled';
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Why the panel closed. The event-carrying reasons fire synchronously from the handler that owns
|
|
38
|
+
* the close (AppPicker in uncontrolled mode): `escape` (a scoped Escape), `click-outside`, and
|
|
39
|
+
* `trigger-toggle` (the trigger clicked while open). `controlled` fires when the consumer flips the
|
|
40
|
+
* `isOpen` prop themselves — no event, delivered when that flip takes effect.
|
|
41
|
+
*/
|
|
42
|
+
type CloseChange = {
|
|
43
|
+
reason: 'escape';
|
|
44
|
+
event: KeyboardEvent;
|
|
45
|
+
} | {
|
|
46
|
+
reason: 'click-outside';
|
|
47
|
+
event: MouseEvent | TouchEvent;
|
|
48
|
+
} | {
|
|
49
|
+
reason: 'trigger-toggle';
|
|
50
|
+
event: React.MouseEvent | React.KeyboardEvent;
|
|
51
|
+
} | {
|
|
52
|
+
reason: 'controlled';
|
|
53
|
+
};
|
|
25
54
|
interface RequiredProps {
|
|
26
55
|
}
|
|
27
56
|
type SlotFunctionArguments = {
|
|
@@ -46,7 +75,8 @@ export declare namespace DSAppPickerT {
|
|
|
46
75
|
[key: string]: unknown;
|
|
47
76
|
}
|
|
48
77
|
interface OptionalProps extends TypescriptHelpersT.PropsForGlobalOnSlots<typeof DSAppPickerName, typeof DSAppPickerSlots> {
|
|
49
|
-
|
|
78
|
+
onOpen?: (info: OpenChange) => void;
|
|
79
|
+
onClose?: (info: CloseChange) => void;
|
|
50
80
|
onClick?: (e: React.MouseEvent | React.KeyboardEvent) => void;
|
|
51
81
|
onClickOutside?: (e: MouseEvent | React.MouseEvent) => void;
|
|
52
82
|
onKeyDown?: (e: React.KeyboardEvent) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getChipRegionId: (chipId: string) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/ds-app-picker",
|
|
3
|
-
"version": "3.70.0-next.
|
|
3
|
+
"version": "3.70.0-next.54",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ICE MT - Dimsum - App Picker",
|
|
6
6
|
"files": [
|
|
@@ -36,24 +36,23 @@
|
|
|
36
36
|
"indent": 4
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"
|
|
40
|
-
"@elliemae/ds-
|
|
41
|
-
"@elliemae/ds-
|
|
42
|
-
"@elliemae/ds-
|
|
43
|
-
"@elliemae/ds-
|
|
44
|
-
"@elliemae/ds-
|
|
45
|
-
"@elliemae/ds-
|
|
46
|
-
"@elliemae/ds-icons": "3.70.0-next.
|
|
47
|
-
"@elliemae/ds-
|
|
48
|
-
"@elliemae/ds-typography": "3.70.0-next.52"
|
|
39
|
+
"@elliemae/ds-button-v2": "3.70.0-next.54",
|
|
40
|
+
"@elliemae/ds-floating-context": "3.70.0-next.54",
|
|
41
|
+
"@elliemae/ds-hooks-focus-trap": "3.70.0-next.54",
|
|
42
|
+
"@elliemae/ds-grid": "3.70.0-next.54",
|
|
43
|
+
"@elliemae/ds-props-helpers": "3.70.0-next.54",
|
|
44
|
+
"@elliemae/ds-system": "3.70.0-next.54",
|
|
45
|
+
"@elliemae/ds-chip": "3.70.0-next.54",
|
|
46
|
+
"@elliemae/ds-icons": "3.70.0-next.54",
|
|
47
|
+
"@elliemae/ds-typography": "3.70.0-next.54"
|
|
49
48
|
},
|
|
50
49
|
"devDependencies": {
|
|
51
50
|
"@playwright/experimental-ct-react": "^1.60.0",
|
|
52
51
|
"jest": "^30.0.0",
|
|
53
52
|
"styled-components": "~5.3.9",
|
|
54
|
-
"@elliemae/ds-
|
|
55
|
-
"@elliemae/ds-
|
|
56
|
-
"@elliemae/ds-
|
|
53
|
+
"@elliemae/ds-typescript-helpers": "3.70.0-next.54",
|
|
54
|
+
"@elliemae/ds-monorepo-devops": "3.70.0-next.54",
|
|
55
|
+
"@elliemae/ds-test-utils": "3.70.0-next.54"
|
|
57
56
|
},
|
|
58
57
|
"peerDependencies": {
|
|
59
58
|
"react": "^18.3.1",
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var useAppPickerBehavior_exports = {};
|
|
30
|
-
__export(useAppPickerBehavior_exports, {
|
|
31
|
-
useAppPickerBehavior: () => useAppPickerBehavior
|
|
32
|
-
});
|
|
33
|
-
module.exports = __toCommonJS(useAppPickerBehavior_exports);
|
|
34
|
-
var React = __toESM(require("react"));
|
|
35
|
-
var import_react = require("react");
|
|
36
|
-
var import_ds_floating_context = require("@elliemae/ds-floating-context");
|
|
37
|
-
var import_useFocusTracker = require("./useFocusTracker.js");
|
|
38
|
-
const useAppPickerBehavior = (appPickerConfig) => {
|
|
39
|
-
const { propsWithDefault, ownerPropsConfig } = appPickerConfig;
|
|
40
|
-
const {
|
|
41
|
-
apps,
|
|
42
|
-
customApps,
|
|
43
|
-
icon: Icon,
|
|
44
|
-
renderTrigger,
|
|
45
|
-
isOpen,
|
|
46
|
-
onClose,
|
|
47
|
-
actionRef,
|
|
48
|
-
onClick,
|
|
49
|
-
onClickOutside,
|
|
50
|
-
triggerRef
|
|
51
|
-
} = propsWithDefault;
|
|
52
|
-
const focusTracker = (0, import_useFocusTracker.useFocusTracker)();
|
|
53
|
-
const { trackFocusSelectedItem, trackFocusItemAtIndex, trackFocusPanel } = focusTracker;
|
|
54
|
-
const [open, setOpen] = (0, import_react.useState)(false);
|
|
55
|
-
const defaultTriggerRef = (0, import_react.useRef)(null);
|
|
56
|
-
const wasOpenedByKeyboardRef = (0, import_react.useRef)(false);
|
|
57
|
-
const appsRef = (0, import_react.useRef)(apps);
|
|
58
|
-
appsRef.current = apps;
|
|
59
|
-
const customAppsRef = (0, import_react.useRef)(customApps);
|
|
60
|
-
customAppsRef.current = customApps;
|
|
61
|
-
const resolvedIsOpen = typeof isOpen === "boolean" ? isOpen : open;
|
|
62
|
-
const handleClose = (0, import_react.useCallback)(() => {
|
|
63
|
-
setOpen(false);
|
|
64
|
-
onClose?.();
|
|
65
|
-
}, [onClose]);
|
|
66
|
-
const handleClickOutside = (0, import_react.useCallback)(
|
|
67
|
-
(e) => {
|
|
68
|
-
setOpen(false);
|
|
69
|
-
onClose?.();
|
|
70
|
-
onClickOutside?.(e);
|
|
71
|
-
},
|
|
72
|
-
[onClose, onClickOutside]
|
|
73
|
-
);
|
|
74
|
-
const {
|
|
75
|
-
refs: floatingRefs,
|
|
76
|
-
floatingStyles,
|
|
77
|
-
arrowStyles,
|
|
78
|
-
context: floatingContext
|
|
79
|
-
} = (0, import_ds_floating_context.useFloatingContext)({
|
|
80
|
-
placement: "bottom",
|
|
81
|
-
// Arrow tip is ~6.1px above the panel top (arrowPlacementBase16 ≈ 17.5px, tip at 11.4px from box top).
|
|
82
|
-
// 4px spec gap → 4 + 6.1 ≈ 10px offset.
|
|
83
|
-
customOffset: [0, 10],
|
|
84
|
-
externallyControlledIsOpen: resolvedIsOpen,
|
|
85
|
-
withoutAnimation: true,
|
|
86
|
-
onClickOutside: handleClickOutside
|
|
87
|
-
});
|
|
88
|
-
const handleTriggerRef = (0, import_react.useCallback)(
|
|
89
|
-
(node) => {
|
|
90
|
-
defaultTriggerRef.current = node;
|
|
91
|
-
floatingRefs.setReference(node);
|
|
92
|
-
if (triggerRef) {
|
|
93
|
-
triggerRef.current = node;
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
[floatingRefs, triggerRef]
|
|
97
|
-
);
|
|
98
|
-
const handleActionRef = (0, import_react.useCallback)(
|
|
99
|
-
(node) => {
|
|
100
|
-
if (node && actionRef?.current) {
|
|
101
|
-
actionRef.current.focusToIndex = (index) => {
|
|
102
|
-
trackFocusItemAtIndex(appsRef.current, customAppsRef.current, index);
|
|
103
|
-
};
|
|
104
|
-
actionRef.current.focusWrapper = () => {
|
|
105
|
-
trackFocusPanel();
|
|
106
|
-
};
|
|
107
|
-
actionRef.current.focusSelectedOrFirstAvailable = () => {
|
|
108
|
-
trackFocusSelectedItem(appsRef.current, customAppsRef.current);
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
[actionRef, trackFocusItemAtIndex, trackFocusPanel, trackFocusSelectedItem]
|
|
113
|
-
);
|
|
114
|
-
const floatingInnerRef = (0, import_react.useCallback)(
|
|
115
|
-
(node) => {
|
|
116
|
-
floatingRefs.setFloating(node);
|
|
117
|
-
handleActionRef(node);
|
|
118
|
-
},
|
|
119
|
-
[floatingRefs.setFloating, handleActionRef]
|
|
120
|
-
);
|
|
121
|
-
(0, import_react.useEffect)(() => {
|
|
122
|
-
if (resolvedIsOpen && wasOpenedByKeyboardRef.current) {
|
|
123
|
-
trackFocusSelectedItem(apps, customApps);
|
|
124
|
-
}
|
|
125
|
-
}, [resolvedIsOpen, trackFocusSelectedItem, apps, customApps]);
|
|
126
|
-
const handleTriggerClick = (0, import_react.useCallback)(
|
|
127
|
-
(e) => {
|
|
128
|
-
wasOpenedByKeyboardRef.current = e.detail === 0;
|
|
129
|
-
onClick?.(e);
|
|
130
|
-
setOpen((prev) => !prev);
|
|
131
|
-
},
|
|
132
|
-
[onClick]
|
|
133
|
-
);
|
|
134
|
-
return {
|
|
135
|
-
// For rendering
|
|
136
|
-
Icon,
|
|
137
|
-
renderTrigger,
|
|
138
|
-
resolvedIsOpen,
|
|
139
|
-
floatingStyles,
|
|
140
|
-
arrowStyles,
|
|
141
|
-
floatingContext,
|
|
142
|
-
ownerPropsConfig,
|
|
143
|
-
// Refs
|
|
144
|
-
defaultTriggerRef,
|
|
145
|
-
triggerRef,
|
|
146
|
-
wasOpenedByKeyboardRef,
|
|
147
|
-
// Handlers
|
|
148
|
-
handleClose,
|
|
149
|
-
handleTriggerRef,
|
|
150
|
-
handleTriggerClick,
|
|
151
|
-
floatingInnerRef,
|
|
152
|
-
// Context value
|
|
153
|
-
focusTracker
|
|
154
|
-
};
|
|
155
|
-
};
|
|
156
|
-
//# sourceMappingURL=useAppPickerBehavior.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/config/useAppPickerBehavior.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable max-statements */\nimport type React from 'react';\nimport { useState, useRef, useCallback, useEffect } from 'react';\nimport { useFloatingContext } from '@elliemae/ds-floating-context';\nimport { useFocusTracker } from './useFocusTracker.js';\nimport type { useAppPicker } from './useAppPicker.js';\n\nexport const useAppPickerBehavior = (appPickerConfig: ReturnType<typeof useAppPicker>) => {\n const { propsWithDefault, ownerPropsConfig } = appPickerConfig;\n const {\n apps,\n customApps,\n icon: Icon,\n renderTrigger,\n isOpen,\n onClose,\n actionRef,\n onClick,\n onClickOutside,\n triggerRef,\n } = propsWithDefault;\n\n const focusTracker = useFocusTracker();\n const { trackFocusSelectedItem, trackFocusItemAtIndex, trackFocusPanel } = focusTracker;\n\n const [open, setOpen] = useState(false);\n const defaultTriggerRef = useRef<HTMLButtonElement>(null);\n const wasOpenedByKeyboardRef = useRef(false);\n\n // Stable refs for actionRef methods \u2014 closed over by the callback below so they are\n // always current without causing the ref callback to regenerate on every data change.\n const appsRef = useRef(apps);\n appsRef.current = apps;\n const customAppsRef = useRef(customApps);\n customAppsRef.current = customApps;\n\n const resolvedIsOpen = typeof isOpen === 'boolean' ? isOpen : open;\n\n const handleClose = useCallback(() => {\n setOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleClickOutside = useCallback(\n (e: MouseEvent | TouchEvent) => {\n setOpen(false);\n onClose?.();\n onClickOutside?.(e as MouseEvent);\n },\n [onClose, onClickOutside],\n );\n\n const {\n refs: floatingRefs,\n floatingStyles,\n arrowStyles,\n context: floatingContext,\n } = useFloatingContext({\n placement: 'bottom',\n // Arrow tip is ~6.1px above the panel top (arrowPlacementBase16 \u2248 17.5px, tip at 11.4px from box top).\n // 4px spec gap \u2192 4 + 6.1 \u2248 10px offset.\n customOffset: [0, 10],\n externallyControlledIsOpen: resolvedIsOpen,\n withoutAnimation: true,\n onClickOutside: handleClickOutside,\n });\n\n const handleTriggerRef = useCallback<React.RefCallback<HTMLButtonElement>>(\n (node) => {\n (defaultTriggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;\n floatingRefs.setReference(node);\n if (triggerRef) {\n (triggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;\n }\n },\n [floatingRefs, triggerRef],\n );\n\n // Ref callback on StyledAppPickerFloating: fires on mount with the panel node, populating\n // actionRef methods. All focus operations go through the tracker \u2014 no DOM queries.\n const handleActionRef = useCallback<React.RefCallback<HTMLDivElement>>(\n (node) => {\n if (node && actionRef?.current) {\n actionRef.current.focusToIndex = (index: number) => {\n trackFocusItemAtIndex(appsRef.current, customAppsRef.current, index);\n };\n actionRef.current.focusWrapper = () => {\n trackFocusPanel();\n };\n actionRef.current.focusSelectedOrFirstAvailable = () => {\n trackFocusSelectedItem(appsRef.current, customAppsRef.current);\n };\n }\n },\n [actionRef, trackFocusItemAtIndex, trackFocusPanel, trackFocusSelectedItem],\n );\n\n const floatingInnerRef = useCallback<React.RefCallback<HTMLDivElement>>(\n (node) => {\n (floatingRefs.setFloating as React.RefCallback<HTMLDivElement>)(node);\n handleActionRef(node);\n },\n [floatingRefs.setFloating, handleActionRef],\n );\n\n // When panel opens via keyboard, seed the focus tracker so the correct chip gets focus\n // via its innerRef callback. Non-keyboard paths are handled by AppPanel on mount.\n useEffect(() => {\n if (resolvedIsOpen && wasOpenedByKeyboardRef.current) {\n trackFocusSelectedItem(apps, customApps);\n }\n }, [resolvedIsOpen, trackFocusSelectedItem, apps, customApps]);\n\n const handleTriggerClick = useCallback(\n (e: React.MouseEvent | React.KeyboardEvent) => {\n wasOpenedByKeyboardRef.current = (e as React.MouseEvent).detail === 0;\n onClick?.(e);\n setOpen((prev) => !prev);\n },\n [onClick],\n );\n\n return {\n // For rendering\n Icon,\n renderTrigger,\n resolvedIsOpen,\n floatingStyles,\n arrowStyles,\n floatingContext,\n ownerPropsConfig,\n // Refs\n defaultTriggerRef,\n triggerRef,\n wasOpenedByKeyboardRef,\n // Handlers\n handleClose,\n handleTriggerRef,\n handleTriggerClick,\n floatingInnerRef,\n // Context value\n focusTracker,\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useState, useRef, useCallback, useEffect } from "react";
|
|
3
|
-
import { useFloatingContext } from "@elliemae/ds-floating-context";
|
|
4
|
-
import { useFocusTracker } from "./useFocusTracker.js";
|
|
5
|
-
const useAppPickerBehavior = (appPickerConfig) => {
|
|
6
|
-
const { propsWithDefault, ownerPropsConfig } = appPickerConfig;
|
|
7
|
-
const {
|
|
8
|
-
apps,
|
|
9
|
-
customApps,
|
|
10
|
-
icon: Icon,
|
|
11
|
-
renderTrigger,
|
|
12
|
-
isOpen,
|
|
13
|
-
onClose,
|
|
14
|
-
actionRef,
|
|
15
|
-
onClick,
|
|
16
|
-
onClickOutside,
|
|
17
|
-
triggerRef
|
|
18
|
-
} = propsWithDefault;
|
|
19
|
-
const focusTracker = useFocusTracker();
|
|
20
|
-
const { trackFocusSelectedItem, trackFocusItemAtIndex, trackFocusPanel } = focusTracker;
|
|
21
|
-
const [open, setOpen] = useState(false);
|
|
22
|
-
const defaultTriggerRef = useRef(null);
|
|
23
|
-
const wasOpenedByKeyboardRef = useRef(false);
|
|
24
|
-
const appsRef = useRef(apps);
|
|
25
|
-
appsRef.current = apps;
|
|
26
|
-
const customAppsRef = useRef(customApps);
|
|
27
|
-
customAppsRef.current = customApps;
|
|
28
|
-
const resolvedIsOpen = typeof isOpen === "boolean" ? isOpen : open;
|
|
29
|
-
const handleClose = useCallback(() => {
|
|
30
|
-
setOpen(false);
|
|
31
|
-
onClose?.();
|
|
32
|
-
}, [onClose]);
|
|
33
|
-
const handleClickOutside = useCallback(
|
|
34
|
-
(e) => {
|
|
35
|
-
setOpen(false);
|
|
36
|
-
onClose?.();
|
|
37
|
-
onClickOutside?.(e);
|
|
38
|
-
},
|
|
39
|
-
[onClose, onClickOutside]
|
|
40
|
-
);
|
|
41
|
-
const {
|
|
42
|
-
refs: floatingRefs,
|
|
43
|
-
floatingStyles,
|
|
44
|
-
arrowStyles,
|
|
45
|
-
context: floatingContext
|
|
46
|
-
} = useFloatingContext({
|
|
47
|
-
placement: "bottom",
|
|
48
|
-
// Arrow tip is ~6.1px above the panel top (arrowPlacementBase16 ≈ 17.5px, tip at 11.4px from box top).
|
|
49
|
-
// 4px spec gap → 4 + 6.1 ≈ 10px offset.
|
|
50
|
-
customOffset: [0, 10],
|
|
51
|
-
externallyControlledIsOpen: resolvedIsOpen,
|
|
52
|
-
withoutAnimation: true,
|
|
53
|
-
onClickOutside: handleClickOutside
|
|
54
|
-
});
|
|
55
|
-
const handleTriggerRef = useCallback(
|
|
56
|
-
(node) => {
|
|
57
|
-
defaultTriggerRef.current = node;
|
|
58
|
-
floatingRefs.setReference(node);
|
|
59
|
-
if (triggerRef) {
|
|
60
|
-
triggerRef.current = node;
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
[floatingRefs, triggerRef]
|
|
64
|
-
);
|
|
65
|
-
const handleActionRef = useCallback(
|
|
66
|
-
(node) => {
|
|
67
|
-
if (node && actionRef?.current) {
|
|
68
|
-
actionRef.current.focusToIndex = (index) => {
|
|
69
|
-
trackFocusItemAtIndex(appsRef.current, customAppsRef.current, index);
|
|
70
|
-
};
|
|
71
|
-
actionRef.current.focusWrapper = () => {
|
|
72
|
-
trackFocusPanel();
|
|
73
|
-
};
|
|
74
|
-
actionRef.current.focusSelectedOrFirstAvailable = () => {
|
|
75
|
-
trackFocusSelectedItem(appsRef.current, customAppsRef.current);
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
[actionRef, trackFocusItemAtIndex, trackFocusPanel, trackFocusSelectedItem]
|
|
80
|
-
);
|
|
81
|
-
const floatingInnerRef = useCallback(
|
|
82
|
-
(node) => {
|
|
83
|
-
floatingRefs.setFloating(node);
|
|
84
|
-
handleActionRef(node);
|
|
85
|
-
},
|
|
86
|
-
[floatingRefs.setFloating, handleActionRef]
|
|
87
|
-
);
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
if (resolvedIsOpen && wasOpenedByKeyboardRef.current) {
|
|
90
|
-
trackFocusSelectedItem(apps, customApps);
|
|
91
|
-
}
|
|
92
|
-
}, [resolvedIsOpen, trackFocusSelectedItem, apps, customApps]);
|
|
93
|
-
const handleTriggerClick = useCallback(
|
|
94
|
-
(e) => {
|
|
95
|
-
wasOpenedByKeyboardRef.current = e.detail === 0;
|
|
96
|
-
onClick?.(e);
|
|
97
|
-
setOpen((prev) => !prev);
|
|
98
|
-
},
|
|
99
|
-
[onClick]
|
|
100
|
-
);
|
|
101
|
-
return {
|
|
102
|
-
// For rendering
|
|
103
|
-
Icon,
|
|
104
|
-
renderTrigger,
|
|
105
|
-
resolvedIsOpen,
|
|
106
|
-
floatingStyles,
|
|
107
|
-
arrowStyles,
|
|
108
|
-
floatingContext,
|
|
109
|
-
ownerPropsConfig,
|
|
110
|
-
// Refs
|
|
111
|
-
defaultTriggerRef,
|
|
112
|
-
triggerRef,
|
|
113
|
-
wasOpenedByKeyboardRef,
|
|
114
|
-
// Handlers
|
|
115
|
-
handleClose,
|
|
116
|
-
handleTriggerRef,
|
|
117
|
-
handleTriggerClick,
|
|
118
|
-
floatingInnerRef,
|
|
119
|
-
// Context value
|
|
120
|
-
focusTracker
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
export {
|
|
124
|
-
useAppPickerBehavior
|
|
125
|
-
};
|
|
126
|
-
//# sourceMappingURL=useAppPickerBehavior.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/config/useAppPickerBehavior.ts"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-statements */\nimport type React from 'react';\nimport { useState, useRef, useCallback, useEffect } from 'react';\nimport { useFloatingContext } from '@elliemae/ds-floating-context';\nimport { useFocusTracker } from './useFocusTracker.js';\nimport type { useAppPicker } from './useAppPicker.js';\n\nexport const useAppPickerBehavior = (appPickerConfig: ReturnType<typeof useAppPicker>) => {\n const { propsWithDefault, ownerPropsConfig } = appPickerConfig;\n const {\n apps,\n customApps,\n icon: Icon,\n renderTrigger,\n isOpen,\n onClose,\n actionRef,\n onClick,\n onClickOutside,\n triggerRef,\n } = propsWithDefault;\n\n const focusTracker = useFocusTracker();\n const { trackFocusSelectedItem, trackFocusItemAtIndex, trackFocusPanel } = focusTracker;\n\n const [open, setOpen] = useState(false);\n const defaultTriggerRef = useRef<HTMLButtonElement>(null);\n const wasOpenedByKeyboardRef = useRef(false);\n\n // Stable refs for actionRef methods \u2014 closed over by the callback below so they are\n // always current without causing the ref callback to regenerate on every data change.\n const appsRef = useRef(apps);\n appsRef.current = apps;\n const customAppsRef = useRef(customApps);\n customAppsRef.current = customApps;\n\n const resolvedIsOpen = typeof isOpen === 'boolean' ? isOpen : open;\n\n const handleClose = useCallback(() => {\n setOpen(false);\n onClose?.();\n }, [onClose]);\n\n const handleClickOutside = useCallback(\n (e: MouseEvent | TouchEvent) => {\n setOpen(false);\n onClose?.();\n onClickOutside?.(e as MouseEvent);\n },\n [onClose, onClickOutside],\n );\n\n const {\n refs: floatingRefs,\n floatingStyles,\n arrowStyles,\n context: floatingContext,\n } = useFloatingContext({\n placement: 'bottom',\n // Arrow tip is ~6.1px above the panel top (arrowPlacementBase16 \u2248 17.5px, tip at 11.4px from box top).\n // 4px spec gap \u2192 4 + 6.1 \u2248 10px offset.\n customOffset: [0, 10],\n externallyControlledIsOpen: resolvedIsOpen,\n withoutAnimation: true,\n onClickOutside: handleClickOutside,\n });\n\n const handleTriggerRef = useCallback<React.RefCallback<HTMLButtonElement>>(\n (node) => {\n (defaultTriggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;\n floatingRefs.setReference(node);\n if (triggerRef) {\n (triggerRef as React.MutableRefObject<HTMLButtonElement | null>).current = node;\n }\n },\n [floatingRefs, triggerRef],\n );\n\n // Ref callback on StyledAppPickerFloating: fires on mount with the panel node, populating\n // actionRef methods. All focus operations go through the tracker \u2014 no DOM queries.\n const handleActionRef = useCallback<React.RefCallback<HTMLDivElement>>(\n (node) => {\n if (node && actionRef?.current) {\n actionRef.current.focusToIndex = (index: number) => {\n trackFocusItemAtIndex(appsRef.current, customAppsRef.current, index);\n };\n actionRef.current.focusWrapper = () => {\n trackFocusPanel();\n };\n actionRef.current.focusSelectedOrFirstAvailable = () => {\n trackFocusSelectedItem(appsRef.current, customAppsRef.current);\n };\n }\n },\n [actionRef, trackFocusItemAtIndex, trackFocusPanel, trackFocusSelectedItem],\n );\n\n const floatingInnerRef = useCallback<React.RefCallback<HTMLDivElement>>(\n (node) => {\n (floatingRefs.setFloating as React.RefCallback<HTMLDivElement>)(node);\n handleActionRef(node);\n },\n [floatingRefs.setFloating, handleActionRef],\n );\n\n // When panel opens via keyboard, seed the focus tracker so the correct chip gets focus\n // via its innerRef callback. Non-keyboard paths are handled by AppPanel on mount.\n useEffect(() => {\n if (resolvedIsOpen && wasOpenedByKeyboardRef.current) {\n trackFocusSelectedItem(apps, customApps);\n }\n }, [resolvedIsOpen, trackFocusSelectedItem, apps, customApps]);\n\n const handleTriggerClick = useCallback(\n (e: React.MouseEvent | React.KeyboardEvent) => {\n wasOpenedByKeyboardRef.current = (e as React.MouseEvent).detail === 0;\n onClick?.(e);\n setOpen((prev) => !prev);\n },\n [onClick],\n );\n\n return {\n // For rendering\n Icon,\n renderTrigger,\n resolvedIsOpen,\n floatingStyles,\n arrowStyles,\n floatingContext,\n ownerPropsConfig,\n // Refs\n defaultTriggerRef,\n triggerRef,\n wasOpenedByKeyboardRef,\n // Handlers\n handleClose,\n handleTriggerRef,\n handleTriggerClick,\n floatingInnerRef,\n // Context value\n focusTracker,\n };\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|