@allxsmith/bestax-bulma 5.36.1 → 5.37.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/EmptyState.js +2 -2
- package/dist/esm/components/Timeline.js +5 -5
- package/dist/esm/components/Timeline.js.map +1 -1
- package/dist/esm/components/TreeView.js +192 -0
- package/dist/esm/components/TreeView.js.map +1 -0
- package/dist/esm/helpers/typeahead.js +82 -0
- package/dist/esm/helpers/typeahead.js.map +1 -0
- package/dist/esm/helpers/useMenuKeys.js +8 -58
- package/dist/esm/helpers/useMenuKeys.js.map +1 -1
- package/dist/esm/helpers/useTreeView.js +380 -0
- package/dist/esm/helpers/useTreeView.js.map +1 -0
- package/dist/extras.css +1 -1
- package/dist/extras.css.map +1 -1
- package/dist/index.cjs +1945 -1368
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/TreeView.d.ts +115 -0
- package/dist/types/helpers/typeahead.d.ts +41 -0
- package/dist/types/helpers/useMenuKeys.d.ts +1 -2
- package/dist/types/helpers/useTreeView.d.ts +88 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types-cjs/components/TreeView.d.ts +115 -0
- package/dist/types-cjs/helpers/typeahead.d.ts +41 -0
- package/dist/types-cjs/helpers/useMenuKeys.d.ts +1 -2
- package/dist/types-cjs/helpers/useTreeView.d.ts +88 -0
- package/dist/types-cjs/index.d.ts +1 -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/components/_index.scss +1 -0
- package/src/scss/components/_treeview.scss +252 -0
package/dist/index.cjs
CHANGED
|
@@ -2365,41 +2365,13 @@ function getDeepestActiveElement(doc = document) {
|
|
|
2365
2365
|
}
|
|
2366
2366
|
|
|
2367
2367
|
// INTERNAL: deliberately not exported from src/index.ts.
|
|
2368
|
-
/**
|
|
2369
|
-
* Every menu-item role, so an item a caller gives `menuitemcheckbox` or
|
|
2370
|
-
* `menuitemradio` (a filter or sort menu) stays reachable.
|
|
2371
|
-
*/
|
|
2372
|
-
const MENU_ITEM_SELECTOR = '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]';
|
|
2373
|
-
/**
|
|
2374
|
-
* Whether a menu item can be reached and activated: it isn't disabled, as a
|
|
2375
|
-
* native control or through `aria-disabled="true"`.
|
|
2376
|
-
*/
|
|
2377
|
-
function isEnabledMenuItem(item) {
|
|
2378
|
-
return (!item.hasAttribute('disabled') &&
|
|
2379
|
-
item.getAttribute('aria-disabled') !== 'true');
|
|
2380
|
-
}
|
|
2381
|
-
/** Whether `node` is one of `menu`'s items, enabled or not. */
|
|
2382
|
-
const isItemOf = (menu, node) => Boolean(node && menu.contains(node) && node.matches(MENU_ITEM_SELECTOR));
|
|
2383
|
-
/** The items in `menu` the keys reach, in document order. */
|
|
2384
|
-
function enabledMenuItems(menu) {
|
|
2385
|
-
return Array.from(menu.querySelectorAll(MENU_ITEM_SELECTOR)).filter(isEnabledMenuItem);
|
|
2386
|
-
}
|
|
2387
2368
|
/** How long typed characters keep adding up to one search, in milliseconds. */
|
|
2388
2369
|
const TYPEAHEAD_TIMEOUT = 500;
|
|
2389
2370
|
/**
|
|
2390
|
-
*
|
|
2391
|
-
*
|
|
2392
|
-
*/
|
|
2393
|
-
function activatesItself(item, key) {
|
|
2394
|
-
if (item.tagName === 'BUTTON')
|
|
2395
|
-
return true;
|
|
2396
|
-
return key === 'Enter' && item.tagName === 'A' && item.hasAttribute('href');
|
|
2397
|
-
}
|
|
2398
|
-
/**
|
|
2399
|
-
* The text typing finds an item by: what it says, without what's hidden from
|
|
2400
|
-
* assistive technology, such as an icon whose glyph is a ligature's name.
|
|
2371
|
+
* The text typing finds an element by: what it says, without what's hidden
|
|
2372
|
+
* from assistive technology, such as an icon whose glyph is a ligature's name.
|
|
2401
2373
|
*/
|
|
2402
|
-
function
|
|
2374
|
+
function typeaheadText(element) {
|
|
2403
2375
|
let text = '';
|
|
2404
2376
|
const read = (node) => {
|
|
2405
2377
|
node.childNodes.forEach(child => {
|
|
@@ -2411,7 +2383,7 @@ function label(item) {
|
|
|
2411
2383
|
}
|
|
2412
2384
|
});
|
|
2413
2385
|
};
|
|
2414
|
-
read(
|
|
2386
|
+
read(element);
|
|
2415
2387
|
return text.trim().toLowerCase();
|
|
2416
2388
|
}
|
|
2417
2389
|
/**
|
|
@@ -2420,18 +2392,84 @@ function label(item) {
|
|
|
2420
2392
|
* through the items that start with it, and so does a run of one letter
|
|
2421
2393
|
* ("dd"). A longer search looks from the focused item, so typing more of
|
|
2422
2394
|
* its own text keeps it.
|
|
2395
|
+
*
|
|
2396
|
+
* @param items - The items typing can reach, in the order they're shown.
|
|
2397
|
+
* @param search - What's been typed, lowercased.
|
|
2398
|
+
* @param current - The focused item's index in `items`, or -1 for none.
|
|
2399
|
+
* @param textOf - The text an item is found by. By default it's the item's
|
|
2400
|
+
* own, read by `typeaheadText`.
|
|
2423
2401
|
*/
|
|
2424
|
-
function typeaheadMatch(items, search, current) {
|
|
2402
|
+
function typeaheadMatch(items, search, current, textOf = typeaheadText) {
|
|
2425
2403
|
const repeated = Array.from(search).every(char => char === search[0]);
|
|
2426
2404
|
const wanted = repeated ? search[0] : search;
|
|
2427
2405
|
const start = current < 0 ? 0 : current + (wanted.length === 1 ? 1 : 0);
|
|
2428
2406
|
for (let i = 0; i < items.length; i += 1) {
|
|
2429
2407
|
const item = items[(start + i) % items.length];
|
|
2430
|
-
if (
|
|
2408
|
+
if (textOf(item).startsWith(wanted))
|
|
2431
2409
|
return item;
|
|
2432
2410
|
}
|
|
2433
2411
|
return undefined;
|
|
2434
2412
|
}
|
|
2413
|
+
/**
|
|
2414
|
+
* Keeps what has been typed for a type-ahead search, and forgets it once
|
|
2415
|
+
* `TYPEAHEAD_TIMEOUT` passes with nothing typed. Pair it with
|
|
2416
|
+
* `typeaheadMatch` to find the item the search names.
|
|
2417
|
+
*
|
|
2418
|
+
* @function useTypeahead
|
|
2419
|
+
* @returns A way to add a character to the search, and a way to forget it.
|
|
2420
|
+
*/
|
|
2421
|
+
function useTypeahead() {
|
|
2422
|
+
const typedRef = React.useRef({ text: '' });
|
|
2423
|
+
React.useEffect(() => {
|
|
2424
|
+
const typed = typedRef.current;
|
|
2425
|
+
return () => clearTimeout(typed.timer);
|
|
2426
|
+
}, []);
|
|
2427
|
+
return React.useMemo(() => {
|
|
2428
|
+
const reset = () => {
|
|
2429
|
+
const typed = typedRef.current;
|
|
2430
|
+
clearTimeout(typed.timer);
|
|
2431
|
+
typed.text = '';
|
|
2432
|
+
};
|
|
2433
|
+
const type = (char) => {
|
|
2434
|
+
const typed = typedRef.current;
|
|
2435
|
+
typed.text += char.toLowerCase();
|
|
2436
|
+
clearTimeout(typed.timer);
|
|
2437
|
+
typed.timer = setTimeout(reset, TYPEAHEAD_TIMEOUT);
|
|
2438
|
+
return typed.text;
|
|
2439
|
+
};
|
|
2440
|
+
return { type, reset };
|
|
2441
|
+
}, []);
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
// INTERNAL: deliberately not exported from src/index.ts.
|
|
2445
|
+
/**
|
|
2446
|
+
* Every menu-item role, so an item a caller gives `menuitemcheckbox` or
|
|
2447
|
+
* `menuitemradio` (a filter or sort menu) stays reachable.
|
|
2448
|
+
*/
|
|
2449
|
+
const MENU_ITEM_SELECTOR = '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]';
|
|
2450
|
+
/**
|
|
2451
|
+
* Whether a menu item can be reached and activated: it isn't disabled, as a
|
|
2452
|
+
* native control or through `aria-disabled="true"`.
|
|
2453
|
+
*/
|
|
2454
|
+
function isEnabledMenuItem(item) {
|
|
2455
|
+
return (!item.hasAttribute('disabled') &&
|
|
2456
|
+
item.getAttribute('aria-disabled') !== 'true');
|
|
2457
|
+
}
|
|
2458
|
+
/** Whether `node` is one of `menu`'s items, enabled or not. */
|
|
2459
|
+
const isItemOf = (menu, node) => Boolean(node && menu.contains(node) && node.matches(MENU_ITEM_SELECTOR));
|
|
2460
|
+
/** The items in `menu` the keys reach, in document order. */
|
|
2461
|
+
function enabledMenuItems(menu) {
|
|
2462
|
+
return Array.from(menu.querySelectorAll(MENU_ITEM_SELECTOR)).filter(isEnabledMenuItem);
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Whether the browser activates `item` on this key by itself: a `<button>`
|
|
2466
|
+
* answers Enter and Space, and a link with an `href` answers Enter.
|
|
2467
|
+
*/
|
|
2468
|
+
function activatesItself(item, key) {
|
|
2469
|
+
if (item.tagName === 'BUTTON')
|
|
2470
|
+
return true;
|
|
2471
|
+
return key === 'Enter' && item.tagName === 'A' && item.hasAttribute('href');
|
|
2472
|
+
}
|
|
2435
2473
|
/**
|
|
2436
2474
|
* Moves through and activates the items of a `role="menu"` element from the
|
|
2437
2475
|
* keyboard. Put the `onKeyDown` it returns on that element. It reads the
|
|
@@ -2463,17 +2501,8 @@ function typeaheadMatch(items, search, current) {
|
|
|
2463
2501
|
* what has been typed.
|
|
2464
2502
|
*/
|
|
2465
2503
|
function useMenuKeys() {
|
|
2466
|
-
const
|
|
2467
|
-
React.useEffect(() => {
|
|
2468
|
-
const typed = typedRef.current;
|
|
2469
|
-
return () => clearTimeout(typed.timer);
|
|
2470
|
-
}, []);
|
|
2504
|
+
const typeahead = useTypeahead();
|
|
2471
2505
|
return React.useMemo(() => {
|
|
2472
|
-
const reset = () => {
|
|
2473
|
-
const typed = typedRef.current;
|
|
2474
|
-
clearTimeout(typed.timer);
|
|
2475
|
-
typed.text = '';
|
|
2476
|
-
};
|
|
2477
2506
|
const onKeyDown = (event) => {
|
|
2478
2507
|
const menu = event.currentTarget;
|
|
2479
2508
|
const focused = getActiveElementInTree(menu);
|
|
@@ -2530,14 +2559,10 @@ function useMenuKeys() {
|
|
|
2530
2559
|
return;
|
|
2531
2560
|
}
|
|
2532
2561
|
event.preventDefault();
|
|
2533
|
-
|
|
2534
|
-
typed.text += event.key.toLowerCase();
|
|
2535
|
-
clearTimeout(typed.timer);
|
|
2536
|
-
typed.timer = setTimeout(reset, TYPEAHEAD_TIMEOUT);
|
|
2537
|
-
typeaheadMatch(items, typed.text, current)?.focus();
|
|
2562
|
+
typeaheadMatch(items, typeahead.type(event.key), current)?.focus();
|
|
2538
2563
|
};
|
|
2539
|
-
return { onKeyDown, reset };
|
|
2540
|
-
}, []);
|
|
2564
|
+
return { onKeyDown, reset: typeahead.reset };
|
|
2565
|
+
}, [typeahead]);
|
|
2541
2566
|
}
|
|
2542
2567
|
|
|
2543
2568
|
/**
|
|
@@ -3473,7 +3498,7 @@ const EmptyStateActions = ({ className, ...props }) => {
|
|
|
3473
3498
|
};
|
|
3474
3499
|
EmptyStateActions.displayName = 'EmptyState.Actions';
|
|
3475
3500
|
/** Whether a shorthand prop was given something to render. */
|
|
3476
|
-
const isGiven$
|
|
3501
|
+
const isGiven$2 = (node) => node !== undefined &&
|
|
3477
3502
|
node !== null &&
|
|
3478
3503
|
typeof node !== 'boolean' &&
|
|
3479
3504
|
node !== '';
|
|
@@ -3520,7 +3545,7 @@ const EmptyStateRoot = React.forwardRef(({ className, icon, title, titleAs = 'h2
|
|
|
3520
3545
|
});
|
|
3521
3546
|
// The props' parts first, each only when it's given, then the children
|
|
3522
3547
|
// exactly as they were written: nothing here looks at them.
|
|
3523
|
-
return (jsxRuntime.jsxs("div", { ref: ref, className: classNames(rootClass, bulmaHelperClasses, className), ...rest, children: [isGiven$
|
|
3548
|
+
return (jsxRuntime.jsxs("div", { ref: ref, className: classNames(rootClass, bulmaHelperClasses, className), ...rest, children: [isGiven$2(icon) && (jsxRuntime.jsx(EmptyStateIndicator, { children: typeof icon === 'string' ? jsxRuntime.jsx(Icon, { name: icon }) : icon })), isGiven$2(title) && (jsxRuntime.jsx(EmptyStateTitle, { as: titleAs, children: title })), isGiven$2(description) && (jsxRuntime.jsx(EmptyStateDescription, { children: description })), children] }));
|
|
3524
3549
|
});
|
|
3525
3550
|
const EmptyState = withSubComponents(EmptyStateRoot, {
|
|
3526
3551
|
Indicator: EmptyStateIndicator,
|
|
@@ -8137,7 +8162,7 @@ const TimelineItemContext = React.createContext({
|
|
|
8137
8162
|
titleAs: 'h2',
|
|
8138
8163
|
});
|
|
8139
8164
|
/** Whether a prop was given something to render. */
|
|
8140
|
-
const isGiven = (node) => node !== undefined &&
|
|
8165
|
+
const isGiven$1 = (node) => node !== undefined &&
|
|
8141
8166
|
node !== null &&
|
|
8142
8167
|
typeof node !== 'boolean' &&
|
|
8143
8168
|
node !== '';
|
|
@@ -8170,7 +8195,7 @@ const TimelineItem = React.forwardRef(({ className, title, time, dateTime, icon,
|
|
|
8170
8195
|
[`is-${color}`]: isTimelineColor(color),
|
|
8171
8196
|
});
|
|
8172
8197
|
const markerClass = usePrefixedClassNames('timeline-marker', {
|
|
8173
|
-
'is-icon': isGiven(icon),
|
|
8198
|
+
'is-icon': isGiven$1(icon),
|
|
8174
8199
|
});
|
|
8175
8200
|
const contentClass = usePrefixedClassNames('timeline-content');
|
|
8176
8201
|
const titleClass = usePrefixedClassNames('timeline-title');
|
|
@@ -8182,8 +8207,8 @@ const TimelineItem = React.forwardRef(({ className, title, time, dateTime, icon,
|
|
|
8182
8207
|
const words = label ? (jsxRuntime.jsx("span", { style: visuallyHidden, children: ` ${label}` })) : null;
|
|
8183
8208
|
return (jsxRuntime.jsxs("li", { ref: ref, className: classNames(itemClass, bulmaHelperClasses, className), ...rest, ...(state && {
|
|
8184
8209
|
'aria-current': state === 'active' ? 'step' : undefined,
|
|
8185
|
-
}), children: [jsxRuntime.jsx("div", { className: markerClass, "aria-hidden": "true", children: isGiven(icon) &&
|
|
8186
|
-
(typeof icon === 'string' ? jsxRuntime.jsx(Icon, { name: icon }) : icon) }), jsxRuntime.jsxs("div", { className: contentClass, children: [isGiven(title) ? (jsxRuntime.jsxs(TitleTag, { className: titleClass, children: [title, words] })) : (words), isGiven(time) &&
|
|
8210
|
+
}), children: [jsxRuntime.jsx("div", { className: markerClass, "aria-hidden": "true", children: isGiven$1(icon) &&
|
|
8211
|
+
(typeof icon === 'string' ? jsxRuntime.jsx(Icon, { name: icon }) : icon) }), jsxRuntime.jsxs("div", { className: contentClass, children: [isGiven$1(title) ? (jsxRuntime.jsxs(TitleTag, { className: titleClass, children: [title, words] })) : (words), isGiven$1(time) &&
|
|
8187
8212
|
(dateTime ? (jsxRuntime.jsx("time", { className: timeClass, dateTime: dateTime, children: time })) : (jsxRuntime.jsx("span", { className: timeClass, children: time }))), children] })] }));
|
|
8188
8213
|
});
|
|
8189
8214
|
TimelineItem.displayName = 'Timeline.Item';
|
|
@@ -8257,7 +8282,7 @@ const TimelineRoot = React.forwardRef(({ className, children, active, pending, a
|
|
|
8257
8282
|
// Each child gets its state through context rather than a clone, so an
|
|
8258
8283
|
// app's own component around a Timeline.Item still gets it. Fragments
|
|
8259
8284
|
// and arrays are opened up first, so each item inside one counts.
|
|
8260
|
-
return (jsxRuntime.jsxs("ol", { ref: ref, className: classNames(rootClass, bulmaHelperClasses, className), ...rest, role: "list", children: [flattenChildren(children).map((child, index) => (jsxRuntime.jsx(TimelineItemContext.Provider, { value: contextFor(stateAt(index)), children: child }, React.isValidElement(child) ? child.key : index))), isGiven(pending) && (jsxRuntime.jsx(TimelineItemContext.Provider, { value: contextFor('pending'), children: jsxRuntime.jsx(TimelineItem, { title: pending }) }))] }));
|
|
8285
|
+
return (jsxRuntime.jsxs("ol", { ref: ref, className: classNames(rootClass, bulmaHelperClasses, className), ...rest, role: "list", children: [flattenChildren(children).map((child, index) => (jsxRuntime.jsx(TimelineItemContext.Provider, { value: contextFor(stateAt(index)), children: child }, React.isValidElement(child) ? child.key : index))), isGiven$1(pending) && (jsxRuntime.jsx(TimelineItemContext.Provider, { value: contextFor('pending'), children: jsxRuntime.jsx(TimelineItem, { title: pending }) }))] }));
|
|
8261
8286
|
});
|
|
8262
8287
|
const Timeline = withSubComponents(TimelineRoot, { Item: TimelineItem }, 'Timeline');
|
|
8263
8288
|
|
|
@@ -9552,922 +9577,1353 @@ function RevealImpl(revealProps) {
|
|
|
9552
9577
|
const Reveal = RevealImpl;
|
|
9553
9578
|
Reveal.displayName = 'Reveal';
|
|
9554
9579
|
|
|
9580
|
+
// INTERNAL: deliberately not exported from src/index.ts.
|
|
9555
9581
|
/**
|
|
9556
|
-
*
|
|
9557
|
-
*
|
|
9558
|
-
*
|
|
9559
|
-
* @param {BlockProps} props - Props for the Block component.
|
|
9560
|
-
* @returns {JSX.Element} The rendered block element.
|
|
9561
|
-
* @see {@link https://bulma.io/documentation/elements/block/ | Bulma Block documentation}
|
|
9582
|
+
* What Enter, Space and a click on the row do in each mode, from the tables
|
|
9583
|
+
* in #1096. `open` opens or closes a parent and does nothing on a leaf. A
|
|
9584
|
+
* click on the chevron only ever opens or closes.
|
|
9562
9585
|
*/
|
|
9563
|
-
const
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
9568
|
-
color: textColor ?? color,
|
|
9569
|
-
backgroundColor: bgColor,
|
|
9570
|
-
...props,
|
|
9571
|
-
});
|
|
9572
|
-
const bulmaClasses = usePrefixedClassNames('block');
|
|
9573
|
-
const blockClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9574
|
-
return (jsxRuntime.jsx("div", { className: blockClasses, ...rest, children: children }));
|
|
9586
|
+
const MODES = {
|
|
9587
|
+
none: { enter: ['open'], space: ['open'], click: ['open'] },
|
|
9588
|
+
single: { enter: ['select'], space: ['select'], click: ['select', 'open'] },
|
|
9589
|
+
checkbox: { enter: ['open'], space: ['check'], click: ['check'] },
|
|
9575
9590
|
};
|
|
9576
|
-
|
|
9591
|
+
/** Left and Right, swapped for a right-to-left page. */
|
|
9592
|
+
const MIRRORED = {
|
|
9593
|
+
ArrowLeft: 'ArrowRight',
|
|
9594
|
+
ArrowRight: 'ArrowLeft',
|
|
9595
|
+
};
|
|
9596
|
+
/** An IME is composing, so the key belongs to it (`keyCode` 229 is Safari's word for it). */
|
|
9597
|
+
const isComposing$2 = (event) => event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229;
|
|
9598
|
+
/** The registry's items on the page, in document order. */
|
|
9599
|
+
const shownIn = (tree, { values }) => Array.from(tree.querySelectorAll('[role="treeitem"]')).filter(element => values.has(element));
|
|
9600
|
+
/** The item an item on the page sits in: its group's `<li>`, or none at the top. */
|
|
9601
|
+
function parentItemOf(element) {
|
|
9602
|
+
const group = element.parentElement;
|
|
9603
|
+
return group.getAttribute('role') === 'group' ? group.parentElement : null;
|
|
9604
|
+
}
|
|
9605
|
+
/** The values of the items an item on the page is in, from the top. */
|
|
9606
|
+
function pathOf(element, { values }) {
|
|
9607
|
+
const path = [];
|
|
9608
|
+
for (let at = parentItemOf(element); at; at = parentItemOf(at)) {
|
|
9609
|
+
path.unshift(values.get(at));
|
|
9610
|
+
}
|
|
9611
|
+
return path;
|
|
9612
|
+
}
|
|
9577
9613
|
/**
|
|
9578
|
-
*
|
|
9579
|
-
*
|
|
9580
|
-
*
|
|
9581
|
-
*
|
|
9582
|
-
*
|
|
9583
|
-
*
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
const
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
|
|
9614
|
+
* Every known item's check state, by the rules in #1096:
|
|
9615
|
+
*
|
|
9616
|
+
* - a disabled item is checked only when its own value is listed;
|
|
9617
|
+
* - an enabled item with no enabled items anywhere under it is checked when
|
|
9618
|
+
* it, or any item above it, is listed;
|
|
9619
|
+
* - any other enabled item follows the items of that second kind in its
|
|
9620
|
+
* branch: checked when they all are, unchecked when none is, mixed between.
|
|
9621
|
+
*
|
|
9622
|
+
* Also returns the items of the second kind, which are what a toggle sets.
|
|
9623
|
+
*/
|
|
9624
|
+
function readChecks(records, listed) {
|
|
9625
|
+
const kids = new Map();
|
|
9626
|
+
records.forEach(({ parent }, value) => {
|
|
9627
|
+
kids.set(parent, [...(kids.get(parent) ?? []), value]);
|
|
9628
|
+
});
|
|
9629
|
+
const states = new Map();
|
|
9630
|
+
const ends = [];
|
|
9631
|
+
// How many enabled ends the branch holds, and how many are checked.
|
|
9632
|
+
const visit = (value, above) => {
|
|
9633
|
+
const marked = above || listed.has(value);
|
|
9634
|
+
let total = 0;
|
|
9635
|
+
let on = 0;
|
|
9636
|
+
for (const kid of kids.get(value) ?? []) {
|
|
9637
|
+
const [t, o] = visit(kid, marked);
|
|
9638
|
+
total += t;
|
|
9639
|
+
on += o;
|
|
9640
|
+
}
|
|
9641
|
+
if (records.get(value).disabled) {
|
|
9642
|
+
states.set(value, listed.has(value));
|
|
9643
|
+
return [total, on];
|
|
9644
|
+
}
|
|
9645
|
+
if (total === 0) {
|
|
9646
|
+
states.set(value, marked);
|
|
9647
|
+
ends.push(value);
|
|
9648
|
+
return [1, marked ? 1 : 0];
|
|
9649
|
+
}
|
|
9650
|
+
states.set(value, on === total ? true : on > 0 && 'mixed');
|
|
9651
|
+
return [total, on];
|
|
9652
|
+
};
|
|
9653
|
+
for (const top of kids.get(null) ?? [])
|
|
9654
|
+
visit(top, false);
|
|
9655
|
+
return { states, ends };
|
|
9656
|
+
}
|
|
9657
|
+
/**
|
|
9658
|
+
* The list a toggle of `value` leaves: it and every enabled item under it
|
|
9659
|
+
* take the opposite of its state (a mixed one checks), and the rest is read
|
|
9660
|
+
* back by the rules. That's every item that shows checked, parents
|
|
9661
|
+
* included, plus any listed value no item has.
|
|
9662
|
+
*/
|
|
9663
|
+
function toggledList(records, list, value) {
|
|
9664
|
+
const { states, ends } = readChecks(records, new Set(list));
|
|
9665
|
+
const to = states.get(value) !== true;
|
|
9666
|
+
// An end was reached from the top, so everything above it is known.
|
|
9667
|
+
const under = (end) => {
|
|
9668
|
+
for (let at = end; at !== null;) {
|
|
9669
|
+
if (at === value)
|
|
9670
|
+
return true;
|
|
9671
|
+
at = records.get(at).parent;
|
|
9672
|
+
}
|
|
9673
|
+
return false;
|
|
9674
|
+
};
|
|
9675
|
+
const seed = new Set(ends.filter(end => (under(end) ? to : states.get(end) === true)));
|
|
9676
|
+
records.forEach(({ disabled }, item) => {
|
|
9677
|
+
if (disabled && states.get(item) === true)
|
|
9678
|
+
seed.add(item);
|
|
9593
9679
|
});
|
|
9594
|
-
const
|
|
9595
|
-
|
|
9680
|
+
const after = readChecks(records, seed).states;
|
|
9681
|
+
return [
|
|
9682
|
+
...Array.from(after)
|
|
9683
|
+
.filter(([, state]) => state === true)
|
|
9684
|
+
.map(([item]) => item),
|
|
9685
|
+
...list.filter(item => !records.has(item)),
|
|
9686
|
+
];
|
|
9687
|
+
}
|
|
9688
|
+
/** A value the caller holds, or one this hook holds when the caller doesn't. */
|
|
9689
|
+
function useControlled(controlled, initial) {
|
|
9690
|
+
const [own, setOwn] = React.useState(initial);
|
|
9691
|
+
const isControlled = controlled !== undefined;
|
|
9692
|
+
const set = (next) => {
|
|
9693
|
+
if (!isControlled)
|
|
9694
|
+
setOwn(next);
|
|
9695
|
+
};
|
|
9696
|
+
return [isControlled ? controlled : own, set];
|
|
9697
|
+
}
|
|
9698
|
+
/**
|
|
9699
|
+
* The open state, the selection, the keys, the tab stop and the registry of
|
|
9700
|
+
* a TreeView (#1096). Focus moves for real, with a roving tabindex, rather
|
|
9701
|
+
* than through `aria-activedescendant`.
|
|
9702
|
+
*
|
|
9703
|
+
* Every item registers its value, its parent and whether it's disabled from
|
|
9704
|
+
* a layout effect. In a checkbox tree a closed item's children still render
|
|
9705
|
+
* and register while drawing nothing, so the registry knows every item and a
|
|
9706
|
+
* check reaches all of them. The keys read the items on the page, in
|
|
9707
|
+
* document order, each time they need them.
|
|
9708
|
+
*
|
|
9709
|
+
* @function useTreeView
|
|
9710
|
+
* @param options - The TreeView's props.
|
|
9711
|
+
* @returns The state and handlers the root and its items wire up.
|
|
9712
|
+
*/
|
|
9713
|
+
function useTreeView(options) {
|
|
9714
|
+
// An own key only, so a name every object inherits, like `toString`, is a
|
|
9715
|
+
// mode the tree doesn't know too.
|
|
9716
|
+
const mode = Object.prototype.hasOwnProperty.call(MODES, options.mode)
|
|
9717
|
+
? options.mode
|
|
9718
|
+
: 'none';
|
|
9719
|
+
const actions = MODES[mode];
|
|
9720
|
+
const [expanded, setExpanded] = useControlled(options.expanded, options.defaultExpanded);
|
|
9721
|
+
const [selection, setSelection] = useControlled(options.selected, options.defaultSelected);
|
|
9722
|
+
const [checkedList, setChecked] = useControlled(options.checked, options.defaultChecked);
|
|
9723
|
+
// Each is read in its own mode only.
|
|
9724
|
+
const selected = mode === 'single' ? selection : null;
|
|
9725
|
+
const listed = new Set(mode === 'checkbox' ? checkedList : []);
|
|
9726
|
+
const treeRef = React.useRef(null);
|
|
9727
|
+
const registryRef = React.useRef({
|
|
9728
|
+
records: new Map(),
|
|
9729
|
+
elements: new Map(),
|
|
9730
|
+
values: new WeakMap(),
|
|
9731
|
+
});
|
|
9732
|
+
// Items register from their own effects, so they ask for a render to be read.
|
|
9733
|
+
const [, refresh] = React.useReducer((n) => n + 1, 0);
|
|
9734
|
+
const typeahead = useTypeahead();
|
|
9735
|
+
// The item with focus, and where the stop rests while focus is elsewhere:
|
|
9736
|
+
// `undefined` until the tree has mounted. With the values above it, for
|
|
9737
|
+
// when it goes away.
|
|
9738
|
+
const [focused, setFocused] = React.useState(null);
|
|
9739
|
+
const [resting, setResting] = React.useState();
|
|
9740
|
+
const restingPathRef = React.useRef([]);
|
|
9741
|
+
// The values above an item that left the page with focus in it.
|
|
9742
|
+
const lostRef = React.useRef(null);
|
|
9743
|
+
const { records } = registryRef.current;
|
|
9744
|
+
const checks = mode === 'checkbox'
|
|
9745
|
+
? // eslint-disable-next-line react-hooks/refs -- read in render on purpose: items write the registry from their layout effects and then ask for this render with `refresh`
|
|
9746
|
+
readChecks(records, listed).states
|
|
9747
|
+
: undefined;
|
|
9748
|
+
const tabStop = focused ?? (resting === undefined ? selected : resting);
|
|
9749
|
+
const isOpen = (value) => expanded.includes(value);
|
|
9750
|
+
const stateOf = (value, path, disabled) => {
|
|
9751
|
+
if (mode === 'single') {
|
|
9752
|
+
return disabled ? {} : { selected: value === selected };
|
|
9753
|
+
}
|
|
9754
|
+
if (checks) {
|
|
9755
|
+
// Until the items register, a value stands for its branch, and a
|
|
9756
|
+
// parent can't know it's mixed.
|
|
9757
|
+
const fromList = listed.has(value) || (!disabled && path.some(v => listed.has(v)));
|
|
9758
|
+
return { checked: checks.get(value) ?? fromList };
|
|
9759
|
+
}
|
|
9760
|
+
return {};
|
|
9761
|
+
};
|
|
9762
|
+
const changeOpen = (next) => {
|
|
9763
|
+
setExpanded(next);
|
|
9764
|
+
options.onExpandedChange?.(next);
|
|
9765
|
+
};
|
|
9766
|
+
const run = {
|
|
9767
|
+
open: ({ value, isParent, open }) => {
|
|
9768
|
+
if (isParent) {
|
|
9769
|
+
changeOpen(open ? expanded.filter(v => v !== value) : [...expanded, value]);
|
|
9770
|
+
}
|
|
9771
|
+
},
|
|
9772
|
+
select: ({ value }) => {
|
|
9773
|
+
if (value === selected)
|
|
9774
|
+
return;
|
|
9775
|
+
setSelection(value);
|
|
9776
|
+
options.onSelectedChange?.(value);
|
|
9777
|
+
},
|
|
9778
|
+
check: ({ value }) => {
|
|
9779
|
+
const next = toggledList(records, checkedList, value);
|
|
9780
|
+
setChecked(next);
|
|
9781
|
+
options.onCheckedChange?.(next);
|
|
9782
|
+
},
|
|
9783
|
+
};
|
|
9784
|
+
/** Disabled items are never selected, checked, opened or closed. */
|
|
9785
|
+
const act = (item, list) => {
|
|
9786
|
+
if (!item.disabled)
|
|
9787
|
+
list.forEach(action => run[action](item));
|
|
9788
|
+
};
|
|
9789
|
+
// After every render, put the stop where it belongs. While focus is in
|
|
9790
|
+
// the tree it's the focused item. Otherwise it's the selected item, or the
|
|
9791
|
+
// first checked one on the page, and failing that it stays where it was.
|
|
9792
|
+
// An item that goes away hands it to its nearest ancestor on the page, or
|
|
9793
|
+
// to the first item, and focus goes with it if it had focus.
|
|
9794
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- after every render on purpose: it reads the page, and sets state only when what it reads has changed
|
|
9795
|
+
useClientLayoutEffect(() => {
|
|
9796
|
+
const tree = treeRef.current;
|
|
9797
|
+
const registry = registryRef.current;
|
|
9798
|
+
// Each item's element is read off the page with its value, rather than
|
|
9799
|
+
// out of `elements`, which holds one element per value: two items
|
|
9800
|
+
// sharing a value, which they shouldn't, can leave it without one the
|
|
9801
|
+
// page still has.
|
|
9802
|
+
const shown = shownIn(tree, registry);
|
|
9803
|
+
const onPage = shown.map(element => registry.values.get(element));
|
|
9804
|
+
const elementOf = (value) => shown[onPage.indexOf(value)];
|
|
9805
|
+
const isShown = (value) => value != null && onPage.includes(value);
|
|
9806
|
+
const heir = (path) => [...path].reverse().find(isShown) ?? onPage[0] ?? null;
|
|
9807
|
+
const lost = lostRef.current;
|
|
9808
|
+
lostRef.current = null;
|
|
9809
|
+
if (lost && !tree.contains(getActiveElementInTree(tree))) {
|
|
9810
|
+
const to = heir(lost);
|
|
9811
|
+
if (to)
|
|
9812
|
+
elementOf(to).focus();
|
|
9813
|
+
return;
|
|
9814
|
+
}
|
|
9815
|
+
if (focused !== null && !isShown(focused))
|
|
9816
|
+
setFocused(null);
|
|
9817
|
+
const preferred = onPage.find(value => value === selected || checks?.get(value) === true);
|
|
9818
|
+
const next = preferred ?? (isShown(resting) ? resting : heir(restingPathRef.current));
|
|
9819
|
+
if (next !== resting) {
|
|
9820
|
+
setResting(next);
|
|
9821
|
+
restingPathRef.current = next ? pathOf(elementOf(next), registry) : [];
|
|
9822
|
+
}
|
|
9596
9823
|
});
|
|
9597
|
-
const
|
|
9598
|
-
|
|
9599
|
-
|
|
9824
|
+
const register = React.useCallback((value, record) => {
|
|
9825
|
+
const { records: known } = registryRef.current;
|
|
9826
|
+
known.set(value, record);
|
|
9827
|
+
refresh();
|
|
9828
|
+
return () => {
|
|
9829
|
+
if (known.get(value) !== record)
|
|
9830
|
+
return;
|
|
9831
|
+
known.delete(value);
|
|
9832
|
+
refresh();
|
|
9833
|
+
};
|
|
9834
|
+
}, []);
|
|
9835
|
+
const setElement = React.useCallback((value, element) => {
|
|
9836
|
+
const registry = registryRef.current;
|
|
9837
|
+
if (element) {
|
|
9838
|
+
registry.elements.set(value, element);
|
|
9839
|
+
registry.values.set(element, value);
|
|
9840
|
+
return;
|
|
9841
|
+
}
|
|
9842
|
+
const gone = registry.elements.get(value);
|
|
9843
|
+
if (!gone)
|
|
9844
|
+
return;
|
|
9845
|
+
// The ref lets go before the element leaves the page, so it can still
|
|
9846
|
+
// say whether focus was in it, and where it sat.
|
|
9847
|
+
if (!lostRef.current && gone.contains(getActiveElementInTree(gone))) {
|
|
9848
|
+
lostRef.current = [...pathOf(gone, registry), value];
|
|
9849
|
+
}
|
|
9850
|
+
registry.elements.delete(value);
|
|
9851
|
+
}, []);
|
|
9852
|
+
const onFocus = (value, element) => {
|
|
9853
|
+
setFocused(value);
|
|
9854
|
+
setResting(value);
|
|
9855
|
+
restingPathRef.current = pathOf(element, registryRef.current);
|
|
9856
|
+
};
|
|
9857
|
+
const onBlur = () => setFocused(null);
|
|
9858
|
+
const onKeyDown = (event, item) => {
|
|
9859
|
+
const element = event.currentTarget;
|
|
9860
|
+
// A key on an item inside this one bubbles here too, and is its own.
|
|
9861
|
+
if (event.target !== element ||
|
|
9862
|
+
event.defaultPrevented ||
|
|
9863
|
+
event.altKey ||
|
|
9864
|
+
event.ctrlKey ||
|
|
9865
|
+
event.metaKey ||
|
|
9866
|
+
isComposing$2(event)) {
|
|
9867
|
+
return;
|
|
9868
|
+
}
|
|
9869
|
+
const registry = registryRef.current;
|
|
9870
|
+
const items = shownIn(treeRef.current, registry);
|
|
9871
|
+
const at = items.indexOf(element);
|
|
9872
|
+
const rtl = getComputedStyle(element).direction === 'rtl';
|
|
9873
|
+
const key = (rtl && MIRRORED[event.key]) || event.key;
|
|
9874
|
+
switch (key) {
|
|
9875
|
+
case 'ArrowDown':
|
|
9876
|
+
items[at + 1]?.focus();
|
|
9877
|
+
break;
|
|
9878
|
+
case 'ArrowUp':
|
|
9879
|
+
items[at - 1]?.focus();
|
|
9880
|
+
break;
|
|
9881
|
+
case 'Home':
|
|
9882
|
+
items[0].focus();
|
|
9883
|
+
break;
|
|
9884
|
+
case 'End':
|
|
9885
|
+
items[items.length - 1].focus();
|
|
9886
|
+
break;
|
|
9887
|
+
case 'ArrowRight': {
|
|
9888
|
+
const next = items[at + 1];
|
|
9889
|
+
if (!item.open)
|
|
9890
|
+
act(item, ['open']);
|
|
9891
|
+
else if (next && parentItemOf(next) === element)
|
|
9892
|
+
next.focus();
|
|
9893
|
+
break;
|
|
9894
|
+
}
|
|
9895
|
+
case 'ArrowLeft':
|
|
9896
|
+
if (item.open && !item.disabled)
|
|
9897
|
+
act(item, ['open']);
|
|
9898
|
+
else
|
|
9899
|
+
parentItemOf(element)?.focus();
|
|
9900
|
+
break;
|
|
9901
|
+
// A held key acts once.
|
|
9902
|
+
case 'Enter':
|
|
9903
|
+
if (!event.repeat)
|
|
9904
|
+
act(item, actions.enter);
|
|
9905
|
+
break;
|
|
9906
|
+
case ' ':
|
|
9907
|
+
if (!event.repeat)
|
|
9908
|
+
act(item, actions.space);
|
|
9909
|
+
break;
|
|
9910
|
+
case '*': {
|
|
9911
|
+
const closed = [];
|
|
9912
|
+
registry.records.forEach((record, value) => {
|
|
9913
|
+
if (record.parent === item.parent &&
|
|
9914
|
+
record.isParent &&
|
|
9915
|
+
!record.disabled &&
|
|
9916
|
+
!expanded.includes(value)) {
|
|
9917
|
+
closed.push(value);
|
|
9918
|
+
}
|
|
9919
|
+
});
|
|
9920
|
+
if (closed.length)
|
|
9921
|
+
changeOpen([...expanded, ...closed]);
|
|
9922
|
+
break;
|
|
9923
|
+
}
|
|
9924
|
+
default:
|
|
9925
|
+
// Type-ahead takes a printable character. Anything else, Escape and
|
|
9926
|
+
// Tab included, is left to whatever is around the tree.
|
|
9927
|
+
if (event.key.length !== 1)
|
|
9928
|
+
return;
|
|
9929
|
+
typeaheadMatch(items, typeahead.type(event.key), at, el => typeaheadText(el.firstElementChild))?.focus();
|
|
9930
|
+
}
|
|
9931
|
+
event.preventDefault();
|
|
9932
|
+
};
|
|
9933
|
+
const onClick = (element, item, onToggle) => {
|
|
9934
|
+
element.focus();
|
|
9935
|
+
act(item, onToggle ? ['open'] : actions.click);
|
|
9936
|
+
};
|
|
9937
|
+
return {
|
|
9938
|
+
treeRef,
|
|
9939
|
+
rendersClosed: mode === 'checkbox',
|
|
9940
|
+
tabStop,
|
|
9941
|
+
isOpen,
|
|
9942
|
+
stateOf,
|
|
9943
|
+
register,
|
|
9944
|
+
setElement,
|
|
9945
|
+
onFocus,
|
|
9946
|
+
onBlur,
|
|
9947
|
+
onKeyDown,
|
|
9948
|
+
onClick,
|
|
9949
|
+
};
|
|
9950
|
+
}
|
|
9600
9951
|
|
|
9952
|
+
const FieldContext = React.createContext(false);
|
|
9953
|
+
const ControlContext = React.createContext(false);
|
|
9601
9954
|
/**
|
|
9602
|
-
*
|
|
9603
|
-
*
|
|
9604
|
-
* @function
|
|
9605
|
-
* @param {CodeProps} props - Props for the Code component.
|
|
9606
|
-
* @returns {JSX.Element} The rendered code element.
|
|
9955
|
+
* Hook to detect if the component is inside a Field wrapper.
|
|
9956
|
+
* Form components use this to skip rendering their own Field.
|
|
9607
9957
|
*/
|
|
9608
|
-
const
|
|
9609
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
9610
|
-
color: textColor,
|
|
9611
|
-
backgroundColor: bgColor,
|
|
9612
|
-
...props,
|
|
9613
|
-
});
|
|
9614
|
-
const bulmaClasses = usePrefixedClassNames();
|
|
9615
|
-
const codeClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9616
|
-
return (jsxRuntime.jsx("code", { className: codeClasses || undefined, ...rest, children: children }));
|
|
9617
|
-
};
|
|
9618
|
-
|
|
9619
|
-
// Valid size modifiers for the content class
|
|
9620
|
-
const validSizes = ['small', 'medium', 'large'];
|
|
9958
|
+
const useInsideField = () => React.useContext(FieldContext);
|
|
9621
9959
|
/**
|
|
9622
|
-
*
|
|
9623
|
-
*
|
|
9624
|
-
* @function
|
|
9625
|
-
* @param {ContentProps} props - Props for the Content component.
|
|
9626
|
-
* @returns {JSX.Element} The rendered content block.
|
|
9627
|
-
* @see {@link https://bulma.io/documentation/elements/content/ | Bulma Content documentation}
|
|
9960
|
+
* Hook to detect if the component is inside a Control wrapper.
|
|
9961
|
+
* Form components use this to skip rendering their own Control.
|
|
9628
9962
|
*/
|
|
9629
|
-
const
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9963
|
+
const useInsideControl = () => React.useContext(ControlContext);
|
|
9964
|
+
/** Provider for Field context — used internally by Field component. */
|
|
9965
|
+
const FieldProvider = FieldContext.Provider;
|
|
9966
|
+
/** Provider for Control context — used internally by Control component. */
|
|
9967
|
+
const ControlProvider = ControlContext.Provider;
|
|
9968
|
+
// Each Field-shaping prop, with what takes its place on a `Field` the caller
|
|
9969
|
+
// wraps around the `Control`. `message` needs nothing there, because the
|
|
9970
|
+
// wrapper still renders it inside `Field > Control`. The other Field-level
|
|
9971
|
+
// props (`labelSize`, `labelProps`, `messageColor`) change nothing unless a
|
|
9972
|
+
// `label` or `message` renders, so on their own they keep no `Field`.
|
|
9973
|
+
// `bare-control.test.tsx` holds this list to what each wrapper hands its
|
|
9974
|
+
// `Field` and to which props change its markup, so a new Field-level prop
|
|
9975
|
+
// fails there until it is sorted into one group or the other.
|
|
9976
|
+
const FIELD_SHAPING = [
|
|
9977
|
+
['label', 'label'],
|
|
9978
|
+
['message', undefined],
|
|
9979
|
+
['horizontal', 'horizontal'],
|
|
9980
|
+
['fieldClassName', 'className (for fieldClassName)'],
|
|
9981
|
+
];
|
|
9982
|
+
/** `a`, `a and b`, `a, b and c`. */
|
|
9983
|
+
const listOf = (items) => items.length > 1
|
|
9984
|
+
? `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`
|
|
9985
|
+
: items[0];
|
|
9645
9986
|
/**
|
|
9646
|
-
*
|
|
9647
|
-
*
|
|
9648
|
-
*
|
|
9649
|
-
*
|
|
9650
|
-
*
|
|
9651
|
-
*
|
|
9652
|
-
*
|
|
9653
|
-
*
|
|
9987
|
+
* Whether a convenience form wrapper renders a `Field` of its own (#905).
|
|
9988
|
+
* Never inside an outer `Field`. Inside a `Control` with no `Field` around
|
|
9989
|
+
* it, a `Field` of its own would put a `.field` inside the `.control`, where
|
|
9990
|
+
* Bulma's control styles break (its icon rules are sibling selectors on the
|
|
9991
|
+
* input). So it renders one there only when a prop that shapes the `Field`'s
|
|
9992
|
+
* markup is set (`label`, `message`, `horizontal`, `fieldClassName`), keeping
|
|
9993
|
+
* the markup it always had, and warns in development that the fix is a
|
|
9994
|
+
* `Field` around that `Control`. A prop counts when it is truthy, the same
|
|
9995
|
+
* test that decides whether it changes the `Field`'s output.
|
|
9996
|
+
* Internal; not part of the public API.
|
|
9654
9997
|
*/
|
|
9655
|
-
const
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
const
|
|
9665
|
-
[
|
|
9666
|
-
|
|
9667
|
-
})
|
|
9668
|
-
|
|
9669
|
-
|
|
9998
|
+
const rendersOwnField = (component, options) => {
|
|
9999
|
+
if (options.insideField)
|
|
10000
|
+
return false;
|
|
10001
|
+
if (!options.insideControl)
|
|
10002
|
+
return true;
|
|
10003
|
+
const held = FIELD_SHAPING.filter(([prop]) => options[prop]);
|
|
10004
|
+
if (held.length === 0)
|
|
10005
|
+
return false;
|
|
10006
|
+
const names = held.map(([prop]) => prop);
|
|
10007
|
+
const moved = held
|
|
10008
|
+
.map(([, onField]) => onField)
|
|
10009
|
+
.filter((onField) => onField !== undefined);
|
|
10010
|
+
warnOnce(`${component}:Field-in-bare-Control:${names.join('+')}`, `[bestax-bulma] <${component} ${names.join(' ')}> inside a <Control> ` +
|
|
10011
|
+
`with no <Field> around it renders its own <Field> for ` +
|
|
10012
|
+
`${names.length > 1 ? 'those props' : 'that prop'}, which puts a ` +
|
|
10013
|
+
`.field inside the .control, a nesting Bulma's styles are not ` +
|
|
10014
|
+
`written for. Wrap the <Control> in a <Field> instead` +
|
|
10015
|
+
(moved.length > 0 ? `, and set ${listOf(moved)} on that <Field>.` : '.'));
|
|
10016
|
+
return true;
|
|
10017
|
+
};
|
|
10018
|
+
// Each Control-level prop, with what takes its place on the `Control` the
|
|
10019
|
+
// caller wrapped around the wrapper. `bare-control.test.tsx` holds this to
|
|
10020
|
+
// what each wrapper hands its own `Control`, so a new Control-level prop
|
|
10021
|
+
// fails there until it is added here and passed to `rendersOwnControl`.
|
|
10022
|
+
const ON_CONTROL = {
|
|
10023
|
+
isLoading: 'isLoading',
|
|
10024
|
+
iconLeft: 'iconLeft',
|
|
10025
|
+
iconLeftName: 'iconLeftName',
|
|
10026
|
+
iconLeftSize: 'iconLeftSize',
|
|
10027
|
+
iconRight: 'iconRight',
|
|
10028
|
+
iconRightName: 'iconRightName',
|
|
10029
|
+
iconRightSize: 'iconRightSize',
|
|
10030
|
+
hasIconsLeft: 'hasIconsLeft',
|
|
10031
|
+
hasIconsRight: 'hasIconsRight',
|
|
10032
|
+
isExpanded: 'isExpanded',
|
|
10033
|
+
controlSize: 'size (for controlSize)',
|
|
10034
|
+
controlClassName: 'className (for controlClassName)',
|
|
9670
10035
|
};
|
|
9671
|
-
|
|
9672
10036
|
/**
|
|
9673
|
-
*
|
|
9674
|
-
*
|
|
9675
|
-
*
|
|
9676
|
-
*
|
|
9677
|
-
*
|
|
10037
|
+
* Whether a convenience form wrapper renders a `Control` of its own (#921):
|
|
10038
|
+
* only outside one. Inside a `Control` it renders none, so the props it
|
|
10039
|
+
* would have handed its own do nothing there, and it warns in development,
|
|
10040
|
+
* naming them and saying to set them on that `Control`. An `inline` picker
|
|
10041
|
+
* renders none in either place, so it drops them inside a `Control` or not,
|
|
10042
|
+
* and its warning says so without pointing at a `Control`. A wrapper passes
|
|
10043
|
+
* only the props it hands its own `Control`, as the caller gave them, so a
|
|
10044
|
+
* default the wrapper fills in itself never warns. A prop counts when it is
|
|
10045
|
+
* truthy, since a falsy one would change nothing on a `Control` either.
|
|
10046
|
+
* `iconLeftSize` and `hasIconsLeft` show nothing on a `Control` without a
|
|
10047
|
+
* glyph, so when they move and the caller chose no left icon, the advice
|
|
10048
|
+
* names the wrapper's default glyph too, and following it draws what the
|
|
10049
|
+
* wrapper's own `Control` did.
|
|
10050
|
+
* Internal; not part of the public API.
|
|
9678
10051
|
*/
|
|
9679
|
-
const
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
10052
|
+
const rendersOwnControl = (component, options) => {
|
|
10053
|
+
if (!options.inline && !options.insideControl)
|
|
10054
|
+
return true;
|
|
10055
|
+
const held = Object.keys(ON_CONTROL).filter(prop => options[prop]);
|
|
10056
|
+
if (held.length === 0)
|
|
10057
|
+
return false;
|
|
10058
|
+
const names = held.join(' ');
|
|
10059
|
+
const doNothing = held.length > 1 ? 'those props do' : 'that prop does';
|
|
10060
|
+
let message;
|
|
10061
|
+
if (options.inline) {
|
|
10062
|
+
message =
|
|
10063
|
+
`[bestax-bulma] <${component} inline ${names}> renders no <Control> ` +
|
|
10064
|
+
`in inline mode, inside a <Control> or not, so ${doNothing} ` +
|
|
10065
|
+
`nothing. Leave ${held.length > 1 ? 'them' : 'it'} out of an ` +
|
|
10066
|
+
`inline picker.`;
|
|
10067
|
+
}
|
|
10068
|
+
else {
|
|
10069
|
+
const toSet = held.map(prop => ON_CONTROL[prop]);
|
|
10070
|
+
const needsGlyph = (options.iconLeftSize || options.hasIconsLeft) &&
|
|
10071
|
+
!options.iconLeft &&
|
|
10072
|
+
options.iconLeftName === undefined &&
|
|
10073
|
+
options.defaultIconLeftName;
|
|
10074
|
+
if (needsGlyph) {
|
|
10075
|
+
toSet.push(`iconLeftName="${options.defaultIconLeftName}" (its default icon)`);
|
|
10076
|
+
}
|
|
10077
|
+
message =
|
|
10078
|
+
`[bestax-bulma] <${component} ${names}> inside a <Control> renders ` +
|
|
10079
|
+
`no <Control> of its own, so ${doNothing} nothing there. Set ` +
|
|
10080
|
+
`${listOf(toSet)} on that <Control> instead.`;
|
|
10081
|
+
}
|
|
10082
|
+
// Keyed by the message itself: the props named do not settle the advice
|
|
10083
|
+
// (an empty `iconLeftName` and an unset one name the same props), so two
|
|
10084
|
+
// calls that would advise differently must not share a key.
|
|
10085
|
+
warnOnce(message, message);
|
|
10086
|
+
return false;
|
|
9690
10087
|
};
|
|
9691
|
-
|
|
10088
|
+
const FieldLabelIdContext = React.createContext(undefined);
|
|
9692
10089
|
/**
|
|
9693
|
-
* The
|
|
9694
|
-
*
|
|
9695
|
-
*
|
|
9696
|
-
*
|
|
9697
|
-
*
|
|
10090
|
+
* The id a labeled Field wants its single composed control to adopt (#495).
|
|
10091
|
+
* `undefined` outside a Field, in unlabeled/grouped/addons Fields, or when the
|
|
10092
|
+
* user took over the association with an explicit `labelProps.htmlFor`.
|
|
10093
|
+
* Consumed through `useFieldLabelTarget` by the single-control bases
|
|
10094
|
+
* (InputBase, SelectBase, TextAreaBase, and the date and time picker bases
|
|
10095
|
+
* unless inline, #968) and, through `useAutoLabelId`, by the convenience
|
|
10096
|
+
* inputs that render an input of their own (#939). Read it only through
|
|
10097
|
+
* those, which report what they take: a control that read it directly would
|
|
10098
|
+
* report nothing and lose its label (#1004), and
|
|
10099
|
+
* `__tests__/field-label-readers.test.ts` fails on one. Internal; not part of
|
|
10100
|
+
* the public API.
|
|
9698
10101
|
*/
|
|
9699
|
-
const
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
...props,
|
|
9704
|
-
});
|
|
9705
|
-
const bulmaClasses = usePrefixedClassNames();
|
|
9706
|
-
const emphasisClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9707
|
-
return (jsxRuntime.jsx("em", { className: emphasisClasses || undefined, ...rest, children: children }));
|
|
9708
|
-
};
|
|
9709
|
-
|
|
10102
|
+
const useFieldLabelId = () => React.useContext(FieldLabelIdContext);
|
|
10103
|
+
/** Provider for the Field label-target id — used internally by Field. */
|
|
10104
|
+
const FieldLabelIdProvider = FieldLabelIdContext.Provider;
|
|
10105
|
+
const FieldLabelElementIdContext = React.createContext(undefined);
|
|
9710
10106
|
/**
|
|
9711
|
-
*
|
|
9712
|
-
*
|
|
9713
|
-
*
|
|
9714
|
-
*
|
|
9715
|
-
*
|
|
9716
|
-
*
|
|
9717
|
-
* @param {FigureCaptionProps} props - Props for the FigureCaption component.
|
|
9718
|
-
* @returns {JSX.Element} The rendered figcaption element.
|
|
10107
|
+
* The id of a labeled Field's own `<label>`, for a group control (Radios,
|
|
10108
|
+
* Checkboxes, Rate, DateRangeInput and DateRangeInputBase) to point
|
|
10109
|
+
* `aria-labelledby` at, since a group cannot take the label's `htmlFor`
|
|
10110
|
+
* (#939, #1005). Set under the same conditions as
|
|
10111
|
+
* {@link useFieldLabelId}. Consumed through `useAutoLabelledBy`.
|
|
10112
|
+
* Internal; not part of the public API.
|
|
9719
10113
|
*/
|
|
9720
|
-
const
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
10114
|
+
const useFieldLabelElementId = () => React.useContext(FieldLabelElementIdContext);
|
|
10115
|
+
/** Provider for the Field label's own id, used internally by Field. */
|
|
10116
|
+
const FieldLabelElementIdProvider = FieldLabelElementIdContext.Provider;
|
|
10117
|
+
const FieldLabelForContext = React.createContext({});
|
|
10118
|
+
/**
|
|
10119
|
+
* The nearest labeled Field's `<label>`: what it points `htmlFor` at, the id
|
|
10120
|
+
* it generated or the caller's own `labelProps.htmlFor`, and the id the label
|
|
10121
|
+
* renders with, if it has one. An unlabeled Field passes both through
|
|
10122
|
+
* together, so a control in the inner Field of a horizontal layout can tell
|
|
10123
|
+
* the outer label names it, and point at that label by its id, as a range
|
|
10124
|
+
* Slider's thumbs (#981) and Autocomplete's and Taginput's suggestion lists
|
|
10125
|
+
* (#998, #1082) do. The
|
|
10126
|
+
* `htmlFor` is only ever compared with a control's own id, never adopted, so
|
|
10127
|
+
* it hands out no id for a control. It keeps the generated id after the
|
|
10128
|
+
* label drops a `for` nothing took (#1004), which no control's id matches
|
|
10129
|
+
* then, so the value does not change under the content that reported it.
|
|
10130
|
+
* The `id` is set only while that label renders with it. Unlike
|
|
10131
|
+
* {@link useFieldLabelId}, it is set in a `grouped` or `hasAddons` Field
|
|
10132
|
+
* too, so a label wired by hand names the control its `for` picks in those
|
|
10133
|
+
* rows as well. Consumed through `useAutoLabelId`.
|
|
10134
|
+
* Internal; not part of the public API.
|
|
10135
|
+
*/
|
|
10136
|
+
const useFieldLabelFor = () => React.useContext(FieldLabelForContext);
|
|
10137
|
+
/** Provider for the Field label's `htmlFor` target and id, used internally by Field. */
|
|
10138
|
+
const FieldLabelForProvider = FieldLabelForContext.Provider;
|
|
10139
|
+
const FieldLabelForReportContext = React.createContext(undefined);
|
|
10140
|
+
/**
|
|
10141
|
+
* Tells the nearest labeled Field that this content took its generated id
|
|
10142
|
+
* while `takesFor` is true (#1004). Once the Field's content has mounted, its
|
|
10143
|
+
* label keeps the generated `for` only while something has said so, so the
|
|
10144
|
+
* label renders none over a group, a `Checkbox`, `Radio` or `Switch`, an
|
|
10145
|
+
* inner `Field`, an input with an `id` of its own, markup of your own, or
|
|
10146
|
+
* nothing at all. Anything that puts the id from {@link useFieldLabelId} on
|
|
10147
|
+
* an element has to say so, or the label drops the `for` that names it, and
|
|
10148
|
+
* content that takes no id has nothing to do. Set under the same conditions
|
|
10149
|
+
* as {@link useFieldLabelId}, so a label wired by hand and a `grouped` or
|
|
10150
|
+
* `hasAddons` Field hear nothing. It reports from a layout effect, which a
|
|
10151
|
+
* server never runs and a hydrating client runs only after its first render,
|
|
10152
|
+
* so that render writes the `for` the way the server did.
|
|
10153
|
+
* Internal; not part of the public API.
|
|
10154
|
+
*/
|
|
10155
|
+
const useReportFieldLabelFor = (takesFor) => {
|
|
10156
|
+
const report = React.useContext(FieldLabelForReportContext);
|
|
10157
|
+
useClientLayoutEffect(() => (takesFor ? report?.() : undefined), [report, takesFor]);
|
|
9729
10158
|
};
|
|
10159
|
+
/** Provider for the labeled Field's report function, used internally by Field. */
|
|
10160
|
+
const FieldLabelForReportProvider = FieldLabelForReportContext.Provider;
|
|
9730
10161
|
/**
|
|
9731
|
-
* The
|
|
9732
|
-
*
|
|
9733
|
-
*
|
|
9734
|
-
*
|
|
9735
|
-
* @
|
|
10162
|
+
* The id a control with one input of its own renders with: the caller's
|
|
10163
|
+
* `id` when one arrived, otherwise the one a labeled Field offers (#495),
|
|
10164
|
+
* unless it has no input to put it on (`hasInput: false`, as in an `inline`
|
|
10165
|
+
* picker). It also tells that Field when it took the Field's id, through
|
|
10166
|
+
* {@link useReportFieldLabelFor}, so the label keeps its `for` (#1004). Used
|
|
10167
|
+
* by the single-control bases. Internal; not part of the public API.
|
|
9736
10168
|
*/
|
|
9737
|
-
const
|
|
9738
|
-
const
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
});
|
|
9743
|
-
const bulmaClasses = usePrefixedClassNames();
|
|
9744
|
-
const figureClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9745
|
-
return (jsxRuntime.jsx("figure", { className: figureClasses || undefined, ...rest, children: children }));
|
|
10169
|
+
const useFieldLabelTarget = (id, hasInput = true) => {
|
|
10170
|
+
const fieldLabelId = useFieldLabelId();
|
|
10171
|
+
const target = id ?? (hasInput ? fieldLabelId : undefined);
|
|
10172
|
+
useReportFieldLabelFor(fieldLabelId !== undefined && target === fieldLabelId);
|
|
10173
|
+
return target;
|
|
9746
10174
|
};
|
|
10175
|
+
const RadiosContext = React.createContext(undefined);
|
|
10176
|
+
const CheckboxesContext = React.createContext(undefined);
|
|
9747
10177
|
/**
|
|
9748
|
-
*
|
|
9749
|
-
*
|
|
9750
|
-
* @example
|
|
9751
|
-
* <Figure>
|
|
9752
|
-
* <img src="image.jpg" alt="Description" />
|
|
9753
|
-
* <Figure.Caption>Image caption text</Figure.Caption>
|
|
9754
|
-
* </Figure>
|
|
10178
|
+
* Hook to read the full surrounding `<Radios>` group context (name + selection).
|
|
10179
|
+
* Returns `undefined` when not inside a `<Radios>` group.
|
|
9755
10180
|
*/
|
|
9756
|
-
const
|
|
9757
|
-
Caption: FigureCaption,
|
|
9758
|
-
}, 'Figure');
|
|
9759
|
-
|
|
10181
|
+
const useRadiosGroup = () => React.useContext(RadiosContext);
|
|
9760
10182
|
/**
|
|
9761
|
-
*
|
|
9762
|
-
* `
|
|
9763
|
-
* `iconLeft`/`iconRight`, `IconText`'s `iconProps`.
|
|
9764
|
-
*
|
|
9765
|
-
* One copy, imported by both consumers: two hand-maintained copies, one per
|
|
9766
|
-
* consumer, is how the deprecated `icon` path came to crash both (#663).
|
|
9767
|
-
*
|
|
9768
|
-
* Its own module rather than `Icon.tsx` because `src/index.ts` wildcard-exports
|
|
9769
|
-
* that file, and everything published there is public forever. `polymorphic.ts`
|
|
9770
|
-
* makes the same call for `isCustomElement`: an internal discriminator is not
|
|
9771
|
-
* something to support for the life of the package.
|
|
9772
|
-
*
|
|
9773
|
-
* It tests each member's VALUE, not merely its key, and only after everything
|
|
9774
|
-
* React owns is out of the way. `'icon' in value` was enough
|
|
9775
|
-
* to claim a Font Awesome `IconDefinition` — `{ prefix, iconName, icon: [w, h, …,
|
|
9776
|
-
* path] }` — whose `icon` is a path array rather than a class string. That object
|
|
9777
|
-
* is not a renderable node either, so the honest outcome is the one this slot has
|
|
9778
|
-
* always had for it: the node branch, and React's own "Objects are not valid as a
|
|
9779
|
-
* React child". Claiming it here instead rendered a blank container that still
|
|
9780
|
-
* reserved layout.
|
|
9781
|
-
*
|
|
9782
|
-
* A member added to `IconProps` needs a line here, and a missed one is a crash
|
|
9783
|
-
* rather than a fallthrough. That is the cost of a slot taking either a props
|
|
9784
|
-
* object or a node; keeping the guard in one place is what keeps the cost to a
|
|
9785
|
-
* single line.
|
|
10183
|
+
* Hook to read the full surrounding `<Checkboxes>` group context.
|
|
10184
|
+
* Returns `undefined` when not inside a `<Checkboxes>` group.
|
|
9786
10185
|
*/
|
|
9787
|
-
|
|
9788
|
-
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
// test below claimed it and `Control` spread it into `<Icon>` as props —
|
|
9793
|
-
// rendering the portal's child locally instead of in its container. Every
|
|
9794
|
-
// React internal carries `$$typeof`, so testing for it covers lazy, context
|
|
9795
|
-
// and whatever React adds next, rather than portals alone.
|
|
9796
|
-
if (React.isValidElement(value) || '$$typeof' in value)
|
|
9797
|
-
return false;
|
|
9798
|
-
const candidate = value;
|
|
9799
|
-
return (typeof candidate.name === 'string' ||
|
|
9800
|
-
typeof candidate.icon === 'string' ||
|
|
9801
|
-
'children' in candidate);
|
|
9802
|
-
}
|
|
10186
|
+
const useCheckboxesGroup = () => React.useContext(CheckboxesContext);
|
|
10187
|
+
/** Provider for the Radios group context — used internally by Radios. */
|
|
10188
|
+
const RadiosProvider = RadiosContext.Provider;
|
|
10189
|
+
/** Provider for the Checkboxes group context — used internally by Checkboxes. */
|
|
10190
|
+
const CheckboxesProvider = CheckboxesContext.Provider;
|
|
9803
10191
|
|
|
9804
10192
|
/**
|
|
9805
|
-
* The
|
|
10193
|
+
* The values the Checkbox `color` prop accepts, as a readonly tuple.
|
|
9806
10194
|
*
|
|
9807
|
-
*
|
|
9808
|
-
*
|
|
9809
|
-
*
|
|
9810
|
-
*
|
|
9811
|
-
*/
|
|
9812
|
-
const IconTextComponent = ({ className, textColor, color, bgColor, iconProps, children, items, ...props }) => {
|
|
9813
|
-
/**
|
|
9814
|
-
* Generates Bulma helper classes and separates out remaining props.
|
|
9815
|
-
*/
|
|
9816
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
9817
|
-
color: textColor ?? color,
|
|
9818
|
-
backgroundColor: bgColor,
|
|
9819
|
-
...props,
|
|
9820
|
-
});
|
|
9821
|
-
const bulmaClasses = usePrefixedClassNames('icon-text');
|
|
9822
|
-
const iconTextClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9823
|
-
return (jsxRuntime.jsx("span", { className: iconTextClasses, ...rest, children: items ? (items.map((item, index) => (jsxRuntime.jsxs(React.Fragment, { children: [item.iconProps &&
|
|
9824
|
-
(isIconProps(item.iconProps) ? (jsxRuntime.jsx(Icon, { ...item.iconProps })) : (jsxRuntime.jsx(Icon, { children: item.iconProps }))), item.text && jsxRuntime.jsx("span", { children: item.text })] }, index)))) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconProps &&
|
|
9825
|
-
(isIconProps(iconProps) ? (jsxRuntime.jsx(Icon, { ...iconProps })) : (jsxRuntime.jsx(Icon, { children: iconProps }))), children && jsxRuntime.jsx("span", { children: children })] })) }));
|
|
9826
|
-
};
|
|
9827
|
-
const IconText = withSubComponents(IconTextComponent, { Icon }, 'IconText');
|
|
9828
|
-
|
|
9829
|
-
/**
|
|
9830
|
-
* The `Image` component wraps images, iframes, or custom content in a Bulma-styled container, supporting fixed sizes, aspect ratios, rounded corners, retina images, and all Bulma helper props for color and spacing.
|
|
10195
|
+
* `CheckboxProps['color']` is typed from it, so the two list the same values.
|
|
10196
|
+
* Map over it to build a color picker, or check a value that arrives at
|
|
10197
|
+
* runtime before passing it in: the component adds no color class for a value
|
|
10198
|
+
* outside the tuple.
|
|
9831
10199
|
*
|
|
9832
|
-
* @
|
|
9833
|
-
*
|
|
9834
|
-
*
|
|
9835
|
-
*
|
|
10200
|
+
* @example
|
|
10201
|
+
* import { Checkbox, checkboxColors } from '@allxsmith/bestax-bulma';
|
|
10202
|
+
*
|
|
10203
|
+
* checkboxColors.map(color => (
|
|
10204
|
+
* <Checkbox key={color} color={color}>
|
|
10205
|
+
* {color}
|
|
10206
|
+
* </Checkbox>
|
|
10207
|
+
* ));
|
|
9836
10208
|
*/
|
|
9837
|
-
const
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
});
|
|
9846
|
-
const bulmaClasses = usePrefixedClassNames('image', {
|
|
9847
|
-
[`is-${size}`]: size,
|
|
9848
|
-
'has-ratio': size && typeof size === 'string' && size.includes('by'),
|
|
9849
|
-
});
|
|
9850
|
-
const imageClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9851
|
-
// Default tag logic: if "as" is provided, use it.
|
|
9852
|
-
// If not, use <figure> for aspect ratios or children, <div> otherwise.
|
|
9853
|
-
let Tag;
|
|
9854
|
-
if (as) {
|
|
9855
|
-
Tag = as;
|
|
9856
|
-
}
|
|
9857
|
-
else if (size && typeof size === 'string' && size.includes('by')) {
|
|
9858
|
-
Tag = 'figure';
|
|
9859
|
-
}
|
|
9860
|
-
else {
|
|
9861
|
-
Tag = 'div';
|
|
9862
|
-
}
|
|
9863
|
-
const roundedClass = usePrefixedClassNames('is-rounded');
|
|
9864
|
-
const content = children ? (children) : (jsxRuntime.jsx("img", { className: classNames({ [roundedClass]: isRounded }) || undefined, src: src, alt: alt, ...(isRetina && src ? { srcSet: `${src} 2x` } : {}) }));
|
|
9865
|
-
return (jsxRuntime.jsx(Tag, { className: imageClasses, ...rest, children: content }));
|
|
9866
|
-
};
|
|
9867
|
-
|
|
10209
|
+
const checkboxColors = [
|
|
10210
|
+
'primary',
|
|
10211
|
+
'link',
|
|
10212
|
+
'info',
|
|
10213
|
+
'success',
|
|
10214
|
+
'warning',
|
|
10215
|
+
'danger',
|
|
10216
|
+
];
|
|
9868
10217
|
/**
|
|
9869
|
-
*
|
|
9870
|
-
*
|
|
9871
|
-
* It doesn't wrap in the middle and isn't drawn as a key itself. It sets no
|
|
9872
|
-
* font size, so the keys in it are the size of a key on its own.
|
|
10218
|
+
* The values the Checkbox `size` prop accepts, as a readonly tuple.
|
|
9873
10219
|
*
|
|
9874
|
-
*
|
|
9875
|
-
*
|
|
9876
|
-
*
|
|
9877
|
-
*
|
|
10220
|
+
* `CheckboxProps['size']` is typed from it, so the two list the same values.
|
|
10221
|
+
* Use it to offer a size choice or to check a value that arrives at runtime:
|
|
10222
|
+
* the component adds no size class for a value outside the tuple. These are
|
|
10223
|
+
* element sizes, not the spacing scale in `validSizes`.
|
|
9878
10224
|
*
|
|
9879
10225
|
* @example
|
|
9880
|
-
*
|
|
9881
|
-
* <Kbd>Ctrl</Kbd>
|
|
9882
|
-
* <Kbd>Shift</Kbd>
|
|
9883
|
-
* <Kbd>P</Kbd>
|
|
9884
|
-
* </Kbd.Group>
|
|
10226
|
+
* import { checkboxSizes } from '@allxsmith/bestax-bulma';
|
|
9885
10227
|
*
|
|
9886
|
-
*
|
|
9887
|
-
* <Kbd.Group separator="then">
|
|
9888
|
-
* <Kbd>G</Kbd>
|
|
9889
|
-
* <Kbd>I</Kbd>
|
|
9890
|
-
* </Kbd.Group>
|
|
10228
|
+
* type CheckboxSize = (typeof checkboxSizes)[number];
|
|
9891
10229
|
*/
|
|
9892
|
-
const
|
|
9893
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
9894
|
-
color: textColor,
|
|
9895
|
-
...props,
|
|
9896
|
-
});
|
|
9897
|
-
const groupClass = usePrefixedClassNames('kbd-group');
|
|
9898
|
-
const separatorClass = usePrefixedClassNames('kbd-separator');
|
|
9899
|
-
// Null, undefined and booleans drop out, and Fragments are opened up, so
|
|
9900
|
-
// an empty Fragment leaves no separator behind and the keys in one are
|
|
9901
|
-
// separated like the rest. The spaces are part of the text, so a screen
|
|
9902
|
-
// reader reads "Ctrl plus S" rather than one run-together word, whatever
|
|
9903
|
-
// the CSS does.
|
|
9904
|
-
const keys = flattenChildren(children);
|
|
9905
|
-
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))) }));
|
|
9906
|
-
});
|
|
9907
|
-
KbdGroup.displayName = 'Kbd.Group';
|
|
10230
|
+
const checkboxSizes = ['small', 'normal', 'medium', 'large'];
|
|
9908
10231
|
/**
|
|
9909
|
-
* The `
|
|
9910
|
-
*
|
|
9911
|
-
* It only shows the key: it doesn't listen for it. The key takes its colors
|
|
9912
|
-
* from the text it sits in, and its size in `em`, so it fits a paragraph, a
|
|
9913
|
-
* title or a filled button as it is, and `textSize` sizes it outright. For a
|
|
9914
|
-
* combination or a sequence, put the keys in a `Kbd.Group`. What tells
|
|
9915
|
-
* assistive tech a control has a shortcut is `aria-keyshortcuts` on that
|
|
9916
|
-
* control, with `Kbd` as the hint people see next to it.
|
|
10232
|
+
* The `Checkbox` component provides a Bulma-styled checkbox input.
|
|
9917
10233
|
*
|
|
9918
10234
|
* @function
|
|
9919
|
-
* @param {
|
|
9920
|
-
* @
|
|
9921
|
-
* @returns {JSX.Element} The rendered key.
|
|
10235
|
+
* @param {CheckboxProps} props - Props for the Checkbox component.
|
|
10236
|
+
* @returns {JSX.Element} The rendered checkbox element.
|
|
9922
10237
|
*
|
|
9923
10238
|
* @example
|
|
9924
|
-
*
|
|
10239
|
+
* // Basic checkbox
|
|
10240
|
+
* <Checkbox>Accept terms</Checkbox>
|
|
9925
10241
|
*
|
|
9926
10242
|
* @example
|
|
9927
|
-
*
|
|
10243
|
+
* // Inside a group
|
|
10244
|
+
* <Checkboxes name="tags" defaultValue={['react']}>
|
|
10245
|
+
* <Checkbox value="react">React</Checkbox>
|
|
10246
|
+
* <Checkbox value="vue">Vue</Checkbox>
|
|
10247
|
+
* </Checkboxes>
|
|
9928
10248
|
*/
|
|
9929
|
-
const
|
|
10249
|
+
const Checkbox = React.forwardRef(({ color, size, className, children, textColor, disabled, name, value, checked, defaultChecked, indeterminate, onChange, ...props }, ref) => {
|
|
9930
10250
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
9931
10251
|
color: textColor,
|
|
9932
|
-
backgroundColor: bgColor,
|
|
9933
10252
|
...props,
|
|
9934
10253
|
});
|
|
9935
|
-
|
|
9936
|
-
//
|
|
9937
|
-
//
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
const
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
10254
|
+
// The input's own ref, merged with the forwarded one. A callback ref's
|
|
10255
|
+
// return value is handed back, so React 19 still runs a cleanup it
|
|
10256
|
+
// returns, as it did when the ref went straight to the input.
|
|
10257
|
+
const inputRef = React.useRef(null);
|
|
10258
|
+
const setRefs = React.useCallback((node) => {
|
|
10259
|
+
inputRef.current = node;
|
|
10260
|
+
if (typeof ref === 'function')
|
|
10261
|
+
return ref(node);
|
|
10262
|
+
if (ref)
|
|
10263
|
+
ref.current = node;
|
|
10264
|
+
}, [ref]);
|
|
10265
|
+
// `indeterminate` is a DOM property with no attribute, so it's set on the
|
|
10266
|
+
// input rather than rendered. A click clears it, so this runs after every
|
|
10267
|
+
// render, not only when the prop changes. Unset, it's left alone, so a
|
|
10268
|
+
// ref that sets the property itself still works. `ownsIndeterminateRef`
|
|
10269
|
+
// remembers that this component set it, so a prop that goes back to unset
|
|
10270
|
+
// clears the dash once instead of leaving it on.
|
|
10271
|
+
const ownsIndeterminateRef = React.useRef(false);
|
|
10272
|
+
useClientLayoutEffect(() => {
|
|
10273
|
+
if (indeterminate !== undefined) {
|
|
10274
|
+
ownsIndeterminateRef.current = true;
|
|
10275
|
+
inputRef.current.indeterminate = indeterminate;
|
|
10276
|
+
}
|
|
10277
|
+
else if (ownsIndeterminateRef.current) {
|
|
10278
|
+
ownsIndeterminateRef.current = false;
|
|
10279
|
+
inputRef.current.indeterminate = false;
|
|
10280
|
+
}
|
|
9961
10281
|
});
|
|
9962
|
-
|
|
9963
|
-
|
|
10282
|
+
// Inherit name + selection state from a surrounding <Checkboxes> group.
|
|
10283
|
+
// Local props always win over the group (explicit > implicit).
|
|
10284
|
+
const group = useCheckboxesGroup();
|
|
10285
|
+
const effectiveName = name ?? group?.name;
|
|
10286
|
+
// Group-managed checked state — only when the group is in
|
|
10287
|
+
// controlled/uncontrolled mode (group.value is defined) AND this Checkbox
|
|
10288
|
+
// has a value to compare against. Local `checked` always wins.
|
|
10289
|
+
const groupManaged = group?.value !== undefined && value !== undefined;
|
|
10290
|
+
const groupHas = groupManaged && group.value.includes(String(value));
|
|
10291
|
+
const effectiveChecked = checked !== undefined ? checked : groupManaged ? groupHas : undefined;
|
|
10292
|
+
// When the group manages checked, suppress local defaultChecked to avoid
|
|
10293
|
+
// the controlled/uncontrolled React warning.
|
|
10294
|
+
const effectiveDefaultChecked = groupManaged ? undefined : defaultChecked;
|
|
10295
|
+
const handleChange = React.useCallback((e) => {
|
|
10296
|
+
// The click that got here cleared the mixed state. Put it back now,
|
|
10297
|
+
// since a click that changes no state renders nothing to do it.
|
|
10298
|
+
if (indeterminate !== undefined)
|
|
10299
|
+
e.target.indeterminate = indeterminate;
|
|
10300
|
+
// Local onChange always fires.
|
|
10301
|
+
onChange?.(e);
|
|
10302
|
+
// Dispatch to the group additionally — toggle this value's
|
|
10303
|
+
// membership in the group's array.
|
|
10304
|
+
if (group?.onChange && value !== undefined) {
|
|
10305
|
+
const valStr = String(value);
|
|
10306
|
+
const currentArr = group.value ?? [];
|
|
10307
|
+
const next = e.target.checked
|
|
10308
|
+
? currentArr.includes(valStr)
|
|
10309
|
+
? currentArr
|
|
10310
|
+
: [...currentArr, valStr]
|
|
10311
|
+
: currentArr.filter(v => v !== valStr);
|
|
10312
|
+
group.onChange(next);
|
|
10313
|
+
}
|
|
10314
|
+
}, [onChange, group, value, indeterminate]);
|
|
10315
|
+
const mainClass = usePrefixedClassNames('styled-checkbox', 'checkbox', {
|
|
10316
|
+
[`is-${color}`]: color && checkboxColors.includes(color),
|
|
10317
|
+
[`is-${size}`]: size && checkboxSizes.includes(size),
|
|
9964
10318
|
});
|
|
9965
|
-
const
|
|
9966
|
-
|
|
10319
|
+
const checkboxClass = classNames(mainClass, bulmaHelperClasses, className);
|
|
10320
|
+
const checkClass = usePrefixedClassNames('check');
|
|
10321
|
+
const controlLabelClass = usePrefixedClassNames('control-label');
|
|
10322
|
+
return (jsxRuntime.jsxs("label", { className: checkboxClass, children: [jsxRuntime.jsx("input", { ref: setRefs, type: "checkbox", disabled: disabled, name: effectiveName, value: value, checked: effectiveChecked, defaultChecked: effectiveDefaultChecked, onChange: handleChange, ...rest }), jsxRuntime.jsx("span", { className: checkClass }), children && jsxRuntime.jsx("span", { className: controlLabelClass, children: children })] }));
|
|
9967
10323
|
});
|
|
9968
|
-
|
|
10324
|
+
Checkbox.displayName = 'Checkbox';
|
|
9969
10325
|
|
|
10326
|
+
const validTreeViewSizes = ['small', 'medium', 'large'];
|
|
10327
|
+
// Not exported, so they stay out of the public API that `index.ts` re-exports.
|
|
10328
|
+
const TreeViewContext = React.createContext(null);
|
|
10329
|
+
const TOP = { path: [], hidden: false };
|
|
10330
|
+
const BranchContext = React.createContext(TOP);
|
|
10331
|
+
/** The box's input lets the row's click toggle it, so a change on its own does nothing. */
|
|
10332
|
+
const ignoreChange = () => { };
|
|
10333
|
+
/** Whether an `icon` was given something to render. */
|
|
10334
|
+
const isGiven = (node) => node !== undefined &&
|
|
10335
|
+
node !== null &&
|
|
10336
|
+
typeof node !== 'boolean' &&
|
|
10337
|
+
node !== '';
|
|
9970
10338
|
/**
|
|
9971
|
-
* The `
|
|
10339
|
+
* The `TreeView` component renders a tree of items you browse and pick from, the way a file explorer works: one tab stop, the arrow keys to move, and Right and Left to open and close.
|
|
9972
10340
|
*
|
|
9973
|
-
*
|
|
9974
|
-
*
|
|
9975
|
-
*
|
|
9976
|
-
|
|
9977
|
-
const ListItem = ({ className, textColor, bgColor, children, ...props }) => {
|
|
9978
|
-
/**
|
|
9979
|
-
* Generates Bulma helper classes and separates out remaining props.
|
|
9980
|
-
*/
|
|
9981
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
9982
|
-
color: textColor,
|
|
9983
|
-
backgroundColor: bgColor,
|
|
9984
|
-
...props,
|
|
9985
|
-
});
|
|
9986
|
-
const bulmaClasses = usePrefixedClassNames();
|
|
9987
|
-
const itemClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
9988
|
-
return (jsxRuntime.jsx("li", { className: itemClasses || undefined, ...rest, children: children }));
|
|
9989
|
-
};
|
|
9990
|
-
|
|
9991
|
-
/**
|
|
9992
|
-
* The `Loader` component renders Bulma's `.loader`, a small spinning ring for inline loading states.
|
|
10341
|
+
* It's the APG Tree View pattern, drawn to look like Bulma's menu. It isn't
|
|
10342
|
+
* for site navigation: items aren't links, and a sidebar whose sections open
|
|
10343
|
+
* and close is `Menu`'s job. The root owns which items are open, through
|
|
10344
|
+
* `expanded`, `defaultExpanded` and `onExpandedChange`.
|
|
9993
10345
|
*
|
|
9994
|
-
*
|
|
9995
|
-
*
|
|
9996
|
-
*
|
|
9997
|
-
*
|
|
10346
|
+
* `selectionMode` picks one of three trees. With `none`, nothing is picked.
|
|
10347
|
+
* With `single`, one item is, and `selected` says which. With `checkbox`,
|
|
10348
|
+
* each item has a box, a check reaches every enabled item under it, closed
|
|
10349
|
+
* branches included, and a parent with some of its items checked is mixed.
|
|
10350
|
+
* `selected` is read in a `single` tree only, and `checked` in a `checkbox`
|
|
10351
|
+
* tree only. Selection never follows focus.
|
|
9998
10352
|
*
|
|
9999
|
-
*
|
|
10000
|
-
*
|
|
10001
|
-
*
|
|
10002
|
-
* @returns {JSX.Element} The rendered loader element.
|
|
10353
|
+
* Disabled items stay reachable from the keys, so a screen reader finds
|
|
10354
|
+
* them. The tree needs a name, from `aria-label` or `aria-labelledby`, and a
|
|
10355
|
+
* development build warns when it has neither.
|
|
10003
10356
|
*
|
|
10004
|
-
* @
|
|
10005
|
-
*
|
|
10357
|
+
* @function
|
|
10358
|
+
* @param {TreeViewProps} props - Props for the TreeView component.
|
|
10359
|
+
* @param {React.Ref<HTMLUListElement>} ref - Forwarded ref to the `<ul>`.
|
|
10360
|
+
* @returns {JSX.Element} The rendered tree.
|
|
10361
|
+
* @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/treeview/ | APG Tree View Pattern}
|
|
10006
10362
|
*
|
|
10007
10363
|
* @example
|
|
10008
|
-
* <
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10364
|
+
* <TreeView aria-label="Files" selectionMode="single" defaultExpanded={['src']}>
|
|
10365
|
+
* <TreeView.Item value="src" label="src" icon="folder">
|
|
10366
|
+
* <TreeView.Item value="src/index.ts" label="index.ts" icon="file" />
|
|
10367
|
+
* </TreeView.Item>
|
|
10368
|
+
* <TreeView.Item value="package.json" label="package.json" icon="file" />
|
|
10369
|
+
* </TreeView>
|
|
10370
|
+
*/
|
|
10371
|
+
const TreeViewRoot = React.forwardRef(function TreeView({ children, selectionMode = 'none', selected, defaultSelected = null, onSelectedChange, checked, defaultChecked = [], onCheckedChange, expanded, defaultExpanded = [], onExpandedChange, size, className, ...props }, ref) {
|
|
10372
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
10373
|
+
const engine = useTreeView({
|
|
10374
|
+
mode: selectionMode,
|
|
10375
|
+
selected,
|
|
10376
|
+
defaultSelected,
|
|
10377
|
+
onSelectedChange,
|
|
10378
|
+
checked,
|
|
10379
|
+
defaultChecked,
|
|
10380
|
+
onCheckedChange,
|
|
10381
|
+
expanded,
|
|
10382
|
+
defaultExpanded,
|
|
10383
|
+
onExpandedChange,
|
|
10384
|
+
});
|
|
10385
|
+
const { treeRef } = engine;
|
|
10386
|
+
const setRefs = React.useCallback((node) => {
|
|
10387
|
+
treeRef.current = node;
|
|
10388
|
+
if (typeof ref === 'function')
|
|
10389
|
+
ref(node);
|
|
10390
|
+
else if (ref)
|
|
10391
|
+
ref.current = node;
|
|
10392
|
+
}, [ref, treeRef]);
|
|
10393
|
+
const named = Boolean(rest['aria-label'] || rest['aria-labelledby']);
|
|
10394
|
+
React.useEffect(() => {
|
|
10395
|
+
if (!named) {
|
|
10396
|
+
warnOnce('TreeView:unnamed', '[bestax-bulma] <TreeView> has no accessible name. Pass ' +
|
|
10397
|
+
'aria-label or aria-labelledby, so a screen reader can say what ' +
|
|
10398
|
+
'the tree holds.');
|
|
10399
|
+
}
|
|
10400
|
+
}, [named]);
|
|
10401
|
+
const rootClass = usePrefixedClassNames('tree-view', {
|
|
10402
|
+
[`is-${size}`]: !!size && validTreeViewSizes.includes(size),
|
|
10403
|
+
});
|
|
10404
|
+
// The props are spread first, so the role and the attributes the tree
|
|
10405
|
+
// owns win over anything a caller passes along.
|
|
10406
|
+
return (jsxRuntime.jsx(TreeViewContext.Provider, { value: engine, children: jsxRuntime.jsx(BranchContext.Provider, { value: TOP, children: jsxRuntime.jsx("ul", { ...rest, ref: setRefs, className: classNames(rootClass, bulmaHelperClasses, className), role: "tree", "aria-multiselectable": engine.rendersClosed || undefined, children: children }) }) }));
|
|
10018
10407
|
});
|
|
10019
|
-
Loader.displayName = 'Loader';
|
|
10020
|
-
|
|
10021
10408
|
/**
|
|
10022
|
-
*
|
|
10409
|
+
* One item in the tree: a row with its chevron, its box, its icon and its label, and, while it's open, a group of the items under it.
|
|
10023
10410
|
*
|
|
10024
10411
|
* @function
|
|
10025
|
-
* @param {
|
|
10026
|
-
* @
|
|
10027
|
-
* @
|
|
10028
|
-
*/
|
|
10029
|
-
const
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
const
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
const
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10412
|
+
* @param {TreeViewItemProps} props - Props for TreeView.Item.
|
|
10413
|
+
* @param {React.Ref<HTMLLIElement>} ref - Forwarded ref to the `<li>`.
|
|
10414
|
+
* @returns {JSX.Element | null} The rendered item, or nothing under a closed one.
|
|
10415
|
+
*/
|
|
10416
|
+
const TreeViewItem = React.forwardRef(function TreeViewItem({ value, label, icon, children, hasChildren = false, disabled = false, className, onClick, onKeyDown, onFocus, onBlur, ...props }, ref) {
|
|
10417
|
+
const tree = React.useContext(TreeViewContext);
|
|
10418
|
+
const branch = React.useContext(BranchContext);
|
|
10419
|
+
const labelId = React.useId();
|
|
10420
|
+
const hasItems = React.Children.toArray(children).length > 0;
|
|
10421
|
+
const isParent = hasItems || hasChildren;
|
|
10422
|
+
const open = isParent && !!tree?.isOpen(value);
|
|
10423
|
+
const parent = branch.path[branch.path.length - 1] ?? null;
|
|
10424
|
+
const itemClass = usePrefixedClassNames('tree-view-item');
|
|
10425
|
+
const groupClass = usePrefixedClassNames('tree-view-group');
|
|
10426
|
+
const toggleClass = usePrefixedClassNames('tree-view-toggle');
|
|
10427
|
+
const checkClass = usePrefixedClassNames('tree-view-check');
|
|
10428
|
+
const iconClass = usePrefixedClassNames('tree-view-icon');
|
|
10429
|
+
const labelClass = usePrefixedClassNames('tree-view-label');
|
|
10430
|
+
const register = tree?.register;
|
|
10431
|
+
useClientLayoutEffect(() => {
|
|
10432
|
+
if (!register) {
|
|
10433
|
+
warnOnce('TreeView.Item:outside', '[bestax-bulma] <TreeView.Item> is outside a <TreeView>, so it ' +
|
|
10434
|
+
'renders nothing. Put it inside one.');
|
|
10435
|
+
return undefined;
|
|
10436
|
+
}
|
|
10437
|
+
return register(value, { parent, disabled, isParent });
|
|
10438
|
+
}, [register, value, parent, disabled, isParent]);
|
|
10439
|
+
const setElement = tree?.setElement;
|
|
10440
|
+
const setRefs = React.useCallback((node) => {
|
|
10441
|
+
// Only an item inside a tree renders an element to hand over.
|
|
10442
|
+
setElement(value, node);
|
|
10443
|
+
if (typeof ref === 'function')
|
|
10444
|
+
ref(node);
|
|
10445
|
+
else if (ref)
|
|
10446
|
+
ref.current = node;
|
|
10447
|
+
}, [setElement, value, ref]);
|
|
10448
|
+
const rowRef = React.useRef(null);
|
|
10449
|
+
const toggleRef = React.useRef(null);
|
|
10450
|
+
const childBranch = React.useMemo(() => ({
|
|
10451
|
+
path: [...branch.path, value],
|
|
10452
|
+
hidden: branch.hidden || !open,
|
|
10453
|
+
}), [branch, value, open]);
|
|
10454
|
+
const { selected, checked } = tree?.stateOf(value, branch.path, disabled) ?? {};
|
|
10455
|
+
const rowClass = usePrefixedClassNames('tree-view-row', {
|
|
10456
|
+
'is-selected': selected,
|
|
10457
|
+
'is-disabled': disabled,
|
|
10042
10458
|
});
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
const
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
//
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
}
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
}
|
|
10459
|
+
if (!tree)
|
|
10460
|
+
return null;
|
|
10461
|
+
// While it's open the children render in its group. In a checkbox tree
|
|
10462
|
+
// they render while it's closed too, drawing nothing, so a check knows
|
|
10463
|
+
// what's under it.
|
|
10464
|
+
const items = (open || tree.rendersClosed) && (jsxRuntime.jsx(BranchContext.Provider, { value: childBranch, children: children }));
|
|
10465
|
+
if (branch.hidden)
|
|
10466
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: items });
|
|
10467
|
+
const info = { value, parent, disabled, isParent, open };
|
|
10468
|
+
return (jsxRuntime.jsxs("li", { ...props, ref: setRefs, className: classNames(itemClass, className), role: "treeitem", "aria-labelledby": labelId, "aria-level": branch.path.length + 1, "aria-expanded": isParent ? open : undefined, "aria-disabled": disabled || undefined, "aria-selected": selected, "aria-checked": checked, tabIndex: tree.tabStop === value ? 0 : -1, onKeyDown: event => {
|
|
10469
|
+
onKeyDown?.(event);
|
|
10470
|
+
tree.onKeyDown(event, info);
|
|
10471
|
+
}, onFocus: event => {
|
|
10472
|
+
onFocus?.(event);
|
|
10473
|
+
if (event.target === event.currentTarget) {
|
|
10474
|
+
tree.onFocus(value, event.currentTarget);
|
|
10475
|
+
}
|
|
10476
|
+
}, onBlur: event => {
|
|
10477
|
+
onBlur?.(event);
|
|
10478
|
+
if (event.target === event.currentTarget)
|
|
10479
|
+
tree.onBlur();
|
|
10480
|
+
}, onClick: event => {
|
|
10481
|
+
onClick?.(event);
|
|
10482
|
+
// A click in its row is its own, and so is one on the item itself,
|
|
10483
|
+
// as a test's click on the treeitem is. One in its group belongs
|
|
10484
|
+
// to the item inside it, or to nothing. The chevron's box is on
|
|
10485
|
+
// every row, but it's a chevron only on a parent: on a leaf it's
|
|
10486
|
+
// more of the row.
|
|
10487
|
+
const target = event.target;
|
|
10488
|
+
if (target === event.currentTarget ||
|
|
10489
|
+
rowRef.current.contains(target)) {
|
|
10490
|
+
tree.onClick(event.currentTarget, info, isParent && toggleRef.current.contains(target));
|
|
10491
|
+
}
|
|
10492
|
+
}, children: [jsxRuntime.jsxs("div", { className: rowClass, ref: rowRef, children: [jsxRuntime.jsx("span", { className: toggleClass, "aria-hidden": "true", ref: toggleRef }), checked !== undefined && (jsxRuntime.jsx("span", { className: checkClass, "aria-hidden": "true", onClick: event => {
|
|
10493
|
+
// A click on the box's label is followed by one on its
|
|
10494
|
+
// input, and both reach the item. The label's is cancelled,
|
|
10495
|
+
// so the item toggles once.
|
|
10496
|
+
if (!(event.target instanceof HTMLInputElement)) {
|
|
10497
|
+
event.preventDefault();
|
|
10498
|
+
}
|
|
10499
|
+
}, children: jsxRuntime.jsx(Checkbox, { tabIndex: -1, checked: checked === true, indeterminate: checked === 'mixed', disabled: disabled, onChange: ignoreChange }) })), isGiven(icon) && (jsxRuntime.jsx("span", { className: iconClass, "aria-hidden": "true", children: typeof icon === 'string' ? jsxRuntime.jsx(Icon, { name: icon }) : icon })), jsxRuntime.jsx("span", { className: labelClass, id: labelId, children: label })] }), open && hasItems ? (jsxRuntime.jsx("ul", { className: groupClass, role: "group", children: items })) : (items)] }));
|
|
10500
|
+
});
|
|
10501
|
+
TreeViewItem.displayName = 'TreeView.Item';
|
|
10502
|
+
const TreeView = withSubComponents(TreeViewRoot, { Item: TreeViewItem }, 'TreeView');
|
|
10503
|
+
|
|
10083
10504
|
/**
|
|
10084
|
-
*
|
|
10505
|
+
* The `Block` component renders a simple container with Bulma's `.block` class, adding vertical margin between sections of content.
|
|
10085
10506
|
*
|
|
10086
|
-
* @
|
|
10087
|
-
*
|
|
10088
|
-
*
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
* Show a notification with the given options.
|
|
10093
|
-
* @param {NotificationOptions} options - Notification configuration.
|
|
10094
|
-
* @returns {string} The unique ID of the created notification.
|
|
10095
|
-
*/
|
|
10096
|
-
show: (options) => {
|
|
10097
|
-
const id = `notification-${++notificationId}`;
|
|
10098
|
-
const instance = { id, options };
|
|
10099
|
-
if (options.queue) {
|
|
10100
|
-
queuedNotifications.push(instance);
|
|
10101
|
-
processQueuedNotification();
|
|
10102
|
-
}
|
|
10103
|
-
else {
|
|
10104
|
-
notifications.push(instance);
|
|
10105
|
-
notifyNotificationListeners();
|
|
10106
|
-
}
|
|
10107
|
-
return id;
|
|
10108
|
-
},
|
|
10109
|
-
/**
|
|
10110
|
-
* Show a success notification.
|
|
10111
|
-
* @param {string|React.ReactNode} message - The message to display.
|
|
10112
|
-
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
10113
|
-
* @returns {string} The notification ID.
|
|
10114
|
-
*/
|
|
10115
|
-
success: (message, options) => {
|
|
10116
|
-
return notification.show({ message, color: 'success', ...options });
|
|
10117
|
-
},
|
|
10118
|
-
/**
|
|
10119
|
-
* Show a danger notification.
|
|
10120
|
-
* @param {string|React.ReactNode} message - The message to display.
|
|
10121
|
-
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
10122
|
-
* @returns {string} The notification ID.
|
|
10123
|
-
*/
|
|
10124
|
-
danger: (message, options) => {
|
|
10125
|
-
return notification.show({ message, color: 'danger', ...options });
|
|
10126
|
-
},
|
|
10127
|
-
/**
|
|
10128
|
-
* Show a warning notification.
|
|
10129
|
-
* @param {string|React.ReactNode} message - The message to display.
|
|
10130
|
-
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
10131
|
-
* @returns {string} The notification ID.
|
|
10132
|
-
*/
|
|
10133
|
-
warning: (message, options) => {
|
|
10134
|
-
return notification.show({ message, color: 'warning', ...options });
|
|
10135
|
-
},
|
|
10136
|
-
/**
|
|
10137
|
-
* Show an info notification.
|
|
10138
|
-
* @param {string|React.ReactNode} message - The message to display.
|
|
10139
|
-
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
10140
|
-
* @returns {string} The notification ID.
|
|
10141
|
-
*/
|
|
10142
|
-
info: (message, options) => {
|
|
10143
|
-
return notification.show({ message, color: 'info', ...options });
|
|
10144
|
-
},
|
|
10507
|
+
* @function
|
|
10508
|
+
* @param {BlockProps} props - Props for the Block component.
|
|
10509
|
+
* @returns {JSX.Element} The rendered block element.
|
|
10510
|
+
* @see {@link https://bulma.io/documentation/elements/block/ | Bulma Block documentation}
|
|
10511
|
+
*/
|
|
10512
|
+
const Block = ({ className, textColor, color, bgColor, children, ...props }) => {
|
|
10145
10513
|
/**
|
|
10146
|
-
*
|
|
10147
|
-
* @param {string} id - The notification ID to close.
|
|
10514
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10148
10515
|
*/
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10516
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10517
|
+
color: textColor ?? color,
|
|
10518
|
+
backgroundColor: bgColor,
|
|
10519
|
+
...props,
|
|
10520
|
+
});
|
|
10521
|
+
const bulmaClasses = usePrefixedClassNames('block');
|
|
10522
|
+
const blockClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10523
|
+
return (jsxRuntime.jsx("div", { className: blockClasses, ...rest, children: children }));
|
|
10524
|
+
};
|
|
10525
|
+
|
|
10526
|
+
/**
|
|
10527
|
+
* The `Box` component renders a bordered, padded container with an optional shadow using Bulma's `.box` class.
|
|
10528
|
+
*
|
|
10529
|
+
* @function
|
|
10530
|
+
* @param {BoxProps} props - Props for the Box component.
|
|
10531
|
+
* @returns {JSX.Element} The rendered box element.
|
|
10532
|
+
* @see {@link https://bulma.io/documentation/elements/box/ | Bulma Box documentation}
|
|
10533
|
+
*/
|
|
10534
|
+
const Box = ({ className, textColor, color, bgColor, hasShadow = true, children, style, ...props }) => {
|
|
10167
10535
|
/**
|
|
10168
|
-
*
|
|
10169
|
-
* @param {(items: NotificationInstance[]) => void} listener - Callback invoked on changes.
|
|
10170
|
-
* @returns {() => void} Unsubscribe function.
|
|
10536
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10171
10537
|
*/
|
|
10172
|
-
|
|
10173
|
-
|
|
10174
|
-
|
|
10175
|
-
|
|
10538
|
+
const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({
|
|
10539
|
+
color: textColor ?? color,
|
|
10540
|
+
backgroundColor: bgColor,
|
|
10541
|
+
...props,
|
|
10542
|
+
});
|
|
10543
|
+
const bulmaClasses = usePrefixedClassNames('box', {
|
|
10544
|
+
'is-shadowless': !hasShadow,
|
|
10545
|
+
});
|
|
10546
|
+
const boxClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10547
|
+
return (jsxRuntime.jsx("div", { className: boxClasses, style: mergeBulmaStyles(bulmaHelperStyles, style), ...rest, children: children }));
|
|
10176
10548
|
};
|
|
10549
|
+
|
|
10177
10550
|
/**
|
|
10178
|
-
*
|
|
10179
|
-
* than politely through NotificationContainer's status region.
|
|
10551
|
+
* The `Code` component renders a styled `<code>` element with Bulma helper class integration.
|
|
10180
10552
|
*
|
|
10181
|
-
* @function
|
|
10182
|
-
* @param {
|
|
10183
|
-
* @returns {
|
|
10553
|
+
* @function
|
|
10554
|
+
* @param {CodeProps} props - Props for the Code component.
|
|
10555
|
+
* @returns {JSX.Element} The rendered code element.
|
|
10184
10556
|
*/
|
|
10185
|
-
const
|
|
10557
|
+
const Code = ({ className, textColor, bgColor, children, ...props }) => {
|
|
10558
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10559
|
+
color: textColor,
|
|
10560
|
+
backgroundColor: bgColor,
|
|
10561
|
+
...props,
|
|
10562
|
+
});
|
|
10563
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
10564
|
+
const codeClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10565
|
+
return (jsxRuntime.jsx("code", { className: codeClasses || undefined, ...rest, children: children }));
|
|
10566
|
+
};
|
|
10567
|
+
|
|
10568
|
+
// Valid size modifiers for the content class
|
|
10569
|
+
const validSizes = ['small', 'medium', 'large'];
|
|
10186
10570
|
/**
|
|
10187
|
-
*
|
|
10571
|
+
* The `Content` component applies Bulma’s typographic styles to its children, enhancing the appearance of HTML elements like paragraphs, headings, lists, and tables.
|
|
10188
10572
|
*
|
|
10189
10573
|
* @function
|
|
10190
|
-
* @param {
|
|
10191
|
-
* @returns {JSX.Element} The rendered
|
|
10574
|
+
* @param {ContentProps} props - Props for the Content component.
|
|
10575
|
+
* @returns {JSX.Element} The rendered content block.
|
|
10576
|
+
* @see {@link https://bulma.io/documentation/elements/content/ | Bulma Content documentation}
|
|
10192
10577
|
*/
|
|
10193
|
-
const
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
const
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10201
|
-
|
|
10202
|
-
|
|
10203
|
-
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
const timer = setTimeout(handleClose, duration);
|
|
10208
|
-
return () => clearTimeout(timer);
|
|
10209
|
-
}, [duration, indefinite, isPaused, handleClose]);
|
|
10210
|
-
const handleMouseEnter = React.useCallback(() => {
|
|
10211
|
-
if (pauseOnHover)
|
|
10212
|
-
setIsPaused(true);
|
|
10213
|
-
}, [pauseOnHover]);
|
|
10214
|
-
const handleMouseLeave = React.useCallback(() => {
|
|
10215
|
-
if (pauseOnHover)
|
|
10216
|
-
setIsPaused(false);
|
|
10217
|
-
}, [pauseOnHover]);
|
|
10218
|
-
return (jsxRuntime.jsx(Notification, { color: color, isLight: isLight, hasDelete: hasDelete, onDelete: handleClose, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: { pointerEvents: 'auto' }, children: urgent ? (jsxRuntime.jsx("span", { role: "alert", "aria-live": "assertive", children: message })) : (jsxRuntime.jsx("span", { ref: messageRef, children: message })) }));
|
|
10578
|
+
const Content = ({ className, textColor, color, bgColor, size, children, ...props }) => {
|
|
10579
|
+
/**
|
|
10580
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10581
|
+
*/
|
|
10582
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10583
|
+
color: textColor ?? color,
|
|
10584
|
+
backgroundColor: bgColor,
|
|
10585
|
+
...props,
|
|
10586
|
+
});
|
|
10587
|
+
const bulmaClasses = usePrefixedClassNames('content', {
|
|
10588
|
+
[`is-${size}`]: size && size !== 'normal' && validSizes.includes(size),
|
|
10589
|
+
});
|
|
10590
|
+
const contentClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10591
|
+
return (jsxRuntime.jsx("div", { className: contentClasses, ...rest, children: children }));
|
|
10219
10592
|
};
|
|
10220
|
-
|
|
10221
|
-
// screen, then across the bottom.
|
|
10222
|
-
const notificationStackOrder = [
|
|
10223
|
-
'top-left',
|
|
10224
|
-
'top',
|
|
10225
|
-
'top-right',
|
|
10226
|
-
'bottom-left',
|
|
10227
|
-
'bottom',
|
|
10228
|
-
'bottom-right',
|
|
10229
|
-
];
|
|
10593
|
+
|
|
10230
10594
|
/**
|
|
10231
|
-
*
|
|
10595
|
+
* The `Delete` component provides a Bulma-styled close/delete button for dismissing modals, notifications, tags, messages, and more.
|
|
10596
|
+
*
|
|
10597
|
+
* It renders `type="button"`, so a delete button inside a form does not submit it.
|
|
10232
10598
|
*
|
|
10233
10599
|
* @function
|
|
10234
|
-
* @param {
|
|
10235
|
-
* @returns {
|
|
10600
|
+
* @param {DeleteProps} props - Props for the Delete component.
|
|
10601
|
+
* @returns {JSX.Element} The rendered delete button.
|
|
10602
|
+
* @see {@link https://bulma.io/documentation/elements/delete/ | Bulma Delete documentation}
|
|
10236
10603
|
*/
|
|
10237
|
-
const
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10241
|
-
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
? { left: '50%', transform: 'translateX(-50%)', alignItems: 'center' }
|
|
10253
|
-
: isRight
|
|
10254
|
-
? { right: 0, alignItems: 'flex-end' }
|
|
10255
|
-
: { left: 0, alignItems: 'flex-start' }),
|
|
10256
|
-
};
|
|
10604
|
+
const Delete = ({ className, textColor, color, bgColor, onClick, size, ariaLabel, disabled = false, ...props }) => {
|
|
10605
|
+
/**
|
|
10606
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10607
|
+
*/
|
|
10608
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10609
|
+
color: textColor ?? color,
|
|
10610
|
+
backgroundColor: bgColor,
|
|
10611
|
+
...props,
|
|
10612
|
+
});
|
|
10613
|
+
const bulmaClasses = usePrefixedClassNames('delete', {
|
|
10614
|
+
[`is-${size}`]: size,
|
|
10615
|
+
'is-disabled': disabled,
|
|
10616
|
+
});
|
|
10617
|
+
const classes = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10618
|
+
return (jsxRuntime.jsx("button", { className: classes, onClick: onClick, disabled: disabled, ...rest, "aria-label": rest['aria-label'] || ariaLabel || 'Close', type: buttonType(rest.type) }));
|
|
10257
10619
|
};
|
|
10620
|
+
|
|
10258
10621
|
/**
|
|
10259
|
-
*
|
|
10260
|
-
* Place once at your app root to enable the notification API. A notification
|
|
10261
|
-
* shown with a `position` appears there, and one shown without goes to the
|
|
10262
|
-
* container's `position`, so the container renders a stack for each position
|
|
10263
|
-
* in use.
|
|
10264
|
-
*
|
|
10265
|
-
* It keeps a visually hidden `role="status"` live region in the page from the
|
|
10266
|
-
* moment it mounts, even while nothing is showing, and announces every
|
|
10267
|
-
* notification other than `danger` and `warning` through it, a moment after
|
|
10268
|
-
* the notification appears. Those notifications carry no `role="status"` of
|
|
10269
|
-
* their own, so `getByRole('status')` finds the region, not the notification.
|
|
10270
|
-
* The text stays in the region briefly, even if the notification closes in
|
|
10271
|
-
* the meantime, and while both are up the page holds two copies of it. A
|
|
10272
|
-
* polite notification that closes before its announcement is written, a
|
|
10273
|
-
* moment after it appears, isn't announced at all. `danger` and `warning`
|
|
10274
|
-
* notifications announce themselves as assertive alerts. The region is hidden
|
|
10275
|
-
* with inline styles, so it needs no stylesheet.
|
|
10622
|
+
* The `Divider` component renders a styled horizontal rule (`<hr>`) element with Bulma helper class integration.
|
|
10276
10623
|
*
|
|
10277
10624
|
* @function
|
|
10278
|
-
* @param {
|
|
10279
|
-
* @returns {JSX.Element
|
|
10625
|
+
* @param {DividerProps} props - Props for the Divider component.
|
|
10626
|
+
* @returns {JSX.Element} The rendered hr element.
|
|
10280
10627
|
*/
|
|
10281
|
-
const
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
const
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
const politeItems = React.useMemo(() => items.filter(item => !isUrgentColor(item.options.color)), [items]);
|
|
10293
|
-
// Each polite notification's message element, so the text the region
|
|
10294
|
-
// announces is the text on screen, whatever the message renders.
|
|
10295
|
-
const messageNodesRef = React.useRef(new Map());
|
|
10296
|
-
const registerMessage = React.useCallback((id, node) => {
|
|
10297
|
-
if (node) {
|
|
10298
|
-
messageNodesRef.current.set(id, node);
|
|
10299
|
-
}
|
|
10300
|
-
else {
|
|
10301
|
-
messageNodesRef.current.delete(id);
|
|
10302
|
-
}
|
|
10303
|
-
}, []);
|
|
10304
|
-
// StatusRegion only describes polite notifications that are on screen, and
|
|
10305
|
-
// each of those registered its message element when it mounted. The
|
|
10306
|
-
// fallback is for a notification announced without being rendered, should
|
|
10307
|
-
// the container ever render fewer than it announces: a plain-text message
|
|
10308
|
-
// still says itself, and anything else is skipped.
|
|
10309
|
-
const describe = React.useCallback((item) => {
|
|
10310
|
-
const node = messageNodesRef.current.get(item.id);
|
|
10311
|
-
/* istanbul ignore if: every polite notification on screen registers its message element when it mounts */
|
|
10312
|
-
if (!node) {
|
|
10313
|
-
const { message } = item.options;
|
|
10314
|
-
return typeof message === 'string' ? message : null;
|
|
10315
|
-
}
|
|
10316
|
-
return spokenText(node);
|
|
10317
|
-
}, []);
|
|
10318
|
-
if (typeof document === 'undefined' || !isHydrated) {
|
|
10319
|
-
return null;
|
|
10320
|
-
}
|
|
10321
|
-
const stacks = groupIntoPositionStacks(items, item => item.options.position, position, notificationStackOrder);
|
|
10322
|
-
return reactDom.createPortal(jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [stacks.map(stack => (jsxRuntime.jsx("div", { style: notificationStackStyle(stack.position), children: stack.items.map(item => (jsxRuntime.jsx(NotificationItem, { instance: item, onClose: notification.close, registerMessage: registerMessage }, item.id))) }, stack.key))), jsxRuntime.jsx(StatusRegion, { items: politeItems, describe: describe })] }), resolveContainer());
|
|
10628
|
+
const Divider = ({ className, bgColor, ...props }) => {
|
|
10629
|
+
/**
|
|
10630
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10631
|
+
*/
|
|
10632
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10633
|
+
backgroundColor: bgColor,
|
|
10634
|
+
...props,
|
|
10635
|
+
});
|
|
10636
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
10637
|
+
const dividerClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10638
|
+
return jsxRuntime.jsx("hr", { className: dividerClasses || undefined, ...rest });
|
|
10323
10639
|
};
|
|
10324
10640
|
|
|
10325
10641
|
/**
|
|
10326
|
-
* The `
|
|
10642
|
+
* The `Emphasis` component renders a styled `<em>` element with Bulma helper class integration.
|
|
10327
10643
|
*
|
|
10328
10644
|
* @function
|
|
10329
|
-
* @param {
|
|
10330
|
-
* @returns {JSX.Element} The rendered
|
|
10645
|
+
* @param {EmphasisProps} props - Props for the Emphasis component.
|
|
10646
|
+
* @returns {JSX.Element} The rendered em element.
|
|
10331
10647
|
*/
|
|
10332
|
-
const
|
|
10333
|
-
/**
|
|
10334
|
-
* Generates Bulma helper classes and separates out remaining props.
|
|
10335
|
-
*/
|
|
10648
|
+
const Emphasis = ({ className, textColor, bgColor, children, ...props }) => {
|
|
10336
10649
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10337
10650
|
color: textColor,
|
|
10338
10651
|
backgroundColor: bgColor,
|
|
10339
10652
|
...props,
|
|
10340
10653
|
});
|
|
10341
10654
|
const bulmaClasses = usePrefixedClassNames();
|
|
10342
|
-
const
|
|
10343
|
-
return (jsxRuntime.jsx("
|
|
10655
|
+
const emphasisClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10656
|
+
return (jsxRuntime.jsx("em", { className: emphasisClasses || undefined, ...rest, children: children }));
|
|
10344
10657
|
};
|
|
10345
|
-
const OrderedList = withSubComponents(OrderedListComponent, { Item: ListItem }, 'OrderedList');
|
|
10346
10658
|
|
|
10347
10659
|
/**
|
|
10348
|
-
*
|
|
10660
|
+
* FigureCaption component for rendering a styled figcaption element.
|
|
10661
|
+
*
|
|
10662
|
+
* A FigureCaption wraps the HTML `<figcaption>` element with Bulma helper class integration.
|
|
10663
|
+
* Use it inside Figure components to provide captions for images or other media.
|
|
10349
10664
|
*
|
|
10350
10665
|
* @function
|
|
10351
|
-
* @param {
|
|
10352
|
-
* @returns {JSX.Element} The rendered
|
|
10666
|
+
* @param {FigureCaptionProps} props - Props for the FigureCaption component.
|
|
10667
|
+
* @returns {JSX.Element} The rendered figcaption element.
|
|
10353
10668
|
*/
|
|
10354
|
-
const
|
|
10669
|
+
const FigureCaption = ({ className, textColor, bgColor, children, ...props }) => {
|
|
10355
10670
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10356
10671
|
color: textColor,
|
|
10357
10672
|
backgroundColor: bgColor,
|
|
10358
10673
|
...props,
|
|
10359
10674
|
});
|
|
10360
10675
|
const bulmaClasses = usePrefixedClassNames();
|
|
10361
|
-
const
|
|
10362
|
-
return (jsxRuntime.jsx("
|
|
10676
|
+
const captionClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10677
|
+
return (jsxRuntime.jsx("figcaption", { className: captionClasses || undefined, ...rest, children: children }));
|
|
10678
|
+
};
|
|
10679
|
+
/**
|
|
10680
|
+
* The `Figure` component renders a styled `<figure>` element with Bulma helper class integration.
|
|
10681
|
+
*
|
|
10682
|
+
* @function
|
|
10683
|
+
* @param {FigureProps} props - Props for the Figure component.
|
|
10684
|
+
* @returns {JSX.Element} The rendered figure element.
|
|
10685
|
+
*/
|
|
10686
|
+
const FigureComponent = ({ className, textColor, bgColor, children, ...props }) => {
|
|
10687
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10688
|
+
color: textColor,
|
|
10689
|
+
backgroundColor: bgColor,
|
|
10690
|
+
...props,
|
|
10691
|
+
});
|
|
10692
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
10693
|
+
const figureClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10694
|
+
return (jsxRuntime.jsx("figure", { className: figureClasses || undefined, ...rest, children: children }));
|
|
10363
10695
|
};
|
|
10696
|
+
/**
|
|
10697
|
+
* Figure component with Caption subcomponent.
|
|
10698
|
+
*
|
|
10699
|
+
* @example
|
|
10700
|
+
* <Figure>
|
|
10701
|
+
* <img src="image.jpg" alt="Description" />
|
|
10702
|
+
* <Figure.Caption>Image caption text</Figure.Caption>
|
|
10703
|
+
* </Figure>
|
|
10704
|
+
*/
|
|
10705
|
+
const Figure = withSubComponents(FigureComponent, {
|
|
10706
|
+
Caption: FigureCaption,
|
|
10707
|
+
}, 'Figure');
|
|
10364
10708
|
|
|
10365
10709
|
/**
|
|
10366
|
-
*
|
|
10710
|
+
* Distinguishes an `IconProps` object from a plain custom node (an inline SVG, a
|
|
10711
|
+
* `react-icons` component, …) in a slot that accepts either — `Control`'s
|
|
10712
|
+
* `iconLeft`/`iconRight`, `IconText`'s `iconProps`.
|
|
10713
|
+
*
|
|
10714
|
+
* One copy, imported by both consumers: two hand-maintained copies, one per
|
|
10715
|
+
* consumer, is how the deprecated `icon` path came to crash both (#663).
|
|
10716
|
+
*
|
|
10717
|
+
* Its own module rather than `Icon.tsx` because `src/index.ts` wildcard-exports
|
|
10718
|
+
* that file, and everything published there is public forever. `polymorphic.ts`
|
|
10719
|
+
* makes the same call for `isCustomElement`: an internal discriminator is not
|
|
10720
|
+
* something to support for the life of the package.
|
|
10721
|
+
*
|
|
10722
|
+
* It tests each member's VALUE, not merely its key, and only after everything
|
|
10723
|
+
* React owns is out of the way. `'icon' in value` was enough
|
|
10724
|
+
* to claim a Font Awesome `IconDefinition` — `{ prefix, iconName, icon: [w, h, …,
|
|
10725
|
+
* path] }` — whose `icon` is a path array rather than a class string. That object
|
|
10726
|
+
* is not a renderable node either, so the honest outcome is the one this slot has
|
|
10727
|
+
* always had for it: the node branch, and React's own "Objects are not valid as a
|
|
10728
|
+
* React child". Claiming it here instead rendered a blank container that still
|
|
10729
|
+
* reserved layout.
|
|
10730
|
+
*
|
|
10731
|
+
* A member added to `IconProps` needs a line here, and a missed one is a crash
|
|
10732
|
+
* rather than a fallthrough. That is the cost of a slot taking either a props
|
|
10733
|
+
* object or a node; keeping the guard in one place is what keeps the cost to a
|
|
10734
|
+
* single line.
|
|
10735
|
+
*/
|
|
10736
|
+
function isIconProps(value) {
|
|
10737
|
+
if (typeof value !== 'object' || value === null)
|
|
10738
|
+
return false;
|
|
10739
|
+
// Anything React owns. `isValidElement` covers elements only; a PORTAL is a
|
|
10740
|
+
// valid `ReactNode` that fails it and carries a `children` key, so the member
|
|
10741
|
+
// test below claimed it and `Control` spread it into `<Icon>` as props —
|
|
10742
|
+
// rendering the portal's child locally instead of in its container. Every
|
|
10743
|
+
// React internal carries `$$typeof`, so testing for it covers lazy, context
|
|
10744
|
+
// and whatever React adds next, rather than portals alone.
|
|
10745
|
+
if (React.isValidElement(value) || '$$typeof' in value)
|
|
10746
|
+
return false;
|
|
10747
|
+
const candidate = value;
|
|
10748
|
+
return (typeof candidate.name === 'string' ||
|
|
10749
|
+
typeof candidate.icon === 'string' ||
|
|
10750
|
+
'children' in candidate);
|
|
10751
|
+
}
|
|
10752
|
+
|
|
10753
|
+
/**
|
|
10754
|
+
* The `IconText` component provides a Bulma-styled horizontal arrangement of one or more `Icon` components and optional text.
|
|
10367
10755
|
*
|
|
10368
10756
|
* @function
|
|
10369
|
-
* @param {
|
|
10370
|
-
* @returns {JSX.Element} The rendered
|
|
10371
|
-
* @see {@link https://bulma.io/documentation/elements/
|
|
10757
|
+
* @param {IconTextProps} props - Props for the IconText component.
|
|
10758
|
+
* @returns {JSX.Element} The rendered icon text element.
|
|
10759
|
+
* @see {@link https://bulma.io/documentation/elements/icon/#icon-text | Bulma IconText documentation}
|
|
10372
10760
|
*/
|
|
10373
|
-
const
|
|
10374
|
-
warnUnstyledColor('Progress', color);
|
|
10761
|
+
const IconTextComponent = ({ className, textColor, color, bgColor, iconProps, children, items, ...props }) => {
|
|
10375
10762
|
/**
|
|
10376
10763
|
* Generates Bulma helper classes and separates out remaining props.
|
|
10377
10764
|
*/
|
|
10378
10765
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10766
|
+
color: textColor ?? color,
|
|
10767
|
+
backgroundColor: bgColor,
|
|
10379
10768
|
...props,
|
|
10380
10769
|
});
|
|
10381
|
-
const bulmaClasses = usePrefixedClassNames('
|
|
10382
|
-
|
|
10770
|
+
const bulmaClasses = usePrefixedClassNames('icon-text');
|
|
10771
|
+
const iconTextClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10772
|
+
return (jsxRuntime.jsx("span", { className: iconTextClasses, ...rest, children: items ? (items.map((item, index) => (jsxRuntime.jsxs(React.Fragment, { children: [item.iconProps &&
|
|
10773
|
+
(isIconProps(item.iconProps) ? (jsxRuntime.jsx(Icon, { ...item.iconProps })) : (jsxRuntime.jsx(Icon, { children: item.iconProps }))), item.text && jsxRuntime.jsx("span", { children: item.text })] }, index)))) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconProps &&
|
|
10774
|
+
(isIconProps(iconProps) ? (jsxRuntime.jsx(Icon, { ...iconProps })) : (jsxRuntime.jsx(Icon, { children: iconProps }))), children && jsxRuntime.jsx("span", { children: children })] })) }));
|
|
10775
|
+
};
|
|
10776
|
+
const IconText = withSubComponents(IconTextComponent, { Icon }, 'IconText');
|
|
10777
|
+
|
|
10778
|
+
/**
|
|
10779
|
+
* The `Image` component wraps images, iframes, or custom content in a Bulma-styled container, supporting fixed sizes, aspect ratios, rounded corners, retina images, and all Bulma helper props for color and spacing.
|
|
10780
|
+
*
|
|
10781
|
+
* @function
|
|
10782
|
+
* @param {ImageProps} props - Props for the Image component.
|
|
10783
|
+
* @returns {JSX.Element} The rendered image element.
|
|
10784
|
+
* @see {@link https://bulma.io/documentation/elements/image/ | Bulma Image documentation}
|
|
10785
|
+
*/
|
|
10786
|
+
const Image = ({ as, className, textColor, color, bgColor, size, isRounded, isRetina, src, alt, children, ...props }) => {
|
|
10787
|
+
/**
|
|
10788
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10789
|
+
*/
|
|
10790
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10791
|
+
color: textColor ?? color,
|
|
10792
|
+
backgroundColor: bgColor,
|
|
10793
|
+
...props,
|
|
10794
|
+
});
|
|
10795
|
+
const bulmaClasses = usePrefixedClassNames('image', {
|
|
10383
10796
|
[`is-${size}`]: size,
|
|
10797
|
+
'has-ratio': size && typeof size === 'string' && size.includes('by'),
|
|
10384
10798
|
});
|
|
10385
|
-
const
|
|
10386
|
-
|
|
10799
|
+
const imageClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10800
|
+
// Default tag logic: if "as" is provided, use it.
|
|
10801
|
+
// If not, use <figure> for aspect ratios or children, <div> otherwise.
|
|
10802
|
+
let Tag;
|
|
10803
|
+
if (as) {
|
|
10804
|
+
Tag = as;
|
|
10805
|
+
}
|
|
10806
|
+
else if (size && typeof size === 'string' && size.includes('by')) {
|
|
10807
|
+
Tag = 'figure';
|
|
10808
|
+
}
|
|
10809
|
+
else {
|
|
10810
|
+
Tag = 'div';
|
|
10811
|
+
}
|
|
10812
|
+
const roundedClass = usePrefixedClassNames('is-rounded');
|
|
10813
|
+
const content = children ? (children) : (jsxRuntime.jsx("img", { className: classNames({ [roundedClass]: isRounded }) || undefined, src: src, alt: alt, ...(isRetina && src ? { srcSet: `${src} 2x` } : {}) }));
|
|
10814
|
+
return (jsxRuntime.jsx(Tag, { className: imageClasses, ...rest, children: content }));
|
|
10387
10815
|
};
|
|
10388
10816
|
|
|
10389
10817
|
/**
|
|
10390
|
-
*
|
|
10818
|
+
* Keys pressed together or one after another, in the outer `<kbd>` HTML gives a combination, with the separator between each pair as text.
|
|
10819
|
+
*
|
|
10820
|
+
* It doesn't wrap in the middle and isn't drawn as a key itself. It sets no
|
|
10821
|
+
* font size, so the keys in it are the size of a key on its own.
|
|
10391
10822
|
*
|
|
10392
10823
|
* @function
|
|
10393
|
-
* @param {
|
|
10394
|
-
* @
|
|
10824
|
+
* @param {KbdGroupProps} props - Props for Kbd.Group.
|
|
10825
|
+
* @param {React.Ref<HTMLElement>} ref - Forwarded ref to the outer `<kbd>`.
|
|
10826
|
+
* @returns {JSX.Element} The rendered combination.
|
|
10395
10827
|
*
|
|
10396
10828
|
* @example
|
|
10397
|
-
*
|
|
10398
|
-
*
|
|
10829
|
+
* <Kbd.Group>
|
|
10830
|
+
* <Kbd>Ctrl</Kbd>
|
|
10831
|
+
* <Kbd>Shift</Kbd>
|
|
10832
|
+
* <Kbd>P</Kbd>
|
|
10833
|
+
* </Kbd.Group>
|
|
10399
10834
|
*
|
|
10400
10835
|
* @example
|
|
10401
|
-
*
|
|
10402
|
-
*
|
|
10836
|
+
* <Kbd.Group separator="then">
|
|
10837
|
+
* <Kbd>G</Kbd>
|
|
10838
|
+
* <Kbd>I</Kbd>
|
|
10839
|
+
* </Kbd.Group>
|
|
10403
10840
|
*/
|
|
10404
|
-
const
|
|
10405
|
-
const
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10841
|
+
const KbdGroup = React.forwardRef(({ className, textColor, separator = '+', children, ...props }, ref) => {
|
|
10842
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10843
|
+
color: textColor,
|
|
10844
|
+
...props,
|
|
10845
|
+
});
|
|
10846
|
+
const groupClass = usePrefixedClassNames('kbd-group');
|
|
10847
|
+
const separatorClass = usePrefixedClassNames('kbd-separator');
|
|
10848
|
+
// Null, undefined and booleans drop out, and Fragments are opened up, so
|
|
10849
|
+
// an empty Fragment leaves no separator behind and the keys in one are
|
|
10850
|
+
// separated like the rest. The spaces are part of the text, so a screen
|
|
10851
|
+
// reader reads "Ctrl plus S" rather than one run-together word, whatever
|
|
10852
|
+
// the CSS does.
|
|
10853
|
+
const keys = flattenChildren(children);
|
|
10854
|
+
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))) }));
|
|
10855
|
+
});
|
|
10856
|
+
KbdGroup.displayName = 'Kbd.Group';
|
|
10413
10857
|
/**
|
|
10414
|
-
* The `
|
|
10858
|
+
* The `Kbd` component renders a `<kbd>` drawn as a keycap, for a key the reader presses.
|
|
10859
|
+
*
|
|
10860
|
+
* It only shows the key: it doesn't listen for it. The key takes its colors
|
|
10861
|
+
* from the text it sits in, and its size in `em`, so it fits a paragraph, a
|
|
10862
|
+
* title or a filled button as it is, and `textSize` sizes it outright. For a
|
|
10863
|
+
* combination or a sequence, put the keys in a `Kbd.Group`. What tells
|
|
10864
|
+
* assistive tech a control has a shortcut is `aria-keyshortcuts` on that
|
|
10865
|
+
* control, with `Kbd` as the hint people see next to it.
|
|
10415
10866
|
*
|
|
10416
10867
|
* @function
|
|
10417
|
-
* @param {
|
|
10418
|
-
* @
|
|
10868
|
+
* @param {KbdProps} props - Props for the Kbd component.
|
|
10869
|
+
* @param {React.Ref<HTMLElement>} ref - Forwarded ref to the `<kbd>`.
|
|
10870
|
+
* @returns {JSX.Element} The rendered key.
|
|
10871
|
+
*
|
|
10872
|
+
* @example
|
|
10873
|
+
* <Kbd>Esc</Kbd>
|
|
10874
|
+
*
|
|
10875
|
+
* @example
|
|
10876
|
+
* <Kbd label="Command">⌘</Kbd>
|
|
10419
10877
|
*/
|
|
10420
|
-
const
|
|
10421
|
-
/**
|
|
10422
|
-
* Generates Bulma helper classes and separates out remaining props.
|
|
10423
|
-
*/
|
|
10878
|
+
const KbdRoot = React.forwardRef(({ className, textColor, bgColor, label, children, ...props }, ref) => {
|
|
10424
10879
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10425
10880
|
color: textColor,
|
|
10426
10881
|
backgroundColor: bgColor,
|
|
10427
10882
|
...props,
|
|
10428
10883
|
});
|
|
10429
|
-
const
|
|
10430
|
-
|
|
10431
|
-
|
|
10432
|
-
|
|
10884
|
+
const kbdClass = usePrefixedClassNames('kbd');
|
|
10885
|
+
// The name is text rather than an aria-label, which ARIA in HTML
|
|
10886
|
+
// prohibits on kbd. Its styles are inline, so it stays hidden in a
|
|
10887
|
+
// modular build that leaves out Bulma's helper classes.
|
|
10888
|
+
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) }));
|
|
10889
|
+
});
|
|
10890
|
+
const Kbd = withSubComponents(KbdRoot, { Group: KbdGroup }, 'Kbd');
|
|
10433
10891
|
|
|
10434
10892
|
/**
|
|
10435
|
-
* The `
|
|
10893
|
+
* The `Link` component renders a styled anchor (`<a>`) element with Bulma helper class integration.
|
|
10436
10894
|
*
|
|
10437
10895
|
* @function
|
|
10438
|
-
* @param {
|
|
10439
|
-
* @
|
|
10896
|
+
* @param {LinkProps} props - Props for the Link component.
|
|
10897
|
+
* @param {React.Ref} ref - Forwarded ref to the element `as` renders.
|
|
10898
|
+
* @returns {JSX.Element} The rendered anchor, or whatever `as` names.
|
|
10899
|
+
* @see {@link https://bulma.io/documentation/elements/content/ | Bulma Content documentation}
|
|
10440
10900
|
*/
|
|
10441
|
-
const
|
|
10901
|
+
const Link = React.forwardRef(function Link(linkProps, ref) {
|
|
10902
|
+
const { className, textColor, bgColor, isActive, as: Component = 'a', children, ...props } = linkProps;
|
|
10903
|
+
/**
|
|
10904
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
10905
|
+
*/
|
|
10442
10906
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10443
10907
|
color: textColor,
|
|
10444
10908
|
backgroundColor: bgColor,
|
|
10445
10909
|
...props,
|
|
10446
10910
|
});
|
|
10447
|
-
const bulmaClasses = usePrefixedClassNames(
|
|
10448
|
-
|
|
10449
|
-
|
|
10450
|
-
|
|
10911
|
+
const bulmaClasses = usePrefixedClassNames({
|
|
10912
|
+
'is-active': isActive,
|
|
10913
|
+
});
|
|
10914
|
+
const linkClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10915
|
+
return (jsxRuntime.jsx(Component, { ref: ref, className: linkClasses || undefined, ...rest, ...(Component === 'button' ? { type: buttonType(rest.type) } : {}), children: children }));
|
|
10916
|
+
});
|
|
10917
|
+
Link.displayName = 'Link';
|
|
10451
10918
|
|
|
10452
|
-
const validSubTitleSizes = ['1', '2', '3', '4', '5', '6'];
|
|
10453
|
-
const validSubTitleElements = [
|
|
10454
|
-
'h1',
|
|
10455
|
-
'h2',
|
|
10456
|
-
'h3',
|
|
10457
|
-
'h4',
|
|
10458
|
-
'h5',
|
|
10459
|
-
'h6',
|
|
10460
|
-
'p',
|
|
10461
|
-
];
|
|
10462
10919
|
/**
|
|
10463
|
-
* The `
|
|
10920
|
+
* The `ListItem` component renders a styled list item (`<li>`) element with Bulma helper class integration.
|
|
10464
10921
|
*
|
|
10465
10922
|
* @function
|
|
10466
|
-
* @param {
|
|
10467
|
-
* @returns {JSX.Element} The rendered
|
|
10468
|
-
* @see {@link https://bulma.io/documentation/elements/title/#subtitle | Bulma Subtitle documentation}
|
|
10923
|
+
* @param {ListItemProps} props - Props for the ListItem component.
|
|
10924
|
+
* @returns {JSX.Element} The rendered li element.
|
|
10469
10925
|
*/
|
|
10470
|
-
const
|
|
10926
|
+
const ListItem = ({ className, textColor, bgColor, children, ...props }) => {
|
|
10471
10927
|
/**
|
|
10472
10928
|
* Generates Bulma helper classes and separates out remaining props.
|
|
10473
10929
|
*/
|
|
@@ -10476,681 +10932,800 @@ const SubTitle = ({ className, size, as = 'h1', hasSkeleton, textColor, bgColor,
|
|
|
10476
10932
|
backgroundColor: bgColor,
|
|
10477
10933
|
...props,
|
|
10478
10934
|
});
|
|
10479
|
-
|
|
10480
|
-
const
|
|
10481
|
-
|
|
10482
|
-
const normalized = size == null ? undefined : String(size);
|
|
10483
|
-
const validSize = normalized && validSubTitleSizes.includes(normalized)
|
|
10484
|
-
? normalized
|
|
10485
|
-
: undefined;
|
|
10486
|
-
const bulmaClasses = usePrefixedClassNames('subtitle', {
|
|
10487
|
-
[`is-${validSize}`]: validSize,
|
|
10488
|
-
'has-skeleton': hasSkeleton,
|
|
10489
|
-
});
|
|
10490
|
-
const subTitleClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10491
|
-
// Determine the tag based on 'element' and 'validSize'
|
|
10492
|
-
const Tag = element === 'p' ? 'p' : validSize ? `h${validSize}` : element;
|
|
10493
|
-
return (jsxRuntime.jsx(Tag, { className: subTitleClasses, ...rest, children: children }));
|
|
10935
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
10936
|
+
const itemClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10937
|
+
return (jsxRuntime.jsx("li", { className: itemClasses || undefined, ...rest, children: children }));
|
|
10494
10938
|
};
|
|
10495
10939
|
|
|
10496
10940
|
/**
|
|
10497
|
-
*
|
|
10941
|
+
* The `Loader` component renders Bulma's `.loader`, a small spinning ring for inline loading states.
|
|
10498
10942
|
*
|
|
10499
|
-
*
|
|
10943
|
+
* The ring is `1em` square, so `textSize` scales it. It is exposed as an
|
|
10944
|
+
* indeterminate `progressbar` named by `ariaLabel`, and it stops spinning
|
|
10945
|
+
* under `prefers-reduced-motion: reduce` while staying drawn. In forced
|
|
10946
|
+
* colors its two open sides take the page's color, so it stays open.
|
|
10500
10947
|
*
|
|
10501
10948
|
* @function
|
|
10502
|
-
* @param {
|
|
10503
|
-
* @
|
|
10504
|
-
* @
|
|
10949
|
+
* @param {LoaderProps} props - Props for the Loader component.
|
|
10950
|
+
* @param {React.Ref<HTMLSpanElement>} ref - Forwarded ref to the loader element.
|
|
10951
|
+
* @returns {JSX.Element} The rendered loader element.
|
|
10952
|
+
*
|
|
10953
|
+
* @example
|
|
10954
|
+
* <Loader />
|
|
10955
|
+
*
|
|
10956
|
+
* @example
|
|
10957
|
+
* <Loader textSize="3" ariaLabel="Saving" />
|
|
10505
10958
|
*/
|
|
10506
|
-
const
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
};
|
|
10959
|
+
const Loader = React.forwardRef(({ className, ariaLabel = 'Loading', ...props }, ref) => {
|
|
10960
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
|
|
10961
|
+
const loaderClass = usePrefixedClassNames('loader');
|
|
10962
|
+
// role="progressbar", not role="status": a status region mounted together
|
|
10963
|
+
// with its text is not reliably announced, so the loader claims only what
|
|
10964
|
+
// it can deliver, a named indicator found by reading the page. No
|
|
10965
|
+
// aria-valuenow, because the progress is indeterminate.
|
|
10966
|
+
return (jsxRuntime.jsx("span", { ref: ref, className: classNames(loaderClass, bulmaHelperClasses, className), role: "progressbar", "aria-label": ariaLabel, ...rest }));
|
|
10967
|
+
});
|
|
10968
|
+
Loader.displayName = 'Loader';
|
|
10514
10969
|
|
|
10515
10970
|
/**
|
|
10516
|
-
*
|
|
10517
|
-
*
|
|
10518
|
-
* Supports Bulma helper classes for additional styling.
|
|
10971
|
+
* The `Notification` component is a Bulma-styled alert/message area for providing feedback, warnings, or information to users.
|
|
10519
10972
|
*
|
|
10520
10973
|
* @function
|
|
10521
|
-
* @param {
|
|
10522
|
-
* @returns {JSX.Element} The rendered
|
|
10523
|
-
* @see {@link https://bulma.io/documentation/elements/
|
|
10974
|
+
* @param {NotificationProps} props - Props for the Notification component.
|
|
10975
|
+
* @returns {JSX.Element} The rendered notification element.
|
|
10976
|
+
* @see {@link https://bulma.io/documentation/elements/notification/ | Bulma Notification documentation}
|
|
10524
10977
|
*/
|
|
10525
|
-
const
|
|
10978
|
+
const Notification = ({ className, color, textColor, isLight, hasDelete, onDelete, children, ...props }) => {
|
|
10979
|
+
warnUnstyledColor('Notification', color);
|
|
10526
10980
|
/**
|
|
10527
10981
|
* Generates Bulma helper classes and separates out remaining props.
|
|
10528
10982
|
*/
|
|
10529
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10530
|
-
|
|
10531
|
-
|
|
10983
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10984
|
+
color: textColor,
|
|
10985
|
+
...props,
|
|
10986
|
+
});
|
|
10987
|
+
const bulmaClasses = usePrefixedClassNames('notification', {
|
|
10988
|
+
[`is-${color}`]: color && validColors.includes(color),
|
|
10989
|
+
'is-light': isLight,
|
|
10990
|
+
'has-delete': hasDelete,
|
|
10991
|
+
});
|
|
10992
|
+
const deleteClasses = usePrefixedClassNames('delete');
|
|
10993
|
+
const notificationClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
10994
|
+
return (jsxRuntime.jsxs("div", { className: notificationClasses, ...rest, children: [hasDelete && (jsxRuntime.jsx("button", { type: "button", className: deleteClasses, onClick: onDelete, "aria-label": "Close notification" })), children] }));
|
|
10995
|
+
};
|
|
10996
|
+
let notificationId = 0;
|
|
10997
|
+
const notificationListeners = new Set();
|
|
10998
|
+
let notifications = [];
|
|
10999
|
+
// Queue support
|
|
11000
|
+
let queuedNotifications = [];
|
|
11001
|
+
let currentQueuedNotification = null;
|
|
11002
|
+
// The server has nowhere to portal a notification to, and its copy of this
|
|
11003
|
+
// module is shared by every request, so server rendering reads an empty list.
|
|
11004
|
+
// Hydration reads it too, which keeps the first client render matching the
|
|
11005
|
+
// server's.
|
|
11006
|
+
const noNotifications = [];
|
|
11007
|
+
const getServerNotifications = () => noNotifications;
|
|
11008
|
+
// What a container shows right now: the stacked notifications, then the queued
|
|
11009
|
+
// one on screen. NotificationContainer renders from this rather than from
|
|
11010
|
+
// updates alone, so notifications raised before it mounted still appear. It is
|
|
11011
|
+
// replaced rather than mutated, and only when listeners are notified, because
|
|
11012
|
+
// useSyncExternalStore needs the same array back between changes. An empty
|
|
11013
|
+
// list is `noNotifications` itself, so an empty store reads the same snapshot
|
|
11014
|
+
// on the client as on the server, and a notify that leaves nothing showing
|
|
11015
|
+
// when nothing was showing doesn't render the container again.
|
|
11016
|
+
let visibleNotifications = noNotifications;
|
|
11017
|
+
const getVisibleNotifications = () => visibleNotifications;
|
|
11018
|
+
const notifyNotificationListeners = () => {
|
|
11019
|
+
const allVisible = [...notifications];
|
|
11020
|
+
if (currentQueuedNotification) {
|
|
11021
|
+
allVisible.push(currentQueuedNotification);
|
|
11022
|
+
}
|
|
11023
|
+
visibleNotifications = allVisible.length > 0 ? allVisible : noNotifications;
|
|
11024
|
+
notificationListeners.forEach(listener => listener([...allVisible]));
|
|
11025
|
+
};
|
|
11026
|
+
const processQueuedNotification = () => {
|
|
11027
|
+
if (currentQueuedNotification || queuedNotifications.length === 0)
|
|
11028
|
+
return;
|
|
11029
|
+
currentQueuedNotification = queuedNotifications.shift();
|
|
11030
|
+
notifyNotificationListeners();
|
|
10532
11031
|
};
|
|
10533
|
-
|
|
10534
11032
|
/**
|
|
10535
|
-
*
|
|
10536
|
-
*
|
|
10537
|
-
* Supports Bulma helper classes for additional styling.
|
|
11033
|
+
* Programmatic notification API for showing, closing, and managing notifications.
|
|
10538
11034
|
*
|
|
10539
|
-
* @
|
|
10540
|
-
*
|
|
10541
|
-
*
|
|
10542
|
-
* @see {@link https://bulma.io/documentation/elements/table/#table-footer | Bulma Table documentation}
|
|
11035
|
+
* @example
|
|
11036
|
+
* notification.success('File saved successfully');
|
|
11037
|
+
* notification.danger('Something went wrong', { duration: 5000 });
|
|
10543
11038
|
*/
|
|
10544
|
-
const
|
|
11039
|
+
const notification = {
|
|
10545
11040
|
/**
|
|
10546
|
-
*
|
|
11041
|
+
* Show a notification with the given options.
|
|
11042
|
+
* @param {NotificationOptions} options - Notification configuration.
|
|
11043
|
+
* @returns {string} The unique ID of the created notification.
|
|
11044
|
+
*/
|
|
11045
|
+
show: (options) => {
|
|
11046
|
+
const id = `notification-${++notificationId}`;
|
|
11047
|
+
const instance = { id, options };
|
|
11048
|
+
if (options.queue) {
|
|
11049
|
+
queuedNotifications.push(instance);
|
|
11050
|
+
processQueuedNotification();
|
|
11051
|
+
}
|
|
11052
|
+
else {
|
|
11053
|
+
notifications.push(instance);
|
|
11054
|
+
notifyNotificationListeners();
|
|
11055
|
+
}
|
|
11056
|
+
return id;
|
|
11057
|
+
},
|
|
11058
|
+
/**
|
|
11059
|
+
* Show a success notification.
|
|
11060
|
+
* @param {string|React.ReactNode} message - The message to display.
|
|
11061
|
+
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
11062
|
+
* @returns {string} The notification ID.
|
|
11063
|
+
*/
|
|
11064
|
+
success: (message, options) => {
|
|
11065
|
+
return notification.show({ message, color: 'success', ...options });
|
|
11066
|
+
},
|
|
11067
|
+
/**
|
|
11068
|
+
* Show a danger notification.
|
|
11069
|
+
* @param {string|React.ReactNode} message - The message to display.
|
|
11070
|
+
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
11071
|
+
* @returns {string} The notification ID.
|
|
11072
|
+
*/
|
|
11073
|
+
danger: (message, options) => {
|
|
11074
|
+
return notification.show({ message, color: 'danger', ...options });
|
|
11075
|
+
},
|
|
11076
|
+
/**
|
|
11077
|
+
* Show a warning notification.
|
|
11078
|
+
* @param {string|React.ReactNode} message - The message to display.
|
|
11079
|
+
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
11080
|
+
* @returns {string} The notification ID.
|
|
11081
|
+
*/
|
|
11082
|
+
warning: (message, options) => {
|
|
11083
|
+
return notification.show({ message, color: 'warning', ...options });
|
|
11084
|
+
},
|
|
11085
|
+
/**
|
|
11086
|
+
* Show an info notification.
|
|
11087
|
+
* @param {string|React.ReactNode} message - The message to display.
|
|
11088
|
+
* @param {Partial<NotificationOptions>} [options] - Additional options.
|
|
11089
|
+
* @returns {string} The notification ID.
|
|
11090
|
+
*/
|
|
11091
|
+
info: (message, options) => {
|
|
11092
|
+
return notification.show({ message, color: 'info', ...options });
|
|
11093
|
+
},
|
|
11094
|
+
/**
|
|
11095
|
+
* Close a specific notification by ID.
|
|
11096
|
+
* @param {string} id - The notification ID to close.
|
|
11097
|
+
*/
|
|
11098
|
+
close: (id) => {
|
|
11099
|
+
if (currentQueuedNotification && currentQueuedNotification.id === id) {
|
|
11100
|
+
currentQueuedNotification = null;
|
|
11101
|
+
processQueuedNotification();
|
|
11102
|
+
}
|
|
11103
|
+
else {
|
|
11104
|
+
queuedNotifications = queuedNotifications.filter(n => n.id !== id);
|
|
11105
|
+
notifications = notifications.filter(n => n.id !== id);
|
|
11106
|
+
}
|
|
11107
|
+
notifyNotificationListeners();
|
|
11108
|
+
},
|
|
11109
|
+
/** Close all notifications and clear the queue. */
|
|
11110
|
+
closeAll: () => {
|
|
11111
|
+
notifications = [];
|
|
11112
|
+
queuedNotifications = [];
|
|
11113
|
+
currentQueuedNotification = null;
|
|
11114
|
+
notifyNotificationListeners();
|
|
11115
|
+
},
|
|
11116
|
+
/**
|
|
11117
|
+
* Subscribe to notification state changes.
|
|
11118
|
+
* @param {(items: NotificationInstance[]) => void} listener - Callback invoked on changes.
|
|
11119
|
+
* @returns {() => void} Unsubscribe function.
|
|
10547
11120
|
*/
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
11121
|
+
subscribe: (listener) => {
|
|
11122
|
+
notificationListeners.add(listener);
|
|
11123
|
+
return () => notificationListeners.delete(listener);
|
|
11124
|
+
},
|
|
10551
11125
|
};
|
|
10552
|
-
|
|
10553
11126
|
/**
|
|
10554
|
-
*
|
|
10555
|
-
*
|
|
10556
|
-
* `TableColor` is typed from it, and `Tr`, `Th` and `Td` all take a
|
|
10557
|
-
* `TableColor`, so the tuple and those props list the same values. Map over
|
|
10558
|
-
* it to build a color picker, or check a value that arrives at runtime before
|
|
10559
|
-
* passing it in: the components add no color class for a value outside the
|
|
10560
|
-
* tuple.
|
|
10561
|
-
*
|
|
10562
|
-
* @example
|
|
10563
|
-
* import { Tr, Td, validTableColors } from '@allxsmith/bestax-bulma';
|
|
11127
|
+
* Whether a notification of this color announces itself as an alert, rather
|
|
11128
|
+
* than politely through NotificationContainer's status region.
|
|
10564
11129
|
*
|
|
10565
|
-
*
|
|
10566
|
-
*
|
|
10567
|
-
*
|
|
10568
|
-
* {color}
|
|
10569
|
-
* </Td>
|
|
10570
|
-
* ))}
|
|
10571
|
-
* </Tr>;
|
|
11130
|
+
* @function isUrgentColor
|
|
11131
|
+
* @param {NotificationOptions['color']} color - The notification's color.
|
|
11132
|
+
* @returns {boolean} True for `danger` and `warning`.
|
|
10572
11133
|
*/
|
|
10573
|
-
const
|
|
10574
|
-
'primary',
|
|
10575
|
-
'link',
|
|
10576
|
-
'info',
|
|
10577
|
-
'success',
|
|
10578
|
-
'warning',
|
|
10579
|
-
'danger',
|
|
10580
|
-
'black',
|
|
10581
|
-
'dark',
|
|
10582
|
-
'light',
|
|
10583
|
-
'white',
|
|
10584
|
-
];
|
|
11134
|
+
const isUrgentColor = (color) => color === 'danger' || color === 'warning';
|
|
10585
11135
|
/**
|
|
10586
|
-
*
|
|
10587
|
-
*
|
|
10588
|
-
* Supports Bulma color modifiers and helper classes for additional styling.
|
|
11136
|
+
* Single auto-dismissing notification item used by NotificationContainer.
|
|
10589
11137
|
*
|
|
10590
11138
|
* @function
|
|
10591
|
-
* @param {
|
|
10592
|
-
* @returns {JSX.Element} The rendered
|
|
10593
|
-
* @see {@link https://bulma.io/documentation/elements/table/#table-body | Bulma Table documentation}
|
|
11139
|
+
* @param {{ instance: NotificationInstance; onClose: (id: string) => void; registerMessage: (id: string, node: HTMLElement | null) => void }} props - Component props.
|
|
11140
|
+
* @returns {JSX.Element} The rendered notification item.
|
|
10594
11141
|
*/
|
|
10595
|
-
const
|
|
10596
|
-
const
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
const
|
|
10603
|
-
|
|
10604
|
-
|
|
11142
|
+
const NotificationItem = ({ instance, onClose, registerMessage }) => {
|
|
11143
|
+
const { message, color, isLight, duration = 3000, hasDelete = true, indefinite = false, pauseOnHover = true, } = instance.options;
|
|
11144
|
+
const [isPaused, setIsPaused] = React.useState(false);
|
|
11145
|
+
const urgent = isUrgentColor(color);
|
|
11146
|
+
const handleClose = React.useCallback(() => {
|
|
11147
|
+
onClose(instance.id);
|
|
11148
|
+
}, [onClose, instance.id]);
|
|
11149
|
+
const messageRef = React.useCallback((node) => {
|
|
11150
|
+
registerMessage(instance.id, node);
|
|
11151
|
+
}, [registerMessage, instance.id]);
|
|
11152
|
+
// Auto-close timer
|
|
11153
|
+
React.useEffect(() => {
|
|
11154
|
+
if (indefinite || duration === 0 || isPaused)
|
|
11155
|
+
return undefined;
|
|
11156
|
+
const timer = setTimeout(handleClose, duration);
|
|
11157
|
+
return () => clearTimeout(timer);
|
|
11158
|
+
}, [duration, indefinite, isPaused, handleClose]);
|
|
11159
|
+
const handleMouseEnter = React.useCallback(() => {
|
|
11160
|
+
if (pauseOnHover)
|
|
11161
|
+
setIsPaused(true);
|
|
11162
|
+
}, [pauseOnHover]);
|
|
11163
|
+
const handleMouseLeave = React.useCallback(() => {
|
|
11164
|
+
if (pauseOnHover)
|
|
11165
|
+
setIsPaused(false);
|
|
11166
|
+
}, [pauseOnHover]);
|
|
11167
|
+
return (jsxRuntime.jsx(Notification, { color: color, isLight: isLight, hasDelete: hasDelete, onDelete: handleClose, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: { pointerEvents: 'auto' }, children: urgent ? (jsxRuntime.jsx("span", { role: "alert", "aria-live": "assertive", children: message })) : (jsxRuntime.jsx("span", { ref: messageRef, children: message })) }));
|
|
10605
11168
|
};
|
|
10606
|
-
|
|
11169
|
+
// The order NotificationContainer renders its stacks in: across the top of the
|
|
11170
|
+
// screen, then across the bottom.
|
|
11171
|
+
const notificationStackOrder = [
|
|
11172
|
+
'top-left',
|
|
11173
|
+
'top',
|
|
11174
|
+
'top-right',
|
|
11175
|
+
'bottom-left',
|
|
11176
|
+
'bottom',
|
|
11177
|
+
'bottom-right',
|
|
11178
|
+
];
|
|
10607
11179
|
/**
|
|
10608
|
-
*
|
|
10609
|
-
*
|
|
10610
|
-
* Supports the is-selected modifier and color modifiers.
|
|
11180
|
+
* Inline style that fixes a stack of notifications to its place on the screen.
|
|
10611
11181
|
*
|
|
10612
11182
|
* @function
|
|
10613
|
-
* @param {
|
|
10614
|
-
* @returns {
|
|
10615
|
-
* @see {@link https://bulma.io/documentation/elements/table/#table-row | Bulma Table documentation}
|
|
11183
|
+
* @param {NotificationPosition} position - Where the stack sits.
|
|
11184
|
+
* @returns {React.CSSProperties} The stack's style.
|
|
10616
11185
|
*/
|
|
10617
|
-
const
|
|
10618
|
-
const
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
11186
|
+
const notificationStackStyle = (position) => {
|
|
11187
|
+
const isBottom = position.startsWith('bottom');
|
|
11188
|
+
const isCenter = position === 'top' || position === 'bottom';
|
|
11189
|
+
const isRight = position.endsWith('right');
|
|
11190
|
+
return {
|
|
11191
|
+
position: 'fixed',
|
|
11192
|
+
zIndex: 100,
|
|
11193
|
+
display: 'flex',
|
|
11194
|
+
flexDirection: isBottom ? 'column-reverse' : 'column',
|
|
11195
|
+
gap: '0.75rem',
|
|
11196
|
+
padding: '1rem',
|
|
11197
|
+
pointerEvents: 'none',
|
|
11198
|
+
maxWidth: '100%',
|
|
11199
|
+
...(isBottom ? { bottom: 0 } : { top: 0 }),
|
|
11200
|
+
...(isCenter
|
|
11201
|
+
? { left: '50%', transform: 'translateX(-50%)', alignItems: 'center' }
|
|
11202
|
+
: isRight
|
|
11203
|
+
? { right: 0, alignItems: 'flex-end' }
|
|
11204
|
+
: { left: 0, alignItems: 'flex-start' }),
|
|
11205
|
+
};
|
|
10628
11206
|
};
|
|
10629
|
-
|
|
10630
|
-
const validAlignments = ['left', 'right', 'centered'];
|
|
10631
11207
|
/**
|
|
10632
|
-
*
|
|
10633
|
-
*
|
|
10634
|
-
*
|
|
11208
|
+
* Container component for rendering programmatic notifications.
|
|
11209
|
+
* Place once at your app root to enable the notification API. A notification
|
|
11210
|
+
* shown with a `position` appears there, and one shown without goes to the
|
|
11211
|
+
* container's `position`, so the container renders a stack for each position
|
|
11212
|
+
* in use.
|
|
10635
11213
|
*
|
|
10636
|
-
*
|
|
10637
|
-
*
|
|
10638
|
-
*
|
|
10639
|
-
*
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
* Generates Bulma helper classes and separates out remaining props.
|
|
10648
|
-
*/
|
|
10649
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
10650
|
-
const thClasses = classNames(bulmaClasses, className, bulmaHelperClasses);
|
|
10651
|
-
return (jsxRuntime.jsx("th", { className: thClasses || undefined, style: width
|
|
10652
|
-
? { width: typeof width === 'number' ? `${width}px` : width }
|
|
10653
|
-
: undefined, ...rest, children: children }));
|
|
10654
|
-
};
|
|
10655
|
-
|
|
10656
|
-
/**
|
|
10657
|
-
* The `Table` component and its subcomponents provide a highly composable, Bulma-styled table system for React.
|
|
11214
|
+
* It keeps a visually hidden `role="status"` live region in the page from the
|
|
11215
|
+
* moment it mounts, even while nothing is showing, and announces every
|
|
11216
|
+
* notification other than `danger` and `warning` through it, a moment after
|
|
11217
|
+
* the notification appears. Those notifications carry no `role="status"` of
|
|
11218
|
+
* their own, so `getByRole('status')` finds the region, not the notification.
|
|
11219
|
+
* The text stays in the region briefly, even if the notification closes in
|
|
11220
|
+
* the meantime, and while both are up the page holds two copies of it. A
|
|
11221
|
+
* polite notification that closes before its announcement is written, a
|
|
11222
|
+
* moment after it appears, isn't announced at all. `danger` and `warning`
|
|
11223
|
+
* notifications announce themselves as assertive alerts. The region is hidden
|
|
11224
|
+
* with inline styles, so it needs no stylesheet.
|
|
10658
11225
|
*
|
|
10659
11226
|
* @function
|
|
10660
|
-
* @param {
|
|
10661
|
-
* @returns {JSX.Element} The rendered
|
|
10662
|
-
* @see {@link https://bulma.io/documentation/elements/table/ | Bulma Table documentation}
|
|
11227
|
+
* @param {{ position?: NotificationPosition }} props - Container props.
|
|
11228
|
+
* @returns {JSX.Element | null} The rendered notification container, or null on the server and while hydrating.
|
|
10663
11229
|
*/
|
|
10664
|
-
const
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
const
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
11230
|
+
const NotificationContainer = ({ position = 'top-right' }) => {
|
|
11231
|
+
// Starts from the notifications already showing instead of an empty list,
|
|
11232
|
+
// then follows changes.
|
|
11233
|
+
const items = React.useSyncExternalStore(notification.subscribe, getVisibleNotifications, getServerNotifications);
|
|
11234
|
+
// A portal needs a document, and it has no server-rendered counterpart, so
|
|
11235
|
+
// the server render and the hydrating one render nothing, and the container
|
|
11236
|
+
// portals in from the render after hydration.
|
|
11237
|
+
const isHydrated = useIsHydrated();
|
|
11238
|
+
const resolveContainer = usePortalContainer();
|
|
11239
|
+
// The notifications the status region announces. Danger and warning
|
|
11240
|
+
// announce themselves.
|
|
11241
|
+
const politeItems = React.useMemo(() => items.filter(item => !isUrgentColor(item.options.color)), [items]);
|
|
11242
|
+
// Each polite notification's message element, so the text the region
|
|
11243
|
+
// announces is the text on screen, whatever the message renders.
|
|
11244
|
+
const messageNodesRef = React.useRef(new Map());
|
|
11245
|
+
const registerMessage = React.useCallback((id, node) => {
|
|
11246
|
+
if (node) {
|
|
11247
|
+
messageNodesRef.current.set(id, node);
|
|
11248
|
+
}
|
|
11249
|
+
else {
|
|
11250
|
+
messageNodesRef.current.delete(id);
|
|
11251
|
+
}
|
|
11252
|
+
}, []);
|
|
11253
|
+
// StatusRegion only describes polite notifications that are on screen, and
|
|
11254
|
+
// each of those registered its message element when it mounted. The
|
|
11255
|
+
// fallback is for a notification announced without being rendered, should
|
|
11256
|
+
// the container ever render fewer than it announces: a plain-text message
|
|
11257
|
+
// still says itself, and anything else is skipped.
|
|
11258
|
+
const describe = React.useCallback((item) => {
|
|
11259
|
+
const node = messageNodesRef.current.get(item.id);
|
|
11260
|
+
/* istanbul ignore if: every polite notification on screen registers its message element when it mounts */
|
|
11261
|
+
if (!node) {
|
|
11262
|
+
const { message } = item.options;
|
|
11263
|
+
return typeof message === 'string' ? message : null;
|
|
11264
|
+
}
|
|
11265
|
+
return spokenText(node);
|
|
11266
|
+
}, []);
|
|
11267
|
+
if (typeof document === 'undefined' || !isHydrated) {
|
|
11268
|
+
return null;
|
|
11269
|
+
}
|
|
11270
|
+
const stacks = groupIntoPositionStacks(items, item => item.options.position, position, notificationStackOrder);
|
|
11271
|
+
return reactDom.createPortal(jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [stacks.map(stack => (jsxRuntime.jsx("div", { style: notificationStackStyle(stack.position), children: stack.items.map(item => (jsxRuntime.jsx(NotificationItem, { instance: item, onClose: notification.close, registerMessage: registerMessage }, item.id))) }, stack.key))), jsxRuntime.jsx(StatusRegion, { items: politeItems, describe: describe })] }), resolveContainer());
|
|
11272
|
+
};
|
|
10692
11273
|
|
|
10693
|
-
const validTagColors = [
|
|
10694
|
-
'primary',
|
|
10695
|
-
'link',
|
|
10696
|
-
'info',
|
|
10697
|
-
'success',
|
|
10698
|
-
'warning',
|
|
10699
|
-
'danger',
|
|
10700
|
-
'black',
|
|
10701
|
-
'dark',
|
|
10702
|
-
'light',
|
|
10703
|
-
'white',
|
|
10704
|
-
];
|
|
10705
|
-
const validTagSizes = ['normal', 'medium', 'large'];
|
|
10706
11274
|
/**
|
|
10707
|
-
* The `
|
|
11275
|
+
* The `OrderedList` component renders a styled ordered list (`<ol>`) element with Bulma helper class integration.
|
|
10708
11276
|
*
|
|
10709
11277
|
* @function
|
|
10710
|
-
* @param {
|
|
10711
|
-
* @returns {JSX.Element} The rendered
|
|
10712
|
-
* @see {@link https://bulma.io/documentation/elements/tag/ | Bulma Tag documentation}
|
|
11278
|
+
* @param {OrderedListProps} props - Props for the OrderedList component.
|
|
11279
|
+
* @returns {JSX.Element} The rendered ol element.
|
|
10713
11280
|
*/
|
|
10714
|
-
const
|
|
11281
|
+
const OrderedListComponent = ({ className, textColor, bgColor, children, ...props }) => {
|
|
10715
11282
|
/**
|
|
10716
11283
|
* Generates Bulma helper classes and separates out remaining props.
|
|
10717
11284
|
*/
|
|
10718
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
'is-light': isLight,
|
|
10723
|
-
'is-rounded': isRounded,
|
|
10724
|
-
'is-delete': isDelete,
|
|
10725
|
-
'is-hoverable': isHoverable,
|
|
11285
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
11286
|
+
color: textColor,
|
|
11287
|
+
backgroundColor: bgColor,
|
|
11288
|
+
...props,
|
|
10726
11289
|
});
|
|
10727
|
-
const
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
}
|
|
10731
|
-
return (jsxRuntime.jsx("span", { className: tagClasses, ...rest, children: children }));
|
|
11290
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
11291
|
+
const listClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11292
|
+
return (jsxRuntime.jsx("ol", { className: listClasses || undefined, ...rest, children: children }));
|
|
10732
11293
|
};
|
|
11294
|
+
const OrderedList = withSubComponents(OrderedListComponent, { Item: ListItem }, 'OrderedList');
|
|
10733
11295
|
|
|
10734
|
-
const validTagsSizes = ['medium', 'large'];
|
|
10735
11296
|
/**
|
|
10736
|
-
* The `
|
|
11297
|
+
* The `Pre` component renders a styled `<pre>` element with Bulma helper class integration.
|
|
10737
11298
|
*
|
|
10738
11299
|
* @function
|
|
10739
|
-
* @param {
|
|
10740
|
-
* @returns {JSX.Element} The rendered
|
|
10741
|
-
* @see {@link https://bulma.io/documentation/elements/tag/#list-of-tags | Bulma Tags documentation}
|
|
11300
|
+
* @param {PreProps} props - Props for the Pre component.
|
|
11301
|
+
* @returns {JSX.Element} The rendered pre element.
|
|
10742
11302
|
*/
|
|
10743
|
-
const
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
*/
|
|
10749
|
-
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
10750
|
-
const bulmaClasses = usePrefixedClassNames('tags', {
|
|
10751
|
-
'has-addons': hasAddons,
|
|
10752
|
-
[`are-${size}`]: size && validTagsSizes.includes(size),
|
|
11303
|
+
const Pre = ({ className, textColor, bgColor, children, ...props }) => {
|
|
11304
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
11305
|
+
color: textColor,
|
|
11306
|
+
backgroundColor: bgColor,
|
|
11307
|
+
...props,
|
|
10753
11308
|
});
|
|
10754
|
-
const
|
|
10755
|
-
|
|
11309
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
11310
|
+
const preClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11311
|
+
return (jsxRuntime.jsx("pre", { className: preClasses || undefined, ...rest, children: children }));
|
|
10756
11312
|
};
|
|
10757
|
-
const Tags = withSubComponents(TagsComponent, { Tag }, 'Tags');
|
|
10758
11313
|
|
|
10759
11314
|
/**
|
|
10760
|
-
* The `
|
|
11315
|
+
* The `Progress` component displays a Bulma-styled progress bar.
|
|
10761
11316
|
*
|
|
10762
11317
|
* @function
|
|
10763
|
-
* @param {
|
|
10764
|
-
* @returns {JSX.Element} The rendered
|
|
11318
|
+
* @param {ProgressProps} props - Props for the Progress component.
|
|
11319
|
+
* @returns {JSX.Element} The rendered progress bar element.
|
|
11320
|
+
* @see {@link https://bulma.io/documentation/elements/progress/ | Bulma Progress documentation}
|
|
10765
11321
|
*/
|
|
10766
|
-
const
|
|
11322
|
+
const Progress = ({ className, color, size, value, max, children, ...props }) => {
|
|
11323
|
+
warnUnstyledColor('Progress', color);
|
|
10767
11324
|
/**
|
|
10768
11325
|
* Generates Bulma helper classes and separates out remaining props.
|
|
10769
11326
|
*/
|
|
10770
11327
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
10771
|
-
color: textColor,
|
|
10772
|
-
backgroundColor: bgColor,
|
|
10773
11328
|
...props,
|
|
10774
11329
|
});
|
|
10775
|
-
const bulmaClasses = usePrefixedClassNames(
|
|
10776
|
-
|
|
10777
|
-
|
|
11330
|
+
const bulmaClasses = usePrefixedClassNames('progress', {
|
|
11331
|
+
[`is-${color}`]: color && validColors.includes(color),
|
|
11332
|
+
[`is-${size}`]: size,
|
|
11333
|
+
});
|
|
11334
|
+
const progressClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11335
|
+
return (jsxRuntime.jsx("progress", { className: progressClasses, value: value, max: max, ...rest, children: children }));
|
|
10778
11336
|
};
|
|
10779
|
-
const UnorderedList = withSubComponents(UnorderedListComponent, { Item: ListItem }, 'UnorderedList');
|
|
10780
11337
|
|
|
10781
|
-
const FieldContext = React.createContext(false);
|
|
10782
|
-
const ControlContext = React.createContext(false);
|
|
10783
|
-
/**
|
|
10784
|
-
* Hook to detect if the component is inside a Field wrapper.
|
|
10785
|
-
* Form components use this to skip rendering their own Field.
|
|
10786
|
-
*/
|
|
10787
|
-
const useInsideField = () => React.useContext(FieldContext);
|
|
10788
|
-
/**
|
|
10789
|
-
* Hook to detect if the component is inside a Control wrapper.
|
|
10790
|
-
* Form components use this to skip rendering their own Control.
|
|
10791
|
-
*/
|
|
10792
|
-
const useInsideControl = () => React.useContext(ControlContext);
|
|
10793
|
-
/** Provider for Field context — used internally by Field component. */
|
|
10794
|
-
const FieldProvider = FieldContext.Provider;
|
|
10795
|
-
/** Provider for Control context — used internally by Control component. */
|
|
10796
|
-
const ControlProvider = ControlContext.Provider;
|
|
10797
|
-
// Each Field-shaping prop, with what takes its place on a `Field` the caller
|
|
10798
|
-
// wraps around the `Control`. `message` needs nothing there, because the
|
|
10799
|
-
// wrapper still renders it inside `Field > Control`. The other Field-level
|
|
10800
|
-
// props (`labelSize`, `labelProps`, `messageColor`) change nothing unless a
|
|
10801
|
-
// `label` or `message` renders, so on their own they keep no `Field`.
|
|
10802
|
-
// `bare-control.test.tsx` holds this list to what each wrapper hands its
|
|
10803
|
-
// `Field` and to which props change its markup, so a new Field-level prop
|
|
10804
|
-
// fails there until it is sorted into one group or the other.
|
|
10805
|
-
const FIELD_SHAPING = [
|
|
10806
|
-
['label', 'label'],
|
|
10807
|
-
['message', undefined],
|
|
10808
|
-
['horizontal', 'horizontal'],
|
|
10809
|
-
['fieldClassName', 'className (for fieldClassName)'],
|
|
10810
|
-
];
|
|
10811
|
-
/** `a`, `a and b`, `a, b and c`. */
|
|
10812
|
-
const listOf = (items) => items.length > 1
|
|
10813
|
-
? `${items.slice(0, -1).join(', ')} and ${items[items.length - 1]}`
|
|
10814
|
-
: items[0];
|
|
10815
11338
|
/**
|
|
10816
|
-
*
|
|
10817
|
-
*
|
|
10818
|
-
*
|
|
10819
|
-
*
|
|
10820
|
-
*
|
|
10821
|
-
*
|
|
10822
|
-
*
|
|
10823
|
-
*
|
|
10824
|
-
*
|
|
10825
|
-
*
|
|
11339
|
+
* The `Skeleton` component provides a Bulma-styled skeleton loader for React applications, useful for indicating that content is loading.
|
|
11340
|
+
*
|
|
11341
|
+
* @function
|
|
11342
|
+
* @param {SkeletonProps} props - Props for the Skeleton component.
|
|
11343
|
+
* @returns {JSX.Element} The rendered skeleton element.
|
|
11344
|
+
*
|
|
11345
|
+
* @example
|
|
11346
|
+
* // Block skeleton
|
|
11347
|
+
* <Skeleton />
|
|
11348
|
+
*
|
|
11349
|
+
* @example
|
|
11350
|
+
* // Multi-line skeleton
|
|
11351
|
+
* <Skeleton variant="lines" lines={5} />
|
|
10826
11352
|
*/
|
|
10827
|
-
const
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
if (
|
|
10831
|
-
return
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
return false;
|
|
10835
|
-
const names = held.map(([prop]) => prop);
|
|
10836
|
-
const moved = held
|
|
10837
|
-
.map(([, onField]) => onField)
|
|
10838
|
-
.filter((onField) => onField !== undefined);
|
|
10839
|
-
warnOnce(`${component}:Field-in-bare-Control:${names.join('+')}`, `[bestax-bulma] <${component} ${names.join(' ')}> inside a <Control> ` +
|
|
10840
|
-
`with no <Field> around it renders its own <Field> for ` +
|
|
10841
|
-
`${names.length > 1 ? 'those props' : 'that prop'}, which puts a ` +
|
|
10842
|
-
`.field inside the .control, a nesting Bulma's styles are not ` +
|
|
10843
|
-
`written for. Wrap the <Control> in a <Field> instead` +
|
|
10844
|
-
(moved.length > 0 ? `, and set ${listOf(moved)} on that <Field>.` : '.'));
|
|
10845
|
-
return true;
|
|
10846
|
-
};
|
|
10847
|
-
// Each Control-level prop, with what takes its place on the `Control` the
|
|
10848
|
-
// caller wrapped around the wrapper. `bare-control.test.tsx` holds this to
|
|
10849
|
-
// what each wrapper hands its own `Control`, so a new Control-level prop
|
|
10850
|
-
// fails there until it is added here and passed to `rendersOwnControl`.
|
|
10851
|
-
const ON_CONTROL = {
|
|
10852
|
-
isLoading: 'isLoading',
|
|
10853
|
-
iconLeft: 'iconLeft',
|
|
10854
|
-
iconLeftName: 'iconLeftName',
|
|
10855
|
-
iconLeftSize: 'iconLeftSize',
|
|
10856
|
-
iconRight: 'iconRight',
|
|
10857
|
-
iconRightName: 'iconRightName',
|
|
10858
|
-
iconRightSize: 'iconRightSize',
|
|
10859
|
-
hasIconsLeft: 'hasIconsLeft',
|
|
10860
|
-
hasIconsRight: 'hasIconsRight',
|
|
10861
|
-
isExpanded: 'isExpanded',
|
|
10862
|
-
controlSize: 'size (for controlSize)',
|
|
10863
|
-
controlClassName: 'className (for controlClassName)',
|
|
11353
|
+
const Skeleton = ({ className, variant = 'block', lines = 3, children, ...props }) => {
|
|
11354
|
+
const linesClass = usePrefixedClassNames('skeleton-lines');
|
|
11355
|
+
const blockClass = usePrefixedClassNames('skeleton-block');
|
|
11356
|
+
if (variant === 'lines') {
|
|
11357
|
+
return (jsxRuntime.jsx("div", { className: classNames(linesClass, className), ...props, children: Array.from({ length: lines }).map((_, i) => (jsxRuntime.jsx("div", {}, i))) }));
|
|
11358
|
+
}
|
|
11359
|
+
return (jsxRuntime.jsx("div", { className: classNames(blockClass, className), ...props, children: children }));
|
|
10864
11360
|
};
|
|
11361
|
+
|
|
10865
11362
|
/**
|
|
10866
|
-
*
|
|
10867
|
-
*
|
|
10868
|
-
*
|
|
10869
|
-
*
|
|
10870
|
-
*
|
|
10871
|
-
* and its warning says so without pointing at a `Control`. A wrapper passes
|
|
10872
|
-
* only the props it hands its own `Control`, as the caller gave them, so a
|
|
10873
|
-
* default the wrapper fills in itself never warns. A prop counts when it is
|
|
10874
|
-
* truthy, since a falsy one would change nothing on a `Control` either.
|
|
10875
|
-
* `iconLeftSize` and `hasIconsLeft` show nothing on a `Control` without a
|
|
10876
|
-
* glyph, so when they move and the caller chose no left icon, the advice
|
|
10877
|
-
* names the wrapper's default glyph too, and following it draws what the
|
|
10878
|
-
* wrapper's own `Control` did.
|
|
10879
|
-
* Internal; not part of the public API.
|
|
11363
|
+
* The `Span` component renders a styled inline `<span>` element with Bulma helper class integration.
|
|
11364
|
+
*
|
|
11365
|
+
* @function
|
|
11366
|
+
* @param {SpanProps} props - Props for the Span component.
|
|
11367
|
+
* @returns {JSX.Element} The rendered span element.
|
|
10880
11368
|
*/
|
|
10881
|
-
const
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
`in inline mode, inside a <Control> or not, so ${doNothing} ` +
|
|
10894
|
-
`nothing. Leave ${held.length > 1 ? 'them' : 'it'} out of an ` +
|
|
10895
|
-
`inline picker.`;
|
|
10896
|
-
}
|
|
10897
|
-
else {
|
|
10898
|
-
const toSet = held.map(prop => ON_CONTROL[prop]);
|
|
10899
|
-
const needsGlyph = (options.iconLeftSize || options.hasIconsLeft) &&
|
|
10900
|
-
!options.iconLeft &&
|
|
10901
|
-
options.iconLeftName === undefined &&
|
|
10902
|
-
options.defaultIconLeftName;
|
|
10903
|
-
if (needsGlyph) {
|
|
10904
|
-
toSet.push(`iconLeftName="${options.defaultIconLeftName}" (its default icon)`);
|
|
10905
|
-
}
|
|
10906
|
-
message =
|
|
10907
|
-
`[bestax-bulma] <${component} ${names}> inside a <Control> renders ` +
|
|
10908
|
-
`no <Control> of its own, so ${doNothing} nothing there. Set ` +
|
|
10909
|
-
`${listOf(toSet)} on that <Control> instead.`;
|
|
10910
|
-
}
|
|
10911
|
-
// Keyed by the message itself: the props named do not settle the advice
|
|
10912
|
-
// (an empty `iconLeftName` and an unset one name the same props), so two
|
|
10913
|
-
// calls that would advise differently must not share a key.
|
|
10914
|
-
warnOnce(message, message);
|
|
10915
|
-
return false;
|
|
11369
|
+
const Span = ({ className, textColor, bgColor, children, ...props }) => {
|
|
11370
|
+
/**
|
|
11371
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11372
|
+
*/
|
|
11373
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
11374
|
+
color: textColor,
|
|
11375
|
+
backgroundColor: bgColor,
|
|
11376
|
+
...props,
|
|
11377
|
+
});
|
|
11378
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
11379
|
+
const spanClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11380
|
+
return (jsxRuntime.jsx("span", { className: spanClasses || undefined, ...rest, children: children }));
|
|
10916
11381
|
};
|
|
10917
|
-
|
|
11382
|
+
|
|
10918
11383
|
/**
|
|
10919
|
-
* The
|
|
10920
|
-
*
|
|
10921
|
-
*
|
|
10922
|
-
*
|
|
10923
|
-
*
|
|
10924
|
-
* unless inline, #968) and, through `useAutoLabelId`, by the convenience
|
|
10925
|
-
* inputs that render an input of their own (#939). Read it only through
|
|
10926
|
-
* those, which report what they take: a control that read it directly would
|
|
10927
|
-
* report nothing and lose its label (#1004), and
|
|
10928
|
-
* `__tests__/field-label-readers.test.ts` fails on one. Internal; not part of
|
|
10929
|
-
* the public API.
|
|
11384
|
+
* The `Strong` component renders a styled `<strong>` element with Bulma helper class integration.
|
|
11385
|
+
*
|
|
11386
|
+
* @function
|
|
11387
|
+
* @param {StrongProps} props - Props for the Strong component.
|
|
11388
|
+
* @returns {JSX.Element} The rendered strong element.
|
|
10930
11389
|
*/
|
|
10931
|
-
const
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
11390
|
+
const Strong = ({ className, textColor, bgColor, children, ...props }) => {
|
|
11391
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
11392
|
+
color: textColor,
|
|
11393
|
+
backgroundColor: bgColor,
|
|
11394
|
+
...props,
|
|
11395
|
+
});
|
|
11396
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
11397
|
+
const strongClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11398
|
+
return (jsxRuntime.jsx("strong", { className: strongClasses || undefined, ...rest, children: children }));
|
|
11399
|
+
};
|
|
11400
|
+
|
|
11401
|
+
const validSubTitleSizes = ['1', '2', '3', '4', '5', '6'];
|
|
11402
|
+
const validSubTitleElements = [
|
|
11403
|
+
'h1',
|
|
11404
|
+
'h2',
|
|
11405
|
+
'h3',
|
|
11406
|
+
'h4',
|
|
11407
|
+
'h5',
|
|
11408
|
+
'h6',
|
|
11409
|
+
'p',
|
|
11410
|
+
];
|
|
10935
11411
|
/**
|
|
10936
|
-
* The
|
|
10937
|
-
*
|
|
10938
|
-
*
|
|
10939
|
-
*
|
|
10940
|
-
*
|
|
10941
|
-
*
|
|
11412
|
+
* The `SubTitle` component renders a Bulma-styled subtitle (secondary heading), supporting sizes `1-6` and rendering as any heading or paragraph element (`h1-h6`, `p`).
|
|
11413
|
+
*
|
|
11414
|
+
* @function
|
|
11415
|
+
* @param {SubTitleProps} props - Props for the SubTitle component.
|
|
11416
|
+
* @returns {JSX.Element} The rendered subtitle element.
|
|
11417
|
+
* @see {@link https://bulma.io/documentation/elements/title/#subtitle | Bulma Subtitle documentation}
|
|
10942
11418
|
*/
|
|
10943
|
-
const
|
|
10944
|
-
/**
|
|
10945
|
-
|
|
10946
|
-
|
|
11419
|
+
const SubTitle = ({ className, size, as = 'h1', hasSkeleton, textColor, bgColor, children, ...props }) => {
|
|
11420
|
+
/**
|
|
11421
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11422
|
+
*/
|
|
11423
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
11424
|
+
color: textColor,
|
|
11425
|
+
backgroundColor: bgColor,
|
|
11426
|
+
...props,
|
|
11427
|
+
});
|
|
11428
|
+
// Validate 'as' prop at runtime
|
|
11429
|
+
const element = validSubTitleElements.includes(as) ? as : 'h1';
|
|
11430
|
+
// Validate 'size' prop at runtime (numeric sizes normalize to strings)
|
|
11431
|
+
const normalized = size == null ? undefined : String(size);
|
|
11432
|
+
const validSize = normalized && validSubTitleSizes.includes(normalized)
|
|
11433
|
+
? normalized
|
|
11434
|
+
: undefined;
|
|
11435
|
+
const bulmaClasses = usePrefixedClassNames('subtitle', {
|
|
11436
|
+
[`is-${validSize}`]: validSize,
|
|
11437
|
+
'has-skeleton': hasSkeleton,
|
|
11438
|
+
});
|
|
11439
|
+
const subTitleClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11440
|
+
// Determine the tag based on 'element' and 'validSize'
|
|
11441
|
+
const Tag = element === 'p' ? 'p' : validSize ? `h${validSize}` : element;
|
|
11442
|
+
return (jsxRuntime.jsx(Tag, { className: subTitleClasses, ...rest, children: children }));
|
|
11443
|
+
};
|
|
11444
|
+
|
|
10947
11445
|
/**
|
|
10948
|
-
*
|
|
10949
|
-
*
|
|
10950
|
-
*
|
|
10951
|
-
*
|
|
10952
|
-
*
|
|
10953
|
-
*
|
|
10954
|
-
*
|
|
10955
|
-
*
|
|
10956
|
-
* it hands out no id for a control. It keeps the generated id after the
|
|
10957
|
-
* label drops a `for` nothing took (#1004), which no control's id matches
|
|
10958
|
-
* then, so the value does not change under the content that reported it.
|
|
10959
|
-
* The `id` is set only while that label renders with it. Unlike
|
|
10960
|
-
* {@link useFieldLabelId}, it is set in a `grouped` or `hasAddons` Field
|
|
10961
|
-
* too, so a label wired by hand names the control its `for` picks in those
|
|
10962
|
-
* rows as well. Consumed through `useAutoLabelId`.
|
|
10963
|
-
* Internal; not part of the public API.
|
|
11446
|
+
* Thead component for rendering a styled Bulma table header.
|
|
11447
|
+
*
|
|
11448
|
+
* Supports Bulma helper classes for additional styling.
|
|
11449
|
+
*
|
|
11450
|
+
* @function
|
|
11451
|
+
* @param {TheadProps} props - Props for the Thead component.
|
|
11452
|
+
* @returns {JSX.Element} The rendered table header element.
|
|
11453
|
+
* @see {@link https://bulma.io/documentation/elements/table/#table-head | Bulma Table documentation}
|
|
10964
11454
|
*/
|
|
10965
|
-
const
|
|
10966
|
-
/**
|
|
10967
|
-
|
|
10968
|
-
|
|
11455
|
+
const Thead = ({ className, children, ...props }) => {
|
|
11456
|
+
/**
|
|
11457
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11458
|
+
*/
|
|
11459
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11460
|
+
const theadClasses = classNames(className, bulmaHelperClasses);
|
|
11461
|
+
return (jsxRuntime.jsx("thead", { className: theadClasses || undefined, ...rest, children: children }));
|
|
11462
|
+
};
|
|
11463
|
+
|
|
10969
11464
|
/**
|
|
10970
|
-
*
|
|
10971
|
-
*
|
|
10972
|
-
*
|
|
10973
|
-
*
|
|
10974
|
-
*
|
|
10975
|
-
*
|
|
10976
|
-
*
|
|
10977
|
-
*
|
|
10978
|
-
* as {@link useFieldLabelId}, so a label wired by hand and a `grouped` or
|
|
10979
|
-
* `hasAddons` Field hear nothing. It reports from a layout effect, which a
|
|
10980
|
-
* server never runs and a hydrating client runs only after its first render,
|
|
10981
|
-
* so that render writes the `for` the way the server did.
|
|
10982
|
-
* Internal; not part of the public API.
|
|
11465
|
+
* Tbody component for rendering a styled Bulma table body.
|
|
11466
|
+
*
|
|
11467
|
+
* Supports Bulma helper classes for additional styling.
|
|
11468
|
+
*
|
|
11469
|
+
* @function
|
|
11470
|
+
* @param {TbodyProps} props - Props for the Tbody component.
|
|
11471
|
+
* @returns {JSX.Element} The rendered table body element.
|
|
11472
|
+
* @see {@link https://bulma.io/documentation/elements/table/#table-body | Bulma Table documentation}
|
|
10983
11473
|
*/
|
|
10984
|
-
const
|
|
10985
|
-
|
|
10986
|
-
|
|
11474
|
+
const Tbody = ({ className, children, ...props }) => {
|
|
11475
|
+
/**
|
|
11476
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11477
|
+
*/
|
|
11478
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11479
|
+
const tbodyClasses = classNames(className, bulmaHelperClasses);
|
|
11480
|
+
return (jsxRuntime.jsx("tbody", { className: tbodyClasses || undefined, ...rest, children: children }));
|
|
10987
11481
|
};
|
|
10988
|
-
|
|
10989
|
-
const FieldLabelForReportProvider = FieldLabelForReportContext.Provider;
|
|
11482
|
+
|
|
10990
11483
|
/**
|
|
10991
|
-
*
|
|
10992
|
-
*
|
|
10993
|
-
*
|
|
10994
|
-
*
|
|
10995
|
-
*
|
|
10996
|
-
*
|
|
11484
|
+
* Tfoot component for rendering a styled Bulma table footer.
|
|
11485
|
+
*
|
|
11486
|
+
* Supports Bulma helper classes for additional styling.
|
|
11487
|
+
*
|
|
11488
|
+
* @function
|
|
11489
|
+
* @param {TfootProps} props - Props for the Tfoot component.
|
|
11490
|
+
* @returns {JSX.Element} The rendered table footer element.
|
|
11491
|
+
* @see {@link https://bulma.io/documentation/elements/table/#table-footer | Bulma Table documentation}
|
|
10997
11492
|
*/
|
|
10998
|
-
const
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11493
|
+
const Tfoot = ({ className, children, ...props }) => {
|
|
11494
|
+
/**
|
|
11495
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11496
|
+
*/
|
|
11497
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11498
|
+
const tfootClasses = classNames(className, bulmaHelperClasses);
|
|
11499
|
+
return (jsxRuntime.jsx("tfoot", { className: tfootClasses || undefined, ...rest, children: children }));
|
|
11003
11500
|
};
|
|
11004
|
-
|
|
11005
|
-
const CheckboxesContext = React.createContext(undefined);
|
|
11501
|
+
|
|
11006
11502
|
/**
|
|
11007
|
-
*
|
|
11008
|
-
*
|
|
11503
|
+
* The values the table `color` prop accepts, as a readonly tuple.
|
|
11504
|
+
*
|
|
11505
|
+
* `TableColor` is typed from it, and `Tr`, `Th` and `Td` all take a
|
|
11506
|
+
* `TableColor`, so the tuple and those props list the same values. Map over
|
|
11507
|
+
* it to build a color picker, or check a value that arrives at runtime before
|
|
11508
|
+
* passing it in: the components add no color class for a value outside the
|
|
11509
|
+
* tuple.
|
|
11510
|
+
*
|
|
11511
|
+
* @example
|
|
11512
|
+
* import { Tr, Td, validTableColors } from '@allxsmith/bestax-bulma';
|
|
11513
|
+
*
|
|
11514
|
+
* <Tr>
|
|
11515
|
+
* {validTableColors.map(color => (
|
|
11516
|
+
* <Td key={color} color={color}>
|
|
11517
|
+
* {color}
|
|
11518
|
+
* </Td>
|
|
11519
|
+
* ))}
|
|
11520
|
+
* </Tr>;
|
|
11009
11521
|
*/
|
|
11010
|
-
const
|
|
11522
|
+
const validTableColors = [
|
|
11523
|
+
'primary',
|
|
11524
|
+
'link',
|
|
11525
|
+
'info',
|
|
11526
|
+
'success',
|
|
11527
|
+
'warning',
|
|
11528
|
+
'danger',
|
|
11529
|
+
'black',
|
|
11530
|
+
'dark',
|
|
11531
|
+
'light',
|
|
11532
|
+
'white',
|
|
11533
|
+
];
|
|
11011
11534
|
/**
|
|
11012
|
-
*
|
|
11013
|
-
*
|
|
11535
|
+
* Td component for rendering a styled Bulma table cell.
|
|
11536
|
+
*
|
|
11537
|
+
* Supports Bulma color modifiers and helper classes for additional styling.
|
|
11538
|
+
*
|
|
11539
|
+
* @function
|
|
11540
|
+
* @param {TdProps} props - Props for the Td component.
|
|
11541
|
+
* @returns {JSX.Element} The rendered table cell element.
|
|
11542
|
+
* @see {@link https://bulma.io/documentation/elements/table/#table-body | Bulma Table documentation}
|
|
11543
|
+
*/
|
|
11544
|
+
const Td = ({ className, color, children, ...props }) => {
|
|
11545
|
+
const colorClass = usePrefixedClassNames('', {
|
|
11546
|
+
[`is-${color}`]: color && validTableColors.includes(color),
|
|
11547
|
+
});
|
|
11548
|
+
/**
|
|
11549
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11550
|
+
*/
|
|
11551
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11552
|
+
const tdClasses = classNames(colorClass, className, bulmaHelperClasses);
|
|
11553
|
+
return (jsxRuntime.jsx("td", { className: tdClasses || undefined, ...rest, children: children }));
|
|
11554
|
+
};
|
|
11555
|
+
|
|
11556
|
+
/**
|
|
11557
|
+
* Tr component for rendering a styled Bulma table row.
|
|
11558
|
+
*
|
|
11559
|
+
* Supports the is-selected modifier and color modifiers.
|
|
11560
|
+
*
|
|
11561
|
+
* @function
|
|
11562
|
+
* @param {TrProps} props - Props for the Tr component.
|
|
11563
|
+
* @returns {JSX.Element} The rendered table row element.
|
|
11564
|
+
* @see {@link https://bulma.io/documentation/elements/table/#table-row | Bulma Table documentation}
|
|
11014
11565
|
*/
|
|
11015
|
-
const
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11566
|
+
const Tr = ({ className, isSelected, color, children, ...props }) => {
|
|
11567
|
+
const bulmaClasses = usePrefixedClassNames('', {
|
|
11568
|
+
'is-selected': isSelected,
|
|
11569
|
+
[`is-${color}`]: color && validTableColors.includes(color),
|
|
11570
|
+
});
|
|
11571
|
+
/**
|
|
11572
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11573
|
+
*/
|
|
11574
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11575
|
+
const trClasses = classNames(bulmaClasses, className, bulmaHelperClasses);
|
|
11576
|
+
return (jsxRuntime.jsx("tr", { className: trClasses || undefined, ...rest, children: children }));
|
|
11577
|
+
};
|
|
11020
11578
|
|
|
11579
|
+
const validAlignments = ['left', 'right', 'centered'];
|
|
11021
11580
|
/**
|
|
11022
|
-
*
|
|
11581
|
+
* Th component for rendering a styled Bulma table header cell.
|
|
11023
11582
|
*
|
|
11024
|
-
*
|
|
11025
|
-
* Map over it to build a color picker, or check a value that arrives at
|
|
11026
|
-
* runtime before passing it in: the component adds no color class for a value
|
|
11027
|
-
* outside the tuple.
|
|
11583
|
+
* Supports alignment, width, and color modifiers.
|
|
11028
11584
|
*
|
|
11029
|
-
* @
|
|
11030
|
-
*
|
|
11585
|
+
* @function
|
|
11586
|
+
* @param {ThProps} props - Props for the Th component.
|
|
11587
|
+
* @returns {JSX.Element} The rendered table header cell element.
|
|
11588
|
+
* @see {@link https://bulma.io/documentation/elements/table/#table-head | Bulma Table documentation}
|
|
11589
|
+
*/
|
|
11590
|
+
const Th = ({ className, isAligned, width, color, children, ...props }) => {
|
|
11591
|
+
const bulmaClasses = usePrefixedClassNames('', {
|
|
11592
|
+
[`has-text-${isAligned}`]: isAligned && validAlignments.includes(isAligned),
|
|
11593
|
+
[`is-${color}`]: color && validTableColors.includes(color),
|
|
11594
|
+
});
|
|
11595
|
+
/**
|
|
11596
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11597
|
+
*/
|
|
11598
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11599
|
+
const thClasses = classNames(bulmaClasses, className, bulmaHelperClasses);
|
|
11600
|
+
return (jsxRuntime.jsx("th", { className: thClasses || undefined, style: width
|
|
11601
|
+
? { width: typeof width === 'number' ? `${width}px` : width }
|
|
11602
|
+
: undefined, ...rest, children: children }));
|
|
11603
|
+
};
|
|
11604
|
+
|
|
11605
|
+
/**
|
|
11606
|
+
* The `Table` component and its subcomponents provide a highly composable, Bulma-styled table system for React.
|
|
11031
11607
|
*
|
|
11032
|
-
*
|
|
11033
|
-
*
|
|
11034
|
-
*
|
|
11035
|
-
*
|
|
11036
|
-
* ));
|
|
11608
|
+
* @function
|
|
11609
|
+
* @param {TableProps} props - Props for the Table component.
|
|
11610
|
+
* @returns {JSX.Element} The rendered table element.
|
|
11611
|
+
* @see {@link https://bulma.io/documentation/elements/table/ | Bulma Table documentation}
|
|
11037
11612
|
*/
|
|
11038
|
-
const
|
|
11613
|
+
const TableComponent = ({ className, isBordered, isStriped, isNarrow, isHoverable, isFullwidth, isFullWidth, isResponsive, children, ...props }) => {
|
|
11614
|
+
/**
|
|
11615
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11616
|
+
*/
|
|
11617
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11618
|
+
const bulmaClasses = usePrefixedClassNames('table', {
|
|
11619
|
+
'is-bordered': isBordered,
|
|
11620
|
+
'is-striped': isStriped,
|
|
11621
|
+
'is-narrow': isNarrow,
|
|
11622
|
+
'is-hoverable': isHoverable,
|
|
11623
|
+
'is-fullwidth': isFullwidth ?? isFullWidth,
|
|
11624
|
+
});
|
|
11625
|
+
const containerClass = usePrefixedClassNames('table-container');
|
|
11626
|
+
const tableClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11627
|
+
const tableElement = (jsxRuntime.jsx("table", { className: tableClasses, ...rest, children: children }));
|
|
11628
|
+
if (isResponsive) {
|
|
11629
|
+
return jsxRuntime.jsx("div", { className: containerClass, children: tableElement });
|
|
11630
|
+
}
|
|
11631
|
+
return tableElement;
|
|
11632
|
+
};
|
|
11633
|
+
const Table = withSubComponents(TableComponent, {
|
|
11634
|
+
Thead,
|
|
11635
|
+
Tbody,
|
|
11636
|
+
Tfoot,
|
|
11637
|
+
Tr,
|
|
11638
|
+
Th,
|
|
11639
|
+
Td,
|
|
11640
|
+
}, 'Table');
|
|
11641
|
+
|
|
11642
|
+
const validTagColors = [
|
|
11039
11643
|
'primary',
|
|
11040
11644
|
'link',
|
|
11041
11645
|
'info',
|
|
11042
11646
|
'success',
|
|
11043
11647
|
'warning',
|
|
11044
11648
|
'danger',
|
|
11649
|
+
'black',
|
|
11650
|
+
'dark',
|
|
11651
|
+
'light',
|
|
11652
|
+
'white',
|
|
11045
11653
|
];
|
|
11654
|
+
const validTagSizes = ['normal', 'medium', 'large'];
|
|
11046
11655
|
/**
|
|
11047
|
-
* The
|
|
11048
|
-
*
|
|
11049
|
-
* `CheckboxProps['size']` is typed from it, so the two list the same values.
|
|
11050
|
-
* Use it to offer a size choice or to check a value that arrives at runtime:
|
|
11051
|
-
* the component adds no size class for a value outside the tuple. These are
|
|
11052
|
-
* element sizes, not the spacing scale in `validSizes`.
|
|
11053
|
-
*
|
|
11054
|
-
* @example
|
|
11055
|
-
* import { checkboxSizes } from '@allxsmith/bestax-bulma';
|
|
11656
|
+
* The `Tag` component renders a Bulma-styled label or badge.
|
|
11056
11657
|
*
|
|
11057
|
-
*
|
|
11658
|
+
* @function
|
|
11659
|
+
* @param {TagProps} props - Props for the Tag component.
|
|
11660
|
+
* @returns {JSX.Element} The rendered tag element.
|
|
11661
|
+
* @see {@link https://bulma.io/documentation/elements/tag/ | Bulma Tag documentation}
|
|
11058
11662
|
*/
|
|
11059
|
-
const
|
|
11663
|
+
const Tag = ({ className, color, size, isLight, isRounded, isDelete, isHoverable, onDelete, children, ...props }) => {
|
|
11664
|
+
/**
|
|
11665
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11666
|
+
*/
|
|
11667
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11668
|
+
const bulmaClasses = usePrefixedClassNames('tag', {
|
|
11669
|
+
[`is-${color}`]: color && validTagColors.includes(color),
|
|
11670
|
+
[`is-${size}`]: size && size !== 'normal' && validTagSizes.includes(size),
|
|
11671
|
+
'is-light': isLight,
|
|
11672
|
+
'is-rounded': isRounded,
|
|
11673
|
+
'is-delete': isDelete,
|
|
11674
|
+
'is-hoverable': isHoverable,
|
|
11675
|
+
});
|
|
11676
|
+
const tagClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11677
|
+
if (isDelete) {
|
|
11678
|
+
return (jsxRuntime.jsx("button", { className: tagClasses, onClick: onDelete, ...rest, "aria-label": rest['aria-label'] || 'Delete tag', type: buttonType(rest.type) }));
|
|
11679
|
+
}
|
|
11680
|
+
return (jsxRuntime.jsx("span", { className: tagClasses, ...rest, children: children }));
|
|
11681
|
+
};
|
|
11682
|
+
|
|
11683
|
+
const validTagsSizes = ['medium', 'large'];
|
|
11060
11684
|
/**
|
|
11061
|
-
* The `
|
|
11685
|
+
* The `Tags` component groups multiple `Tag` components together in a Bulma-styled container that wraps onto multiple lines by default.
|
|
11062
11686
|
*
|
|
11063
11687
|
* @function
|
|
11064
|
-
* @param {
|
|
11065
|
-
* @returns {JSX.Element} The rendered
|
|
11066
|
-
*
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11688
|
+
* @param {TagsProps} props - Props for the Tags component.
|
|
11689
|
+
* @returns {JSX.Element} The rendered tags container.
|
|
11690
|
+
* @see {@link https://bulma.io/documentation/elements/tag/#list-of-tags | Bulma Tags documentation}
|
|
11691
|
+
*/
|
|
11692
|
+
const TagsComponent = ({ className, hasAddons,
|
|
11693
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- accepted for backwards compatibility, deprecated no-op (no `are-multiline` CSS ships)
|
|
11694
|
+
isMultiline, size, children, ...props }) => {
|
|
11695
|
+
/**
|
|
11696
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11697
|
+
*/
|
|
11698
|
+
const { bulmaHelperClasses, rest } = useBulmaClasses({ ...props });
|
|
11699
|
+
const bulmaClasses = usePrefixedClassNames('tags', {
|
|
11700
|
+
'has-addons': hasAddons,
|
|
11701
|
+
[`are-${size}`]: size && validTagsSizes.includes(size),
|
|
11702
|
+
});
|
|
11703
|
+
const tagsClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11704
|
+
return (jsxRuntime.jsx("div", { className: tagsClasses, ...rest, children: children }));
|
|
11705
|
+
};
|
|
11706
|
+
const Tags = withSubComponents(TagsComponent, { Tag }, 'Tags');
|
|
11707
|
+
|
|
11708
|
+
/**
|
|
11709
|
+
* The `UnorderedList` component renders a styled unordered list (`<ul>`) element with Bulma helper class integration.
|
|
11070
11710
|
*
|
|
11071
|
-
* @
|
|
11072
|
-
*
|
|
11073
|
-
*
|
|
11074
|
-
* <Checkbox value="react">React</Checkbox>
|
|
11075
|
-
* <Checkbox value="vue">Vue</Checkbox>
|
|
11076
|
-
* </Checkboxes>
|
|
11711
|
+
* @function
|
|
11712
|
+
* @param {UnorderedListProps} props - Props for the UnorderedList component.
|
|
11713
|
+
* @returns {JSX.Element} The rendered ul element.
|
|
11077
11714
|
*/
|
|
11078
|
-
const
|
|
11715
|
+
const UnorderedListComponent = ({ className, textColor, bgColor, children, ...props }) => {
|
|
11716
|
+
/**
|
|
11717
|
+
* Generates Bulma helper classes and separates out remaining props.
|
|
11718
|
+
*/
|
|
11079
11719
|
const { bulmaHelperClasses, rest } = useBulmaClasses({
|
|
11080
11720
|
color: textColor,
|
|
11721
|
+
backgroundColor: bgColor,
|
|
11081
11722
|
...props,
|
|
11082
11723
|
});
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
inputRef.current = node;
|
|
11089
|
-
if (typeof ref === 'function')
|
|
11090
|
-
return ref(node);
|
|
11091
|
-
if (ref)
|
|
11092
|
-
ref.current = node;
|
|
11093
|
-
}, [ref]);
|
|
11094
|
-
// `indeterminate` is a DOM property with no attribute, so it's set on the
|
|
11095
|
-
// input rather than rendered. A click clears it, so this runs after every
|
|
11096
|
-
// render, not only when the prop changes. Unset, it's left alone, so a
|
|
11097
|
-
// ref that sets the property itself still works. `ownsIndeterminateRef`
|
|
11098
|
-
// remembers that this component set it, so a prop that goes back to unset
|
|
11099
|
-
// clears the dash once instead of leaving it on.
|
|
11100
|
-
const ownsIndeterminateRef = React.useRef(false);
|
|
11101
|
-
useClientLayoutEffect(() => {
|
|
11102
|
-
if (indeterminate !== undefined) {
|
|
11103
|
-
ownsIndeterminateRef.current = true;
|
|
11104
|
-
inputRef.current.indeterminate = indeterminate;
|
|
11105
|
-
}
|
|
11106
|
-
else if (ownsIndeterminateRef.current) {
|
|
11107
|
-
ownsIndeterminateRef.current = false;
|
|
11108
|
-
inputRef.current.indeterminate = false;
|
|
11109
|
-
}
|
|
11110
|
-
});
|
|
11111
|
-
// Inherit name + selection state from a surrounding <Checkboxes> group.
|
|
11112
|
-
// Local props always win over the group (explicit > implicit).
|
|
11113
|
-
const group = useCheckboxesGroup();
|
|
11114
|
-
const effectiveName = name ?? group?.name;
|
|
11115
|
-
// Group-managed checked state — only when the group is in
|
|
11116
|
-
// controlled/uncontrolled mode (group.value is defined) AND this Checkbox
|
|
11117
|
-
// has a value to compare against. Local `checked` always wins.
|
|
11118
|
-
const groupManaged = group?.value !== undefined && value !== undefined;
|
|
11119
|
-
const groupHas = groupManaged && group.value.includes(String(value));
|
|
11120
|
-
const effectiveChecked = checked !== undefined ? checked : groupManaged ? groupHas : undefined;
|
|
11121
|
-
// When the group manages checked, suppress local defaultChecked to avoid
|
|
11122
|
-
// the controlled/uncontrolled React warning.
|
|
11123
|
-
const effectiveDefaultChecked = groupManaged ? undefined : defaultChecked;
|
|
11124
|
-
const handleChange = React.useCallback((e) => {
|
|
11125
|
-
// The click that got here cleared the mixed state. Put it back now,
|
|
11126
|
-
// since a click that changes no state renders nothing to do it.
|
|
11127
|
-
if (indeterminate !== undefined)
|
|
11128
|
-
e.target.indeterminate = indeterminate;
|
|
11129
|
-
// Local onChange always fires.
|
|
11130
|
-
onChange?.(e);
|
|
11131
|
-
// Dispatch to the group additionally — toggle this value's
|
|
11132
|
-
// membership in the group's array.
|
|
11133
|
-
if (group?.onChange && value !== undefined) {
|
|
11134
|
-
const valStr = String(value);
|
|
11135
|
-
const currentArr = group.value ?? [];
|
|
11136
|
-
const next = e.target.checked
|
|
11137
|
-
? currentArr.includes(valStr)
|
|
11138
|
-
? currentArr
|
|
11139
|
-
: [...currentArr, valStr]
|
|
11140
|
-
: currentArr.filter(v => v !== valStr);
|
|
11141
|
-
group.onChange(next);
|
|
11142
|
-
}
|
|
11143
|
-
}, [onChange, group, value, indeterminate]);
|
|
11144
|
-
const mainClass = usePrefixedClassNames('styled-checkbox', 'checkbox', {
|
|
11145
|
-
[`is-${color}`]: color && checkboxColors.includes(color),
|
|
11146
|
-
[`is-${size}`]: size && checkboxSizes.includes(size),
|
|
11147
|
-
});
|
|
11148
|
-
const checkboxClass = classNames(mainClass, bulmaHelperClasses, className);
|
|
11149
|
-
const checkClass = usePrefixedClassNames('check');
|
|
11150
|
-
const controlLabelClass = usePrefixedClassNames('control-label');
|
|
11151
|
-
return (jsxRuntime.jsxs("label", { className: checkboxClass, children: [jsxRuntime.jsx("input", { ref: setRefs, type: "checkbox", disabled: disabled, name: effectiveName, value: value, checked: effectiveChecked, defaultChecked: effectiveDefaultChecked, onChange: handleChange, ...rest }), jsxRuntime.jsx("span", { className: checkClass }), children && jsxRuntime.jsx("span", { className: controlLabelClass, children: children })] }));
|
|
11152
|
-
});
|
|
11153
|
-
Checkbox.displayName = 'Checkbox';
|
|
11724
|
+
const bulmaClasses = usePrefixedClassNames();
|
|
11725
|
+
const listClasses = classNames(bulmaClasses, bulmaHelperClasses, className);
|
|
11726
|
+
return (jsxRuntime.jsx("ul", { className: listClasses || undefined, ...rest, children: children }));
|
|
11727
|
+
};
|
|
11728
|
+
const UnorderedList = withSubComponents(UnorderedListComponent, { Item: ListItem }, 'UnorderedList');
|
|
11154
11729
|
|
|
11155
11730
|
// Whether the nearest enclosing `Control` shows its `isLoading` spinner. The
|
|
11156
11731
|
// picker bases read it so their right-side launcher gives way to that
|
|
@@ -20126,6 +20701,8 @@ exports.ToastContainer = ToastContainer;
|
|
|
20126
20701
|
exports.ToggleButton = ToggleButton;
|
|
20127
20702
|
exports.Tooltip = Tooltip;
|
|
20128
20703
|
exports.Tr = Tr;
|
|
20704
|
+
exports.TreeView = TreeView;
|
|
20705
|
+
exports.TreeViewItem = TreeViewItem;
|
|
20129
20706
|
exports.UnorderedList = UnorderedList;
|
|
20130
20707
|
exports.checkboxColors = checkboxColors;
|
|
20131
20708
|
exports.checkboxSizes = checkboxSizes;
|