@proyecto-viviana/solidaria 0.2.2 → 0.2.4
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/autocomplete/createAutocomplete.d.ts +2 -2
- package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
- package/dist/index.js +233 -234
- package/dist/index.js.map +2 -2
- package/dist/index.ssr.js +233 -234
- package/dist/index.ssr.js.map +2 -2
- package/dist/interactions/PressEvent.d.ts +13 -10
- package/dist/interactions/PressEvent.d.ts.map +1 -1
- package/dist/interactions/createPress.d.ts.map +1 -1
- package/dist/interactions/index.d.ts +1 -1
- package/dist/interactions/index.d.ts.map +1 -1
- package/dist/select/createHiddenSelect.d.ts.map +1 -1
- package/dist/toolbar/createToolbar.d.ts.map +1 -1
- package/dist/tooltip/createTooltipTrigger.d.ts.map +1 -1
- package/package.json +9 -7
- package/src/autocomplete/createAutocomplete.ts +341 -0
- package/src/autocomplete/index.ts +9 -0
- package/src/breadcrumbs/createBreadcrumbs.ts +196 -0
- package/src/breadcrumbs/index.ts +8 -0
- package/src/button/createButton.ts +142 -0
- package/src/button/createToggleButton.ts +101 -0
- package/src/button/index.ts +4 -0
- package/src/button/types.ts +78 -0
- package/src/calendar/createCalendar.ts +138 -0
- package/src/calendar/createCalendarCell.ts +187 -0
- package/src/calendar/createCalendarGrid.ts +140 -0
- package/src/calendar/createRangeCalendar.ts +136 -0
- package/src/calendar/createRangeCalendarCell.ts +186 -0
- package/src/calendar/index.ts +34 -0
- package/src/checkbox/createCheckbox.ts +135 -0
- package/src/checkbox/createCheckboxGroup.ts +137 -0
- package/src/checkbox/createCheckboxGroupItem.ts +117 -0
- package/src/checkbox/createCheckboxGroupState.ts +193 -0
- package/src/checkbox/index.ts +13 -0
- package/src/color/createColorArea.ts +314 -0
- package/src/color/createColorField.ts +137 -0
- package/src/color/createColorSlider.ts +197 -0
- package/src/color/createColorSwatch.ts +40 -0
- package/src/color/createColorWheel.ts +208 -0
- package/src/color/index.ts +24 -0
- package/src/color/types.ts +116 -0
- package/src/combobox/createComboBox.ts +647 -0
- package/src/combobox/index.ts +6 -0
- package/src/combobox/intl/en-US.json +7 -0
- package/src/combobox/intl/es-ES.json +7 -0
- package/src/combobox/intl/index.ts +23 -0
- package/src/datepicker/createDateField.ts +154 -0
- package/src/datepicker/createDatePicker.ts +206 -0
- package/src/datepicker/createDateSegment.ts +229 -0
- package/src/datepicker/createTimeField.ts +154 -0
- package/src/datepicker/index.ts +28 -0
- package/src/dialog/createDialog.ts +120 -0
- package/src/dialog/index.ts +2 -0
- package/src/dialog/types.ts +19 -0
- package/src/disclosure/createDisclosure.ts +131 -0
- package/src/disclosure/createDisclosureGroup.ts +62 -0
- package/src/disclosure/index.ts +11 -0
- package/src/dnd/createDrag.ts +209 -0
- package/src/dnd/createDraggableCollection.ts +63 -0
- package/src/dnd/createDraggableItem.ts +243 -0
- package/src/dnd/createDrop.ts +321 -0
- package/src/dnd/createDroppableCollection.ts +293 -0
- package/src/dnd/createDroppableItem.ts +213 -0
- package/src/dnd/index.ts +47 -0
- package/src/dnd/types.ts +89 -0
- package/src/dnd/utils.ts +294 -0
- package/src/focus/FocusScope.tsx +408 -0
- package/src/focus/createAutoFocus.ts +321 -0
- package/src/focus/createFocusRestore.ts +313 -0
- package/src/focus/createVirtualFocus.ts +396 -0
- package/src/focus/index.ts +35 -0
- package/src/form/createFormReset.ts +51 -0
- package/src/form/createFormValidation.ts +224 -0
- package/src/form/index.ts +11 -0
- package/src/grid/GridKeyboardDelegate.ts +429 -0
- package/src/grid/createGrid.ts +261 -0
- package/src/grid/createGridCell.ts +182 -0
- package/src/grid/createGridRow.ts +153 -0
- package/src/grid/index.ts +18 -0
- package/src/grid/types.ts +133 -0
- package/src/gridlist/createGridList.ts +185 -0
- package/src/gridlist/createGridListItem.ts +180 -0
- package/src/gridlist/createGridListSelectionCheckbox.ts +59 -0
- package/src/gridlist/index.ts +16 -0
- package/src/gridlist/types.ts +81 -0
- package/src/i18n/NumberFormatter.ts +266 -0
- package/src/i18n/createCollator.ts +79 -0
- package/src/i18n/createDateFormatter.ts +83 -0
- package/src/i18n/createFilter.ts +131 -0
- package/src/i18n/createNumberFormatter.ts +52 -0
- package/src/i18n/createStringFormatter.ts +87 -0
- package/src/i18n/index.ts +40 -0
- package/src/i18n/locale.tsx +188 -0
- package/src/i18n/utils.ts +99 -0
- package/src/index.ts +670 -0
- package/src/interactions/FocusableProvider.tsx +44 -0
- package/src/interactions/PressEvent.ts +126 -0
- package/src/interactions/createFocus.ts +163 -0
- package/src/interactions/createFocusRing.ts +89 -0
- package/src/interactions/createFocusWithin.ts +206 -0
- package/src/interactions/createFocusable.ts +168 -0
- package/src/interactions/createHover.ts +254 -0
- package/src/interactions/createInteractionModality.ts +424 -0
- package/src/interactions/createKeyboard.ts +82 -0
- package/src/interactions/createLongPress.ts +174 -0
- package/src/interactions/createMove.ts +289 -0
- package/src/interactions/createPress.ts +834 -0
- package/src/interactions/index.ts +78 -0
- package/src/label/createField.ts +145 -0
- package/src/label/createLabel.ts +117 -0
- package/src/label/createLabels.ts +50 -0
- package/src/label/index.ts +19 -0
- package/src/landmark/createLandmark.ts +377 -0
- package/src/landmark/index.ts +8 -0
- package/src/link/createLink.ts +182 -0
- package/src/link/index.ts +1 -0
- package/src/listbox/createListBox.ts +269 -0
- package/src/listbox/createOption.ts +151 -0
- package/src/listbox/index.ts +12 -0
- package/src/live-announcer/announce.ts +322 -0
- package/src/live-announcer/index.ts +9 -0
- package/src/menu/createMenu.ts +396 -0
- package/src/menu/createMenuItem.ts +149 -0
- package/src/menu/createMenuTrigger.ts +88 -0
- package/src/menu/index.ts +18 -0
- package/src/meter/createMeter.ts +75 -0
- package/src/meter/index.ts +1 -0
- package/src/numberfield/createNumberField.ts +268 -0
- package/src/numberfield/index.ts +5 -0
- package/src/overlays/ariaHideOutside.ts +219 -0
- package/src/overlays/createInteractOutside.ts +149 -0
- package/src/overlays/createModal.tsx +202 -0
- package/src/overlays/createOverlay.ts +155 -0
- package/src/overlays/createOverlayTrigger.ts +85 -0
- package/src/overlays/createPreventScroll.ts +266 -0
- package/src/overlays/index.ts +44 -0
- package/src/popover/calculatePosition.ts +766 -0
- package/src/popover/createOverlayPosition.ts +356 -0
- package/src/popover/createPopover.ts +170 -0
- package/src/popover/index.ts +24 -0
- package/src/progress/createProgressBar.ts +128 -0
- package/src/progress/index.ts +5 -0
- package/src/radio/createRadio.ts +287 -0
- package/src/radio/createRadioGroup.ts +189 -0
- package/src/radio/createRadioGroupState.ts +201 -0
- package/src/radio/index.ts +23 -0
- package/src/searchfield/createSearchField.ts +186 -0
- package/src/searchfield/index.ts +2 -0
- package/src/select/createHiddenSelect.tsx +236 -0
- package/src/select/createSelect.ts +395 -0
- package/src/select/index.ts +14 -0
- package/src/selection/createTypeSelect.ts +201 -0
- package/src/selection/index.ts +6 -0
- package/src/separator/createSeparator.ts +82 -0
- package/src/separator/index.ts +6 -0
- package/src/slider/createSlider.ts +349 -0
- package/src/slider/index.ts +2 -0
- package/src/ssr/index.tsx +370 -0
- package/src/switch/createSwitch.ts +70 -0
- package/src/switch/index.ts +1 -0
- package/src/table/createTable.ts +526 -0
- package/src/table/createTableCell.ts +147 -0
- package/src/table/createTableColumnHeader.ts +115 -0
- package/src/table/createTableHeaderRow.ts +40 -0
- package/src/table/createTableRow.ts +155 -0
- package/src/table/createTableRowGroup.ts +32 -0
- package/src/table/createTableSelectAllCheckbox.ts +73 -0
- package/src/table/createTableSelectionCheckbox.ts +59 -0
- package/src/table/index.ts +30 -0
- package/src/table/types.ts +165 -0
- package/src/tabs/createTabs.ts +472 -0
- package/src/tabs/index.ts +14 -0
- package/src/tag/createTag.ts +194 -0
- package/src/tag/createTagGroup.ts +154 -0
- package/src/tag/index.ts +12 -0
- package/src/textfield/createTextField.ts +198 -0
- package/src/textfield/index.ts +5 -0
- package/src/toast/createToast.ts +118 -0
- package/src/toast/createToastRegion.ts +100 -0
- package/src/toast/index.ts +11 -0
- package/src/toggle/createToggle.ts +223 -0
- package/src/toggle/createToggleState.ts +94 -0
- package/src/toggle/index.ts +7 -0
- package/src/toolbar/createToolbar.ts +369 -0
- package/src/toolbar/index.ts +6 -0
- package/src/tooltip/createTooltip.ts +79 -0
- package/src/tooltip/createTooltipTrigger.ts +222 -0
- package/src/tooltip/index.ts +6 -0
- package/src/tree/createTree.ts +246 -0
- package/src/tree/createTreeItem.ts +233 -0
- package/src/tree/createTreeSelectionCheckbox.ts +68 -0
- package/src/tree/index.ts +16 -0
- package/src/tree/types.ts +87 -0
- package/src/utils/createDescription.ts +137 -0
- package/src/utils/dom.ts +327 -0
- package/src/utils/env.ts +54 -0
- package/src/utils/events.ts +106 -0
- package/src/utils/filterDOMProps.ts +116 -0
- package/src/utils/focus.ts +151 -0
- package/src/utils/geometry.ts +115 -0
- package/src/utils/globalListeners.ts +142 -0
- package/src/utils/index.ts +80 -0
- package/src/utils/mergeProps.ts +52 -0
- package/src/utils/platform.ts +52 -0
- package/src/utils/reactivity.ts +36 -0
- package/src/utils/textSelection.ts +114 -0
- package/src/visually-hidden/createVisuallyHidden.ts +124 -0
- package/src/visually-hidden/index.ts +6 -0
- package/dist/index.jsx +0 -15845
- package/dist/index.jsx.map +0 -7
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Press interactions
|
|
2
|
+
export { createPress, type CreatePressProps, type PressResult } from './createPress';
|
|
3
|
+
export { PressEvent, type IPressEvent, type PressEventType } from './PressEvent';
|
|
4
|
+
|
|
5
|
+
// Long press interactions
|
|
6
|
+
export {
|
|
7
|
+
createLongPress,
|
|
8
|
+
type LongPressProps,
|
|
9
|
+
type LongPressResult,
|
|
10
|
+
type LongPressEvent,
|
|
11
|
+
} from './createLongPress';
|
|
12
|
+
|
|
13
|
+
// Move interactions
|
|
14
|
+
export { createMove, type MoveEvents, type MoveResult, type MoveStartEvent, type MoveMoveEvent, type MoveEndEvent } from './createMove';
|
|
15
|
+
|
|
16
|
+
// Focus interactions
|
|
17
|
+
export { createFocus, type CreateFocusProps, type FocusResult, type FocusEvents } from './createFocus';
|
|
18
|
+
export {
|
|
19
|
+
createFocusWithin,
|
|
20
|
+
type FocusWithinProps,
|
|
21
|
+
type FocusWithinResult,
|
|
22
|
+
} from './createFocusWithin';
|
|
23
|
+
export {
|
|
24
|
+
createFocusable,
|
|
25
|
+
FocusableContext,
|
|
26
|
+
type CreateFocusableProps,
|
|
27
|
+
type FocusableResult,
|
|
28
|
+
type FocusableContextValue,
|
|
29
|
+
type FocusableProviderProps,
|
|
30
|
+
type FocusableProps,
|
|
31
|
+
type FocusableDOMProps,
|
|
32
|
+
} from './createFocusable';
|
|
33
|
+
export { FocusableProvider } from './FocusableProvider';
|
|
34
|
+
export {
|
|
35
|
+
createFocusRing,
|
|
36
|
+
type FocusRingProps,
|
|
37
|
+
type FocusRingResult,
|
|
38
|
+
} from './createFocusRing';
|
|
39
|
+
|
|
40
|
+
// Interaction modality
|
|
41
|
+
export {
|
|
42
|
+
createInteractionModality,
|
|
43
|
+
createFocusVisible,
|
|
44
|
+
createFocusVisibleListener,
|
|
45
|
+
addWindowFocusTracking,
|
|
46
|
+
isFocusVisible,
|
|
47
|
+
getInteractionModality,
|
|
48
|
+
setInteractionModality,
|
|
49
|
+
getPointerType,
|
|
50
|
+
setupGlobalFocusListeners,
|
|
51
|
+
addModalityListener,
|
|
52
|
+
useIsKeyboardFocused,
|
|
53
|
+
type Modality,
|
|
54
|
+
type PointerType,
|
|
55
|
+
type FocusVisibleProps,
|
|
56
|
+
type FocusVisibleResult,
|
|
57
|
+
type FocusVisibleHandler,
|
|
58
|
+
type InteractionModalityResult,
|
|
59
|
+
} from './createInteractionModality';
|
|
60
|
+
|
|
61
|
+
// Hover interactions
|
|
62
|
+
export {
|
|
63
|
+
createHover,
|
|
64
|
+
type CreateHoverProps,
|
|
65
|
+
type HoverProps,
|
|
66
|
+
type HoverResult,
|
|
67
|
+
type HoverEvent,
|
|
68
|
+
type HoverEvents,
|
|
69
|
+
} from './createHover';
|
|
70
|
+
|
|
71
|
+
// Keyboard interactions
|
|
72
|
+
export {
|
|
73
|
+
createKeyboard,
|
|
74
|
+
type CreateKeyboardProps,
|
|
75
|
+
type KeyboardResult,
|
|
76
|
+
type KeyboardEvents,
|
|
77
|
+
type KeyboardEvent,
|
|
78
|
+
} from './createKeyboard';
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field hook for Solidaria
|
|
3
|
+
*
|
|
4
|
+
* Provides the accessibility implementation for input fields.
|
|
5
|
+
* Fields accept user input, gain context from their label, and may display
|
|
6
|
+
* a description or error message.
|
|
7
|
+
*
|
|
8
|
+
* This is a 1:1 port of @react-aria/label's useField hook.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { JSX } from 'solid-js';
|
|
12
|
+
import { createId } from '../ssr';
|
|
13
|
+
import { createLabel, type LabelAriaProps, type LabelAria, type AriaLabelingProps, type DOMProps } from './createLabel';
|
|
14
|
+
import { mergeProps } from '../utils/mergeProps';
|
|
15
|
+
import { type MaybeAccessor, access } from '../utils/reactivity';
|
|
16
|
+
|
|
17
|
+
// ============================================
|
|
18
|
+
// TYPES
|
|
19
|
+
// ============================================
|
|
20
|
+
|
|
21
|
+
export interface HelpTextProps {
|
|
22
|
+
/** A description for the field. Provides a hint such as specific requirements for what to choose. */
|
|
23
|
+
description?: JSX.Element;
|
|
24
|
+
/** An error message for the field. */
|
|
25
|
+
errorMessage?: JSX.Element | ((validation: ValidationResult) => JSX.Element);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ValidationResult {
|
|
29
|
+
/** Whether the input value is invalid. */
|
|
30
|
+
isInvalid: boolean;
|
|
31
|
+
/** The current error messages for the input if it is invalid, otherwise an empty array. */
|
|
32
|
+
validationErrors: string[];
|
|
33
|
+
/** The native validity state for the input. */
|
|
34
|
+
validationDetails: ValidityState;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface Validation<T> {
|
|
38
|
+
/** Whether the input value is invalid. */
|
|
39
|
+
isInvalid?: boolean;
|
|
40
|
+
/** Whether the input is required before form submission. */
|
|
41
|
+
isRequired?: boolean;
|
|
42
|
+
/** A function that returns an error message if a given value is invalid. */
|
|
43
|
+
validate?: (value: T) => string | string[] | true | null | undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface AriaFieldProps extends LabelAriaProps, HelpTextProps, Omit<Validation<any>, 'isRequired'> {}
|
|
47
|
+
|
|
48
|
+
export interface FieldAria extends LabelAria {
|
|
49
|
+
/** Props for the description element, if any. */
|
|
50
|
+
descriptionProps: JSX.HTMLAttributes<HTMLElement>;
|
|
51
|
+
/** Props for the error message element, if any. */
|
|
52
|
+
errorMessageProps: JSX.HTMLAttributes<HTMLElement>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ============================================
|
|
56
|
+
// IMPLEMENTATION
|
|
57
|
+
// ============================================
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Provides the accessibility implementation for input fields.
|
|
61
|
+
* Fields accept user input, gain context from their label, and may display
|
|
62
|
+
* a description or error message.
|
|
63
|
+
*
|
|
64
|
+
* @param props - Props for the Field.
|
|
65
|
+
*/
|
|
66
|
+
export function createField(props: MaybeAccessor<AriaFieldProps>): FieldAria {
|
|
67
|
+
const getProps = () => access(props);
|
|
68
|
+
|
|
69
|
+
const { labelProps, fieldProps: baseLabelFieldProps } = createLabel(props);
|
|
70
|
+
|
|
71
|
+
// Generate IDs for description and error message
|
|
72
|
+
const descriptionId = createId();
|
|
73
|
+
const errorMessageId = createId();
|
|
74
|
+
|
|
75
|
+
const getDescriptionProps = (): FieldAria['descriptionProps'] => {
|
|
76
|
+
const { description, errorMessage, isInvalid } = getProps();
|
|
77
|
+
|
|
78
|
+
// Only include ID if description exists or there's an error message that might be shown
|
|
79
|
+
if (!description && !errorMessage && !isInvalid) {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
id: descriptionId,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const getErrorMessageProps = (): FieldAria['errorMessageProps'] => {
|
|
89
|
+
const { errorMessage, isInvalid } = getProps();
|
|
90
|
+
|
|
91
|
+
// Only include ID if there's an error message and the field is invalid
|
|
92
|
+
if (!errorMessage && !isInvalid) {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
id: errorMessageId,
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const getFieldProps = (): AriaLabelingProps & DOMProps => {
|
|
102
|
+
const { description, errorMessage, isInvalid } = getProps();
|
|
103
|
+
|
|
104
|
+
const describedByIds: string[] = [];
|
|
105
|
+
|
|
106
|
+
// Add description ID if description exists
|
|
107
|
+
if (description) {
|
|
108
|
+
describedByIds.push(descriptionId);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Add error message ID if field is invalid and error message exists
|
|
112
|
+
// Use aria-describedby for error message because aria-errormessage is unsupported
|
|
113
|
+
// using VoiceOver or NVDA. See https://github.com/adobe/react-spectrum/issues/1346#issuecomment-740136268
|
|
114
|
+
if (isInvalid && errorMessage) {
|
|
115
|
+
describedByIds.push(errorMessageId);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Add any existing aria-describedby from props
|
|
119
|
+
const existingDescribedBy = getProps()['aria-describedby'];
|
|
120
|
+
if (existingDescribedBy) {
|
|
121
|
+
describedByIds.push(existingDescribedBy);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const ariaDescribedBy = describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
|
|
125
|
+
|
|
126
|
+
return mergeProps(baseLabelFieldProps, {
|
|
127
|
+
'aria-describedby': ariaDescribedBy,
|
|
128
|
+
}) as AriaLabelingProps & DOMProps;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
get labelProps() {
|
|
133
|
+
return labelProps;
|
|
134
|
+
},
|
|
135
|
+
get fieldProps() {
|
|
136
|
+
return getFieldProps();
|
|
137
|
+
},
|
|
138
|
+
get descriptionProps() {
|
|
139
|
+
return getDescriptionProps();
|
|
140
|
+
},
|
|
141
|
+
get errorMessageProps() {
|
|
142
|
+
return getErrorMessageProps();
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label hook for Solidaria
|
|
3
|
+
*
|
|
4
|
+
* Provides the accessibility implementation for labels and their associated elements.
|
|
5
|
+
* Labels provide context for user inputs.
|
|
6
|
+
*
|
|
7
|
+
* This is a 1:1 port of @react-aria/label's useLabel hook.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { JSX } from 'solid-js';
|
|
11
|
+
import { createId } from '../ssr';
|
|
12
|
+
import { createLabels } from './createLabels';
|
|
13
|
+
import { type MaybeAccessor, access } from '../utils/reactivity';
|
|
14
|
+
import { isDevEnv } from '../utils/env';
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// TYPES
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
export interface AriaLabelingProps {
|
|
21
|
+
/** Defines a string value that labels the current element. */
|
|
22
|
+
'aria-label'?: string;
|
|
23
|
+
/** Identifies the element (or elements) that labels the current element. */
|
|
24
|
+
'aria-labelledby'?: string;
|
|
25
|
+
/** Identifies the element (or elements) that describes the object. */
|
|
26
|
+
'aria-describedby'?: string;
|
|
27
|
+
/** Identifies the element (or elements) that provide a detailed, extended description for the object. */
|
|
28
|
+
'aria-details'?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface LabelableProps {
|
|
32
|
+
/** The content to display as the label. */
|
|
33
|
+
label?: JSX.Element;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DOMProps {
|
|
37
|
+
/** The element's unique identifier. */
|
|
38
|
+
id?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface LabelAriaProps extends LabelableProps, DOMProps, AriaLabelingProps {
|
|
42
|
+
/**
|
|
43
|
+
* The HTML element used to render the label, e.g. 'label', or 'span'.
|
|
44
|
+
* @default 'label'
|
|
45
|
+
*/
|
|
46
|
+
labelElementType?: 'label' | 'span' | 'div';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface LabelAria {
|
|
50
|
+
/** Props to apply to the label container element. */
|
|
51
|
+
labelProps: JSX.LabelHTMLAttributes<HTMLLabelElement> | JSX.HTMLAttributes<HTMLSpanElement>;
|
|
52
|
+
/** Props to apply to the field container element being labeled. */
|
|
53
|
+
fieldProps: AriaLabelingProps & DOMProps;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================
|
|
57
|
+
// IMPLEMENTATION
|
|
58
|
+
// ============================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Provides the accessibility implementation for labels and their associated elements.
|
|
62
|
+
* Labels provide context for user inputs.
|
|
63
|
+
*
|
|
64
|
+
* @param props - The props for labels and fields.
|
|
65
|
+
*/
|
|
66
|
+
export function createLabel(props: MaybeAccessor<LabelAriaProps>): LabelAria {
|
|
67
|
+
const getProps = () => access(props);
|
|
68
|
+
|
|
69
|
+
const id = createId(getProps().id);
|
|
70
|
+
const labelId = createId();
|
|
71
|
+
|
|
72
|
+
const getLabelProps = (): LabelAria['labelProps'] => {
|
|
73
|
+
const { label, labelElementType = 'label' } = getProps();
|
|
74
|
+
|
|
75
|
+
if (!label) {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
id: labelId,
|
|
81
|
+
...(labelElementType === 'label' ? { for: id } : {}),
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const getFieldProps = (): LabelAria['fieldProps'] => {
|
|
86
|
+
const {
|
|
87
|
+
label,
|
|
88
|
+
'aria-labelledby': ariaLabelledby,
|
|
89
|
+
'aria-label': ariaLabel,
|
|
90
|
+
} = getProps();
|
|
91
|
+
|
|
92
|
+
let labelledBy = ariaLabelledby;
|
|
93
|
+
|
|
94
|
+
if (label) {
|
|
95
|
+
labelledBy = ariaLabelledby ? `${labelId} ${ariaLabelledby}` : labelId;
|
|
96
|
+
} else if (!ariaLabelledby && !ariaLabel && isDevEnv()) {
|
|
97
|
+
console.warn(
|
|
98
|
+
'If you do not provide a visible label, you must specify an aria-label or aria-labelledby attribute for accessibility'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return createLabels({
|
|
103
|
+
id,
|
|
104
|
+
'aria-label': ariaLabel,
|
|
105
|
+
'aria-labelledby': labelledBy,
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
get labelProps() {
|
|
111
|
+
return getLabelProps();
|
|
112
|
+
},
|
|
113
|
+
get fieldProps() {
|
|
114
|
+
return getFieldProps();
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Labels utility for Solidaria
|
|
3
|
+
*
|
|
4
|
+
* Merges aria-label and aria-labelledby into aria-labelledby when both exist.
|
|
5
|
+
*
|
|
6
|
+
* This is a 1:1 port of @react-aria/utils's useLabels hook.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createId } from '../ssr';
|
|
10
|
+
import type { AriaLabelingProps, DOMProps } from './createLabel';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Merges aria-label and aria-labelledby into aria-labelledby when both exist.
|
|
14
|
+
*
|
|
15
|
+
* @param props - Aria label props.
|
|
16
|
+
* @param defaultLabel - Default value for aria-label when not present.
|
|
17
|
+
*/
|
|
18
|
+
export function createLabels(
|
|
19
|
+
props: DOMProps & AriaLabelingProps,
|
|
20
|
+
defaultLabel?: string
|
|
21
|
+
): DOMProps & AriaLabelingProps {
|
|
22
|
+
let {
|
|
23
|
+
id,
|
|
24
|
+
'aria-label': label,
|
|
25
|
+
'aria-labelledby': labelledBy,
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
// Generate an ID if not provided
|
|
29
|
+
id = createId(id);
|
|
30
|
+
|
|
31
|
+
// If there is both an aria-label and aria-labelledby,
|
|
32
|
+
// combine them by pointing to the element itself.
|
|
33
|
+
if (labelledBy && label) {
|
|
34
|
+
const ids = new Set([id, ...labelledBy.trim().split(/\s+/)]);
|
|
35
|
+
labelledBy = [...ids].join(' ');
|
|
36
|
+
} else if (labelledBy) {
|
|
37
|
+
labelledBy = labelledBy.trim().split(/\s+/).join(' ');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// If no labels are provided, use the default
|
|
41
|
+
if (!label && !labelledBy && defaultLabel) {
|
|
42
|
+
label = defaultLabel;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
id,
|
|
47
|
+
'aria-label': label,
|
|
48
|
+
'aria-labelledby': labelledBy,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { createLabel } from './createLabel';
|
|
2
|
+
export type {
|
|
3
|
+
LabelAriaProps,
|
|
4
|
+
LabelAria,
|
|
5
|
+
AriaLabelingProps,
|
|
6
|
+
LabelableProps,
|
|
7
|
+
DOMProps,
|
|
8
|
+
} from './createLabel';
|
|
9
|
+
|
|
10
|
+
export { createField } from './createField';
|
|
11
|
+
export type {
|
|
12
|
+
AriaFieldProps,
|
|
13
|
+
FieldAria,
|
|
14
|
+
HelpTextProps,
|
|
15
|
+
ValidationResult,
|
|
16
|
+
Validation,
|
|
17
|
+
} from './createField';
|
|
18
|
+
|
|
19
|
+
export { createLabels } from './createLabels';
|