@allxsmith/bestax-bulma 5.18.1 → 5.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +137 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.esm.js +137 -35
- package/dist/index.esm.js.map +1 -1
- package/dist/types/components/Avatar.d.ts +3 -0
- package/dist/types/components/Dropdown.d.ts +6 -1
- package/dist/types/components/Menu.d.ts +6 -1
- package/dist/types/components/Toast.d.ts +15 -4
- package/dist/types/elements/Notification.d.ts +16 -4
- package/dist/types/helpers/buttonType.d.ts +19 -0
- package/dist/types/helpers/positionStacks.d.ts +33 -0
- package/dist/types-cjs/components/Avatar.d.ts +3 -0
- package/dist/types-cjs/components/Dropdown.d.ts +6 -1
- package/dist/types-cjs/components/Menu.d.ts +6 -1
- package/dist/types-cjs/components/Toast.d.ts +15 -4
- package/dist/types-cjs/elements/Notification.d.ts +16 -4
- package/dist/types-cjs/helpers/buttonType.d.ts +19 -0
- package/dist/types-cjs/helpers/positionStacks.d.ts +33 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1237,6 +1237,27 @@ const ColumnsComponent = ({ className, textColor, color: _fieldColor, bgColor, i
|
|
|
1237
1237
|
};
|
|
1238
1238
|
const Columns = withSubComponents(ColumnsComponent, { Column }, 'Columns');
|
|
1239
1239
|
|
|
1240
|
+
/**
|
|
1241
|
+
* The `type` to render on a `<button>` a component defaults to `button`: the
|
|
1242
|
+
* caller's own value when it is `button`, `submit` or `reset`, and `button`
|
|
1243
|
+
* otherwise.
|
|
1244
|
+
*
|
|
1245
|
+
* A missing `type` is not the only way a button ends up submitting the form
|
|
1246
|
+
* around it. HTML reads an invalid value, such as the anchor's MIME-type
|
|
1247
|
+
* `type="text/html"`, as submit too, and a props spread carrying
|
|
1248
|
+
* `type: undefined` removes the attribute outright. Both can arrive through a
|
|
1249
|
+
* spread or an untyped caller the component's own types never see, so this
|
|
1250
|
+
* checks the value rather than trusting where it came from.
|
|
1251
|
+
*
|
|
1252
|
+
* Call it AFTER the forwarded props are spread and pass it the forwarded
|
|
1253
|
+
* `type`, so its result is the attribute that renders.
|
|
1254
|
+
*/
|
|
1255
|
+
function buttonType(given) {
|
|
1256
|
+
return given === 'submit' || given === 'reset' || given === 'button'
|
|
1257
|
+
? given
|
|
1258
|
+
: 'button';
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1240
1261
|
/**
|
|
1241
1262
|
* Whether an `as` target is a custom element rather than a built-in tag.
|
|
1242
1263
|
*
|
|
@@ -1534,7 +1555,7 @@ const Avatar = React.forwardRef(function Avatar(avatarProps, ref) {
|
|
|
1534
1555
|
// The decorative opt-out never applies to an interactive avatar — a link or
|
|
1535
1556
|
// button must always expose an accessible name.
|
|
1536
1557
|
const isDecorative = alt === '' && !isInteractive;
|
|
1537
|
-
const
|
|
1558
|
+
const a11yDefaults = showImage
|
|
1538
1559
|
? isInteractive && !accessibleName
|
|
1539
1560
|
? // The img alt normally names the control; with no alt/name (an API
|
|
1540
1561
|
// returning only a photo URL) the link/button would be nameless.
|
|
@@ -1546,10 +1567,18 @@ const Avatar = React.forwardRef(function Avatar(avatarProps, ref) {
|
|
|
1546
1567
|
...(isInteractive ? {} : { role: 'img' }),
|
|
1547
1568
|
'aria-label': accessibleName || name || 'Avatar',
|
|
1548
1569
|
};
|
|
1549
|
-
//
|
|
1550
|
-
//
|
|
1551
|
-
|
|
1552
|
-
|
|
1570
|
+
// Each default yields to a value the caller passed, and is applied after
|
|
1571
|
+
// `rest` reading through it rather than spread before it. React treats an
|
|
1572
|
+
// `undefined` attribute as "remove it", and a spread carrying the key with no
|
|
1573
|
+
// value is how that arrives, so a default spread first was erased by it: an
|
|
1574
|
+
// `aria-label: undefined` left a button avatar nameless, and `role` and
|
|
1575
|
+
// `aria-hidden` went the same way. The button `type` below has the same
|
|
1576
|
+
// shape (#690).
|
|
1577
|
+
const a11yProps = Object.fromEntries(Object.entries(a11yDefaults).map(([key, fallback]) => [
|
|
1578
|
+
key,
|
|
1579
|
+
rest[key] ?? fallback,
|
|
1580
|
+
]));
|
|
1581
|
+
return (jsxRuntime.jsxs(Tag, { ref: ref, className: combinedClasses, style: { ...sizeStyle, ...style }, ...linkProps, ...rest, ...a11yProps, ...(Tag === 'button' ? { type: buttonType(rest.type) } : {}), children: [showImage && (jsxRuntime.jsx("img", { ...imageProps, ref: imgRef, src: src, alt: accessibleName ?? '', onError: e => {
|
|
1553
1582
|
imageProps?.onError?.(e);
|
|
1554
1583
|
setErroredSrc(src);
|
|
1555
1584
|
} }, src)), showInitials && (jsxRuntime.jsx("span", { className: initialsClass, children: resolvedInitials })), showIcon && icon, showDefaultIcon && jsxRuntime.jsx(DefaultAvatarIcon, {})] }));
|
|
@@ -2049,7 +2078,6 @@ const CardFooterItem = ({ as = 'span', className, children, color, bgColor, text
|
|
|
2049
2078
|
}
|
|
2050
2079
|
const forwarded = omitAttrs(rest, STRIP_FROM_NON_ANCHOR$1);
|
|
2051
2080
|
if (as === 'button') {
|
|
2052
|
-
const forwardedType = forwarded.type;
|
|
2053
2081
|
return (jsxRuntime.jsx("button", { className: itemClasses, ...forwarded,
|
|
2054
2082
|
// A footer item button must not submit an enclosing form by default —
|
|
2055
2083
|
// `<button>` defaults to `type="submit"`, and a Save/Cancel action row
|
|
@@ -2059,13 +2087,9 @@ const CardFooterItem = ({ as = 'span', className, children, color, bgColor, text
|
|
|
2059
2087
|
// typed here as the `<a>` MIME string (`STRIP_FROM_NON_ANCHOR` above
|
|
2060
2088
|
// says why it is not withheld), so `as="button" type="text/html"`
|
|
2061
2089
|
// compiles, and HTML's INVALID-value default for a button's `type` is
|
|
2062
|
-
// submit too.
|
|
2063
|
-
//
|
|
2064
|
-
type:
|
|
2065
|
-
forwardedType === 'reset' ||
|
|
2066
|
-
forwardedType === 'button'
|
|
2067
|
-
? forwardedType
|
|
2068
|
-
: 'button', children: children }));
|
|
2090
|
+
// submit too. `buttonType` keeps `button`, `submit` and `reset` and
|
|
2091
|
+
// turns anything else into `button`.
|
|
2092
|
+
type: buttonType(forwarded.type), children: children }));
|
|
2069
2093
|
}
|
|
2070
2094
|
return (jsxRuntime.jsx("span", { className: itemClasses, ...omitAttrs(forwarded, STRIP_FROM_NON_BUTTON), children: children }));
|
|
2071
2095
|
};
|
|
@@ -2402,9 +2426,7 @@ const DropdownItem = ((itemProps) => {
|
|
|
2402
2426
|
// carrying `role: undefined` would otherwise erase the default, and an
|
|
2403
2427
|
// item with no role drops out of the menu and its arrow-key order.
|
|
2404
2428
|
role: forwarded.role ?? 'menuitem', ...(Component === 'button'
|
|
2405
|
-
? {
|
|
2406
|
-
type: forwarded.type ?? 'button',
|
|
2407
|
-
}
|
|
2429
|
+
? { type: buttonType(forwarded.type) }
|
|
2408
2430
|
: {}), children: children }));
|
|
2409
2431
|
});
|
|
2410
2432
|
/**
|
|
@@ -2513,7 +2535,9 @@ const MenuItem = React.forwardRef(function MenuItem(itemProps, ref) {
|
|
|
2513
2535
|
labelChildren.push(child);
|
|
2514
2536
|
}
|
|
2515
2537
|
});
|
|
2516
|
-
return (jsxRuntime.jsxs("li", { className: className, "data-testid": testId, style: style, id: id, title: title, role: role, tabIndex: tabIndex, children: [jsxRuntime.jsx(Component, { ref: ref, className: itemClass || undefined, ...linkProps,
|
|
2538
|
+
return (jsxRuntime.jsxs("li", { className: className, "data-testid": testId, style: style, id: id, title: title, role: role, tabIndex: tabIndex, children: [jsxRuntime.jsx(Component, { ref: ref, className: itemClass || undefined, ...linkProps, ...(Component === 'button'
|
|
2539
|
+
? { type: buttonType(linkProps.type) }
|
|
2540
|
+
: {}), children: labelChildren }), nestedMenuLists] }));
|
|
2517
2541
|
});
|
|
2518
2542
|
MenuItem.displayName = 'MenuItem';
|
|
2519
2543
|
// Attach static subcomponents
|
|
@@ -4713,6 +4737,48 @@ const Sidebar = withSubComponents(SidebarComponent, {
|
|
|
4713
4737
|
Footer: SidebarFooter,
|
|
4714
4738
|
}, 'Sidebar');
|
|
4715
4739
|
|
|
4740
|
+
/**
|
|
4741
|
+
* Splits the items a container shows into one stack per position in use. An
|
|
4742
|
+
* item goes to its own position when it has one and to the container's
|
|
4743
|
+
* otherwise. A position with no items gets no stack.
|
|
4744
|
+
*
|
|
4745
|
+
* Stacks come back in `order`, so their order in the page follows the screen
|
|
4746
|
+
* rather than which position happened to be used first, and a stack keeps its
|
|
4747
|
+
* place while the others come and go. A position missing from `order` sorts
|
|
4748
|
+
* after the known ones.
|
|
4749
|
+
*
|
|
4750
|
+
* @function groupIntoPositionStacks
|
|
4751
|
+
* @param items - The items the container shows, in the order they were shown.
|
|
4752
|
+
* @param positionOf - Reads an item's own position, if it has one.
|
|
4753
|
+
* @param containerPosition - Where an item without a position of its own goes.
|
|
4754
|
+
* @param order - Every known position, in the order stacks should render.
|
|
4755
|
+
* @returns One stack per position in use.
|
|
4756
|
+
*/
|
|
4757
|
+
function groupIntoPositionStacks(items, positionOf, containerPosition, order) {
|
|
4758
|
+
const byPosition = new Map();
|
|
4759
|
+
for (const item of items) {
|
|
4760
|
+
const position = positionOf(item) ?? containerPosition;
|
|
4761
|
+
const stack = byPosition.get(position);
|
|
4762
|
+
if (stack) {
|
|
4763
|
+
stack.push(item);
|
|
4764
|
+
}
|
|
4765
|
+
else {
|
|
4766
|
+
byPosition.set(position, [item]);
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
const rank = (position) => {
|
|
4770
|
+
const index = order.indexOf(position);
|
|
4771
|
+
return index === -1 ? order.length : index;
|
|
4772
|
+
};
|
|
4773
|
+
// Array.prototype.sort is stable, so unknown positions keep the order they
|
|
4774
|
+
// were first used in.
|
|
4775
|
+
return Array.from(byPosition, ([position, stackItems]) => ({
|
|
4776
|
+
key: position === containerPosition ? 'container' : `at-${position}`,
|
|
4777
|
+
position,
|
|
4778
|
+
items: stackItems,
|
|
4779
|
+
})).sort((a, b) => rank(a.position) - rank(b.position));
|
|
4780
|
+
}
|
|
4781
|
+
|
|
4716
4782
|
/**
|
|
4717
4783
|
* The `Toast` component provides brief notification messages with optional action and cancel buttons.
|
|
4718
4784
|
*
|
|
@@ -4989,25 +5055,38 @@ const toast = {
|
|
|
4989
5055
|
return () => toastListeners.delete(listener);
|
|
4990
5056
|
},
|
|
4991
5057
|
};
|
|
5058
|
+
// The order ToastContainer renders its stacks in: across the top of the
|
|
5059
|
+
// screen, then across the bottom.
|
|
5060
|
+
const toastStackOrder = [
|
|
5061
|
+
'top-left',
|
|
5062
|
+
'top-center',
|
|
5063
|
+
'top-right',
|
|
5064
|
+
'bottom-left',
|
|
5065
|
+
'bottom-center',
|
|
5066
|
+
'bottom-right',
|
|
5067
|
+
];
|
|
4992
5068
|
/**
|
|
4993
5069
|
* Container component for rendering programmatic toasts.
|
|
4994
|
-
* Place once at your app root to enable the toast API.
|
|
5070
|
+
* Place once at your app root to enable the toast API. A toast shown with a
|
|
5071
|
+
* `position` appears there, and one shown without goes to the container's
|
|
5072
|
+
* `position`.
|
|
4995
5073
|
*
|
|
4996
5074
|
* @function
|
|
4997
5075
|
* @param {{ position?: ToastPosition }} props - Container props.
|
|
4998
5076
|
* @returns {JSX.Element | null} The rendered toast container, or null if empty.
|
|
4999
5077
|
*/
|
|
5000
|
-
const ToastContainer = ({ position = 'top-right'
|
|
5078
|
+
const ToastContainer = ({ position = 'top-right' }) => {
|
|
5001
5079
|
// Starts from the toasts already showing instead of an empty list, then
|
|
5002
5080
|
// follows changes.
|
|
5003
5081
|
const toastList = React.useSyncExternalStore(toast.subscribe, getVisibleToasts, getServerToasts);
|
|
5004
5082
|
if (typeof document === 'undefined' || toastList.length === 0) {
|
|
5005
5083
|
return null;
|
|
5006
5084
|
}
|
|
5007
|
-
|
|
5085
|
+
const stacks = groupIntoPositionStacks(toastList, t => t.props.position, position, toastStackOrder);
|
|
5086
|
+
return reactDom.createPortal(stacks.map(stack => (jsxRuntime.jsx("div", { className: `toast-container is-${stack.position}`, children: stack.items.map(t => {
|
|
5008
5087
|
const { queue: _queue, ...toastProps } = t.props;
|
|
5009
|
-
return (jsxRuntime.jsx(Toast, { ...toastProps, position: position, onClose: () => toast.close(t.id) }, t.id));
|
|
5010
|
-
}) }), document.body);
|
|
5088
|
+
return (jsxRuntime.jsx(Toast, { ...toastProps, position: stack.position, onClose: () => toast.close(t.id) }, t.id));
|
|
5089
|
+
}) }, stack.key))), document.body);
|
|
5011
5090
|
};
|
|
5012
5091
|
|
|
5013
5092
|
/**
|
|
@@ -6451,25 +6530,28 @@ const NotificationItem = ({ instance, onClose }) => {
|
|
|
6451
6530
|
}, [pauseOnHover]);
|
|
6452
6531
|
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", { role: "status", "aria-live": "polite", children: message })) }));
|
|
6453
6532
|
};
|
|
6533
|
+
// The order NotificationContainer renders its stacks in: across the top of the
|
|
6534
|
+
// screen, then across the bottom.
|
|
6535
|
+
const notificationStackOrder = [
|
|
6536
|
+
'top-left',
|
|
6537
|
+
'top',
|
|
6538
|
+
'top-right',
|
|
6539
|
+
'bottom-left',
|
|
6540
|
+
'bottom',
|
|
6541
|
+
'bottom-right',
|
|
6542
|
+
];
|
|
6454
6543
|
/**
|
|
6455
|
-
*
|
|
6456
|
-
* Place once at your app root to enable the notification API.
|
|
6544
|
+
* Inline style that fixes a stack of notifications to its place on the screen.
|
|
6457
6545
|
*
|
|
6458
6546
|
* @function
|
|
6459
|
-
* @param {
|
|
6460
|
-
* @returns {
|
|
6547
|
+
* @param {NotificationPosition} position - Where the stack sits.
|
|
6548
|
+
* @returns {React.CSSProperties} The stack's style.
|
|
6461
6549
|
*/
|
|
6462
|
-
const
|
|
6463
|
-
// Starts from the notifications already showing instead of an empty list,
|
|
6464
|
-
// then follows changes.
|
|
6465
|
-
const items = React.useSyncExternalStore(notification.subscribe, getVisibleNotifications, getServerNotifications);
|
|
6466
|
-
if (typeof document === 'undefined' || items.length === 0) {
|
|
6467
|
-
return null;
|
|
6468
|
-
}
|
|
6550
|
+
const notificationStackStyle = (position) => {
|
|
6469
6551
|
const isBottom = position.startsWith('bottom');
|
|
6470
6552
|
const isCenter = position === 'top' || position === 'bottom';
|
|
6471
6553
|
const isRight = position.endsWith('right');
|
|
6472
|
-
|
|
6554
|
+
return {
|
|
6473
6555
|
position: 'fixed',
|
|
6474
6556
|
zIndex: 100,
|
|
6475
6557
|
display: 'flex',
|
|
@@ -6485,7 +6567,27 @@ const NotificationContainer = ({ position = 'top-right' }) => {
|
|
|
6485
6567
|
? { right: 0, alignItems: 'flex-end' }
|
|
6486
6568
|
: { left: 0, alignItems: 'flex-start' }),
|
|
6487
6569
|
};
|
|
6488
|
-
|
|
6570
|
+
};
|
|
6571
|
+
/**
|
|
6572
|
+
* Container component for rendering programmatic notifications.
|
|
6573
|
+
* Place once at your app root to enable the notification API. A notification
|
|
6574
|
+
* shown with a `position` appears there, and one shown without goes to the
|
|
6575
|
+
* container's `position`, so the container renders a stack for each position
|
|
6576
|
+
* in use.
|
|
6577
|
+
*
|
|
6578
|
+
* @function
|
|
6579
|
+
* @param {{ position?: NotificationPosition }} props - Container props.
|
|
6580
|
+
* @returns {JSX.Element | null} The rendered notification container, or null if empty.
|
|
6581
|
+
*/
|
|
6582
|
+
const NotificationContainer = ({ position = 'top-right' }) => {
|
|
6583
|
+
// Starts from the notifications already showing instead of an empty list,
|
|
6584
|
+
// then follows changes.
|
|
6585
|
+
const items = React.useSyncExternalStore(notification.subscribe, getVisibleNotifications, getServerNotifications);
|
|
6586
|
+
if (typeof document === 'undefined' || items.length === 0) {
|
|
6587
|
+
return null;
|
|
6588
|
+
}
|
|
6589
|
+
const stacks = groupIntoPositionStacks(items, item => item.options.position, position, notificationStackOrder);
|
|
6590
|
+
return reactDom.createPortal(stacks.map(stack => (jsxRuntime.jsx("div", { style: notificationStackStyle(stack.position), children: stack.items.map(item => (jsxRuntime.jsx(NotificationItem, { instance: item, onClose: notification.close }, item.id))) }, stack.key))), document.body);
|
|
6489
6591
|
};
|
|
6490
6592
|
|
|
6491
6593
|
/**
|