@apliteni/apliteni-ui 0.55.0 → 0.56.1
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/package.json +1 -1
- package/react/README.md +16 -6
- package/react/dist/index.css +56 -2
- package/react/dist/index.d.ts +8 -1
- package/react/dist/index.js +98 -36
package/package.json
CHANGED
package/react/README.md
CHANGED
|
@@ -385,8 +385,20 @@ uses its normal opening focus.
|
|
|
385
385
|
|
|
386
386
|
`Timeline` displays a record’s events in the order provided. Pass events from oldest
|
|
387
387
|
to newest, with stable IDs, machine-readable `dateTime` values, and formatted
|
|
388
|
-
`timestamp` text.
|
|
389
|
-
|
|
388
|
+
`timestamp` text. Place Timeline on a page or card reading surface, never a grey
|
|
389
|
+
fill; the standalone stories compose it inside `Card`.
|
|
390
|
+
Descriptions should say what changed and to where. Optional `kind` accepts
|
|
391
|
+
`person`, `rule`, or `reversal` (`TimelineEventKind`); these show the kit’s user,
|
|
392
|
+
bolt, or refresh glyph in a 20px ring. The last event is newest and its ring is
|
|
393
|
+
filled, using the danger colour for a reversal. Events without a kind keep their
|
|
394
|
+
dot. Mixed histories mute older dots; older reversal glyphs keep danger ink.
|
|
395
|
+
|
|
396
|
+
Initial history stays still, including history loaded into an empty list.
|
|
397
|
+
New IDs added to a non-empty history enter with the kit’s slide-up motion (400ms)
|
|
398
|
+
and marker scale-in (250ms, delayed 60ms). Existing IDs stay still when reordered
|
|
399
|
+
or edited. Reduced motion disables the entrance. Optional `relativeTimestamp`
|
|
400
|
+
(such as "just now") appears beside the absolute stamp only on the newest row,
|
|
401
|
+
in accent ink. The caller updates this text; Timeline does not run a clock.
|
|
390
402
|
|
|
391
403
|
```tsx
|
|
392
404
|
<Timeline aria-label="Record history" events={[
|
|
@@ -400,11 +412,9 @@ Descriptions should say what changed and to where.
|
|
|
400
412
|
|
|
401
413
|
Omit `undo` for read-only events. For a reversible batch, pass
|
|
402
414
|
`undo: { label: 'Undo batch DEMO-12', onUndo }`. The app checks permissions,
|
|
403
|
-
|
|
404
|
-
entire batch, and adds a new event. Timeline only calls `onUndo`; it does not
|
|
415
|
+
reverses the entire batch, and adds a new event without a confirmation dialog. Timeline only calls `onUndo`; it does not
|
|
405
416
|
modify history.
|
|
406
|
-
Import both the kit CSS and React CSS. The Privileged story shows
|
|
407
|
-
and a reversing event.
|
|
417
|
+
Import both the kit CSS and React CSS. The Privileged story shows Undo adding a reversing event.
|
|
408
418
|
|
|
409
419
|
## Fields
|
|
410
420
|
|
package/react/dist/index.css
CHANGED
|
@@ -68,6 +68,8 @@
|
|
|
68
68
|
border-bottom: 1px solid var(--border);
|
|
69
69
|
}
|
|
70
70
|
.rx-modal__title {
|
|
71
|
+
margin: 0;
|
|
72
|
+
font-family: var(--font-sans);
|
|
71
73
|
font-weight: var(--weight-normal);
|
|
72
74
|
font-size: var(--text-base);
|
|
73
75
|
color: var(--text);
|
|
@@ -189,8 +191,7 @@
|
|
|
189
191
|
.ui-timeline__event:last-child::before {
|
|
190
192
|
display: none;
|
|
191
193
|
}
|
|
192
|
-
.ui-
|
|
193
|
-
content: "";
|
|
194
|
+
.ui-timeline__marker {
|
|
194
195
|
position: absolute;
|
|
195
196
|
inset-inline-start: 0;
|
|
196
197
|
inset-block-start: calc(0.75em - var(--space-2) / 2);
|
|
@@ -214,6 +215,10 @@
|
|
|
214
215
|
.ui-timeline__meta {
|
|
215
216
|
font-size: var(--text-xs);
|
|
216
217
|
}
|
|
218
|
+
.ui-timeline__relative {
|
|
219
|
+
color: var(--accent);
|
|
220
|
+
font-size: var(--text-xs);
|
|
221
|
+
}
|
|
217
222
|
.ui-timeline__description {
|
|
218
223
|
margin: var(--space-1) 0;
|
|
219
224
|
}
|
|
@@ -224,6 +229,55 @@
|
|
|
224
229
|
.ui-timeline__undo:focus-visible {
|
|
225
230
|
color: var(--pink);
|
|
226
231
|
}
|
|
232
|
+
.ui-timeline--kinds .ui-timeline__event {
|
|
233
|
+
padding-inline-start: var(--space-8);
|
|
234
|
+
}
|
|
235
|
+
.ui-timeline--kinds .ui-timeline__event::before {
|
|
236
|
+
inset-inline-start: calc(var(--space-5) / 2);
|
|
237
|
+
}
|
|
238
|
+
.ui-timeline--kinds .ui-timeline__marker {
|
|
239
|
+
inset-inline-start: calc((var(--space-5) - var(--space-2)) / 2);
|
|
240
|
+
background: var(--muted);
|
|
241
|
+
}
|
|
242
|
+
.ui-timeline--kinds .ui-timeline__event:last-child .ui-timeline__marker {
|
|
243
|
+
background: var(--accent);
|
|
244
|
+
}
|
|
245
|
+
.ui-timeline--kinds .ui-timeline__marker--kind {
|
|
246
|
+
display: flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
justify-content: center;
|
|
249
|
+
inset-inline-start: 0;
|
|
250
|
+
inset-block-start: calc(0.75em - var(--space-5) / 2);
|
|
251
|
+
width: var(--space-5);
|
|
252
|
+
height: var(--space-5);
|
|
253
|
+
border: 1px solid var(--muted);
|
|
254
|
+
background: var(--surface);
|
|
255
|
+
color: var(--muted);
|
|
256
|
+
}
|
|
257
|
+
.ui-timeline--kinds .ui-timeline__marker--reversal {
|
|
258
|
+
color: var(--pink);
|
|
259
|
+
}
|
|
260
|
+
.ui-timeline__marker--kind svg {
|
|
261
|
+
width: var(--space-3);
|
|
262
|
+
height: var(--space-3);
|
|
263
|
+
}
|
|
264
|
+
.ui-timeline--kinds .ui-timeline__event:last-child .ui-timeline__marker--kind {
|
|
265
|
+
border-color: var(--accent-strong);
|
|
266
|
+
background: var(--accent-strong);
|
|
267
|
+
color: var(--accent-contrast);
|
|
268
|
+
}
|
|
269
|
+
.ui-timeline--kinds .ui-timeline__event:last-child .ui-timeline__marker--reversal {
|
|
270
|
+
border-color: var(--pink);
|
|
271
|
+
background: var(--pink);
|
|
272
|
+
color: var(--danger-contrast);
|
|
273
|
+
}
|
|
274
|
+
.ui-timeline__event.is-entering {
|
|
275
|
+
--m-dist: var(--space-2);
|
|
276
|
+
animation: m-slide-up var(--dur-slow) var(--ease-out) both;
|
|
277
|
+
}
|
|
278
|
+
.ui-timeline__marker.is-entering {
|
|
279
|
+
animation: m-scale-in var(--dur-med) var(--ease-out) var(--delay-1) both;
|
|
280
|
+
}
|
|
227
281
|
|
|
228
282
|
/* ../src/styles/input.css */
|
|
229
283
|
.ui-field {
|
package/react/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ type ButtonProps = {
|
|
|
14
14
|
block?: boolean;
|
|
15
15
|
/** In flight: keeps focus, blocks activation, announces progress, and shows dots. */
|
|
16
16
|
busy?: boolean;
|
|
17
|
+
/** Message after busy ends; an empty string leaves outcome announcements to the caller. */
|
|
18
|
+
completionMessage?: string;
|
|
17
19
|
children?: ReactNode;
|
|
18
20
|
} & ButtonHTMLAttributes<HTMLButtonElement>;
|
|
19
21
|
declare const Button: react.ForwardRefExoticComponent<{
|
|
@@ -25,6 +27,8 @@ declare const Button: react.ForwardRefExoticComponent<{
|
|
|
25
27
|
block?: boolean;
|
|
26
28
|
/** In flight: keeps focus, blocks activation, announces progress, and shows dots. */
|
|
27
29
|
busy?: boolean;
|
|
30
|
+
/** Message after busy ends; an empty string leaves outcome announcements to the caller. */
|
|
31
|
+
completionMessage?: string;
|
|
28
32
|
children?: ReactNode;
|
|
29
33
|
} & ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>;
|
|
30
34
|
|
|
@@ -498,11 +502,14 @@ type TabsProps = {
|
|
|
498
502
|
};
|
|
499
503
|
declare function Tabs({ items, value, onChange, label }: TabsProps): react.JSX.Element;
|
|
500
504
|
|
|
505
|
+
type TimelineEventKind = 'person' | 'rule' | 'reversal';
|
|
501
506
|
type TimelineEvent = {
|
|
502
507
|
id: string;
|
|
508
|
+
kind?: TimelineEventKind;
|
|
503
509
|
actor: string;
|
|
504
510
|
dateTime: string;
|
|
505
511
|
timestamp: string;
|
|
512
|
+
relativeTimestamp?: string;
|
|
506
513
|
description: string;
|
|
507
514
|
meta?: ReactNode;
|
|
508
515
|
undo?: {
|
|
@@ -608,4 +615,4 @@ declare function ThemeToggle({ labelled }: ThemeToggleProps): react.JSX.Element;
|
|
|
608
615
|
declare const PAGE_SIZES: readonly number[];
|
|
609
616
|
declare const DEFAULT_PAGE_SIZE: number;
|
|
610
617
|
|
|
611
|
-
export { AppShell, type AppShellProps, type AppShellSection, BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, BusyRegion, type BusyRegionProps, Button, type ButtonProps, Callout, type CalloutProps, type CalloutVariant, Card, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, Confirm, type ConfirmProps, DEFAULT_PAGE_SIZE, DataTable, type DataTableProps, DeltaValue, type DeltaValueProps, Denied, type DeniedProps, Drawer, type DrawerProps, DrawerSection, type DrawerSectionProps, Dropdown, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, EmptyState, type EmptyStateProps, type EmptyStateVariant, FileField, type FileFieldProps, type Filter, FilterBar, type FilterBarProps, Icon, KeyValueList, type KeyValueListProps, type KeyValueRow, Modal, type ModalProps, NumericValue, type NumericValueProps, PAGE_SIZES, Pagination, type PaginationProps, RowIdentity, type RowIdentityProps, type SegmentOption, Segmented, type SegmentedProps, SelectField, type SelectFieldProps, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, THEME_INIT_SCRIPT, type TabItem, type TableSort, Tabs, type TabsProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, ThemeToggle, type ThemeToggleProps, Timeline, type TimelineEvent, type TimelineProps, Toast, type ToastNotice, type ToastProps, sortTableRows, useToast };
|
|
618
|
+
export { AppShell, type AppShellProps, type AppShellSection, BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, BusyRegion, type BusyRegionProps, Button, type ButtonProps, Callout, type CalloutProps, type CalloutVariant, Card, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, Confirm, type ConfirmProps, DEFAULT_PAGE_SIZE, DataTable, type DataTableProps, DeltaValue, type DeltaValueProps, Denied, type DeniedProps, Drawer, type DrawerProps, DrawerSection, type DrawerSectionProps, Dropdown, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, EmptyState, type EmptyStateProps, type EmptyStateVariant, FileField, type FileFieldProps, type Filter, FilterBar, type FilterBarProps, Icon, KeyValueList, type KeyValueListProps, type KeyValueRow, Modal, type ModalProps, NumericValue, type NumericValueProps, PAGE_SIZES, Pagination, type PaginationProps, RowIdentity, type RowIdentityProps, type SegmentOption, Segmented, type SegmentedProps, SelectField, type SelectFieldProps, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, THEME_INIT_SCRIPT, type TabItem, type TableSort, Tabs, type TabsProps, TextArea, type TextAreaProps, TextField, type TextFieldProps, ThemeToggle, type ThemeToggleProps, Timeline, type TimelineEvent, type TimelineEventKind, type TimelineProps, Toast, type ToastNotice, type ToastProps, sortTableRows, useToast };
|
package/react/dist/index.js
CHANGED
|
@@ -56,6 +56,7 @@ var Button = forwardRef(function Button2({
|
|
|
56
56
|
iconOnly,
|
|
57
57
|
block,
|
|
58
58
|
busy,
|
|
59
|
+
completionMessage,
|
|
59
60
|
children,
|
|
60
61
|
type = "button",
|
|
61
62
|
disabled,
|
|
@@ -83,7 +84,7 @@ var Button = forwardRef(function Button2({
|
|
|
83
84
|
const prior = previous.current;
|
|
84
85
|
if ((busy || prior?.busy) && (!prior || prior.text !== text2 || prior.busy !== busy)) {
|
|
85
86
|
announcer.current ?? (announcer.current = acquireAnnouncer(buttonRef.current.ownerDocument));
|
|
86
|
-
announcer.current.announce(`${text2}:
|
|
87
|
+
announcer.current.announce(busy ? `${text2}: in progress` : completionMessage ?? `${text2}: complete`);
|
|
87
88
|
}
|
|
88
89
|
previous.current = { text: text2, busy };
|
|
89
90
|
});
|
|
@@ -472,7 +473,7 @@ function Modal({ open, title, onClose, footer, children, initialFocusRef, role =
|
|
|
472
473
|
ref: panel,
|
|
473
474
|
children: [
|
|
474
475
|
/* @__PURE__ */ jsxs5("div", { className: "rx-modal__head", children: [
|
|
475
|
-
/* @__PURE__ */ jsx7("
|
|
476
|
+
/* @__PURE__ */ jsx7("h2", { className: "rx-modal__title", id: titleId, children: title }),
|
|
476
477
|
/* @__PURE__ */ jsx7(Button, { variant: "ghost", size: "sm", iconOnly: true, icon: "x", "aria-label": "Close", onClick: onClose })
|
|
477
478
|
] }),
|
|
478
479
|
/* @__PURE__ */ jsx7("div", { className: "rx-modal__body", id: bodyId, ref: body, children }),
|
|
@@ -1890,25 +1891,62 @@ function Tabs({ items, value, onChange, label }) {
|
|
|
1890
1891
|
}
|
|
1891
1892
|
|
|
1892
1893
|
// src/Timeline.tsx
|
|
1894
|
+
import { useEffect as useEffect7, useRef as useRef12 } from "react";
|
|
1895
|
+
import { playEntrance as playEntrance2, prefersReducedMotion } from "@apliteni/apliteni-ui/motion";
|
|
1893
1896
|
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1897
|
+
var kindIcons = { person: "user", rule: "bolt", reversal: "refresh" };
|
|
1894
1898
|
function Timeline({ events, className, ...rest }) {
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1899
|
+
const previousIds = useRef12(new Set(events.map((event) => event.id)));
|
|
1900
|
+
const rows = useRef12(/* @__PURE__ */ new Map());
|
|
1901
|
+
useEffect7(() => {
|
|
1902
|
+
if (previousIds.current.size > 0 && !prefersReducedMotion()) {
|
|
1903
|
+
for (const event of events) {
|
|
1904
|
+
if (previousIds.current.has(event.id)) continue;
|
|
1905
|
+
const row = rows.current.get(event.id);
|
|
1906
|
+
if (!row) continue;
|
|
1907
|
+
playEntrance2(row);
|
|
1908
|
+
playEntrance2(row.querySelector(".ui-timeline__marker"));
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
previousIds.current = new Set(events.map((event) => event.id));
|
|
1912
|
+
}, [events]);
|
|
1913
|
+
return /* @__PURE__ */ jsx22("ol", { ...rest, role: "list", className: ["ui-timeline", events.some((event) => event.kind) && "ui-timeline--kinds", className].filter(Boolean).join(" "), children: events.map((event, index) => /* @__PURE__ */ jsxs18(
|
|
1914
|
+
"li",
|
|
1915
|
+
{
|
|
1916
|
+
className: "ui-timeline__event",
|
|
1917
|
+
ref: (row) => {
|
|
1918
|
+
if (row) rows.current.set(event.id, row);
|
|
1919
|
+
else rows.current.delete(event.id);
|
|
1920
|
+
},
|
|
1921
|
+
children: [
|
|
1922
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": "true", className: [
|
|
1923
|
+
"ui-timeline__marker",
|
|
1924
|
+
event.kind && "ui-timeline__marker--kind",
|
|
1925
|
+
event.kind === "reversal" && "ui-timeline__marker--reversal"
|
|
1926
|
+
].filter(Boolean).join(" "), children: event.kind && /* @__PURE__ */ jsx22(Icon, { name: kindIcons[event.kind] }) }),
|
|
1927
|
+
/* @__PURE__ */ jsxs18("div", { className: "ui-timeline__head", children: [
|
|
1928
|
+
/* @__PURE__ */ jsx22("span", { className: "ui-timeline__actor", children: event.actor }),
|
|
1929
|
+
/* @__PURE__ */ jsx22("time", { dateTime: event.dateTime, children: event.timestamp }),
|
|
1930
|
+
index === events.length - 1 && event.relativeTimestamp && /* @__PURE__ */ jsx22("span", { className: "ui-timeline__relative", children: event.relativeTimestamp })
|
|
1931
|
+
] }),
|
|
1932
|
+
/* @__PURE__ */ jsx22("p", { className: "ui-timeline__description", children: event.description }),
|
|
1933
|
+
(event.meta != null || event.undo) && /* @__PURE__ */ jsxs18("div", { className: "ui-timeline__meta", children: [
|
|
1934
|
+
event.meta != null && /* @__PURE__ */ jsx22("span", { children: event.meta }),
|
|
1935
|
+
event.undo && /* @__PURE__ */ jsx22(Button, { variant: "ghost", size: "xs", className: "ui-btn ui-btn--ghost ui-btn--xs ui-timeline__undo", "aria-label": event.undo.label, onClick: event.undo.onUndo, children: "Undo" })
|
|
1936
|
+
] })
|
|
1937
|
+
]
|
|
1938
|
+
},
|
|
1939
|
+
event.id
|
|
1940
|
+
)) });
|
|
1906
1941
|
}
|
|
1907
1942
|
|
|
1908
1943
|
// src/Field.tsx
|
|
1909
|
-
import { useEffect as
|
|
1944
|
+
import { useEffect as useEffect8, useId as useId8, useRef as useRef13, useState as useState7 } from "react";
|
|
1910
1945
|
import { esc, icon as icon4 } from "@apliteni/apliteni-ui";
|
|
1911
1946
|
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1947
|
+
function messages(id, hint, error) {
|
|
1948
|
+
return [error && `${id}-error`, hint && `${id}-hint`].filter(Boolean).join(" ") || void 0;
|
|
1949
|
+
}
|
|
1912
1950
|
function Frame({ id, label, hint, error, required, children }) {
|
|
1913
1951
|
return /* @__PURE__ */ jsxs19("div", { className: "ui-field", children: [
|
|
1914
1952
|
/* @__PURE__ */ jsxs19("label", { className: "ui-field__label", htmlFor: id, children: [
|
|
@@ -1916,23 +1954,25 @@ function Frame({ id, label, hint, error, required, children }) {
|
|
|
1916
1954
|
required && /* @__PURE__ */ jsx23("span", { className: "ui-field__req", "aria-hidden": "true", children: "*" })
|
|
1917
1955
|
] }),
|
|
1918
1956
|
children,
|
|
1919
|
-
|
|
1957
|
+
error && /* @__PURE__ */ jsx23(
|
|
1920
1958
|
"div",
|
|
1921
1959
|
{
|
|
1922
|
-
id: `${id}-
|
|
1923
|
-
className:
|
|
1924
|
-
|
|
1960
|
+
id: `${id}-error`,
|
|
1961
|
+
className: "ui-field__error",
|
|
1962
|
+
role: "alert",
|
|
1963
|
+
dangerouslySetInnerHTML: { __html: icon4("alert") + esc(error) }
|
|
1925
1964
|
}
|
|
1926
|
-
)
|
|
1965
|
+
),
|
|
1966
|
+
hint && /* @__PURE__ */ jsx23("div", { id: `${id}-hint`, className: "ui-field__hint", children: hint })
|
|
1927
1967
|
] });
|
|
1928
1968
|
}
|
|
1929
1969
|
function wiring(id, hint, error) {
|
|
1930
|
-
return { id, "aria-describedby":
|
|
1970
|
+
return { id, "aria-describedby": messages(id, hint, error), "aria-invalid": error ? true : void 0 };
|
|
1931
1971
|
}
|
|
1932
1972
|
function TextField({ label, hint, error, required, type = "text", unit, className = "", ...props }) {
|
|
1933
1973
|
const id = useId8();
|
|
1934
1974
|
const hasUnit = type === "number" && !!unit;
|
|
1935
|
-
const describedBy = [
|
|
1975
|
+
const describedBy = [messages(id, hint, error), hasUnit ? `${id}-unit` : ""].filter(Boolean).join(" ") || void 0;
|
|
1936
1976
|
const control = /* @__PURE__ */ jsx23(
|
|
1937
1977
|
"input",
|
|
1938
1978
|
{
|
|
@@ -1978,10 +2018,10 @@ function SelectField({ label, hint, error, required, className = "", children, .
|
|
|
1978
2018
|
}
|
|
1979
2019
|
function FileField({ label, hint, error, required, disabled, onFileChange, className = "", ...props }) {
|
|
1980
2020
|
const id = useId8();
|
|
1981
|
-
const input =
|
|
2021
|
+
const input = useRef13(null);
|
|
1982
2022
|
const [file, setFile] = useState7(null);
|
|
1983
2023
|
const [dragging, setDragging] = useState7(false);
|
|
1984
|
-
|
|
2024
|
+
useEffect8(() => {
|
|
1985
2025
|
const form = input.current?.form;
|
|
1986
2026
|
const reset = () => {
|
|
1987
2027
|
setFile(null);
|
|
@@ -2040,7 +2080,7 @@ function FileField({ label, hint, error, required, disabled, onFileChange, class
|
|
|
2040
2080
|
}
|
|
2041
2081
|
|
|
2042
2082
|
// src/Toast.tsx
|
|
2043
|
-
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as
|
|
2083
|
+
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect9, useLayoutEffect as useLayoutEffect4, useRef as useRef14, useState as useState8 } from "react";
|
|
2044
2084
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2045
2085
|
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2046
2086
|
var Context = createContext2(null);
|
|
@@ -2051,10 +2091,10 @@ function useToast() {
|
|
|
2051
2091
|
return push;
|
|
2052
2092
|
}
|
|
2053
2093
|
function Notice({ notice, remove }) {
|
|
2054
|
-
const root =
|
|
2094
|
+
const root = useRef14(null);
|
|
2055
2095
|
const [leaving2, setLeaving] = useState8(false);
|
|
2056
|
-
const dismissed =
|
|
2057
|
-
const remaining =
|
|
2096
|
+
const dismissed = useRef14(false);
|
|
2097
|
+
const remaining = useRef14(5e3);
|
|
2058
2098
|
const [hovered, setHovered] = useState8(false);
|
|
2059
2099
|
const [focused, setFocused] = useState8(false);
|
|
2060
2100
|
const paused = hovered || focused;
|
|
@@ -2065,7 +2105,7 @@ function Notice({ notice, remove }) {
|
|
|
2065
2105
|
if (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches) remove();
|
|
2066
2106
|
else setLeaving(true);
|
|
2067
2107
|
}, [remove]);
|
|
2068
|
-
|
|
2108
|
+
useEffect9(() => {
|
|
2069
2109
|
if (leaving2) {
|
|
2070
2110
|
const element = root.current;
|
|
2071
2111
|
const finish = (event) => {
|
|
@@ -2079,7 +2119,7 @@ function Notice({ notice, remove }) {
|
|
|
2079
2119
|
};
|
|
2080
2120
|
}
|
|
2081
2121
|
}, [leaving2, remove]);
|
|
2082
|
-
|
|
2122
|
+
useEffect9(() => {
|
|
2083
2123
|
if (leaving2 || notice.action || paused) return;
|
|
2084
2124
|
const started = Date.now();
|
|
2085
2125
|
const timer = setTimeout(dismiss, remaining.current);
|
|
@@ -2135,25 +2175,47 @@ function Notice({ notice, remove }) {
|
|
|
2135
2175
|
}
|
|
2136
2176
|
);
|
|
2137
2177
|
}
|
|
2178
|
+
var REACH = "--rx-toast-stack";
|
|
2179
|
+
function usePublishedReach(stack2, count) {
|
|
2180
|
+
useLayoutEffect4(() => {
|
|
2181
|
+
const element = stack2.current;
|
|
2182
|
+
const view = element?.ownerDocument.defaultView;
|
|
2183
|
+
const root = element?.ownerDocument.documentElement;
|
|
2184
|
+
if (!element || !view || !root) return;
|
|
2185
|
+
const publish = () => {
|
|
2186
|
+
const box = element.getBoundingClientRect();
|
|
2187
|
+
root.style.setProperty(REACH, `${box.height ? Math.round(view.innerHeight - box.top) : 0}px`);
|
|
2188
|
+
};
|
|
2189
|
+
publish();
|
|
2190
|
+
const observer = typeof view.ResizeObserver === "function" ? new view.ResizeObserver(publish) : void 0;
|
|
2191
|
+
observer?.observe(element);
|
|
2192
|
+
return () => {
|
|
2193
|
+
observer?.disconnect();
|
|
2194
|
+
root.style.removeProperty(REACH);
|
|
2195
|
+
};
|
|
2196
|
+
}, [stack2, count]);
|
|
2197
|
+
}
|
|
2138
2198
|
function Toast({ children }) {
|
|
2139
2199
|
const [entries, setEntries] = useState8([]);
|
|
2140
|
-
const nextId =
|
|
2200
|
+
const nextId = useRef14(0);
|
|
2201
|
+
const stack2 = useRef14(null);
|
|
2141
2202
|
const push = useCallback3((notice) => {
|
|
2142
2203
|
const id = nextId.current++;
|
|
2143
2204
|
const remove = () => setEntries((current) => current.filter((entry) => entry.id !== id));
|
|
2144
2205
|
setEntries((current) => [...current, { id, notice, remove }]);
|
|
2145
2206
|
}, []);
|
|
2207
|
+
usePublishedReach(stack2, entries.length);
|
|
2146
2208
|
return /* @__PURE__ */ jsxs20(Context.Provider, { value: push, children: [
|
|
2147
2209
|
children,
|
|
2148
2210
|
typeof document !== "undefined" && createPortal4(
|
|
2149
|
-
/* @__PURE__ */ jsx24("div", { className: "ui-toast-stack rx-toast-stack", children: entries.map((entry) => /* @__PURE__ */ jsx24(Notice, { notice: entry.notice, remove: entry.remove }, entry.id)) }),
|
|
2211
|
+
/* @__PURE__ */ jsx24("div", { className: "ui-toast-stack rx-toast-stack", ref: stack2, children: entries.map((entry) => /* @__PURE__ */ jsx24(Notice, { notice: entry.notice, remove: entry.remove }, entry.id)) }),
|
|
2150
2212
|
document.body
|
|
2151
2213
|
)
|
|
2152
2214
|
] });
|
|
2153
2215
|
}
|
|
2154
2216
|
|
|
2155
2217
|
// src/AppShell.tsx
|
|
2156
|
-
import { useEffect as
|
|
2218
|
+
import { useEffect as useEffect10, useId as useId9, useState as useState9 } from "react";
|
|
2157
2219
|
import { applyTheme, paletteHotkey, prism, railCollapsed, themeIcon, themeName } from "@apliteni/apliteni-ui";
|
|
2158
2220
|
import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2159
2221
|
var path = (value) => value.split(/[?#]/)[0].replace(/\/+$/, "") || "/";
|
|
@@ -2183,14 +2245,14 @@ function AppShell({
|
|
|
2183
2245
|
const [theme, setTheme] = useState9("dark");
|
|
2184
2246
|
const current = path(pathname);
|
|
2185
2247
|
const active = sections.filter((section) => current === path(section.href) || path(section.href) !== "/" && current.startsWith(`${path(section.href)}/`)).sort((a, b) => path(b.href).length - path(a.href).length)[0];
|
|
2186
|
-
|
|
2248
|
+
useEffect10(() => {
|
|
2187
2249
|
setCollapsed(railCollapsed() ?? defaultCollapsed);
|
|
2188
2250
|
}, [defaultCollapsed]);
|
|
2189
|
-
|
|
2251
|
+
useEffect10(() => {
|
|
2190
2252
|
setMore(false);
|
|
2191
2253
|
setSearch(false);
|
|
2192
2254
|
}, [pathname]);
|
|
2193
|
-
|
|
2255
|
+
useEffect10(() => {
|
|
2194
2256
|
const root = document.documentElement;
|
|
2195
2257
|
const sync2 = () => setTheme(root.getAttribute("data-theme") === "light" ? "light" : "dark");
|
|
2196
2258
|
sync2();
|
|
@@ -2198,7 +2260,7 @@ function AppShell({
|
|
|
2198
2260
|
observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] });
|
|
2199
2261
|
return () => observer.disconnect();
|
|
2200
2262
|
}, []);
|
|
2201
|
-
|
|
2263
|
+
useEffect10(() => {
|
|
2202
2264
|
const hotkey = (event) => {
|
|
2203
2265
|
if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey || event.key.toLowerCase() !== "k") return;
|
|
2204
2266
|
const target = event.target;
|