@proyecto-viviana/solidaria-components 0.3.0 → 0.3.2
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/Button.d.ts.map +1 -1
- package/dist/ComboBox.d.ts +4 -1
- package/dist/ComboBox.d.ts.map +1 -1
- package/dist/DatePicker.d.ts.map +1 -1
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Modal.d.ts.map +1 -1
- package/dist/NumberField.d.ts.map +1 -1
- package/dist/Popover.d.ts.map +1 -1
- package/dist/TagGroup.d.ts.map +1 -1
- package/dist/TextField.d.ts +1 -0
- package/dist/TextField.d.ts.map +1 -1
- package/dist/Toast.d.ts.map +1 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/index.js +264 -37
- package/dist/index.js.map +1 -1
- package/dist/index.jsx +264 -37
- package/dist/index.jsx.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/Button.tsx +69 -22
- package/src/ComboBox.tsx +77 -9
- package/src/DatePicker.tsx +60 -5
- package/src/Menu.tsx +49 -6
- package/src/Modal.tsx +8 -1
- package/src/NumberField.tsx +22 -2
- package/src/Popover.tsx +19 -2
- package/src/TagGroup.tsx +1 -0
- package/src/TextField.tsx +32 -7
- package/src/Toast.tsx +7 -1
- package/src/Tooltip.tsx +52 -7
- package/src/utils.tsx +9 -5
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proyecto-viviana/solidaria-components",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Pre-wired headless components for SolidJS - port of react-aria-components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@internationalized/date": "^3.8.0",
|
|
41
|
-
"@proyecto-viviana/
|
|
42
|
-
"@proyecto-viviana/
|
|
41
|
+
"@proyecto-viviana/solid-stately": "0.3.0",
|
|
42
|
+
"@proyecto-viviana/solidaria": "0.3.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"solid-js": "^1.9.11"
|
package/src/Button.tsx
CHANGED
|
@@ -97,6 +97,44 @@ function createLiveCustomRootProps(
|
|
|
97
97
|
return props;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
const buttonAriaOverrideProps = [
|
|
101
|
+
"aria-label",
|
|
102
|
+
"aria-labelledby",
|
|
103
|
+
"aria-describedby",
|
|
104
|
+
"aria-details",
|
|
105
|
+
"aria-haspopup",
|
|
106
|
+
"aria-expanded",
|
|
107
|
+
"aria-controls",
|
|
108
|
+
"aria-pressed",
|
|
109
|
+
"aria-current",
|
|
110
|
+
"aria-disabled",
|
|
111
|
+
] as const;
|
|
112
|
+
|
|
113
|
+
function createForwardedAriaButtonProps(
|
|
114
|
+
source: AriaButtonProps,
|
|
115
|
+
overrides: AriaButtonProps,
|
|
116
|
+
): AriaButtonProps {
|
|
117
|
+
const result = {} as AriaButtonProps;
|
|
118
|
+
|
|
119
|
+
for (const key in source) {
|
|
120
|
+
Object.defineProperty(result, key, {
|
|
121
|
+
enumerable: true,
|
|
122
|
+
configurable: true,
|
|
123
|
+
get() {
|
|
124
|
+
return (source as Record<string, unknown>)[key];
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (const key in overrides) {
|
|
130
|
+
const descriptor = Object.getOwnPropertyDescriptor(overrides, key);
|
|
131
|
+
if (!descriptor) continue;
|
|
132
|
+
Object.defineProperty(result, key, { ...descriptor, enumerable: true, configurable: true });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
100
138
|
export interface ButtonRenderProps {
|
|
101
139
|
/** Whether the button is currently hovered with a mouse. */
|
|
102
140
|
isHovered: boolean;
|
|
@@ -238,28 +276,29 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
238
276
|
}
|
|
239
277
|
};
|
|
240
278
|
|
|
241
|
-
const buttonAria = createButton(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
279
|
+
const buttonAria = createButton(
|
|
280
|
+
createForwardedAriaButtonProps(ariaProps, {
|
|
281
|
+
onPress: handlePress,
|
|
282
|
+
get onPressStart() {
|
|
283
|
+
return resolvePending() ? undefined : ariaProps.onPressStart;
|
|
284
|
+
},
|
|
285
|
+
get onPressEnd() {
|
|
286
|
+
return resolvePending() ? undefined : ariaProps.onPressEnd;
|
|
287
|
+
},
|
|
288
|
+
get onPressUp() {
|
|
289
|
+
return resolvePending() ? undefined : ariaProps.onPressUp;
|
|
290
|
+
},
|
|
291
|
+
get onPressChange() {
|
|
292
|
+
return resolvePending() ? undefined : ariaProps.onPressChange;
|
|
293
|
+
},
|
|
294
|
+
get onClick() {
|
|
295
|
+
return resolvePending() ? undefined : ariaProps.onClick;
|
|
296
|
+
},
|
|
297
|
+
get isDisabled() {
|
|
298
|
+
return resolveDisabled() || resolvePending();
|
|
299
|
+
},
|
|
300
|
+
}),
|
|
301
|
+
);
|
|
263
302
|
|
|
264
303
|
const { isFocused, isFocusVisible, focusProps } = createFocusRing();
|
|
265
304
|
|
|
@@ -394,6 +433,13 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
394
433
|
}
|
|
395
434
|
return next;
|
|
396
435
|
};
|
|
436
|
+
const directAriaProps = () => {
|
|
437
|
+
const next: Record<string, unknown> = {};
|
|
438
|
+
for (const name of buttonAriaOverrideProps) {
|
|
439
|
+
next[name] = (ariaProps as Record<string, unknown>)[name];
|
|
440
|
+
}
|
|
441
|
+
return next;
|
|
442
|
+
};
|
|
397
443
|
const disablePendingInteractions = (props: Record<string, unknown>) => {
|
|
398
444
|
if (!resolvePending()) {
|
|
399
445
|
return props;
|
|
@@ -433,6 +479,7 @@ export function Button(props: ButtonProps): JSX.Element {
|
|
|
433
479
|
({
|
|
434
480
|
...domProps(),
|
|
435
481
|
...disablePendingInteractions(cleanButtonProps()),
|
|
482
|
+
...directAriaProps(),
|
|
436
483
|
...triggerAriaProps(),
|
|
437
484
|
...cleanFocusProps(),
|
|
438
485
|
...cleanHoverProps(),
|
package/src/ComboBox.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type JSX,
|
|
10
10
|
type Accessor,
|
|
11
11
|
createContext,
|
|
12
|
+
createEffect,
|
|
12
13
|
createMemo,
|
|
13
14
|
onCleanup,
|
|
14
15
|
splitProps,
|
|
@@ -290,6 +291,7 @@ export interface ComboBoxOptionProps<T>
|
|
|
290
291
|
|
|
291
292
|
interface ComboBoxContextValue<T> {
|
|
292
293
|
state: ComboBoxState<T>;
|
|
294
|
+
listState: ListState<T>;
|
|
293
295
|
inputProps: () => JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
294
296
|
buttonProps: () => JSX.HTMLAttributes<HTMLElement>;
|
|
295
297
|
listBoxProps: () => JSX.HTMLAttributes<HTMLElement>;
|
|
@@ -308,13 +310,31 @@ interface ComboBoxContextValue<T> {
|
|
|
308
310
|
setTriggerRef: (el: HTMLElement | null) => void;
|
|
309
311
|
listBoxRef: () => HTMLElement | null;
|
|
310
312
|
setListBoxRef: (el: HTMLElement | null) => void;
|
|
313
|
+
registerOptionAction: (key: Key, action: (() => void) | undefined) => void;
|
|
314
|
+
runOptionAction: (key: Key) => void;
|
|
311
315
|
slots?: Record<string, Partial<ComboBoxProps<T>>>;
|
|
312
316
|
}
|
|
313
317
|
|
|
318
|
+
type InputKeyboardEvent = KeyboardEvent & {
|
|
319
|
+
currentTarget: HTMLInputElement;
|
|
320
|
+
target: Element;
|
|
321
|
+
};
|
|
322
|
+
|
|
314
323
|
export const ComboBoxContext = createContext<ComboBoxContextValue<unknown> | null>(null);
|
|
315
324
|
export const ComboBoxStateContext = createContext<ComboBoxState<unknown> | null>(null);
|
|
316
325
|
export const ComboBoxValueContext = ComboBoxContext;
|
|
317
326
|
|
|
327
|
+
function callInputKeyDown(
|
|
328
|
+
handler: JSX.EventHandlerUnion<HTMLInputElement, KeyboardEvent> | undefined,
|
|
329
|
+
event: InputKeyboardEvent,
|
|
330
|
+
) {
|
|
331
|
+
if (typeof handler === "function") {
|
|
332
|
+
handler(event);
|
|
333
|
+
} else if (handler) {
|
|
334
|
+
handler[0](handler[1], event);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
318
338
|
/**
|
|
319
339
|
* A combobox combines a text input with a listbox, allowing users to filter a list of options.
|
|
320
340
|
*/
|
|
@@ -360,6 +380,10 @@ export function ComboBox<T>(props: ComboBoxProps<T>): JSX.Element {
|
|
|
360
380
|
let buttonRef: HTMLElement | null = null;
|
|
361
381
|
let triggerRef: HTMLElement | null = null;
|
|
362
382
|
let listBoxRef: HTMLElement | null = null;
|
|
383
|
+
const optionActions = new Map<Key, () => void>();
|
|
384
|
+
const runOptionAction = (key: Key) => {
|
|
385
|
+
optionActions.get(key)?.();
|
|
386
|
+
};
|
|
363
387
|
|
|
364
388
|
const state = createComboBoxState<T>({
|
|
365
389
|
get items() {
|
|
@@ -441,6 +465,7 @@ export function ComboBox<T>(props: ComboBoxProps<T>): JSX.Element {
|
|
|
441
465
|
return ariaProps.isRequired;
|
|
442
466
|
},
|
|
443
467
|
});
|
|
468
|
+
const listState = createComboBoxListStateAdapter(state);
|
|
444
469
|
|
|
445
470
|
const effectiveFormValue = createMemo<"key" | "text">(() => {
|
|
446
471
|
if (stateProps.allowsCustomValue) {
|
|
@@ -472,6 +497,28 @@ export function ComboBox<T>(props: ComboBoxProps<T>): JSX.Element {
|
|
|
472
497
|
() => listBoxRef,
|
|
473
498
|
);
|
|
474
499
|
|
|
500
|
+
const getInputProps = () => {
|
|
501
|
+
const inputProps = comboBoxAria.inputProps;
|
|
502
|
+
const originalOnKeyDown = inputProps.onKeyDown;
|
|
503
|
+
|
|
504
|
+
return {
|
|
505
|
+
...inputProps,
|
|
506
|
+
onKeyDown: (event: InputKeyboardEvent) => {
|
|
507
|
+
const focusedKey = state.focusedKey();
|
|
508
|
+
const shouldRunAction =
|
|
509
|
+
event.key === "Enter" &&
|
|
510
|
+
state.isOpen() &&
|
|
511
|
+
focusedKey != null &&
|
|
512
|
+
!state.isKeyDisabled(focusedKey);
|
|
513
|
+
const optionAction = shouldRunAction ? optionActions.get(focusedKey) : undefined;
|
|
514
|
+
|
|
515
|
+
callInputKeyDown(originalOnKeyDown, event);
|
|
516
|
+
|
|
517
|
+
optionAction?.();
|
|
518
|
+
},
|
|
519
|
+
} as JSX.InputHTMLAttributes<HTMLInputElement>;
|
|
520
|
+
};
|
|
521
|
+
|
|
475
522
|
const { isHovered, hoverProps } = createHover({
|
|
476
523
|
get isDisabled() {
|
|
477
524
|
return ariaProps.isDisabled;
|
|
@@ -519,9 +566,13 @@ export function ComboBox<T>(props: ComboBoxProps<T>): JSX.Element {
|
|
|
519
566
|
value={
|
|
520
567
|
{
|
|
521
568
|
state,
|
|
522
|
-
|
|
569
|
+
listState,
|
|
570
|
+
inputProps: getInputProps,
|
|
523
571
|
buttonProps: () => comboBoxAria.buttonProps,
|
|
524
|
-
listBoxProps: () =>
|
|
572
|
+
listBoxProps: () => ({
|
|
573
|
+
...comboBoxAria.listBoxProps,
|
|
574
|
+
onAction: runOptionAction,
|
|
575
|
+
}),
|
|
525
576
|
labelProps: () => comboBoxAria.labelProps,
|
|
526
577
|
descriptionProps: () => comboBoxAria.descriptionProps,
|
|
527
578
|
errorMessageProps: () => comboBoxAria.errorMessageProps,
|
|
@@ -545,6 +596,14 @@ export function ComboBox<T>(props: ComboBoxProps<T>): JSX.Element {
|
|
|
545
596
|
setListBoxRef: (el) => {
|
|
546
597
|
listBoxRef = el;
|
|
547
598
|
},
|
|
599
|
+
registerOptionAction: (key, action) => {
|
|
600
|
+
if (action) {
|
|
601
|
+
optionActions.set(key, action);
|
|
602
|
+
} else {
|
|
603
|
+
optionActions.delete(key);
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
runOptionAction,
|
|
548
607
|
slots: local.slots,
|
|
549
608
|
} as ComboBoxContextValue<unknown>
|
|
550
609
|
}
|
|
@@ -850,7 +909,7 @@ export function ComboBoxListBox<T>(props: ComboBoxListBoxProps<T>): JSX.Element
|
|
|
850
909
|
throw new Error("ComboBoxListBox must be used within a ComboBox");
|
|
851
910
|
}
|
|
852
911
|
const context = rawContext as ComboBoxContextValue<T>;
|
|
853
|
-
const { state: comboBoxState, isOpen, inputRef, buttonRef, setListBoxRef } = context;
|
|
912
|
+
const { state: comboBoxState, listState, isOpen, inputRef, buttonRef, setListBoxRef } = context;
|
|
854
913
|
const state = comboBoxState;
|
|
855
914
|
|
|
856
915
|
let listBoxRef: HTMLUListElement | undefined;
|
|
@@ -880,7 +939,7 @@ export function ComboBoxListBox<T>(props: ComboBoxListBoxProps<T>): JSX.Element
|
|
|
880
939
|
// Create listbox aria props using ComboBoxState's ListState-compatible interface
|
|
881
940
|
const { listBoxProps } = createListBox(
|
|
882
941
|
context.listBoxProps as unknown as AriaListBoxProps,
|
|
883
|
-
|
|
942
|
+
listState,
|
|
884
943
|
);
|
|
885
944
|
|
|
886
945
|
const renderValues = createMemo<ComboBoxListBoxRenderProps>(() => ({
|
|
@@ -976,15 +1035,24 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
976
1035
|
|
|
977
1036
|
const stateContext = useContext(ComboBoxStateContext);
|
|
978
1037
|
const comboBoxContext = useContext(ComboBoxContext);
|
|
979
|
-
if (!stateContext) {
|
|
1038
|
+
if (!stateContext || !comboBoxContext) {
|
|
980
1039
|
throw new Error("ComboBoxOption must be used within a ComboBox");
|
|
981
1040
|
}
|
|
982
1041
|
const state = stateContext as ComboBoxState<T>;
|
|
1042
|
+
const listState = (comboBoxContext as ComboBoxContextValue<T>).listState;
|
|
983
1043
|
const optionId = () => {
|
|
984
1044
|
const listBoxId = getComboBoxData(state as ComboBoxState<unknown>)?.listBoxId;
|
|
985
1045
|
return listBoxId ? `${listBoxId}-option-${local.id}` : String(local.id);
|
|
986
1046
|
};
|
|
987
1047
|
|
|
1048
|
+
createEffect(() => {
|
|
1049
|
+
const key = local.id;
|
|
1050
|
+
comboBoxContext?.registerOptionAction(key, local.onAction);
|
|
1051
|
+
onCleanup(() => {
|
|
1052
|
+
comboBoxContext?.registerOptionAction(key, undefined);
|
|
1053
|
+
});
|
|
1054
|
+
});
|
|
1055
|
+
|
|
988
1056
|
// Create option aria props using ComboBoxState's ListState-compatible interface
|
|
989
1057
|
const optionAria = createOption<T>(
|
|
990
1058
|
{
|
|
@@ -998,9 +1066,6 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
998
1066
|
get "aria-label"() {
|
|
999
1067
|
return ariaProps["aria-label"];
|
|
1000
1068
|
},
|
|
1001
|
-
get onAction() {
|
|
1002
|
-
return local.onAction;
|
|
1003
|
-
},
|
|
1004
1069
|
shouldSelectOnPressUp: true,
|
|
1005
1070
|
shouldFocusOnHover: true,
|
|
1006
1071
|
shouldUseVirtualFocus: true,
|
|
@@ -1014,8 +1079,11 @@ export function ComboBoxOption<T>(props: ComboBoxOptionProps<T>): JSX.Element {
|
|
|
1014
1079
|
get onHoverChange() {
|
|
1015
1080
|
return ariaProps.onHoverChange;
|
|
1016
1081
|
},
|
|
1082
|
+
get onAction() {
|
|
1083
|
+
return local.onAction;
|
|
1084
|
+
},
|
|
1017
1085
|
},
|
|
1018
|
-
|
|
1086
|
+
listState,
|
|
1019
1087
|
);
|
|
1020
1088
|
|
|
1021
1089
|
const isOptionFocusVisible = () =>
|
package/src/DatePicker.tsx
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
type CalendarState,
|
|
40
40
|
type RangeCalendarState,
|
|
41
41
|
type DateFieldStateProps,
|
|
42
|
+
type DatePickerStateOptions,
|
|
42
43
|
type CalendarDate,
|
|
43
44
|
type DateValue,
|
|
44
45
|
type RangeCalendarStateProps,
|
|
@@ -349,11 +350,65 @@ function DatePickerInner<T extends DateValue = CalendarDate>(
|
|
|
349
350
|
const [triggerRef, setTriggerRef] = createSignal<HTMLElement | null>(null);
|
|
350
351
|
const [fieldRef, setFieldRef] = createSignal<HTMLDivElement | null>(null);
|
|
351
352
|
|
|
352
|
-
// Unified state using createDatePickerState as single source of truth
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
353
|
+
// Unified state using createDatePickerState as single source of truth.
|
|
354
|
+
// Use getters here so controlled props keep tracking after splitProps.
|
|
355
|
+
const datePickerStateProps = {
|
|
356
|
+
get value() {
|
|
357
|
+
return stateProps.value;
|
|
358
|
+
},
|
|
359
|
+
get defaultValue() {
|
|
360
|
+
return stateProps.defaultValue;
|
|
361
|
+
},
|
|
362
|
+
get onChange() {
|
|
363
|
+
return stateProps.onChange;
|
|
364
|
+
},
|
|
365
|
+
get minValue() {
|
|
366
|
+
return stateProps.minValue;
|
|
367
|
+
},
|
|
368
|
+
get maxValue() {
|
|
369
|
+
return stateProps.maxValue;
|
|
370
|
+
},
|
|
371
|
+
get isDisabled() {
|
|
372
|
+
return stateProps.isDisabled;
|
|
373
|
+
},
|
|
374
|
+
get isReadOnly() {
|
|
375
|
+
return stateProps.isReadOnly;
|
|
376
|
+
},
|
|
377
|
+
get isRequired() {
|
|
378
|
+
return stateProps.isRequired;
|
|
379
|
+
},
|
|
380
|
+
get granularity() {
|
|
381
|
+
return stateProps.granularity;
|
|
382
|
+
},
|
|
383
|
+
get hourCycle() {
|
|
384
|
+
return stateProps.hourCycle;
|
|
385
|
+
},
|
|
386
|
+
get hideTimeZone() {
|
|
387
|
+
return stateProps.hideTimeZone;
|
|
388
|
+
},
|
|
389
|
+
get placeholderValue() {
|
|
390
|
+
return stateProps.placeholderValue;
|
|
391
|
+
},
|
|
392
|
+
get shouldCloseOnSelect() {
|
|
393
|
+
return local.shouldCloseOnSelect;
|
|
394
|
+
},
|
|
395
|
+
get defaultOpen() {
|
|
396
|
+
return stateProps.defaultOpen;
|
|
397
|
+
},
|
|
398
|
+
get isOpen() {
|
|
399
|
+
return stateProps.isOpen;
|
|
400
|
+
},
|
|
401
|
+
get onOpenChange() {
|
|
402
|
+
return stateProps.onOpenChange;
|
|
403
|
+
},
|
|
404
|
+
get isDateUnavailable() {
|
|
405
|
+
return stateProps.isDateUnavailable;
|
|
406
|
+
},
|
|
407
|
+
get validationState() {
|
|
408
|
+
return stateProps.validationState;
|
|
409
|
+
},
|
|
410
|
+
} satisfies DatePickerStateOptions<T>;
|
|
411
|
+
const datePickerState = createDatePickerState<T>(datePickerStateProps);
|
|
357
412
|
|
|
358
413
|
const overlayState = {
|
|
359
414
|
get isOpen() {
|
package/src/Menu.tsx
CHANGED
|
@@ -373,6 +373,7 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
373
373
|
const triggerId = createUniqueId();
|
|
374
374
|
const menuId = createUniqueId();
|
|
375
375
|
let hoverTimeout: number | undefined;
|
|
376
|
+
let hasPointerHover = false;
|
|
376
377
|
const delay = () => props.delay ?? 200;
|
|
377
378
|
|
|
378
379
|
const clearHoverTimeout = () => {
|
|
@@ -387,6 +388,16 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
387
388
|
state.open();
|
|
388
389
|
};
|
|
389
390
|
|
|
391
|
+
const queueOpenSubmenu = () => {
|
|
392
|
+
clearHoverTimeout();
|
|
393
|
+
const open = () => state.open();
|
|
394
|
+
if (typeof queueMicrotask === "function") {
|
|
395
|
+
queueMicrotask(open);
|
|
396
|
+
} else {
|
|
397
|
+
Promise.resolve().then(open);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
390
401
|
const scheduleOpen = () => {
|
|
391
402
|
clearHoverTimeout();
|
|
392
403
|
hoverTimeout = window.setTimeout(() => {
|
|
@@ -395,6 +406,28 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
395
406
|
}, delay());
|
|
396
407
|
};
|
|
397
408
|
|
|
409
|
+
const schedulePointerOpen = (event: PointerEvent) => {
|
|
410
|
+
hasPointerHover = true;
|
|
411
|
+
if (event.isTrusted === false) {
|
|
412
|
+
queueOpenSubmenu();
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
scheduleOpen();
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const openFromMouseHover = () => {
|
|
420
|
+
if (state.isOpen()) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (hasPointerHover) {
|
|
425
|
+
scheduleOpen();
|
|
426
|
+
} else {
|
|
427
|
+
queueOpenSubmenu();
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
398
431
|
onCleanup(clearHoverTimeout);
|
|
399
432
|
|
|
400
433
|
const menuTriggerContext = createMemo<MenuTriggerContextValue>(() => ({
|
|
@@ -430,17 +463,22 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
|
|
|
430
463
|
props: () => ({
|
|
431
464
|
id: triggerId,
|
|
432
465
|
"aria-haspopup": "menu",
|
|
433
|
-
"aria-expanded"
|
|
434
|
-
|
|
466
|
+
get "aria-expanded"() {
|
|
467
|
+
return state.isOpen() || undefined;
|
|
468
|
+
},
|
|
469
|
+
get "aria-controls"() {
|
|
470
|
+
return state.isOpen() ? menuId : undefined;
|
|
471
|
+
},
|
|
435
472
|
onPointerEnter: (event: PointerEvent) => {
|
|
436
473
|
if (event.pointerType === "touch") return;
|
|
437
|
-
|
|
474
|
+
schedulePointerOpen(event);
|
|
438
475
|
},
|
|
439
476
|
onPointerOver: (event: PointerEvent) => {
|
|
440
477
|
if (event.pointerType === "touch") return;
|
|
441
|
-
|
|
478
|
+
schedulePointerOpen(event);
|
|
442
479
|
},
|
|
443
|
-
onMouseEnter:
|
|
480
|
+
onMouseEnter: openFromMouseHover,
|
|
481
|
+
onMouseOver: openFromMouseHover,
|
|
444
482
|
onKeyDown: (event: KeyboardEvent) => {
|
|
445
483
|
if (event.key === "ArrowRight" || event.key === "Enter" || event.key === " ") {
|
|
446
484
|
event.preventDefault();
|
|
@@ -1028,6 +1066,11 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1028
1066
|
dndDropIndicator(index, position) ??
|
|
1029
1067
|
parentCollectionRenderer?.renderDropIndicator?.(index, position),
|
|
1030
1068
|
}));
|
|
1069
|
+
const menuItemContextValue = createMemo<MenuItemContextValue>(() =>
|
|
1070
|
+
local.shouldCloseOnSelect !== undefined
|
|
1071
|
+
? { closeOnSelect: local.shouldCloseOnSelect }
|
|
1072
|
+
: {},
|
|
1073
|
+
);
|
|
1031
1074
|
const menuListChildren = () => (
|
|
1032
1075
|
<SharedElementTransition>
|
|
1033
1076
|
{state.collection().size === 0 && !usesStaticChildren() && local.renderEmptyState ? (
|
|
@@ -1156,7 +1199,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
|
|
|
1156
1199
|
<StaticMenuCollectionContext.Provider
|
|
1157
1200
|
value={usesStaticChildren() ? staticCollectionContext : null}
|
|
1158
1201
|
>
|
|
1159
|
-
<MenuItemContext.Provider value={
|
|
1202
|
+
<MenuItemContext.Provider value={menuItemContextValue()}>
|
|
1160
1203
|
<CollectionRendererContext.Provider value={collectionRenderer()}>
|
|
1161
1204
|
<>
|
|
1162
1205
|
<Show when={ariaProps.label}>
|
package/src/Modal.tsx
CHANGED
|
@@ -479,7 +479,14 @@ function ModalContent(
|
|
|
479
479
|
|
|
480
480
|
const renderProps = useRenderProps(
|
|
481
481
|
{
|
|
482
|
-
|
|
482
|
+
// Lazy: the modal content is gated behind `<Show when={isHydrated() && …}>`
|
|
483
|
+
// (Portal) below, so it must not be instantiated during the component body.
|
|
484
|
+
// An eager `children: props.children` would build the content template (and
|
|
485
|
+
// walk getNextElement) before the gate — content the server never emitted →
|
|
486
|
+
// hydration mismatch. See Popover for the full rationale.
|
|
487
|
+
get children() {
|
|
488
|
+
return props.children;
|
|
489
|
+
},
|
|
483
490
|
class: local.class,
|
|
484
491
|
style: local.style,
|
|
485
492
|
defaultClassName: "solidaria-Modal",
|
package/src/NumberField.tsx
CHANGED
|
@@ -525,9 +525,19 @@ export function NumberFieldIncrementButton(props: NumberFieldIncrementButtonProp
|
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
const isDisabled = () => context.isDisabled || !context.state.canIncrement();
|
|
528
|
+
const pressButtonProps = () => {
|
|
529
|
+
const {
|
|
530
|
+
onClick: _onClick,
|
|
531
|
+
disabled: _disabled,
|
|
532
|
+
type: _type,
|
|
533
|
+
tabIndex: _tabIndex,
|
|
534
|
+
...rest
|
|
535
|
+
} = context.incrementButtonProps as Record<string, unknown>;
|
|
536
|
+
return rest;
|
|
537
|
+
};
|
|
528
538
|
|
|
529
539
|
const buttonAria = createButton({
|
|
530
|
-
...(
|
|
540
|
+
...pressButtonProps(),
|
|
531
541
|
elementType: "div",
|
|
532
542
|
get isDisabled() {
|
|
533
543
|
return isDisabled();
|
|
@@ -594,9 +604,19 @@ export function NumberFieldDecrementButton(props: NumberFieldDecrementButtonProp
|
|
|
594
604
|
}
|
|
595
605
|
|
|
596
606
|
const isDisabled = () => context.isDisabled || !context.state.canDecrement();
|
|
607
|
+
const pressButtonProps = () => {
|
|
608
|
+
const {
|
|
609
|
+
onClick: _onClick,
|
|
610
|
+
disabled: _disabled,
|
|
611
|
+
type: _type,
|
|
612
|
+
tabIndex: _tabIndex,
|
|
613
|
+
...rest
|
|
614
|
+
} = context.decrementButtonProps as Record<string, unknown>;
|
|
615
|
+
return rest;
|
|
616
|
+
};
|
|
597
617
|
|
|
598
618
|
const buttonAria = createButton({
|
|
599
|
-
...(
|
|
619
|
+
...pressButtonProps(),
|
|
600
620
|
elementType: "div",
|
|
601
621
|
get isDisabled() {
|
|
602
622
|
return isDisabled();
|
package/src/Popover.tsx
CHANGED
|
@@ -407,7 +407,16 @@ export function Popover(props: PopoverProps): JSX.Element {
|
|
|
407
407
|
|
|
408
408
|
const renderProps = useRenderProps(
|
|
409
409
|
{
|
|
410
|
-
children
|
|
410
|
+
// Read children lazily. The popover content is gated behind
|
|
411
|
+
// `<Show when={isHydrated() && …}>` below, so it must NOT be instantiated
|
|
412
|
+
// during the component body. An eager `children: props.children` reads the
|
|
413
|
+
// child getter at object-construction time, building the content template
|
|
414
|
+
// (and walking `getNextElement`) before the gate — which the server, with
|
|
415
|
+
// the gate closed, never emitted → hydration mismatch. The getter defers
|
|
416
|
+
// the read until `renderChildren()` runs inside the gated overlay.
|
|
417
|
+
get children() {
|
|
418
|
+
return props.children;
|
|
419
|
+
},
|
|
411
420
|
class: local.class,
|
|
412
421
|
style: local.style,
|
|
413
422
|
defaultClassName: "solidaria-Popover",
|
|
@@ -471,6 +480,14 @@ export function Popover(props: PopoverProps): JSX.Element {
|
|
|
471
480
|
};
|
|
472
481
|
|
|
473
482
|
const shouldBeDialog = () => !local.isNonModal || resolvedTrigger() === "SubmenuTrigger";
|
|
483
|
+
const shouldContainFocus = () => {
|
|
484
|
+
if (!shouldBeDialog()) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const trigger = resolvedTrigger();
|
|
489
|
+
return trigger !== "MenuTrigger" && trigger !== "SubmenuTrigger";
|
|
490
|
+
};
|
|
474
491
|
const portalContext = useUNSAFE_PortalContext();
|
|
475
492
|
const portalContainer = () => {
|
|
476
493
|
if (isSubPopover()) {
|
|
@@ -538,7 +555,7 @@ export function Popover(props: PopoverProps): JSX.Element {
|
|
|
538
555
|
<PopoverContext.Provider
|
|
539
556
|
value={{ placement: popoverAria.placement, arrowProps: () => popoverAria.arrowProps }}
|
|
540
557
|
>
|
|
541
|
-
<FocusScope contain={
|
|
558
|
+
<FocusScope contain={shouldContainFocus()} restoreFocus>
|
|
542
559
|
<div
|
|
543
560
|
{...domProps()}
|
|
544
561
|
{...cleanPopoverProps()}
|