@allxsmith/bestax-bulma 5.57.5 → 5.59.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 (112) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/components/Avatars.js +2 -2
  4. package/dist/esm/components/Avatars.js.map +1 -1
  5. package/dist/esm/components/Badge.js +2 -2
  6. package/dist/esm/components/Badge.js.map +1 -1
  7. package/dist/esm/components/Pagination.js +2 -2
  8. package/dist/esm/components/Pagination.js.map +1 -1
  9. package/dist/esm/components/Steps.js +2 -2
  10. package/dist/esm/components/Steps.js.map +1 -1
  11. package/dist/esm/components/TreeView.js +7 -5
  12. package/dist/esm/components/TreeView.js.map +1 -1
  13. package/dist/esm/components/useDataTable.js +2 -2
  14. package/dist/esm/components/useDataTable.js.map +1 -1
  15. package/dist/esm/elements/Buttons.js +2 -0
  16. package/dist/esm/elements/Buttons.js.map +1 -1
  17. package/dist/esm/elements/IconButton.js +114 -0
  18. package/dist/esm/elements/IconButton.js.map +1 -0
  19. package/dist/esm/elements/NumberFormatter.js +42 -0
  20. package/dist/esm/elements/NumberFormatter.js.map +1 -0
  21. package/dist/esm/elements/RingProgress.js +2 -2
  22. package/dist/esm/elements/RingProgress.js.map +1 -1
  23. package/dist/esm/form/Dropzone.js +2 -2
  24. package/dist/esm/form/Dropzone.js.map +1 -1
  25. package/dist/esm/form/File.js +2 -2
  26. package/dist/esm/form/File.js.map +1 -1
  27. package/dist/esm/form/Rate.js +2 -2
  28. package/dist/esm/form/Rate.js.map +1 -1
  29. package/dist/esm/form/Slider.js +2 -2
  30. package/dist/esm/form/Slider.js.map +1 -1
  31. package/dist/esm/form/Taginput.js +2 -2
  32. package/dist/esm/form/Taginput.js.map +1 -1
  33. package/dist/esm/form/_colorInternals/pickerState.js +2 -2
  34. package/dist/esm/form/_colorInternals/pickerState.js.map +1 -1
  35. package/dist/esm/helpers/LocaleProvider.js +13 -6
  36. package/dist/esm/helpers/LocaleProvider.js.map +1 -1
  37. package/dist/esm/helpers/containerBreakpoints.js +14 -0
  38. package/dist/esm/helpers/containerBreakpoints.js.map +1 -0
  39. package/dist/esm/helpers/localeFormat.js +196 -36
  40. package/dist/esm/helpers/localeFormat.js.map +1 -1
  41. package/dist/esm/helpers/polymorphic.js.map +1 -1
  42. package/dist/esm/helpers/stackLayout.js +30 -0
  43. package/dist/esm/helpers/stackLayout.js.map +1 -0
  44. package/dist/esm/helpers/useBulmaClasses.js +8 -2
  45. package/dist/esm/helpers/useBulmaClasses.js.map +1 -1
  46. package/dist/esm/helpers/useFlexboxClasses.js +17 -4
  47. package/dist/esm/helpers/useFlexboxClasses.js.map +1 -1
  48. package/dist/esm/helpers/useTreeView.js +54 -20
  49. package/dist/esm/helpers/useTreeView.js.map +1 -1
  50. package/dist/esm/layout/Center.js +33 -0
  51. package/dist/esm/layout/Center.js.map +1 -0
  52. package/dist/esm/layout/Container.js +2 -6
  53. package/dist/esm/layout/Container.js.map +1 -1
  54. package/dist/esm/layout/Flex.js +34 -0
  55. package/dist/esm/layout/Flex.js.map +1 -0
  56. package/dist/esm/layout/Group.js +43 -0
  57. package/dist/esm/layout/Group.js.map +1 -0
  58. package/dist/esm/layout/Stack.js +34 -0
  59. package/dist/esm/layout/Stack.js.map +1 -0
  60. package/dist/extras.css +1 -1
  61. package/dist/extras.css.map +1 -1
  62. package/dist/index.cjs +712 -212
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.esm.js +7 -0
  65. package/dist/index.esm.js.map +1 -1
  66. package/dist/types/components/TreeView.d.ts +20 -11
  67. package/dist/types/elements/Buttons.d.ts +1 -0
  68. package/dist/types/elements/IconButton.d.ts +110 -0
  69. package/dist/types/elements/NumberFormatter.d.ts +62 -0
  70. package/dist/types/helpers/LocaleProvider.d.ts +7 -0
  71. package/dist/types/helpers/containerBreakpoints.d.ts +2 -0
  72. package/dist/types/helpers/localeFormat.d.ts +30 -8
  73. package/dist/types/helpers/polymorphic.d.ts +19 -0
  74. package/dist/types/helpers/stackLayout.d.ts +62 -0
  75. package/dist/types/helpers/useBulmaClasses.d.ts +8 -2
  76. package/dist/types/helpers/useFlexboxClasses.d.ts +26 -3
  77. package/dist/types/helpers/useTreeView.d.ts +12 -6
  78. package/dist/types/index.d.ts +10 -1
  79. package/dist/types/layout/Center.d.ts +54 -0
  80. package/dist/types/layout/Flex.d.ts +92 -0
  81. package/dist/types/layout/Group.d.ts +86 -0
  82. package/dist/types/layout/Stack.d.ts +63 -0
  83. package/dist/types-cjs/components/TreeView.d.ts +20 -11
  84. package/dist/types-cjs/elements/Buttons.d.ts +1 -0
  85. package/dist/types-cjs/elements/IconButton.d.ts +110 -0
  86. package/dist/types-cjs/elements/NumberFormatter.d.ts +62 -0
  87. package/dist/types-cjs/helpers/LocaleProvider.d.ts +7 -0
  88. package/dist/types-cjs/helpers/containerBreakpoints.d.ts +2 -0
  89. package/dist/types-cjs/helpers/localeFormat.d.ts +30 -8
  90. package/dist/types-cjs/helpers/polymorphic.d.ts +19 -0
  91. package/dist/types-cjs/helpers/stackLayout.d.ts +62 -0
  92. package/dist/types-cjs/helpers/useBulmaClasses.d.ts +8 -2
  93. package/dist/types-cjs/helpers/useFlexboxClasses.d.ts +26 -3
  94. package/dist/types-cjs/helpers/useTreeView.d.ts +12 -6
  95. package/dist/types-cjs/index.d.ts +10 -1
  96. package/dist/types-cjs/layout/Center.d.ts +54 -0
  97. package/dist/types-cjs/layout/Flex.d.ts +92 -0
  98. package/dist/types-cjs/layout/Group.d.ts +86 -0
  99. package/dist/types-cjs/layout/Stack.d.ts +63 -0
  100. package/dist/versions/bestax-no-dark-mode.css +1 -1
  101. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  102. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  103. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  104. package/dist/versions/bestax-no-helpers.css +1 -1
  105. package/dist/versions/bestax-no-helpers.css.map +1 -1
  106. package/dist/versions/bestax-prefixed.css +1 -1
  107. package/dist/versions/bestax-prefixed.css.map +1 -1
  108. package/package.json +1 -1
  109. package/src/scss/elements/_iconbutton.scss +36 -0
  110. package/src/scss/elements/_index.scss +1 -0
  111. package/src/scss/layout/_index.scss +1 -0
  112. package/src/scss/layout/_stack.scss +145 -0
package/dist/index.cjs CHANGED
@@ -970,8 +970,9 @@ const useVisibilityClasses = (props) => {
970
970
  /**
971
971
  * A hook that generates Bulma flexbox helper classes. Flex container helpers
972
972
  * (direction, wrap, justify/align content, align items) are only emitted when
973
- * one of the display props indicates a flex display; flex item helpers
974
- * (align self, grow, shrink) are always emitted.
973
+ * one of the display props indicates a flex display, or when `options` says
974
+ * the element is a flex container by its own CSS; flex item helpers (align
975
+ * self, grow, shrink) are always emitted.
975
976
  *
976
977
  * Note: this hook reads the display props purely as a gate and never emits
977
978
  * display classes — `is-flex` and friends come from useVisibilityClasses (or
@@ -979,6 +980,7 @@ const useVisibilityClasses = (props) => {
979
980
  *
980
981
  * @function useFlexboxClasses
981
982
  * @param props - Flexbox-related Bulma helper props.
983
+ * @param options - Whether the element is a flex container without a display prop.
982
984
  * @returns A space-separated string of flexbox helper classes.
983
985
  * @example
984
986
  * const flexboxClasses = useFlexboxClasses({
@@ -987,14 +989,24 @@ const useVisibilityClasses = (props) => {
987
989
  * });
988
990
  * // flexboxClasses: 'is-justify-content-center'
989
991
  * // ('is-flex' itself comes from useVisibilityClasses/useBulmaClasses)
990
- */
991
- const useFlexboxClasses = (props) => {
992
+ *
993
+ * @example
994
+ * // An element whose own stylesheet makes it a flex container
995
+ * const flexboxClasses = useFlexboxClasses(
996
+ * { alignItems: 'center' },
997
+ * { flexContainer: true }
998
+ * );
999
+ * // flexboxClasses: 'is-align-items-center'
1000
+ */
1001
+ const useFlexboxClasses = (props, options = {}) => {
992
1002
  const { classPrefix } = useConfig();
1003
+ const { flexContainer = false } = options;
993
1004
  const { flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, flexGrow, flexShrink, display, displayMobile, displayTablet, displayTabletOnly, displayTouch, displayDesktop, displayDesktopOnly, displayWidescreen, displayWidescreenOnly, displayFullhd, } = props;
994
1005
  return React.useMemo(() => {
995
1006
  const { classes, addClassNoViewport } = createBulmaClassHelpers(classPrefix);
996
1007
  // Flexbox
997
- const hasFlexDisplay = display === 'flex' ||
1008
+ const hasFlexDisplay = flexContainer ||
1009
+ display === 'flex' ||
998
1010
  display === 'inline-flex' ||
999
1011
  displayMobile === 'flex' ||
1000
1012
  displayMobile === 'inline-flex' ||
@@ -1030,6 +1042,7 @@ const useFlexboxClasses = (props) => {
1030
1042
  return classNames(classes);
1031
1043
  }, [
1032
1044
  classPrefix,
1045
+ flexContainer,
1033
1046
  flexDirection,
1034
1047
  flexWrap,
1035
1048
  justifyContent,
@@ -1170,8 +1183,14 @@ const useOtherClasses = (props) => {
1170
1183
  * `background-color: var(--bulma-scheme-*)` style (`undefined` for all other
1171
1184
  * inputs). Merge it with a user `style` prop via `mergeBulmaStyles`.
1172
1185
  *
1186
+ * The flex container props (`flexDirection`, `flexWrap`, `justifyContent`,
1187
+ * `alignContent`, `alignItems`) emit a class only on a flex container: when a
1188
+ * `display` prop is `flex` or `inline-flex`, or when `options.flexContainer`
1189
+ * says the element's own stylesheet makes it one.
1190
+ *
1173
1191
  * @function useBulmaClasses
1174
1192
  * @param props - Combination of BulmaClassesPropsWithScheme and additional props.
1193
+ * @param options - Passed to `useFlexboxClasses`: whether the element is a flex container without a display prop.
1175
1194
  * @returns An object containing the Bulma helper classes, optional helper
1176
1195
  * styles, and unhandled props.
1177
1196
  * @example
@@ -1184,7 +1203,7 @@ const useOtherClasses = (props) => {
1184
1203
  * // bulmaHelperStyles: { backgroundColor: 'var(--bulma-scheme-main-bis)' }
1185
1204
  * // rest: { className: 'custom-class' }
1186
1205
  */
1187
- const useBulmaClasses = (props) => {
1206
+ const useBulmaClasses = (props, options) => {
1188
1207
  const { color, backgroundColor, colorShade, backgroundColorShade, m, mt, mr, mb, ml, mx, my, p, pt, pr, pb, pl, px, py, gap, columnGap, rowGap, gapless, textSize, textAlign, textTransform, textWeight, fontFamily, display, visibility, flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, flexGrow, flexShrink, float, overflow, overflowX, overflowY, overlay, interaction, cursor, radius, shadow, responsive, viewport, displayMobile, displayTablet, displayTabletOnly, displayTouch, displayDesktop, displayDesktopOnly, displayWidescreen, displayWidescreenOnly, displayFullhd, textSizeMobile, textSizeTablet, textSizeDesktop, textSizeWidescreen, textSizeFullhd, textAlignMobile, textAlignTablet, textAlignDesktop, textAlignWidescreen, textAlignFullhd, visibilityMobile, visibilityTablet, visibilityTabletOnly, visibilityTouch, visibilityDesktop, visibilityDesktopOnly, visibilityWidescreen, visibilityWidescreenOnly, visibilityFullhd, skeleton, clearfix, pos, relative, fullHeight, aspectRatio, ...rest } = props;
1189
1208
  const colorClasses = useColorClasses({
1190
1209
  color,
@@ -1273,7 +1292,7 @@ const useBulmaClasses = (props) => {
1273
1292
  displayWidescreen,
1274
1293
  displayWidescreenOnly,
1275
1294
  displayFullhd,
1276
- });
1295
+ }, options);
1277
1296
  const otherClasses = useOtherClasses({
1278
1297
  float,
1279
1298
  overflow,
@@ -1901,15 +1920,22 @@ function localeFirstDay(locale) {
1901
1920
  const LocaleContext = React.createContext(null);
1902
1921
  /** The nearest provider's wrapper element, for `LocalePortalScope` to test targets against. */
1903
1922
  const LocaleElementContext = React.createContext(null);
1904
- /** A tag in canonical form, or `undefined`, warning about one `Intl` refuses. */
1905
- function validLocale(tag) {
1923
+ /** The provider's warning about a tag `Intl` refuses. */
1924
+ const warnProviderLocale = (tag) => warnOnce(`locale-provider-invalid:${tag}`, `[bestax-bulma] <LocaleProvider locale="${tag}">: not a language ` +
1925
+ 'tag Intl accepts, so it is ignored. Use a BCP 47 tag such as ' +
1926
+ '"en-US", with a hyphen rather than an underscore.');
1927
+ /**
1928
+ * INTERNAL, deliberately not exported from `src/index.ts`. A tag in
1929
+ * canonical form, or `undefined` for an empty or missing one and for one
1930
+ * `Intl` refuses, which `refused` reports: by default the provider's own
1931
+ * development warning, once per tag.
1932
+ */
1933
+ function validLocale(tag, refused = warnProviderLocale) {
1906
1934
  try {
1907
1935
  return canonicalLocale(tag);
1908
1936
  }
1909
1937
  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.');
1938
+ refused(tag);
1913
1939
  return undefined;
1914
1940
  }
1915
1941
  }
@@ -2044,48 +2070,207 @@ function LocalePortalScope({ children, target, scope, }) {
2044
2070
  return (jsxRuntime.jsx("div", { dir: values.dir, lang: values.locale, style: displayContents, children: children }));
2045
2071
  }
2046
2072
 
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.
2073
+ // Number formatting and text matching in a locale.
2074
+ //
2075
+ // `useNumberFormat` and its `NumberFormatFunction` type are public, exported
2076
+ // from src/index.ts. The rest is INTERNAL, deliberately not exported.
2077
+ //
2078
+ // Which a component calls depends on its job. A component whose job is to
2079
+ // write a number, such as `NumberFormatter`, uses `useNumberFormat`, which
2080
+ // writes in the runtime's locale outside a `LocaleProvider`, as the pickers
2081
+ // do. Any other component that shows a number in passing, such as a badge
2082
+ // count, a page number or a step's number, uses `useScopedNumberFormat`,
2083
+ // and filters a list through `useLocaleMatcher`. Those two return `null`
2084
+ // outside a provider, and inside one that gives no locale, as a provider
2085
+ // with only a `dir` doesn't, so the component keeps the formatting and the
2086
+ // matching it has always had there, as `LocaleProvider` promises.
2051
2087
  /** A combining mark: an accent, a vowel sign or a point written on a letter. */
2052
2088
  const MARK = /\p{M}/u;
2053
2089
  /**
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.
2090
+ * The warning about a locale `Intl` refuses, given to `useNumberFormat`,
2091
+ * and so to `NumberFormatter`, the only callers that pass one.
2057
2092
  */
2058
- function useScopedLocale(own) {
2093
+ const warnOwnLocale = (tag) => warnOnce(`number-format-invalid-locale:${tag}`, `[bestax-bulma] NumberFormatter or useNumberFormat was given the locale ` +
2094
+ `"${tag}", which is not a language tag Intl accepts, so it is ` +
2095
+ "ignored and numbers are written in the LocaleProvider's locale, " +
2096
+ 'else the runtime\'s. Use a BCP 47 tag such as "en-US", with a ' +
2097
+ 'hyphen rather than an underscore.');
2098
+ /**
2099
+ * The locale a component formats and matches in: the locale given, else the
2100
+ * `LocaleProvider`'s, else none. A tag `Intl` refuses counts as none, with a
2101
+ * development warning, as `LocaleProvider` treats one.
2102
+ */
2103
+ function useResolvedLocale(own) {
2059
2104
  const scope = useLocaleScope();
2060
- if (!scope)
2061
- return undefined;
2062
- return scope.locale;
2105
+ const valid = React.useMemo(() => validLocale(own, warnOwnLocale), [own]);
2106
+ return valid || scope?.locale;
2063
2107
  }
2064
2108
  /**
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.
2109
+ * The options `Intl.NumberFormat` reads, as ECMA-402 lists them. A key reads
2110
+ * each by name, so an inherited option counts as `Intl` counts it.
2111
+ */
2112
+ const NUMBER_FORMAT_OPTIONS = [
2113
+ 'localeMatcher',
2114
+ 'numberingSystem',
2115
+ 'style',
2116
+ 'currency',
2117
+ 'currencyDisplay',
2118
+ 'currencySign',
2119
+ 'unit',
2120
+ 'unitDisplay',
2121
+ 'notation',
2122
+ 'minimumIntegerDigits',
2123
+ 'minimumFractionDigits',
2124
+ 'maximumFractionDigits',
2125
+ 'minimumSignificantDigits',
2126
+ 'maximumSignificantDigits',
2127
+ 'roundingIncrement',
2128
+ 'roundingMode',
2129
+ 'roundingPriority',
2130
+ 'trailingZeroDisplay',
2131
+ 'compactDisplay',
2132
+ 'useGrouping',
2133
+ 'signDisplay',
2134
+ ];
2135
+ const KNOWN_OPTIONS = new Set(NUMBER_FORMAT_OPTIONS);
2136
+ /** One option's value with its type, or `null` for one a key can't hold. */
2137
+ function writeOption(value) {
2138
+ switch (typeof value) {
2139
+ case 'string':
2140
+ return JSON.stringify(value);
2141
+ case 'number':
2142
+ // `NaN` and `Infinity` as themselves, which `JSON.stringify` makes
2143
+ // `null`, and `-0` with its sign.
2144
+ return Object.is(value, -0) ? '-0' : String(value);
2145
+ case 'boolean':
2146
+ return String(value);
2147
+ case 'bigint':
2148
+ return `${value}n`;
2149
+ default:
2150
+ return value === null ? 'null' : null;
2151
+ }
2152
+ }
2153
+ /**
2154
+ * The options as `Intl` will read them, and a key that tells apart any two
2155
+ * sets it would read differently; `null` when an option `Intl` reads holds
2156
+ * an object, a function or a symbol, which `Intl` converts in ways a key
2157
+ * can't follow. It reads each option `Intl` reads by name, inherited ones
2158
+ * included, then every other enumerable key, own or inherited, so an option
2159
+ * `Intl` gains later still keeps two sets apart. Since `Intl`'s options are
2160
+ * all primitives, one of those other keys holding anything else is left
2161
+ * out. An option set to `undefined` is unset, as it is for `Intl`. The
2162
+ * formatter is built from the copy, so `Intl` sees what the key says, even
2163
+ * of a getter.
2164
+ */
2165
+ function readOptions(options) {
2166
+ const others = [];
2167
+ for (const name in options) {
2168
+ if (!KNOWN_OPTIONS.has(name))
2169
+ others.push(name);
2170
+ }
2171
+ const names = NUMBER_FORMAT_OPTIONS.concat(others.sort());
2172
+ const read = {};
2173
+ const parts = [];
2174
+ for (const name of names) {
2175
+ const value = options[name];
2176
+ if (value === undefined)
2177
+ continue;
2178
+ const written = writeOption(value);
2179
+ if (written === null) {
2180
+ // An option `Intl` reads converts an object; a key it doesn't read,
2181
+ // such as a config's own `meta`, means nothing to it.
2182
+ if (KNOWN_OPTIONS.has(name))
2183
+ return null;
2184
+ continue;
2185
+ }
2186
+ read[name] = value;
2187
+ parts.push(`${JSON.stringify(name)}:${written}`);
2188
+ }
2189
+ return { key: parts.join(','), read };
2190
+ }
2191
+ /**
2192
+ * Every formatter's `Intl.NumberFormat`s, by locale and options, so a page of
2193
+ * numbers in one locale and format builds one. Building one is the expensive
2194
+ * part of formatting. Past `MOST_NUMBER_FORMATS`, the one used longest ago
2195
+ * goes, so a server that writes numbers in many locales doesn't keep them
2196
+ * all, and the ones in use stay. A `Map` keeps its keys in the order they
2197
+ * were set, so a formatter is set again each time it's used.
2198
+ */
2199
+ const numberFormats = new Map();
2200
+ const MOST_NUMBER_FORMATS = 200;
2201
+ /** The `Intl.NumberFormat` for `locale` and `options`, built once. */
2202
+ function numberFormatFor(locale, options) {
2203
+ let read;
2204
+ let key = '';
2205
+ if (options !== undefined) {
2206
+ const copy = typeof options === 'object' && options !== null
2207
+ ? readOptions(options)
2208
+ : null;
2209
+ // Options a key can't hold get a formatter of their own, which also
2210
+ // throws what `Intl` throws for them.
2211
+ if (!copy)
2212
+ return new Intl.NumberFormat(locale, options);
2213
+ read = copy.read;
2214
+ key = copy.key;
2215
+ }
2216
+ // A locale tag has no spaces, so the key can't be read two ways.
2217
+ const cacheKey = `${locale ?? ''} ${key}`;
2218
+ let format = numberFormats.get(cacheKey);
2219
+ if (format) {
2220
+ numberFormats.delete(cacheKey);
2221
+ }
2222
+ else {
2223
+ // Built before anything is stored, so options `Intl` refuses throw its
2224
+ // error and leave nothing behind.
2225
+ format = new Intl.NumberFormat(locale, read);
2226
+ if (numberFormats.size >= MOST_NUMBER_FORMATS) {
2227
+ numberFormats.delete(numberFormats.keys().next().value);
2228
+ }
2229
+ }
2230
+ numberFormats.set(cacheKey, format);
2231
+ return format;
2232
+ }
2233
+ /** A function that writes numbers in `locale`, the same one for each locale. */
2234
+ function useFormatIn(locale) {
2235
+ return React.useMemo(() => (value, options) => numberFormatFor(locale, options).format(value), [locale]);
2236
+ }
2237
+ /**
2238
+ * A function that writes numbers for display in a locale: `locale` when given, else the `LocaleProvider`'s around the component, else the runtime's.
2239
+ *
2240
+ * Formatters are kept per locale and set of options, since building one is
2241
+ * the expensive part, and shared, so many numbers written the same way build
2242
+ * one. The function is the same from one render to the next for the same
2243
+ * locale, so it's safe in a dependency array. Use it for text outside JSX,
2244
+ * such as an `aria-label`, a `placeholder` or a chart's axis; in JSX,
2245
+ * `NumberFormatter` also marks the number up. On a server render the
2246
+ * runtime's locale is the server's, so give it a locale, here or through a
2247
+ * `LocaleProvider`, where the server's and the browser's can differ. A tag
2248
+ * `Intl` refuses is ignored, with a warning in development, as
2249
+ * `LocaleProvider` ignores one. Options `Intl` refuses throw its error when
2250
+ * the function is called.
2251
+ *
2252
+ * @function
2253
+ * @param locale - A BCP 47 locale tag, which wins over the provider's.
2254
+ * @returns {NumberFormatFunction} Writes `value` with `Intl.NumberFormat` options.
2069
2255
  *
2070
- * @param own - The component's own locale, such as a picker's `locale`,
2071
- * which wins inside a provider.
2256
+ * @example
2257
+ * const format = useNumberFormat();
2258
+ * const placeholder = format(1500, { style: 'currency', currency: 'EUR' });
2072
2259
  */
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]);
2260
+ function useNumberFormat(locale) {
2261
+ return useFormatIn(useResolvedLocale(locale));
2262
+ }
2263
+ /**
2264
+ * INTERNAL, deliberately not exported from `src/index.ts`. Number formatting
2265
+ * for a component that shows a number in passing, as `useNumberFormat`
2266
+ * writes it in the `LocaleProvider`'s locale, or `null` outside a provider
2267
+ * and inside one that gives no locale, as a provider with only a `dir`
2268
+ * doesn't, where the component keeps the formatting it has always had.
2269
+ */
2270
+ function useScopedNumberFormat() {
2271
+ const scoped = useResolvedLocale(undefined);
2272
+ const format = useFormatIn(scoped);
2273
+ return scoped ? format : null;
2089
2274
  }
2090
2275
  /**
2091
2276
  * A matcher for filtering a list by what was typed, in the locale of the
@@ -2099,7 +2284,7 @@ function useNumberFormat(own) {
2099
2284
  * matches everything.
2100
2285
  */
2101
2286
  function useLocaleMatcher() {
2102
- const locale = useScopedLocale();
2287
+ const locale = useResolvedLocale(undefined);
2103
2288
  return React.useMemo(() => {
2104
2289
  if (!locale)
2105
2290
  return null;
@@ -2160,7 +2345,7 @@ function useLocaleMatcher() {
2160
2345
  */
2161
2346
  const AvatarsComponent = ({ className, max, size, shape, spacing = 'md', spaced = false, surplusLabel, style, children, ...props }) => {
2162
2347
  const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
2163
- const formatNumber = useNumberFormat();
2348
+ const formatNumber = useScopedNumberFormat();
2164
2349
  // A preset spacing maps to a class; a numeric spacing sets the CSS var inline
2165
2350
  // (mirrors Sidebar's inline --bulma-* width var).
2166
2351
  const isPresetSpacing = typeof spacing === 'string';
@@ -2249,7 +2434,7 @@ const Badge = ({ className, badgeClassName, content, max = 99, dot = false, show
2249
2434
  // A negative or non-integer max is nonsensical; fall back to the default
2250
2435
  // rather than render e.g. "-1+" (mirrors Avatars' max sanitization).
2251
2436
  const sanitizedMax = Number.isInteger(max) && max >= 0 ? max : 99;
2252
- const formatNumber = useNumberFormat();
2437
+ const formatNumber = useScopedNumberFormat();
2253
2438
  const displayValue = React.useMemo(() => {
2254
2439
  if (dot || !hasContent)
2255
2440
  return undefined;
@@ -3404,129 +3589,6 @@ const Button = React.forwardRef(function Button(props, ref) {
3404
3589
  });
3405
3590
  Button.displayName = 'Button';
3406
3591
 
3407
- /**
3408
- * The `LinkButton` component renders a `<button>` that visually looks like text or a link.
3409
- *
3410
- * @function
3411
- * @param {LinkButtonProps} props - Props for the LinkButton component.
3412
- * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
3413
- * @returns {JSX.Element} The rendered link-styled button element.
3414
- *
3415
- * @example
3416
- * // Text variant (default)
3417
- * <LinkButton onClick={handleClick}>Click me</LinkButton>
3418
- *
3419
- * @example
3420
- * // Underline variant with color
3421
- * <LinkButton variant="underline" color="primary">Learn more</LinkButton>
3422
- */
3423
- const LinkButton = React.forwardRef(function LinkButton({ variant = 'text', color, className, ...props }, ref) {
3424
- const buttonColor = variant === 'underline' ? 'text' : variant;
3425
- const prefixedClasses = usePrefixedClassNames('link-button', color && `link-button-${color}`, variant === 'underline' && 'link-button-underline');
3426
- return (jsxRuntime.jsx(Button
3427
- // LinkButton is polymorphic through to Button, which resolves the element
3428
- // from `as`. TS cannot infer that through the spread below.
3429
- , {
3430
- // LinkButton is polymorphic through to Button, which resolves the element
3431
- // from `as`. TS cannot infer that through the spread below.
3432
- ref: ref, color: buttonColor, className: classNames(prefixedClasses, className), ...props }));
3433
- });
3434
- LinkButton.displayName = 'LinkButton';
3435
-
3436
- /**
3437
- * The `ToggleButton` component renders a button that stays pressed until it's pressed again, and says whether it's on through `aria-pressed`.
3438
- *
3439
- * It's always a `<button type="button">`, so it never submits a form and
3440
- * carries no form value: a setting saved with a form is a `Checkbox` or a
3441
- * `Switch`. A set of toggles that each turn on and off on their own goes in
3442
- * `Buttons hasAddons` with `role="group"` and an `aria-label`. A set where only
3443
- * one can be on is a radio group rather than a row of these: use
3444
- * `SegmentedControl`, or `Radios` for a choice that's sent with a form.
3445
- *
3446
- * @function
3447
- * @param {ToggleButtonProps} props - Props for the ToggleButton component.
3448
- * @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.
3449
- * @returns {JSX.Element} The rendered toggle button.
3450
- * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/button/ | APG button pattern}
3451
- *
3452
- * @example
3453
- * <ToggleButton onPressedChange={setMuted}>Mute</ToggleButton>
3454
- *
3455
- * @example
3456
- * <Buttons hasAddons role="group" aria-label="Text style">
3457
- * <ToggleButton aria-label="Bold" pressed={bold} onPressedChange={setBold}>
3458
- * <Icon name="bold" />
3459
- * </ToggleButton>
3460
- * </Buttons>
3461
- */
3462
- const ToggleButton = React.forwardRef(function ToggleButton({ pressed: controlledPressed, defaultPressed = false, onPressedChange, color = 'link', isLoading, 'aria-busy': ariaBusy, 'aria-disabled': ariaDisabled, className, onClick, ...props }, ref) {
3463
- const isControlled = controlledPressed !== undefined;
3464
- const [internalPressed, setInternalPressed] = React.useState(defaultPressed);
3465
- const pressed = controlledPressed ?? internalPressed;
3466
- // Prefixed like Button's own classes, which a hand-written
3467
- // `className="is-selected"` could not be under ConfigProvider classPrefix.
3468
- // Bulma lifts `is-selected` above its neighbours in `.buttons.has-addons`.
3469
- const selectedClass = usePrefixedClassNames({ 'is-selected': pressed });
3470
- // The caller's onClick runs first, so a `preventDefault()` there vetoes
3471
- // the toggle, as it does in Radix, MUI and Zag. Enter and Space reach here
3472
- // through the button's own click, and a disabled button gets no click.
3473
- //
3474
- // A loading one gets the click but drops it. Bulma's spinner only stops a
3475
- // pointer, so without this a key flipped a toggle the mouse couldn't.
3476
- // `disabled` would stop both, but it takes focus away mid-save.
3477
- const handleClick = (event) => {
3478
- if (isLoading)
3479
- return;
3480
- onClick?.(event);
3481
- if (event.defaultPrevented)
3482
- return;
3483
- const next = !pressed;
3484
- onPressedChange?.(next);
3485
- if (!isControlled)
3486
- setInternalPressed(next);
3487
- };
3488
- // The props are spread first, so what a toggle depends on wins over
3489
- // anything a JavaScript caller or a spread object passes along: it stays
3490
- // a button, never submits, reports the state it's in, and says it's busy
3491
- // and won't respond while it's loading. A caller's own `aria-busy` or
3492
- // `aria-disabled` stays when it isn't loading.
3493
- return (jsxRuntime.jsx(Button, { ...props, ref: ref, as: "button", type: "button", isLoading: isLoading, "aria-busy": isLoading || ariaBusy, "aria-disabled": isLoading || ariaDisabled, "aria-pressed": pressed, color: pressed ? color : undefined, className: classNames(selectedClass, className), onClick: handleClick }));
3494
- });
3495
- ToggleButton.displayName = 'ToggleButton';
3496
-
3497
- const validButtonsSizes = ['small', 'medium', 'large'];
3498
- /**
3499
- * The `Buttons` component lets you group multiple `Button` elements together with Bulma's spacing, alignment, and add-on features.
3500
- *
3501
- * @function
3502
- * @param {ButtonsProps} props - Props for the Buttons component.
3503
- * @returns {JSX.Element} The rendered group of buttons.
3504
- * @see {@link https://bulma.io/documentation/elements/button/#group | Bulma Button Group documentation}
3505
- */
3506
- const ButtonsComponent = ({ className, textColor, color, bgColor, isCentered, isRight, hasAddons, size, children, ...props }) => {
3507
- const buttonsClasses = usePrefixedClassNames('buttons', {
3508
- 'is-centered': isCentered,
3509
- 'is-right': isRight,
3510
- 'has-addons': hasAddons,
3511
- [`are-${size}`]: size && validButtonsSizes.includes(size),
3512
- });
3513
- /**
3514
- * Generates Bulma helper classes and separates out remaining props.
3515
- */
3516
- const { bulmaHelperClasses, rest } = useBulmaClasses({
3517
- color: textColor ?? color,
3518
- backgroundColor: bgColor,
3519
- ...props,
3520
- });
3521
- const combinedClasses = classNames(buttonsClasses, className, bulmaHelperClasses);
3522
- return (jsxRuntime.jsx("div", { className: combinedClasses, ...rest, children: children }));
3523
- };
3524
- const Buttons = withSubComponents(ButtonsComponent, {
3525
- Button,
3526
- LinkButton,
3527
- ToggleButton,
3528
- }, 'Buttons');
3529
-
3530
3592
  /**
3531
3593
  * Strips a redundant leading library prefix from an icon name (e.g. `fa-check` -> `check`
3532
3594
  * for the `fa` library, `mdi-account` -> `account` for `mdi`), so `name` behaves the same
@@ -3774,6 +3836,231 @@ color, containerClassName, children, ...restProps }) => {
3774
3836
  return (jsxRuntime.jsx("span", { className: iconContainerClasses, ...a11yProps, style: style, ...rest, children: jsxRuntime.jsx("i", { className: iClasses }) }));
3775
3837
  };
3776
3838
 
3839
+ /** Whether a string has something in it besides spaces. */
3840
+ const hasText = (value) => typeof value === 'string' && value.trim() !== '';
3841
+ /** Whether a string is only spaces, which JSX leaves between elements. */
3842
+ const isBlank = (node) => typeof node === 'string' && node.trim() === '';
3843
+ /**
3844
+ * The glyph in one `.icon`, which is what Bulma keeps square: an `<Icon>` as
3845
+ * given, Fragments opened up and blank text left out, and anything else
3846
+ * inside an `Icon`. Null when there's nothing to draw, so an empty Fragment
3847
+ * or array counts as no glyph.
3848
+ */
3849
+ function iconOf(node) {
3850
+ const items = flattenChildren(node).filter(item => !isBlank(item));
3851
+ if (items.length === 0)
3852
+ return null;
3853
+ const [only] = items;
3854
+ if (items.length === 1 && React.isValidElement(only) && only.type === Icon) {
3855
+ return only;
3856
+ }
3857
+ return jsxRuntime.jsx(Icon, { children: items });
3858
+ }
3859
+ /** The glyph `icon` draws: a string is an `Icon` name, the rest as `iconOf`. */
3860
+ function iconFromProp(icon) {
3861
+ if (typeof icon !== 'string')
3862
+ return iconOf(icon);
3863
+ return hasText(icon) ? jsxRuntime.jsx(Icon, { name: icon }) : null;
3864
+ }
3865
+ /**
3866
+ * The `IconButton` component renders a button that shows only an icon, and requires a name for it.
3867
+ *
3868
+ * It renders through `Button`, so it takes everything `Button` takes, and
3869
+ * adds the icon and a name the types require: `aria-label`, or
3870
+ * `aria-labelledby` in its place. Bulma keeps a button whose only child is an
3871
+ * `.icon` square at every size, and `isRounded` makes it a circle. It has no
3872
+ * tooltip of its own: wrap it in `Tooltip` for a description.
3873
+ *
3874
+ * @function
3875
+ * @param {IconButtonProps} props - Props for the IconButton component.
3876
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
3877
+ * @returns {JSX.Element} The rendered button, anchor, or custom element.
3878
+ * @see {@link https://bulma.io/documentation/elements/button/ | Bulma Button documentation}
3879
+ *
3880
+ * @example
3881
+ * <IconButton icon="trash" aria-label="Delete" color="danger" />
3882
+ *
3883
+ * @example
3884
+ * <IconButton aria-label="Settings">
3885
+ * <Icon name="cog" />
3886
+ * </IconButton>
3887
+ */
3888
+ const IconButton = React.forwardRef(function IconButton(props, ref) {
3889
+ const { icon, children, className, ...rest } = props;
3890
+ const iconButtonClass = usePrefixedClassNames('icon-button');
3891
+ const unnamed = !hasText(rest['aria-label']) && !hasText(rest['aria-labelledby']);
3892
+ // Each way of giving the glyph counts only if it draws something, so an
3893
+ // empty Fragment or array as `icon` doesn't hide real children, and an
3894
+ // empty one as children doesn't warn.
3895
+ const fromIcon = iconFromProp(icon);
3896
+ const fromChildren = iconOf(children);
3897
+ const both = fromIcon !== null && fromChildren !== null;
3898
+ // One glyph, from `icon` or else from `children`, so the button's only
3899
+ // child is one `.icon`, which Bulma keeps square, and round with
3900
+ // `isRounded`.
3901
+ const glyph = fromIcon ?? fromChildren;
3902
+ const empty = glyph === null;
3903
+ // Only top-level text, Fragments opened up, and only in development, where
3904
+ // the warning below can say something about it.
3905
+ const textInside = isDev() &&
3906
+ flattenChildren(children).some(child => typeof child === 'number' || hasText(child));
3907
+ React.useEffect(() => {
3908
+ if (unnamed) {
3909
+ warnOnce('IconButton:unnamed', '[bestax-bulma] <IconButton> has no accessible name. Pass ' +
3910
+ 'aria-label naming what it does ("Delete"), or aria-labelledby, ' +
3911
+ 'so a screen reader has something to announce.');
3912
+ }
3913
+ if (empty) {
3914
+ warnOnce('IconButton:no-glyph', '[bestax-bulma] <IconButton> has no glyph: neither icon nor ' +
3915
+ 'children draws one, so it renders an empty square. Pass an icon ' +
3916
+ 'name, an <Icon> or another node.');
3917
+ }
3918
+ if (both) {
3919
+ warnOnce('IconButton:icon-and-children', '[bestax-bulma] <IconButton> was given both icon and children. It ' +
3920
+ 'draws icon and leaves the children out: give the glyph one way.');
3921
+ }
3922
+ if (textInside) {
3923
+ warnOnce('IconButton:text', '[bestax-bulma] <IconButton> was given text as children. Its ' +
3924
+ 'aria-label replaces the text as its name, so a button with text ' +
3925
+ 'is a <Button>.');
3926
+ }
3927
+ }, [unnamed, empty, both, textInside]);
3928
+ // `type` is a button's only on a `<button>`. On an `<a>` it's the MIME hint,
3929
+ // and a custom component owns what it means, so those get it as given.
3930
+ const tag = rest.as ?? 'button';
3931
+ const typeProp = tag === 'button' ? { type: buttonType(rest.type) } : undefined;
3932
+ return (jsxRuntime.jsx(Button
3933
+ // IconButton is polymorphic through to Button, which resolves the
3934
+ // element from `as`. TS can't infer that through the spread, so the
3935
+ // props and the ref are read at Button's default element.
3936
+ , { ...rest, ...typeProp, ref: ref, className: classNames(iconButtonClass, className), children: glyph }));
3937
+ });
3938
+ IconButton.displayName = 'IconButton';
3939
+
3940
+ /**
3941
+ * The `LinkButton` component renders a `<button>` that visually looks like text or a link.
3942
+ *
3943
+ * @function
3944
+ * @param {LinkButtonProps} props - Props for the LinkButton component.
3945
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
3946
+ * @returns {JSX.Element} The rendered link-styled button element.
3947
+ *
3948
+ * @example
3949
+ * // Text variant (default)
3950
+ * <LinkButton onClick={handleClick}>Click me</LinkButton>
3951
+ *
3952
+ * @example
3953
+ * // Underline variant with color
3954
+ * <LinkButton variant="underline" color="primary">Learn more</LinkButton>
3955
+ */
3956
+ const LinkButton = React.forwardRef(function LinkButton({ variant = 'text', color, className, ...props }, ref) {
3957
+ const buttonColor = variant === 'underline' ? 'text' : variant;
3958
+ const prefixedClasses = usePrefixedClassNames('link-button', color && `link-button-${color}`, variant === 'underline' && 'link-button-underline');
3959
+ return (jsxRuntime.jsx(Button
3960
+ // LinkButton is polymorphic through to Button, which resolves the element
3961
+ // from `as`. TS cannot infer that through the spread below.
3962
+ , {
3963
+ // LinkButton is polymorphic through to Button, which resolves the element
3964
+ // from `as`. TS cannot infer that through the spread below.
3965
+ ref: ref, color: buttonColor, className: classNames(prefixedClasses, className), ...props }));
3966
+ });
3967
+ LinkButton.displayName = 'LinkButton';
3968
+
3969
+ /**
3970
+ * The `ToggleButton` component renders a button that stays pressed until it's pressed again, and says whether it's on through `aria-pressed`.
3971
+ *
3972
+ * It's always a `<button type="button">`, so it never submits a form and
3973
+ * carries no form value: a setting saved with a form is a `Checkbox` or a
3974
+ * `Switch`. A set of toggles that each turn on and off on their own goes in
3975
+ * `Buttons hasAddons` with `role="group"` and an `aria-label`. A set where only
3976
+ * one can be on is a radio group rather than a row of these: use
3977
+ * `SegmentedControl`, or `Radios` for a choice that's sent with a form.
3978
+ *
3979
+ * @function
3980
+ * @param {ToggleButtonProps} props - Props for the ToggleButton component.
3981
+ * @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.
3982
+ * @returns {JSX.Element} The rendered toggle button.
3983
+ * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/button/ | APG button pattern}
3984
+ *
3985
+ * @example
3986
+ * <ToggleButton onPressedChange={setMuted}>Mute</ToggleButton>
3987
+ *
3988
+ * @example
3989
+ * <Buttons hasAddons role="group" aria-label="Text style">
3990
+ * <ToggleButton aria-label="Bold" pressed={bold} onPressedChange={setBold}>
3991
+ * <Icon name="bold" />
3992
+ * </ToggleButton>
3993
+ * </Buttons>
3994
+ */
3995
+ const ToggleButton = React.forwardRef(function ToggleButton({ pressed: controlledPressed, defaultPressed = false, onPressedChange, color = 'link', isLoading, 'aria-busy': ariaBusy, 'aria-disabled': ariaDisabled, className, onClick, ...props }, ref) {
3996
+ const isControlled = controlledPressed !== undefined;
3997
+ const [internalPressed, setInternalPressed] = React.useState(defaultPressed);
3998
+ const pressed = controlledPressed ?? internalPressed;
3999
+ // Prefixed like Button's own classes, which a hand-written
4000
+ // `className="is-selected"` could not be under ConfigProvider classPrefix.
4001
+ // Bulma lifts `is-selected` above its neighbours in `.buttons.has-addons`.
4002
+ const selectedClass = usePrefixedClassNames({ 'is-selected': pressed });
4003
+ // The caller's onClick runs first, so a `preventDefault()` there vetoes
4004
+ // the toggle, as it does in Radix, MUI and Zag. Enter and Space reach here
4005
+ // through the button's own click, and a disabled button gets no click.
4006
+ //
4007
+ // A loading one gets the click but drops it. Bulma's spinner only stops a
4008
+ // pointer, so without this a key flipped a toggle the mouse couldn't.
4009
+ // `disabled` would stop both, but it takes focus away mid-save.
4010
+ const handleClick = (event) => {
4011
+ if (isLoading)
4012
+ return;
4013
+ onClick?.(event);
4014
+ if (event.defaultPrevented)
4015
+ return;
4016
+ const next = !pressed;
4017
+ onPressedChange?.(next);
4018
+ if (!isControlled)
4019
+ setInternalPressed(next);
4020
+ };
4021
+ // The props are spread first, so what a toggle depends on wins over
4022
+ // anything a JavaScript caller or a spread object passes along: it stays
4023
+ // a button, never submits, reports the state it's in, and says it's busy
4024
+ // and won't respond while it's loading. A caller's own `aria-busy` or
4025
+ // `aria-disabled` stays when it isn't loading.
4026
+ return (jsxRuntime.jsx(Button, { ...props, ref: ref, as: "button", type: "button", isLoading: isLoading, "aria-busy": isLoading || ariaBusy, "aria-disabled": isLoading || ariaDisabled, "aria-pressed": pressed, color: pressed ? color : undefined, className: classNames(selectedClass, className), onClick: handleClick }));
4027
+ });
4028
+ ToggleButton.displayName = 'ToggleButton';
4029
+
4030
+ const validButtonsSizes = ['small', 'medium', 'large'];
4031
+ /**
4032
+ * The `Buttons` component lets you group multiple `Button` elements together with Bulma's spacing, alignment, and add-on features.
4033
+ *
4034
+ * @function
4035
+ * @param {ButtonsProps} props - Props for the Buttons component.
4036
+ * @returns {JSX.Element} The rendered group of buttons.
4037
+ * @see {@link https://bulma.io/documentation/elements/button/#group | Bulma Button Group documentation}
4038
+ */
4039
+ const ButtonsComponent = ({ className, textColor, color, bgColor, isCentered, isRight, hasAddons, size, children, ...props }) => {
4040
+ const buttonsClasses = usePrefixedClassNames('buttons', {
4041
+ 'is-centered': isCentered,
4042
+ 'is-right': isRight,
4043
+ 'has-addons': hasAddons,
4044
+ [`are-${size}`]: size && validButtonsSizes.includes(size),
4045
+ });
4046
+ /**
4047
+ * Generates Bulma helper classes and separates out remaining props.
4048
+ */
4049
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
4050
+ color: textColor ?? color,
4051
+ backgroundColor: bgColor,
4052
+ ...props,
4053
+ });
4054
+ const combinedClasses = classNames(buttonsClasses, className, bulmaHelperClasses);
4055
+ return (jsxRuntime.jsx("div", { className: combinedClasses, ...rest, children: children }));
4056
+ };
4057
+ const Buttons = withSubComponents(ButtonsComponent, {
4058
+ Button,
4059
+ LinkButton,
4060
+ ToggleButton,
4061
+ IconButton,
4062
+ }, 'Buttons');
4063
+
3777
4064
  /**
3778
4065
  * The `Paragraph` component renders a styled `<p>` element with Bulma helper class integration.
3779
4066
  *
@@ -5699,7 +5986,7 @@ const PaginationComponent = ({ color, textColor, bgColor, size, align, rounded,
5699
5986
  backgroundColor: bgColor,
5700
5987
  ...props,
5701
5988
  });
5702
- const formatNumber = useNumberFormat();
5989
+ const formatNumber = useScopedNumberFormat();
5703
5990
  // Generate Bulma classes with prefix
5704
5991
  const bulmaClasses = usePrefixedClassNames('pagination', {
5705
5992
  [`is-${color}`]: color,
@@ -8453,7 +8740,7 @@ const ContextMenu = withSubComponents(ContextMenuComponent, {
8453
8740
  */
8454
8741
  const Step = ({ isActive = false, isCompleted = false, label, icon, clickable = false, onClick, stepNumber, completedIcon, className, children, ...props }) => {
8455
8742
  const { bulmaHelperClasses, rest } = useBulmaClasses(props);
8456
- const formatNumber = useNumberFormat();
8743
+ const formatNumber = useScopedNumberFormat();
8457
8744
  const stepClasses = classNames(usePrefixedClassNames('steps-segment', {
8458
8745
  'is-active': isActive,
8459
8746
  'is-completed': isCompleted,
@@ -10517,15 +10804,23 @@ const Reveal = RevealImpl;
10517
10804
  Reveal.displayName = 'Reveal';
10518
10805
 
10519
10806
  // INTERNAL: deliberately not exported from src/index.ts.
10807
+ /** The keys and clicks of both checkbox modes, which differ only in what a check reaches. */
10808
+ const CHECKBOX_ACTIONS = {
10809
+ enter: ['open'],
10810
+ space: ['check'],
10811
+ click: ['check'],
10812
+ };
10520
10813
  /**
10521
10814
  * 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.
10815
+ * in #1096, with `checkbox-independent` from #1430. `open` opens or closes a
10816
+ * parent and does nothing on a leaf. A click on the chevron only ever opens
10817
+ * or closes.
10524
10818
  */
10525
10819
  const MODES = {
10526
10820
  none: { enter: ['open'], space: ['open'], click: ['open'] },
10527
10821
  single: { enter: ['select'], space: ['select'], click: ['select', 'open'] },
10528
- checkbox: { enter: ['open'], space: ['check'], click: ['check'] },
10822
+ checkbox: CHECKBOX_ACTIONS,
10823
+ 'checkbox-independent': CHECKBOX_ACTIONS,
10529
10824
  };
10530
10825
  /** Left and Right, swapped for a right-to-left page. */
10531
10826
  const MIRRORED = {
@@ -10666,6 +10961,13 @@ function useControlled(controlled, initial) {
10666
10961
  };
10667
10962
  return [isControlled ? controlled : own, set];
10668
10963
  }
10964
+ /**
10965
+ * The list with `value` added at the end, or, when it's `present`, with
10966
+ * every copy of it taken out. Everything else stays as it was, in its order.
10967
+ */
10968
+ function addedOrRemoved(list, value, present) {
10969
+ return present ? list.filter(v => v !== value) : [...list, value];
10970
+ }
10669
10971
  /**
10670
10972
  * The open state, the selection, the keys, the tab stop, the positions and
10671
10973
  * the registry of a TreeView (#1096). Focus moves for real, with a roving
@@ -10674,10 +10976,12 @@ function useControlled(controlled, initial) {
10674
10976
  * browser (#1171), read off the page once the tree has mounted.
10675
10977
  *
10676
10978
  * 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.
10979
+ * a layout effect. In a `checkbox` tree a closed item's children still
10980
+ * render and register while drawing nothing, so the registry knows every item
10981
+ * and a check reaches all of them. A `checkbox-independent` tree reads each
10982
+ * box off the checked list alone, so a check adds or takes out its own value
10983
+ * and nothing else. The keys read the items on the page, in document order,
10984
+ * each time they need them.
10681
10985
  *
10682
10986
  * @function useTreeView
10683
10987
  * @param options - The TreeView's props.
@@ -10693,9 +10997,15 @@ function useTreeView(options) {
10693
10997
  const [expanded, setExpanded] = useControlled(options.expanded, options.defaultExpanded);
10694
10998
  const [selection, setSelection] = useControlled(options.selected, options.defaultSelected);
10695
10999
  const [checkedList, setChecked] = useControlled(options.checked, options.defaultChecked);
11000
+ // In a `checkbox` tree a check reaches the items under it, by the rules. In
11001
+ // a `checkbox-independent` one each box is its own item's, read off the list.
11002
+ const cascade = mode === 'checkbox';
11003
+ const independent = mode === 'checkbox-independent';
11004
+ // A box on every item, in either checkbox tree.
11005
+ const boxed = cascade || independent;
10696
11006
  // Each is read in its own mode only.
10697
11007
  const selected = mode === 'single' ? selection : null;
10698
- const listed = new Set(mode === 'checkbox' ? checkedList : []);
11008
+ const listed = new Set(boxed ? checkedList : []);
10699
11009
  const treeRef = React.useRef(null);
10700
11010
  const registryRef = React.useRef({
10701
11011
  records: new Map(),
@@ -10716,21 +11026,28 @@ function useTreeView(options) {
10716
11026
  // Each item's place among the items beside it, by its key.
10717
11027
  const [positions, setPositions] = React.useState(NO_POSITIONS);
10718
11028
  const { records } = registryRef.current;
10719
- const checks = mode === 'checkbox'
11029
+ const checks = cascade
10720
11030
  ? // 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
11031
  readChecks(records, listed).states
10722
11032
  : undefined;
10723
11033
  const tabStop = focused ?? (resting === undefined ? selected : resting);
11034
+ // An item's box, decided here alone, so the box drawn, the tab stop and a
11035
+ // toggle agree: off the list in a `checkbox-independent` tree, and by the
11036
+ // rules in a `checkbox` one, where it's `undefined` until the item
11037
+ // registers. `undefined` in a tree with no boxes.
11038
+ const checkOf = (value) => independent ? listed.has(value) : checks?.get(value);
10724
11039
  const isOpen = (value) => expanded.includes(value);
10725
11040
  const stateOf = (value, path, disabled) => {
10726
11041
  if (mode === 'single') {
10727
11042
  return disabled ? {} : { selected: value === selected };
10728
11043
  }
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 };
11044
+ if (boxed) {
11045
+ // Until the items register in a `checkbox` tree, a value stands for
11046
+ // its branch, and a parent can't know it's mixed.
11047
+ return {
11048
+ checked: checkOf(value) ??
11049
+ (listed.has(value) || (!disabled && path.some(v => listed.has(v)))),
11050
+ };
10734
11051
  }
10735
11052
  return {};
10736
11053
  };
@@ -10740,9 +11057,8 @@ function useTreeView(options) {
10740
11057
  };
10741
11058
  const run = {
10742
11059
  open: ({ value, isParent, open }) => {
10743
- if (isParent) {
10744
- changeOpen(open ? expanded.filter(v => v !== value) : [...expanded, value]);
10745
- }
11060
+ if (isParent)
11061
+ changeOpen(addedOrRemoved(expanded, value, open));
10746
11062
  },
10747
11063
  select: ({ value }) => {
10748
11064
  if (value === selected)
@@ -10751,7 +11067,11 @@ function useTreeView(options) {
10751
11067
  options.onSelectedChange?.(value);
10752
11068
  },
10753
11069
  check: ({ value }) => {
10754
- const next = toggledList(records, checkedList, value);
11070
+ // A `checkbox-independent` box is its own item's alone, so its value
11071
+ // comes or goes and the rest of the list stays as it was.
11072
+ const next = independent
11073
+ ? addedOrRemoved(checkedList, value, checkOf(value) === true)
11074
+ : toggledList(records, checkedList, value);
10755
11075
  setChecked(next);
10756
11076
  options.onCheckedChange?.(next);
10757
11077
  },
@@ -10800,7 +11120,7 @@ function useTreeView(options) {
10800
11120
  }
10801
11121
  if (focused !== null && !isShown(focused))
10802
11122
  setFocused(null);
10803
- const preferred = onPage.find(value => value === selected || checks?.get(value) === true);
11123
+ const preferred = onPage.find(value => value === selected || checkOf(value) === true);
10804
11124
  const next = preferred ?? (isShown(resting) ? resting : heir(restingPathRef.current));
10805
11125
  if (next !== resting) {
10806
11126
  setResting(next);
@@ -10939,7 +11259,8 @@ function useTreeView(options) {
10939
11259
  };
10940
11260
  return {
10941
11261
  treeRef,
10942
- rendersClosed: mode === 'checkbox',
11262
+ rendersClosed: cascade,
11263
+ multiselectable: boxed,
10943
11264
  tabStop,
10944
11265
  isOpen,
10945
11266
  stateOf,
@@ -11403,12 +11724,14 @@ const isGiven$1 = (node) => node !== undefined &&
11403
11724
  * and close is `Menu`'s job. The root owns which items are open, through
11404
11725
  * `expanded`, `defaultExpanded` and `onExpandedChange`.
11405
11726
  *
11406
- * `selectionMode` picks one of three trees. With `none`, nothing is picked.
11727
+ * `selectionMode` picks the kind of tree. With `none`, nothing is picked.
11407
11728
  * With `single`, one item is, and `selected` says which. With `checkbox`,
11408
11729
  * each item has a box, a check reaches every enabled item under it, closed
11409
11730
  * 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.
11731
+ * With `checkbox-independent`, each item has a box that checks that item
11732
+ * alone, so a parent means only itself and is never mixed. `selected` is
11733
+ * read in a `single` tree only, and `checked` in the two checkbox trees only.
11734
+ * Selection never follows focus.
11412
11735
  *
11413
11736
  * Disabled items stay reachable from the keys, so a screen reader finds
11414
11737
  * them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a
@@ -11482,7 +11805,7 @@ const TreeViewRoot = React.forwardRef(function TreeView({ children, selectionMod
11482
11805
  // beside the tree, since a tree holds items and groups only, and it's
11483
11806
  // there from the start, so a screen reader is listening to it before
11484
11807
  // 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 })] }));
11808
+ 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
11809
  });
11487
11810
  /**
11488
11811
  * 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 +11899,7 @@ const TreeViewItem = React.forwardRef(function TreeViewItem({ value, label, icon
11576
11899
  });
11577
11900
  if (!tree)
11578
11901
  return null;
11579
- // While it's open the children render in its group. In a checkbox tree
11902
+ // While it's open the children render in its group. In a `checkbox` tree
11580
11903
  // they render while it's closed too, drawing nothing, so a check knows
11581
11904
  // what's under it.
11582
11905
  const items = (open || tree.rendersClosed) && (jsxRuntime.jsx(BranchContext.Provider, { value: childBranch, children: children }));
@@ -13737,7 +14060,7 @@ function useDataTable(options) {
13737
14060
  const prefix = useClassPrefix();
13738
14061
  const { locale } = useLocale();
13739
14062
  const matchText = useLocaleMatcher();
13740
- const formatNumber = useNumberFormat();
14063
+ const formatNumber = useScopedNumberFormat();
13741
14064
  const collator = React.useMemo(() => new Intl.Collator(locale, { numeric: true }), [locale]);
13742
14065
  const pageSize = pageSizeProp !== undefined &&
13743
14066
  Number.isFinite(pageSizeProp) &&
@@ -15184,6 +15507,38 @@ const NotificationContainer = ({ position = 'top-right' }) => {
15184
15507
  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
15508
  };
15186
15509
 
15510
+ /**
15511
+ * 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`.
15512
+ *
15513
+ * It formats with `Intl.NumberFormat`, in its own `locale`, else the
15514
+ * `LocaleProvider`'s around it, else the runtime's, with `format` as the
15515
+ * options. The `<data>` has no role and no class of its own, so a screen
15516
+ * reader reads the formatted text and it takes the look of the text around
15517
+ * it. For text outside JSX, such as an `aria-label`, `useNumberFormat`
15518
+ * gives the same formatting as a function.
15519
+ *
15520
+ * @function
15521
+ * @param {NumberFormatterProps} props - Props for the NumberFormatter component.
15522
+ * @param {React.Ref<HTMLDataElement>} ref - Forwarded ref to the `<data>`.
15523
+ * @returns {JSX.Element} The rendered number.
15524
+ *
15525
+ * @example
15526
+ * <NumberFormatter
15527
+ * value={8456.4}
15528
+ * format={{ style: 'currency', currency: 'USD' }}
15529
+ * />
15530
+ */
15531
+ const NumberFormatter = React.forwardRef(({ className, textColor, bgColor, value, format, locale, ...props }, ref) => {
15532
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
15533
+ color: textColor,
15534
+ backgroundColor: bgColor,
15535
+ ...props,
15536
+ });
15537
+ const formatNumber = useNumberFormat(locale);
15538
+ return (jsxRuntime.jsx("data", { ref: ref, className: classNames(bulmaHelperClasses, className) || undefined, ...rest, value: Object.is(value, -0) ? '-0' : String(value), children: formatNumber(value, format) }));
15539
+ });
15540
+ NumberFormatter.displayName = 'NumberFormatter';
15541
+
15187
15542
  /**
15188
15543
  * The `OrderedList` component renders a styled ordered list (`<ol>`) element with Bulma helper class integration.
15189
15544
  *
@@ -15327,7 +15682,7 @@ const RingProgress = React.forwardRef(({ className, textColor, bgColor, value, m
15327
15682
  const labelClass = usePrefixedClassNames('ring-progress-label');
15328
15683
  // A section's color class, prefixed like the rest.
15329
15684
  const classPrefix = useClassPrefix();
15330
- const formatNumber = useNumberFormat();
15685
+ const formatNumber = useScopedNumberFormat();
15331
15686
  const writeShare = (share) => formatNumber
15332
15687
  ? formatNumber(share / 100, { style: 'percent' })
15333
15688
  : `${share}%`;
@@ -15966,7 +16321,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
15966
16321
  node;
15967
16322
  }
15968
16323
  }, [ref]);
15969
- const formatNumber = useNumberFormat();
16324
+ const formatNumber = useScopedNumberFormat();
15970
16325
  const tokens = acceptTokens(accept);
15971
16326
  const sizeText = (bytes) => formatFileSize(bytes, formatNumber);
15972
16327
  const countText = (count) => formatNumber ? formatNumber(count) : String(count);
@@ -16391,7 +16746,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
16391
16746
  : undefined);
16392
16747
  onChange?.(event);
16393
16748
  };
16394
- const formatNumber = useNumberFormat();
16749
+ const formatNumber = useScopedNumberFormat();
16395
16750
  const pickedText = picked &&
16396
16751
  (picked.count === 1
16397
16752
  ? picked.firstName
@@ -17006,7 +17361,7 @@ const Slider = React.forwardRef((props, ref) => {
17006
17361
  // Scale helper
17007
17362
  const scaleValue = React.useCallback((v) => (scale ? scale(v) : v), [scale]);
17008
17363
  // Format helper: the caller's, else the locale's, else the number as is.
17009
- const formatNumber = useNumberFormat();
17364
+ const formatNumber = useScopedNumberFormat();
17010
17365
  const writeNumber = React.useCallback((v) => (formatNumber ? formatNumber(v) : v.toString()), [formatNumber]);
17011
17366
  const formatValue = React.useCallback((v) => {
17012
17367
  const scaled = scaleValue(v);
@@ -17745,7 +18100,7 @@ const Rate = React.forwardRef(({ label, labelSize, labelProps, horizontal, messa
17745
18100
  callerProps: props,
17746
18101
  });
17747
18102
  const { bulmaHelperClasses, rest } = useBulmaClasses(props);
17748
- const formatNumber = useNumberFormat();
18103
+ const formatNumber = useScopedNumberFormat();
17749
18104
  const starBaseId = React.useId();
17750
18105
  const [internalValue, setInternalValue] = React.useState(defaultValue);
17751
18106
  const [hoverValue, setHoverValue] = React.useState(null);
@@ -18953,7 +19308,7 @@ label, labelSize, labelProps, horizontal, message, messageColor, fieldClassName,
18953
19308
  const { bulmaHelperClasses, rest } = useBulmaClasses(props);
18954
19309
  const { classPrefix } = useConfig();
18955
19310
  const defaultIconLibrary = useIconLibrary();
18956
- const formatNumber = useNumberFormat();
19311
+ const formatNumber = useScopedNumberFormat();
18957
19312
  const matchText = useLocaleMatcher();
18958
19313
  const resolvedLibrary = iconLibraryProp || defaultIconLibrary || 'fa';
18959
19314
  const pcn = (...args) => prefixedClassNames(classPrefix, ...args);
@@ -19770,7 +20125,7 @@ function useColorPicker({ value, defaultValue, onChange, onChangeEnd, format, al
19770
20125
  onChangeEnd?.(nextText);
19771
20126
  }, [disabled, alpha, format, onChange, onChangeEnd, empty]);
19772
20127
  const end = React.useCallback(() => onChangeEnd?.(lastTextRef.current), [onChangeEnd]);
19773
- const formatNumber = useNumberFormat();
20128
+ const formatNumber = useScopedNumberFormat();
19774
20129
  const { isCoarsePointer } = useNativeMobilePicker();
19775
20130
  const merged = mergeColorLabels(labels);
19776
20131
  return {
@@ -26605,6 +26960,63 @@ function ClientOnly({ children, fallback = null }) {
26605
26960
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: typeof children === 'function' ? children() : children });
26606
26961
  }
26607
26962
 
26963
+ /**
26964
+ * The `.stack` element behind Stack, Group, Center and Flex.
26965
+ *
26966
+ * With `as="ul"` or `as="ol"` it renders `role="list"`, which Safari needs:
26967
+ * WebKit stops exposing a list as one once its markers are hidden, and
26968
+ * Bulma's reset hides a `<ul>`'s. Menu.List restates it for the same reason.
26969
+ */
26970
+ const StackLayout = React.forwardRef(function StackLayout({ as = 'div', className, textColor, bgColor,
26971
+ // Not accepted, and taken out before the spread below, where a spread's
26972
+ // `color: undefined`, or a JavaScript caller's `color`, would replace
26973
+ // `textColor`, as `backgroundColor` would `bgColor`.
26974
+ color: _color, backgroundColor: _backgroundColor, modifiers, children, ...props }, ref) {
26975
+ // The partial makes the element a flex container, so the container
26976
+ // helpers (alignItems and the rest) apply without a `display` prop.
26977
+ const { bulmaHelperClasses, rest } = useBulmaClasses({ color: textColor, backgroundColor: bgColor, ...props }, { flexContainer: true });
26978
+ const stackClasses = usePrefixedClassNames('stack', modifiers);
26979
+ const Component = as;
26980
+ const isList = as === 'ul' || as === 'ol';
26981
+ return (jsxRuntime.jsx(Component, { ref: ref, className: classNames(stackClasses, bulmaHelperClasses, className), ...rest, ...(isList ? { role: rest.role || 'list' } : {}), children: children }));
26982
+ });
26983
+
26984
+ /**
26985
+ * The `Center` component centers its content on both axes.
26986
+ *
26987
+ * Use it for a loader, an icon or an empty state in the middle of a box, a
26988
+ * card or a section. Give it a height, or put it in something that has one,
26989
+ * to center down the middle as well as across. Several children sit side by
26990
+ * side in the middle, with no gap unless you set one.
26991
+ *
26992
+ * @function
26993
+ * @param {CenterProps} props - Props for the Center component.
26994
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
26995
+ * @returns {JSX.Element} The rendered center.
26996
+ *
26997
+ * @example
26998
+ * <Center p="6">
26999
+ * <Loader />
27000
+ * </Center>
27001
+ */
27002
+ const Center = React.forwardRef(function Center(props, ref) {
27003
+ return (jsxRuntime.jsx(StackLayout, { ref: ref, ...props,
27004
+ // Centered both ways, in the children's own order.
27005
+ flexDirection: undefined, modifiers: { 'is-centered': true } }));
27006
+ });
27007
+ Center.displayName = 'Center';
27008
+
27009
+ // INTERNAL: not exported from src/index.ts, which re-exports Container's
27010
+ // module whole, so this list lives here rather than beside the type.
27011
+ //
27012
+ // Every value `ContainerBreakpoint` takes, in one list, so Container's and
27013
+ // Group's checks of a JavaScript caller's `breakpoint` can't drift apart.
27014
+ const CONTAINER_BREAKPOINTS = [
27015
+ 'tablet',
27016
+ 'desktop',
27017
+ 'widescreen',
27018
+ ];
27019
+
26608
27020
  /**
26609
27021
  * The `Container` component provides a responsive and flexible layout wrapper for your Bulma React UI.
26610
27022
  *
@@ -26620,14 +27032,9 @@ const Container = ({ as: Tag = 'div', className, textColor, color, bgColor, flui
26620
27032
  ...props,
26621
27033
  });
26622
27034
  // Only allow isMax for supported breakpoints
26623
- const validMaxBreakpoints = [
26624
- 'tablet',
26625
- 'desktop',
26626
- 'widescreen',
26627
- ];
26628
27035
  let breakpointClass;
26629
27036
  if (breakpoint) {
26630
- if (isMax && validMaxBreakpoints.includes(breakpoint)) {
27037
+ if (isMax && CONTAINER_BREAKPOINTS.includes(breakpoint)) {
26631
27038
  breakpointClass = `is-max-${breakpoint}`;
26632
27039
  }
26633
27040
  else if (!isMax) {
@@ -26645,6 +27052,32 @@ const Container = ({ as: Tag = 'div', className, textColor, color, bgColor, flui
26645
27052
  return (jsxRuntime.jsx(Tag, { className: containerClasses, style: mergeBulmaStyles(bulmaHelperStyles, style), ...rest, children: children }));
26646
27053
  };
26647
27054
 
27055
+ /**
27056
+ * The `Flex` component is a flex container with CSS's own defaults, taking the flex container's properties as props.
27057
+ *
27058
+ * It's a row that doesn't wrap, with its children stretched across it and no
27059
+ * gap, until you set otherwise. Use it for a layout of your own, such as a
27060
+ * fixed side beside a growing one, with `flexGrow` and `flexShrink` on the
27061
+ * children. Its children's own block margins are zeroed, so the gap is the
27062
+ * only space. For a column of blocks or a row of controls with Bulma's
27063
+ * spacing already in place, `Stack` and `Group` start closer.
27064
+ *
27065
+ * @function
27066
+ * @param {FlexProps} props - Props for the Flex component.
27067
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
27068
+ * @returns {JSX.Element} The rendered flex container.
27069
+ *
27070
+ * @example
27071
+ * <Flex gap="4" alignItems="flex-start">
27072
+ * <Box flexShrink="0">…</Box>
27073
+ * <Box flexGrow="1">…</Box>
27074
+ * </Flex>
27075
+ */
27076
+ const Flex = React.forwardRef(function Flex(props, ref) {
27077
+ return jsxRuntime.jsx(StackLayout, { ref: ref, ...props });
27078
+ });
27079
+ Flex.displayName = 'Flex';
27080
+
26648
27081
  /**
26649
27082
  * The `Footer` component provides a semantic and accessible site footer for your Bulma React UI.
26650
27083
  *
@@ -26670,6 +27103,40 @@ const Footer = ({ as = 'footer', className, children, color, bgColor, textColor,
26670
27103
  return (jsxRuntime.jsx(Tag, { className: footerClasses, style: mergeBulmaStyles(bulmaHelperStyles, style), ...rest, children: children }));
26671
27104
  };
26672
27105
 
27106
+ /**
27107
+ * The `Group` component lays its children out in a row that wraps, centered on each other, with half of Bulma's block spacing between them.
27108
+ *
27109
+ * Use it for a row of buttons, tags or avatars beside some text, or a toolbar
27110
+ * with `justifyContent="space-between"` pushing its ends apart. The children's
27111
+ * own block margins are zeroed, so the gap is the only space. With
27112
+ * `breakpoint`, it's a column on narrow screens and a row from that
27113
+ * breakpoint up. For controls joined into one, with no gap and shared
27114
+ * borders, use `hasAddons` on Field or Buttons instead.
27115
+ *
27116
+ * @function
27117
+ * @param {GroupProps} props - Props for the Group component.
27118
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
27119
+ * @returns {JSX.Element} The rendered group.
27120
+ *
27121
+ * @example
27122
+ * <Group justifyContent="space-between">
27123
+ * <Title as="h2" size="4">Invoices</Title>
27124
+ * <Button color="primary">New invoice</Button>
27125
+ * </Group>
27126
+ */
27127
+ const Group = React.forwardRef(function Group(props, ref) {
27128
+ const { isFullwidth, breakpoint, ...rest } = props;
27129
+ return (jsxRuntime.jsx(StackLayout, { ref: ref, ...rest,
27130
+ // A row always, or a column below `breakpoint`: never reversed, so
27131
+ // reading and Tab order follow what's seen.
27132
+ flexDirection: undefined, modifiers: {
27133
+ 'is-horizontal': true,
27134
+ 'is-fullwidth': isFullwidth,
27135
+ [`is-${breakpoint}`]: !!breakpoint && CONTAINER_BREAKPOINTS.includes(breakpoint),
27136
+ } }));
27137
+ });
27138
+ Group.displayName = 'Group';
27139
+
26673
27140
  /**
26674
27141
  * The `Hero` component provides a responsive, flexible, and visually striking section for your Bulma React UI.
26675
27142
  *
@@ -27475,6 +27942,32 @@ const Splitter = withSubComponents(SplitterRoot, {
27475
27942
  Pane: SplitterPane,
27476
27943
  });
27477
27944
 
27945
+ /**
27946
+ * The `Stack` component lays its children out in a column, with Bulma's block spacing between them and the margins Bulma gives them zeroed.
27947
+ *
27948
+ * A Stack of Boxes, Cards or Notifications looks like Bulma's own stacked
27949
+ * blocks, spaced by the gap alone, so there are no margins to undo. A `gap`
27950
+ * step replaces the default spacing. It's always a column, top to bottom.
27951
+ *
27952
+ * @function
27953
+ * @param {StackProps} props - Props for the Stack component.
27954
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
27955
+ * @returns {JSX.Element} The rendered stack.
27956
+ *
27957
+ * @example
27958
+ * <Stack>
27959
+ * <Notification color="info">Your changes are saved.</Notification>
27960
+ * <Box>…</Box>
27961
+ * </Stack>
27962
+ */
27963
+ const Stack = React.forwardRef(function Stack(props, ref) {
27964
+ return (jsxRuntime.jsx(StackLayout, { ref: ref, ...props,
27965
+ // A column always: reading and Tab order follow the children's order,
27966
+ // and a reversed column would show them in another.
27967
+ flexDirection: undefined, modifiers: { 'is-vertical': true } }));
27968
+ });
27969
+ Stack.displayName = 'Stack';
27970
+
27478
27971
  exports.Autocomplete = Autocomplete;
27479
27972
  exports.Avatar = Avatar;
27480
27973
  exports.Avatars = Avatars;
@@ -27488,6 +27981,7 @@ exports.Card = Card;
27488
27981
  exports.Carousel = Carousel;
27489
27982
  exports.CarouselItem = CarouselItem;
27490
27983
  exports.Cell = Cell;
27984
+ exports.Center = Center;
27491
27985
  exports.Checkbox = Checkbox;
27492
27986
  exports.CheckboxCard = CheckboxCard;
27493
27987
  exports.Checkboxes = Checkboxes;
@@ -27556,14 +28050,17 @@ exports.FieldLabel = FieldLabel;
27556
28050
  exports.Fieldset = Fieldset;
27557
28051
  exports.Figure = Figure;
27558
28052
  exports.File = File;
28053
+ exports.Flex = Flex;
27559
28054
  exports.Footer = Footer;
27560
28055
  exports.Grid = Grid;
28056
+ exports.Group = Group;
27561
28057
  exports.Hero = Hero;
27562
28058
  exports.HeroBody = HeroBody;
27563
28059
  exports.HeroFoot = HeroFoot;
27564
28060
  exports.HeroHead = HeroHead;
27565
28061
  exports.HoverCard = HoverCard;
27566
28062
  exports.Icon = Icon;
28063
+ exports.IconButton = IconButton;
27567
28064
  exports.IconText = IconText;
27568
28065
  exports.Image = Image;
27569
28066
  exports.Input = Input;
@@ -27604,6 +28101,7 @@ exports.NavbarMenu = NavbarMenu;
27604
28101
  exports.NavbarStart = NavbarStart;
27605
28102
  exports.Notification = Notification;
27606
28103
  exports.NotificationContainer = NotificationContainer;
28104
+ exports.NumberFormatter = NumberFormatter;
27607
28105
  exports.NumberInput = NumberInput;
27608
28106
  exports.Numberinput = Numberinput;
27609
28107
  exports.OrderedList = OrderedList;
@@ -27648,6 +28146,7 @@ exports.Slider = Slider;
27648
28146
  exports.Span = Span;
27649
28147
  exports.Splitter = Splitter;
27650
28148
  exports.SplitterPane = SplitterPane;
28149
+ exports.Stack = Stack;
27651
28150
  exports.Step = Step;
27652
28151
  exports.Steps = Steps;
27653
28152
  exports.Strong = Strong;
@@ -27712,6 +28211,7 @@ exports.useInsideControl = useInsideControl;
27712
28211
  exports.useInsideField = useInsideField;
27713
28212
  exports.useIsHydrated = useIsHydrated;
27714
28213
  exports.useLocale = useLocale;
28214
+ exports.useNumberFormat = useNumberFormat;
27715
28215
  exports.useOtherClasses = useOtherClasses;
27716
28216
  exports.usePrefixedClass = usePrefixedClass;
27717
28217
  exports.usePrefixedClassNames = usePrefixedClassNames;