@allxsmith/bestax-bulma 5.11.7 → 5.13.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/index.cjs.js CHANGED
@@ -324,6 +324,7 @@ const validDisplays = [
324
324
  'inline',
325
325
  'inline-block',
326
326
  'inline-flex',
327
+ 'grid',
327
328
  ];
328
329
  /**
329
330
  * Valid Bulma visibility classes.
@@ -412,8 +413,12 @@ const validFlexGrowShrink = ['0', '1', '2', '3', '4', '5'];
412
413
  const validViewports = [
413
414
  'mobile',
414
415
  'tablet',
416
+ 'tablet-only',
417
+ 'touch',
415
418
  'desktop',
419
+ 'desktop-only',
416
420
  'widescreen',
421
+ 'widescreen-only',
417
422
  'fullhd',
418
423
  ];
419
424
  /**
@@ -433,9 +438,17 @@ const createBulmaClassHelpers = (classPrefix, viewport) => {
433
438
  classes.push(classPrefix ? `${classPrefix}${className}` : className);
434
439
  };
435
440
  // Helper to add class with optional viewport
436
- const addClass = (prefix, value, validValues, supportsViewport = false) => {
441
+ //
442
+ // `supportedViewports` narrows which viewports may be suffixed onto this
443
+ // class. It defaults to every viewport, but a few Bulma helper families
444
+ // (notably `is-size-*`, which ships no `-only` bands) support only a subset,
445
+ // so passing the emitting set keeps us from producing dead classes.
446
+ const addClass = (prefix, value, validValues, supportsViewport = false, supportedViewports = validViewports) => {
437
447
  if (value && validValues.includes(value)) {
438
- const className = supportsViewport && viewport && validViewports.includes(viewport)
448
+ const className = supportsViewport &&
449
+ viewport &&
450
+ validViewports.includes(viewport) &&
451
+ supportedViewports.includes(viewport)
439
452
  ? `${prefix}-${value}-${viewport}`
440
453
  : `${prefix}-${value}`;
441
454
  addPrefixedClass(className);
@@ -560,6 +573,19 @@ const useSpacingClasses = (props) => {
560
573
  }, [classPrefix, m, mt, mr, mb, ml, mx, my, p, pt, pr, pb, pl, px, py]);
561
574
  };
562
575
 
576
+ /**
577
+ * Viewports Bulma generates `is-size-*` classes for. Unlike text alignment,
578
+ * text size ships no `-only` bands (`tablet-only`/`desktop-only`/`widescreen-only`),
579
+ * so the `viewport` prop's suffix is limited to these on the `is-size` path.
580
+ */
581
+ const sizeSupportedViewports = [
582
+ 'mobile',
583
+ 'tablet',
584
+ 'touch',
585
+ 'desktop',
586
+ 'widescreen',
587
+ 'fullhd',
588
+ ];
563
589
  /**
564
590
  * A hook that generates Bulma typography helper classes, including
565
591
  * viewport-specific text size and alignment variants.
@@ -580,8 +606,11 @@ const useTypographyClasses = (props) => {
580
606
  return React.useMemo(() => {
581
607
  const { classes, addPrefixedClass, addClass, addClassNoViewport } = createBulmaClassHelpers(classPrefix, viewport);
582
608
  // Typography
583
- addClass('is-size', textSize, validTextSizes, true); // supports viewport
584
- addClass('has-text', textAlign, validAlignments$1, true); // supports viewport
609
+ // Bulma emits `is-size-*` for the six main/`touch` breakpoints but not the
610
+ // three `-only` bands, so restrict the viewport suffix to the ones it ships
611
+ // — otherwise `viewport="tablet-only"` would render a dead `is-size-N-tablet-only`.
612
+ addClass('is-size', textSize, validTextSizes, true, sizeSupportedViewports); // supports viewport (no `-only` bands)
613
+ addClass('has-text', textAlign, validAlignments$1, true); // supports viewport (all bands)
585
614
  addClassNoViewport('is', textTransform, validTextTransforms); // no viewport support
586
615
  addClassNoViewport('has-text-weight', textWeight, validTextWeights); // no viewport support
587
616
  addClassNoViewport('is-family', fontFamily, validFontFamilies); // no viewport support
@@ -647,7 +676,7 @@ const useTypographyClasses = (props) => {
647
676
  */
648
677
  const useVisibilityClasses = (props) => {
649
678
  const { classPrefix } = useConfig();
650
- const { visibility, visibilityMobile, visibilityTablet, visibilityDesktop, visibilityWidescreen, visibilityFullhd, display, displayMobile, displayTablet, displayDesktop, displayWidescreen, displayFullhd, viewport, } = props;
679
+ const { visibility, visibilityMobile, visibilityTablet, visibilityTabletOnly, visibilityTouch, visibilityDesktop, visibilityDesktopOnly, visibilityWidescreen, visibilityWidescreenOnly, visibilityFullhd, display, displayMobile, displayTablet, displayTabletOnly, displayTouch, displayDesktop, displayDesktopOnly, displayWidescreen, displayWidescreenOnly, displayFullhd, viewport, } = props;
651
680
  return React.useMemo(() => {
652
681
  const { classes, addPrefixedClass, addClass } = createBulmaClassHelpers(classPrefix, viewport);
653
682
  // Viewport-specific visibility
@@ -664,8 +693,12 @@ const useVisibilityClasses = (props) => {
664
693
  };
665
694
  addViewportSpecificVisibilityClass(visibilityMobile, '-mobile');
666
695
  addViewportSpecificVisibilityClass(visibilityTablet, '-tablet');
696
+ addViewportSpecificVisibilityClass(visibilityTabletOnly, '-tablet-only');
697
+ addViewportSpecificVisibilityClass(visibilityTouch, '-touch');
667
698
  addViewportSpecificVisibilityClass(visibilityDesktop, '-desktop');
699
+ addViewportSpecificVisibilityClass(visibilityDesktopOnly, '-desktop-only');
668
700
  addViewportSpecificVisibilityClass(visibilityWidescreen, '-widescreen');
701
+ addViewportSpecificVisibilityClass(visibilityWidescreenOnly, '-widescreen-only');
669
702
  addViewportSpecificVisibilityClass(visibilityFullhd, '-fullhd');
670
703
  // Visibility and Display
671
704
  // Handle viewport-specific display properties first (they take precedence)
@@ -682,14 +715,22 @@ const useVisibilityClasses = (props) => {
682
715
  // Apply viewport-specific display classes
683
716
  addDisplayClass(displayMobile, '-mobile');
684
717
  addDisplayClass(displayTablet, '-tablet');
718
+ addDisplayClass(displayTabletOnly, '-tablet-only');
719
+ addDisplayClass(displayTouch, '-touch');
685
720
  addDisplayClass(displayDesktop, '-desktop');
721
+ addDisplayClass(displayDesktopOnly, '-desktop-only');
686
722
  addDisplayClass(displayWidescreen, '-widescreen');
723
+ addDisplayClass(displayWidescreenOnly, '-widescreen-only');
687
724
  addDisplayClass(displayFullhd, '-fullhd');
688
725
  // Apply legacy display/viewport combination if no viewport-specific display props are set
689
726
  const hasViewportSpecificDisplay = !!(displayMobile ||
690
727
  displayTablet ||
728
+ displayTabletOnly ||
729
+ displayTouch ||
691
730
  displayDesktop ||
731
+ displayDesktopOnly ||
692
732
  displayWidescreen ||
733
+ displayWidescreenOnly ||
693
734
  displayFullhd);
694
735
  if (!hasViewportSpecificDisplay) {
695
736
  // Legacy display handling
@@ -722,14 +763,22 @@ const useVisibilityClasses = (props) => {
722
763
  visibility,
723
764
  visibilityMobile,
724
765
  visibilityTablet,
766
+ visibilityTabletOnly,
767
+ visibilityTouch,
725
768
  visibilityDesktop,
769
+ visibilityDesktopOnly,
726
770
  visibilityWidescreen,
771
+ visibilityWidescreenOnly,
727
772
  visibilityFullhd,
728
773
  display,
729
774
  displayMobile,
730
775
  displayTablet,
776
+ displayTabletOnly,
777
+ displayTouch,
731
778
  displayDesktop,
779
+ displayDesktopOnly,
732
780
  displayWidescreen,
781
+ displayWidescreenOnly,
733
782
  displayFullhd,
734
783
  viewport,
735
784
  ]);
@@ -758,7 +807,7 @@ const useVisibilityClasses = (props) => {
758
807
  */
759
808
  const useFlexboxClasses = (props) => {
760
809
  const { classPrefix } = useConfig();
761
- const { flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, flexGrow, flexShrink, display, displayMobile, displayTablet, displayDesktop, displayWidescreen, displayFullhd, } = props;
810
+ const { flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, flexGrow, flexShrink, display, displayMobile, displayTablet, displayTabletOnly, displayTouch, displayDesktop, displayDesktopOnly, displayWidescreen, displayWidescreenOnly, displayFullhd, } = props;
762
811
  return React.useMemo(() => {
763
812
  const { classes, addClassNoViewport } = createBulmaClassHelpers(classPrefix);
764
813
  // Flexbox
@@ -768,10 +817,18 @@ const useFlexboxClasses = (props) => {
768
817
  displayMobile === 'inline-flex' ||
769
818
  displayTablet === 'flex' ||
770
819
  displayTablet === 'inline-flex' ||
820
+ displayTabletOnly === 'flex' ||
821
+ displayTabletOnly === 'inline-flex' ||
822
+ displayTouch === 'flex' ||
823
+ displayTouch === 'inline-flex' ||
771
824
  displayDesktop === 'flex' ||
772
825
  displayDesktop === 'inline-flex' ||
826
+ displayDesktopOnly === 'flex' ||
827
+ displayDesktopOnly === 'inline-flex' ||
773
828
  displayWidescreen === 'flex' ||
774
829
  displayWidescreen === 'inline-flex' ||
830
+ displayWidescreenOnly === 'flex' ||
831
+ displayWidescreenOnly === 'inline-flex' ||
775
832
  displayFullhd === 'flex' ||
776
833
  displayFullhd === 'inline-flex';
777
834
  if (hasFlexDisplay) {
@@ -801,8 +858,12 @@ const useFlexboxClasses = (props) => {
801
858
  display,
802
859
  displayMobile,
803
860
  displayTablet,
861
+ displayTabletOnly,
862
+ displayTouch,
804
863
  displayDesktop,
864
+ displayDesktopOnly,
805
865
  displayWidescreen,
866
+ displayWidescreenOnly,
806
867
  displayFullhd,
807
868
  ]);
808
869
  };
@@ -915,7 +976,7 @@ const useOtherClasses = (props) => {
915
976
  * // rest: { className: 'custom-class' }
916
977
  */
917
978
  const useBulmaClasses = (props) => {
918
- const { color, backgroundColor, colorShade, backgroundColorShade, m, mt, mr, mb, ml, mx, my, p, pt, pr, pb, pl, px, py, textSize, textAlign, textTransform, textWeight, fontFamily, display, visibility, flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, flexGrow, flexShrink, float, overflow, overlay, interaction, cursor, radius, shadow, responsive, viewport, displayMobile, displayTablet, displayDesktop, displayWidescreen, displayFullhd, textSizeMobile, textSizeTablet, textSizeDesktop, textSizeWidescreen, textSizeFullhd, textAlignMobile, textAlignTablet, textAlignDesktop, textAlignWidescreen, textAlignFullhd, visibilityMobile, visibilityTablet, visibilityDesktop, visibilityWidescreen, visibilityFullhd, skeleton, clearfix, relative, fullHeight, ...rest } = props;
979
+ const { color, backgroundColor, colorShade, backgroundColorShade, m, mt, mr, mb, ml, mx, my, p, pt, pr, pb, pl, px, py, textSize, textAlign, textTransform, textWeight, fontFamily, display, visibility, flexDirection, flexWrap, justifyContent, alignContent, alignItems, alignSelf, flexGrow, flexShrink, float, overflow, 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, relative, fullHeight, ...rest } = props;
919
980
  const colorClasses = useColorClasses({
920
981
  color,
921
982
  colorShade,
@@ -961,14 +1022,22 @@ const useBulmaClasses = (props) => {
961
1022
  visibility,
962
1023
  visibilityMobile,
963
1024
  visibilityTablet,
1025
+ visibilityTabletOnly,
1026
+ visibilityTouch,
964
1027
  visibilityDesktop,
1028
+ visibilityDesktopOnly,
965
1029
  visibilityWidescreen,
1030
+ visibilityWidescreenOnly,
966
1031
  visibilityFullhd,
967
1032
  display,
968
1033
  displayMobile,
969
1034
  displayTablet,
1035
+ displayTabletOnly,
1036
+ displayTouch,
970
1037
  displayDesktop,
1038
+ displayDesktopOnly,
971
1039
  displayWidescreen,
1040
+ displayWidescreenOnly,
972
1041
  displayFullhd,
973
1042
  viewport,
974
1043
  });
@@ -984,8 +1053,12 @@ const useBulmaClasses = (props) => {
984
1053
  display,
985
1054
  displayMobile,
986
1055
  displayTablet,
1056
+ displayTabletOnly,
1057
+ displayTouch,
987
1058
  displayDesktop,
1059
+ displayDesktopOnly,
988
1060
  displayWidescreen,
1061
+ displayWidescreenOnly,
989
1062
  displayFullhd,
990
1063
  });
991
1064
  const otherClasses = useOtherClasses({
@@ -1709,6 +1782,8 @@ const isBrowser$1 = (win, doc) => typeof win !== 'undefined' && typeof doc !== '
1709
1782
  const DropdownComponent = ({ label, children, className, menuClassName, active: activeProp, up, right, hoverable, disabled, onActiveChange, closeOnClick = true, id, ...props }) => {
1710
1783
  const [active, setActive] = React.useState(!!activeProp);
1711
1784
  const dropdownRef = React.useRef(null);
1785
+ const triggerRef = React.useRef(null);
1786
+ const pendingFocusRef = React.useRef(null);
1712
1787
  const { bulmaHelperClasses, rest } = useBulmaClasses(props);
1713
1788
  // Generate Bulma classes with prefix
1714
1789
  const bulmaClasses = usePrefixedClassNames('dropdown', {
@@ -1757,8 +1832,126 @@ const DropdownComponent = ({ label, children, className, menuClassName, active:
1757
1832
  onActiveChange?.(false);
1758
1833
  }
1759
1834
  };
1835
+ const getMenuItems = () => {
1836
+ /* istanbul ignore next: dropdownRef.current is never null once mounted */
1837
+ if (!dropdownRef.current)
1838
+ return [];
1839
+ return Array.from(dropdownRef.current.querySelectorAll('[role="menuitem"]')).filter(el => !el.hasAttribute('disabled') &&
1840
+ el.getAttribute('aria-disabled') !== 'true');
1841
+ };
1842
+ // Focus the pending menu item once the menu becomes visible; the item is
1843
+ // unfocusable while `display: none` applies, so this must wait for the
1844
+ // `is-active` class to actually land in the DOM.
1845
+ React.useEffect(() => {
1846
+ if (!active || !pendingFocusRef.current)
1847
+ return;
1848
+ const items = getMenuItems();
1849
+ if (items.length) {
1850
+ const index = pendingFocusRef.current === 'first' ? 0 : items.length - 1;
1851
+ items[index].focus();
1852
+ }
1853
+ pendingFocusRef.current = null;
1854
+ }, [active]);
1855
+ const handleTriggerKeyDown = (e) => {
1856
+ if (disabled)
1857
+ return;
1858
+ switch (e.key) {
1859
+ case 'ArrowDown':
1860
+ e.preventDefault();
1861
+ pendingFocusRef.current = 'first';
1862
+ if (!active) {
1863
+ setActive(true);
1864
+ onActiveChange?.(true);
1865
+ }
1866
+ else {
1867
+ const items = getMenuItems();
1868
+ if (items.length)
1869
+ items[0].focus();
1870
+ pendingFocusRef.current = null;
1871
+ }
1872
+ break;
1873
+ case 'ArrowUp':
1874
+ e.preventDefault();
1875
+ pendingFocusRef.current = 'last';
1876
+ if (!active) {
1877
+ setActive(true);
1878
+ onActiveChange?.(true);
1879
+ }
1880
+ else {
1881
+ const items = getMenuItems();
1882
+ if (items.length)
1883
+ items[items.length - 1].focus();
1884
+ pendingFocusRef.current = null;
1885
+ }
1886
+ break;
1887
+ case 'Enter':
1888
+ case ' ':
1889
+ e.preventDefault();
1890
+ if (!active) {
1891
+ pendingFocusRef.current = 'first';
1892
+ setActive(true);
1893
+ onActiveChange?.(true);
1894
+ }
1895
+ else {
1896
+ setActive(false);
1897
+ onActiveChange?.(false);
1898
+ }
1899
+ break;
1900
+ case 'Escape':
1901
+ if (active) {
1902
+ e.preventDefault();
1903
+ setActive(false);
1904
+ onActiveChange?.(false);
1905
+ }
1906
+ break;
1907
+ }
1908
+ };
1909
+ const handleMenuKeyDown = (e) => {
1910
+ // Escape and Tab close the menu regardless of whether it has any focusable
1911
+ // items — an empty or all-disabled menu must still honor the close contract.
1912
+ if (e.key === 'Escape') {
1913
+ e.preventDefault();
1914
+ setActive(false);
1915
+ onActiveChange?.(false);
1916
+ triggerRef.current?.focus();
1917
+ return;
1918
+ }
1919
+ if (e.key === 'Tab') {
1920
+ setActive(false);
1921
+ onActiveChange?.(false);
1922
+ return;
1923
+ }
1924
+ const items = getMenuItems();
1925
+ if (!items.length)
1926
+ return;
1927
+ const currentIndex = items.indexOf(document.activeElement);
1928
+ switch (e.key) {
1929
+ case 'ArrowDown': {
1930
+ e.preventDefault();
1931
+ const next = currentIndex >= 0 ? (currentIndex + 1) % items.length : 0;
1932
+ items[next].focus();
1933
+ break;
1934
+ }
1935
+ case 'ArrowUp': {
1936
+ e.preventDefault();
1937
+ const prev = currentIndex >= 0
1938
+ ? (currentIndex - 1 + items.length) % items.length
1939
+ : items.length - 1;
1940
+ items[prev].focus();
1941
+ break;
1942
+ }
1943
+ case 'Home':
1944
+ e.preventDefault();
1945
+ items[0].focus();
1946
+ break;
1947
+ case 'End':
1948
+ e.preventDefault();
1949
+ items[items.length - 1].focus();
1950
+ break;
1951
+ }
1952
+ };
1760
1953
  const dropdownClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
1761
- return (jsxRuntime.jsxs("div", { className: dropdownClasses, ref: dropdownRef, id: id, "data-testid": "dropdown-root", ...rest, children: [jsxRuntime.jsx("div", { className: usePrefixedClassNames('dropdown-trigger'), children: jsxRuntime.jsxs("button", { className: buttonClass, "aria-haspopup": "true", "aria-controls": id ? `${id}-menu` : undefined, "aria-expanded": active, onClick: handleToggle, disabled: disabled, type: "button", children: [jsxRuntime.jsx("span", { children: label }), jsxRuntime.jsx("span", { className: usePrefixedClassNames('icon', 'is-small'), "aria-hidden": "true", children: jsxRuntime.jsx("i", { className: "fas fa-angle-down" }) })] }) }), jsxRuntime.jsx("div", { className: classNames(usePrefixedClassNames('dropdown-menu'), menuClassName), id: id ? `${id}-menu` : undefined, role: "menu", "data-testid": "dropdown-menu", children: jsxRuntime.jsx("div", { className: usePrefixedClassNames('dropdown-content'), onClick: handleMenuClick, tabIndex: -1, children: children }) })] }));
1954
+ return (jsxRuntime.jsxs("div", { className: dropdownClasses, ref: dropdownRef, id: id, "data-testid": "dropdown-root", ...rest, children: [jsxRuntime.jsx("div", { className: usePrefixedClassNames('dropdown-trigger'), children: jsxRuntime.jsxs("button", { ref: triggerRef, className: buttonClass, "aria-haspopup": "true", "aria-controls": id ? `${id}-menu` : undefined, "aria-expanded": active, onClick: handleToggle, onKeyDown: handleTriggerKeyDown, disabled: disabled, type: "button", children: [jsxRuntime.jsx("span", { children: label }), jsxRuntime.jsx("span", { className: usePrefixedClassNames('icon', 'is-small'), "aria-hidden": "true", children: jsxRuntime.jsx("i", { className: "fas fa-angle-down" }) })] }) }), jsxRuntime.jsx("div", { className: classNames(usePrefixedClassNames('dropdown-menu'), menuClassName), id: id ? `${id}-menu` : undefined, role: "menu", "data-testid": "dropdown-menu", onKeyDown: handleMenuKeyDown, children: jsxRuntime.jsx("div", { className: usePrefixedClassNames('dropdown-content'), onClick: handleMenuClick, tabIndex: -1, children: children }) })] }));
1762
1955
  };
1763
1956
  /**
1764
1957
  * Bulma Dropdown item.
@@ -1868,6 +2061,7 @@ const Menu = withSubComponents(MenuComponent, {
1868
2061
  Item: MenuItem,
1869
2062
  }, 'Menu');
1870
2063
 
2064
+ const validMessageSizes = ['small', 'medium', 'large'];
1871
2065
  /**
1872
2066
  * The `Message` component provides Bulma's flexible notice/message box for your Bulma React UI.
1873
2067
  *
@@ -1876,7 +2070,7 @@ const Menu = withSubComponents(MenuComponent, {
1876
2070
  * @returns {JSX.Element} The rendered message.
1877
2071
  * @see {@link https://bulma.io/documentation/components/message/ | Bulma Message documentation}
1878
2072
  */
1879
- const MessageComponent = ({ className, title, textColor, color, bgColor, onClose, children, ...props }) => {
2073
+ const MessageComponent = ({ className, title, textColor, color, bgColor, size, onClose, children, ...props }) => {
1880
2074
  const { classPrefix } = useConfig();
1881
2075
  const { bulmaHelperClasses, rest } = useBulmaClasses({
1882
2076
  color: textColor,
@@ -1886,6 +2080,7 @@ const MessageComponent = ({ className, title, textColor, color, bgColor, onClose
1886
2080
  // Generate Bulma classes with prefix
1887
2081
  const bulmaClasses = usePrefixedClassNames('message', {
1888
2082
  [`is-${color}`]: color,
2083
+ [`is-${size}`]: size && validMessageSizes.includes(size),
1889
2084
  });
1890
2085
  const deleteClass = usePrefixedClassNames('delete');
1891
2086
  const messageClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
@@ -2085,6 +2280,7 @@ const Modal = withSubComponents(ModalRoot, {
2085
2280
  Close: ModalClose,
2086
2281
  }, 'Modal');
2087
2282
 
2283
+ const NavbarDropdownContext = React.createContext(null);
2088
2284
  /**
2089
2285
  * The `Navbar` component implements Bulma's powerful, responsive navigation bar for your Bulma React UI.
2090
2286
  *
@@ -2208,9 +2404,45 @@ const NavbarLink = ({ className, as: Component = 'a', arrowless, textColor, bgCo
2208
2404
  backgroundColor: bgColor,
2209
2405
  ...props,
2210
2406
  });
2407
+ const dropdownContext = React.useContext(NavbarDropdownContext);
2408
+ const hasHref = rest.href !== undefined;
2409
+ const isNativeInteractive = Component === 'button' || hasHref;
2410
+ const handleKeyDown = (e) => {
2411
+ rest.onKeyDown?.(e);
2412
+ if (!dropdownContext || e.defaultPrevented)
2413
+ return;
2414
+ if (e.key === 'Enter' || e.key === ' ') {
2415
+ e.preventDefault();
2416
+ dropdownContext.toggle();
2417
+ }
2418
+ else if (e.key === 'Escape' && dropdownContext.active) {
2419
+ e.preventDefault();
2420
+ dropdownContext.close();
2421
+ }
2422
+ };
2423
+ // When the link is not natively interactive (no `href`, not a `<button>`) it
2424
+ // renders as `role="button"`, so a mouse/touch click has no default action to
2425
+ // open the dropdown. Compose the caller's handler and toggle the dropdown
2426
+ // unless the caller prevented the default. Native links/buttons keep their own
2427
+ // click semantics (navigation / the caller's handler).
2428
+ const handleClick = (e) => {
2429
+ rest.onClick?.(e);
2430
+ if (!dropdownContext || isNativeInteractive || e.defaultPrevented)
2431
+ return;
2432
+ dropdownContext.toggle();
2433
+ };
2211
2434
  return (jsxRuntime.jsx(Component, { className: classNames(usePrefixedClassNames('navbar-link', {
2212
2435
  'is-arrowless': arrowless,
2213
- }), bulmaHelperClasses, className), ...rest, children: children }));
2436
+ }), bulmaHelperClasses, className), ...rest, ...(dropdownContext && {
2437
+ 'aria-haspopup': 'true',
2438
+ 'aria-expanded': dropdownContext.active,
2439
+ onKeyDown: handleKeyDown,
2440
+ ...(!isNativeInteractive && {
2441
+ role: 'button',
2442
+ tabIndex: 0,
2443
+ onClick: handleClick,
2444
+ }),
2445
+ }), children: children }));
2214
2446
  };
2215
2447
  /**
2216
2448
  * Dropdown parent (with options for hover, up, right, active)
@@ -2219,12 +2451,34 @@ const NavbarLink = ({ className, as: Component = 'a', arrowless, textColor, bgCo
2219
2451
  * @param {NavbarDropdownProps} props - Props for the NavbarDropdown component.
2220
2452
  * @returns {JSX.Element} The rendered dropdown.
2221
2453
  */
2222
- const NavbarDropdown = ({ className, right, up, hoverable, active, children, ...props }) => (jsxRuntime.jsx("div", { className: classNames(usePrefixedClassNames('navbar-item', 'has-dropdown', {
2223
- 'has-dropdown-up': up,
2224
- 'is-right': right,
2225
- 'is-hoverable': hoverable,
2226
- 'is-active': active,
2227
- }), className), ...props, children: children }));
2454
+ const NavbarDropdown = ({ className, right, up, hoverable, active: activeProp, onActiveChange, children, ...props }) => {
2455
+ const [active, setActive] = React.useState(!!activeProp);
2456
+ React.useEffect(() => {
2457
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- syncing to controlled prop
2458
+ if (typeof activeProp === 'boolean')
2459
+ setActive(activeProp);
2460
+ }, [activeProp]);
2461
+ // Keep `onActiveChange` out of the state updater (a pure function) so Strict
2462
+ // Mode's double-invoked updaters don't double-fire it — mirrors `Dropdown`.
2463
+ const toggle = () => {
2464
+ const next = !active;
2465
+ setActive(next);
2466
+ onActiveChange?.(next);
2467
+ };
2468
+ const close = () => {
2469
+ /* istanbul ignore next: close() is only invoked once already active */
2470
+ if (!active)
2471
+ return;
2472
+ setActive(false);
2473
+ onActiveChange?.(false);
2474
+ };
2475
+ return (jsxRuntime.jsx(NavbarDropdownContext.Provider, { value: { active, toggle, close }, children: jsxRuntime.jsx("div", { className: classNames(usePrefixedClassNames('navbar-item', 'has-dropdown', {
2476
+ 'has-dropdown-up': up,
2477
+ 'is-right': right,
2478
+ 'is-hoverable': hoverable,
2479
+ 'is-active': active,
2480
+ }), className), ...props, children: children }) }));
2481
+ };
2228
2482
  /**
2229
2483
  * Dropdown menu container
2230
2484
  *
@@ -4684,6 +4938,7 @@ const LinkButton = ({ variant = 'text', color, className, ...props }) => {
4684
4938
  return (jsxRuntime.jsx(Button, { color: buttonColor, className: classNames(prefixedClasses, className), ...props }));
4685
4939
  };
4686
4940
 
4941
+ const validButtonsSizes = ['small', 'medium', 'large'];
4687
4942
  /**
4688
4943
  * The `Buttons` component lets you group multiple `Button` elements together with Bulma's spacing, alignment, and add-on features.
4689
4944
  *
@@ -4692,11 +4947,12 @@ const LinkButton = ({ variant = 'text', color, className, ...props }) => {
4692
4947
  * @returns {JSX.Element} The rendered group of buttons.
4693
4948
  * @see {@link https://bulma.io/documentation/elements/button/#group | Bulma Button Group documentation}
4694
4949
  */
4695
- const ButtonsComponent = ({ className, textColor, color, bgColor, isCentered, isRight, hasAddons, children, ...props }) => {
4950
+ const ButtonsComponent = ({ className, textColor, color, bgColor, isCentered, isRight, hasAddons, size, children, ...props }) => {
4696
4951
  const buttonsClasses = usePrefixedClassNames('buttons', {
4697
4952
  'is-centered': isCentered,
4698
4953
  'is-right': isRight,
4699
4954
  'has-addons': hasAddons,
4955
+ [`are-${size}`]: size && validButtonsSizes.includes(size),
4700
4956
  });
4701
4957
  /**
4702
4958
  * Generates Bulma helper classes and separates out remaining props.
@@ -5595,22 +5851,25 @@ const Tag = ({ className, color, size, isLight, isRounded, isDelete, isHoverable
5595
5851
  return (jsxRuntime.jsx("span", { className: tagClasses, ...rest, children: children }));
5596
5852
  };
5597
5853
 
5854
+ const validTagsSizes = ['medium', 'large'];
5598
5855
  /**
5599
- * The `Tags` component groups multiple `Tag` components together in a horizontal (or multiline) Bulma-styled container.
5856
+ * The `Tags` component groups multiple `Tag` components together in a Bulma-styled container that wraps onto multiple lines by default.
5600
5857
  *
5601
5858
  * @function
5602
5859
  * @param {TagsProps} props - Props for the Tags component.
5603
5860
  * @returns {JSX.Element} The rendered tags container.
5604
5861
  * @see {@link https://bulma.io/documentation/elements/tag/#list-of-tags | Bulma Tags documentation}
5605
5862
  */
5606
- const TagsComponent = ({ className, hasAddons, isMultiline, children, ...props }) => {
5863
+ const TagsComponent = ({ className, hasAddons,
5864
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- accepted for backwards compatibility, deprecated no-op (no `are-multiline` CSS ships)
5865
+ isMultiline, size, children, ...props }) => {
5607
5866
  /**
5608
5867
  * Generates Bulma helper classes and separates out remaining props.
5609
5868
  */
5610
5869
  const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
5611
5870
  const bulmaClasses = usePrefixedClassNames('tags', {
5612
5871
  'has-addons': hasAddons,
5613
- 'are-multiline': isMultiline,
5872
+ [`are-${size}`]: size && validTagsSizes.includes(size),
5614
5873
  });
5615
5874
  const tagsClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
5616
5875
  return (jsxRuntime.jsx("div", { className: tagsClasses, ...rest, children: children }));