@salemcobalt/ui 0.2.0-rc.28 → 0.2.0-rc.29
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/README.md +1 -1
- package/dist/index.d.ts +20 -3
- package/dist/index.js +28 -13
- package/dist/index.js.map +1 -1
- package/dist/styles.css +20 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ Styles ship as one stylesheet inside `@layer sc`, so an app's unlayered CSS alwa
|
|
|
51
51
|
| `Menu` | `Root` (`open`, `onOpenChange`, `modal`), `Trigger` (secondary Button with a chevron, or `render={<IconButton label="More" />}`), `Content` (`side`, `align`), `Item` (`icon`, decorative; `description`, a muted second line that is the item's accessible description, not part of its name; `trailing`, `tone="danger"`, `disabled`), `LinkItem` (`href`, and the same `icon` and `description`), `CheckboxItem` (`checked`, `onCheckedChange`), `RadioGroup` (`value`, `onValueChange`, `label`) + `RadioItem`, `Group` (`label`), `Separator`. Arrow keys, Home/End, type-ahead, Esc and focus return come from Base UI. |
|
|
52
52
|
| `Table` selection | `useRowSelection(ids)` (ids in visible order; ids that disappear leave the selection): `selected`, `selectedIds`, `count`, `anchor`, `headerState` none · some · all, `isSelected`, `toggle`, `toggleRange`, `selectAll`, `clear`; a pure reducer underneath (`selection.*` events). `Table.Root selection` + `Table.SelectionHeader` (`label`, mixed when some) + `Table.SelectionCell label="Select …"` in a `Table.Row selectionId`. Shift+click (checkbox or row) and Shift+Space extend from the anchor; Cmd/Ctrl+click on a row toggles without reaching its `onClick`; Cmd/Ctrl+A in the table selects all, Esc clears. |
|
|
53
53
|
| `SelectionBar` | Floating bulk-action bar on Toolbar, centred at the bottom of the viewport (content width up to 48rem, gutters and the safe area respected, full width between the gutters under 640px, fade and slide-up, none under reduced motion): `count` (hidden at 0), `onClear`, children are `Toolbar.Button`s, `aria-label` ("Bulk actions"), `countLabel`, `clearLabel`. Mount it at the end of the scrolling content: while open it leaves a spacer as tall as itself so the last rows scroll clear. A polite status region announces the count; focus returns to where it came from when the bar leaves. |
|
|
54
|
-
| `Toast` | `Toast.Provider` (`timeout` 6000, `limit` 3) near the root, `useToast().add({ title, description, tone, action: { label, onClick }, timeout, priority })` below it; Base UI Toast: polite region, paused on hover and focus, F6 to reach it, bottom-end at `--sc-z-toast`.
|
|
54
|
+
| `Toast` | `Toast.Provider` (`timeout` 6000, `limit` 3) near the root (one viewport: a Provider inside another adds nothing), `useToast().add({ title, description, tone, action: { label, onClick, keepOpen }, timeout, priority, id, dismissLabel, onClose })` below it (`timeout: 0` stays; the same `id` updates in place; `dismissLabel` makes the × a text button such as Later); Base UI Toast: polite region, paused on hover and focus, F6 to reach it, bottom-end at `--sc-z-toast`, above an open `SelectionBar` or any bar with `anchor-name: --sc-bottom-bar`. |
|
|
55
55
|
| `PriorityNav` | Priority+ primary navigation (docs/adr/0005): required `aria-label`; `items` as `{ href, label, id?, current?, badge?, badgeLabel? }` in priority order; links that fit stay inline and the rest go into a "More" disclosure (APG disclosure navigation: a `button` with `aria-expanded`, not a menu; Esc, click outside and focus leaving close it). The `current` link is never collapsed. `moreLabel`, `moreCountLabel(n)` (announced only: "More, 3 links"), `renderLink={(props) => <Link {...props} />}` for a router. Server-renders every link on one clipped line (scrolls sideways without JS), measures widths once (again after web fonts load or when keys/string labels change) and re-renders only when the inline count changes. Takes the free space in a flex row (`flex: 1 1 0%`); in a grid use a `minmax(0, 1fr)` track. The open panel sits in the top layer (Popover API), anchored to the toggle with CSS anchor positioning (a JS fallback elsewhere) and capped to the viewport. `data-overflowing` + `onOverflowChange(boolean)` let a header make room, with `overflowHysteresis` (px) so it cannot oscillate. Under 400px wide (container query) More shows only an ellipsis. `badge` (a count, or `'dot'`; `0` shows nothing) draws an accent pill or dot after the label, decorative, with `badgeLabel` ("2 suggestions to review") appended to the link's name; while the item is collapsed, More shows the collapsed items' summed count (a dot when they only have dots) and adds their `badgeLabel`s to its name ("More, 3 links, 2 suggestions to review"). Icon-only, the badge sits on More's corner. No motion. |
|
|
56
56
|
| `Popover` | Non-modal panel on Base UI Popover: `Root` (`open`, `defaultOpen`, `onOpenChange`, `modal` default false), `Trigger` (secondary Button, or `render={<IconButton label dot />}`), `Content` (`side`, `align`, `sideOffset`, `arrow`, `anchor` to position against another element than the Trigger, e.g. a row's action button with a controlled `Root`; portaled to `document.body`; Menu's surface, `--sc-z-dropdown`, dropping to the backdrop layer while a Dialog opened from inside it is open, so the Dialog covers it), `Title` (names the dialog), `Description`, `Close` (the × with no children, or wraps a Button). Esc and focus return come from Base UI. |
|
|
57
57
|
| `BroomIcon` | Animated 24px-grid icon for "a sweep is running": `sweeping`, `size` (Icon sizes, default `lg`, or `display` 72px with a 1.75px stroke), `title`. Inline SVG; strokes stay 1.25px at any size; holds still with the dust shown under `prefers-reduced-motion`. Inside an IconButton it takes the next icon size up. |
|
package/dist/index.d.ts
CHANGED
|
@@ -1870,15 +1870,28 @@ interface ToastOptions {
|
|
|
1870
1870
|
description?: ReactNode | undefined;
|
|
1871
1871
|
/** A coloured edge. Default `neutral`. */
|
|
1872
1872
|
tone?: ToastTone | undefined;
|
|
1873
|
-
/**
|
|
1873
|
+
/**
|
|
1874
|
+
* One action, usually Undo. It closes the toast after `onClick`, unless `keepOpen` (the action asks first, and the
|
|
1875
|
+
* person may cancel).
|
|
1876
|
+
*/
|
|
1874
1877
|
action?: {
|
|
1875
1878
|
label: string;
|
|
1876
1879
|
onClick: () => void;
|
|
1880
|
+
keepOpen?: boolean | undefined;
|
|
1877
1881
|
} | undefined;
|
|
1878
1882
|
/** Milliseconds before it closes; paused while hovered or focused; `0` keeps it. Default: the Provider's. */
|
|
1879
1883
|
timeout?: number | undefined;
|
|
1880
1884
|
/** `high` announces assertively (errors). Default `low`, polite. */
|
|
1881
1885
|
priority?: 'low' | 'high' | undefined;
|
|
1886
|
+
/**
|
|
1887
|
+
* Names the toast. Adding one whose id is showing updates it in place (new text, the timer starts again) instead
|
|
1888
|
+
* of stacking a second.
|
|
1889
|
+
*/
|
|
1890
|
+
id?: string | undefined;
|
|
1891
|
+
/** The dismiss control as a text button ("Later") instead of the ×. */
|
|
1892
|
+
dismissLabel?: string | undefined;
|
|
1893
|
+
/** Called once when it closes, however: dismissed, swiped away, its action, its timeout or `close()`. */
|
|
1894
|
+
onClose?: (() => void) | undefined;
|
|
1882
1895
|
}
|
|
1883
1896
|
interface ToastProviderProps {
|
|
1884
1897
|
children?: ReactNode | undefined;
|
|
@@ -1887,8 +1900,12 @@ interface ToastProviderProps {
|
|
|
1887
1900
|
/** How many show at once; older ones close. Default 3. */
|
|
1888
1901
|
limit?: number | undefined;
|
|
1889
1902
|
}
|
|
1890
|
-
/**
|
|
1891
|
-
|
|
1903
|
+
/**
|
|
1904
|
+
* Holds the toasts for `useToast()` below it and renders them, bottom-end, above the page. One viewport per page: a
|
|
1905
|
+
* Provider inside another adds nothing (its `timeout` and `limit` are ignored), so a component may wrap itself in one
|
|
1906
|
+
* and still share the app's.
|
|
1907
|
+
*/
|
|
1908
|
+
declare function Provider({ children, timeout, limit }: ToastProviderProps): string | number | bigint | boolean | react.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
|
|
1892
1909
|
interface ToastApi {
|
|
1893
1910
|
/** Shows a toast and returns its id. */
|
|
1894
1911
|
add: (options: ToastOptions) => string;
|
package/dist/index.js
CHANGED
|
@@ -2052,13 +2052,15 @@ function SelectionBar({
|
|
|
2052
2052
|
|
|
2053
2053
|
// src/components/Toast/Toast.tsx
|
|
2054
2054
|
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
2055
|
-
import { useMemo as useMemo2 } from "react";
|
|
2055
|
+
import { createContext as createContext3, useContext as useContext3, useMemo as useMemo2 } from "react";
|
|
2056
2056
|
import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2057
|
+
var InsideProvider = createContext3(false);
|
|
2057
2058
|
function Provider2({ children, timeout = 6e3, limit = 3 }) {
|
|
2058
|
-
|
|
2059
|
+
if (useContext3(InsideProvider)) return children;
|
|
2060
|
+
return /* @__PURE__ */ jsx23(InsideProvider.Provider, { value: true, children: /* @__PURE__ */ jsxs20(BaseToast.Provider, { timeout, limit, children: [
|
|
2059
2061
|
children,
|
|
2060
2062
|
/* @__PURE__ */ jsx23(BaseToast.Portal, { children: /* @__PURE__ */ jsx23(Viewport, {}) })
|
|
2061
|
-
] });
|
|
2063
|
+
] }) });
|
|
2062
2064
|
}
|
|
2063
2065
|
function Viewport() {
|
|
2064
2066
|
const { toasts, close } = BaseToast.useToastManager();
|
|
@@ -2074,27 +2076,40 @@ function Viewport() {
|
|
|
2074
2076
|
render: /* @__PURE__ */ jsx23(Button, { variant: "secondary", size: "sm" })
|
|
2075
2077
|
}
|
|
2076
2078
|
) : null,
|
|
2077
|
-
/* @__PURE__ */ jsx23(IconButton, { label: "Dismiss", size: "sm", className: "sc-toast__close", onClick: () => close(toast.id), children: /* @__PURE__ */ jsx23(XIcon, {}) })
|
|
2079
|
+
toast.data?.dismissLabel ? /* @__PURE__ */ jsx23(Button, { variant: "ghost", size: "sm", className: "sc-toast__close", onClick: () => close(toast.id), children: toast.data.dismissLabel }) : /* @__PURE__ */ jsx23(IconButton, { label: "Dismiss", size: "sm", className: "sc-toast__close", onClick: () => close(toast.id), children: /* @__PURE__ */ jsx23(XIcon, {}) })
|
|
2078
2080
|
] }, toast.id)) });
|
|
2079
2081
|
}
|
|
2080
2082
|
function useToast() {
|
|
2081
2083
|
const manager = BaseToast.useToastManager();
|
|
2082
2084
|
return useMemo2(
|
|
2083
2085
|
() => ({
|
|
2084
|
-
add: ({
|
|
2085
|
-
|
|
2086
|
+
add: ({
|
|
2087
|
+
title,
|
|
2088
|
+
description,
|
|
2089
|
+
tone = "neutral",
|
|
2090
|
+
action,
|
|
2091
|
+
timeout,
|
|
2092
|
+
priority,
|
|
2093
|
+
id: given,
|
|
2094
|
+
dismissLabel,
|
|
2095
|
+
onClose
|
|
2096
|
+
}) => {
|
|
2097
|
+
let id = given ?? "";
|
|
2086
2098
|
id = manager.add({
|
|
2087
2099
|
title,
|
|
2088
2100
|
description,
|
|
2089
2101
|
type: tone,
|
|
2102
|
+
data: { dismissLabel },
|
|
2103
|
+
...given ? { id: given } : {},
|
|
2090
2104
|
...timeout !== void 0 ? { timeout } : {},
|
|
2091
2105
|
...priority ? { priority } : {},
|
|
2106
|
+
...onClose ? { onClose } : {},
|
|
2092
2107
|
...action ? {
|
|
2093
2108
|
actionProps: {
|
|
2094
2109
|
children: action.label,
|
|
2095
2110
|
onClick: () => {
|
|
2096
2111
|
action.onClick();
|
|
2097
|
-
manager.close(id);
|
|
2112
|
+
if (!action.keepOpen) manager.close(id);
|
|
2098
2113
|
}
|
|
2099
2114
|
}
|
|
2100
2115
|
} : {}
|
|
@@ -3398,9 +3413,9 @@ function BroomIcon({ sweeping = false, size = "lg", title, className, ...rest })
|
|
|
3398
3413
|
// src/components/FullScreenFlow/FullScreenFlow.tsx
|
|
3399
3414
|
import {
|
|
3400
3415
|
Children as Children2,
|
|
3401
|
-
createContext as
|
|
3416
|
+
createContext as createContext4,
|
|
3402
3417
|
useCallback as useCallback3,
|
|
3403
|
-
useContext as
|
|
3418
|
+
useContext as useContext4,
|
|
3404
3419
|
useEffect as useEffect6,
|
|
3405
3420
|
useId as useId6,
|
|
3406
3421
|
useMemo as useMemo3,
|
|
@@ -3408,9 +3423,9 @@ import {
|
|
|
3408
3423
|
useState as useState8
|
|
3409
3424
|
} from "react";
|
|
3410
3425
|
import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3411
|
-
var FlowContext =
|
|
3426
|
+
var FlowContext = createContext4({ announce: () => {
|
|
3412
3427
|
} });
|
|
3413
|
-
var FrameContext =
|
|
3428
|
+
var FrameContext = createContext4(void 0);
|
|
3414
3429
|
var ENTER_IGNORES = 'textarea, button, a[href], summary, select, [contenteditable], [role="combobox"], [data-flow-keys="local"]';
|
|
3415
3430
|
var ARROW_IGNORES = 'input, textarea, select, button, a[href], summary, [contenteditable], [role="radiogroup"], [role="slider"], [role="listbox"], [role="tablist"], [role="menu"], [role="grid"], [role="combobox"], [data-flow-keys="local"]';
|
|
3416
3431
|
function Root7({
|
|
@@ -3680,8 +3695,8 @@ function Step({
|
|
|
3680
3695
|
}) {
|
|
3681
3696
|
const id = useId6();
|
|
3682
3697
|
const titleRef = useRef6(null);
|
|
3683
|
-
const phase =
|
|
3684
|
-
const { announce } =
|
|
3698
|
+
const phase = useContext4(FrameContext);
|
|
3699
|
+
const { announce } = useContext4(FlowContext);
|
|
3685
3700
|
const message = announcement ?? (typeof title === "string" ? title : void 0);
|
|
3686
3701
|
const latest = useRef6({ message, announce });
|
|
3687
3702
|
useEffect6(() => {
|