@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.
- package/dist/bestax.css +1 -1
- package/dist/bestax.css.map +1 -1
- package/dist/esm/components/Avatars.js +4 -21
- package/dist/esm/components/Avatars.js.map +1 -1
- package/dist/esm/components/Collapses.js +1 -20
- package/dist/esm/components/Collapses.js.map +1 -1
- package/dist/esm/components/SegmentedControl.js +230 -0
- package/dist/esm/components/SegmentedControl.js.map +1 -0
- package/dist/esm/elements/Kbd.js +86 -0
- package/dist/esm/elements/Kbd.js.map +1 -0
- package/dist/esm/elements/ToggleButton.js +2 -1
- package/dist/esm/elements/ToggleButton.js.map +1 -1
- package/dist/esm/helpers/flattenChildren.js +35 -0
- package/dist/esm/helpers/flattenChildren.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +535 -246
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/SegmentedControl.d.ts +116 -0
- package/dist/types/elements/Kbd.d.ts +100 -0
- package/dist/types/elements/ToggleButton.d.ts +2 -1
- package/dist/types/helpers/flattenChildren.d.ts +16 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types-cjs/components/SegmentedControl.d.ts +116 -0
- package/dist/types-cjs/elements/Kbd.d.ts +100 -0
- package/dist/types-cjs/elements/ToggleButton.d.ts +2 -1
- package/dist/types-cjs/helpers/flattenChildren.d.ts +16 -0
- package/dist/types-cjs/index.d.ts +2 -0
- package/dist/versions/bestax-no-dark-mode.css +1 -1
- package/dist/versions/bestax-no-dark-mode.css.map +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
- package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
- package/dist/versions/bestax-no-helpers.css +1 -1
- package/dist/versions/bestax-no-helpers.css.map +1 -1
- package/dist/versions/bestax-prefixed.css +1 -1
- package/dist/versions/bestax-prefixed.css.map +1 -1
- package/package.json +1 -1
- package/src/scss/elements/_index.scss +1 -0
- 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
|
-
*
|
|
1767
|
-
*
|
|
1768
|
-
*
|
|
1769
|
-
*
|
|
1770
|
-
*
|
|
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
|
|
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
|
|
1785
|
+
return flattenChildren(child.props.children, keyPrefix + child.key);
|
|
1778
1786
|
}
|
|
1779
|
-
const el = child;
|
|
1780
1787
|
return [
|
|
1781
|
-
keyPrefix
|
|
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
|
-
|
|
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
|
|
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;
|