@apliteni/apliteni-ui 0.44.0 → 0.46.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.44.0",
3
+ "version": "0.46.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
package/react/README.md CHANGED
@@ -28,7 +28,7 @@ import '@apliteni/apliteni-ui/react/css'; // React components' shell styles (mo
28
28
  import { DataTable, Modal, Button } from '@apliteni/apliteni-ui/react';
29
29
  ```
30
30
 
31
- Components: `DataTable`, `Pagination`, `StatBand`, `Modal`, `Drawer`, `CommandPalette`, `Dropdown`, `BackLink`, `Snippet`, `Tabs`, `Button`, `Badge`, `Card`, `Icon`.
31
+ Components: `DataTable`, `Pagination`, `StatBand`, `Modal`, `Confirm`, `Drawer`, `CommandPalette`, `Dropdown`, `BackLink`, `Snippet`, `Tabs`, `Button`, `Badge`, `Card`, `Icon`.
32
32
 
33
33
  `Snippet` accepts `label`, `code`, `reveal`, and `copyLabel` props. It treats `code`
34
34
  as plain text and copies it exactly as provided. After a successful clipboard write,
@@ -338,3 +338,54 @@ import '@apliteni/apliteni-ui/react/css';
338
338
  Tabs is controlled through `value` and `onChange`. Pass items with unique values, labels, optional counts, and React panel content. Provide a label for the tablist and a value that matches one item. Inactive panel content is unmounted.
339
339
 
340
340
  Arrow keys move between tabs and wrap from the last tab to the first. They also activate the selected tab. Home and End select the first and last tabs. Tab moves to the selected panel. New panels use the kit’s fade animation, which is shortened when reduced motion is enabled.
341
+
342
+ ## Confirm
343
+
344
+ Use `Confirm` before an action that has a cost. Put the object name in `title`. In
345
+ `body`, explain what will change and whether the change can be reversed. Give both
346
+ buttons clear, specific labels. For an undoable action, use a toast with Undo instead.
347
+
348
+ ```tsx
349
+ <Confirm open={open} title="Revoke demo token?"
350
+ body="This token will stop working immediately. You cannot restore it."
351
+ confirmLabel="Revoke token" cancelLabel="Keep the token" danger busy={saving}
352
+ onConfirm={revokeToken} onCancel={() => setOpen(false)} />
353
+ ```
354
+
355
+ The consumer controls `open` and `busy`. `Confirm` does not wait for `onConfirm` or
356
+ close itself. Set `busy` while saving. This keeps focus, prevents repeated presses, and
357
+ announces progress. Without `danger`, the committing button uses the primary tone.
358
+
359
+ Escape, the scrim, the close button, and the safe action call `onCancel`, even while
360
+ busy. Closing the dialog does not cancel a write that has already started.
361
+
362
+ `Confirm` uses Modal's focus trap, focus return, and reduced-motion transitions. When it
363
+ opens, focus goes to the safe action. It renders an `alertdialog`, named by its title
364
+ and described by its body. Modal also accepts
365
+ `initialFocusRef` for a mounted, focusable element inside its panel. Without it, Modal
366
+ uses its normal opening focus.
367
+
368
+ ## Timeline
369
+
370
+ `Timeline` displays a record’s events in the order provided. Pass events from oldest
371
+ to newest, with stable IDs, machine-readable `dateTime` values, and formatted
372
+ `timestamp` text.
373
+ Descriptions should say what changed and to where.
374
+
375
+ ```tsx
376
+ <Timeline aria-label="Record history" events={[
377
+ {
378
+ id: 'created', actor: 'Demo operator', dateTime: '2026-09-01T09:00:00Z',
379
+ timestamp: '1 Sep, 09:00 UTC', description: 'Created the record in Unassigned.',
380
+ meta: 'Batch DEMO-12',
381
+ },
382
+ ]} />
383
+ ```
384
+
385
+ Omit `undo` for read-only events. For a reversible batch, pass
386
+ `undo: { label: 'Undo batch DEMO-12', onUndo }`. The app checks permissions,
387
+ asks for confirmation when the batch affects finalized records, reverses the
388
+ entire batch, and adds a new event. Timeline only calls `onUndo`; it does not
389
+ modify history.
390
+ Import both the kit CSS and React CSS. The Privileged story shows confirmation
391
+ and a reversing event.
@@ -142,3 +142,69 @@
142
142
  display: block;
143
143
  }
144
144
  }
145
+
146
+ /* src/Timeline.css */
147
+ .ui-timeline {
148
+ margin: 0;
149
+ padding: 0;
150
+ list-style: none;
151
+ color: var(--text);
152
+ font-size: var(--text-sm);
153
+ line-height: 1.5;
154
+ }
155
+ .ui-timeline__event {
156
+ position: relative;
157
+ padding-inline-start: var(--space-6);
158
+ padding-block-end: var(--space-6);
159
+ overflow-wrap: anywhere;
160
+ }
161
+ .ui-timeline__event:last-child {
162
+ padding-block-end: 0;
163
+ }
164
+ .ui-timeline__event::before {
165
+ content: "";
166
+ position: absolute;
167
+ inset-inline-start: calc(var(--space-2) / 2);
168
+ inset-block-start: 0.75em;
169
+ inset-block-end: -0.75em;
170
+ width: 1px;
171
+ background: var(--border);
172
+ }
173
+ .ui-timeline__event:last-child::before {
174
+ display: none;
175
+ }
176
+ .ui-timeline__event::after {
177
+ content: "";
178
+ position: absolute;
179
+ inset-inline-start: 0;
180
+ inset-block-start: calc(0.75em - var(--space-2) / 2);
181
+ width: var(--space-2);
182
+ height: var(--space-2);
183
+ border-radius: 50%;
184
+ background: var(--accent);
185
+ }
186
+ .ui-timeline__head,
187
+ .ui-timeline__meta {
188
+ display: flex;
189
+ flex-wrap: wrap;
190
+ align-items: baseline;
191
+ column-gap: var(--space-3);
192
+ row-gap: var(--space-1);
193
+ }
194
+ .ui-timeline__actor {
195
+ font-weight: var(--weight-semibold);
196
+ }
197
+ .ui-timeline__head time,
198
+ .ui-timeline__meta {
199
+ font-size: var(--text-xs);
200
+ }
201
+ .ui-timeline__description {
202
+ margin: var(--space-1) 0;
203
+ }
204
+ .ui-timeline__undo {
205
+ white-space: normal;
206
+ }
207
+ .ui-timeline__undo:hover,
208
+ .ui-timeline__undo:focus-visible {
209
+ color: var(--pink);
210
+ }
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, ButtonHTMLAttributes, MouseEvent, ElementType, ComponentPropsWithoutRef } from 'react';
2
+ import { ReactNode, ButtonHTMLAttributes, RefObject, MouseEvent, ElementType, ComponentPropsWithoutRef } from 'react';
3
3
 
4
4
  declare function Icon({ name }: {
5
5
  name: string;
@@ -16,7 +16,17 @@ type ButtonProps = {
16
16
  busy?: boolean;
17
17
  children?: ReactNode;
18
18
  } & ButtonHTMLAttributes<HTMLButtonElement>;
19
- declare function Button({ variant, size, icon, iconRight, iconOnly, block, busy, children, type, disabled, onClick, onClickCapture, onKeyDown, onKeyDownCapture, onKeyUp, onKeyUpCapture, ...rest }: ButtonProps): react.JSX.Element;
19
+ declare const Button: react.ForwardRefExoticComponent<{
20
+ variant?: "primary" | "secondary" | "ghost" | "danger";
21
+ size?: "xs" | "sm" | "md" | "lg";
22
+ icon?: string;
23
+ iconRight?: string;
24
+ iconOnly?: boolean;
25
+ block?: boolean;
26
+ /** In flight: keeps focus, blocks activation, announces progress, and shows dots. */
27
+ busy?: boolean;
28
+ children?: ReactNode;
29
+ } & ButtonHTMLAttributes<HTMLButtonElement> & react.RefAttributes<HTMLButtonElement>>;
20
30
 
21
31
  declare function Badge({ variant, children }: {
22
32
  variant?: string;
@@ -55,14 +65,29 @@ interface StatBandProps {
55
65
  }
56
66
  declare function StatBand({ stats, variant, basis, label, id }: StatBandProps): react.JSX.Element;
57
67
 
68
+ type ConfirmProps = {
69
+ open: boolean;
70
+ title: string;
71
+ body: ReactNode;
72
+ confirmLabel: string;
73
+ cancelLabel: string;
74
+ danger?: boolean;
75
+ busy?: boolean;
76
+ onConfirm: () => void;
77
+ onCancel: () => void;
78
+ };
79
+ declare function Confirm({ open, title, body, confirmLabel, cancelLabel, danger, busy, onConfirm, onCancel, }: ConfirmProps): react.JSX.Element;
80
+
58
81
  type ModalProps = {
59
82
  open: boolean;
60
83
  title: string;
61
84
  onClose: () => void;
62
85
  footer?: ReactNode;
63
86
  children?: ReactNode;
87
+ role?: 'dialog' | 'alertdialog';
88
+ initialFocusRef?: RefObject<HTMLElement | null>;
64
89
  };
65
- declare function Modal({ open, title, onClose, footer, children }: ModalProps): react.ReactPortal | null;
90
+ declare function Modal({ open, title, onClose, footer, children, initialFocusRef, role }: ModalProps): react.ReactPortal | null;
66
91
 
67
92
  type DrawerProps = {
68
93
  open: boolean;
@@ -464,7 +489,24 @@ type TabsProps = {
464
489
  };
465
490
  declare function Tabs({ items, value, onChange, label }: TabsProps): react.JSX.Element;
466
491
 
492
+ type TimelineEvent = {
493
+ id: string;
494
+ actor: string;
495
+ dateTime: string;
496
+ timestamp: string;
497
+ description: string;
498
+ meta?: ReactNode;
499
+ undo?: {
500
+ label: string;
501
+ onUndo: () => void;
502
+ };
503
+ };
504
+ type TimelineProps = Omit<ComponentPropsWithoutRef<'ol'>, 'children' | 'reversed' | 'start'> & {
505
+ events: readonly TimelineEvent[];
506
+ };
507
+ declare function Timeline({ events, className, ...rest }: TimelineProps): react.JSX.Element;
508
+
467
509
  declare const PAGE_SIZES: readonly number[];
468
510
  declare const DEFAULT_PAGE_SIZE: number;
469
511
 
470
- export { BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, BusyRegion, type BusyRegionProps, Button, type ButtonProps, Card, type Column, type CommandGroup, type CommandItem, CommandPalette, type CommandPaletteProps, 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, 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, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, type TabItem, type TableSort, Tabs, type TabsProps, sortTableRows };
512
+ export { BackLink, type BackLinkOwnProps, type BackLinkProps, Badge, BusyRegion, type BusyRegionProps, Button, type ButtonProps, 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, 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, Skeleton, type SkeletonProps, SkeletonTable, type SkeletonTableProps, Snippet, type SnippetProps, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, type TabItem, type TableSort, Tabs, type TabsProps, Timeline, type TimelineEvent, type TimelineProps, sortTableRows };