@allxsmith/bestax-bulma 5.52.0 → 5.53.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/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/components/Modal.js +2 -1
- package/dist/esm/components/Modal.js.map +1 -1
- package/dist/esm/components/Sidebar.js +3 -1
- package/dist/esm/components/Sidebar.js.map +1 -1
- package/dist/esm/components/Toast.js +8 -5
- package/dist/esm/components/Toast.js.map +1 -1
- package/dist/esm/elements/Notification.js +4 -2
- package/dist/esm/elements/Notification.js.map +1 -1
- package/dist/esm/form/Autocomplete.js +3 -2
- package/dist/esm/form/Autocomplete.js.map +1 -1
- package/dist/esm/form/Checkbox.js +3 -2
- package/dist/esm/form/Checkbox.js.map +1 -1
- package/dist/esm/form/CheckboxCard.js +3 -2
- package/dist/esm/form/CheckboxCard.js.map +1 -1
- package/dist/esm/form/Combobox.js +3 -2
- package/dist/esm/form/Combobox.js.map +1 -1
- package/dist/esm/form/DateInputBase.js +15 -6
- package/dist/esm/form/DateInputBase.js.map +1 -1
- package/dist/esm/form/DateRangeInputBase.js +15 -5
- package/dist/esm/form/DateRangeInputBase.js.map +1 -1
- package/dist/esm/form/DateTimeInputBase.js +15 -6
- package/dist/esm/form/DateTimeInputBase.js.map +1 -1
- package/dist/esm/form/Fieldset.js +64 -0
- package/dist/esm/form/Fieldset.js.map +1 -0
- package/dist/esm/form/FormContext.js +17 -1
- package/dist/esm/form/FormContext.js.map +1 -1
- package/dist/esm/form/InputBase.js +3 -2
- package/dist/esm/form/InputBase.js.map +1 -1
- package/dist/esm/form/Numberinput.js +3 -2
- package/dist/esm/form/Numberinput.js.map +1 -1
- package/dist/esm/form/PinInput.js +3 -2
- package/dist/esm/form/PinInput.js.map +1 -1
- package/dist/esm/form/Radio.js +3 -2
- package/dist/esm/form/Radio.js.map +1 -1
- package/dist/esm/form/RadioCard.js +3 -2
- package/dist/esm/form/RadioCard.js.map +1 -1
- package/dist/esm/form/Rate.js +3 -2
- package/dist/esm/form/Rate.js.map +1 -1
- package/dist/esm/form/SelectBase.js +3 -2
- package/dist/esm/form/SelectBase.js.map +1 -1
- package/dist/esm/form/Slider.js +3 -2
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Switch.js +3 -1
- package/dist/esm/form/Switch.js.map +1 -1
- package/dist/esm/form/Taginput.js +3 -2
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/TextAreaBase.js +3 -2
- package/dist/esm/form/TextAreaBase.js.map +1 -1
- package/dist/esm/form/TimeInputBase.js +13 -6
- package/dist/esm/form/TimeInputBase.js.map +1 -1
- package/dist/esm/form/_pickerInternals/PickerPopover.js +4 -2
- package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -1
- package/dist/esm/form/_pickerInternals/useLocaleDefaults.js +80 -0
- package/dist/esm/form/_pickerInternals/useLocaleDefaults.js.map +1 -0
- package/dist/esm/helpers/LocaleProvider.js +153 -0
- package/dist/esm/helpers/LocaleProvider.js.map +1 -0
- package/dist/esm/helpers/localeInfo.js +109 -0
- package/dist/esm/helpers/localeInfo.js.map +1 -0
- package/dist/esm/helpers/portal.js +14 -1
- package/dist/esm/helpers/portal.js.map +1 -1
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +504 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/form/DateInputBase.d.ts +25 -3
- package/dist/types/form/DateRangeInputBase.d.ts +25 -3
- package/dist/types/form/DateTimeInputBase.d.ts +25 -3
- package/dist/types/form/Fieldset.d.ts +86 -0
- package/dist/types/form/FormContext.d.ts +12 -0
- package/dist/types/form/TimeInputBase.d.ts +5 -1
- package/dist/types/form/_pickerInternals/PickerPopover.d.ts +6 -0
- package/dist/types/form/_pickerInternals/useLocaleDefaults.d.ts +49 -0
- package/dist/types/helpers/LocaleProvider.d.ts +128 -0
- package/dist/types/helpers/localeInfo.d.ts +23 -0
- package/dist/types/helpers/portal.d.ts +11 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types-cjs/form/DateInputBase.d.ts +25 -3
- package/dist/types-cjs/form/DateRangeInputBase.d.ts +25 -3
- package/dist/types-cjs/form/DateTimeInputBase.d.ts +25 -3
- package/dist/types-cjs/form/Fieldset.d.ts +86 -0
- package/dist/types-cjs/form/FormContext.d.ts +12 -0
- package/dist/types-cjs/form/TimeInputBase.d.ts +5 -1
- package/dist/types-cjs/form/_pickerInternals/PickerPopover.d.ts +6 -0
- package/dist/types-cjs/form/_pickerInternals/useLocaleDefaults.d.ts +49 -0
- package/dist/types-cjs/helpers/LocaleProvider.d.ts +128 -0
- package/dist/types-cjs/helpers/localeInfo.d.ts +23 -0
- package/dist/types-cjs/helpers/portal.d.ts +11 -0
- package/dist/types-cjs/index.d.ts +3 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +1 -1
- package/src/scss/form/_fieldset.scss +108 -0
- package/src/scss/form/_index.scss +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocaleProvider.js","sources":["../../../src/helpers/LocaleProvider.tsx"],"sourcesContent":["import React, {\n createContext,\n forwardRef,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { classNames } from './classNames';\nimport { useBulmaClasses, BulmaClassesProps } from './useBulmaClasses';\nimport { warnOnce } from './devWarnings';\nimport { canonicalLocale, localeDirection } from './localeInfo';\n\n/** A writing direction. */\nexport type TextDirection = 'ltr' | 'rtl';\n\n/** What the nearest `LocaleProvider` sets, both `undefined` outside one. */\nexport interface LocaleContextValue {\n /**\n * The locale, as a canonical BCP 47 tag such as `\"ar-EG\"`: the provider's\n * own, else the one an outer provider sets.\n */\n locale?: string;\n /**\n * The direction: the provider's own `dir`, else its own locale's, else the\n * one an outer provider sets.\n */\n dir?: TextDirection;\n}\n\nconst LocaleContext = createContext<LocaleContextValue | null>(null);\n\n/** The nearest provider's wrapper element, for `LocalePortalScope` to test targets against. */\nconst LocaleElementContext =\n createContext<React.RefObject<HTMLDivElement | null> | null>(null);\n\n/**\n * Props for the LocaleProvider component. The helper props, the other\n * attributes and the `ref` land on its `<div>`.\n */\nexport interface LocaleProviderProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'dir' | 'lang' | 'color'>,\n Omit<BulmaClassesProps, 'color' | 'backgroundColor'> {\n /**\n * A BCP 47 language tag, such as `\"de\"` or `\"ar-EG\"`. It becomes the\n * wrapper's `lang`, the default `locale` of the date and time pickers\n * inside, and, with no `dir`, the direction, from the way its script is\n * written. Unset, a nested provider keeps the outer one's. A tag `Intl`\n * refuses is ignored, with a warning in development.\n */\n locale?: string;\n /**\n * The direction, whatever the locale. Unset, it follows this provider's\n * `locale`, else an outer provider's direction, else the page's.\n */\n dir?: TextDirection;\n /** The part of the app it covers. */\n children?: React.ReactNode;\n}\n\n/** A tag in canonical form, or `undefined`, warning about one `Intl` refuses. */\nfunction validLocale(tag: string | undefined): string | undefined {\n try {\n return canonicalLocale(tag);\n } catch {\n warnOnce(\n `locale-provider-invalid:${tag}`,\n `[bestax-bulma] <LocaleProvider locale=\"${tag}\">: not a language ` +\n 'tag Intl accepts, so it is ignored. Use a BCP 47 tag such as ' +\n '\"en-US\", with a hyphen rather than an underscore.'\n );\n return undefined;\n }\n}\n\n/**\n * Sets the language and writing direction for the part of the app inside it, on a wrapper `<div>` and on what the library portals out of it.\n *\n * The wrapper carries `dir` and `lang`, so CSS and the components that read\n * the computed direction follow it, as they follow `<html dir>`. A `locale`\n * alone sets the direction of its script, and a `dir` sets the direction\n * whatever the locale. A nested provider keeps whatever it leaves unset.\n *\n * Inside it, the date and time pickers take its `locale` unless given their\n * own, and their week starts on the first day of the locale they use unless\n * `firstDayOfWeek` is set, and a picker with a `locale` of its own is read\n * like a nested provider. The library's portaled content, such as a\n * `Popover` panel, a `Modal` with `portal`, a `Toast` or a `Portal`'s\n * children, keeps the same `dir` and `lang` though it renders outside the\n * wrapper: in a container outside the wrapper, it sits in a\n * `display: contents` element that carries them. Without a provider none of\n * this changes.\n *\n * @function\n * @param {LocaleProviderProps} props - Props for the LocaleProvider.\n * @returns {JSX.Element} The wrapper, inside the context.\n *\n * @example\n * <LocaleProvider locale=\"ar-EG\">\n * <App />\n * </LocaleProvider>\n */\nexport const LocaleProvider = forwardRef<HTMLDivElement, LocaleProviderProps>(\n (\n { locale: localeProp, dir: dirProp, className, children, ...props },\n ref\n ) => {\n const outer = useContext(LocaleContext);\n const ownLocale = useMemo(() => validLocale(localeProp), [localeProp]);\n const ownLocaleDir = useMemo(\n () => (ownLocale ? localeDirection(ownLocale) : undefined),\n [ownLocale]\n );\n const locale = ownLocale || outer?.locale;\n const dir = dirProp || ownLocaleDir || outer?.dir;\n const value = useMemo(() => ({ locale, dir }), [locale, dir]);\n\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n\n // The wrapper, for portaled content to tell whether its target is inside\n // it, and the caller's ref. A callback ref's cleanup is held and run on\n // detach, as Toast and Modal do, since React 18 discards the return value.\n const elementRef = useRef<HTMLDivElement | null>(null);\n const consumerCleanupRef = useRef<(() => void) | null>(null);\n const setElement = useCallback(\n (node: HTMLDivElement | null) => {\n elementRef.current = node;\n if (typeof ref === 'function') {\n if (node === null) {\n const consumerCleanup = consumerCleanupRef.current;\n consumerCleanupRef.current = null;\n if (consumerCleanup) consumerCleanup();\n else ref(null);\n return;\n }\n const cleanup: unknown = ref(node);\n consumerCleanupRef.current =\n typeof cleanup === 'function' ? (cleanup as () => void) : null;\n } else if (ref) {\n ref.current = node;\n }\n },\n [ref]\n );\n\n return (\n <LocaleContext.Provider value={value}>\n <LocaleElementContext.Provider value={elementRef}>\n <div\n ref={setElement}\n className={classNames(bulmaHelperClasses, className) || undefined}\n {...rest}\n dir={dir}\n lang={locale}\n >\n {children}\n </div>\n </LocaleElementContext.Provider>\n </LocaleContext.Provider>\n );\n }\n);\n\nLocaleProvider.displayName = 'LocaleProvider';\n\n/** What `useLocale` returns outside a provider, the same object each time. */\nconst noLocale: LocaleContextValue = {};\n\n/**\n * The locale and direction the nearest `LocaleProvider` sets, for an app's own `Intl` calls or its own portaled content; both are `undefined` outside one.\n *\n * It isn't the page's direction: with no provider, or one that sets no\n * direction, the page's `<html dir>` still decides. To act on the direction\n * an element is laid out in, read `getComputedStyle(element).direction`, as\n * the library's components do.\n *\n * @function\n * @returns {LocaleContextValue} The nearest provider's `locale` and `dir`.\n *\n * @example\n * const { locale } = useLocale();\n * const price = new Intl.NumberFormat(locale, {\n * style: 'currency',\n * currency: 'EUR',\n * }).format(12.5);\n */\nexport function useLocale(): LocaleContextValue {\n return useContext(LocaleContext) ?? noLocale;\n}\n\n/**\n * INTERNAL, deliberately not exported from `src/index.ts`. The nearest\n * provider's settings, or `null` outside any provider, so a caller can tell\n * \"no provider\" from \"a provider that sets nothing\".\n */\nexport function useLocaleScope(): LocaleContextValue | null {\n return useContext(LocaleContext);\n}\n\nconst displayContents: React.CSSProperties = { display: 'contents' };\n\n/** The `dir` and `lang` portaled content carries: a provider's, or a picker's own. */\nexport interface PortalLocale {\n /** The `lang` to carry, unset for none. */\n locale?: string;\n /** The `dir` to carry, unset for none. */\n dir?: string;\n}\n\n/**\n * INTERNAL, deliberately not exported from `src/index.ts`. Keeps the `dir`\n * and `lang` of the nearest provider, or the `scope` given in their place,\n * on content the library portals into `target`, which has left the\n * provider's wrapper behind.\n *\n * A target inside the provider's own wrapper gets the content as it is: it\n * inherits from the wrapper, and follows it when the provider changes.\n * Content that must be its container's direct child, a `<tr>` portaled into\n * a `<tbody>` there, stays one. Any other target, `document.body` included,\n * gets the content inside a `display: contents` element carrying the\n * values, which adds no box. So does content with a `scope` of its own, a\n * picker's panel, since the provider's values aren't its own.\n *\n * Which of the two is decided once, when the content mounts, and kept while\n * it stays: switching between them would put a different element in its\n * place and remount everything inside, losing typed text, focus and timers.\n * A change of locale or direction updates the wrapper's attributes instead.\n * A target is never left bare because something else, such as `<html>`,\n * happens to carry the same values, since that can stop being true without\n * the content remounting. Outside a provider it renders the children alone,\n * so nothing changes there.\n */\nexport function LocalePortalScope({\n children,\n target,\n scope,\n}: {\n children: React.ReactNode;\n /** The element the content is portaled into. */\n target: Element;\n /** Values to carry in place of the provider's, such as a picker's own. */\n scope?: PortalLocale;\n}) {\n const provider = useContext(LocaleContext);\n const element = useContext(LocaleElementContext);\n const [wrap] = useState(\n () => scope !== undefined || !element?.current?.contains(target)\n );\n if (!provider || !wrap) return <>{children}</>;\n const values = scope ?? provider;\n return (\n <div dir={values.dir} lang={values.locale} style={displayContents}>\n {children}\n </div>\n );\n}\n"],"names":["_jsx","_Fragment"],"mappings":";;;;;;;;AA+BA,MAAM,aAAa,GAAG,aAAa,CAA4B,IAAI,CAAC;AAEpE;AACA,MAAM,oBAAoB,GACxB,aAAa,CAAgD,IAAI,CAAC;AA2BpE;AACA,SAAS,WAAW,CAAC,GAAuB,EAAA;AAC1C,IAAA,IAAI;AACF,QAAA,OAAO,eAAe,CAAC,GAAG,CAAC;IAC7B;AAAE,IAAA,MAAM;AACN,QAAA,QAAQ,CACN,CAAA,wBAAA,EAA2B,GAAG,EAAE,EAChC,CAAA,uCAAA,EAA0C,GAAG,CAAA,mBAAA,CAAqB;YAChE,+DAA+D;AAC/D,YAAA,mDAAmD,CACtD;AACD,QAAA,OAAO,SAAS;IAClB;AACF;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;AACI,MAAM,cAAc,GAAG,UAAU,CACtC,CACE,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EACnE,GAAG,KACD;AACF,IAAA,MAAM,KAAK,GAAG,UAAU,CAAC,aAAa,CAAC;AACvC,IAAA,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,EAC1D,CAAC,SAAS,CAAC,CACZ;AACD,IAAA,MAAM,MAAM,GAAG,SAAS,IAAI,KAAK,EAAE,MAAM;IACzC,MAAM,GAAG,GAAG,OAAO,IAAI,YAAY,IAAI,KAAK,EAAE,GAAG;IACjD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE7D,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,KAAK,CAAC;;;;AAK3D,IAAA,MAAM,UAAU,GAAG,MAAM,CAAwB,IAAI,CAAC;AACtD,IAAA,MAAM,kBAAkB,GAAG,MAAM,CAAsB,IAAI,CAAC;AAC5D,IAAA,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,IAA2B,KAAI;AAC9B,QAAA,UAAU,CAAC,OAAO,GAAG,IAAI;AACzB,QAAA,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE;AAC7B,YAAA,IAAI,IAAI,KAAK,IAAI,EAAE;AACjB,gBAAA,MAAM,eAAe,GAAG,kBAAkB,CAAC,OAAO;AAClD,gBAAA,kBAAkB,CAAC,OAAO,GAAG,IAAI;AACjC,gBAAA,IAAI,eAAe;AAAE,oBAAA,eAAe,EAAE;;oBACjC,GAAG,CAAC,IAAI,CAAC;gBACd;YACF;AACA,YAAA,MAAM,OAAO,GAAY,GAAG,CAAC,IAAI,CAAC;AAClC,YAAA,kBAAkB,CAAC,OAAO;gBACxB,OAAO,OAAO,KAAK,UAAU,GAAI,OAAsB,GAAG,IAAI;QAClE;aAAO,IAAI,GAAG,EAAE;AACd,YAAA,GAAG,CAAC,OAAO,GAAG,IAAI;QACpB;AACF,IAAA,CAAC,EACD,CAAC,GAAG,CAAC,CACN;IAED,QACEA,IAAC,aAAa,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,QAAA,EAClCA,GAAA,CAAC,oBAAoB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,UAAU,YAC9CA,GAAA,CAAA,KAAA,EAAA,EACE,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,UAAU,CAAC,kBAAkB,EAAE,SAAS,CAAC,IAAI,SAAS,EAAA,GAC7D,IAAI,EACR,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,MAAM,EAAA,QAAA,EAEX,QAAQ,EAAA,CACL,EAAA,CACwB,EAAA,CACT;AAE7B,CAAC;AAGH,cAAc,CAAC,WAAW,GAAG,gBAAgB;AAE7C;AACA,MAAM,QAAQ,GAAuB,EAAE;AAEvC;;;;;;;;;;;;;;;;;AAiBG;SACa,SAAS,GAAA;AACvB,IAAA,OAAO,UAAU,CAAC,aAAa,CAAC,IAAI,QAAQ;AAC9C;AAEA;;;;AAIG;SACa,cAAc,GAAA;AAC5B,IAAA,OAAO,UAAU,CAAC,aAAa,CAAC;AAClC;AAEA,MAAM,eAAe,GAAwB,EAAE,OAAO,EAAE,UAAU,EAAE;AAUpE;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,iBAAiB,CAAC,EAChC,QAAQ,EACR,MAAM,EACN,KAAK,GAON,EAAA;AACC,IAAA,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC;AAC1C,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,oBAAoB,CAAC;IAChD,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CACrB,MAAM,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CACjE;AACD,IAAA,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI;QAAE,OAAOA,GAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAI;AAC9C,IAAA,MAAM,MAAM,GAAG,KAAK,IAAI,QAAQ;IAChC,QACED,aAAK,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,eAAe,EAAA,QAAA,EAC9D,QAAQ,EAAA,CACL;AAEV;;"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* @allxsmith/bestax-bulma — AI agents: see AGENTS.md in the package root, or https://bestax.io/llms.txt */
|
|
2
|
+
// INTERNAL: deliberately not exported from src/index.ts. What a locale says
|
|
3
|
+
// about its direction, read from `Intl.Locale` where the engine has the data,
|
|
4
|
+
// and about its week, read from a copy of CLDR's week data.
|
|
5
|
+
/**
|
|
6
|
+
* Scripts written right to left: every script for which ICU's text info
|
|
7
|
+
* says `rtl`, as Node reported it, and `Aran`, the Nastaliq form of Arabic
|
|
8
|
+
* that WebKit fills in for Urdu. Read only where the engine has no text info
|
|
9
|
+
* of its own, which includes Firefox before 153.
|
|
10
|
+
*/
|
|
11
|
+
const RTL_SCRIPTS = ' Adlm Arab Aran Armi Avst Chrs Cprt Elym Gara Hatr Hebr Hung Khar Lydi ' +
|
|
12
|
+
'Mand Mani Mend Merc Mero Narb Nbat Nkoo Orkh Ougr Palm Phli Phlp Phnx ' +
|
|
13
|
+
'Prti Rohg Samr Sarb Sidt Sogd Sogo Syrc Thaa Yezi ';
|
|
14
|
+
/**
|
|
15
|
+
* Widely used languages whose usual script reads right to left, for an engine
|
|
16
|
+
* that can't fill in a locale's script with `maximize()`.
|
|
17
|
+
*/
|
|
18
|
+
const RTL_LANGUAGES = ' ar ckb dv fa he iw ji ks mzn nqo pnb ps sd syr ug ur yi ';
|
|
19
|
+
/**
|
|
20
|
+
* The regions whose week doesn't start on Monday, by the day it starts on
|
|
21
|
+
* (0 = Sunday, 5 = Friday, 6 = Saturday), from CLDR 48's week data as Node
|
|
22
|
+
* reported it. The library reads this rather than `Intl.Locale`'s week info
|
|
23
|
+
* because engines disagree: Firefox before 153 has none, and WebKit's differs
|
|
24
|
+
* from Node's, Chromium's and current Firefox's for China, Algeria, Jordan and
|
|
25
|
+
* Iceland among others, so an inline calendar rendered on the server would
|
|
26
|
+
* fail to hydrate there. With one table, the server and every browser agree.
|
|
27
|
+
*/
|
|
28
|
+
const WEEK_STARTS = [
|
|
29
|
+
[
|
|
30
|
+
0,
|
|
31
|
+
' AG AS BD BR BS BT BU BW BZ CA CO DM DO ET GT GU HK HN ID IL IN IS JM JP ' +
|
|
32
|
+
'KE KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PT PY RH SA SG SV TH ' +
|
|
33
|
+
'TT TW UM US VE VI WS YD YE ZA ZW ',
|
|
34
|
+
],
|
|
35
|
+
[5, ' MV '],
|
|
36
|
+
[6, ' AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY '],
|
|
37
|
+
];
|
|
38
|
+
/** Whether a space-separated list, padded with spaces, holds `code`. */
|
|
39
|
+
const listed = (list, code) => list.includes(` ${code} `);
|
|
40
|
+
/** The `-u-fw-` keyword's values, by the day they name. */
|
|
41
|
+
const FW_DAYS = {
|
|
42
|
+
sun: 0,
|
|
43
|
+
mon: 1,
|
|
44
|
+
tue: 2,
|
|
45
|
+
wed: 3,
|
|
46
|
+
thu: 4,
|
|
47
|
+
fri: 5,
|
|
48
|
+
sat: 6,
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The canonical form of a BCP 47 tag (`"en-us"` becomes `"en-US"`), or
|
|
52
|
+
* `undefined` for an empty or missing one. Throws a `RangeError` for a tag
|
|
53
|
+
* `Intl` refuses, as `Intl.DateTimeFormat` would.
|
|
54
|
+
*/
|
|
55
|
+
function canonicalLocale(tag) {
|
|
56
|
+
if (!tag)
|
|
57
|
+
return undefined;
|
|
58
|
+
return Intl.getCanonicalLocales(tag)[0];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The direction a locale's script is written in: from `Intl.Locale`'s text
|
|
62
|
+
* info, else from the script `maximize()` fills in, else from the language.
|
|
63
|
+
*
|
|
64
|
+
* @param locale - A canonical tag, as `canonicalLocale` returns.
|
|
65
|
+
*/
|
|
66
|
+
function localeDirection(locale) {
|
|
67
|
+
const intlLocale = new Intl.Locale(locale);
|
|
68
|
+
const info = intlLocale;
|
|
69
|
+
const direction = typeof info.getTextInfo === 'function'
|
|
70
|
+
? info.getTextInfo().direction
|
|
71
|
+
: info.textInfo?.direction;
|
|
72
|
+
if (direction === 'rtl' || direction === 'ltr')
|
|
73
|
+
return direction;
|
|
74
|
+
if (typeof intlLocale.maximize === 'function') {
|
|
75
|
+
const script = intlLocale.maximize().script;
|
|
76
|
+
return script && listed(RTL_SCRIPTS, script) ? 'rtl' : 'ltr';
|
|
77
|
+
}
|
|
78
|
+
return listed(RTL_LANGUAGES, intlLocale.language) ? 'rtl' : 'ltr';
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The day a locale's week starts on, 0 for Sunday, as `getWeekInfo()` reads
|
|
82
|
+
* it: the tag's `-u-fw-` keyword, else the region its `-u-rg-` keyword names,
|
|
83
|
+
* else its own region or the one `maximize()` fills in, looked up in CLDR's
|
|
84
|
+
* week data, where a region not listed starts on Monday.
|
|
85
|
+
*
|
|
86
|
+
* @param locale - A canonical tag, as `canonicalLocale` returns.
|
|
87
|
+
*/
|
|
88
|
+
function localeFirstDay(locale) {
|
|
89
|
+
const fw = /-u(?:-[a-z0-9]{2,8})*?-fw-([a-z]{3})(?=-|$)/i.exec(locale);
|
|
90
|
+
if (fw && fw[1].toLowerCase() in FW_DAYS)
|
|
91
|
+
return FW_DAYS[fw[1].toLowerCase()];
|
|
92
|
+
const rg = /-u(?:-[a-z0-9]{2,8})*?-rg-([a-z]{2})[a-z0-9]{1,4}(?=-|$)/i.exec(locale);
|
|
93
|
+
const intlLocale = new Intl.Locale(locale);
|
|
94
|
+
const region = rg
|
|
95
|
+
? rg[1].toUpperCase()
|
|
96
|
+
: typeof intlLocale.maximize === 'function'
|
|
97
|
+
? intlLocale.maximize().region
|
|
98
|
+
: intlLocale.region;
|
|
99
|
+
if (region) {
|
|
100
|
+
for (const [day, regions] of WEEK_STARTS) {
|
|
101
|
+
if (listed(regions, region))
|
|
102
|
+
return day;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { canonicalLocale, localeDirection, localeFirstDay };
|
|
109
|
+
//# sourceMappingURL=localeInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localeInfo.js","sources":["../../../src/helpers/localeInfo.ts"],"sourcesContent":["// INTERNAL: deliberately not exported from src/index.ts. What a locale says\n// about its direction, read from `Intl.Locale` where the engine has the data,\n// and about its week, read from a copy of CLDR's week data.\n\nimport type { DayOfWeek } from '../form/_pickerInternals/pickerTypes';\n\n/** The parts of `Intl.Locale` newer than the ES2020 library types. */\ninterface LocaleInfo {\n getTextInfo?: () => { direction?: string };\n textInfo?: { direction?: string };\n}\n\n/**\n * Scripts written right to left: every script for which ICU's text info\n * says `rtl`, as Node reported it, and `Aran`, the Nastaliq form of Arabic\n * that WebKit fills in for Urdu. Read only where the engine has no text info\n * of its own, which includes Firefox before 153.\n */\nconst RTL_SCRIPTS =\n ' Adlm Arab Aran Armi Avst Chrs Cprt Elym Gara Hatr Hebr Hung Khar Lydi ' +\n 'Mand Mani Mend Merc Mero Narb Nbat Nkoo Orkh Ougr Palm Phli Phlp Phnx ' +\n 'Prti Rohg Samr Sarb Sidt Sogd Sogo Syrc Thaa Yezi ';\n\n/**\n * Widely used languages whose usual script reads right to left, for an engine\n * that can't fill in a locale's script with `maximize()`.\n */\nconst RTL_LANGUAGES =\n ' ar ckb dv fa he iw ji ks mzn nqo pnb ps sd syr ug ur yi ';\n\n/**\n * The regions whose week doesn't start on Monday, by the day it starts on\n * (0 = Sunday, 5 = Friday, 6 = Saturday), from CLDR 48's week data as Node\n * reported it. The library reads this rather than `Intl.Locale`'s week info\n * because engines disagree: Firefox before 153 has none, and WebKit's differs\n * from Node's, Chromium's and current Firefox's for China, Algeria, Jordan and\n * Iceland among others, so an inline calendar rendered on the server would\n * fail to hydrate there. With one table, the server and every browser agree.\n */\nconst WEEK_STARTS: ReadonlyArray<readonly [DayOfWeek, string]> = [\n [\n 0,\n ' AG AS BD BR BS BT BU BW BZ CA CO DM DO ET GT GU HK HN ID IL IN IS JM JP ' +\n 'KE KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PT PY RH SA SG SV TH ' +\n 'TT TW UM US VE VI WS YD YE ZA ZW ',\n ],\n [5, ' MV '],\n [6, ' AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY '],\n];\n\n/** Whether a space-separated list, padded with spaces, holds `code`. */\nconst listed = (list: string, code: string) => list.includes(` ${code} `);\n\n/** The `-u-fw-` keyword's values, by the day they name. */\nconst FW_DAYS: Record<string, DayOfWeek> = {\n sun: 0,\n mon: 1,\n tue: 2,\n wed: 3,\n thu: 4,\n fri: 5,\n sat: 6,\n};\n\n/**\n * The canonical form of a BCP 47 tag (`\"en-us\"` becomes `\"en-US\"`), or\n * `undefined` for an empty or missing one. Throws a `RangeError` for a tag\n * `Intl` refuses, as `Intl.DateTimeFormat` would.\n */\nexport function canonicalLocale(tag: string | undefined): string | undefined {\n if (!tag) return undefined;\n return Intl.getCanonicalLocales(tag)[0];\n}\n\n/**\n * The direction a locale's script is written in: from `Intl.Locale`'s text\n * info, else from the script `maximize()` fills in, else from the language.\n *\n * @param locale - A canonical tag, as `canonicalLocale` returns.\n */\nexport function localeDirection(locale: string): 'ltr' | 'rtl' {\n const intlLocale = new Intl.Locale(locale);\n const info = intlLocale as unknown as LocaleInfo;\n const direction =\n typeof info.getTextInfo === 'function'\n ? info.getTextInfo().direction\n : info.textInfo?.direction;\n if (direction === 'rtl' || direction === 'ltr') return direction;\n if (typeof intlLocale.maximize === 'function') {\n const script = intlLocale.maximize().script;\n return script && listed(RTL_SCRIPTS, script) ? 'rtl' : 'ltr';\n }\n return listed(RTL_LANGUAGES, intlLocale.language) ? 'rtl' : 'ltr';\n}\n\n/**\n * The day a locale's week starts on, 0 for Sunday, as `getWeekInfo()` reads\n * it: the tag's `-u-fw-` keyword, else the region its `-u-rg-` keyword names,\n * else its own region or the one `maximize()` fills in, looked up in CLDR's\n * week data, where a region not listed starts on Monday.\n *\n * @param locale - A canonical tag, as `canonicalLocale` returns.\n */\nexport function localeFirstDay(locale: string): DayOfWeek {\n const fw = /-u(?:-[a-z0-9]{2,8})*?-fw-([a-z]{3})(?=-|$)/i.exec(locale);\n if (fw && fw[1].toLowerCase() in FW_DAYS) return FW_DAYS[fw[1].toLowerCase()];\n const rg = /-u(?:-[a-z0-9]{2,8})*?-rg-([a-z]{2})[a-z0-9]{1,4}(?=-|$)/i.exec(\n locale\n );\n const intlLocale = new Intl.Locale(locale);\n const region = rg\n ? rg[1].toUpperCase()\n : typeof intlLocale.maximize === 'function'\n ? intlLocale.maximize().region\n : intlLocale.region;\n if (region) {\n for (const [day, regions] of WEEK_STARTS) {\n if (listed(regions, region)) return day;\n }\n }\n return 1;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { jsx, Fragment } from 'react/jsx-runtime';
|
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
4
|
import { useIsHydrated } from './useIsHydrated.js';
|
|
5
5
|
import { useConfig } from './Config.js';
|
|
6
|
+
import { LocalePortalScope } from './LocaleProvider.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Resolves a portal target: an `HTMLElement` is used directly, a non-empty
|
|
@@ -65,6 +66,17 @@ function usePortalContainer() {
|
|
|
65
66
|
* also reaches what the library's components portal, such as Popover's
|
|
66
67
|
* `appendToBody` panel or a `Modal` with `portal`.
|
|
67
68
|
*
|
|
69
|
+
* Inside a `LocaleProvider`, the children keep its `dir` and `lang`. A
|
|
70
|
+
* container inside the provider's own wrapper takes the children as they
|
|
71
|
+
* are, and they follow the provider through the page. Any other,
|
|
72
|
+
* `document.body` included, gets them inside one `<div>` carrying the
|
|
73
|
+
* provider's values, with `display: contents` so it adds no box. It is
|
|
74
|
+
* still an element, so content that must be the container's direct child,
|
|
75
|
+
* a `<tr>` in a `<tbody>`, or that a direct-child selector styles, belongs
|
|
76
|
+
* in a container inside the provider. Which of the two is settled when the
|
|
77
|
+
* children mount, so a change of locale updates them in place rather than
|
|
78
|
+
* remounting them.
|
|
79
|
+
*
|
|
68
80
|
* Tab order and focus follow the DOM too. Content portaled from inside a
|
|
69
81
|
* focus trap is no longer inside the trapped element, so the trap neither
|
|
70
82
|
* reaches it nor holds focus there: render nested overlays inside the
|
|
@@ -94,7 +106,8 @@ function Portal({ children, container, disabled = false }) {
|
|
|
94
106
|
return jsx(Fragment, { children: children });
|
|
95
107
|
if (!hydrated)
|
|
96
108
|
return null;
|
|
97
|
-
|
|
109
|
+
const target = resolveContainer(container);
|
|
110
|
+
return createPortal(jsx(LocalePortalScope, { target: target, children: children }), target);
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
export { Portal, resolvePortalContainer, usePortalContainer };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.js","sources":["../../../src/helpers/portal.tsx"],"sourcesContent":["import React from 'react';\nimport { createPortal } from 'react-dom';\nimport { useIsHydrated } from './useIsHydrated';\nimport { useConfig } from './Config';\n\n/**\n * Resolves a portal target: an `HTMLElement` is used directly, a non-empty\n * `string` is treated as a `document.querySelector` selector (falling back to\n * `document.body` when it matches nothing), and any falsy value — `undefined`\n * or the empty string — resolves to `document.body`.\n *\n * The empty string is deliberately treated as \"no target\" rather than passed\n * through: `document.querySelector('')` throws a `SyntaxError`, and callers\n * building a selector from state can easily hand us `''`.\n *\n * @function resolvePortalContainer\n * @param container - The requested portal target, if any.\n * @returns The resolved DOM node to portal into.\n */\nexport function resolvePortalContainer(\n container?: string | HTMLElement\n): HTMLElement {\n if (!container) {\n return document.body;\n }\n if (typeof container === 'string') {\n return (\n (document.querySelector(container) as HTMLElement | null) ?? document.body\n );\n }\n return container;\n}\n\n/**\n * Where a component's portal goes, as a function to call when the portal is\n * created: the target the component was given, else the `portalContainer` a\n * `ConfigProvider` sets, else `document.body`, each read as\n * `resolvePortalContainer` reads it. A component that portals resolves its\n * target through this, so the provider's default reaches it.\n *\n * The hook only reads context, so it is safe to call on the server, ahead of\n * any early return. The function it returns reads the DOM, so call it only\n * where the portal is created, which the server never reaches.\n *\n * @function usePortalContainer\n * @returns A function that takes the component's own target, if any, and\n * returns the DOM node to portal into.\n */\nexport function usePortalContainer(): (\n container?: string | HTMLElement\n) => HTMLElement {\n const { portalContainer } = useConfig();\n return container => resolvePortalContainer(container || portalContainer);\n}\n\n/**\n * Props for the Portal component.\n */\nexport interface PortalProps {\n /** Content to render into the container. */\n children?: React.ReactNode;\n /**\n * Where the content goes: an element, or a `document.querySelector`\n * selector. Omitted or empty, it goes to the `portalContainer` a\n * `ConfigProvider` sets, and to `document.body` when none is set. A\n * selector that matches nothing means `document.body` too. A selector is\n * looked up again on each render, so the\n * content follows the target when it changes. Moving to another target\n * remounts the children and resets their state, which includes a selector\n * that only starts matching after the content has shown in `document.body`.\n * Render the target first, or pass the element once you have it.\n */\n container?: string | HTMLElement;\n /**\n * Render the children in place instead, on the server as well as the\n * client. Lets a component that portals only sometimes keep a single code\n * path.\n * @defaultValue false\n */\n disabled?: boolean;\n}\n\n/**\n * Renders its children into another part of the page, `document.body` unless `container` or a `ConfigProvider` says otherwise, so floating content escapes an ancestor's `overflow`, `transform` or stacking context.\n *\n * React's server renderer can't render a portal, so `Portal` renders nothing\n * on the server and during hydration, and mounts its children in the commit\n * that follows. The first client render then matches the server markup. In an app\n * without server rendering it portals on the first render.\n *\n * React context, such as `ConfigProvider`'s class prefix, reaches the\n * portaled children, and their React events bubble through the React tree.\n * CSS inheritance follows the DOM instead: a scoped (non-`isRoot`) `Theme`\n * sets its variables on a wrapper element the portaled content has left, so\n * that content sees the page-level theme, and styles scoped to a shadow root\n * don't reach `document.body` at all. To keep them, portal into an element\n * inside the themed area or the shadow root: pass it as `container`, or as\n * the `portalContainer` of a `ConfigProvider` around that area. The second\n * also reaches what the library's components portal, such as Popover's\n * `appendToBody` panel or a `Modal` with `portal`.\n *\n * Tab order and focus follow the DOM too. Content portaled from inside a\n * focus trap is no longer inside the trapped element, so the trap neither\n * reaches it nor holds focus there: render nested overlays inside the\n * trapped element, or give them a trap of their own. To trap portaled\n * content, put `useFocusTrap`'s ref on the element inside the `Portal`.\n *\n * @function\n * @param {PortalProps} props - Props for the Portal component.\n * @returns The portal, the children in place when `disabled`, or nothing\n * before hydration.\n *\n * @example\n * <Portal>\n * <div className=\"box\">Rendered at the end of document.body</div>\n * </Portal>\n *\n * @example\n * // Into a dedicated overlay root\n * <Portal container=\"#overlays\">\n * <CommandPalette />\n * </Portal>\n */\nexport function Portal({ children, container, disabled = false }: PortalProps) {\n const hydrated = useIsHydrated();\n const resolveContainer = usePortalContainer();\n if (disabled) return <>{children}</>;\n if (!hydrated) return null;\n
|
|
1
|
+
{"version":3,"file":"portal.js","sources":["../../../src/helpers/portal.tsx"],"sourcesContent":["import React from 'react';\nimport { createPortal } from 'react-dom';\nimport { useIsHydrated } from './useIsHydrated';\nimport { useConfig } from './Config';\nimport { LocalePortalScope } from './LocaleProvider';\n\n/**\n * Resolves a portal target: an `HTMLElement` is used directly, a non-empty\n * `string` is treated as a `document.querySelector` selector (falling back to\n * `document.body` when it matches nothing), and any falsy value — `undefined`\n * or the empty string — resolves to `document.body`.\n *\n * The empty string is deliberately treated as \"no target\" rather than passed\n * through: `document.querySelector('')` throws a `SyntaxError`, and callers\n * building a selector from state can easily hand us `''`.\n *\n * @function resolvePortalContainer\n * @param container - The requested portal target, if any.\n * @returns The resolved DOM node to portal into.\n */\nexport function resolvePortalContainer(\n container?: string | HTMLElement\n): HTMLElement {\n if (!container) {\n return document.body;\n }\n if (typeof container === 'string') {\n return (\n (document.querySelector(container) as HTMLElement | null) ?? document.body\n );\n }\n return container;\n}\n\n/**\n * Where a component's portal goes, as a function to call when the portal is\n * created: the target the component was given, else the `portalContainer` a\n * `ConfigProvider` sets, else `document.body`, each read as\n * `resolvePortalContainer` reads it. A component that portals resolves its\n * target through this, so the provider's default reaches it.\n *\n * The hook only reads context, so it is safe to call on the server, ahead of\n * any early return. The function it returns reads the DOM, so call it only\n * where the portal is created, which the server never reaches.\n *\n * @function usePortalContainer\n * @returns A function that takes the component's own target, if any, and\n * returns the DOM node to portal into.\n */\nexport function usePortalContainer(): (\n container?: string | HTMLElement\n) => HTMLElement {\n const { portalContainer } = useConfig();\n return container => resolvePortalContainer(container || portalContainer);\n}\n\n/**\n * Props for the Portal component.\n */\nexport interface PortalProps {\n /** Content to render into the container. */\n children?: React.ReactNode;\n /**\n * Where the content goes: an element, or a `document.querySelector`\n * selector. Omitted or empty, it goes to the `portalContainer` a\n * `ConfigProvider` sets, and to `document.body` when none is set. A\n * selector that matches nothing means `document.body` too. A selector is\n * looked up again on each render, so the\n * content follows the target when it changes. Moving to another target\n * remounts the children and resets their state, which includes a selector\n * that only starts matching after the content has shown in `document.body`.\n * Render the target first, or pass the element once you have it.\n */\n container?: string | HTMLElement;\n /**\n * Render the children in place instead, on the server as well as the\n * client. Lets a component that portals only sometimes keep a single code\n * path.\n * @defaultValue false\n */\n disabled?: boolean;\n}\n\n/**\n * Renders its children into another part of the page, `document.body` unless `container` or a `ConfigProvider` says otherwise, so floating content escapes an ancestor's `overflow`, `transform` or stacking context.\n *\n * React's server renderer can't render a portal, so `Portal` renders nothing\n * on the server and during hydration, and mounts its children in the commit\n * that follows. The first client render then matches the server markup. In an app\n * without server rendering it portals on the first render.\n *\n * React context, such as `ConfigProvider`'s class prefix, reaches the\n * portaled children, and their React events bubble through the React tree.\n * CSS inheritance follows the DOM instead: a scoped (non-`isRoot`) `Theme`\n * sets its variables on a wrapper element the portaled content has left, so\n * that content sees the page-level theme, and styles scoped to a shadow root\n * don't reach `document.body` at all. To keep them, portal into an element\n * inside the themed area or the shadow root: pass it as `container`, or as\n * the `portalContainer` of a `ConfigProvider` around that area. The second\n * also reaches what the library's components portal, such as Popover's\n * `appendToBody` panel or a `Modal` with `portal`.\n *\n * Inside a `LocaleProvider`, the children keep its `dir` and `lang`. A\n * container inside the provider's own wrapper takes the children as they\n * are, and they follow the provider through the page. Any other,\n * `document.body` included, gets them inside one `<div>` carrying the\n * provider's values, with `display: contents` so it adds no box. It is\n * still an element, so content that must be the container's direct child,\n * a `<tr>` in a `<tbody>`, or that a direct-child selector styles, belongs\n * in a container inside the provider. Which of the two is settled when the\n * children mount, so a change of locale updates them in place rather than\n * remounting them.\n *\n * Tab order and focus follow the DOM too. Content portaled from inside a\n * focus trap is no longer inside the trapped element, so the trap neither\n * reaches it nor holds focus there: render nested overlays inside the\n * trapped element, or give them a trap of their own. To trap portaled\n * content, put `useFocusTrap`'s ref on the element inside the `Portal`.\n *\n * @function\n * @param {PortalProps} props - Props for the Portal component.\n * @returns The portal, the children in place when `disabled`, or nothing\n * before hydration.\n *\n * @example\n * <Portal>\n * <div className=\"box\">Rendered at the end of document.body</div>\n * </Portal>\n *\n * @example\n * // Into a dedicated overlay root\n * <Portal container=\"#overlays\">\n * <CommandPalette />\n * </Portal>\n */\nexport function Portal({ children, container, disabled = false }: PortalProps) {\n const hydrated = useIsHydrated();\n const resolveContainer = usePortalContainer();\n if (disabled) return <>{children}</>;\n if (!hydrated) return null;\n const target = resolveContainer(container);\n return createPortal(\n <LocalePortalScope target={target}>{children}</LocalePortalScope>,\n target\n );\n}\n"],"names":["_jsx","_Fragment"],"mappings":";;;;;;;AAMA;;;;;;;;;;;;;AAaG;AACG,SAAU,sBAAsB,CACpC,SAAgC,EAAA;IAEhC,IAAI,CAAC,SAAS,EAAE;QACd,OAAO,QAAQ,CAAC,IAAI;IACtB;AACA,IAAA,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE;AACjC,QAAA,QACG,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAwB,IAAI,QAAQ,CAAC,IAAI;IAE9E;AACA,IAAA,OAAO,SAAS;AAClB;AAEA;;;;;;;;;;;;;;AAcG;SACa,kBAAkB,GAAA;AAGhC,IAAA,MAAM,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE;IACvC,OAAO,SAAS,IAAI,sBAAsB,CAAC,SAAS,IAAI,eAAe,CAAC;AAC1E;AA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDG;AACG,SAAU,MAAM,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,KAAK,EAAe,EAAA;AAC3E,IAAA,MAAM,QAAQ,GAAG,aAAa,EAAE;AAChC,IAAA,MAAM,gBAAgB,GAAG,kBAAkB,EAAE;AAC7C,IAAA,IAAI,QAAQ;QAAE,OAAOA,GAAA,CAAAC,QAAA,EAAA,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAI;AACpC,IAAA,IAAI,CAAC,QAAQ;AAAE,QAAA,OAAO,IAAI;AAC1B,IAAA,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC;AAC1C,IAAA,OAAO,YAAY,CACjBD,GAAA,CAAC,iBAAiB,IAAC,MAAM,EAAE,MAAM,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAqB,EACjE,MAAM,CACP;AACH;;"}
|