@proyecto-viviana/solidaria 0.2.4 → 0.2.8
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/LICENSE +21 -0
- package/dist/actiongroup/createActionGroup.d.ts +29 -0
- package/dist/actiongroup/createActionGroup.d.ts.map +1 -0
- package/dist/actiongroup/index.d.ts +2 -0
- package/dist/actiongroup/index.d.ts.map +1 -0
- package/dist/autocomplete/createAutocomplete.d.ts +6 -2
- package/dist/autocomplete/createAutocomplete.d.ts.map +1 -1
- package/dist/breadcrumbs/createBreadcrumbs.d.ts +2 -0
- package/dist/breadcrumbs/createBreadcrumbs.d.ts.map +1 -1
- package/dist/button/createToggleButtonGroup.d.ts +32 -0
- package/dist/button/createToggleButtonGroup.d.ts.map +1 -0
- package/dist/button/index.d.ts +2 -0
- package/dist/button/index.d.ts.map +1 -1
- package/dist/calendar/createCalendarCell.d.ts +2 -0
- package/dist/calendar/createCalendarCell.d.ts.map +1 -1
- package/dist/calendar/createCalendarGrid.d.ts.map +1 -1
- package/dist/calendar/createRangeCalendarCell.d.ts +3 -1
- package/dist/calendar/createRangeCalendarCell.d.ts.map +1 -1
- package/dist/checkbox/createCheckboxGroup.d.ts +5 -1
- package/dist/checkbox/createCheckboxGroup.d.ts.map +1 -1
- package/dist/collections/index.d.ts +56 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/color/createColorArea.d.ts.map +1 -1
- package/dist/color/createColorSlider.d.ts.map +1 -1
- package/dist/color/createColorWheel.d.ts.map +1 -1
- package/dist/combobox/createComboBox.d.ts +6 -0
- package/dist/combobox/createComboBox.d.ts.map +1 -1
- package/dist/datepicker/createDatePicker.d.ts +6 -0
- package/dist/datepicker/createDatePicker.d.ts.map +1 -1
- package/dist/datepicker/createDateRangePicker.d.ts +40 -0
- package/dist/datepicker/createDateRangePicker.d.ts.map +1 -0
- package/dist/datepicker/createDateSegment.d.ts +1 -1
- package/dist/datepicker/createDateSegment.d.ts.map +1 -1
- package/dist/datepicker/createTimeSegment.d.ts +29 -0
- package/dist/datepicker/createTimeSegment.d.ts.map +1 -0
- package/dist/datepicker/index.d.ts +2 -0
- package/dist/datepicker/index.d.ts.map +1 -1
- package/dist/disclosure/createDisclosureGroup.d.ts +2 -1
- package/dist/disclosure/createDisclosureGroup.d.ts.map +1 -1
- package/dist/dnd/createDrag.d.ts.map +1 -1
- package/dist/dnd/createDraggableCollection.d.ts +4 -0
- package/dist/dnd/createDraggableCollection.d.ts.map +1 -1
- package/dist/dnd/createDraggableItem.d.ts.map +1 -1
- package/dist/dnd/createDrop.d.ts.map +1 -1
- package/dist/dnd/createDroppableCollection.d.ts +32 -1
- package/dist/dnd/createDroppableCollection.d.ts.map +1 -1
- package/dist/dnd/createDroppableItem.d.ts.map +1 -1
- package/dist/dnd/index.d.ts +1 -1
- package/dist/dnd/index.d.ts.map +1 -1
- package/dist/grid/createGrid.d.ts.map +1 -1
- package/dist/gridlist/createGridList.d.ts.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4659 -3452
- package/dist/index.js.map +1 -7
- package/dist/index.ssr.js +4659 -3452
- package/dist/index.ssr.js.map +1 -7
- package/dist/interactions/createFocus.d.ts.map +1 -1
- package/dist/interactions/createFocusWithin.d.ts.map +1 -1
- package/dist/link/createLink.d.ts +10 -0
- package/dist/link/createLink.d.ts.map +1 -1
- package/dist/listbox/createListBox.d.ts +1 -0
- package/dist/listbox/createListBox.d.ts.map +1 -1
- package/dist/listbox/createOption.d.ts.map +1 -1
- package/dist/menu/createMenu.d.ts +1 -0
- package/dist/menu/createMenu.d.ts.map +1 -1
- package/dist/meter/createMeter.d.ts.map +1 -1
- package/dist/numberfield/createNumberField.d.ts +18 -0
- package/dist/numberfield/createNumberField.d.ts.map +1 -1
- package/dist/overlays/createModal.d.ts +16 -0
- package/dist/overlays/createModal.d.ts.map +1 -1
- package/dist/overlays/createOverlay.d.ts.map +1 -1
- package/dist/overlays/index.d.ts +1 -1
- package/dist/overlays/index.d.ts.map +1 -1
- package/dist/popover/createOverlayPosition.d.ts.map +1 -1
- package/dist/popover/createPopover.d.ts.map +1 -1
- package/dist/progress/createProgressBar.d.ts.map +1 -1
- package/dist/radio/createRadioGroup.d.ts +2 -2
- package/dist/radio/createRadioGroup.d.ts.map +1 -1
- package/dist/searchfield/createSearchField.d.ts.map +1 -1
- package/dist/select/createHiddenSelect.d.ts.map +1 -1
- package/dist/select/createSelect.d.ts.map +1 -1
- package/dist/slider/createSlider.d.ts.map +1 -1
- package/dist/table/createTable.d.ts.map +1 -1
- package/dist/tabs/createTabs.d.ts +1 -1
- package/dist/tabs/createTabs.d.ts.map +1 -1
- package/dist/tag/createTag.d.ts.map +1 -1
- package/dist/tag/createTagGroup.d.ts.map +1 -1
- package/dist/toast/createToast.d.ts +4 -0
- package/dist/toast/createToast.d.ts.map +1 -1
- package/dist/toast/createToastRegion.d.ts.map +1 -1
- package/dist/toolbar/createToolbar.d.ts.map +1 -1
- package/dist/tooltip/createTooltipTrigger.d.ts.map +1 -1
- package/dist/tree/createTree.d.ts.map +1 -1
- package/dist/tree/createTreeItem.d.ts.map +1 -1
- package/dist/tree/types.d.ts +4 -0
- package/dist/tree/types.d.ts.map +1 -1
- package/dist/utils/env.d.ts +1 -1
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/platform.d.ts.map +1 -1
- package/dist/visually-hidden/createVisuallyHidden.d.ts.map +1 -1
- package/package.json +8 -6
- package/src/actiongroup/createActionGroup.ts +324 -0
- package/src/actiongroup/index.ts +8 -0
- package/src/autocomplete/createAutocomplete.ts +32 -9
- package/src/breadcrumbs/createBreadcrumbs.ts +10 -15
- package/src/button/createButton.ts +1 -1
- package/src/button/createToggleButtonGroup.ts +128 -0
- package/src/button/index.ts +9 -0
- package/src/calendar/createCalendarCell.ts +6 -4
- package/src/calendar/createCalendarGrid.ts +27 -18
- package/src/calendar/createRangeCalendarCell.ts +26 -9
- package/src/checkbox/createCheckboxGroup.ts +21 -4
- package/src/collections/index.ts +242 -0
- package/src/color/createColorArea.ts +380 -314
- package/src/color/createColorField.ts +137 -137
- package/src/color/createColorSlider.ts +286 -197
- package/src/color/createColorSwatch.ts +40 -40
- package/src/color/createColorWheel.ts +218 -208
- package/src/color/index.ts +24 -24
- package/src/color/types.ts +116 -116
- package/src/combobox/createComboBox.ts +670 -647
- package/src/combobox/index.ts +6 -6
- package/src/datepicker/createDatePicker.ts +54 -16
- package/src/datepicker/createDateRangePicker.ts +246 -0
- package/src/datepicker/createDateSegment.ts +185 -31
- package/src/datepicker/createTimeSegment.ts +370 -0
- package/src/datepicker/index.ts +14 -0
- package/src/dialog/createDialog.ts +120 -120
- package/src/dialog/index.ts +2 -2
- package/src/dialog/types.ts +19 -19
- package/src/disclosure/createDisclosureGroup.ts +5 -2
- package/src/dnd/createDrag.ts +224 -209
- package/src/dnd/createDraggableCollection.ts +96 -63
- package/src/dnd/createDraggableItem.ts +259 -243
- package/src/dnd/createDrop.ts +322 -321
- package/src/dnd/createDroppableCollection.ts +682 -293
- package/src/dnd/createDroppableItem.ts +215 -213
- package/src/dnd/index.ts +55 -47
- package/src/dnd/types.ts +89 -89
- package/src/dnd/utils.ts +294 -294
- package/src/focus/createAutoFocus.ts +321 -321
- package/src/focus/createFocusRestore.ts +313 -313
- package/src/focus/createVirtualFocus.ts +396 -396
- package/src/form/createFormValidation.ts +224 -224
- package/src/form/index.ts +11 -11
- package/src/grid/createGrid.ts +3 -1
- package/src/gridlist/createGridList.ts +16 -0
- package/src/gridlist/createGridListItem.ts +1 -1
- package/src/i18n/NumberFormatter.ts +266 -266
- package/src/i18n/createCollator.ts +79 -79
- package/src/i18n/createDateFormatter.ts +83 -83
- package/src/i18n/createFilter.ts +131 -131
- package/src/i18n/createNumberFormatter.ts +52 -52
- package/src/i18n/index.ts +40 -40
- package/src/i18n/locale.tsx +188 -188
- package/src/i18n/utils.ts +99 -99
- package/src/index.ts +51 -0
- package/src/interactions/createFocus.ts +6 -5
- package/src/interactions/createFocusWithin.ts +6 -5
- package/src/interactions/createLongPress.ts +174 -174
- package/src/interactions/createMove.ts +289 -289
- package/src/interactions/createPress.ts +5 -5
- package/src/landmark/createLandmark.ts +377 -377
- package/src/landmark/index.ts +8 -8
- package/src/link/createLink.ts +23 -8
- package/src/listbox/createListBox.ts +308 -269
- package/src/listbox/createOption.ts +162 -151
- package/src/listbox/index.ts +12 -12
- package/src/live-announcer/announce.ts +322 -322
- package/src/live-announcer/index.ts +9 -9
- package/src/menu/createMenu.ts +405 -396
- package/src/menu/createMenuItem.ts +149 -149
- package/src/menu/createMenuTrigger.ts +88 -88
- package/src/menu/index.ts +18 -18
- package/src/meter/createMeter.ts +1 -6
- package/src/numberfield/createNumberField.ts +311 -268
- package/src/numberfield/index.ts +5 -5
- package/src/overlays/ariaHideOutside.ts +219 -219
- package/src/overlays/createInteractOutside.ts +149 -149
- package/src/overlays/createModal.tsx +238 -202
- package/src/overlays/createOverlay.ts +165 -155
- package/src/overlays/createOverlayTrigger.ts +85 -85
- package/src/overlays/createPreventScroll.ts +266 -266
- package/src/overlays/index.ts +48 -44
- package/src/popover/calculatePosition.ts +6 -6
- package/src/popover/createOverlayPosition.ts +7 -4
- package/src/popover/createPopover.ts +21 -7
- package/src/progress/createProgressBar.ts +6 -1
- package/src/radio/createRadioGroup.ts +88 -14
- package/src/searchfield/createSearchField.ts +241 -186
- package/src/searchfield/index.ts +2 -2
- package/src/select/createHiddenSelect.tsx +263 -236
- package/src/select/createSelect.ts +373 -395
- package/src/select/index.ts +14 -14
- package/src/slider/createSlider.ts +364 -349
- package/src/slider/index.ts +2 -2
- package/src/ssr/index.tsx +370 -370
- package/src/table/createTable.ts +3 -1
- package/src/table/createTableColumnHeader.ts +1 -1
- package/src/table/createTableRow.ts +1 -1
- package/src/tabs/createTabs.ts +80 -51
- package/src/tag/createTag.ts +135 -6
- package/src/tag/createTagGroup.ts +7 -2
- package/src/toast/createToast.ts +8 -2
- package/src/toast/createToastRegion.ts +0 -1
- package/src/toolbar/createToolbar.ts +75 -1
- package/src/tooltip/createTooltip.ts +79 -79
- package/src/tooltip/createTooltipTrigger.ts +226 -222
- package/src/tooltip/index.ts +6 -6
- package/src/tree/createTree.ts +261 -246
- package/src/tree/createTreeItem.ts +282 -233
- package/src/tree/createTreeSelectionCheckbox.ts +68 -68
- package/src/tree/index.ts +16 -16
- package/src/tree/types.ts +91 -87
- package/src/utils/env.ts +55 -54
- package/src/utils/platform.ts +16 -6
- package/src/visually-hidden/createVisuallyHidden.ts +139 -124
- package/src/visually-hidden/index.ts +6 -6
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* createNumberFormatter hook for solidaria
|
|
3
|
-
*
|
|
4
|
-
* Provides localized number formatting with automatic locale updates.
|
|
5
|
-
*
|
|
6
|
-
* Port of @react-aria/i18n useNumberFormatter.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { createMemo } from 'solid-js';
|
|
10
|
-
import { useLocale } from './locale';
|
|
11
|
-
import { NumberFormatter, type NumberFormatOptions } from './NumberFormatter';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Provides localized number formatting for the current locale.
|
|
15
|
-
* Automatically updates when the locale changes.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* function PriceDisplay(props: { value: number }) {
|
|
20
|
-
* const formatter = createNumberFormatter({
|
|
21
|
-
* style: 'currency',
|
|
22
|
-
* currency: 'USD',
|
|
23
|
-
* });
|
|
24
|
-
*
|
|
25
|
-
* return <span>{formatter().format(props.value)}</span>;
|
|
26
|
-
* }
|
|
27
|
-
* ```
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```tsx
|
|
31
|
-
* // Percent formatting
|
|
32
|
-
* const percentFormatter = createNumberFormatter({
|
|
33
|
-
* style: 'percent',
|
|
34
|
-
* minimumFractionDigits: 1,
|
|
35
|
-
* });
|
|
36
|
-
* percentFormatter().format(0.125); // '12.5%'
|
|
37
|
-
*
|
|
38
|
-
* // Unit formatting
|
|
39
|
-
* const tempFormatter = createNumberFormatter({
|
|
40
|
-
* style: 'unit',
|
|
41
|
-
* unit: 'celsius',
|
|
42
|
-
* });
|
|
43
|
-
* tempFormatter().format(25); // '25°C'
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export function createNumberFormatter(
|
|
47
|
-
options: NumberFormatOptions = {}
|
|
48
|
-
): () => NumberFormatter {
|
|
49
|
-
const locale = useLocale();
|
|
50
|
-
|
|
51
|
-
return createMemo(() => new NumberFormatter(locale().locale, options));
|
|
52
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* createNumberFormatter hook for solidaria
|
|
3
|
+
*
|
|
4
|
+
* Provides localized number formatting with automatic locale updates.
|
|
5
|
+
*
|
|
6
|
+
* Port of @react-aria/i18n useNumberFormatter.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createMemo } from 'solid-js';
|
|
10
|
+
import { useLocale } from './locale';
|
|
11
|
+
import { NumberFormatter, type NumberFormatOptions } from './NumberFormatter';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provides localized number formatting for the current locale.
|
|
15
|
+
* Automatically updates when the locale changes.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* function PriceDisplay(props: { value: number }) {
|
|
20
|
+
* const formatter = createNumberFormatter({
|
|
21
|
+
* style: 'currency',
|
|
22
|
+
* currency: 'USD',
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* return <span>{formatter().format(props.value)}</span>;
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* // Percent formatting
|
|
32
|
+
* const percentFormatter = createNumberFormatter({
|
|
33
|
+
* style: 'percent',
|
|
34
|
+
* minimumFractionDigits: 1,
|
|
35
|
+
* });
|
|
36
|
+
* percentFormatter().format(0.125); // '12.5%'
|
|
37
|
+
*
|
|
38
|
+
* // Unit formatting
|
|
39
|
+
* const tempFormatter = createNumberFormatter({
|
|
40
|
+
* style: 'unit',
|
|
41
|
+
* unit: 'celsius',
|
|
42
|
+
* });
|
|
43
|
+
* tempFormatter().format(25); // '25°C'
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function createNumberFormatter(
|
|
47
|
+
options: NumberFormatOptions = {}
|
|
48
|
+
): () => NumberFormatter {
|
|
49
|
+
const locale = useLocale();
|
|
50
|
+
|
|
51
|
+
return createMemo(() => new NumberFormatter(locale().locale, options));
|
|
52
|
+
}
|
package/src/i18n/index.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
// Locale context and provider
|
|
2
|
-
export {
|
|
3
|
-
I18nProvider,
|
|
4
|
-
useLocale,
|
|
5
|
-
createDefaultLocale,
|
|
6
|
-
getDefaultLocale,
|
|
7
|
-
type Direction,
|
|
8
|
-
type Locale,
|
|
9
|
-
type I18nProviderProps,
|
|
10
|
-
} from './locale';
|
|
11
|
-
|
|
12
|
-
// RTL utilities
|
|
13
|
-
export { isRTL, createCacheKey } from './utils';
|
|
14
|
-
|
|
15
|
-
// Number formatting
|
|
16
|
-
export {
|
|
17
|
-
NumberFormatter,
|
|
18
|
-
type NumberFormatOptions,
|
|
19
|
-
} from './NumberFormatter';
|
|
20
|
-
|
|
21
|
-
export { createNumberFormatter } from './createNumberFormatter';
|
|
22
|
-
|
|
23
|
-
// Date formatting
|
|
24
|
-
export { createDateFormatter } from './createDateFormatter';
|
|
25
|
-
|
|
26
|
-
// String collation
|
|
27
|
-
export { createCollator } from './createCollator';
|
|
28
|
-
|
|
29
|
-
// String filtering
|
|
30
|
-
export { createFilter, type Filter } from './createFilter';
|
|
31
|
-
|
|
32
|
-
// String formatting (ICU MessageFormat)
|
|
33
|
-
export {
|
|
34
|
-
createStringFormatter,
|
|
35
|
-
createStringDictionary,
|
|
36
|
-
type LocalizedString,
|
|
37
|
-
type LocalizedStringDictionary,
|
|
38
|
-
type LocalizedStringFormatter,
|
|
39
|
-
type LocalizedStrings,
|
|
40
|
-
} from './createStringFormatter';
|
|
1
|
+
// Locale context and provider
|
|
2
|
+
export {
|
|
3
|
+
I18nProvider,
|
|
4
|
+
useLocale,
|
|
5
|
+
createDefaultLocale,
|
|
6
|
+
getDefaultLocale,
|
|
7
|
+
type Direction,
|
|
8
|
+
type Locale,
|
|
9
|
+
type I18nProviderProps,
|
|
10
|
+
} from './locale';
|
|
11
|
+
|
|
12
|
+
// RTL utilities
|
|
13
|
+
export { isRTL, createCacheKey } from './utils';
|
|
14
|
+
|
|
15
|
+
// Number formatting
|
|
16
|
+
export {
|
|
17
|
+
NumberFormatter,
|
|
18
|
+
type NumberFormatOptions,
|
|
19
|
+
} from './NumberFormatter';
|
|
20
|
+
|
|
21
|
+
export { createNumberFormatter } from './createNumberFormatter';
|
|
22
|
+
|
|
23
|
+
// Date formatting
|
|
24
|
+
export { createDateFormatter } from './createDateFormatter';
|
|
25
|
+
|
|
26
|
+
// String collation
|
|
27
|
+
export { createCollator } from './createCollator';
|
|
28
|
+
|
|
29
|
+
// String filtering
|
|
30
|
+
export { createFilter, type Filter } from './createFilter';
|
|
31
|
+
|
|
32
|
+
// String formatting (ICU MessageFormat)
|
|
33
|
+
export {
|
|
34
|
+
createStringFormatter,
|
|
35
|
+
createStringDictionary,
|
|
36
|
+
type LocalizedString,
|
|
37
|
+
type LocalizedStringDictionary,
|
|
38
|
+
type LocalizedStringFormatter,
|
|
39
|
+
type LocalizedStrings,
|
|
40
|
+
} from './createStringFormatter';
|
package/src/i18n/locale.tsx
CHANGED
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Locale context and provider for solidaria
|
|
3
|
-
*
|
|
4
|
-
* Provides locale and text direction to the component tree.
|
|
5
|
-
*
|
|
6
|
-
* Port of @react-aria/i18n context and useDefaultLocale.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
type Accessor,
|
|
11
|
-
type JSX,
|
|
12
|
-
type ParentProps,
|
|
13
|
-
createContext,
|
|
14
|
-
createEffect,
|
|
15
|
-
createMemo,
|
|
16
|
-
createSignal,
|
|
17
|
-
onCleanup,
|
|
18
|
-
useContext,
|
|
19
|
-
} from 'solid-js';
|
|
20
|
-
import { isRTL } from './utils';
|
|
21
|
-
|
|
22
|
-
// ============================================
|
|
23
|
-
// TYPES
|
|
24
|
-
// ============================================
|
|
25
|
-
|
|
26
|
-
/** Text direction: left-to-right or right-to-left. */
|
|
27
|
-
export type Direction = 'ltr' | 'rtl';
|
|
28
|
-
|
|
29
|
-
/** Locale information including language code and text direction. */
|
|
30
|
-
export interface Locale {
|
|
31
|
-
/** The BCP47 language code for the locale (e.g., 'en-US', 'ar-SA'). */
|
|
32
|
-
locale: string;
|
|
33
|
-
/** The writing direction for the locale. */
|
|
34
|
-
direction: Direction;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface I18nProviderProps extends ParentProps {
|
|
38
|
-
/** The locale to apply to the children. If not provided, uses browser default. */
|
|
39
|
-
locale?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// ============================================
|
|
43
|
-
// GLOBAL STATE
|
|
44
|
-
// ============================================
|
|
45
|
-
|
|
46
|
-
// Symbol for server-provided locale
|
|
47
|
-
const localeSymbol = Symbol.for('solidaria.i18n.locale');
|
|
48
|
-
|
|
49
|
-
let currentLocale: Locale | null = null;
|
|
50
|
-
const listeners = new Set<(locale: Locale) => void>();
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Gets the default locale from the browser/system.
|
|
54
|
-
*/
|
|
55
|
-
export function getDefaultLocale(): Locale {
|
|
56
|
-
let locale =
|
|
57
|
-
(typeof window !== 'undefined' &&
|
|
58
|
-
(window as unknown as Record<symbol, string>)[localeSymbol]) ||
|
|
59
|
-
(typeof navigator !== 'undefined' &&
|
|
60
|
-
(navigator.language ||
|
|
61
|
-
(navigator as unknown as { userLanguage?: string }).userLanguage)) ||
|
|
62
|
-
'en-US';
|
|
63
|
-
|
|
64
|
-
// Validate the locale is supported
|
|
65
|
-
try {
|
|
66
|
-
Intl.DateTimeFormat.supportedLocalesOf([locale]);
|
|
67
|
-
} catch {
|
|
68
|
-
locale = 'en-US';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
locale,
|
|
73
|
-
direction: isRTL(locale) ? 'rtl' : 'ltr',
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function updateLocale(): void {
|
|
78
|
-
currentLocale = getDefaultLocale();
|
|
79
|
-
for (const listener of listeners) {
|
|
80
|
-
listener(currentLocale);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ============================================
|
|
85
|
-
// CONTEXT
|
|
86
|
-
// ============================================
|
|
87
|
-
|
|
88
|
-
const I18nContext = createContext<Accessor<Locale> | null>(null);
|
|
89
|
-
|
|
90
|
-
// ============================================
|
|
91
|
-
// HOOKS
|
|
92
|
-
// ============================================
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Returns the current browser/system locale, and updates when it changes.
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* ```tsx
|
|
99
|
-
* const locale = createDefaultLocale();
|
|
100
|
-
* console.log(locale().locale); // 'en-US'
|
|
101
|
-
* console.log(locale().direction); // 'ltr'
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
104
|
-
export function createDefaultLocale(): Accessor<Locale> {
|
|
105
|
-
if (!currentLocale) {
|
|
106
|
-
currentLocale = getDefaultLocale();
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const [locale, setLocale] = createSignal<Locale>(currentLocale);
|
|
110
|
-
|
|
111
|
-
createEffect(() => {
|
|
112
|
-
if (typeof window === 'undefined') {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (listeners.size === 0) {
|
|
117
|
-
window.addEventListener('languagechange', updateLocale);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
listeners.add(setLocale);
|
|
121
|
-
|
|
122
|
-
onCleanup(() => {
|
|
123
|
-
listeners.delete(setLocale);
|
|
124
|
-
if (listeners.size === 0) {
|
|
125
|
-
window.removeEventListener('languagechange', updateLocale);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return locale;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Returns the current locale and layout direction from context or browser default.
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* ```tsx
|
|
138
|
-
* function MyComponent() {
|
|
139
|
-
* const locale = useLocale();
|
|
140
|
-
* return <div dir={locale().direction}>{locale().locale}</div>;
|
|
141
|
-
* }
|
|
142
|
-
* ```
|
|
143
|
-
*/
|
|
144
|
-
export function useLocale(): Accessor<Locale> {
|
|
145
|
-
const context = useContext(I18nContext);
|
|
146
|
-
const defaultLocale = createDefaultLocale();
|
|
147
|
-
return context || defaultLocale;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// ============================================
|
|
151
|
-
// PROVIDER
|
|
152
|
-
// ============================================
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Provides the locale for the application to all child components.
|
|
156
|
-
*
|
|
157
|
-
* @example
|
|
158
|
-
* ```tsx
|
|
159
|
-
* // Use browser default locale
|
|
160
|
-
* <I18nProvider>
|
|
161
|
-
* <App />
|
|
162
|
-
* </I18nProvider>
|
|
163
|
-
*
|
|
164
|
-
* // Override with specific locale
|
|
165
|
-
* <I18nProvider locale="ar-SA">
|
|
166
|
-
* <App /> // Will have RTL direction
|
|
167
|
-
* </I18nProvider>
|
|
168
|
-
* ```
|
|
169
|
-
*/
|
|
170
|
-
export function I18nProvider(props: I18nProviderProps): JSX.Element {
|
|
171
|
-
const defaultLocale = createDefaultLocale();
|
|
172
|
-
|
|
173
|
-
const locale = createMemo<Locale>(() => {
|
|
174
|
-
if (props.locale) {
|
|
175
|
-
return {
|
|
176
|
-
locale: props.locale,
|
|
177
|
-
direction: isRTL(props.locale) ? 'rtl' : 'ltr',
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
return defaultLocale();
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
return (
|
|
184
|
-
<I18nContext.Provider value={locale}>
|
|
185
|
-
{props.children}
|
|
186
|
-
</I18nContext.Provider>
|
|
187
|
-
);
|
|
188
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Locale context and provider for solidaria
|
|
3
|
+
*
|
|
4
|
+
* Provides locale and text direction to the component tree.
|
|
5
|
+
*
|
|
6
|
+
* Port of @react-aria/i18n context and useDefaultLocale.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type Accessor,
|
|
11
|
+
type JSX,
|
|
12
|
+
type ParentProps,
|
|
13
|
+
createContext,
|
|
14
|
+
createEffect,
|
|
15
|
+
createMemo,
|
|
16
|
+
createSignal,
|
|
17
|
+
onCleanup,
|
|
18
|
+
useContext,
|
|
19
|
+
} from 'solid-js';
|
|
20
|
+
import { isRTL } from './utils';
|
|
21
|
+
|
|
22
|
+
// ============================================
|
|
23
|
+
// TYPES
|
|
24
|
+
// ============================================
|
|
25
|
+
|
|
26
|
+
/** Text direction: left-to-right or right-to-left. */
|
|
27
|
+
export type Direction = 'ltr' | 'rtl';
|
|
28
|
+
|
|
29
|
+
/** Locale information including language code and text direction. */
|
|
30
|
+
export interface Locale {
|
|
31
|
+
/** The BCP47 language code for the locale (e.g., 'en-US', 'ar-SA'). */
|
|
32
|
+
locale: string;
|
|
33
|
+
/** The writing direction for the locale. */
|
|
34
|
+
direction: Direction;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface I18nProviderProps extends ParentProps {
|
|
38
|
+
/** The locale to apply to the children. If not provided, uses browser default. */
|
|
39
|
+
locale?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ============================================
|
|
43
|
+
// GLOBAL STATE
|
|
44
|
+
// ============================================
|
|
45
|
+
|
|
46
|
+
// Symbol for server-provided locale
|
|
47
|
+
const localeSymbol = Symbol.for('solidaria.i18n.locale');
|
|
48
|
+
|
|
49
|
+
let currentLocale: Locale | null = null;
|
|
50
|
+
const listeners = new Set<(locale: Locale) => void>();
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Gets the default locale from the browser/system.
|
|
54
|
+
*/
|
|
55
|
+
export function getDefaultLocale(): Locale {
|
|
56
|
+
let locale =
|
|
57
|
+
(typeof window !== 'undefined' &&
|
|
58
|
+
(window as unknown as Record<symbol, string>)[localeSymbol]) ||
|
|
59
|
+
(typeof navigator !== 'undefined' &&
|
|
60
|
+
(navigator.language ||
|
|
61
|
+
(navigator as unknown as { userLanguage?: string }).userLanguage)) ||
|
|
62
|
+
'en-US';
|
|
63
|
+
|
|
64
|
+
// Validate the locale is supported
|
|
65
|
+
try {
|
|
66
|
+
Intl.DateTimeFormat.supportedLocalesOf([locale]);
|
|
67
|
+
} catch {
|
|
68
|
+
locale = 'en-US';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
locale,
|
|
73
|
+
direction: isRTL(locale) ? 'rtl' : 'ltr',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function updateLocale(): void {
|
|
78
|
+
currentLocale = getDefaultLocale();
|
|
79
|
+
for (const listener of listeners) {
|
|
80
|
+
listener(currentLocale);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ============================================
|
|
85
|
+
// CONTEXT
|
|
86
|
+
// ============================================
|
|
87
|
+
|
|
88
|
+
const I18nContext = createContext<Accessor<Locale> | null>(null);
|
|
89
|
+
|
|
90
|
+
// ============================================
|
|
91
|
+
// HOOKS
|
|
92
|
+
// ============================================
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns the current browser/system locale, and updates when it changes.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```tsx
|
|
99
|
+
* const locale = createDefaultLocale();
|
|
100
|
+
* console.log(locale().locale); // 'en-US'
|
|
101
|
+
* console.log(locale().direction); // 'ltr'
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function createDefaultLocale(): Accessor<Locale> {
|
|
105
|
+
if (!currentLocale) {
|
|
106
|
+
currentLocale = getDefaultLocale();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const [locale, setLocale] = createSignal<Locale>(currentLocale);
|
|
110
|
+
|
|
111
|
+
createEffect(() => {
|
|
112
|
+
if (typeof window === 'undefined') {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (listeners.size === 0) {
|
|
117
|
+
window.addEventListener('languagechange', updateLocale);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
listeners.add(setLocale);
|
|
121
|
+
|
|
122
|
+
onCleanup(() => {
|
|
123
|
+
listeners.delete(setLocale);
|
|
124
|
+
if (listeners.size === 0) {
|
|
125
|
+
window.removeEventListener('languagechange', updateLocale);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return locale;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Returns the current locale and layout direction from context or browser default.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```tsx
|
|
138
|
+
* function MyComponent() {
|
|
139
|
+
* const locale = useLocale();
|
|
140
|
+
* return <div dir={locale().direction}>{locale().locale}</div>;
|
|
141
|
+
* }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export function useLocale(): Accessor<Locale> {
|
|
145
|
+
const context = useContext(I18nContext);
|
|
146
|
+
const defaultLocale = createDefaultLocale();
|
|
147
|
+
return context || defaultLocale;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============================================
|
|
151
|
+
// PROVIDER
|
|
152
|
+
// ============================================
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Provides the locale for the application to all child components.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```tsx
|
|
159
|
+
* // Use browser default locale
|
|
160
|
+
* <I18nProvider>
|
|
161
|
+
* <App />
|
|
162
|
+
* </I18nProvider>
|
|
163
|
+
*
|
|
164
|
+
* // Override with specific locale
|
|
165
|
+
* <I18nProvider locale="ar-SA">
|
|
166
|
+
* <App /> // Will have RTL direction
|
|
167
|
+
* </I18nProvider>
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export function I18nProvider(props: I18nProviderProps): JSX.Element {
|
|
171
|
+
const defaultLocale = createDefaultLocale();
|
|
172
|
+
|
|
173
|
+
const locale = createMemo<Locale>(() => {
|
|
174
|
+
if (props.locale) {
|
|
175
|
+
return {
|
|
176
|
+
locale: props.locale,
|
|
177
|
+
direction: isRTL(props.locale) ? 'rtl' : 'ltr',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return defaultLocale();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<I18nContext.Provider value={locale}>
|
|
185
|
+
{props.children}
|
|
186
|
+
</I18nContext.Provider>
|
|
187
|
+
);
|
|
188
|
+
}
|