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