@allxsmith/bestax-bulma 5.58.0 → 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 (68) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/elements/Buttons.js +2 -0
  4. package/dist/esm/elements/Buttons.js.map +1 -1
  5. package/dist/esm/elements/IconButton.js +114 -0
  6. package/dist/esm/elements/IconButton.js.map +1 -0
  7. package/dist/esm/helpers/containerBreakpoints.js +14 -0
  8. package/dist/esm/helpers/containerBreakpoints.js.map +1 -0
  9. package/dist/esm/helpers/polymorphic.js.map +1 -1
  10. package/dist/esm/helpers/stackLayout.js +30 -0
  11. package/dist/esm/helpers/stackLayout.js.map +1 -0
  12. package/dist/esm/helpers/useBulmaClasses.js +8 -2
  13. package/dist/esm/helpers/useBulmaClasses.js.map +1 -1
  14. package/dist/esm/helpers/useFlexboxClasses.js +17 -4
  15. package/dist/esm/helpers/useFlexboxClasses.js.map +1 -1
  16. package/dist/esm/layout/Center.js +33 -0
  17. package/dist/esm/layout/Center.js.map +1 -0
  18. package/dist/esm/layout/Container.js +2 -6
  19. package/dist/esm/layout/Container.js.map +1 -1
  20. package/dist/esm/layout/Flex.js +34 -0
  21. package/dist/esm/layout/Flex.js.map +1 -0
  22. package/dist/esm/layout/Group.js +43 -0
  23. package/dist/esm/layout/Group.js.map +1 -0
  24. package/dist/esm/layout/Stack.js +34 -0
  25. package/dist/esm/layout/Stack.js.map +1 -0
  26. package/dist/extras.css +1 -1
  27. package/dist/extras.css.map +1 -1
  28. package/dist/index.cjs +400 -136
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.esm.js +5 -0
  31. package/dist/index.esm.js.map +1 -1
  32. package/dist/types/elements/Buttons.d.ts +1 -0
  33. package/dist/types/elements/IconButton.d.ts +110 -0
  34. package/dist/types/helpers/containerBreakpoints.d.ts +2 -0
  35. package/dist/types/helpers/polymorphic.d.ts +19 -0
  36. package/dist/types/helpers/stackLayout.d.ts +62 -0
  37. package/dist/types/helpers/useBulmaClasses.d.ts +8 -2
  38. package/dist/types/helpers/useFlexboxClasses.d.ts +26 -3
  39. package/dist/types/index.d.ts +7 -1
  40. package/dist/types/layout/Center.d.ts +54 -0
  41. package/dist/types/layout/Flex.d.ts +92 -0
  42. package/dist/types/layout/Group.d.ts +86 -0
  43. package/dist/types/layout/Stack.d.ts +63 -0
  44. package/dist/types-cjs/elements/Buttons.d.ts +1 -0
  45. package/dist/types-cjs/elements/IconButton.d.ts +110 -0
  46. package/dist/types-cjs/helpers/containerBreakpoints.d.ts +2 -0
  47. package/dist/types-cjs/helpers/polymorphic.d.ts +19 -0
  48. package/dist/types-cjs/helpers/stackLayout.d.ts +62 -0
  49. package/dist/types-cjs/helpers/useBulmaClasses.d.ts +8 -2
  50. package/dist/types-cjs/helpers/useFlexboxClasses.d.ts +26 -3
  51. package/dist/types-cjs/index.d.ts +7 -1
  52. package/dist/types-cjs/layout/Center.d.ts +54 -0
  53. package/dist/types-cjs/layout/Flex.d.ts +92 -0
  54. package/dist/types-cjs/layout/Group.d.ts +86 -0
  55. package/dist/types-cjs/layout/Stack.d.ts +63 -0
  56. package/dist/versions/bestax-no-dark-mode.css +1 -1
  57. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  58. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  59. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  60. package/dist/versions/bestax-no-helpers.css +1 -1
  61. package/dist/versions/bestax-no-helpers.css.map +1 -1
  62. package/dist/versions/bestax-prefixed.css +1 -1
  63. package/dist/versions/bestax-prefixed.css.map +1 -1
  64. package/package.json +1 -1
  65. package/src/scss/elements/_iconbutton.scss +36 -0
  66. package/src/scss/elements/_index.scss +1 -0
  67. package/src/scss/layout/_index.scss +1 -0
  68. 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,
@@ -3570,129 +3589,6 @@ const Button = React.forwardRef(function Button(props, ref) {
3570
3589
  });
3571
3590
  Button.displayName = 'Button';
3572
3591
 
3573
- /**
3574
- * The `LinkButton` component renders a `<button>` that visually looks like text or a link.
3575
- *
3576
- * @function
3577
- * @param {LinkButtonProps} props - Props for the LinkButton component.
3578
- * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
3579
- * @returns {JSX.Element} The rendered link-styled button element.
3580
- *
3581
- * @example
3582
- * // Text variant (default)
3583
- * <LinkButton onClick={handleClick}>Click me</LinkButton>
3584
- *
3585
- * @example
3586
- * // Underline variant with color
3587
- * <LinkButton variant="underline" color="primary">Learn more</LinkButton>
3588
- */
3589
- const LinkButton = React.forwardRef(function LinkButton({ variant = 'text', color, className, ...props }, ref) {
3590
- const buttonColor = variant === 'underline' ? 'text' : variant;
3591
- const prefixedClasses = usePrefixedClassNames('link-button', color && `link-button-${color}`, variant === 'underline' && 'link-button-underline');
3592
- return (jsxRuntime.jsx(Button
3593
- // LinkButton is polymorphic through to Button, which resolves the element
3594
- // from `as`. TS cannot infer that through the spread below.
3595
- , {
3596
- // LinkButton is polymorphic through to Button, which resolves the element
3597
- // from `as`. TS cannot infer that through the spread below.
3598
- ref: ref, color: buttonColor, className: classNames(prefixedClasses, className), ...props }));
3599
- });
3600
- LinkButton.displayName = 'LinkButton';
3601
-
3602
- /**
3603
- * The `ToggleButton` component renders a button that stays pressed until it's pressed again, and says whether it's on through `aria-pressed`.
3604
- *
3605
- * It's always a `<button type="button">`, so it never submits a form and
3606
- * carries no form value: a setting saved with a form is a `Checkbox` or a
3607
- * `Switch`. A set of toggles that each turn on and off on their own goes in
3608
- * `Buttons hasAddons` with `role="group"` and an `aria-label`. A set where only
3609
- * one can be on is a radio group rather than a row of these: use
3610
- * `SegmentedControl`, or `Radios` for a choice that's sent with a form.
3611
- *
3612
- * @function
3613
- * @param {ToggleButtonProps} props - Props for the ToggleButton component.
3614
- * @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.
3615
- * @returns {JSX.Element} The rendered toggle button.
3616
- * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/button/ | APG button pattern}
3617
- *
3618
- * @example
3619
- * <ToggleButton onPressedChange={setMuted}>Mute</ToggleButton>
3620
- *
3621
- * @example
3622
- * <Buttons hasAddons role="group" aria-label="Text style">
3623
- * <ToggleButton aria-label="Bold" pressed={bold} onPressedChange={setBold}>
3624
- * <Icon name="bold" />
3625
- * </ToggleButton>
3626
- * </Buttons>
3627
- */
3628
- const ToggleButton = React.forwardRef(function ToggleButton({ pressed: controlledPressed, defaultPressed = false, onPressedChange, color = 'link', isLoading, 'aria-busy': ariaBusy, 'aria-disabled': ariaDisabled, className, onClick, ...props }, ref) {
3629
- const isControlled = controlledPressed !== undefined;
3630
- const [internalPressed, setInternalPressed] = React.useState(defaultPressed);
3631
- const pressed = controlledPressed ?? internalPressed;
3632
- // Prefixed like Button's own classes, which a hand-written
3633
- // `className="is-selected"` could not be under ConfigProvider classPrefix.
3634
- // Bulma lifts `is-selected` above its neighbours in `.buttons.has-addons`.
3635
- const selectedClass = usePrefixedClassNames({ 'is-selected': pressed });
3636
- // The caller's onClick runs first, so a `preventDefault()` there vetoes
3637
- // the toggle, as it does in Radix, MUI and Zag. Enter and Space reach here
3638
- // through the button's own click, and a disabled button gets no click.
3639
- //
3640
- // A loading one gets the click but drops it. Bulma's spinner only stops a
3641
- // pointer, so without this a key flipped a toggle the mouse couldn't.
3642
- // `disabled` would stop both, but it takes focus away mid-save.
3643
- const handleClick = (event) => {
3644
- if (isLoading)
3645
- return;
3646
- onClick?.(event);
3647
- if (event.defaultPrevented)
3648
- return;
3649
- const next = !pressed;
3650
- onPressedChange?.(next);
3651
- if (!isControlled)
3652
- setInternalPressed(next);
3653
- };
3654
- // The props are spread first, so what a toggle depends on wins over
3655
- // anything a JavaScript caller or a spread object passes along: it stays
3656
- // a button, never submits, reports the state it's in, and says it's busy
3657
- // and won't respond while it's loading. A caller's own `aria-busy` or
3658
- // `aria-disabled` stays when it isn't loading.
3659
- 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 }));
3660
- });
3661
- ToggleButton.displayName = 'ToggleButton';
3662
-
3663
- const validButtonsSizes = ['small', 'medium', 'large'];
3664
- /**
3665
- * The `Buttons` component lets you group multiple `Button` elements together with Bulma's spacing, alignment, and add-on features.
3666
- *
3667
- * @function
3668
- * @param {ButtonsProps} props - Props for the Buttons component.
3669
- * @returns {JSX.Element} The rendered group of buttons.
3670
- * @see {@link https://bulma.io/documentation/elements/button/#group | Bulma Button Group documentation}
3671
- */
3672
- const ButtonsComponent = ({ className, textColor, color, bgColor, isCentered, isRight, hasAddons, size, children, ...props }) => {
3673
- const buttonsClasses = usePrefixedClassNames('buttons', {
3674
- 'is-centered': isCentered,
3675
- 'is-right': isRight,
3676
- 'has-addons': hasAddons,
3677
- [`are-${size}`]: size && validButtonsSizes.includes(size),
3678
- });
3679
- /**
3680
- * Generates Bulma helper classes and separates out remaining props.
3681
- */
3682
- const { bulmaHelperClasses, rest } = useBulmaClasses({
3683
- color: textColor ?? color,
3684
- backgroundColor: bgColor,
3685
- ...props,
3686
- });
3687
- const combinedClasses = classNames(buttonsClasses, className, bulmaHelperClasses);
3688
- return (jsxRuntime.jsx("div", { className: combinedClasses, ...rest, children: children }));
3689
- };
3690
- const Buttons = withSubComponents(ButtonsComponent, {
3691
- Button,
3692
- LinkButton,
3693
- ToggleButton,
3694
- }, 'Buttons');
3695
-
3696
3592
  /**
3697
3593
  * Strips a redundant leading library prefix from an icon name (e.g. `fa-check` -> `check`
3698
3594
  * for the `fa` library, `mdi-account` -> `account` for `mdi`), so `name` behaves the same
@@ -3940,6 +3836,231 @@ color, containerClassName, children, ...restProps }) => {
3940
3836
  return (jsxRuntime.jsx("span", { className: iconContainerClasses, ...a11yProps, style: style, ...rest, children: jsxRuntime.jsx("i", { className: iClasses }) }));
3941
3837
  };
3942
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
+
3943
4064
  /**
3944
4065
  * The `Paragraph` component renders a styled `<p>` element with Bulma helper class integration.
3945
4066
  *
@@ -26839,6 +26960,63 @@ function ClientOnly({ children, fallback = null }) {
26839
26960
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: typeof children === 'function' ? children() : children });
26840
26961
  }
26841
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
+
26842
27020
  /**
26843
27021
  * The `Container` component provides a responsive and flexible layout wrapper for your Bulma React UI.
26844
27022
  *
@@ -26854,14 +27032,9 @@ const Container = ({ as: Tag = 'div', className, textColor, color, bgColor, flui
26854
27032
  ...props,
26855
27033
  });
26856
27034
  // Only allow isMax for supported breakpoints
26857
- const validMaxBreakpoints = [
26858
- 'tablet',
26859
- 'desktop',
26860
- 'widescreen',
26861
- ];
26862
27035
  let breakpointClass;
26863
27036
  if (breakpoint) {
26864
- if (isMax && validMaxBreakpoints.includes(breakpoint)) {
27037
+ if (isMax && CONTAINER_BREAKPOINTS.includes(breakpoint)) {
26865
27038
  breakpointClass = `is-max-${breakpoint}`;
26866
27039
  }
26867
27040
  else if (!isMax) {
@@ -26879,6 +27052,32 @@ const Container = ({ as: Tag = 'div', className, textColor, color, bgColor, flui
26879
27052
  return (jsxRuntime.jsx(Tag, { className: containerClasses, style: mergeBulmaStyles(bulmaHelperStyles, style), ...rest, children: children }));
26880
27053
  };
26881
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
+
26882
27081
  /**
26883
27082
  * The `Footer` component provides a semantic and accessible site footer for your Bulma React UI.
26884
27083
  *
@@ -26904,6 +27103,40 @@ const Footer = ({ as = 'footer', className, children, color, bgColor, textColor,
26904
27103
  return (jsxRuntime.jsx(Tag, { className: footerClasses, style: mergeBulmaStyles(bulmaHelperStyles, style), ...rest, children: children }));
26905
27104
  };
26906
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
+
26907
27140
  /**
26908
27141
  * The `Hero` component provides a responsive, flexible, and visually striking section for your Bulma React UI.
26909
27142
  *
@@ -27709,6 +27942,32 @@ const Splitter = withSubComponents(SplitterRoot, {
27709
27942
  Pane: SplitterPane,
27710
27943
  });
27711
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
+
27712
27971
  exports.Autocomplete = Autocomplete;
27713
27972
  exports.Avatar = Avatar;
27714
27973
  exports.Avatars = Avatars;
@@ -27722,6 +27981,7 @@ exports.Card = Card;
27722
27981
  exports.Carousel = Carousel;
27723
27982
  exports.CarouselItem = CarouselItem;
27724
27983
  exports.Cell = Cell;
27984
+ exports.Center = Center;
27725
27985
  exports.Checkbox = Checkbox;
27726
27986
  exports.CheckboxCard = CheckboxCard;
27727
27987
  exports.Checkboxes = Checkboxes;
@@ -27790,14 +28050,17 @@ exports.FieldLabel = FieldLabel;
27790
28050
  exports.Fieldset = Fieldset;
27791
28051
  exports.Figure = Figure;
27792
28052
  exports.File = File;
28053
+ exports.Flex = Flex;
27793
28054
  exports.Footer = Footer;
27794
28055
  exports.Grid = Grid;
28056
+ exports.Group = Group;
27795
28057
  exports.Hero = Hero;
27796
28058
  exports.HeroBody = HeroBody;
27797
28059
  exports.HeroFoot = HeroFoot;
27798
28060
  exports.HeroHead = HeroHead;
27799
28061
  exports.HoverCard = HoverCard;
27800
28062
  exports.Icon = Icon;
28063
+ exports.IconButton = IconButton;
27801
28064
  exports.IconText = IconText;
27802
28065
  exports.Image = Image;
27803
28066
  exports.Input = Input;
@@ -27883,6 +28146,7 @@ exports.Slider = Slider;
27883
28146
  exports.Span = Span;
27884
28147
  exports.Splitter = Splitter;
27885
28148
  exports.SplitterPane = SplitterPane;
28149
+ exports.Stack = Stack;
27886
28150
  exports.Step = Step;
27887
28151
  exports.Steps = Steps;
27888
28152
  exports.Strong = Strong;