@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.
- package/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/components/Avatars.js +2 -2
- package/dist/esm/components/Avatars.js.map +1 -1
- package/dist/esm/components/Badge.js +2 -2
- package/dist/esm/components/Badge.js.map +1 -1
- package/dist/esm/components/Pagination.js +2 -2
- package/dist/esm/components/Pagination.js.map +1 -1
- package/dist/esm/components/Steps.js +2 -2
- package/dist/esm/components/Steps.js.map +1 -1
- package/dist/esm/components/TreeView.js +7 -5
- package/dist/esm/components/TreeView.js.map +1 -1
- package/dist/esm/components/useDataTable.js +2 -2
- package/dist/esm/components/useDataTable.js.map +1 -1
- package/dist/esm/elements/Buttons.js +2 -0
- package/dist/esm/elements/Buttons.js.map +1 -1
- package/dist/esm/elements/IconButton.js +114 -0
- package/dist/esm/elements/IconButton.js.map +1 -0
- package/dist/esm/elements/NumberFormatter.js +42 -0
- package/dist/esm/elements/NumberFormatter.js.map +1 -0
- package/dist/esm/elements/RingProgress.js +2 -2
- package/dist/esm/elements/RingProgress.js.map +1 -1
- package/dist/esm/form/Dropzone.js +2 -2
- package/dist/esm/form/Dropzone.js.map +1 -1
- package/dist/esm/form/File.js +2 -2
- package/dist/esm/form/File.js.map +1 -1
- package/dist/esm/form/Rate.js +2 -2
- package/dist/esm/form/Rate.js.map +1 -1
- package/dist/esm/form/Slider.js +2 -2
- package/dist/esm/form/Slider.js.map +1 -1
- package/dist/esm/form/Taginput.js +2 -2
- package/dist/esm/form/Taginput.js.map +1 -1
- package/dist/esm/form/_colorInternals/pickerState.js +2 -2
- package/dist/esm/form/_colorInternals/pickerState.js.map +1 -1
- package/dist/esm/helpers/LocaleProvider.js +13 -6
- package/dist/esm/helpers/LocaleProvider.js.map +1 -1
- package/dist/esm/helpers/containerBreakpoints.js +14 -0
- package/dist/esm/helpers/containerBreakpoints.js.map +1 -0
- package/dist/esm/helpers/localeFormat.js +196 -36
- package/dist/esm/helpers/localeFormat.js.map +1 -1
- package/dist/esm/helpers/polymorphic.js.map +1 -1
- package/dist/esm/helpers/stackLayout.js +30 -0
- package/dist/esm/helpers/stackLayout.js.map +1 -0
- package/dist/esm/helpers/useBulmaClasses.js +8 -2
- package/dist/esm/helpers/useBulmaClasses.js.map +1 -1
- package/dist/esm/helpers/useFlexboxClasses.js +17 -4
- package/dist/esm/helpers/useFlexboxClasses.js.map +1 -1
- package/dist/esm/helpers/useTreeView.js +54 -20
- package/dist/esm/helpers/useTreeView.js.map +1 -1
- package/dist/esm/layout/Center.js +33 -0
- package/dist/esm/layout/Center.js.map +1 -0
- package/dist/esm/layout/Container.js +2 -6
- package/dist/esm/layout/Container.js.map +1 -1
- package/dist/esm/layout/Flex.js +34 -0
- package/dist/esm/layout/Flex.js.map +1 -0
- package/dist/esm/layout/Group.js +43 -0
- package/dist/esm/layout/Group.js.map +1 -0
- package/dist/esm/layout/Stack.js +34 -0
- package/dist/esm/layout/Stack.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +712 -212
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +7 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/TreeView.d.ts +20 -11
- package/dist/types/elements/Buttons.d.ts +1 -0
- package/dist/types/elements/IconButton.d.ts +110 -0
- package/dist/types/elements/NumberFormatter.d.ts +62 -0
- package/dist/types/helpers/LocaleProvider.d.ts +7 -0
- package/dist/types/helpers/containerBreakpoints.d.ts +2 -0
- package/dist/types/helpers/localeFormat.d.ts +30 -8
- package/dist/types/helpers/polymorphic.d.ts +19 -0
- package/dist/types/helpers/stackLayout.d.ts +62 -0
- package/dist/types/helpers/useBulmaClasses.d.ts +8 -2
- package/dist/types/helpers/useFlexboxClasses.d.ts +26 -3
- package/dist/types/helpers/useTreeView.d.ts +12 -6
- package/dist/types/index.d.ts +10 -1
- package/dist/types/layout/Center.d.ts +54 -0
- package/dist/types/layout/Flex.d.ts +92 -0
- package/dist/types/layout/Group.d.ts +86 -0
- package/dist/types/layout/Stack.d.ts +63 -0
- package/dist/types-cjs/components/TreeView.d.ts +20 -11
- package/dist/types-cjs/elements/Buttons.d.ts +1 -0
- package/dist/types-cjs/elements/IconButton.d.ts +110 -0
- package/dist/types-cjs/elements/NumberFormatter.d.ts +62 -0
- package/dist/types-cjs/helpers/LocaleProvider.d.ts +7 -0
- package/dist/types-cjs/helpers/containerBreakpoints.d.ts +2 -0
- package/dist/types-cjs/helpers/localeFormat.d.ts +30 -8
- package/dist/types-cjs/helpers/polymorphic.d.ts +19 -0
- package/dist/types-cjs/helpers/stackLayout.d.ts +62 -0
- package/dist/types-cjs/helpers/useBulmaClasses.d.ts +8 -2
- package/dist/types-cjs/helpers/useFlexboxClasses.d.ts +26 -3
- package/dist/types-cjs/helpers/useTreeView.d.ts +12 -6
- package/dist/types-cjs/index.d.ts +10 -1
- package/dist/types-cjs/layout/Center.d.ts +54 -0
- package/dist/types-cjs/layout/Flex.d.ts +92 -0
- package/dist/types-cjs/layout/Group.d.ts +86 -0
- package/dist/types-cjs/layout/Stack.d.ts +63 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +1 -1
- package/src/scss/elements/_iconbutton.scss +36 -0
- package/src/scss/elements/_index.scss +1 -0
- package/src/scss/layout/_index.scss +1 -0
- 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
|
|
974
|
-
*
|
|
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
|
-
|
|
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 =
|
|
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
|
-
/**
|
|
1905
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
2048
|
-
//
|
|
2049
|
-
//
|
|
2050
|
-
//
|
|
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
|
|
2055
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
2061
|
-
|
|
2062
|
-
return scope.locale;
|
|
2105
|
+
const valid = React.useMemo(() => validLocale(own, warnOwnLocale), [own]);
|
|
2106
|
+
return valid || scope?.locale;
|
|
2063
2107
|
}
|
|
2064
2108
|
/**
|
|
2065
|
-
*
|
|
2066
|
-
*
|
|
2067
|
-
|
|
2068
|
-
|
|
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
|
-
* @
|
|
2071
|
-
*
|
|
2256
|
+
* @example
|
|
2257
|
+
* const format = useNumberFormat();
|
|
2258
|
+
* const placeholder = format(1500, { style: 'currency', currency: 'EUR' });
|
|
2072
2259
|
*/
|
|
2073
|
-
function useNumberFormat(
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
10523
|
-
* click on the chevron only ever opens
|
|
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:
|
|
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
|
|
10678
|
-
* and register while drawing nothing, so the registry knows every item
|
|
10679
|
-
* check reaches all of them.
|
|
10680
|
-
*
|
|
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(
|
|
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 =
|
|
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 (
|
|
10730
|
-
// Until the items register, a value stands for
|
|
10731
|
-
// parent can't know it's mixed.
|
|
10732
|
-
|
|
10733
|
-
|
|
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(
|
|
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
|
-
|
|
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 ||
|
|
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:
|
|
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
|
|
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
|
-
* `
|
|
11411
|
-
*
|
|
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.
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 &&
|
|
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;
|