@allxsmith/bestax-bulma 5.53.0 → 5.54.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/esm/components/Avatars.js +7 -2
- package/dist/esm/components/Avatars.js.map +1 -1
- package/dist/esm/components/Badge.js +7 -2
- package/dist/esm/components/Badge.js.map +1 -1
- package/dist/esm/components/Command.js +19 -9
- package/dist/esm/components/Command.js.map +1 -1
- package/dist/esm/components/Pagination.js +9 -1
- package/dist/esm/components/Pagination.js.map +1 -1
- package/dist/esm/components/Steps.js +5 -1
- package/dist/esm/components/Steps.js.map +1 -1
- package/dist/esm/elements/RingProgress.js +6 -1
- package/dist/esm/elements/RingProgress.js.map +1 -1
- package/dist/esm/form/Autocomplete.js +4 -0
- package/dist/esm/form/Autocomplete.js.map +1 -1
- package/dist/esm/form/Combobox.js +7 -2
- package/dist/esm/form/Combobox.js.map +1 -1
- package/dist/esm/form/File.js +4 -1
- package/dist/esm/form/File.js.map +1 -1
- package/dist/esm/form/Rate.js +9 -1
- package/dist/esm/form/Rate.js.map +1 -1
- package/dist/esm/form/Slider.js +7 -4
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Taginput.js +9 -3
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/helpers/LocaleProvider.js +9 -6
- package/dist/esm/helpers/LocaleProvider.js.map +1 -1
- package/dist/esm/helpers/localeFormat.js +108 -0
- package/dist/esm/helpers/localeFormat.js.map +1 -0
- package/dist/index.cjs +435 -276
- package/dist/index.cjs.map +1 -1
- package/dist/types/components/Avatars.d.ts +1 -1
- package/dist/types/components/Badge.d.ts +1 -1
- package/dist/types/components/Command.d.ts +4 -2
- package/dist/types/components/Pagination.d.ts +3 -0
- package/dist/types/components/Steps.d.ts +4 -1
- package/dist/types/elements/RingProgress.d.ts +3 -2
- package/dist/types/form/Autocomplete.d.ts +6 -1
- package/dist/types/form/Combobox.d.ts +3 -2
- package/dist/types/form/File.d.ts +2 -1
- package/dist/types/form/Rate.d.ts +4 -1
- package/dist/types/form/Slider.d.ts +9 -2
- package/dist/types/form/Taginput.d.ts +8 -2
- package/dist/types/helpers/LocaleProvider.d.ts +9 -6
- package/dist/types/helpers/localeFormat.d.ts +26 -0
- package/dist/types-cjs/components/Avatars.d.ts +1 -1
- package/dist/types-cjs/components/Badge.d.ts +1 -1
- package/dist/types-cjs/components/Command.d.ts +4 -2
- package/dist/types-cjs/components/Pagination.d.ts +3 -0
- package/dist/types-cjs/components/Steps.d.ts +4 -1
- package/dist/types-cjs/elements/RingProgress.d.ts +3 -2
- package/dist/types-cjs/form/Autocomplete.d.ts +6 -1
- package/dist/types-cjs/form/Combobox.d.ts +3 -2
- package/dist/types-cjs/form/File.d.ts +2 -1
- package/dist/types-cjs/form/Rate.d.ts +4 -1
- package/dist/types-cjs/form/Slider.d.ts +9 -2
- package/dist/types-cjs/form/Taginput.d.ts +8 -2
- package/dist/types-cjs/helpers/LocaleProvider.d.ts +9 -6
- package/dist/types-cjs/helpers/localeFormat.d.ts +26 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1792,6 +1792,360 @@ function flattenChildren(children, keyPrefix = '') {
|
|
|
1792
1792
|
});
|
|
1793
1793
|
}
|
|
1794
1794
|
|
|
1795
|
+
// INTERNAL: deliberately not exported from src/index.ts. What a locale says
|
|
1796
|
+
// about its direction, read from `Intl.Locale` where the engine has the data,
|
|
1797
|
+
// and about its week, read from a copy of CLDR's week data.
|
|
1798
|
+
/**
|
|
1799
|
+
* Scripts written right to left: every script for which ICU's text info
|
|
1800
|
+
* says `rtl`, as Node reported it, and `Aran`, the Nastaliq form of Arabic
|
|
1801
|
+
* that WebKit fills in for Urdu. Read only where the engine has no text info
|
|
1802
|
+
* of its own, which includes Firefox before 153.
|
|
1803
|
+
*/
|
|
1804
|
+
const RTL_SCRIPTS = ' Adlm Arab Aran Armi Avst Chrs Cprt Elym Gara Hatr Hebr Hung Khar Lydi ' +
|
|
1805
|
+
'Mand Mani Mend Merc Mero Narb Nbat Nkoo Orkh Ougr Palm Phli Phlp Phnx ' +
|
|
1806
|
+
'Prti Rohg Samr Sarb Sidt Sogd Sogo Syrc Thaa Yezi ';
|
|
1807
|
+
/**
|
|
1808
|
+
* Widely used languages whose usual script reads right to left, for an engine
|
|
1809
|
+
* that can't fill in a locale's script with `maximize()`.
|
|
1810
|
+
*/
|
|
1811
|
+
const RTL_LANGUAGES = ' ar ckb dv fa he iw ji ks mzn nqo pnb ps sd syr ug ur yi ';
|
|
1812
|
+
/**
|
|
1813
|
+
* The regions whose week doesn't start on Monday, by the day it starts on
|
|
1814
|
+
* (0 = Sunday, 5 = Friday, 6 = Saturday), from CLDR 48's week data as Node
|
|
1815
|
+
* reported it. The library reads this rather than `Intl.Locale`'s week info
|
|
1816
|
+
* because engines disagree: Firefox before 153 has none, and WebKit's differs
|
|
1817
|
+
* from Node's, Chromium's and current Firefox's for China, Algeria, Jordan and
|
|
1818
|
+
* Iceland among others, so an inline calendar rendered on the server would
|
|
1819
|
+
* fail to hydrate there. With one table, the server and every browser agree.
|
|
1820
|
+
*/
|
|
1821
|
+
const WEEK_STARTS = [
|
|
1822
|
+
[
|
|
1823
|
+
0,
|
|
1824
|
+
' AG AS BD BR BS BT BU BW BZ CA CO DM DO ET GT GU HK HN ID IL IN IS JM JP ' +
|
|
1825
|
+
'KE KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PT PY RH SA SG SV TH ' +
|
|
1826
|
+
'TT TW UM US VE VI WS YD YE ZA ZW ',
|
|
1827
|
+
],
|
|
1828
|
+
[5, ' MV '],
|
|
1829
|
+
[6, ' AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY '],
|
|
1830
|
+
];
|
|
1831
|
+
/** Whether a space-separated list, padded with spaces, holds `code`. */
|
|
1832
|
+
const listed = (list, code) => list.includes(` ${code} `);
|
|
1833
|
+
/** The `-u-fw-` keyword's values, by the day they name. */
|
|
1834
|
+
const FW_DAYS = {
|
|
1835
|
+
sun: 0,
|
|
1836
|
+
mon: 1,
|
|
1837
|
+
tue: 2,
|
|
1838
|
+
wed: 3,
|
|
1839
|
+
thu: 4,
|
|
1840
|
+
fri: 5,
|
|
1841
|
+
sat: 6,
|
|
1842
|
+
};
|
|
1843
|
+
/**
|
|
1844
|
+
* The canonical form of a BCP 47 tag (`"en-us"` becomes `"en-US"`), or
|
|
1845
|
+
* `undefined` for an empty or missing one. Throws a `RangeError` for a tag
|
|
1846
|
+
* `Intl` refuses, as `Intl.DateTimeFormat` would.
|
|
1847
|
+
*/
|
|
1848
|
+
function canonicalLocale(tag) {
|
|
1849
|
+
if (!tag)
|
|
1850
|
+
return undefined;
|
|
1851
|
+
return Intl.getCanonicalLocales(tag)[0];
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* The direction a locale's script is written in: from `Intl.Locale`'s text
|
|
1855
|
+
* info, else from the script `maximize()` fills in, else from the language.
|
|
1856
|
+
*
|
|
1857
|
+
* @param locale - A canonical tag, as `canonicalLocale` returns.
|
|
1858
|
+
*/
|
|
1859
|
+
function localeDirection(locale) {
|
|
1860
|
+
const intlLocale = new Intl.Locale(locale);
|
|
1861
|
+
const info = intlLocale;
|
|
1862
|
+
const direction = typeof info.getTextInfo === 'function'
|
|
1863
|
+
? info.getTextInfo().direction
|
|
1864
|
+
: info.textInfo?.direction;
|
|
1865
|
+
if (direction === 'rtl' || direction === 'ltr')
|
|
1866
|
+
return direction;
|
|
1867
|
+
if (typeof intlLocale.maximize === 'function') {
|
|
1868
|
+
const script = intlLocale.maximize().script;
|
|
1869
|
+
return script && listed(RTL_SCRIPTS, script) ? 'rtl' : 'ltr';
|
|
1870
|
+
}
|
|
1871
|
+
return listed(RTL_LANGUAGES, intlLocale.language) ? 'rtl' : 'ltr';
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1874
|
+
* The day a locale's week starts on, 0 for Sunday, as `getWeekInfo()` reads
|
|
1875
|
+
* it: the tag's `-u-fw-` keyword, else the region its `-u-rg-` keyword names,
|
|
1876
|
+
* else its own region or the one `maximize()` fills in, looked up in CLDR's
|
|
1877
|
+
* week data, where a region not listed starts on Monday.
|
|
1878
|
+
*
|
|
1879
|
+
* @param locale - A canonical tag, as `canonicalLocale` returns.
|
|
1880
|
+
*/
|
|
1881
|
+
function localeFirstDay(locale) {
|
|
1882
|
+
const fw = /-u(?:-[a-z0-9]{2,8})*?-fw-([a-z]{3})(?=-|$)/i.exec(locale);
|
|
1883
|
+
if (fw && fw[1].toLowerCase() in FW_DAYS)
|
|
1884
|
+
return FW_DAYS[fw[1].toLowerCase()];
|
|
1885
|
+
const rg = /-u(?:-[a-z0-9]{2,8})*?-rg-([a-z]{2})[a-z0-9]{1,4}(?=-|$)/i.exec(locale);
|
|
1886
|
+
const intlLocale = new Intl.Locale(locale);
|
|
1887
|
+
const region = rg
|
|
1888
|
+
? rg[1].toUpperCase()
|
|
1889
|
+
: typeof intlLocale.maximize === 'function'
|
|
1890
|
+
? intlLocale.maximize().region
|
|
1891
|
+
: intlLocale.region;
|
|
1892
|
+
if (region) {
|
|
1893
|
+
for (const [day, regions] of WEEK_STARTS) {
|
|
1894
|
+
if (listed(regions, region))
|
|
1895
|
+
return day;
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
return 1;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
const LocaleContext = React.createContext(null);
|
|
1902
|
+
/** The nearest provider's wrapper element, for `LocalePortalScope` to test targets against. */
|
|
1903
|
+
const LocaleElementContext = React.createContext(null);
|
|
1904
|
+
/** A tag in canonical form, or `undefined`, warning about one `Intl` refuses. */
|
|
1905
|
+
function validLocale(tag) {
|
|
1906
|
+
try {
|
|
1907
|
+
return canonicalLocale(tag);
|
|
1908
|
+
}
|
|
1909
|
+
catch {
|
|
1910
|
+
warnOnce(`locale-provider-invalid:${tag}`, `[bestax-bulma] <LocaleProvider locale="${tag}">: not a language ` +
|
|
1911
|
+
'tag Intl accepts, so it is ignored. Use a BCP 47 tag such as ' +
|
|
1912
|
+
'"en-US", with a hyphen rather than an underscore.');
|
|
1913
|
+
return undefined;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* 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.
|
|
1918
|
+
*
|
|
1919
|
+
* The wrapper carries `dir` and `lang`, so CSS and the components that read
|
|
1920
|
+
* the computed direction follow it, as they follow `<html dir>`. A `locale`
|
|
1921
|
+
* alone sets the direction of its script, and a `dir` sets the direction
|
|
1922
|
+
* whatever the locale. A nested provider keeps whatever it leaves unset.
|
|
1923
|
+
*
|
|
1924
|
+
* Inside it, the date and time pickers take its `locale` unless given their
|
|
1925
|
+
* own, and their week starts on the first day of the locale they use unless
|
|
1926
|
+
* `firstDayOfWeek` is set, and a picker with a `locale` of its own is read
|
|
1927
|
+
* like a nested provider. With a `locale`, the numbers the library writes,
|
|
1928
|
+
* such as page numbers and badge counts, follow it, and so does the
|
|
1929
|
+
* filtering in `Combobox`, `Autocomplete`, `Taginput` and `Command`, which then ignores
|
|
1930
|
+
* accents where the language treats letters as the same. The library's
|
|
1931
|
+
* portaled content, such as a `Popover` panel, a `Modal` with `portal`, a
|
|
1932
|
+
* `Toast` or a `Portal`'s children, keeps the same `dir` and `lang` though
|
|
1933
|
+
* it renders outside the wrapper: in a container outside the wrapper, it
|
|
1934
|
+
* sits in a `display: contents` element that carries them. Without a
|
|
1935
|
+
* provider none of this changes.
|
|
1936
|
+
*
|
|
1937
|
+
* @function
|
|
1938
|
+
* @param {LocaleProviderProps} props - Props for the LocaleProvider.
|
|
1939
|
+
* @returns {JSX.Element} The wrapper, inside the context.
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* <LocaleProvider locale="ar-EG">
|
|
1943
|
+
* <App />
|
|
1944
|
+
* </LocaleProvider>
|
|
1945
|
+
*/
|
|
1946
|
+
const LocaleProvider = React.forwardRef(({ locale: localeProp, dir: dirProp, className, children, ...props }, ref) => {
|
|
1947
|
+
const outer = React.useContext(LocaleContext);
|
|
1948
|
+
const ownLocale = React.useMemo(() => validLocale(localeProp), [localeProp]);
|
|
1949
|
+
const ownLocaleDir = React.useMemo(() => (ownLocale ? localeDirection(ownLocale) : undefined), [ownLocale]);
|
|
1950
|
+
const locale = ownLocale || outer?.locale;
|
|
1951
|
+
const dir = dirProp || ownLocaleDir || outer?.dir;
|
|
1952
|
+
const value = React.useMemo(() => ({ locale, dir }), [locale, dir]);
|
|
1953
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
1954
|
+
// The wrapper, for portaled content to tell whether its target is inside
|
|
1955
|
+
// it, and the caller's ref. A callback ref's cleanup is held and run on
|
|
1956
|
+
// detach, as Toast and Modal do, since React 18 discards the return value.
|
|
1957
|
+
const elementRef = React.useRef(null);
|
|
1958
|
+
const consumerCleanupRef = React.useRef(null);
|
|
1959
|
+
const setElement = React.useCallback((node) => {
|
|
1960
|
+
elementRef.current = node;
|
|
1961
|
+
if (typeof ref === 'function') {
|
|
1962
|
+
if (node === null) {
|
|
1963
|
+
const consumerCleanup = consumerCleanupRef.current;
|
|
1964
|
+
consumerCleanupRef.current = null;
|
|
1965
|
+
if (consumerCleanup)
|
|
1966
|
+
consumerCleanup();
|
|
1967
|
+
else
|
|
1968
|
+
ref(null);
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
const cleanup = ref(node);
|
|
1972
|
+
consumerCleanupRef.current =
|
|
1973
|
+
typeof cleanup === 'function' ? cleanup : null;
|
|
1974
|
+
}
|
|
1975
|
+
else if (ref) {
|
|
1976
|
+
ref.current = node;
|
|
1977
|
+
}
|
|
1978
|
+
}, [ref]);
|
|
1979
|
+
return (jsxRuntime.jsx(LocaleContext.Provider, { value: value, children: jsxRuntime.jsx(LocaleElementContext.Provider, { value: elementRef, children: jsxRuntime.jsx("div", { ref: setElement, className: classNames(bulmaHelperClasses, className) || undefined, ...rest, dir: dir, lang: locale, children: children }) }) }));
|
|
1980
|
+
});
|
|
1981
|
+
LocaleProvider.displayName = 'LocaleProvider';
|
|
1982
|
+
/** What `useLocale` returns outside a provider, the same object each time. */
|
|
1983
|
+
const noLocale = {};
|
|
1984
|
+
/**
|
|
1985
|
+
* 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.
|
|
1986
|
+
*
|
|
1987
|
+
* It isn't the page's direction: with no provider, or one that sets no
|
|
1988
|
+
* direction, the page's `<html dir>` still decides. To act on the direction
|
|
1989
|
+
* an element is laid out in, read `getComputedStyle(element).direction`, as
|
|
1990
|
+
* the library's components do.
|
|
1991
|
+
*
|
|
1992
|
+
* @function
|
|
1993
|
+
* @returns {LocaleContextValue} The nearest provider's `locale` and `dir`.
|
|
1994
|
+
*
|
|
1995
|
+
* @example
|
|
1996
|
+
* const { locale } = useLocale();
|
|
1997
|
+
* const price = new Intl.NumberFormat(locale, {
|
|
1998
|
+
* style: 'currency',
|
|
1999
|
+
* currency: 'EUR',
|
|
2000
|
+
* }).format(12.5);
|
|
2001
|
+
*/
|
|
2002
|
+
function useLocale() {
|
|
2003
|
+
return React.useContext(LocaleContext) ?? noLocale;
|
|
2004
|
+
}
|
|
2005
|
+
/**
|
|
2006
|
+
* INTERNAL, deliberately not exported from `src/index.ts`. The nearest
|
|
2007
|
+
* provider's settings, or `null` outside any provider, so a caller can tell
|
|
2008
|
+
* "no provider" from "a provider that sets nothing".
|
|
2009
|
+
*/
|
|
2010
|
+
function useLocaleScope() {
|
|
2011
|
+
return React.useContext(LocaleContext);
|
|
2012
|
+
}
|
|
2013
|
+
const displayContents = { display: 'contents' };
|
|
2014
|
+
/**
|
|
2015
|
+
* INTERNAL, deliberately not exported from `src/index.ts`. Keeps the `dir`
|
|
2016
|
+
* and `lang` of the nearest provider, or the `scope` given in their place,
|
|
2017
|
+
* on content the library portals into `target`, which has left the
|
|
2018
|
+
* provider's wrapper behind.
|
|
2019
|
+
*
|
|
2020
|
+
* A target inside the provider's own wrapper gets the content as it is: it
|
|
2021
|
+
* inherits from the wrapper, and follows it when the provider changes.
|
|
2022
|
+
* Content that must be its container's direct child, a `<tr>` portaled into
|
|
2023
|
+
* a `<tbody>` there, stays one. Any other target, `document.body` included,
|
|
2024
|
+
* gets the content inside a `display: contents` element carrying the
|
|
2025
|
+
* values, which adds no box. So does content with a `scope` of its own, a
|
|
2026
|
+
* picker's panel, since the provider's values aren't its own.
|
|
2027
|
+
*
|
|
2028
|
+
* Which of the two is decided once, when the content mounts, and kept while
|
|
2029
|
+
* it stays: switching between them would put a different element in its
|
|
2030
|
+
* place and remount everything inside, losing typed text, focus and timers.
|
|
2031
|
+
* A change of locale or direction updates the wrapper's attributes instead.
|
|
2032
|
+
* A target is never left bare because something else, such as `<html>`,
|
|
2033
|
+
* happens to carry the same values, since that can stop being true without
|
|
2034
|
+
* the content remounting. Outside a provider it renders the children alone,
|
|
2035
|
+
* so nothing changes there.
|
|
2036
|
+
*/
|
|
2037
|
+
function LocalePortalScope({ children, target, scope, }) {
|
|
2038
|
+
const provider = React.useContext(LocaleContext);
|
|
2039
|
+
const element = React.useContext(LocaleElementContext);
|
|
2040
|
+
const [wrap] = React.useState(() => scope !== undefined || !element?.current?.contains(target));
|
|
2041
|
+
if (!provider || !wrap)
|
|
2042
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
|
|
2043
|
+
const values = scope ?? provider;
|
|
2044
|
+
return (jsxRuntime.jsx("div", { dir: values.dir, lang: values.locale, style: displayContents, children: children }));
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
// INTERNAL: deliberately not exported from src/index.ts. Number formatting
|
|
2048
|
+
// and text matching in a LocaleProvider's locale. Both return `null` outside
|
|
2049
|
+
// a provider that gives a locale, so each caller keeps the formatting and the
|
|
2050
|
+
// matching it has always had there.
|
|
2051
|
+
/** A combining mark: an accent, a vowel sign or a point written on a letter. */
|
|
2052
|
+
const MARK = /\p{M}/u;
|
|
2053
|
+
/**
|
|
2054
|
+
* The locale a component formats and matches in: inside a `LocaleProvider`,
|
|
2055
|
+
* the component's own locale when it has one (a picker's `locale`), else the
|
|
2056
|
+
* provider's; outside a provider, none.
|
|
2057
|
+
*/
|
|
2058
|
+
function useScopedLocale(own) {
|
|
2059
|
+
const scope = useLocaleScope();
|
|
2060
|
+
if (!scope)
|
|
2061
|
+
return undefined;
|
|
2062
|
+
return scope.locale;
|
|
2063
|
+
}
|
|
2064
|
+
/**
|
|
2065
|
+
* A formatter for numbers shown on screen, in the locale of the
|
|
2066
|
+
* `LocaleProvider` around the component, or `null` outside one that gives a
|
|
2067
|
+
* locale. Formatters are kept per set of options, since building one is the
|
|
2068
|
+
* expensive part.
|
|
2069
|
+
*
|
|
2070
|
+
* @param own - The component's own locale, such as a picker's `locale`,
|
|
2071
|
+
* which wins inside a provider.
|
|
2072
|
+
*/
|
|
2073
|
+
function useNumberFormat(own) {
|
|
2074
|
+
const locale = useScopedLocale();
|
|
2075
|
+
return React.useMemo(() => {
|
|
2076
|
+
if (!locale)
|
|
2077
|
+
return null;
|
|
2078
|
+
const formats = new Map();
|
|
2079
|
+
return (value, options) => {
|
|
2080
|
+
const key = options ? JSON.stringify(options) : '';
|
|
2081
|
+
let format = formats.get(key);
|
|
2082
|
+
if (!format) {
|
|
2083
|
+
format = new Intl.NumberFormat(locale, options);
|
|
2084
|
+
formats.set(key, format);
|
|
2085
|
+
}
|
|
2086
|
+
return format.format(value);
|
|
2087
|
+
};
|
|
2088
|
+
}, [locale]);
|
|
2089
|
+
}
|
|
2090
|
+
/**
|
|
2091
|
+
* A matcher for filtering a list by what was typed, in the locale of the
|
|
2092
|
+
* `LocaleProvider` around the component, or `null` outside one that gives a
|
|
2093
|
+
* locale. It compares with `Intl.Collator` at `usage: 'search'` and
|
|
2094
|
+
* `sensitivity: 'base'`, so it ignores case and accents where the language
|
|
2095
|
+
* treats the letters as the same: "cafe" finds "Café", while in Swedish "a"
|
|
2096
|
+
* doesn't find "å", a letter of its own there. Marks the language ignores
|
|
2097
|
+
* count for nothing on either side, so in Arabic محمد finds مُحَمَّد and the
|
|
2098
|
+
* other way round. An empty query, or one of nothing but such marks,
|
|
2099
|
+
* matches everything.
|
|
2100
|
+
*/
|
|
2101
|
+
function useLocaleMatcher() {
|
|
2102
|
+
const locale = useScopedLocale();
|
|
2103
|
+
return React.useMemo(() => {
|
|
2104
|
+
if (!locale)
|
|
2105
|
+
return null;
|
|
2106
|
+
const collator = new Intl.Collator(locale, {
|
|
2107
|
+
usage: 'search',
|
|
2108
|
+
sensitivity: 'base',
|
|
2109
|
+
});
|
|
2110
|
+
return (text, query) => {
|
|
2111
|
+
const needle = query.normalize('NFC');
|
|
2112
|
+
if (collator.compare(needle, '') === 0)
|
|
2113
|
+
return true;
|
|
2114
|
+
// Compared by code point, so a slice never splits a surrogate pair.
|
|
2115
|
+
const chars = Array.from(text.normalize('NFC'));
|
|
2116
|
+
const marks = chars.map(char => MARK.test(char));
|
|
2117
|
+
// A slice equal to the needle can be longer or shorter than it: the
|
|
2118
|
+
// marks the collator ignores, Arabic harakat or Hebrew niqqud, take
|
|
2119
|
+
// code points on one side and not the other, and the expansions the
|
|
2120
|
+
// collator makes, "ß" against "ss" or "æ" against "ae", turn one letter
|
|
2121
|
+
// into two. So each slice runs from a letter to just before the next
|
|
2122
|
+
// letter, never cutting a letter from its marks, and the slices from
|
|
2123
|
+
// one start grow until they hold twice the needle's letters, which
|
|
2124
|
+
// those expansions can't get past. That keeps the work proportional to
|
|
2125
|
+
// the text's length, however long a label is, rather than to its
|
|
2126
|
+
// square.
|
|
2127
|
+
const most = 2 * Array.from(needle).filter(char => !MARK.test(char)).length;
|
|
2128
|
+
for (let start = 0; start < chars.length; start++) {
|
|
2129
|
+
if (marks[start])
|
|
2130
|
+
continue;
|
|
2131
|
+
let letters = 0;
|
|
2132
|
+
for (let end = start + 1; end <= chars.length; end++) {
|
|
2133
|
+
if (!marks[end - 1])
|
|
2134
|
+
letters++;
|
|
2135
|
+
if (letters > most)
|
|
2136
|
+
break;
|
|
2137
|
+
if (marks[end])
|
|
2138
|
+
continue;
|
|
2139
|
+
if (collator.compare(chars.slice(start, end).join(''), needle) === 0) {
|
|
2140
|
+
return true;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
return false;
|
|
2145
|
+
};
|
|
2146
|
+
}, [locale]);
|
|
2147
|
+
}
|
|
2148
|
+
|
|
1795
2149
|
/**
|
|
1796
2150
|
* The `Avatars` component renders an overlapping/stacked group of `Avatar`s, the "members" list pattern.
|
|
1797
2151
|
*
|
|
@@ -1806,6 +2160,7 @@ function flattenChildren(children, keyPrefix = '') {
|
|
|
1806
2160
|
*/
|
|
1807
2161
|
const AvatarsComponent = ({ className, max, size, shape, spacing = 'md', spaced = false, surplusLabel, style, children, ...props }) => {
|
|
1808
2162
|
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
2163
|
+
const formatNumber = useNumberFormat();
|
|
1809
2164
|
// A preset spacing maps to a class; a numeric spacing sets the CSS var inline
|
|
1810
2165
|
// (mirrors Sidebar's inline --bulma-* width var).
|
|
1811
2166
|
const isPresetSpacing = typeof spacing === 'string';
|
|
@@ -1837,11 +2192,14 @@ const AvatarsComponent = ({ className, max, size, shape, spacing = 'md', spaced
|
|
|
1837
2192
|
React.cloneElement(child, {
|
|
1838
2193
|
...(size !== undefined ? { size } : {}),
|
|
1839
2194
|
...(shape !== undefined ? { shape } : {}),
|
|
1840
|
-
})), overflowCount > 0 && (jsxRuntime.jsx(Avatar, { initials:
|
|
2195
|
+
})), overflowCount > 0 && (jsxRuntime.jsx(Avatar, { initials: formatNumber
|
|
2196
|
+
? formatNumber(overflowCount, { signDisplay: 'always' })
|
|
2197
|
+
: `+${overflowCount}`, alt:
|
|
1841
2198
|
// `||` (not a plain ternary): an empty string from surplusLabel
|
|
1842
2199
|
// would make the bubble decorative (alt="") and hide the count
|
|
1843
2200
|
// from assistive tech — fall back to the default label instead.
|
|
1844
|
-
surplusLabel?.(overflowCount) ||
|
|
2201
|
+
surplusLabel?.(overflowCount) ||
|
|
2202
|
+
`${formatNumber ? formatNumber(overflowCount) : overflowCount} more`, size: size, shape: shape, className: surplusClass }))] }));
|
|
1845
2203
|
};
|
|
1846
2204
|
const Avatars = withSubComponents(AvatarsComponent, { Avatar }, 'Avatars');
|
|
1847
2205
|
|
|
@@ -1891,15 +2249,19 @@ const Badge = ({ className, badgeClassName, content, max = 99, dot = false, show
|
|
|
1891
2249
|
// A negative or non-integer max is nonsensical; fall back to the default
|
|
1892
2250
|
// rather than render e.g. "-1+" (mirrors Avatars' max sanitization).
|
|
1893
2251
|
const sanitizedMax = Number.isInteger(max) && max >= 0 ? max : 99;
|
|
2252
|
+
const formatNumber = useNumberFormat();
|
|
1894
2253
|
const displayValue = React.useMemo(() => {
|
|
1895
2254
|
if (dot || !hasContent)
|
|
1896
2255
|
return undefined;
|
|
1897
2256
|
// max only applies to numeric content; any other node renders verbatim.
|
|
1898
2257
|
if (typeof content === 'number') {
|
|
1899
|
-
|
|
2258
|
+
const write = formatNumber ?? String;
|
|
2259
|
+
return content > sanitizedMax
|
|
2260
|
+
? `${write(sanitizedMax)}+`
|
|
2261
|
+
: write(content);
|
|
1900
2262
|
}
|
|
1901
2263
|
return content;
|
|
1902
|
-
}, [dot, hasContent, content, sanitizedMax]);
|
|
2264
|
+
}, [dot, hasContent, content, sanitizedMax, formatNumber]);
|
|
1903
2265
|
// Only primitive content produces a meaningful aria-label; a custom node
|
|
1904
2266
|
// supplies its own accessible text, so we leave role="status" unlabeled.
|
|
1905
2267
|
const ariaLabel = typeof displayValue === 'string' || typeof displayValue === 'number'
|
|
@@ -3909,255 +4271,6 @@ function useIsHydrated() {
|
|
|
3909
4271
|
return React.useSyncExternalStore(subscribeToNothing, getClientSnapshot, getServerSnapshot);
|
|
3910
4272
|
}
|
|
3911
4273
|
|
|
3912
|
-
// INTERNAL: deliberately not exported from src/index.ts. What a locale says
|
|
3913
|
-
// about its direction, read from `Intl.Locale` where the engine has the data,
|
|
3914
|
-
// and about its week, read from a copy of CLDR's week data.
|
|
3915
|
-
/**
|
|
3916
|
-
* Scripts written right to left: every script for which ICU's text info
|
|
3917
|
-
* says `rtl`, as Node reported it, and `Aran`, the Nastaliq form of Arabic
|
|
3918
|
-
* that WebKit fills in for Urdu. Read only where the engine has no text info
|
|
3919
|
-
* of its own, which includes Firefox before 153.
|
|
3920
|
-
*/
|
|
3921
|
-
const RTL_SCRIPTS = ' Adlm Arab Aran Armi Avst Chrs Cprt Elym Gara Hatr Hebr Hung Khar Lydi ' +
|
|
3922
|
-
'Mand Mani Mend Merc Mero Narb Nbat Nkoo Orkh Ougr Palm Phli Phlp Phnx ' +
|
|
3923
|
-
'Prti Rohg Samr Sarb Sidt Sogd Sogo Syrc Thaa Yezi ';
|
|
3924
|
-
/**
|
|
3925
|
-
* Widely used languages whose usual script reads right to left, for an engine
|
|
3926
|
-
* that can't fill in a locale's script with `maximize()`.
|
|
3927
|
-
*/
|
|
3928
|
-
const RTL_LANGUAGES = ' ar ckb dv fa he iw ji ks mzn nqo pnb ps sd syr ug ur yi ';
|
|
3929
|
-
/**
|
|
3930
|
-
* The regions whose week doesn't start on Monday, by the day it starts on
|
|
3931
|
-
* (0 = Sunday, 5 = Friday, 6 = Saturday), from CLDR 48's week data as Node
|
|
3932
|
-
* reported it. The library reads this rather than `Intl.Locale`'s week info
|
|
3933
|
-
* because engines disagree: Firefox before 153 has none, and WebKit's differs
|
|
3934
|
-
* from Node's, Chromium's and current Firefox's for China, Algeria, Jordan and
|
|
3935
|
-
* Iceland among others, so an inline calendar rendered on the server would
|
|
3936
|
-
* fail to hydrate there. With one table, the server and every browser agree.
|
|
3937
|
-
*/
|
|
3938
|
-
const WEEK_STARTS = [
|
|
3939
|
-
[
|
|
3940
|
-
0,
|
|
3941
|
-
' AG AS BD BR BS BT BU BW BZ CA CO DM DO ET GT GU HK HN ID IL IN IS JM JP ' +
|
|
3942
|
-
'KE KH KR LA MH MM MO MT MX MZ NI NP PA PE PH PK PR PT PY RH SA SG SV TH ' +
|
|
3943
|
-
'TT TW UM US VE VI WS YD YE ZA ZW ',
|
|
3944
|
-
],
|
|
3945
|
-
[5, ' MV '],
|
|
3946
|
-
[6, ' AF BH DJ DZ EG IQ IR JO KW LY OM QA SD SY '],
|
|
3947
|
-
];
|
|
3948
|
-
/** Whether a space-separated list, padded with spaces, holds `code`. */
|
|
3949
|
-
const listed = (list, code) => list.includes(` ${code} `);
|
|
3950
|
-
/** The `-u-fw-` keyword's values, by the day they name. */
|
|
3951
|
-
const FW_DAYS = {
|
|
3952
|
-
sun: 0,
|
|
3953
|
-
mon: 1,
|
|
3954
|
-
tue: 2,
|
|
3955
|
-
wed: 3,
|
|
3956
|
-
thu: 4,
|
|
3957
|
-
fri: 5,
|
|
3958
|
-
sat: 6,
|
|
3959
|
-
};
|
|
3960
|
-
/**
|
|
3961
|
-
* The canonical form of a BCP 47 tag (`"en-us"` becomes `"en-US"`), or
|
|
3962
|
-
* `undefined` for an empty or missing one. Throws a `RangeError` for a tag
|
|
3963
|
-
* `Intl` refuses, as `Intl.DateTimeFormat` would.
|
|
3964
|
-
*/
|
|
3965
|
-
function canonicalLocale(tag) {
|
|
3966
|
-
if (!tag)
|
|
3967
|
-
return undefined;
|
|
3968
|
-
return Intl.getCanonicalLocales(tag)[0];
|
|
3969
|
-
}
|
|
3970
|
-
/**
|
|
3971
|
-
* The direction a locale's script is written in: from `Intl.Locale`'s text
|
|
3972
|
-
* info, else from the script `maximize()` fills in, else from the language.
|
|
3973
|
-
*
|
|
3974
|
-
* @param locale - A canonical tag, as `canonicalLocale` returns.
|
|
3975
|
-
*/
|
|
3976
|
-
function localeDirection(locale) {
|
|
3977
|
-
const intlLocale = new Intl.Locale(locale);
|
|
3978
|
-
const info = intlLocale;
|
|
3979
|
-
const direction = typeof info.getTextInfo === 'function'
|
|
3980
|
-
? info.getTextInfo().direction
|
|
3981
|
-
: info.textInfo?.direction;
|
|
3982
|
-
if (direction === 'rtl' || direction === 'ltr')
|
|
3983
|
-
return direction;
|
|
3984
|
-
if (typeof intlLocale.maximize === 'function') {
|
|
3985
|
-
const script = intlLocale.maximize().script;
|
|
3986
|
-
return script && listed(RTL_SCRIPTS, script) ? 'rtl' : 'ltr';
|
|
3987
|
-
}
|
|
3988
|
-
return listed(RTL_LANGUAGES, intlLocale.language) ? 'rtl' : 'ltr';
|
|
3989
|
-
}
|
|
3990
|
-
/**
|
|
3991
|
-
* The day a locale's week starts on, 0 for Sunday, as `getWeekInfo()` reads
|
|
3992
|
-
* it: the tag's `-u-fw-` keyword, else the region its `-u-rg-` keyword names,
|
|
3993
|
-
* else its own region or the one `maximize()` fills in, looked up in CLDR's
|
|
3994
|
-
* week data, where a region not listed starts on Monday.
|
|
3995
|
-
*
|
|
3996
|
-
* @param locale - A canonical tag, as `canonicalLocale` returns.
|
|
3997
|
-
*/
|
|
3998
|
-
function localeFirstDay(locale) {
|
|
3999
|
-
const fw = /-u(?:-[a-z0-9]{2,8})*?-fw-([a-z]{3})(?=-|$)/i.exec(locale);
|
|
4000
|
-
if (fw && fw[1].toLowerCase() in FW_DAYS)
|
|
4001
|
-
return FW_DAYS[fw[1].toLowerCase()];
|
|
4002
|
-
const rg = /-u(?:-[a-z0-9]{2,8})*?-rg-([a-z]{2})[a-z0-9]{1,4}(?=-|$)/i.exec(locale);
|
|
4003
|
-
const intlLocale = new Intl.Locale(locale);
|
|
4004
|
-
const region = rg
|
|
4005
|
-
? rg[1].toUpperCase()
|
|
4006
|
-
: typeof intlLocale.maximize === 'function'
|
|
4007
|
-
? intlLocale.maximize().region
|
|
4008
|
-
: intlLocale.region;
|
|
4009
|
-
if (region) {
|
|
4010
|
-
for (const [day, regions] of WEEK_STARTS) {
|
|
4011
|
-
if (listed(regions, region))
|
|
4012
|
-
return day;
|
|
4013
|
-
}
|
|
4014
|
-
}
|
|
4015
|
-
return 1;
|
|
4016
|
-
}
|
|
4017
|
-
|
|
4018
|
-
const LocaleContext = React.createContext(null);
|
|
4019
|
-
/** The nearest provider's wrapper element, for `LocalePortalScope` to test targets against. */
|
|
4020
|
-
const LocaleElementContext = React.createContext(null);
|
|
4021
|
-
/** A tag in canonical form, or `undefined`, warning about one `Intl` refuses. */
|
|
4022
|
-
function validLocale(tag) {
|
|
4023
|
-
try {
|
|
4024
|
-
return canonicalLocale(tag);
|
|
4025
|
-
}
|
|
4026
|
-
catch {
|
|
4027
|
-
warnOnce(`locale-provider-invalid:${tag}`, `[bestax-bulma] <LocaleProvider locale="${tag}">: not a language ` +
|
|
4028
|
-
'tag Intl accepts, so it is ignored. Use a BCP 47 tag such as ' +
|
|
4029
|
-
'"en-US", with a hyphen rather than an underscore.');
|
|
4030
|
-
return undefined;
|
|
4031
|
-
}
|
|
4032
|
-
}
|
|
4033
|
-
/**
|
|
4034
|
-
* 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.
|
|
4035
|
-
*
|
|
4036
|
-
* The wrapper carries `dir` and `lang`, so CSS and the components that read
|
|
4037
|
-
* the computed direction follow it, as they follow `<html dir>`. A `locale`
|
|
4038
|
-
* alone sets the direction of its script, and a `dir` sets the direction
|
|
4039
|
-
* whatever the locale. A nested provider keeps whatever it leaves unset.
|
|
4040
|
-
*
|
|
4041
|
-
* Inside it, the date and time pickers take its `locale` unless given their
|
|
4042
|
-
* own, and their week starts on the first day of the locale they use unless
|
|
4043
|
-
* `firstDayOfWeek` is set, and a picker with a `locale` of its own is read
|
|
4044
|
-
* like a nested provider. The library's portaled content, such as a
|
|
4045
|
-
* `Popover` panel, a `Modal` with `portal`, a `Toast` or a `Portal`'s
|
|
4046
|
-
* children, keeps the same `dir` and `lang` though it renders outside the
|
|
4047
|
-
* wrapper: in a container outside the wrapper, it sits in a
|
|
4048
|
-
* `display: contents` element that carries them. Without a provider none of
|
|
4049
|
-
* this changes.
|
|
4050
|
-
*
|
|
4051
|
-
* @function
|
|
4052
|
-
* @param {LocaleProviderProps} props - Props for the LocaleProvider.
|
|
4053
|
-
* @returns {JSX.Element} The wrapper, inside the context.
|
|
4054
|
-
*
|
|
4055
|
-
* @example
|
|
4056
|
-
* <LocaleProvider locale="ar-EG">
|
|
4057
|
-
* <App />
|
|
4058
|
-
* </LocaleProvider>
|
|
4059
|
-
*/
|
|
4060
|
-
const LocaleProvider = React.forwardRef(({ locale: localeProp, dir: dirProp, className, children, ...props }, ref) => {
|
|
4061
|
-
const outer = React.useContext(LocaleContext);
|
|
4062
|
-
const ownLocale = React.useMemo(() => validLocale(localeProp), [localeProp]);
|
|
4063
|
-
const ownLocaleDir = React.useMemo(() => (ownLocale ? localeDirection(ownLocale) : undefined), [ownLocale]);
|
|
4064
|
-
const locale = ownLocale || outer?.locale;
|
|
4065
|
-
const dir = dirProp || ownLocaleDir || outer?.dir;
|
|
4066
|
-
const value = React.useMemo(() => ({ locale, dir }), [locale, dir]);
|
|
4067
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
4068
|
-
// The wrapper, for portaled content to tell whether its target is inside
|
|
4069
|
-
// it, and the caller's ref. A callback ref's cleanup is held and run on
|
|
4070
|
-
// detach, as Toast and Modal do, since React 18 discards the return value.
|
|
4071
|
-
const elementRef = React.useRef(null);
|
|
4072
|
-
const consumerCleanupRef = React.useRef(null);
|
|
4073
|
-
const setElement = React.useCallback((node) => {
|
|
4074
|
-
elementRef.current = node;
|
|
4075
|
-
if (typeof ref === 'function') {
|
|
4076
|
-
if (node === null) {
|
|
4077
|
-
const consumerCleanup = consumerCleanupRef.current;
|
|
4078
|
-
consumerCleanupRef.current = null;
|
|
4079
|
-
if (consumerCleanup)
|
|
4080
|
-
consumerCleanup();
|
|
4081
|
-
else
|
|
4082
|
-
ref(null);
|
|
4083
|
-
return;
|
|
4084
|
-
}
|
|
4085
|
-
const cleanup = ref(node);
|
|
4086
|
-
consumerCleanupRef.current =
|
|
4087
|
-
typeof cleanup === 'function' ? cleanup : null;
|
|
4088
|
-
}
|
|
4089
|
-
else if (ref) {
|
|
4090
|
-
ref.current = node;
|
|
4091
|
-
}
|
|
4092
|
-
}, [ref]);
|
|
4093
|
-
return (jsxRuntime.jsx(LocaleContext.Provider, { value: value, children: jsxRuntime.jsx(LocaleElementContext.Provider, { value: elementRef, children: jsxRuntime.jsx("div", { ref: setElement, className: classNames(bulmaHelperClasses, className) || undefined, ...rest, dir: dir, lang: locale, children: children }) }) }));
|
|
4094
|
-
});
|
|
4095
|
-
LocaleProvider.displayName = 'LocaleProvider';
|
|
4096
|
-
/** What `useLocale` returns outside a provider, the same object each time. */
|
|
4097
|
-
const noLocale = {};
|
|
4098
|
-
/**
|
|
4099
|
-
* 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.
|
|
4100
|
-
*
|
|
4101
|
-
* It isn't the page's direction: with no provider, or one that sets no
|
|
4102
|
-
* direction, the page's `<html dir>` still decides. To act on the direction
|
|
4103
|
-
* an element is laid out in, read `getComputedStyle(element).direction`, as
|
|
4104
|
-
* the library's components do.
|
|
4105
|
-
*
|
|
4106
|
-
* @function
|
|
4107
|
-
* @returns {LocaleContextValue} The nearest provider's `locale` and `dir`.
|
|
4108
|
-
*
|
|
4109
|
-
* @example
|
|
4110
|
-
* const { locale } = useLocale();
|
|
4111
|
-
* const price = new Intl.NumberFormat(locale, {
|
|
4112
|
-
* style: 'currency',
|
|
4113
|
-
* currency: 'EUR',
|
|
4114
|
-
* }).format(12.5);
|
|
4115
|
-
*/
|
|
4116
|
-
function useLocale() {
|
|
4117
|
-
return React.useContext(LocaleContext) ?? noLocale;
|
|
4118
|
-
}
|
|
4119
|
-
/**
|
|
4120
|
-
* INTERNAL, deliberately not exported from `src/index.ts`. The nearest
|
|
4121
|
-
* provider's settings, or `null` outside any provider, so a caller can tell
|
|
4122
|
-
* "no provider" from "a provider that sets nothing".
|
|
4123
|
-
*/
|
|
4124
|
-
function useLocaleScope() {
|
|
4125
|
-
return React.useContext(LocaleContext);
|
|
4126
|
-
}
|
|
4127
|
-
const displayContents = { display: 'contents' };
|
|
4128
|
-
/**
|
|
4129
|
-
* INTERNAL, deliberately not exported from `src/index.ts`. Keeps the `dir`
|
|
4130
|
-
* and `lang` of the nearest provider, or the `scope` given in their place,
|
|
4131
|
-
* on content the library portals into `target`, which has left the
|
|
4132
|
-
* provider's wrapper behind.
|
|
4133
|
-
*
|
|
4134
|
-
* A target inside the provider's own wrapper gets the content as it is: it
|
|
4135
|
-
* inherits from the wrapper, and follows it when the provider changes.
|
|
4136
|
-
* Content that must be its container's direct child, a `<tr>` portaled into
|
|
4137
|
-
* a `<tbody>` there, stays one. Any other target, `document.body` included,
|
|
4138
|
-
* gets the content inside a `display: contents` element carrying the
|
|
4139
|
-
* values, which adds no box. So does content with a `scope` of its own, a
|
|
4140
|
-
* picker's panel, since the provider's values aren't its own.
|
|
4141
|
-
*
|
|
4142
|
-
* Which of the two is decided once, when the content mounts, and kept while
|
|
4143
|
-
* it stays: switching between them would put a different element in its
|
|
4144
|
-
* place and remount everything inside, losing typed text, focus and timers.
|
|
4145
|
-
* A change of locale or direction updates the wrapper's attributes instead.
|
|
4146
|
-
* A target is never left bare because something else, such as `<html>`,
|
|
4147
|
-
* happens to carry the same values, since that can stop being true without
|
|
4148
|
-
* the content remounting. Outside a provider it renders the children alone,
|
|
4149
|
-
* so nothing changes there.
|
|
4150
|
-
*/
|
|
4151
|
-
function LocalePortalScope({ children, target, scope, }) {
|
|
4152
|
-
const provider = React.useContext(LocaleContext);
|
|
4153
|
-
const element = React.useContext(LocaleElementContext);
|
|
4154
|
-
const [wrap] = React.useState(() => scope !== undefined || !element?.current?.contains(target));
|
|
4155
|
-
if (!provider || !wrap)
|
|
4156
|
-
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: children });
|
|
4157
|
-
const values = scope ?? provider;
|
|
4158
|
-
return (jsxRuntime.jsx("div", { dir: values.dir, lang: values.locale, style: displayContents, children: children }));
|
|
4159
|
-
}
|
|
4160
|
-
|
|
4161
4274
|
/**
|
|
4162
4275
|
* Resolves a portal target: an `HTMLElement` is used directly, a non-empty
|
|
4163
4276
|
* `string` is treated as a `document.querySelector` selector (falling back to
|
|
@@ -5583,6 +5696,7 @@ const PaginationComponent = ({ color, textColor, bgColor, size, align, rounded,
|
|
|
5583
5696
|
backgroundColor: bgColor,
|
|
5584
5697
|
...props,
|
|
5585
5698
|
});
|
|
5699
|
+
const formatNumber = useNumberFormat();
|
|
5586
5700
|
// Generate Bulma classes with prefix
|
|
5587
5701
|
const bulmaClasses = usePrefixedClassNames('pagination', {
|
|
5588
5702
|
[`is-${color}`]: color,
|
|
@@ -5625,7 +5739,13 @@ const PaginationComponent = ({ color, textColor, bgColor, size, align, rounded,
|
|
|
5625
5739
|
});
|
|
5626
5740
|
const atStart = disabled || page <= 1;
|
|
5627
5741
|
const atEnd = disabled || page >= pages;
|
|
5628
|
-
content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(PaginationPrevious, { disabled: atStart, ...linkTo(page - 1, atStart), children: previousLabel }), jsxRuntime.jsx(PaginationNext, { disabled: atEnd, ...linkTo(page + 1, atEnd), children: nextLabel }), jsxRuntime.jsx(PaginationList, { children: pageItems(pages, page, whole(siblingCount, 1), whole(boundaryCount, 1)).map(item =>
|
|
5742
|
+
content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(PaginationPrevious, { disabled: atStart, ...linkTo(page - 1, atStart), children: previousLabel }), jsxRuntime.jsx(PaginationNext, { disabled: atEnd, ...linkTo(page + 1, atEnd), children: nextLabel }), jsxRuntime.jsx(PaginationList, { children: pageItems(pages, page, whole(siblingCount, 1), whole(boundaryCount, 1)).map(item => {
|
|
5743
|
+
if (typeof item !== 'number') {
|
|
5744
|
+
return jsxRuntime.jsx(PaginationEllipsis, {}, item);
|
|
5745
|
+
}
|
|
5746
|
+
const shown = formatNumber ? formatNumber(item) : item;
|
|
5747
|
+
return (jsxRuntime.jsx(PaginationLink, { "aria-label": getPageLabel ? getPageLabel(item) : `Page ${shown}`, active: item === page, disabled: disabled, ...linkTo(item, Boolean(disabled)), children: shown }, item));
|
|
5748
|
+
}) })] }));
|
|
5629
5749
|
}
|
|
5630
5750
|
return (jsxRuntime.jsx("nav", { className: paginationClasses, role: "navigation", "aria-label": "pagination", ...rest, children: content }));
|
|
5631
5751
|
};
|
|
@@ -8330,6 +8450,7 @@ const ContextMenu = withSubComponents(ContextMenuComponent, {
|
|
|
8330
8450
|
*/
|
|
8331
8451
|
const Step = ({ isActive = false, isCompleted = false, label, icon, clickable = false, onClick, stepNumber, completedIcon, className, children, ...props }) => {
|
|
8332
8452
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
8453
|
+
const formatNumber = useNumberFormat();
|
|
8333
8454
|
const stepClasses = classNames(usePrefixedClassNames('steps-segment', {
|
|
8334
8455
|
'is-active': isActive,
|
|
8335
8456
|
'is-completed': isCompleted,
|
|
@@ -8342,7 +8463,9 @@ const Step = ({ isActive = false, isCompleted = false, label, icon, clickable =
|
|
|
8342
8463
|
const markerContent = icon ||
|
|
8343
8464
|
(isCompleted && resolvedCompletedIcon
|
|
8344
8465
|
? resolvedCompletedIcon
|
|
8345
|
-
:
|
|
8466
|
+
: stepNumber == null || !formatNumber
|
|
8467
|
+
? (stepNumber ?? null)
|
|
8468
|
+
: formatNumber(stepNumber));
|
|
8346
8469
|
const title = label || children;
|
|
8347
8470
|
const current = isActive ? 'step' : undefined;
|
|
8348
8471
|
// The step stays a list item, and a real button inside it does the
|
|
@@ -12621,20 +12744,26 @@ function setRefs$1(node, own, forwarded) {
|
|
|
12621
12744
|
/**
|
|
12622
12745
|
* The default filter: the actions whose label, keywords or description hold
|
|
12623
12746
|
* the search, ignoring case and the spaces around it, label matches first and
|
|
12624
|
-
* the order otherwise kept. An empty search keeps them all.
|
|
12747
|
+
* the order otherwise kept. An empty search keeps them all. `matchText`, a
|
|
12748
|
+
* `LocaleProvider`'s locale-aware matcher, replaces the lowercased
|
|
12749
|
+
* comparison when there is one.
|
|
12625
12750
|
*/
|
|
12626
|
-
const filterActions = (query, actions) => {
|
|
12627
|
-
const
|
|
12628
|
-
if (
|
|
12751
|
+
const filterActions = (query, actions, matchText) => {
|
|
12752
|
+
const search = query.trim();
|
|
12753
|
+
if (search === '')
|
|
12629
12754
|
return actions;
|
|
12755
|
+
const term = search.toLowerCase();
|
|
12756
|
+
const holds = matchText
|
|
12757
|
+
? (text) => matchText(text, search)
|
|
12758
|
+
: (text) => text.toLowerCase().includes(term);
|
|
12630
12759
|
const byLabel = [];
|
|
12631
12760
|
const byOther = [];
|
|
12632
12761
|
for (const action of actions) {
|
|
12633
|
-
if (action.label
|
|
12762
|
+
if (holds(action.label)) {
|
|
12634
12763
|
byLabel.push(action);
|
|
12635
12764
|
}
|
|
12636
|
-
else if (action.description
|
|
12637
|
-
action.keywords?.some(
|
|
12765
|
+
else if ((action.description !== undefined && holds(action.description)) ||
|
|
12766
|
+
action.keywords?.some(holds)) {
|
|
12638
12767
|
byOther.push(action);
|
|
12639
12768
|
}
|
|
12640
12769
|
}
|
|
@@ -12870,9 +12999,12 @@ CommandEmpty.displayName = 'CommandEmpty';
|
|
|
12870
12999
|
* The field, and the actions that match the search, grouped, or the empty
|
|
12871
13000
|
* message. The search is the parts root's, read from its context.
|
|
12872
13001
|
*/
|
|
12873
|
-
const CommandActionsContent = ({ actions, filter
|
|
13002
|
+
const CommandActionsContent = ({ actions, filter, placeholder, empty, }) => {
|
|
12874
13003
|
const { query } = useCommand();
|
|
12875
|
-
const
|
|
13004
|
+
const matchText = useLocaleMatcher();
|
|
13005
|
+
const shown = filter
|
|
13006
|
+
? filter(query, actions)
|
|
13007
|
+
: filterActions(query, actions, matchText);
|
|
12876
13008
|
// Each group where the matches first name it, and the actions with none
|
|
12877
13009
|
// together where the first of them is, so the best match stays on top.
|
|
12878
13010
|
const sections = new Map();
|
|
@@ -14169,13 +14301,17 @@ const RingProgress = React.forwardRef(({ className, textColor, bgColor, value, m
|
|
|
14169
14301
|
const labelClass = usePrefixedClassNames('ring-progress-label');
|
|
14170
14302
|
// A section's color class, prefixed like the rest.
|
|
14171
14303
|
const classPrefix = useClassPrefix();
|
|
14304
|
+
const formatNumber = useNumberFormat();
|
|
14305
|
+
const writeShare = (share) => formatNumber
|
|
14306
|
+
? formatNumber(share / 100, { style: 'percent' })
|
|
14307
|
+
: `${share}%`;
|
|
14172
14308
|
const roleProps = sections
|
|
14173
14309
|
? {
|
|
14174
14310
|
role: 'img',
|
|
14175
14311
|
'aria-label': [
|
|
14176
14312
|
label || rest['aria-label'],
|
|
14177
14313
|
sections
|
|
14178
|
-
.map((section, i) => `${section.label} ${Math.round(arcs[i].length)}
|
|
14314
|
+
.map((section, i) => `${section.label} ${writeShare(Math.round(arcs[i].length))}`)
|
|
14179
14315
|
.join(', '),
|
|
14180
14316
|
]
|
|
14181
14317
|
.filter(Boolean)
|
|
@@ -14922,10 +15058,12 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
14922
15058
|
: undefined);
|
|
14923
15059
|
onChange?.(event);
|
|
14924
15060
|
};
|
|
15061
|
+
const formatNumber = useNumberFormat();
|
|
14925
15062
|
const pickedText = picked &&
|
|
14926
15063
|
(picked.count === 1
|
|
14927
15064
|
? picked.firstName
|
|
14928
|
-
: (pickedFilesLabel?.(picked.count) ??
|
|
15065
|
+
: (pickedFilesLabel?.(picked.count) ??
|
|
15066
|
+
`${formatNumber ? formatNumber(picked.count) : picked.count} files`));
|
|
14929
15067
|
const shownName = fileName ?? pickedText;
|
|
14930
15068
|
const insideField = useInsideField();
|
|
14931
15069
|
const insideControl = useInsideControl();
|
|
@@ -15517,11 +15655,13 @@ const Slider = React.forwardRef((props, ref) => {
|
|
|
15517
15655
|
: 0;
|
|
15518
15656
|
// Scale helper
|
|
15519
15657
|
const scaleValue = React.useCallback((v) => (scale ? scale(v) : v), [scale]);
|
|
15520
|
-
// Format helper
|
|
15658
|
+
// Format helper: the caller's, else the locale's, else the number as is.
|
|
15659
|
+
const formatNumber = useNumberFormat();
|
|
15660
|
+
const writeNumber = React.useCallback((v) => (formatNumber ? formatNumber(v) : v.toString()), [formatNumber]);
|
|
15521
15661
|
const formatValue = React.useCallback((v) => {
|
|
15522
15662
|
const scaled = scaleValue(v);
|
|
15523
|
-
return formatOutput ? formatOutput(scaled) : scaled
|
|
15524
|
-
}, [formatOutput, scaleValue]);
|
|
15663
|
+
return formatOutput ? formatOutput(scaled) : writeNumber(scaled);
|
|
15664
|
+
}, [formatOutput, scaleValue, writeNumber]);
|
|
15525
15665
|
// --- Handlers ---
|
|
15526
15666
|
const handleSingleChange = React.useCallback((e) => {
|
|
15527
15667
|
const newValue = parseFloat(e.target.value);
|
|
@@ -15641,7 +15781,7 @@ const Slider = React.forwardRef((props, ref) => {
|
|
|
15641
15781
|
ariaProps['aria-valuetext'] = getAriaValueText(value);
|
|
15642
15782
|
}
|
|
15643
15783
|
else if (scale) {
|
|
15644
|
-
ariaProps['aria-valuetext'] = scaleValue(value)
|
|
15784
|
+
ariaProps['aria-valuetext'] = writeNumber(scaleValue(value));
|
|
15645
15785
|
}
|
|
15646
15786
|
return ariaProps;
|
|
15647
15787
|
};
|
|
@@ -16255,6 +16395,7 @@ const Rate = React.forwardRef(({ label, labelSize, labelProps, horizontal, messa
|
|
|
16255
16395
|
callerProps: props,
|
|
16256
16396
|
});
|
|
16257
16397
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
16398
|
+
const formatNumber = useNumberFormat();
|
|
16258
16399
|
const starBaseId = React.useId();
|
|
16259
16400
|
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
16260
16401
|
const [hoverValue, setHoverValue] = React.useState(null);
|
|
@@ -16363,7 +16504,13 @@ const Rate = React.forwardRef(({ label, labelSize, labelProps, horizontal, messa
|
|
|
16363
16504
|
};
|
|
16364
16505
|
// Format score display
|
|
16365
16506
|
const getScoreDisplay = () => {
|
|
16366
|
-
|
|
16507
|
+
const fractional = precision < 1 && currentValue % 1 !== 0;
|
|
16508
|
+
if (formatNumber) {
|
|
16509
|
+
return formatNumber(currentValue, fractional
|
|
16510
|
+
? { minimumFractionDigits: 1, maximumFractionDigits: 1 }
|
|
16511
|
+
: undefined);
|
|
16512
|
+
}
|
|
16513
|
+
if (fractional) {
|
|
16367
16514
|
return currentValue.toFixed(1);
|
|
16368
16515
|
}
|
|
16369
16516
|
return currentValue;
|
|
@@ -16527,6 +16674,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
16527
16674
|
needsLabelId: true,
|
|
16528
16675
|
});
|
|
16529
16676
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
16677
|
+
const matchText = useLocaleMatcher();
|
|
16530
16678
|
const { classPrefix } = useConfig();
|
|
16531
16679
|
const containerRef = React.useRef(null);
|
|
16532
16680
|
const inputRef = React.useRef(null);
|
|
@@ -16556,6 +16704,8 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
16556
16704
|
// Filter data based on input
|
|
16557
16705
|
const filteredData = data.filter(item => {
|
|
16558
16706
|
const displayValue = getDisplayValue(item);
|
|
16707
|
+
if (matchText)
|
|
16708
|
+
return matchText(displayValue, inputValue);
|
|
16559
16709
|
return displayValue.toLowerCase().includes(inputValue.toLowerCase());
|
|
16560
16710
|
});
|
|
16561
16711
|
// The dropdown shows the options or, when nothing matches, the `empty`
|
|
@@ -17262,6 +17412,7 @@ const ComboboxFromData = React.forwardRef((props, ref) => {
|
|
|
17262
17412
|
};
|
|
17263
17413
|
const controlled = value !== undefined;
|
|
17264
17414
|
const [ownValue, setOwnValue] = React.useState(() => asList(defaultValue));
|
|
17415
|
+
const matchText = useLocaleMatcher();
|
|
17265
17416
|
const picked = controlled ? asList(value) : ownValue;
|
|
17266
17417
|
const change = (next) => {
|
|
17267
17418
|
if (!controlled)
|
|
@@ -17289,8 +17440,11 @@ const ComboboxFromData = React.forwardRef((props, ref) => {
|
|
|
17289
17440
|
}
|
|
17290
17441
|
setQuery(null);
|
|
17291
17442
|
};
|
|
17292
|
-
const
|
|
17293
|
-
const
|
|
17443
|
+
const typed = (query ?? '').trim();
|
|
17444
|
+
const term = typed.toLowerCase();
|
|
17445
|
+
const shown = items.filter(item => matchText
|
|
17446
|
+
? matchText(labelOf(item), typed)
|
|
17447
|
+
: labelOf(item).toLowerCase().includes(term));
|
|
17294
17448
|
const inputRef = React.useRef(null);
|
|
17295
17449
|
const select = (pick) => {
|
|
17296
17450
|
onSelect?.(pick);
|
|
@@ -17449,6 +17603,8 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
17449
17603
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
17450
17604
|
const { classPrefix } = useConfig();
|
|
17451
17605
|
const defaultIconLibrary = useIconLibrary();
|
|
17606
|
+
const formatNumber = useNumberFormat();
|
|
17607
|
+
const matchText = useLocaleMatcher();
|
|
17452
17608
|
const resolvedLibrary = iconLibraryProp || defaultIconLibrary || 'fa';
|
|
17453
17609
|
const pcn = (...args) => prefixedClassNames(classPrefix, ...args);
|
|
17454
17610
|
const containerRef = React.useRef(null);
|
|
@@ -17490,7 +17646,9 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
17490
17646
|
// Filter autocomplete data
|
|
17491
17647
|
const filteredData = data.filter(item => {
|
|
17492
17648
|
const displayValue = item.toLowerCase();
|
|
17493
|
-
const matchesInput =
|
|
17649
|
+
const matchesInput = matchText
|
|
17650
|
+
? matchText(item, inputValue)
|
|
17651
|
+
: displayValue.includes(inputValue.toLowerCase());
|
|
17494
17652
|
const notAlreadyAdded = allowDuplicates ||
|
|
17495
17653
|
!tags.some(tag => getDisplayValue(tag).toLowerCase() === displayValue);
|
|
17496
17654
|
const hasInput = inputValue || (openOnFocus && isActive);
|
|
@@ -17740,10 +17898,11 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
17740
17898
|
const combinedClasses = classNames(taginputClasses, bulmaHelperClasses, className);
|
|
17741
17899
|
// Counter text
|
|
17742
17900
|
const showCounter = hasCounter && (maxTags !== undefined || maxlength !== undefined);
|
|
17901
|
+
const write = formatNumber ?? String;
|
|
17743
17902
|
const counterText = maxTags !== undefined
|
|
17744
|
-
? `${tags.length} / ${maxTags}`
|
|
17903
|
+
? `${write(tags.length)} / ${write(maxTags)}`
|
|
17745
17904
|
: maxlength !== undefined
|
|
17746
|
-
? `${inputValue.length} / ${maxlength}`
|
|
17905
|
+
? `${write(inputValue.length)} / ${write(maxlength)}`
|
|
17747
17906
|
: '';
|
|
17748
17907
|
const counterClasses = pcn('help', 'counter');
|
|
17749
17908
|
const tagsClasses = pcn('tags');
|