@allxsmith/bestax-bulma 5.31.0 → 5.33.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 (41) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/components/Avatars.js +4 -21
  4. package/dist/esm/components/Avatars.js.map +1 -1
  5. package/dist/esm/components/Collapses.js +1 -20
  6. package/dist/esm/components/Collapses.js.map +1 -1
  7. package/dist/esm/components/SegmentedControl.js +230 -0
  8. package/dist/esm/components/SegmentedControl.js.map +1 -0
  9. package/dist/esm/elements/Kbd.js +86 -0
  10. package/dist/esm/elements/Kbd.js.map +1 -0
  11. package/dist/esm/elements/ToggleButton.js +2 -1
  12. package/dist/esm/elements/ToggleButton.js.map +1 -1
  13. package/dist/esm/helpers/flattenChildren.js +35 -0
  14. package/dist/esm/helpers/flattenChildren.js.map +1 -0
  15. package/dist/extras.css +1 -1
  16. package/dist/extras.css.map +1 -1
  17. package/dist/index.cjs +535 -246
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.esm.js +2 -0
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/types/components/SegmentedControl.d.ts +116 -0
  22. package/dist/types/elements/Kbd.d.ts +100 -0
  23. package/dist/types/elements/ToggleButton.d.ts +2 -1
  24. package/dist/types/helpers/flattenChildren.d.ts +16 -0
  25. package/dist/types/index.d.ts +2 -0
  26. package/dist/types-cjs/components/SegmentedControl.d.ts +116 -0
  27. package/dist/types-cjs/elements/Kbd.d.ts +100 -0
  28. package/dist/types-cjs/elements/ToggleButton.d.ts +2 -1
  29. package/dist/types-cjs/helpers/flattenChildren.d.ts +16 -0
  30. package/dist/types-cjs/index.d.ts +2 -0
  31. package/dist/versions/bestax-no-dark-mode.css +1 -1
  32. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  33. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  34. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  35. package/dist/versions/bestax-no-helpers.css +1 -1
  36. package/dist/versions/bestax-no-helpers.css.map +1 -1
  37. package/dist/versions/bestax-prefixed.css +1 -1
  38. package/dist/versions/bestax-prefixed.css.map +1 -1
  39. package/package.json +1 -1
  40. package/src/scss/elements/_index.scss +1 -0
  41. package/src/scss/elements/_kbd.scss +86 -0
package/dist/index.cjs CHANGED
@@ -1762,26 +1762,36 @@ const Avatar = React.forwardRef(function Avatar(avatarProps, ref) {
1762
1762
  });
1763
1763
  Avatar.displayName = 'Avatar';
1764
1764
 
1765
+ // INTERNAL: deliberately not exported from src/index.ts.
1765
1766
  /**
1766
- * Flattens Fragment children (recursively) into a flat element array so they
1767
- * participate in max clamping and size/shape injection. Children.toArray keys
1768
- * restart at ".0" inside each fragment, so fragment children are re-keyed by
1769
- * prefixing the fragment's own key — otherwise a fragment sibling of a direct
1770
- * child would collide (both ".0") and trigger duplicate-key warnings.
1767
+ * A component's children as a flat list, with each Fragment opened up
1768
+ * (recursively) so the items inside one count one by one rather than as the
1769
+ * Fragment. `Children.toArray` already drops `null`, `undefined` and
1770
+ * booleans and flattens arrays, but it keeps a Fragment whole, so an empty
1771
+ * one would still count as an item and two items in one would count as one.
1772
+ *
1773
+ * `Children.toArray` keys restart at ".0" inside each Fragment, so the items
1774
+ * in one are re-keyed with the Fragment's own key as a prefix. Otherwise an
1775
+ * item in a Fragment and a sibling outside it could share a key.
1776
+ *
1777
+ * Text and numbers pass through as they are, so a caller that wants only
1778
+ * elements filters with `React.isValidElement`.
1771
1779
  */
1772
- function flattenChildren$1(children, keyPrefix = '') {
1780
+ function flattenChildren(children, keyPrefix = '') {
1773
1781
  return React.Children.toArray(children).flatMap(child => {
1774
1782
  if (!React.isValidElement(child))
1775
- return [];
1783
+ return [child];
1776
1784
  if (child.type === React.Fragment) {
1777
- return flattenChildren$1(child.props.children, keyPrefix + child.key);
1785
+ return flattenChildren(child.props.children, keyPrefix + child.key);
1778
1786
  }
1779
- const el = child;
1780
1787
  return [
1781
- keyPrefix ? React.cloneElement(el, { key: keyPrefix + el.key }) : el,
1788
+ keyPrefix
1789
+ ? React.cloneElement(child, { key: keyPrefix + child.key })
1790
+ : child,
1782
1791
  ];
1783
1792
  });
1784
1793
  }
1794
+
1785
1795
  /**
1786
1796
  * The `Avatars` component renders an overlapping/stacked group of `Avatar`s, the "members" list pattern.
1787
1797
  *
@@ -1808,7 +1818,9 @@ const AvatarsComponent = ({ className, max, size, shape, spacing = 'md', spaced
1808
1818
  : undefined;
1809
1819
  const surplusClass = usePrefixedClassNames('is-surplus');
1810
1820
  const combinedClasses = classNames(avatarsClasses, bulmaHelperClasses, className);
1811
- const childArray = flattenChildren$1(children);
1821
+ // Fragments are opened up, so the avatars inside one count toward `max` and
1822
+ // take the group's size and shape one by one. Text between them is dropped.
1823
+ const childArray = flattenChildren(children).filter((child) => React.isValidElement(child));
1812
1824
  const maxCount = typeof max === 'number' && Number.isInteger(max) && max >= 0
1813
1825
  ? max
1814
1826
  : undefined;
@@ -4645,6 +4657,361 @@ const Tabs = withSubComponents(TabsComponent, {
4645
4657
  Content: TabsContent,
4646
4658
  }, 'Tabs');
4647
4659
 
4660
+ const validButtonColors = [...validColors, 'text', 'ghost'];
4661
+ /**
4662
+ * The `Button` component provides a flexible and highly customizable button for your Bulma React UI.
4663
+ *
4664
+ * @function
4665
+ * @param {ButtonProps} props - Props for the Button component.
4666
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
4667
+ * @returns {JSX.Element} The rendered button, anchor, or custom element.
4668
+ * @see {@link https://bulma.io/documentation/elements/button/ | Bulma Button documentation}
4669
+ */
4670
+ const Button = React.forwardRef(function Button(props, ref) {
4671
+ const { color, size, isLight, isRounded, isLoading, isStatic, isFullwidth, isFullWidth, isOutlined, isInverted, isFocused, isActive, isHovered, isDisabled, className, children, textColor, bgColor, as: Component = 'button', href, onClick, target, rel, ...bulmaProps } = props;
4672
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
4673
+ color: textColor,
4674
+ backgroundColor: bgColor,
4675
+ ...bulmaProps,
4676
+ });
4677
+ // Generate Bulma classes with prefix
4678
+ const bulmaClasses = usePrefixedClassNames('button', {
4679
+ [`is-${color}`]: color &&
4680
+ validButtonColors.includes(color),
4681
+ [`is-${size}`]: size,
4682
+ 'is-outlined': isOutlined,
4683
+ 'is-light': isLight,
4684
+ 'is-loading': isLoading,
4685
+ 'is-static': isStatic,
4686
+ 'is-disabled': isDisabled,
4687
+ 'is-rounded': isRounded,
4688
+ 'is-hovered': isHovered,
4689
+ 'is-focused': isFocused,
4690
+ 'is-active': isActive,
4691
+ 'is-inverted': isInverted,
4692
+ 'is-fullwidth': isFullwidth ?? isFullWidth,
4693
+ });
4694
+ // Combine prefixed Bulma classes with unprefixed user className and prefixed helper classes
4695
+ const buttonClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
4696
+ if (Component !== 'button') {
4697
+ // Strip the form-control attributes a link-like element cannot carry, so a
4698
+ // JavaScript consumer or a spread object doesn't put them on the DOM. The
4699
+ // types no longer allow them through; this is the runtime backstop.
4700
+ //
4701
+ // Only for INTRINSIC tags. A custom component (a router Link, ...) owns its
4702
+ // prop contract, and `ComponentPropsWithoutRef<T>` promises the caller that
4703
+ // its props reach it. Stripping names by their spelling alone broke that
4704
+ // promise silently: `<Button as={Custom} name="x" />` type-checked while
4705
+ // `Custom` never received the `name` it requires.
4706
+ //
4707
+ // `autoFocus` and `type` are deliberately NOT stripped: both are valid on
4708
+ // targets this list was filtering them from. `autoFocus` is a global
4709
+ // attribute (React decides per element whether to honour it, which is not
4710
+ // ours to pre-empt), and `type` on an anchor is the MIME hint that
4711
+ // `ButtonProps<'a'>` now types it as.
4712
+ //
4713
+ // The types already answer this for a TypeScript caller: `ButtonProps<T>`
4714
+ // derives from `ComponentPropsWithoutRef<T>`, so only what the target
4715
+ // accepts can be passed. What is left is a runtime backstop for JavaScript
4716
+ // consumers and spread objects.
4717
+ //
4718
+ // Keep it to the two cases where a stray attribute does something. The
4719
+ // submit-overrides belong to a submit control and never make sense on the
4720
+ // anchor path. `disabled` is the one that is VISIBLE: Bulma styles
4721
+ // `.button[disabled]` (background, border, shadow, opacity), so letting it
4722
+ // through to a `<span>` greys the element out — main stripped it, and not
4723
+ // stripping it would be a silent visual change on a types-only release.
4724
+ //
4725
+ // Everything else (`name`, `value`, `form`) is inert where it does not
4726
+ // belong, and enumerating which tags own it is what kept going wrong:
4727
+ // first all nine names on every non-button tag (so `<Button as="input"
4728
+ // name="query" value="Search">` submitted nothing), then a form-control
4729
+ // allowlist that still lost `formAction` on an input and `value` on an
4730
+ // option. Those now ride on the types instead.
4731
+ //
4732
+ // A custom component is exempt entirely — it owns its prop contract, and
4733
+ // `ComponentPropsWithoutRef<T>` promises the caller its props arrive.
4734
+ //
4735
+ // The elements that own `disabled`, per the HTML spec. A closed set, unlike
4736
+ // the open-ended question of which tag owns which attribute.
4737
+ const SUBMIT_OVERRIDES = [
4738
+ 'formAction',
4739
+ 'formEncType',
4740
+ 'formMethod',
4741
+ 'formNoValidate',
4742
+ 'formTarget',
4743
+ ];
4744
+ const OWNS_DISABLED = [
4745
+ 'button',
4746
+ 'fieldset',
4747
+ 'input',
4748
+ 'optgroup',
4749
+ 'option',
4750
+ 'select',
4751
+ 'textarea',
4752
+ ];
4753
+ // Two independent filters. They are not exclusive — an `<a>` owns neither
4754
+ // the submit-overrides nor `disabled`, so it takes both — and deriving them
4755
+ // from one destructure, or from one if/else, is what broke each of them in
4756
+ // turn: first the overrides came off every intrinsic (an `as="input"` lost
4757
+ // `formAction`), then scoping them to the anchor let `disabled` back onto
4758
+ // it.
4759
+ const forwardedRest = { ...rest };
4760
+ if (typeof Component === 'string' && !isCustomElement(Component)) {
4761
+ // Meaningless anywhere but a submit control, and an anchor is not one.
4762
+ if (Component === 'a') {
4763
+ for (const key of SUBMIT_OVERRIDES)
4764
+ delete forwardedRest[key];
4765
+ }
4766
+ // Visible via Bulma's `.button[disabled]`, so withheld from any element
4767
+ // that does not own it.
4768
+ if (!OWNS_DISABLED.includes(Component))
4769
+ delete forwardedRest.disabled;
4770
+ }
4771
+ return (jsxRuntime.jsx(Component, { ref: ref, className: buttonClasses, href: href, target: target, rel: rel, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : undefined, onClick: isDisabled
4772
+ ? // Guarded, because this handler is installed into whatever `as`
4773
+ // renders and a custom component's `onClick` need not be a DOM
4774
+ // event handler at all. One declaring `onClick: (v: string) =>
4775
+ // void` calls this with a string, and an unguarded
4776
+ // `e.preventDefault()` throws `is not a function`. Blocking the
4777
+ // real event is the point; a foreign payload is simply not ours
4778
+ // to act on.
4779
+ (e) => {
4780
+ if (typeof e?.preventDefault === 'function')
4781
+ e.preventDefault();
4782
+ }
4783
+ : onClick, ...forwardedRest, children: children }));
4784
+ }
4785
+ return (jsxRuntime.jsx("button", { ref: ref, className: buttonClasses, disabled: isDisabled, onClick: onClick, ...rest, children: children }));
4786
+ });
4787
+ Button.displayName = 'Button';
4788
+
4789
+ // INTERNAL: deliberately not exported from src/index.ts.
4790
+ /**
4791
+ * `useLayoutEffect` in the browser, `useEffect` on the server. A server
4792
+ * render runs neither, and React 18 warns about a layout effect there, so the
4793
+ * server is handed the plain one.
4794
+ */
4795
+ const useClientLayoutEffect = typeof document === 'undefined' ? React.useEffect : React.useLayoutEffect;
4796
+
4797
+ // Not exported, so it stays out of the public API that `index.ts` re-exports.
4798
+ const SegmentedControlContext = React.createContext(null);
4799
+ /** Sorts mounted segments into the order they sit in the page. */
4800
+ const inDocumentOrder = (a, b) => a.node.compareDocumentPosition(b.node) & Node.DOCUMENT_POSITION_FOLLOWING
4801
+ ? -1
4802
+ : 1;
4803
+ /** How far each arrow key moves along the row. */
4804
+ const STEPS = {
4805
+ ArrowRight: 1,
4806
+ ArrowDown: 1,
4807
+ ArrowLeft: -1,
4808
+ ArrowUp: -1,
4809
+ };
4810
+ /**
4811
+ * The segment a key moves to, found among the segments of the same group in
4812
+ * DOM order, skipping disabled ones and wrapping at either end. `undefined`
4813
+ * for a key the group leaves alone, when no enabled segment is left, or when
4814
+ * the segment isn't inside its row in the page, as a portaled one isn't.
4815
+ */
4816
+ function segmentFor(current, key) {
4817
+ const group = current.closest('[role="radiogroup"]');
4818
+ if (!group)
4819
+ return undefined;
4820
+ const segments = Array.from(group.querySelectorAll('[role="radio"]'));
4821
+ const enabled = segments.filter(segment => !segment.disabled);
4822
+ if (key === 'Home')
4823
+ return enabled[0];
4824
+ if (key === 'End')
4825
+ return enabled[enabled.length - 1];
4826
+ const step = STEPS[key];
4827
+ if (!step)
4828
+ return undefined;
4829
+ const at = segments.indexOf(current);
4830
+ for (let i = 1; i <= segments.length; i += 1) {
4831
+ const candidate = segments[(at + step * i + segments.length) % segments.length];
4832
+ if (!candidate.disabled)
4833
+ return candidate;
4834
+ }
4835
+ return undefined;
4836
+ }
4837
+ /**
4838
+ * The `SegmentedControl` component renders a row of buttons where only one can be on, and tells a screen reader it's a radio group.
4839
+ *
4840
+ * It's Bulma's `.buttons.has-addons` row, with the checked segment filled and
4841
+ * marked `is-selected`, the way Bulma's button docs show it. To a screen
4842
+ * reader it's `role="radiogroup"`, with `role="radio"` and `aria-checked` on
4843
+ * each segment, which is how the APG toolbar example marks its alignment
4844
+ * buttons. The keys follow the APG radio group: the row is one tab stop, the
4845
+ * arrow keys move to the next or previous enabled segment and check it,
4846
+ * wrapping at either end, Home and End go to the first and last, and Space
4847
+ * checks the focused segment. Once a segment is checked, one always is.
4848
+ *
4849
+ * It carries no form value. A choice that's sent with a form is `Radios`.
4850
+ *
4851
+ * @function
4852
+ * @param {SegmentedControlProps} props - Props for the SegmentedControl component.
4853
+ * @param {React.Ref<HTMLDivElement>} ref - Forwarded ref to the row's `<div>`.
4854
+ * @returns {JSX.Element} The rendered segmented control.
4855
+ * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/radio/ | APG radio group pattern}
4856
+ * @see {@link https://bulma.io/documentation/elements/button/#list-of-buttons | Bulma list of buttons}
4857
+ *
4858
+ * @example
4859
+ * <SegmentedControl aria-label="Text alignment" defaultValue="left">
4860
+ * <SegmentedControl.Segment value="left">Left</SegmentedControl.Segment>
4861
+ * <SegmentedControl.Segment value="center">Center</SegmentedControl.Segment>
4862
+ * <SegmentedControl.Segment value="right">Right</SegmentedControl.Segment>
4863
+ * </SegmentedControl>
4864
+ */
4865
+ const SegmentedControlRoot = React.forwardRef(function SegmentedControl({ value, defaultValue, onChange, color = 'link', size, hasAddons = true, isCentered, isRight, className, children, ...props }, ref) {
4866
+ const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
4867
+ // Controlled vs uncontrolled, as in Tabs and Collapses.
4868
+ const isControlled = value !== undefined;
4869
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
4870
+ const checked = isControlled ? (value ?? undefined) : internalValue;
4871
+ const select = (next) => {
4872
+ if (next === checked)
4873
+ return;
4874
+ if (!isControlled)
4875
+ setInternalValue(next);
4876
+ onChange?.(next);
4877
+ };
4878
+ // The segments mount and register from an effect, so the group knows
4879
+ // which can hold the tab stop wherever in the tree they sit.
4880
+ const [segments, setSegments] = React.useState([]);
4881
+ const register = React.useCallback((record) => {
4882
+ setSegments(prev => [...prev, record]);
4883
+ return () => setSegments(prev => prev.filter(r => r !== record));
4884
+ }, []);
4885
+ const [focused, setFocused] = React.useState();
4886
+ // The first enabled segment in the page, sorted when it's read rather
4887
+ // than when a segment registers, so reordered segments are seen too. It's
4888
+ // read after the commit: a render runs before React moves the nodes, so
4889
+ // sorting there would find the old order.
4890
+ const [firstEnabled, setFirstEnabled] = React.useState();
4891
+ useClientLayoutEffect(() => {
4892
+ const inPage = segments.filter(s => !s.disabled).sort(inDocumentOrder);
4893
+ setFirstEnabled(inPage[0]?.value);
4894
+ }, [segments, children]);
4895
+ // One tab stop for the row (roving tabindex). While focus is in the row
4896
+ // the stop follows it, so Tab leaves from wherever focus is even when a
4897
+ // controlled group hasn't taken the new value. Otherwise it's the checked
4898
+ // segment, or the first enabled one when none is checked or the checked
4899
+ // one is disabled. Before the segments register (the server render and
4900
+ // the first client render) the checked one holds it, so a row with
4901
+ // nothing checked has no stop until the client has rendered.
4902
+ const canHoldStop = (candidate) => segments.some(s => !s.disabled && s.value === candidate);
4903
+ let tabStop;
4904
+ if (canHoldStop(focused))
4905
+ tabStop = focused;
4906
+ else if (segments.length === 0 || canHoldStop(checked))
4907
+ tabStop = checked;
4908
+ else
4909
+ tabStop = firstEnabled;
4910
+ const named = Boolean(rest['aria-label'] || rest['aria-labelledby']);
4911
+ React.useEffect(() => {
4912
+ if (!named) {
4913
+ warnOnce('SegmentedControl:unnamed', '[bestax-bulma] <SegmentedControl> has no accessible name. Pass ' +
4914
+ 'aria-label or aria-labelledby, so a screen reader can say what ' +
4915
+ 'the choice is.');
4916
+ }
4917
+ }, [named]);
4918
+ const rowClasses = usePrefixedClassNames('buttons', {
4919
+ 'has-addons': hasAddons,
4920
+ 'is-centered': isCentered,
4921
+ 'is-right': isRight,
4922
+ [`are-${size}`]: size,
4923
+ });
4924
+ // The props are spread first, so the role a screen reader relies on wins
4925
+ // over anything a JavaScript caller or a spread object passes along.
4926
+ return (jsxRuntime.jsx(SegmentedControlContext.Provider, { value: { checked, tabStop, color, select, setFocused, register }, children: jsxRuntime.jsx("div", { ...rest, ref: ref, role: "radiogroup", className: classNames(rowClasses, bulmaHelperClasses, className), children: children }) }));
4927
+ });
4928
+ /**
4929
+ * One option in the row: a `<button role="radio">` that's checked while the group's value is its `value`, filled with the group's `color` and marked `is-selected`.
4930
+ *
4931
+ * @function
4932
+ * @param {SegmentedControlSegmentProps} props - Props for the segment.
4933
+ * @param {React.Ref<HTMLButtonElement>} ref - Forwarded ref to the `<button>`.
4934
+ * @returns {JSX.Element} The rendered segment.
4935
+ */
4936
+ const Segment = React.forwardRef(function Segment({ value, isDisabled, disabled, className, onClick, onKeyDown, onFocus, onBlur, ...props }, ref) {
4937
+ const ctx = React.useContext(SegmentedControlContext);
4938
+ const checked = ctx !== null && ctx.checked === value;
4939
+ const off = Boolean(isDisabled || disabled);
4940
+ // Prefixed like Button's own classes, which a hand-written
4941
+ // `className="is-selected"` could not be under ConfigProvider classPrefix.
4942
+ // Bulma lifts `is-selected` above its neighbours in `.buttons.has-addons`.
4943
+ const selectedClass = usePrefixedClassNames({ 'is-selected': checked });
4944
+ const nodeRef = React.useRef(null);
4945
+ const setRefs = React.useCallback((node) => {
4946
+ nodeRef.current = node;
4947
+ if (typeof ref === 'function')
4948
+ ref(node);
4949
+ else if (ref)
4950
+ ref.current = node;
4951
+ }, [ref]);
4952
+ const register = ctx?.register;
4953
+ React.useEffect(() => {
4954
+ if (!register) {
4955
+ warnOnce('SegmentedControl.Segment:outside', '[bestax-bulma] <SegmentedControl.Segment> is outside a ' +
4956
+ '<SegmentedControl>, so nothing can check it. Put it inside one.');
4957
+ return undefined;
4958
+ }
4959
+ return register({
4960
+ value,
4961
+ disabled: off,
4962
+ node: nodeRef.current,
4963
+ });
4964
+ }, [register, value, off]);
4965
+ // The caller's onClick runs first, so a `preventDefault()` there keeps
4966
+ // the segment from being checked. A disabled button gets no click.
4967
+ const handleClick = (event) => {
4968
+ onClick?.(event);
4969
+ if (event.defaultPrevented)
4970
+ return;
4971
+ ctx?.select(value);
4972
+ };
4973
+ const handleKeyDown = (event) => {
4974
+ onKeyDown?.(event);
4975
+ if (!ctx ||
4976
+ event.defaultPrevented ||
4977
+ event.altKey ||
4978
+ event.ctrlKey ||
4979
+ event.metaKey) {
4980
+ return;
4981
+ }
4982
+ const target = segmentFor(event.currentTarget, event.key);
4983
+ if (!target)
4984
+ return;
4985
+ event.preventDefault();
4986
+ // The row has taken this key, so nothing above it acts on it too: a
4987
+ // Carousel moves its slide on the arrows from a document listener that
4988
+ // doesn't read `defaultPrevented`. Keys the row leaves alone still bubble.
4989
+ event.stopPropagation();
4990
+ target.focus();
4991
+ // The check follows focus, APG's rule for a radio group outside a
4992
+ // toolbar. It goes through a click on the segment, as a native radio's
4993
+ // does, so its onClick sees it. Inside a toolbar the arrows would move
4994
+ // focus alone; that is the line a toolbar would change.
4995
+ target.click();
4996
+ };
4997
+ const handleFocus = (event) => {
4998
+ onFocus?.(event);
4999
+ ctx?.setFocused(value);
5000
+ };
5001
+ // The segment focus moves to, if any, records itself straight after.
5002
+ const handleBlur = (event) => {
5003
+ onBlur?.(event);
5004
+ ctx?.setFocused(undefined);
5005
+ };
5006
+ // The props are spread first, so what a radio depends on wins over
5007
+ // anything a JavaScript caller or a spread object passes along: it stays
5008
+ // a button, never submits, reports whether it's checked, and the group
5009
+ // decides whether Tab reaches it.
5010
+ return (jsxRuntime.jsx(Button, { ...props, ref: setRefs, as: "button", type: "button", role: "radio", "aria-checked": checked, tabIndex: ctx ? (ctx.tabStop === value ? 0 : -1) : undefined, isDisabled: off, color: checked ? ctx.color : undefined, className: classNames(selectedClass, className), onClick: handleClick, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur }));
5011
+ });
5012
+ Segment.displayName = 'SegmentedControl.Segment';
5013
+ const SegmentedControl = withSubComponents(SegmentedControlRoot, { Segment }, 'SegmentedControl');
5014
+
4648
5015
  /**
4649
5016
  * The `Loading` component provides a loading overlay with a spinner animation.
4650
5017
  *
@@ -4940,26 +5307,6 @@ function toIndexes(value) {
4940
5307
  return value;
4941
5308
  return typeof value === 'number' ? [value] : [];
4942
5309
  }
4943
- /**
4944
- * Flattens Fragment children (recursively) so each item inside one gets its
4945
- * own index rather than sharing the fragment's. Children.toArray keys restart
4946
- * at ".0" inside each fragment, so those children are re-keyed with the
4947
- * fragment's own key as a prefix, the way Avatars does it.
4948
- */
4949
- function flattenChildren(children, keyPrefix = '') {
4950
- return React.Children.toArray(children).flatMap(child => {
4951
- if (!React.isValidElement(child))
4952
- return [child];
4953
- if (child.type === React.Fragment) {
4954
- return flattenChildren(child.props.children, keyPrefix + child.key);
4955
- }
4956
- return [
4957
- keyPrefix
4958
- ? React.cloneElement(child, { key: keyPrefix + child.key })
4959
- : child,
4960
- ];
4961
- });
4962
- }
4963
5310
  /**
4964
5311
  * The `Collapses` component groups `Collapse` items into an accordion that keeps one item open at a time, or any number with `multiple`.
4965
5312
  *
@@ -5022,14 +5369,6 @@ const CollapsesComponent = ({ multiple = false, value, defaultValue, onChange, s
5022
5369
  };
5023
5370
  const Collapses = withSubComponents(CollapsesComponent, { Collapse }, 'Collapses');
5024
5371
 
5025
- // INTERNAL: deliberately not exported from src/index.ts.
5026
- /**
5027
- * `useLayoutEffect` in the browser, `useEffect` on the server. A server
5028
- * render runs neither, and React 18 warns about a layout effect there, so the
5029
- * server is handed the plain one.
5030
- */
5031
- const useClientLayoutEffect = typeof document === 'undefined' ? React.useEffect : React.useLayoutEffect;
5032
-
5033
5372
  // INTERNAL: deliberately not exported from src/index.ts.
5034
5373
  /**
5035
5374
  * Runs the caller's own handler on the element that holds the trigger, then
@@ -6207,135 +6546,6 @@ function useAnchoredPosition(anchorRef, panelRef, { active, position, fixed, off
6207
6546
  return resolved;
6208
6547
  }
6209
6548
 
6210
- const validButtonColors = [...validColors, 'text', 'ghost'];
6211
- /**
6212
- * The `Button` component provides a flexible and highly customizable button for your Bulma React UI.
6213
- *
6214
- * @function
6215
- * @param {ButtonProps} props - Props for the Button component.
6216
- * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
6217
- * @returns {JSX.Element} The rendered button, anchor, or custom element.
6218
- * @see {@link https://bulma.io/documentation/elements/button/ | Bulma Button documentation}
6219
- */
6220
- const Button = React.forwardRef(function Button(props, ref) {
6221
- const { color, size, isLight, isRounded, isLoading, isStatic, isFullwidth, isFullWidth, isOutlined, isInverted, isFocused, isActive, isHovered, isDisabled, className, children, textColor, bgColor, as: Component = 'button', href, onClick, target, rel, ...bulmaProps } = props;
6222
- const { bulmaHelperClasses, rest } = useBulmaClasses({
6223
- color: textColor,
6224
- backgroundColor: bgColor,
6225
- ...bulmaProps,
6226
- });
6227
- // Generate Bulma classes with prefix
6228
- const bulmaClasses = usePrefixedClassNames('button', {
6229
- [`is-${color}`]: color &&
6230
- validButtonColors.includes(color),
6231
- [`is-${size}`]: size,
6232
- 'is-outlined': isOutlined,
6233
- 'is-light': isLight,
6234
- 'is-loading': isLoading,
6235
- 'is-static': isStatic,
6236
- 'is-disabled': isDisabled,
6237
- 'is-rounded': isRounded,
6238
- 'is-hovered': isHovered,
6239
- 'is-focused': isFocused,
6240
- 'is-active': isActive,
6241
- 'is-inverted': isInverted,
6242
- 'is-fullwidth': isFullwidth ?? isFullWidth,
6243
- });
6244
- // Combine prefixed Bulma classes with unprefixed user className and prefixed helper classes
6245
- const buttonClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
6246
- if (Component !== 'button') {
6247
- // Strip the form-control attributes a link-like element cannot carry, so a
6248
- // JavaScript consumer or a spread object doesn't put them on the DOM. The
6249
- // types no longer allow them through; this is the runtime backstop.
6250
- //
6251
- // Only for INTRINSIC tags. A custom component (a router Link, ...) owns its
6252
- // prop contract, and `ComponentPropsWithoutRef<T>` promises the caller that
6253
- // its props reach it. Stripping names by their spelling alone broke that
6254
- // promise silently: `<Button as={Custom} name="x" />` type-checked while
6255
- // `Custom` never received the `name` it requires.
6256
- //
6257
- // `autoFocus` and `type` are deliberately NOT stripped: both are valid on
6258
- // targets this list was filtering them from. `autoFocus` is a global
6259
- // attribute (React decides per element whether to honour it, which is not
6260
- // ours to pre-empt), and `type` on an anchor is the MIME hint that
6261
- // `ButtonProps<'a'>` now types it as.
6262
- //
6263
- // The types already answer this for a TypeScript caller: `ButtonProps<T>`
6264
- // derives from `ComponentPropsWithoutRef<T>`, so only what the target
6265
- // accepts can be passed. What is left is a runtime backstop for JavaScript
6266
- // consumers and spread objects.
6267
- //
6268
- // Keep it to the two cases where a stray attribute does something. The
6269
- // submit-overrides belong to a submit control and never make sense on the
6270
- // anchor path. `disabled` is the one that is VISIBLE: Bulma styles
6271
- // `.button[disabled]` (background, border, shadow, opacity), so letting it
6272
- // through to a `<span>` greys the element out — main stripped it, and not
6273
- // stripping it would be a silent visual change on a types-only release.
6274
- //
6275
- // Everything else (`name`, `value`, `form`) is inert where it does not
6276
- // belong, and enumerating which tags own it is what kept going wrong:
6277
- // first all nine names on every non-button tag (so `<Button as="input"
6278
- // name="query" value="Search">` submitted nothing), then a form-control
6279
- // allowlist that still lost `formAction` on an input and `value` on an
6280
- // option. Those now ride on the types instead.
6281
- //
6282
- // A custom component is exempt entirely — it owns its prop contract, and
6283
- // `ComponentPropsWithoutRef<T>` promises the caller its props arrive.
6284
- //
6285
- // The elements that own `disabled`, per the HTML spec. A closed set, unlike
6286
- // the open-ended question of which tag owns which attribute.
6287
- const SUBMIT_OVERRIDES = [
6288
- 'formAction',
6289
- 'formEncType',
6290
- 'formMethod',
6291
- 'formNoValidate',
6292
- 'formTarget',
6293
- ];
6294
- const OWNS_DISABLED = [
6295
- 'button',
6296
- 'fieldset',
6297
- 'input',
6298
- 'optgroup',
6299
- 'option',
6300
- 'select',
6301
- 'textarea',
6302
- ];
6303
- // Two independent filters. They are not exclusive — an `<a>` owns neither
6304
- // the submit-overrides nor `disabled`, so it takes both — and deriving them
6305
- // from one destructure, or from one if/else, is what broke each of them in
6306
- // turn: first the overrides came off every intrinsic (an `as="input"` lost
6307
- // `formAction`), then scoping them to the anchor let `disabled` back onto
6308
- // it.
6309
- const forwardedRest = { ...rest };
6310
- if (typeof Component === 'string' && !isCustomElement(Component)) {
6311
- // Meaningless anywhere but a submit control, and an anchor is not one.
6312
- if (Component === 'a') {
6313
- for (const key of SUBMIT_OVERRIDES)
6314
- delete forwardedRest[key];
6315
- }
6316
- // Visible via Bulma's `.button[disabled]`, so withheld from any element
6317
- // that does not own it.
6318
- if (!OWNS_DISABLED.includes(Component))
6319
- delete forwardedRest.disabled;
6320
- }
6321
- return (jsxRuntime.jsx(Component, { ref: ref, className: buttonClasses, href: href, target: target, rel: rel, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : undefined, onClick: isDisabled
6322
- ? // Guarded, because this handler is installed into whatever `as`
6323
- // renders and a custom component's `onClick` need not be a DOM
6324
- // event handler at all. One declaring `onClick: (v: string) =>
6325
- // void` calls this with a string, and an unguarded
6326
- // `e.preventDefault()` throws `is not a function`. Blocking the
6327
- // real event is the point; a foreign payload is simply not ours
6328
- // to act on.
6329
- (e) => {
6330
- if (typeof e?.preventDefault === 'function')
6331
- e.preventDefault();
6332
- }
6333
- : onClick, ...forwardedRest, children: children }));
6334
- }
6335
- return (jsxRuntime.jsx("button", { ref: ref, className: buttonClasses, disabled: isDisabled, onClick: onClick, ...rest, children: children }));
6336
- });
6337
- Button.displayName = 'Button';
6338
-
6339
6549
  const PopoverContext = React.createContext(null);
6340
6550
  /** Intrinsic elements that are controls already, and keep their own role. */
6341
6551
  const NATIVE_CONTROLS = new Set([
@@ -8579,7 +8789,8 @@ LinkButton.displayName = 'LinkButton';
8579
8789
  * carries no form value: a setting saved with a form is a `Checkbox` or a
8580
8790
  * `Switch`. A set of toggles that each turn on and off on their own goes in
8581
8791
  * `Buttons hasAddons` with `role="group"` and an `aria-label`. A set where only
8582
- * one can be on is a radio group rather than a row of these: use `Radios`.
8792
+ * one can be on is a radio group rather than a row of these: use
8793
+ * `SegmentedControl`, or `Radios` for a choice that's sent with a form.
8583
8794
  *
8584
8795
  * @function
8585
8796
  * @param {ToggleButtonProps} props - Props for the ToggleButton component.
@@ -8932,83 +9143,6 @@ const Image = ({ as, className, textColor, color, bgColor, size, isRounded, isRe
8932
9143
  return (jsxRuntime.jsx(Tag, { className: imageClasses, ...rest, children: content }));
8933
9144
  };
8934
9145
 
8935
- /**
8936
- * The `Link` component renders a styled anchor (`<a>`) element with Bulma helper class integration.
8937
- *
8938
- * @function
8939
- * @param {LinkProps} props - Props for the Link component.
8940
- * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
8941
- * @returns {JSX.Element} The rendered anchor, or whatever `as` names.
8942
- * @see {@link https://bulma.io/documentation/elements/content/ | Bulma Content documentation}
8943
- */
8944
- const Link = React.forwardRef(function Link(linkProps, ref) {
8945
- const { className, textColor, bgColor, isActive, as: Component = 'a', children, ...props } = linkProps;
8946
- /**
8947
- * Generates Bulma helper classes and separates out remaining props.
8948
- */
8949
- const { bulmaHelperClasses, rest } = useBulmaClasses({
8950
- color: textColor,
8951
- backgroundColor: bgColor,
8952
- ...props,
8953
- });
8954
- const bulmaClasses = usePrefixedClassNames({
8955
- 'is-active': isActive,
8956
- });
8957
- const linkClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
8958
- return (jsxRuntime.jsx(Component, { ref: ref, className: linkClasses || undefined, ...rest, ...(Component === 'button' ? { type: buttonType(rest.type) } : {}), children: children }));
8959
- });
8960
- Link.displayName = 'Link';
8961
-
8962
- /**
8963
- * The `ListItem` component renders a styled list item (`<li>`) element with Bulma helper class integration.
8964
- *
8965
- * @function
8966
- * @param {ListItemProps} props - Props for the ListItem component.
8967
- * @returns {JSX.Element} The rendered li element.
8968
- */
8969
- const ListItem = ({ className, textColor, bgColor, children, ...props }) => {
8970
- /**
8971
- * Generates Bulma helper classes and separates out remaining props.
8972
- */
8973
- const { bulmaHelperClasses, rest } = useBulmaClasses({
8974
- color: textColor,
8975
- backgroundColor: bgColor,
8976
- ...props,
8977
- });
8978
- const bulmaClasses = usePrefixedClassNames();
8979
- const itemClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
8980
- return (jsxRuntime.jsx("li", { className: itemClasses || undefined, ...rest, children: children }));
8981
- };
8982
-
8983
- /**
8984
- * The `Loader` component renders Bulma's `.loader`, a small spinning ring for inline loading states.
8985
- *
8986
- * The ring is `1em` square, so `textSize` scales it. It is exposed as an
8987
- * indeterminate `progressbar` named by `ariaLabel`, and it stops spinning
8988
- * under `prefers-reduced-motion: reduce` while staying drawn.
8989
- *
8990
- * @function
8991
- * @param {LoaderProps} props - Props for the Loader component.
8992
- * @param {React.Ref<HTMLSpanElement>} ref - Forwarded ref to the loader element.
8993
- * @returns {JSX.Element} The rendered loader element.
8994
- *
8995
- * @example
8996
- * <Loader />
8997
- *
8998
- * @example
8999
- * <Loader textSize="3" ariaLabel="Saving" />
9000
- */
9001
- const Loader = React.forwardRef(({ className, ariaLabel = 'Loading', ...props }, ref) => {
9002
- const { bulmaHelperClasses, rest } = useBulmaClasses(props);
9003
- const loaderClass = usePrefixedClassNames('loader');
9004
- // role="progressbar", not role="status": a status region mounted together
9005
- // with its text is not reliably announced, so the loader claims only what
9006
- // it can deliver, a named indicator found by reading the page. No
9007
- // aria-valuenow, because the progress is indeterminate.
9008
- return (jsxRuntime.jsx("span", { ref: ref, className: classNames(loaderClass, bulmaHelperClasses, className), role: "progressbar", "aria-label": ariaLabel, ...rest }));
9009
- });
9010
- Loader.displayName = 'Loader';
9011
-
9012
9146
  /**
9013
9147
  * How long after an item appears its announcement is written, in ms. The wait
9014
9148
  * lets a screen reader register a region the container has only just mounted,
@@ -9285,6 +9419,158 @@ function StatusRegion({ items, describe, }) {
9285
9419
  return (jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "false", style: visuallyHidden, children: announcements.map(announcement => (jsxRuntime.jsx("div", { children: announcement.text }, announcement.id))) }));
9286
9420
  }
9287
9421
 
9422
+ /**
9423
+ * Keys pressed together or one after another, in the outer `<kbd>` HTML gives a combination, with the separator between each pair as text.
9424
+ *
9425
+ * It doesn't wrap in the middle and isn't drawn as a key itself. It sets no
9426
+ * font size, so the keys in it are the size of a key on its own.
9427
+ *
9428
+ * @function
9429
+ * @param {KbdGroupProps} props - Props for Kbd.Group.
9430
+ * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the outer `<kbd>`.
9431
+ * @returns {JSX.Element} The rendered combination.
9432
+ *
9433
+ * @example
9434
+ * <Kbd.Group>
9435
+ * <Kbd>Ctrl</Kbd>
9436
+ * <Kbd>Shift</Kbd>
9437
+ * <Kbd>P</Kbd>
9438
+ * </Kbd.Group>
9439
+ *
9440
+ * @example
9441
+ * <Kbd.Group separator="then">
9442
+ * <Kbd>G</Kbd>
9443
+ * <Kbd>I</Kbd>
9444
+ * </Kbd.Group>
9445
+ */
9446
+ const KbdGroup = React.forwardRef(({ className, textColor, separator = '+', children, ...props }, ref) => {
9447
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
9448
+ color: textColor,
9449
+ ...props,
9450
+ });
9451
+ const groupClass = usePrefixedClassNames('kbd-group');
9452
+ const separatorClass = usePrefixedClassNames('kbd-separator');
9453
+ // Null, undefined and booleans drop out, and Fragments are opened up, so
9454
+ // an empty Fragment leaves no separator behind and the keys in one are
9455
+ // separated like the rest. The spaces are part of the text, so a screen
9456
+ // reader reads "Ctrl plus S" rather than one run-together word, whatever
9457
+ // the CSS does.
9458
+ const keys = flattenChildren(children);
9459
+ return (jsxRuntime.jsx("kbd", { ref: ref, className: classNames(groupClass, bulmaHelperClasses, className), ...rest, children: keys.map((key, index) => (jsxRuntime.jsxs(React.Fragment, { children: [index > 0 && (jsxRuntime.jsx("span", { className: separatorClass, children: ` ${separator} ` })), key] }, React.isValidElement(key) && key.key != null ? key.key : index))) }));
9460
+ });
9461
+ KbdGroup.displayName = 'Kbd.Group';
9462
+ /**
9463
+ * The `Kbd` component renders a `<kbd>` drawn as a keycap, for a key the reader presses.
9464
+ *
9465
+ * It only shows the key: it doesn't listen for it. The key takes its colors
9466
+ * from the text it sits in, and its size in `em`, so it fits a paragraph, a
9467
+ * title or a filled button as it is, and `textSize` sizes it outright. For a
9468
+ * combination or a sequence, put the keys in a `Kbd.Group`. What tells
9469
+ * assistive tech a control has a shortcut is `aria-keyshortcuts` on that
9470
+ * control, with `Kbd` as the hint people see next to it.
9471
+ *
9472
+ * @function
9473
+ * @param {KbdProps} props - Props for the Kbd component.
9474
+ * @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<kbd>`.
9475
+ * @returns {JSX.Element} The rendered key.
9476
+ *
9477
+ * @example
9478
+ * <Kbd>Esc</Kbd>
9479
+ *
9480
+ * @example
9481
+ * <Kbd label="Command">⌘</Kbd>
9482
+ */
9483
+ const KbdRoot = React.forwardRef(({ className, textColor, bgColor, label, children, ...props }, ref) => {
9484
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
9485
+ color: textColor,
9486
+ backgroundColor: bgColor,
9487
+ ...props,
9488
+ });
9489
+ const kbdClass = usePrefixedClassNames('kbd');
9490
+ // The name is text rather than an aria-label, which ARIA in HTML
9491
+ // prohibits on kbd. Its styles are inline, so it stays hidden in a
9492
+ // modular build that leaves out Bulma's helper classes.
9493
+ return (jsxRuntime.jsx("kbd", { ref: ref, className: classNames(kbdClass, bulmaHelperClasses, className), ...rest, children: label ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { "aria-hidden": "true", children: children }), jsxRuntime.jsx("span", { style: visuallyHidden, children: label })] })) : (children) }));
9494
+ });
9495
+ const Kbd = withSubComponents(KbdRoot, { Group: KbdGroup }, 'Kbd');
9496
+
9497
+ /**
9498
+ * The `Link` component renders a styled anchor (`<a>`) element with Bulma helper class integration.
9499
+ *
9500
+ * @function
9501
+ * @param {LinkProps} props - Props for the Link component.
9502
+ * @param {React.Ref} ref - Forwarded ref to the element `as` renders.
9503
+ * @returns {JSX.Element} The rendered anchor, or whatever `as` names.
9504
+ * @see {@link https://bulma.io/documentation/elements/content/ | Bulma Content documentation}
9505
+ */
9506
+ const Link = React.forwardRef(function Link(linkProps, ref) {
9507
+ const { className, textColor, bgColor, isActive, as: Component = 'a', children, ...props } = linkProps;
9508
+ /**
9509
+ * Generates Bulma helper classes and separates out remaining props.
9510
+ */
9511
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
9512
+ color: textColor,
9513
+ backgroundColor: bgColor,
9514
+ ...props,
9515
+ });
9516
+ const bulmaClasses = usePrefixedClassNames({
9517
+ 'is-active': isActive,
9518
+ });
9519
+ const linkClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
9520
+ return (jsxRuntime.jsx(Component, { ref: ref, className: linkClasses || undefined, ...rest, ...(Component === 'button' ? { type: buttonType(rest.type) } : {}), children: children }));
9521
+ });
9522
+ Link.displayName = 'Link';
9523
+
9524
+ /**
9525
+ * The `ListItem` component renders a styled list item (`<li>`) element with Bulma helper class integration.
9526
+ *
9527
+ * @function
9528
+ * @param {ListItemProps} props - Props for the ListItem component.
9529
+ * @returns {JSX.Element} The rendered li element.
9530
+ */
9531
+ const ListItem = ({ className, textColor, bgColor, children, ...props }) => {
9532
+ /**
9533
+ * Generates Bulma helper classes and separates out remaining props.
9534
+ */
9535
+ const { bulmaHelperClasses, rest } = useBulmaClasses({
9536
+ color: textColor,
9537
+ backgroundColor: bgColor,
9538
+ ...props,
9539
+ });
9540
+ const bulmaClasses = usePrefixedClassNames();
9541
+ const itemClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
9542
+ return (jsxRuntime.jsx("li", { className: itemClasses || undefined, ...rest, children: children }));
9543
+ };
9544
+
9545
+ /**
9546
+ * The `Loader` component renders Bulma's `.loader`, a small spinning ring for inline loading states.
9547
+ *
9548
+ * The ring is `1em` square, so `textSize` scales it. It is exposed as an
9549
+ * indeterminate `progressbar` named by `ariaLabel`, and it stops spinning
9550
+ * under `prefers-reduced-motion: reduce` while staying drawn.
9551
+ *
9552
+ * @function
9553
+ * @param {LoaderProps} props - Props for the Loader component.
9554
+ * @param {React.Ref<HTMLSpanElement>} ref - Forwarded ref to the loader element.
9555
+ * @returns {JSX.Element} The rendered loader element.
9556
+ *
9557
+ * @example
9558
+ * <Loader />
9559
+ *
9560
+ * @example
9561
+ * <Loader textSize="3" ariaLabel="Saving" />
9562
+ */
9563
+ const Loader = React.forwardRef(({ className, ariaLabel = 'Loading', ...props }, ref) => {
9564
+ const { bulmaHelperClasses, rest } = useBulmaClasses(props);
9565
+ const loaderClass = usePrefixedClassNames('loader');
9566
+ // role="progressbar", not role="status": a status region mounted together
9567
+ // with its text is not reliably announced, so the loader claims only what
9568
+ // it can deliver, a named indicator found by reading the page. No
9569
+ // aria-valuenow, because the progress is indeterminate.
9570
+ return (jsxRuntime.jsx("span", { ref: ref, className: classNames(loaderClass, bulmaHelperClasses, className), role: "progressbar", "aria-label": ariaLabel, ...rest }));
9571
+ });
9572
+ Loader.displayName = 'Loader';
9573
+
9288
9574
  /**
9289
9575
  * The `Notification` component is a Bulma-styled alert/message area for providing feedback, warnings, or information to users.
9290
9576
  *
@@ -19143,6 +19429,8 @@ exports.IconText = IconText;
19143
19429
  exports.Image = Image;
19144
19430
  exports.Input = Input;
19145
19431
  exports.InputBase = InputBase;
19432
+ exports.Kbd = Kbd;
19433
+ exports.KbdGroup = KbdGroup;
19146
19434
  exports.Level = Level;
19147
19435
  exports.LevelItem = LevelItem;
19148
19436
  exports.LevelLeft = LevelLeft;
@@ -19206,6 +19494,7 @@ exports.Radios = Radios;
19206
19494
  exports.Rate = Rate;
19207
19495
  exports.Reveal = Reveal;
19208
19496
  exports.Section = Section;
19497
+ exports.SegmentedControl = SegmentedControl;
19209
19498
  exports.Select = Select;
19210
19499
  exports.SelectBase = SelectBase;
19211
19500
  exports.Sidebar = Sidebar;