@apliteni/apliteni-ui 0.42.0 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apliteni/apliteni-ui",
3
- "version": "0.42.0",
3
+ "version": "0.43.0",
4
4
  "workspaces": [
5
5
  "react"
6
6
  ],
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>`.
@@ -441,7 +441,16 @@ type DrawerSectionProps = Omit<ComponentPropsWithoutRef<'section'>, 'title'> & {
441
441
  };
442
442
  declare function DrawerSection({ title, headingLevel, className, children, ...rest }: DrawerSectionProps): react.JSX.Element;
443
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
+
444
453
  declare const PAGE_SIZES: readonly number[];
445
454
  declare const DEFAULT_PAGE_SIZE: number;
446
455
 
447
- 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, 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 };
@@ -1709,6 +1709,45 @@ function DrawerSection({ title, headingLevel = 3, className, children, ...rest }
1709
1709
  ] });
1710
1710
  }
1711
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
+
1712
1751
  // src/index.ts
1713
1752
  var PAGE_SIZES = KIT_PAGE_SIZES;
1714
1753
  var DEFAULT_PAGE_SIZE3 = KIT_DEFAULT_PAGE_SIZE;
@@ -1737,6 +1776,7 @@ export {
1737
1776
  Segmented,
1738
1777
  Skeleton,
1739
1778
  SkeletonTable,
1779
+ Snippet,
1740
1780
  StatBand,
1741
1781
  sortTableRows
1742
1782
  };
@@ -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(--green); }
67
- .ui-snippet--reveal pre { color: var(--green); word-break: break-all; white-space: pre-wrap; }
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 {