@allxsmith/bestax-bulma 5.57.5 → 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.
Files changed (51) hide show
  1. package/dist/esm/components/Avatars.js +2 -2
  2. package/dist/esm/components/Avatars.js.map +1 -1
  3. package/dist/esm/components/Badge.js +2 -2
  4. package/dist/esm/components/Badge.js.map +1 -1
  5. package/dist/esm/components/Pagination.js +2 -2
  6. package/dist/esm/components/Pagination.js.map +1 -1
  7. package/dist/esm/components/Steps.js +2 -2
  8. package/dist/esm/components/Steps.js.map +1 -1
  9. package/dist/esm/components/TreeView.js +7 -5
  10. package/dist/esm/components/TreeView.js.map +1 -1
  11. package/dist/esm/components/useDataTable.js +2 -2
  12. package/dist/esm/components/useDataTable.js.map +1 -1
  13. package/dist/esm/elements/NumberFormatter.js +42 -0
  14. package/dist/esm/elements/NumberFormatter.js.map +1 -0
  15. package/dist/esm/elements/RingProgress.js +2 -2
  16. package/dist/esm/elements/RingProgress.js.map +1 -1
  17. package/dist/esm/form/Dropzone.js +2 -2
  18. package/dist/esm/form/Dropzone.js.map +1 -1
  19. package/dist/esm/form/File.js +2 -2
  20. package/dist/esm/form/File.js.map +1 -1
  21. package/dist/esm/form/Rate.js +2 -2
  22. package/dist/esm/form/Rate.js.map +1 -1
  23. package/dist/esm/form/Slider.js +2 -2
  24. package/dist/esm/form/Slider.js.map +1 -1
  25. package/dist/esm/form/Taginput.js +2 -2
  26. package/dist/esm/form/Taginput.js.map +1 -1
  27. package/dist/esm/form/_colorInternals/pickerState.js +2 -2
  28. package/dist/esm/form/_colorInternals/pickerState.js.map +1 -1
  29. package/dist/esm/helpers/LocaleProvider.js +13 -6
  30. package/dist/esm/helpers/LocaleProvider.js.map +1 -1
  31. package/dist/esm/helpers/localeFormat.js +196 -36
  32. package/dist/esm/helpers/localeFormat.js.map +1 -1
  33. package/dist/esm/helpers/useTreeView.js +54 -20
  34. package/dist/esm/helpers/useTreeView.js.map +1 -1
  35. package/dist/index.cjs +312 -76
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.esm.js +2 -0
  38. package/dist/index.esm.js.map +1 -1
  39. package/dist/types/components/TreeView.d.ts +20 -11
  40. package/dist/types/elements/NumberFormatter.d.ts +62 -0
  41. package/dist/types/helpers/LocaleProvider.d.ts +7 -0
  42. package/dist/types/helpers/localeFormat.d.ts +30 -8
  43. package/dist/types/helpers/useTreeView.d.ts +12 -6
  44. package/dist/types/index.d.ts +3 -0
  45. package/dist/types-cjs/components/TreeView.d.ts +20 -11
  46. package/dist/types-cjs/elements/NumberFormatter.d.ts +62 -0
  47. package/dist/types-cjs/helpers/LocaleProvider.d.ts +7 -0
  48. package/dist/types-cjs/helpers/localeFormat.d.ts +30 -8
  49. package/dist/types-cjs/helpers/useTreeView.d.ts +12 -6
  50. package/dist/types-cjs/index.d.ts +3 -0
  51. package/package.json +1 -1
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
- /** A tag in canonical form, or `undefined`, warning about one `Intl` refuses. */
1905
- function validLocale(tag) {
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
- 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.');
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
- // 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.
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 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.
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
- function useScopedLocale(own) {
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
- if (!scope)
2061
- return undefined;
2062
- return scope.locale;
2086
+ const valid = React.useMemo(() => validLocale(own, warnOwnLocale), [own]);
2087
+ return valid || scope?.locale;
2063
2088
  }
2064
2089
  /**
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.
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
- * @param own - The component's own locale, such as a picker's `locale`,
2071
- * which wins inside a provider.
2237
+ * @example
2238
+ * const format = useNumberFormat();
2239
+ * const placeholder = format(1500, { style: 'currency', currency: 'EUR' });
2072
2240
  */
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]);
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 = useScopedLocale();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 parent and does nothing on a leaf. A
10523
- * click on the chevron only ever opens or closes.
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: { enter: ['open'], space: ['check'], click: ['check'] },
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 render
10678
- * and register while drawing nothing, so the registry knows every item and a
10679
- * check reaches all of them. The keys read the items on the page, in
10680
- * document order, each time they need them.
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(mode === 'checkbox' ? checkedList : []);
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 = mode === 'checkbox'
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 (checks) {
10730
- // Until the items register, a value stands for its branch, and a
10731
- // parent can't know it's mixed.
10732
- const fromList = listed.has(value) || (!disabled && path.some(v => listed.has(v)));
10733
- return { checked: checks.get(value) ?? fromList };
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(open ? expanded.filter(v => v !== value) : [...expanded, value]);
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
- const next = toggledList(records, checkedList, value);
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 || checks?.get(value) === true);
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: mode === 'checkbox',
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 one of three trees. With `none`, nothing is picked.
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
- * `selected` is read in a `single` tree only, and `checked` in a `checkbox`
11411
- * tree only. Selection never follows focus.
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.rendersClosed || undefined, children: children }) }), jsxRuntime.jsx(StatusRegion, { items: announcements, describe: describe })] }));
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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 = useNumberFormat();
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;