@allxsmith/bestax-bulma 5.12.0 → 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 +271 -18
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +271 -18
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/Dropdown.d.ts +2 -0
- package/dist/types/components/Navbar.d.ts +2 -0
- package/dist/types/elements/Tags.d.ts +7 -1
- package/dist/types/helpers/bulmaClassHelpers.d.ts +11 -3
- package/dist/types/helpers/useVisibilityClasses.d.ts +8 -0
- package/package.json +1 -1
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
|
-
|
|
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 &&
|
|
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
|
-
|
|
584
|
-
|
|
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.
|
|
@@ -2087,6 +2280,7 @@ const Modal = withSubComponents(ModalRoot, {
|
|
|
2087
2280
|
Close: ModalClose,
|
|
2088
2281
|
}, 'Modal');
|
|
2089
2282
|
|
|
2283
|
+
const NavbarDropdownContext = React.createContext(null);
|
|
2090
2284
|
/**
|
|
2091
2285
|
* The `Navbar` component implements Bulma's powerful, responsive navigation bar for your Bulma React UI.
|
|
2092
2286
|
*
|
|
@@ -2210,9 +2404,45 @@ const NavbarLink = ({ className, as: Component = 'a', arrowless, textColor, bgCo
|
|
|
2210
2404
|
backgroundColor: bgColor,
|
|
2211
2405
|
...props,
|
|
2212
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
|
+
};
|
|
2213
2434
|
return (jsxRuntime.jsx(Component, { className: classNames(usePrefixedClassNames('navbar-link', {
|
|
2214
2435
|
'is-arrowless': arrowless,
|
|
2215
|
-
}), bulmaHelperClasses, className), ...rest,
|
|
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 }));
|
|
2216
2446
|
};
|
|
2217
2447
|
/**
|
|
2218
2448
|
* Dropdown parent (with options for hover, up, right, active)
|
|
@@ -2221,12 +2451,34 @@ const NavbarLink = ({ className, as: Component = 'a', arrowless, textColor, bgCo
|
|
|
2221
2451
|
* @param {NavbarDropdownProps} props - Props for the NavbarDropdown component.
|
|
2222
2452
|
* @returns {JSX.Element} The rendered dropdown.
|
|
2223
2453
|
*/
|
|
2224
|
-
const NavbarDropdown = ({ className, right, up, hoverable, active, children, ...props }) =>
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
'
|
|
2229
|
-
|
|
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
|
+
};
|
|
2230
2482
|
/**
|
|
2231
2483
|
* Dropdown menu container
|
|
2232
2484
|
*
|
|
@@ -5601,21 +5853,22 @@ const Tag = ({ className, color, size, isLight, isRounded, isDelete, isHoverable
|
|
|
5601
5853
|
|
|
5602
5854
|
const validTagsSizes = ['medium', 'large'];
|
|
5603
5855
|
/**
|
|
5604
|
-
* The `Tags` component groups multiple `Tag` components together in a
|
|
5856
|
+
* The `Tags` component groups multiple `Tag` components together in a Bulma-styled container that wraps onto multiple lines by default.
|
|
5605
5857
|
*
|
|
5606
5858
|
* @function
|
|
5607
5859
|
* @param {TagsProps} props - Props for the Tags component.
|
|
5608
5860
|
* @returns {JSX.Element} The rendered tags container.
|
|
5609
5861
|
* @see {@link https://bulma.io/documentation/elements/tag/#list-of-tags | Bulma Tags documentation}
|
|
5610
5862
|
*/
|
|
5611
|
-
const TagsComponent = ({ className, hasAddons,
|
|
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 }) => {
|
|
5612
5866
|
/**
|
|
5613
5867
|
* Generates Bulma helper classes and separates out remaining props.
|
|
5614
5868
|
*/
|
|
5615
5869
|
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
5616
5870
|
const bulmaClasses = usePrefixedClassNames('tags', {
|
|
5617
5871
|
'has-addons': hasAddons,
|
|
5618
|
-
'are-multiline': isMultiline,
|
|
5619
5872
|
[`are-${size}`]: size && validTagsSizes.includes(size),
|
|
5620
5873
|
});
|
|
5621
5874
|
const tagsClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|