@allxsmith/bestax-bulma 5.57.4 → 5.58.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/Avatars.js +2 -2
- package/dist/esm/components/Avatars.js.map +1 -1
- package/dist/esm/components/Badge.js +2 -2
- package/dist/esm/components/Badge.js.map +1 -1
- package/dist/esm/components/Pagination.js +2 -2
- package/dist/esm/components/Pagination.js.map +1 -1
- package/dist/esm/components/Steps.js +2 -2
- package/dist/esm/components/Steps.js.map +1 -1
- package/dist/esm/components/TreeView.js +7 -5
- package/dist/esm/components/TreeView.js.map +1 -1
- package/dist/esm/components/useDataTable.js +2 -2
- package/dist/esm/components/useDataTable.js.map +1 -1
- package/dist/esm/elements/NumberFormatter.js +42 -0
- package/dist/esm/elements/NumberFormatter.js.map +1 -0
- package/dist/esm/elements/RingProgress.js +2 -2
- package/dist/esm/elements/RingProgress.js.map +1 -1
- package/dist/esm/form/Dropzone.js +2 -2
- package/dist/esm/form/Dropzone.js.map +1 -1
- package/dist/esm/form/File.js +2 -2
- package/dist/esm/form/File.js.map +1 -1
- package/dist/esm/form/Rate.js +2 -2
- package/dist/esm/form/Rate.js.map +1 -1
- package/dist/esm/form/Slider.js +2 -2
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Taginput.js +2 -2
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/_colorInternals/pickerState.js +2 -2
- package/dist/esm/form/_colorInternals/pickerState.js.map +1 -1
- package/dist/esm/helpers/LocaleProvider.js +13 -6
- package/dist/esm/helpers/LocaleProvider.js.map +1 -1
- package/dist/esm/helpers/localeFormat.js +196 -36
- package/dist/esm/helpers/localeFormat.js.map +1 -1
- package/dist/esm/helpers/useTreeView.js +54 -20
- package/dist/esm/helpers/useTreeView.js.map +1 -1
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +312 -76
- 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/components/TreeView.d.ts +20 -11
- package/dist/types/elements/NumberFormatter.d.ts +62 -0
- package/dist/types/helpers/LocaleProvider.d.ts +7 -0
- package/dist/types/helpers/localeFormat.d.ts +30 -8
- package/dist/types/helpers/useTreeView.d.ts +12 -6
- package/dist/types/index.d.ts +3 -0
- package/dist/types-cjs/components/TreeView.d.ts +20 -11
- package/dist/types-cjs/elements/NumberFormatter.d.ts +62 -0
- package/dist/types-cjs/helpers/LocaleProvider.d.ts +7 -0
- package/dist/types-cjs/helpers/localeFormat.d.ts +30 -8
- package/dist/types-cjs/helpers/useTreeView.d.ts +12 -6
- 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/_field.scss +40 -0
- package/src/scss/form/_index.scss +1 -0
package/dist/index.cjs
CHANGED
|
@@ -1901,15 +1901,22 @@ function localeFirstDay(locale) {
|
|
|
1901
1901
|
const LocaleContext = React.createContext(null);
|
|
1902
1902
|
/** The nearest provider's wrapper element, for `LocalePortalScope` to test targets against. */
|
|
1903
1903
|
const LocaleElementContext = React.createContext(null);
|
|
1904
|
-
/**
|
|
1905
|
-
|
|
1904
|
+
/** The provider's warning about a tag `Intl` refuses. */
|
|
1905
|
+
const warnProviderLocale = (tag) => warnOnce(`locale-provider-invalid:${tag}`, `[bestax-bulma] <LocaleProvider locale="${tag}">: not a language ` +
|
|
1906
|
+
'tag Intl accepts, so it is ignored. Use a BCP 47 tag such as ' +
|
|
1907
|
+
'"en-US", with a hyphen rather than an underscore.');
|
|
1908
|
+
/**
|
|
1909
|
+
* INTERNAL, deliberately not exported from `src/index.ts`. A tag in
|
|
1910
|
+
* canonical form, or `undefined` for an empty or missing one and for one
|
|
1911
|
+
* `Intl` refuses, which `refused` reports: by default the provider's own
|
|
1912
|
+
* development warning, once per tag.
|
|
1913
|
+
*/
|
|
1914
|
+
function validLocale(tag, refused = warnProviderLocale) {
|
|
1906
1915
|
try {
|
|
1907
1916
|
return canonicalLocale(tag);
|
|
1908
1917
|
}
|
|
1909
1918
|
catch {
|
|
1910
|
-
|
|
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.');
|
|
1919
|
+
refused(tag);
|
|
1913
1920
|
return undefined;
|
|
1914
1921
|
}
|
|
1915
1922
|
}
|
|
@@ -2044,48 +2051,207 @@ function LocalePortalScope({ children, target, scope, }) {
|
|
|
2044
2051
|
return (jsxRuntime.jsx("div", { dir: values.dir, lang: values.locale, style: displayContents, children: children }));
|
|
2045
2052
|
}
|
|
2046
2053
|
|
|
2047
|
-
//
|
|
2048
|
-
//
|
|
2049
|
-
//
|
|
2050
|
-
//
|
|
2054
|
+
// Number formatting and text matching in a locale.
|
|
2055
|
+
//
|
|
2056
|
+
// `useNumberFormat` and its `NumberFormatFunction` type are public, exported
|
|
2057
|
+
// from src/index.ts. The rest is INTERNAL, deliberately not exported.
|
|
2058
|
+
//
|
|
2059
|
+
// Which a component calls depends on its job. A component whose job is to
|
|
2060
|
+
// write a number, such as `NumberFormatter`, uses `useNumberFormat`, which
|
|
2061
|
+
// writes in the runtime's locale outside a `LocaleProvider`, as the pickers
|
|
2062
|
+
// do. Any other component that shows a number in passing, such as a badge
|
|
2063
|
+
// count, a page number or a step's number, uses `useScopedNumberFormat`,
|
|
2064
|
+
// and filters a list through `useLocaleMatcher`. Those two return `null`
|
|
2065
|
+
// outside a provider, and inside one that gives no locale, as a provider
|
|
2066
|
+
// with only a `dir` doesn't, so the component keeps the formatting and the
|
|
2067
|
+
// matching it has always had there, as `LocaleProvider` promises.
|
|
2051
2068
|
/** A combining mark: an accent, a vowel sign or a point written on a letter. */
|
|
2052
2069
|
const MARK = /\p{M}/u;
|
|
2053
2070
|
/**
|
|
2054
|
-
* The
|
|
2055
|
-
*
|
|
2056
|
-
* provider's; outside a provider, none.
|
|
2071
|
+
* The warning about a locale `Intl` refuses, given to `useNumberFormat`,
|
|
2072
|
+
* and so to `NumberFormatter`, the only callers that pass one.
|
|
2057
2073
|
*/
|
|
2058
|
-
|
|
2074
|
+
const warnOwnLocale = (tag) => warnOnce(`number-format-invalid-locale:${tag}`, `[bestax-bulma] NumberFormatter or useNumberFormat was given the locale ` +
|
|
2075
|
+
`"${tag}", which is not a language tag Intl accepts, so it is ` +
|
|
2076
|
+
"ignored and numbers are written in the LocaleProvider's locale, " +
|
|
2077
|
+
'else the runtime\'s. Use a BCP 47 tag such as "en-US", with a ' +
|
|
2078
|
+
'hyphen rather than an underscore.');
|
|
2079
|
+
/**
|
|
2080
|
+
* The locale a component formats and matches in: the locale given, else the
|
|
2081
|
+
* `LocaleProvider`'s, else none. A tag `Intl` refuses counts as none, with a
|
|
2082
|
+
* development warning, as `LocaleProvider` treats one.
|
|
2083
|
+
*/
|
|
2084
|
+
function useResolvedLocale(own) {
|
|
2059
2085
|
const scope = useLocaleScope();
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
return scope.locale;
|
|
2086
|
+
const valid = React.useMemo(() => validLocale(own, warnOwnLocale), [own]);
|
|
2087
|
+
return valid || scope?.locale;
|
|
2063
2088
|
}
|
|
2064
2089
|
/**
|
|
2065
|
-
*
|
|
2066
|
-
*
|
|
2067
|
-
|
|
2068
|
-
|
|
2090
|
+
* The options `Intl.NumberFormat` reads, as ECMA-402 lists them. A key reads
|
|
2091
|
+
* each by name, so an inherited option counts as `Intl` counts it.
|
|
2092
|
+
*/
|
|
2093
|
+
const NUMBER_FORMAT_OPTIONS = [
|
|
2094
|
+
'localeMatcher',
|
|
2095
|
+
'numberingSystem',
|
|
2096
|
+
'style',
|
|
2097
|
+
'currency',
|
|
2098
|
+
'currencyDisplay',
|
|
2099
|
+
'currencySign',
|
|
2100
|
+
'unit',
|
|
2101
|
+
'unitDisplay',
|
|
2102
|
+
'notation',
|
|
2103
|
+
'minimumIntegerDigits',
|
|
2104
|
+
'minimumFractionDigits',
|
|
2105
|
+
'maximumFractionDigits',
|
|
2106
|
+
'minimumSignificantDigits',
|
|
2107
|
+
'maximumSignificantDigits',
|
|
2108
|
+
'roundingIncrement',
|
|
2109
|
+
'roundingMode',
|
|
2110
|
+
'roundingPriority',
|
|
2111
|
+
'trailingZeroDisplay',
|
|
2112
|
+
'compactDisplay',
|
|
2113
|
+
'useGrouping',
|
|
2114
|
+
'signDisplay',
|
|
2115
|
+
];
|
|
2116
|
+
const KNOWN_OPTIONS = new Set(NUMBER_FORMAT_OPTIONS);
|
|
2117
|
+
/** One option's value with its type, or `null` for one a key can't hold. */
|
|
2118
|
+
function writeOption(value) {
|
|
2119
|
+
switch (typeof value) {
|
|
2120
|
+
case 'string':
|
|
2121
|
+
return JSON.stringify(value);
|
|
2122
|
+
case 'number':
|
|
2123
|
+
// `NaN` and `Infinity` as themselves, which `JSON.stringify` makes
|
|
2124
|
+
// `null`, and `-0` with its sign.
|
|
2125
|
+
return Object.is(value, -0) ? '-0' : String(value);
|
|
2126
|
+
case 'boolean':
|
|
2127
|
+
return String(value);
|
|
2128
|
+
case 'bigint':
|
|
2129
|
+
return `${value}n`;
|
|
2130
|
+
default:
|
|
2131
|
+
return value === null ? 'null' : null;
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
/**
|
|
2135
|
+
* The options as `Intl` will read them, and a key that tells apart any two
|
|
2136
|
+
* sets it would read differently; `null` when an option `Intl` reads holds
|
|
2137
|
+
* an object, a function or a symbol, which `Intl` converts in ways a key
|
|
2138
|
+
* can't follow. It reads each option `Intl` reads by name, inherited ones
|
|
2139
|
+
* included, then every other enumerable key, own or inherited, so an option
|
|
2140
|
+
* `Intl` gains later still keeps two sets apart. Since `Intl`'s options are
|
|
2141
|
+
* all primitives, one of those other keys holding anything else is left
|
|
2142
|
+
* out. An option set to `undefined` is unset, as it is for `Intl`. The
|
|
2143
|
+
* formatter is built from the copy, so `Intl` sees what the key says, even
|
|
2144
|
+
* of a getter.
|
|
2145
|
+
*/
|
|
2146
|
+
function readOptions(options) {
|
|
2147
|
+
const others = [];
|
|
2148
|
+
for (const name in options) {
|
|
2149
|
+
if (!KNOWN_OPTIONS.has(name))
|
|
2150
|
+
others.push(name);
|
|
2151
|
+
}
|
|
2152
|
+
const names = NUMBER_FORMAT_OPTIONS.concat(others.sort());
|
|
2153
|
+
const read = {};
|
|
2154
|
+
const parts = [];
|
|
2155
|
+
for (const name of names) {
|
|
2156
|
+
const value = options[name];
|
|
2157
|
+
if (value === undefined)
|
|
2158
|
+
continue;
|
|
2159
|
+
const written = writeOption(value);
|
|
2160
|
+
if (written === null) {
|
|
2161
|
+
// An option `Intl` reads converts an object; a key it doesn't read,
|
|
2162
|
+
// such as a config's own `meta`, means nothing to it.
|
|
2163
|
+
if (KNOWN_OPTIONS.has(name))
|
|
2164
|
+
return null;
|
|
2165
|
+
continue;
|
|
2166
|
+
}
|
|
2167
|
+
read[name] = value;
|
|
2168
|
+
parts.push(`${JSON.stringify(name)}:${written}`);
|
|
2169
|
+
}
|
|
2170
|
+
return { key: parts.join(','), read };
|
|
2171
|
+
}
|
|
2172
|
+
/**
|
|
2173
|
+
* Every formatter's `Intl.NumberFormat`s, by locale and options, so a page of
|
|
2174
|
+
* numbers in one locale and format builds one. Building one is the expensive
|
|
2175
|
+
* part of formatting. Past `MOST_NUMBER_FORMATS`, the one used longest ago
|
|
2176
|
+
* goes, so a server that writes numbers in many locales doesn't keep them
|
|
2177
|
+
* all, and the ones in use stay. A `Map` keeps its keys in the order they
|
|
2178
|
+
* were set, so a formatter is set again each time it's used.
|
|
2179
|
+
*/
|
|
2180
|
+
const numberFormats = new Map();
|
|
2181
|
+
const MOST_NUMBER_FORMATS = 200;
|
|
2182
|
+
/** The `Intl.NumberFormat` for `locale` and `options`, built once. */
|
|
2183
|
+
function numberFormatFor(locale, options) {
|
|
2184
|
+
let read;
|
|
2185
|
+
let key = '';
|
|
2186
|
+
if (options !== undefined) {
|
|
2187
|
+
const copy = typeof options === 'object' && options !== null
|
|
2188
|
+
? readOptions(options)
|
|
2189
|
+
: null;
|
|
2190
|
+
// Options a key can't hold get a formatter of their own, which also
|
|
2191
|
+
// throws what `Intl` throws for them.
|
|
2192
|
+
if (!copy)
|
|
2193
|
+
return new Intl.NumberFormat(locale, options);
|
|
2194
|
+
read = copy.read;
|
|
2195
|
+
key = copy.key;
|
|
2196
|
+
}
|
|
2197
|
+
// A locale tag has no spaces, so the key can't be read two ways.
|
|
2198
|
+
const cacheKey = `${locale ?? ''} ${key}`;
|
|
2199
|
+
let format = numberFormats.get(cacheKey);
|
|
2200
|
+
if (format) {
|
|
2201
|
+
numberFormats.delete(cacheKey);
|
|
2202
|
+
}
|
|
2203
|
+
else {
|
|
2204
|
+
// Built before anything is stored, so options `Intl` refuses throw its
|
|
2205
|
+
// error and leave nothing behind.
|
|
2206
|
+
format = new Intl.NumberFormat(locale, read);
|
|
2207
|
+
if (numberFormats.size >= MOST_NUMBER_FORMATS) {
|
|
2208
|
+
numberFormats.delete(numberFormats.keys().next().value);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
numberFormats.set(cacheKey, format);
|
|
2212
|
+
return format;
|
|
2213
|
+
}
|
|
2214
|
+
/** A function that writes numbers in `locale`, the same one for each locale. */
|
|
2215
|
+
function useFormatIn(locale) {
|
|
2216
|
+
return React.useMemo(() => (value, options) => numberFormatFor(locale, options).format(value), [locale]);
|
|
2217
|
+
}
|
|
2218
|
+
/**
|
|
2219
|
+
* A function that writes numbers for display in a locale: `locale` when given, else the `LocaleProvider`'s around the component, else the runtime's.
|
|
2220
|
+
*
|
|
2221
|
+
* Formatters are kept per locale and set of options, since building one is
|
|
2222
|
+
* the expensive part, and shared, so many numbers written the same way build
|
|
2223
|
+
* one. The function is the same from one render to the next for the same
|
|
2224
|
+
* locale, so it's safe in a dependency array. Use it for text outside JSX,
|
|
2225
|
+
* such as an `aria-label`, a `placeholder` or a chart's axis; in JSX,
|
|
2226
|
+
* `NumberFormatter` also marks the number up. On a server render the
|
|
2227
|
+
* runtime's locale is the server's, so give it a locale, here or through a
|
|
2228
|
+
* `LocaleProvider`, where the server's and the browser's can differ. A tag
|
|
2229
|
+
* `Intl` refuses is ignored, with a warning in development, as
|
|
2230
|
+
* `LocaleProvider` ignores one. Options `Intl` refuses throw its error when
|
|
2231
|
+
* the function is called.
|
|
2232
|
+
*
|
|
2233
|
+
* @function
|
|
2234
|
+
* @param locale - A BCP 47 locale tag, which wins over the provider's.
|
|
2235
|
+
* @returns {NumberFormatFunction} Writes `value` with `Intl.NumberFormat` options.
|
|
2069
2236
|
*
|
|
2070
|
-
* @
|
|
2071
|
-
*
|
|
2237
|
+
* @example
|
|
2238
|
+
* const format = useNumberFormat();
|
|
2239
|
+
* const placeholder = format(1500, { style: 'currency', currency: 'EUR' });
|
|
2072
2240
|
*/
|
|
2073
|
-
function useNumberFormat(
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
};
|
|
2088
|
-
}, [locale]);
|
|
2241
|
+
function useNumberFormat(locale) {
|
|
2242
|
+
return useFormatIn(useResolvedLocale(locale));
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* INTERNAL, deliberately not exported from `src/index.ts`. Number formatting
|
|
2246
|
+
* for a component that shows a number in passing, as `useNumberFormat`
|
|
2247
|
+
* writes it in the `LocaleProvider`'s locale, or `null` outside a provider
|
|
2248
|
+
* and inside one that gives no locale, as a provider with only a `dir`
|
|
2249
|
+
* doesn't, where the component keeps the formatting it has always had.
|
|
2250
|
+
*/
|
|
2251
|
+
function useScopedNumberFormat() {
|
|
2252
|
+
const scoped = useResolvedLocale(undefined);
|
|
2253
|
+
const format = useFormatIn(scoped);
|
|
2254
|
+
return scoped ? format : null;
|
|
2089
2255
|
}
|
|
2090
2256
|
/**
|
|
2091
2257
|
* A matcher for filtering a list by what was typed, in the locale of the
|
|
@@ -2099,7 +2265,7 @@ function useNumberFormat(own) {
|
|
|
2099
2265
|
* matches everything.
|
|
2100
2266
|
*/
|
|
2101
2267
|
function useLocaleMatcher() {
|
|
2102
|
-
const locale =
|
|
2268
|
+
const locale = useResolvedLocale(undefined);
|
|
2103
2269
|
return React.useMemo(() => {
|
|
2104
2270
|
if (!locale)
|
|
2105
2271
|
return null;
|
|
@@ -2160,7 +2326,7 @@ function useLocaleMatcher() {
|
|
|
2160
2326
|
*/
|
|
2161
2327
|
const AvatarsComponent = ({ className, max, size, shape, spacing = 'md', spaced = false, surplusLabel, style, children, ...props }) => {
|
|
2162
2328
|
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
2163
|
-
const formatNumber =
|
|
2329
|
+
const formatNumber = useScopedNumberFormat();
|
|
2164
2330
|
// A preset spacing maps to a class; a numeric spacing sets the CSS var inline
|
|
2165
2331
|
// (mirrors Sidebar's inline --bulma-* width var).
|
|
2166
2332
|
const isPresetSpacing = typeof spacing === 'string';
|
|
@@ -2249,7 +2415,7 @@ const Badge = ({ className, badgeClassName, content, max = 99, dot = false, show
|
|
|
2249
2415
|
// A negative or non-integer max is nonsensical; fall back to the default
|
|
2250
2416
|
// rather than render e.g. "-1+" (mirrors Avatars' max sanitization).
|
|
2251
2417
|
const sanitizedMax = Number.isInteger(max) && max >= 0 ? max : 99;
|
|
2252
|
-
const formatNumber =
|
|
2418
|
+
const formatNumber = useScopedNumberFormat();
|
|
2253
2419
|
const displayValue = React.useMemo(() => {
|
|
2254
2420
|
if (dot || !hasContent)
|
|
2255
2421
|
return undefined;
|
|
@@ -5699,7 +5865,7 @@ const PaginationComponent = ({ color, textColor, bgColor, size, align, rounded,
|
|
|
5699
5865
|
backgroundColor: bgColor,
|
|
5700
5866
|
...props,
|
|
5701
5867
|
});
|
|
5702
|
-
const formatNumber =
|
|
5868
|
+
const formatNumber = useScopedNumberFormat();
|
|
5703
5869
|
// Generate Bulma classes with prefix
|
|
5704
5870
|
const bulmaClasses = usePrefixedClassNames('pagination', {
|
|
5705
5871
|
[`is-${color}`]: color,
|
|
@@ -8453,7 +8619,7 @@ const ContextMenu = withSubComponents(ContextMenuComponent, {
|
|
|
8453
8619
|
*/
|
|
8454
8620
|
const Step = ({ isActive = false, isCompleted = false, label, icon, clickable = false, onClick, stepNumber, completedIcon, className, children, ...props }) => {
|
|
8455
8621
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
8456
|
-
const formatNumber =
|
|
8622
|
+
const formatNumber = useScopedNumberFormat();
|
|
8457
8623
|
const stepClasses = classNames(usePrefixedClassNames('steps-segment', {
|
|
8458
8624
|
'is-active': isActive,
|
|
8459
8625
|
'is-completed': isCompleted,
|
|
@@ -10517,15 +10683,23 @@ const Reveal = RevealImpl;
|
|
|
10517
10683
|
Reveal.displayName = 'Reveal';
|
|
10518
10684
|
|
|
10519
10685
|
// INTERNAL: deliberately not exported from src/index.ts.
|
|
10686
|
+
/** The keys and clicks of both checkbox modes, which differ only in what a check reaches. */
|
|
10687
|
+
const CHECKBOX_ACTIONS = {
|
|
10688
|
+
enter: ['open'],
|
|
10689
|
+
space: ['check'],
|
|
10690
|
+
click: ['check'],
|
|
10691
|
+
};
|
|
10520
10692
|
/**
|
|
10521
10693
|
* What Enter, Space and a click on the row do in each mode, from the tables
|
|
10522
|
-
* in #1096. `open` opens or closes a
|
|
10523
|
-
* click on the chevron only ever opens
|
|
10694
|
+
* in #1096, with `checkbox-independent` from #1430. `open` opens or closes a
|
|
10695
|
+
* parent and does nothing on a leaf. A click on the chevron only ever opens
|
|
10696
|
+
* or closes.
|
|
10524
10697
|
*/
|
|
10525
10698
|
const MODES = {
|
|
10526
10699
|
none: { enter: ['open'], space: ['open'], click: ['open'] },
|
|
10527
10700
|
single: { enter: ['select'], space: ['select'], click: ['select', 'open'] },
|
|
10528
|
-
checkbox:
|
|
10701
|
+
checkbox: CHECKBOX_ACTIONS,
|
|
10702
|
+
'checkbox-independent': CHECKBOX_ACTIONS,
|
|
10529
10703
|
};
|
|
10530
10704
|
/** Left and Right, swapped for a right-to-left page. */
|
|
10531
10705
|
const MIRRORED = {
|
|
@@ -10666,6 +10840,13 @@ function useControlled(controlled, initial) {
|
|
|
10666
10840
|
};
|
|
10667
10841
|
return [isControlled ? controlled : own, set];
|
|
10668
10842
|
}
|
|
10843
|
+
/**
|
|
10844
|
+
* The list with `value` added at the end, or, when it's `present`, with
|
|
10845
|
+
* every copy of it taken out. Everything else stays as it was, in its order.
|
|
10846
|
+
*/
|
|
10847
|
+
function addedOrRemoved(list, value, present) {
|
|
10848
|
+
return present ? list.filter(v => v !== value) : [...list, value];
|
|
10849
|
+
}
|
|
10669
10850
|
/**
|
|
10670
10851
|
* The open state, the selection, the keys, the tab stop, the positions and
|
|
10671
10852
|
* the registry of a TreeView (#1096). Focus moves for real, with a roving
|
|
@@ -10674,10 +10855,12 @@ function useControlled(controlled, initial) {
|
|
|
10674
10855
|
* browser (#1171), read off the page once the tree has mounted.
|
|
10675
10856
|
*
|
|
10676
10857
|
* Every item registers its value, its parent and whether it's disabled from
|
|
10677
|
-
* a layout effect. In a checkbox tree a closed item's children still
|
|
10678
|
-
* and register while drawing nothing, so the registry knows every item
|
|
10679
|
-
* check reaches all of them.
|
|
10680
|
-
*
|
|
10858
|
+
* a layout effect. In a `checkbox` tree a closed item's children still
|
|
10859
|
+
* render and register while drawing nothing, so the registry knows every item
|
|
10860
|
+
* and a check reaches all of them. A `checkbox-independent` tree reads each
|
|
10861
|
+
* box off the checked list alone, so a check adds or takes out its own value
|
|
10862
|
+
* and nothing else. The keys read the items on the page, in document order,
|
|
10863
|
+
* each time they need them.
|
|
10681
10864
|
*
|
|
10682
10865
|
* @function useTreeView
|
|
10683
10866
|
* @param options - The TreeView's props.
|
|
@@ -10693,9 +10876,15 @@ function useTreeView(options) {
|
|
|
10693
10876
|
const [expanded, setExpanded] = useControlled(options.expanded, options.defaultExpanded);
|
|
10694
10877
|
const [selection, setSelection] = useControlled(options.selected, options.defaultSelected);
|
|
10695
10878
|
const [checkedList, setChecked] = useControlled(options.checked, options.defaultChecked);
|
|
10879
|
+
// In a `checkbox` tree a check reaches the items under it, by the rules. In
|
|
10880
|
+
// a `checkbox-independent` one each box is its own item's, read off the list.
|
|
10881
|
+
const cascade = mode === 'checkbox';
|
|
10882
|
+
const independent = mode === 'checkbox-independent';
|
|
10883
|
+
// A box on every item, in either checkbox tree.
|
|
10884
|
+
const boxed = cascade || independent;
|
|
10696
10885
|
// Each is read in its own mode only.
|
|
10697
10886
|
const selected = mode === 'single' ? selection : null;
|
|
10698
|
-
const listed = new Set(
|
|
10887
|
+
const listed = new Set(boxed ? checkedList : []);
|
|
10699
10888
|
const treeRef = React.useRef(null);
|
|
10700
10889
|
const registryRef = React.useRef({
|
|
10701
10890
|
records: new Map(),
|
|
@@ -10716,21 +10905,28 @@ function useTreeView(options) {
|
|
|
10716
10905
|
// Each item's place among the items beside it, by its key.
|
|
10717
10906
|
const [positions, setPositions] = React.useState(NO_POSITIONS);
|
|
10718
10907
|
const { records } = registryRef.current;
|
|
10719
|
-
const checks =
|
|
10908
|
+
const checks = cascade
|
|
10720
10909
|
? // eslint-disable-next-line react-hooks/refs -- read in render on purpose: items write the registry from their layout effects and then ask for this render with `refresh`
|
|
10721
10910
|
readChecks(records, listed).states
|
|
10722
10911
|
: undefined;
|
|
10723
10912
|
const tabStop = focused ?? (resting === undefined ? selected : resting);
|
|
10913
|
+
// An item's box, decided here alone, so the box drawn, the tab stop and a
|
|
10914
|
+
// toggle agree: off the list in a `checkbox-independent` tree, and by the
|
|
10915
|
+
// rules in a `checkbox` one, where it's `undefined` until the item
|
|
10916
|
+
// registers. `undefined` in a tree with no boxes.
|
|
10917
|
+
const checkOf = (value) => independent ? listed.has(value) : checks?.get(value);
|
|
10724
10918
|
const isOpen = (value) => expanded.includes(value);
|
|
10725
10919
|
const stateOf = (value, path, disabled) => {
|
|
10726
10920
|
if (mode === 'single') {
|
|
10727
10921
|
return disabled ? {} : { selected: value === selected };
|
|
10728
10922
|
}
|
|
10729
|
-
if (
|
|
10730
|
-
// Until the items register, a value stands for
|
|
10731
|
-
// parent can't know it's mixed.
|
|
10732
|
-
|
|
10733
|
-
|
|
10923
|
+
if (boxed) {
|
|
10924
|
+
// Until the items register in a `checkbox` tree, a value stands for
|
|
10925
|
+
// its branch, and a parent can't know it's mixed.
|
|
10926
|
+
return {
|
|
10927
|
+
checked: checkOf(value) ??
|
|
10928
|
+
(listed.has(value) || (!disabled && path.some(v => listed.has(v)))),
|
|
10929
|
+
};
|
|
10734
10930
|
}
|
|
10735
10931
|
return {};
|
|
10736
10932
|
};
|
|
@@ -10740,9 +10936,8 @@ function useTreeView(options) {
|
|
|
10740
10936
|
};
|
|
10741
10937
|
const run = {
|
|
10742
10938
|
open: ({ value, isParent, open }) => {
|
|
10743
|
-
if (isParent)
|
|
10744
|
-
changeOpen(
|
|
10745
|
-
}
|
|
10939
|
+
if (isParent)
|
|
10940
|
+
changeOpen(addedOrRemoved(expanded, value, open));
|
|
10746
10941
|
},
|
|
10747
10942
|
select: ({ value }) => {
|
|
10748
10943
|
if (value === selected)
|
|
@@ -10751,7 +10946,11 @@ function useTreeView(options) {
|
|
|
10751
10946
|
options.onSelectedChange?.(value);
|
|
10752
10947
|
},
|
|
10753
10948
|
check: ({ value }) => {
|
|
10754
|
-
|
|
10949
|
+
// A `checkbox-independent` box is its own item's alone, so its value
|
|
10950
|
+
// comes or goes and the rest of the list stays as it was.
|
|
10951
|
+
const next = independent
|
|
10952
|
+
? addedOrRemoved(checkedList, value, checkOf(value) === true)
|
|
10953
|
+
: toggledList(records, checkedList, value);
|
|
10755
10954
|
setChecked(next);
|
|
10756
10955
|
options.onCheckedChange?.(next);
|
|
10757
10956
|
},
|
|
@@ -10800,7 +10999,7 @@ function useTreeView(options) {
|
|
|
10800
10999
|
}
|
|
10801
11000
|
if (focused !== null && !isShown(focused))
|
|
10802
11001
|
setFocused(null);
|
|
10803
|
-
const preferred = onPage.find(value => value === selected ||
|
|
11002
|
+
const preferred = onPage.find(value => value === selected || checkOf(value) === true);
|
|
10804
11003
|
const next = preferred ?? (isShown(resting) ? resting : heir(restingPathRef.current));
|
|
10805
11004
|
if (next !== resting) {
|
|
10806
11005
|
setResting(next);
|
|
@@ -10939,7 +11138,8 @@ function useTreeView(options) {
|
|
|
10939
11138
|
};
|
|
10940
11139
|
return {
|
|
10941
11140
|
treeRef,
|
|
10942
|
-
rendersClosed:
|
|
11141
|
+
rendersClosed: cascade,
|
|
11142
|
+
multiselectable: boxed,
|
|
10943
11143
|
tabStop,
|
|
10944
11144
|
isOpen,
|
|
10945
11145
|
stateOf,
|
|
@@ -11403,12 +11603,14 @@ const isGiven$1 = (node) => node !== undefined &&
|
|
|
11403
11603
|
* and close is `Menu`'s job. The root owns which items are open, through
|
|
11404
11604
|
* `expanded`, `defaultExpanded` and `onExpandedChange`.
|
|
11405
11605
|
*
|
|
11406
|
-
* `selectionMode` picks
|
|
11606
|
+
* `selectionMode` picks the kind of tree. With `none`, nothing is picked.
|
|
11407
11607
|
* With `single`, one item is, and `selected` says which. With `checkbox`,
|
|
11408
11608
|
* each item has a box, a check reaches every enabled item under it, closed
|
|
11409
11609
|
* branches included, and a parent with some of its items checked is mixed.
|
|
11410
|
-
* `
|
|
11411
|
-
*
|
|
11610
|
+
* With `checkbox-independent`, each item has a box that checks that item
|
|
11611
|
+
* alone, so a parent means only itself and is never mixed. `selected` is
|
|
11612
|
+
* read in a `single` tree only, and `checked` in the two checkbox trees only.
|
|
11613
|
+
* Selection never follows focus.
|
|
11412
11614
|
*
|
|
11413
11615
|
* Disabled items stay reachable from the keys, so a screen reader finds
|
|
11414
11616
|
* them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a
|
|
@@ -11482,7 +11684,7 @@ const TreeViewRoot = React.forwardRef(function TreeView({ children, selectionMod
|
|
|
11482
11684
|
// beside the tree, since a tree holds items and groups only, and it's
|
|
11483
11685
|
// there from the start, so a screen reader is listening to it before
|
|
11484
11686
|
// anything is written into it.
|
|
11485
|
-
return (jsxRuntime.jsxs(TreeViewContext.Provider, { value: { ...engine, announce, loadingLabel, retryLabel }, children: [jsxRuntime.jsx(BranchContext.Provider, { value: TOP, children: jsxRuntime.jsx("ul", { ...rest, ref: setRefs, className: classNames(rootClass, bulmaHelperClasses, className), role: "tree", "aria-multiselectable": engine.
|
|
11687
|
+
return (jsxRuntime.jsxs(TreeViewContext.Provider, { value: { ...engine, announce, loadingLabel, retryLabel }, children: [jsxRuntime.jsx(BranchContext.Provider, { value: TOP, children: jsxRuntime.jsx("ul", { ...rest, ref: setRefs, className: classNames(rootClass, bulmaHelperClasses, className), role: "tree", "aria-multiselectable": engine.multiselectable || undefined, children: children }) }), jsxRuntime.jsx(StatusRegion, { items: announcements, describe: describe })] }));
|
|
11486
11688
|
});
|
|
11487
11689
|
/**
|
|
11488
11690
|
* One item in the tree: a row with its chevron, its box, its icon and its label, and, while it's open, a group of the items under it.
|
|
@@ -11576,7 +11778,7 @@ const TreeViewItem = React.forwardRef(function TreeViewItem({ value, label, icon
|
|
|
11576
11778
|
});
|
|
11577
11779
|
if (!tree)
|
|
11578
11780
|
return null;
|
|
11579
|
-
// While it's open the children render in its group. In a checkbox tree
|
|
11781
|
+
// While it's open the children render in its group. In a `checkbox` tree
|
|
11580
11782
|
// they render while it's closed too, drawing nothing, so a check knows
|
|
11581
11783
|
// what's under it.
|
|
11582
11784
|
const items = (open || tree.rendersClosed) && (jsxRuntime.jsx(BranchContext.Provider, { value: childBranch, children: children }));
|
|
@@ -13737,7 +13939,7 @@ function useDataTable(options) {
|
|
|
13737
13939
|
const prefix = useClassPrefix();
|
|
13738
13940
|
const { locale } = useLocale();
|
|
13739
13941
|
const matchText = useLocaleMatcher();
|
|
13740
|
-
const formatNumber =
|
|
13942
|
+
const formatNumber = useScopedNumberFormat();
|
|
13741
13943
|
const collator = React.useMemo(() => new Intl.Collator(locale, { numeric: true }), [locale]);
|
|
13742
13944
|
const pageSize = pageSizeProp !== undefined &&
|
|
13743
13945
|
Number.isFinite(pageSizeProp) &&
|
|
@@ -15184,6 +15386,38 @@ const NotificationContainer = ({ position = 'top-right' }) => {
|
|
|
15184
15386
|
return reactDom.createPortal(jsxRuntime.jsxs(LocalePortalScope, { target: target, children: [stacks.map(stack => (jsxRuntime.jsx("div", { style: notificationStackStyle(stack.position), children: stack.items.map(item => (jsxRuntime.jsx(NotificationItem, { instance: item, onClose: notification.close, registerMessage: registerMessage }, item.id))) }, stack.key))), jsxRuntime.jsx(StatusRegion, { items: politeItems, describe: describe })] }), target);
|
|
15185
15387
|
};
|
|
15186
15388
|
|
|
15389
|
+
/**
|
|
15390
|
+
* The `NumberFormatter` component writes a number the way a locale writes it, such as a price, a percentage or a count, in a `<data>` element that keeps the number itself in its `value`.
|
|
15391
|
+
*
|
|
15392
|
+
* It formats with `Intl.NumberFormat`, in its own `locale`, else the
|
|
15393
|
+
* `LocaleProvider`'s around it, else the runtime's, with `format` as the
|
|
15394
|
+
* options. The `<data>` has no role and no class of its own, so a screen
|
|
15395
|
+
* reader reads the formatted text and it takes the look of the text around
|
|
15396
|
+
* it. For text outside JSX, such as an `aria-label`, `useNumberFormat`
|
|
15397
|
+
* gives the same formatting as a function.
|
|
15398
|
+
*
|
|
15399
|
+
* @function
|
|
15400
|
+
* @param {NumberFormatterProps} props - Props for the NumberFormatter component.
|
|
15401
|
+
* @param {React.Ref<HTMLDataElement>} ref - Forwarded ref to the `<data>`.
|
|
15402
|
+
* @returns {JSX.Element} The rendered number.
|
|
15403
|
+
*
|
|
15404
|
+
* @example
|
|
15405
|
+
* <NumberFormatter
|
|
15406
|
+
* value={8456.4}
|
|
15407
|
+
* format={{ style: 'currency', currency: 'USD' }}
|
|
15408
|
+
* />
|
|
15409
|
+
*/
|
|
15410
|
+
const NumberFormatter = React.forwardRef(({ className, textColor, bgColor, value, format, locale, ...props }, ref) => {
|
|
15411
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
15412
|
+
color: textColor,
|
|
15413
|
+
backgroundColor: bgColor,
|
|
15414
|
+
...props,
|
|
15415
|
+
});
|
|
15416
|
+
const formatNumber = useNumberFormat(locale);
|
|
15417
|
+
return (jsxRuntime.jsx("data", { ref: ref, className: classNames(bulmaHelperClasses, className) || undefined, ...rest, value: Object.is(value, -0) ? '-0' : String(value), children: formatNumber(value, format) }));
|
|
15418
|
+
});
|
|
15419
|
+
NumberFormatter.displayName = 'NumberFormatter';
|
|
15420
|
+
|
|
15187
15421
|
/**
|
|
15188
15422
|
* The `OrderedList` component renders a styled ordered list (`<ol>`) element with Bulma helper class integration.
|
|
15189
15423
|
*
|
|
@@ -15327,7 +15561,7 @@ const RingProgress = React.forwardRef(({ className, textColor, bgColor, value, m
|
|
|
15327
15561
|
const labelClass = usePrefixedClassNames('ring-progress-label');
|
|
15328
15562
|
// A section's color class, prefixed like the rest.
|
|
15329
15563
|
const classPrefix = useClassPrefix();
|
|
15330
|
-
const formatNumber =
|
|
15564
|
+
const formatNumber = useScopedNumberFormat();
|
|
15331
15565
|
const writeShare = (share) => formatNumber
|
|
15332
15566
|
? formatNumber(share / 100, { style: 'percent' })
|
|
15333
15567
|
: `${share}%`;
|
|
@@ -15966,7 +16200,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
15966
16200
|
node;
|
|
15967
16201
|
}
|
|
15968
16202
|
}, [ref]);
|
|
15969
|
-
const formatNumber =
|
|
16203
|
+
const formatNumber = useScopedNumberFormat();
|
|
15970
16204
|
const tokens = acceptTokens(accept);
|
|
15971
16205
|
const sizeText = (bytes) => formatFileSize(bytes, formatNumber);
|
|
15972
16206
|
const countText = (count) => formatNumber ? formatNumber(count) : String(count);
|
|
@@ -16391,7 +16625,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
16391
16625
|
: undefined);
|
|
16392
16626
|
onChange?.(event);
|
|
16393
16627
|
};
|
|
16394
|
-
const formatNumber =
|
|
16628
|
+
const formatNumber = useScopedNumberFormat();
|
|
16395
16629
|
const pickedText = picked &&
|
|
16396
16630
|
(picked.count === 1
|
|
16397
16631
|
? picked.firstName
|
|
@@ -17006,7 +17240,7 @@ const Slider = React.forwardRef((props, ref) => {
|
|
|
17006
17240
|
// Scale helper
|
|
17007
17241
|
const scaleValue = React.useCallback((v) => (scale ? scale(v) : v), [scale]);
|
|
17008
17242
|
// Format helper: the caller's, else the locale's, else the number as is.
|
|
17009
|
-
const formatNumber =
|
|
17243
|
+
const formatNumber = useScopedNumberFormat();
|
|
17010
17244
|
const writeNumber = React.useCallback((v) => (formatNumber ? formatNumber(v) : v.toString()), [formatNumber]);
|
|
17011
17245
|
const formatValue = React.useCallback((v) => {
|
|
17012
17246
|
const scaled = scaleValue(v);
|
|
@@ -17745,7 +17979,7 @@ const Rate = React.forwardRef(({ label, labelSize, labelProps, horizontal, messa
|
|
|
17745
17979
|
callerProps: props,
|
|
17746
17980
|
});
|
|
17747
17981
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
17748
|
-
const formatNumber =
|
|
17982
|
+
const formatNumber = useScopedNumberFormat();
|
|
17749
17983
|
const starBaseId = React.useId();
|
|
17750
17984
|
const [internalValue, setInternalValue] = React.useState(defaultValue);
|
|
17751
17985
|
const [hoverValue, setHoverValue] = React.useState(null);
|
|
@@ -18953,7 +19187,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
|
|
|
18953
19187
|
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
18954
19188
|
const { classPrefix } = useConfig();
|
|
18955
19189
|
const defaultIconLibrary = useIconLibrary();
|
|
18956
|
-
const formatNumber =
|
|
19190
|
+
const formatNumber = useScopedNumberFormat();
|
|
18957
19191
|
const matchText = useLocaleMatcher();
|
|
18958
19192
|
const resolvedLibrary = iconLibraryProp || defaultIconLibrary || 'fa';
|
|
18959
19193
|
const pcn = (...args) => prefixedClassNames(classPrefix, ...args);
|
|
@@ -19770,7 +20004,7 @@ function useColorPicker({ value, defaultValue, onChange, onChangeEnd, format, al
|
|
|
19770
20004
|
onChangeEnd?.(nextText);
|
|
19771
20005
|
}, [disabled, alpha, format, onChange, onChangeEnd, empty]);
|
|
19772
20006
|
const end = React.useCallback(() => onChangeEnd?.(lastTextRef.current), [onChangeEnd]);
|
|
19773
|
-
const formatNumber =
|
|
20007
|
+
const formatNumber = useScopedNumberFormat();
|
|
19774
20008
|
const { isCoarsePointer } = useNativeMobilePicker();
|
|
19775
20009
|
const merged = mergeColorLabels(labels);
|
|
19776
20010
|
return {
|
|
@@ -27604,6 +27838,7 @@ exports.NavbarMenu = NavbarMenu;
|
|
|
27604
27838
|
exports.NavbarStart = NavbarStart;
|
|
27605
27839
|
exports.Notification = Notification;
|
|
27606
27840
|
exports.NotificationContainer = NotificationContainer;
|
|
27841
|
+
exports.NumberFormatter = NumberFormatter;
|
|
27607
27842
|
exports.NumberInput = NumberInput;
|
|
27608
27843
|
exports.Numberinput = Numberinput;
|
|
27609
27844
|
exports.OrderedList = OrderedList;
|
|
@@ -27712,6 +27947,7 @@ exports.useInsideControl = useInsideControl;
|
|
|
27712
27947
|
exports.useInsideField = useInsideField;
|
|
27713
27948
|
exports.useIsHydrated = useIsHydrated;
|
|
27714
27949
|
exports.useLocale = useLocale;
|
|
27950
|
+
exports.useNumberFormat = useNumberFormat;
|
|
27715
27951
|
exports.useOtherClasses = useOtherClasses;
|
|
27716
27952
|
exports.usePrefixedClass = usePrefixedClass;
|
|
27717
27953
|
exports.usePrefixedClassNames = usePrefixedClassNames;
|