@lumx/react 4.0.1-alpha.8 → 4.1.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/package.json CHANGED
@@ -6,8 +6,8 @@
6
6
  "url": "https://github.com/lumapps/design-system/issues"
7
7
  },
8
8
  "dependencies": {
9
- "@lumx/core": "^4.0.1-alpha.8",
10
- "@lumx/icons": "^4.0.1-alpha.8",
9
+ "@lumx/core": "^4.1.0",
10
+ "@lumx/icons": "^4.1.0",
11
11
  "@popperjs/core": "^2.5.4",
12
12
  "body-scroll-lock": "^3.1.5",
13
13
  "react-popper": "^2.2.4"
@@ -41,7 +41,7 @@
41
41
  "focus-visible": "^5.0.2",
42
42
  "glob": "^7.1.6",
43
43
  "jsdom": "^27.2.0",
44
- "lodash": "4.17.21",
44
+ "lodash": "4.17.23",
45
45
  "react": "^18.3.1",
46
46
  "react-dom": "^18.3.1",
47
47
  "rollup": "^4.53.3",
@@ -58,7 +58,7 @@
58
58
  "vitest": "^3.0.0"
59
59
  },
60
60
  "peerDependencies": {
61
- "lodash": "4.17.21",
61
+ "lodash": "4.17.23",
62
62
  "react": ">= 17.0.2",
63
63
  "react-dom": ">= 17.0.2"
64
64
  },
@@ -90,5 +90,5 @@
90
90
  "build:storybook": "storybook build"
91
91
  },
92
92
  "sideEffects": false,
93
- "version": "4.0.1-alpha.8"
93
+ "version": "4.1.0"
94
94
  }
package/utils/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import React__default, { RefObject } from 'react';
2
2
  import { Falsy } from '@lumx/core/js/types';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ObjectValues } from '@lumx/core/src/js/types/ObjectValues';
4
5
 
5
6
  interface ClickAwayParameters {
6
7
  /**
@@ -78,5 +79,266 @@ declare function DisabledStateProvider({ children, ...value }: DisabledStateProv
78
79
  */
79
80
  declare function useDisabledStateContext(): DisabledStateContextValue;
80
81
 
81
- export { ClickAwayProvider, DisabledStateProvider, Portal, PortalProvider, useDisabledStateContext };
82
+ declare const LOOP_AROUND_TYPES: {
83
+ /**
84
+ * Will continue navigation to the next row or column and loop back to the start
85
+ * when the last tab stop is reached
86
+ */
87
+ readonly nextLoop: "next-loop";
88
+ /**
89
+ * Will continue navigation to the next row or column until
90
+ * the last tab stop is reached
91
+ */
92
+ readonly nextEnd: "next-end";
93
+ /**
94
+ * Will loop within the current row or column
95
+ */
96
+ readonly inside: "inside";
97
+ };
98
+
99
+ /**
100
+ * Base hook options
101
+ */
102
+ type BaseHookOptions = [
103
+ /**
104
+ * The DOM element to include.
105
+ * This must be the same DOM element for the lifetime of the containing component.
106
+ */
107
+ ref: React.RefObject<Element>,
108
+ /**
109
+ * Whether or not the DOM element is currently enabled. This value can be updated as appropriate throughout the
110
+ * lifetime of the containing component.
111
+ */
112
+ disabled?: boolean,
113
+ /**
114
+ * An optional string value that must be populated if the roving tabindex is being used in a grid. In that case,
115
+ * set it to a unique key for all tabStops part of the same row that the given DOM element is currently part of. You can update this
116
+ * row key as appropriate throughout the lifetime of the containing component, for example if the shape of the
117
+ * grid can change dynamically.
118
+ */
119
+ rowKey?: string | number | null,
120
+ /** Whether the tab stop should be set as selected by default */
121
+ autofocus?: boolean
122
+ ];
123
+ type KeyDirection = 'horizontal' | 'vertical' | 'both';
124
+ type LoopTypes = ObjectValues<typeof LOOP_AROUND_TYPES>;
125
+ /**
126
+ * The behavior to set when the end of a column or row is reached
127
+ */
128
+ type LoopAroundByAxis = {
129
+ col: LoopTypes;
130
+ row: LoopTypes;
131
+ };
132
+ /**
133
+ * The LoopAround behavior to have.
134
+ * Can be a boolean as a shortcut
135
+ *
136
+ * * true => { row: 'next-loop', col: 'next-loop' }
137
+ * * false => { row: 'next-end', col: 'next-end' }
138
+ */
139
+ type LoopAround = LoopAroundByAxis | boolean;
140
+ interface MovingFocusOptions {
141
+ /**
142
+ * An optional direction value that only applies when the roving tabindex is not being used within a grid.
143
+ * This value specifies the arrow key behaviour.
144
+ * The default value is 'horizontal'.
145
+ * When set to 'horizontal' then only the ArrowLeft and ArrowRight keys move to the previous and next tab stop
146
+ * respectively.
147
+ * When set to 'vertical' then only the ArrowUp and ArrowDown keys move to the previous and next tab stop
148
+ * respectively.
149
+ * When set to 'both' then both the ArrowLeft and ArrowUp keys can be used to move to the previous tab stop, and
150
+ * both the ArrowRight and ArrowDown keys can be used to move to the next tab stop.
151
+ * If you do not pass an explicit value then the 'horizontal' behaviour applies.
152
+ */
153
+ direction: KeyDirection;
154
+ /**
155
+ * Direction in which initial virtual focus must be set focused on the virtual focus parent.
156
+ * Ex: With `firstFocusDirection: vertical`, pressing "left" and "right" arrows while virtual focus is
157
+ * not enabled yet will do nothing.
158
+ * /!\ Only used with `virtualFocus` hooks.
159
+ */
160
+ firstFocusDirection?: KeyDirection;
161
+ /**
162
+ * An optional flag that, when set to `true`, will loop the tabindex around when the user tries to tab to the
163
+ * first or last elements in the roving tabindex, rather than stopping.
164
+ * The default value is `false` (no looping).
165
+ * Note that this option does not apply if the roving tabindex is being used on a grid.
166
+ */
167
+ loopAround: LoopAround;
168
+ /**
169
+ * Id of the tab stop should accept focus if selectedId is undefined.
170
+ */
171
+ defaultSelectedId: string | null;
172
+ /**
173
+ * Autofocus first or last item after the list/grid is mounted.
174
+ */
175
+ autofocus?: 'first' | 'last';
176
+ /**
177
+ * The axis on which the "skip" shortcuts (home / end) must function.
178
+ */
179
+ gridJumpToShortcutDirection?: 'vertical' | 'horizontal';
180
+ /**
181
+ * Enable default selected item focusing
182
+ *
183
+ * Note: The `allowFocusing` state property is set at "false" by default until an interaction is made.
184
+ * This is required to delay focusing of the selected tab stop DOM element
185
+ * until the user has started interacting with the roving tabindex's controls.
186
+ * If this delay did not occur, the selected control would be focused as soon as it was mounted, which is
187
+ * unlikely to be the desired behaviour for the page.
188
+ */
189
+ allowFocusing: boolean;
190
+ /**
191
+ * An optional an unique key.
192
+ * If this key is set, tab stops will be re-registered each time the key changes.
193
+ * If this key is unset, tab stops will only be registered on mount and unregistered on unmount.
194
+ *
195
+ * This can be useful to set if you have cases where your tab stops might be reordered without being unmounted.
196
+ */
197
+ listKey?: string;
198
+ }
199
+ type TabStopRowKey = string | number;
200
+ type BaseTypeStop = {
201
+ id: string;
202
+ domElementRef: React.RefObject<Element>;
203
+ disabled: boolean;
204
+ rowKey: TabStopRowKey | null;
205
+ autofocus?: boolean;
206
+ };
207
+ type TabStop = Readonly<BaseTypeStop>;
208
+ type GridMap = {
209
+ tabStopsByRowKey: Record<TabStopRowKey, TabStop[]>;
210
+ rowKeys: Array<TabStopRowKey>;
211
+ };
212
+ type State = Readonly<{
213
+ /**
214
+ * Id of the tab stop that can currently accept focus.
215
+ */
216
+ selectedId: string | null;
217
+ /** Whether the user is currently using keyboard navigation */
218
+ isUsingKeyboard: boolean;
219
+ /**
220
+ * Array of tab stops
221
+ */
222
+ tabStops: readonly TabStop[];
223
+ /**
224
+ * Note: The gridMap is only created if row-related navigation occurs (e.g., move to row start or end).
225
+ * The map gets cleared if registering, unregistering, or updating.
226
+ */
227
+ gridMap: GridMap | null;
228
+ /** The loop behavior to apply to the columns and rows */
229
+ loopAround: LoopAroundByAxis;
230
+ } & Omit<MovingFocusOptions, 'loopAround'>>;
231
+ type RegisterAction = {
232
+ type: 'REGISTER_TAB_STOP';
233
+ payload: TabStop;
234
+ };
235
+ type UnregisterAction = {
236
+ type: 'UNREGISTER_TAB_STOP';
237
+ payload: {
238
+ id: TabStop['id'];
239
+ };
240
+ };
241
+ type UpdateTabStopAction = {
242
+ type: 'UPDATE_TAB_STOP';
243
+ payload: Pick<TabStop, 'id' | 'rowKey' | 'disabled'>;
244
+ };
245
+ type KeyNavAction = {
246
+ type: 'KEY_NAV';
247
+ payload: {
248
+ id?: TabStop['id'];
249
+ key: string;
250
+ ctrlKey: boolean;
251
+ };
252
+ };
253
+ type SetAllowFocusingAction = {
254
+ type: 'SET_ALLOW_FOCUSING';
255
+ payload: {
256
+ allow: boolean;
257
+ isKeyboardNavigation?: boolean;
258
+ };
259
+ };
260
+ type ResetSelectedTabStopAction = {
261
+ type: 'RESET_SELECTED_TAB_STOP';
262
+ };
263
+ type SelectTabStopAction = {
264
+ type: 'SELECT_TAB_STOP';
265
+ payload: {
266
+ id: TabStop['id'];
267
+ type?: 'pointer' | 'keyboard';
268
+ };
269
+ };
270
+ type OptionsUpdatedAction = {
271
+ type: 'OPTIONS_UPDATED';
272
+ payload: MovingFocusOptions;
273
+ };
274
+ type Action = RegisterAction | UnregisterAction | UpdateTabStopAction | KeyNavAction | SelectTabStopAction | OptionsUpdatedAction | SetAllowFocusingAction | ResetSelectedTabStopAction;
275
+
276
+ interface MovingFocusProviderProps {
277
+ /**
278
+ * The child content, which will include the DOM elements to rove between using the tab key.
279
+ */
280
+ children: React__default.ReactNode;
281
+ /**
282
+ * An optional object to customize the behaviour of the moving focus. It is fine to pass a new object every time
283
+ * the containing component is rendered, and the options can be updated at any time.
284
+ */
285
+ options?: Partial<MovingFocusOptions>;
286
+ }
287
+ /**
288
+ * Creates a roving tabindex context.
289
+ */
290
+ declare const MovingFocusProvider: React__default.FC<MovingFocusProviderProps>;
291
+
292
+ type MovingFocusContext = Readonly<{
293
+ state: State;
294
+ dispatch: React__default.Dispatch<Action>;
295
+ }>;
296
+ declare const MovingFocusContext: React__default.Context<Readonly<{
297
+ state: State;
298
+ dispatch: React__default.Dispatch<Action>;
299
+ }>>;
300
+
301
+ /**
302
+ * Hook options
303
+ */
304
+ type Options = [
305
+ /** The DOM id of the tab stop. */
306
+ id: string,
307
+ ...baseOptions: BaseHookOptions
308
+ ];
309
+ /**
310
+ * Hook to use in tab stop element of a virtual focus (ex: options of a listbox in a combobox).
311
+ *
312
+ * @returns true if the current tab stop has virtual focus
313
+ */
314
+ declare const useVirtualFocus: (...args: Options) => boolean;
315
+
316
+ /**
317
+ * Hook to use in a virtual focus parent (ex: `aria-activedescendant` on the input of a combobox).
318
+ * * @returns the id of the currently active tab stop (virtual focus)
319
+ */
320
+ declare const useVirtualFocusParent: (ref: React__default.RefObject<HTMLElement>) => string | undefined;
321
+
322
+ /**
323
+ * A tuple of values to be applied by the containing component for the roving tabindex to work correctly.
324
+ */
325
+ type Output = [
326
+ /** The tabIndex value to apply to the tab stop element. */
327
+ tabIndex: number,
328
+ /** Whether focus() should be invoked on the tab stop element. */
329
+ focused: boolean,
330
+ /**
331
+ * The onKeyDown callback to apply to the tab stop element. If the key press is relevant to the hook then
332
+ * event.preventDefault() will be invoked on the event.
333
+ */
334
+ handleKeyDown: (event: React__default.KeyboardEvent) => void,
335
+ /** The onClick callback to apply to the tab stop element. */
336
+ handleClick: () => void
337
+ ];
338
+ /**
339
+ * Includes the given DOM element in the current roving tabindex.
340
+ */
341
+ declare const useRovingTabIndex: (...args: BaseHookOptions) => Output;
342
+
343
+ export { ClickAwayProvider, DisabledStateProvider, MovingFocusContext, MovingFocusProvider, Portal, PortalProvider, useDisabledStateContext, useRovingTabIndex, useVirtualFocus, useVirtualFocusParent };
82
344
  export type { PortalInit, PortalProps, PortalProviderProps };