@apliteni/apliteni-ui 0.41.5 → 0.43.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 +1 -1
- package/react/README.md +43 -3
- package/react/dist/index.css +28 -0
- package/react/dist/index.d.ts +26 -1
- package/react/dist/index.js +66 -0
- package/src/styles/code.css +4 -3
package/package.json
CHANGED
package/react/README.md
CHANGED
|
@@ -28,7 +28,19 @@ 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`, `Button`, `Badge`, `Card`, `Icon`.
|
|
31
|
+
Components: `DataTable`, `Pagination`, `StatBand`, `Modal`, `Drawer`, `CommandPalette`, `Dropdown`, `BackLink`, `Snippet`, `Button`, `Badge`, `Card`, `Icon`.
|
|
32
|
+
|
|
33
|
+
`Snippet` accepts `label`, `code`, `reveal`, and `copyLabel` props. It treats `code`
|
|
34
|
+
as plain text and copies it exactly as provided. After a successful clipboard write,
|
|
35
|
+
it shows “Copied” for 1.4 seconds. If copying fails, it shows “Copy failed” so readers
|
|
36
|
+
can try again or select the text manually.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Snippet label="Terminal" code="npm install @apliteni/apliteni-ui" />
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Before a reveal snippet, explain that the secret is stored hashed and will not be
|
|
43
|
+
shown again, and ask the reader to copy it now. The page decides when to remove it.
|
|
32
44
|
|
|
33
45
|
`Button` accepts `size="xs" | "sm" | "md" | "lg"` (default `md`). Use `xs`
|
|
34
46
|
for a small inline control: `<Button size="xs" variant="ghost" icon="copy" iconOnly>Copy</Button>`.
|
|
@@ -73,8 +85,7 @@ focus is already back on the opener and the dialog takes no clicks.
|
|
|
73
85
|
A panel that slides in from an edge of the screen over a scrim. It renders the vanilla
|
|
74
86
|
`drawer()` markup, class for class, so it looks and moves like the kit's drawer, and like
|
|
75
87
|
`Pagination` its styles come from `@apliteni/apliteni-ui/css` rather than from this bundle.
|
|
76
|
-
Group
|
|
77
|
-
and value rows — rather than in cards; the rules are on Guidelines / Drawers.
|
|
88
|
+
Group its contents with `DrawerSection` and `KeyValueList`; see Guidelines / Drawers.
|
|
78
89
|
|
|
79
90
|
```tsx
|
|
80
91
|
<Drawer open={open} title="Transaction" onClose={() => setOpen(false)}
|
|
@@ -292,3 +303,32 @@ Clearing the page-jump box, or typing into it and then pressing a step, does not
|
|
|
292
303
|
page.
|
|
293
304
|
|
|
294
305
|
`pageSize` defaults to `DEFAULT_PAGE_SIZE` (100). **Breaking:** it used to default to 4.
|
|
306
|
+
|
|
307
|
+
## KeyValueList and DrawerSection
|
|
308
|
+
|
|
309
|
+
KeyValueList displays one record’s facts with labels beside their values. Pass rows
|
|
310
|
+
with a label and a React value. Set `columns={2}` to show two label-value pairs on
|
|
311
|
+
each line. Null and undefined values are displayed as an em dash. Boolean values
|
|
312
|
+
are displayed as `false` or `true`, zero remains visible, and strings are preserved.
|
|
313
|
+
Set `redacted` on a row to display “Hidden” with an eye-off icon without rendering
|
|
314
|
+
the value. Below 560px, each label appears above its value, and the layout
|
|
315
|
+
changes to one column.
|
|
316
|
+
|
|
317
|
+
DrawerSection groups content under a heading and adds a hairline between adjacent
|
|
318
|
+
sections. Its `headingLevel` defaults to 3. Import both the kit CSS and the React
|
|
319
|
+
CSS. Use a table for figures that readers need to compare down a column.
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
import { DrawerSection, KeyValueList } from '@apliteni/apliteni-ui/react';
|
|
323
|
+
import '@apliteni/apliteni-ui/css';
|
|
324
|
+
import '@apliteni/apliteni-ui/react/css';
|
|
325
|
+
|
|
326
|
+
<DrawerSection title="Transaction">
|
|
327
|
+
<KeyValueList rows={[
|
|
328
|
+
{ label: 'Reference', value: <a href="/invoices/1001">INV-1001</a> },
|
|
329
|
+
{ label: 'Amount', value: '€ 1,240.00' },
|
|
330
|
+
{ label: 'Account', redacted: true },
|
|
331
|
+
{ label: 'Note' },
|
|
332
|
+
]} />
|
|
333
|
+
</DrawerSection>
|
|
334
|
+
```
|
package/react/dist/index.css
CHANGED
|
@@ -114,3 +114,31 @@
|
|
|
114
114
|
transition: none;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
/* src/KeyValueList.css */
|
|
119
|
+
.ui-drawer__rows.ui-kv {
|
|
120
|
+
grid-template-columns: calc(var(--space-6) * 5) minmax(0, 1fr);
|
|
121
|
+
}
|
|
122
|
+
.ui-drawer__rows.ui-kv--two-columns {
|
|
123
|
+
grid-template-columns: repeat(2, calc(var(--space-6) * 5) minmax(0, 1fr));
|
|
124
|
+
}
|
|
125
|
+
.ui-kv__hidden {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
gap: var(--space-1);
|
|
129
|
+
color: var(--text);
|
|
130
|
+
}
|
|
131
|
+
.ui-kv__hidden svg {
|
|
132
|
+
width: var(--space-4);
|
|
133
|
+
height: var(--space-4);
|
|
134
|
+
stroke-width: 2.25;
|
|
135
|
+
}
|
|
136
|
+
@media (max-width: 560px) {
|
|
137
|
+
.ui-drawer__rows.ui-kv {
|
|
138
|
+
grid-template-columns: minmax(0, 1fr);
|
|
139
|
+
row-gap: var(--space-3);
|
|
140
|
+
}
|
|
141
|
+
.ui-kv > .ui-drawer__row {
|
|
142
|
+
display: block;
|
|
143
|
+
}
|
|
144
|
+
}
|
package/react/dist/index.d.ts
CHANGED
|
@@ -425,7 +425,32 @@ type FilterBarProps = {
|
|
|
425
425
|
};
|
|
426
426
|
declare function FilterBar(props: FilterBarProps): react.JSX.Element;
|
|
427
427
|
|
|
428
|
+
type KeyValueRow = {
|
|
429
|
+
label: string;
|
|
430
|
+
value?: ReactNode;
|
|
431
|
+
redacted?: boolean;
|
|
432
|
+
};
|
|
433
|
+
type KeyValueListProps = Omit<ComponentPropsWithoutRef<'dl'>, 'children'> & {
|
|
434
|
+
rows: readonly KeyValueRow[];
|
|
435
|
+
columns?: 1 | 2;
|
|
436
|
+
};
|
|
437
|
+
declare function KeyValueList({ rows, columns, className, ...rest }: KeyValueListProps): react.JSX.Element;
|
|
438
|
+
type DrawerSectionProps = Omit<ComponentPropsWithoutRef<'section'>, 'title'> & {
|
|
439
|
+
title?: ReactNode;
|
|
440
|
+
headingLevel?: 2 | 3 | 4 | 5 | 6;
|
|
441
|
+
};
|
|
442
|
+
declare function DrawerSection({ title, headingLevel, className, children, ...rest }: DrawerSectionProps): react.JSX.Element;
|
|
443
|
+
|
|
444
|
+
type SnippetProps = {
|
|
445
|
+
label?: string;
|
|
446
|
+
/** Plain text, displayed and copied without HTML parsing. */
|
|
447
|
+
code?: string;
|
|
448
|
+
reveal?: boolean;
|
|
449
|
+
copyLabel?: string;
|
|
450
|
+
};
|
|
451
|
+
declare function Snippet({ label, code, reveal, copyLabel }: SnippetProps): react.JSX.Element;
|
|
452
|
+
|
|
428
453
|
declare const PAGE_SIZES: readonly number[];
|
|
429
454
|
declare const DEFAULT_PAGE_SIZE: number;
|
|
430
455
|
|
|
431
|
-
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, Dropdown, type DropdownBadge, type DropdownEntry, type DropdownItem, type DropdownProps, type DropdownRowProps, type DropdownSearch, type DropdownSection, type DropdownSeparator, type Filter, FilterBar, type FilterBarProps, Icon, 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, StatBand, type StatBandProps, type StatDelta, type StatFigure, type StatTone, type StatVariant, type TableSort, sortTableRows };
|
|
456
|
+
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 TableSort, sortTableRows };
|
package/react/dist/index.js
CHANGED
|
@@ -1685,6 +1685,69 @@ function FilterBar(props) {
|
|
|
1685
1685
|
return /* @__PURE__ */ jsx16("div", { ref: host, dangerouslySetInnerHTML: initial.current });
|
|
1686
1686
|
}
|
|
1687
1687
|
|
|
1688
|
+
// src/KeyValueList.tsx
|
|
1689
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1690
|
+
function detail({ value, redacted }) {
|
|
1691
|
+
if (redacted) return /* @__PURE__ */ jsxs13("span", { className: "ui-kv__hidden", children: [
|
|
1692
|
+
/* @__PURE__ */ jsx17(Icon, { name: "eyeOff" }),
|
|
1693
|
+
"Hidden"
|
|
1694
|
+
] });
|
|
1695
|
+
if (value == null) return "\u2014";
|
|
1696
|
+
return typeof value === "boolean" ? String(value) : value;
|
|
1697
|
+
}
|
|
1698
|
+
function KeyValueList({ rows, columns = 1, className, ...rest }) {
|
|
1699
|
+
return /* @__PURE__ */ jsx17("dl", { ...rest, className: ["ui-drawer__rows", "ui-kv", columns === 2 && "ui-kv--two-columns", className].filter(Boolean).join(" "), children: rows.map((row, index) => /* @__PURE__ */ jsxs13("div", { className: "ui-drawer__row", children: [
|
|
1700
|
+
/* @__PURE__ */ jsx17("dt", { children: row.label }),
|
|
1701
|
+
/* @__PURE__ */ jsx17("dd", { children: detail(row) })
|
|
1702
|
+
] }, index)) });
|
|
1703
|
+
}
|
|
1704
|
+
function DrawerSection({ title, headingLevel = 3, className, children, ...rest }) {
|
|
1705
|
+
const Heading = `h${headingLevel}`;
|
|
1706
|
+
return /* @__PURE__ */ jsxs13("section", { ...rest, className: ["ui-drawer__section", className].filter(Boolean).join(" "), children: [
|
|
1707
|
+
title != null && /* @__PURE__ */ jsx17(Heading, { className: "ui-drawer__section-title", children: title }),
|
|
1708
|
+
children
|
|
1709
|
+
] });
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// src/Snippet.tsx
|
|
1713
|
+
import { useEffect as useEffect5, useRef as useRef9, useState as useState6 } from "react";
|
|
1714
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1715
|
+
function Snippet({ label = "shell", code = "", reveal = false, copyLabel = "Copy" }) {
|
|
1716
|
+
const [status, setStatus] = useState6("idle");
|
|
1717
|
+
const request = useRef9(0);
|
|
1718
|
+
const timer = useRef9(void 0);
|
|
1719
|
+
useEffect5(() => {
|
|
1720
|
+
setStatus("idle");
|
|
1721
|
+
return () => {
|
|
1722
|
+
request.current++;
|
|
1723
|
+
clearTimeout(timer.current);
|
|
1724
|
+
};
|
|
1725
|
+
}, [code]);
|
|
1726
|
+
async function copy() {
|
|
1727
|
+
const current = ++request.current;
|
|
1728
|
+
clearTimeout(timer.current);
|
|
1729
|
+
setStatus("idle");
|
|
1730
|
+
try {
|
|
1731
|
+
await navigator.clipboard.writeText(code);
|
|
1732
|
+
if (current !== request.current) return;
|
|
1733
|
+
setStatus("copied");
|
|
1734
|
+
timer.current = setTimeout(() => setStatus("idle"), 1400);
|
|
1735
|
+
} catch {
|
|
1736
|
+
if (current === request.current) setStatus("failed");
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
return /* @__PURE__ */ jsxs14("div", { className: reveal ? "ui-snippet ui-snippet--reveal" : "ui-snippet", children: [
|
|
1740
|
+
/* @__PURE__ */ jsxs14("div", { className: "ui-snippet__bar", children: [
|
|
1741
|
+
/* @__PURE__ */ jsx18("span", { children: label }),
|
|
1742
|
+
/* @__PURE__ */ jsxs14("button", { type: "button", className: "ui-snippet__copy", "aria-live": "polite", "aria-atomic": "true", onClick: copy, children: [
|
|
1743
|
+
/* @__PURE__ */ jsx18(Icon, { name: status === "copied" ? "check" : "copy" }),
|
|
1744
|
+
status === "copied" ? "Copied" : status === "failed" ? "Copy failed" : copyLabel
|
|
1745
|
+
] })
|
|
1746
|
+
] }),
|
|
1747
|
+
/* @__PURE__ */ jsx18("pre", { children: code })
|
|
1748
|
+
] });
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1688
1751
|
// src/index.ts
|
|
1689
1752
|
var PAGE_SIZES = KIT_PAGE_SIZES;
|
|
1690
1753
|
var DEFAULT_PAGE_SIZE3 = KIT_DEFAULT_PAGE_SIZE;
|
|
@@ -1700,9 +1763,11 @@ export {
|
|
|
1700
1763
|
DeltaValue,
|
|
1701
1764
|
Denied,
|
|
1702
1765
|
Drawer,
|
|
1766
|
+
DrawerSection,
|
|
1703
1767
|
Dropdown,
|
|
1704
1768
|
FilterBar,
|
|
1705
1769
|
Icon,
|
|
1770
|
+
KeyValueList,
|
|
1706
1771
|
Modal,
|
|
1707
1772
|
NumericValue,
|
|
1708
1773
|
PAGE_SIZES,
|
|
@@ -1711,6 +1776,7 @@ export {
|
|
|
1711
1776
|
Segmented,
|
|
1712
1777
|
Skeleton,
|
|
1713
1778
|
SkeletonTable,
|
|
1779
|
+
Snippet,
|
|
1714
1780
|
StatBand,
|
|
1715
1781
|
sortTableRows
|
|
1716
1782
|
};
|
package/src/styles/code.css
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
align-items: center;
|
|
15
15
|
padding: 10px 15px;
|
|
16
16
|
}
|
|
17
|
-
.ui-snippet__bar span {
|
|
17
|
+
.ui-snippet__bar > span {
|
|
18
18
|
/* rank: label */
|
|
19
19
|
font-size: var(--text-sm);
|
|
20
20
|
font-weight: var(--weight-medium);
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
transition: color var(--dur-fast) var(--ease);
|
|
51
51
|
}
|
|
52
52
|
.ui-snippet__copy:hover { color: var(--accent); }
|
|
53
|
+
.ui-snippet--reveal .ui-snippet__copy:hover { color: var(--strong); }
|
|
53
54
|
.ui-snippet__copy svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 2.8; }
|
|
54
55
|
|
|
55
56
|
/* Shell token highlighting (matches viz/account.mjs classes) */
|
|
@@ -63,8 +64,8 @@
|
|
|
63
64
|
.ui-snippet--reveal {
|
|
64
65
|
background: color-mix(in srgb, var(--green) 10%, var(--surface)); --ring-gap: color-mix(in srgb, var(--green) 10%, var(--surface));
|
|
65
66
|
}
|
|
66
|
-
.ui-snippet--reveal .ui-snippet__bar span { color: var(--
|
|
67
|
-
.ui-snippet--reveal pre { color: var(--
|
|
67
|
+
.ui-snippet--reveal .ui-snippet__bar > span { color: var(--chip-success-ink); }
|
|
68
|
+
.ui-snippet--reveal pre { color: var(--chip-success-ink); word-break: break-all; white-space: pre-wrap; }
|
|
68
69
|
|
|
69
70
|
/* Inline code */
|
|
70
71
|
.ui-code {
|