anentrypoint-design 0.0.477 → 0.0.478

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 CHANGED
@@ -29,6 +29,14 @@ npm install anentrypoint-design
29
29
  </script>
30
30
  ```
31
31
 
32
+ `@latest` is unpinned — a production deploy tracking it silently picks up every future release, breaking or not, with no warning. Pin to the exact version you tested against instead:
33
+
34
+ ```html
35
+ <script type="importmap">
36
+ { "imports": { "anentrypoint-design": "https://unpkg.com/anentrypoint-design@0.0.476/dist/247420.js" } }
37
+ </script>
38
+ ```
39
+
32
40
  Add the scope class on a wrapping element and you are done:
33
41
 
34
42
  ```html
@@ -51,6 +59,72 @@ mount(document.getElementById('app'), () => C.AppShell({
51
59
 
52
60
  `mount` automatically adds `.ds-247420` to your root.
53
61
 
62
+ ## Framework integration
63
+
64
+ The SDK is framework-free (webjsx + custom elements), so React/Vue integration
65
+ means treating `<ds-chat>` (see below) as an imperative DOM element rather than
66
+ a native component.
67
+
68
+ **React** — set props/attributes on the element via `ref`, after import registers it:
69
+
70
+ ```jsx
71
+ import { useRef, useEffect } from 'react';
72
+ import 'anentrypoint-design'; // registers <ds-chat>
73
+
74
+ function ChatWidget({ messages, onSend }) {
75
+ const ref = useRef(null);
76
+
77
+ useEffect(() => {
78
+ const el = ref.current;
79
+ el.messages = messages;
80
+ const handleSend = (e) => onSend(e.detail.text);
81
+ el.addEventListener('send', handleSend);
82
+ return () => el.removeEventListener('send', handleSend);
83
+ }, [messages, onSend]);
84
+
85
+ return <ds-chat ref={ref} />;
86
+ }
87
+ ```
88
+
89
+ **Vue** — tell the compiler `ds-chat` is a custom element (not a Vue component)
90
+ so it isn't warned about / resolved against your component registry, then use
91
+ it directly in a template. In `vite.config.js`:
92
+
93
+ ```js
94
+ import vue from '@vitejs/plugin-vue';
95
+
96
+ export default {
97
+ plugins: [
98
+ vue({
99
+ template: {
100
+ compilerOptions: {
101
+ isCustomElement: (tag) => tag === 'ds-chat',
102
+ },
103
+ },
104
+ }),
105
+ ],
106
+ };
107
+ ```
108
+
109
+ Then in a Vue SFC:
110
+
111
+ ```vue
112
+ <script setup>
113
+ import 'anentrypoint-design'; // registers <ds-chat>
114
+ import { ref, onMounted } from 'vue';
115
+
116
+ const el = ref(null);
117
+ onMounted(() => {
118
+ el.value.messages = [{ role: 'assistant', text: 'gm.' }];
119
+ el.value.addEventListener('send', (e) => console.log(e.detail.text));
120
+ });
121
+ </script>
122
+
123
+ <template>
124
+ <ds-chat ref="el" />
125
+ </template>
126
+ ```
127
+
54
128
  ## what's in the box
55
129
 
56
130
  - **chrome** — `Topbar`, `Crumb`, `Side`, `Status`, `AppShell`, `Brand`, `Chip`, `Btn`, `Glyph`, `Heading`, `Lede`
@@ -257,6 +331,33 @@ Layout primitives worth knowing: `.ds-app-surface` is the Operate-mode page root
257
331
 
258
332
  The scanned set is computed, not listed: `COMPONENT_SHEETS` in `scripts/lint-tokens.mjs` names entry points and `expandSheets()` resolves each one's `@import` graph transitively, because the root `app-shell.css` is a barrel with no declarations of its own. A companion guard requires every `.css` file under `src/css/app-shell/` to appear in that expanded set, so a split sheet cannot be bundled into `dist/247420.css` while remaining invisible to both the linters and any consumer that `<link>`s `app-shell.css` directly.
259
333
 
334
+ ## Visual regression testing
335
+
336
+ `npm run visual` (`node scripts/visual-baseline.mjs check`) screenshots every
337
+ `preview/*.html` page (except `index.html`/`theme-map.html`) in three theme
338
+ states — `paper`, `ink`, `auto` (with `auto` pinned to an emulated `light`
339
+ color-scheme preference, so it captures deterministically) — via Chrome DevTools
340
+ Protocol `Page.captureScreenshot` at a fixed 1280×900 viewport, then diffs each
341
+ capture pixel-by-pixel against the matching committed PNG under
342
+ `visual-baselines/`. It needs no browser-automation package and no image
343
+ library: `scripts/cdp.mjs` drives an already-running Chrome over Node's built-in
344
+ `WebSocket` (it never launches a browser itself — start one with
345
+ `--headless --remote-debugging-port=9333`, or your own workflow step) and
346
+ `scripts/png-diff.mjs` decodes PNG bytes using only `node:zlib`.
347
+
348
+ A page fails the check when either: it has no committed baseline for a given
349
+ file+theme combination, or its diff ratio exceeds `DIFF_THRESHOLD_RATIO`
350
+ (0.5% of pixels), where a pixel only counts as differing once its per-channel
351
+ delta exceeds `CHANNEL_TOLERANCE` (24/255) — this tolerance absorbs
352
+ antialiasing/font-rendering jitter rather than flagging it as a regression. A
353
+ size mismatch between capture and baseline is always a failure regardless of
354
+ threshold.
355
+
356
+ To (re-)freeze the current rendering as the new baseline, run
357
+ `npm run visual:update` (`node scripts/visual-baseline.mjs update`), which
358
+ overwrites every `visual-baselines/*.png` with a fresh capture — no diffing,
359
+ no pass/fail, just a straight re-write.
360
+
260
361
  ## why scope-prefixed
261
362
 
262
363
  Every selector in the bundle is namespaced under `.ds-247420` via PostCSS. The bundle ships a system-font stack (`--ff-body`/`--ff-display`/`--ff-mono`, no web-font `@import`/`@font-face` -- see `colors_and_type.css`) + the design tokens **without** colliding with whatever the host app already runs. Add the class to a root element to opt in. The font tokens are fully overridable: set `--ff-body`/`--ff-display`/`--ff-mono` on any scope to swap typography without touching component code.
package/dist/247420.css CHANGED
@@ -1091,6 +1091,7 @@
1091
1091
  .ds-247420 .app-topbar > .brand { flex: 0 0 auto; }
1092
1092
  .ds-247420 .app-topbar > .app-search { flex: 1 1 auto; }
1093
1093
  .ds-247420 .app-topbar > nav { margin-left: auto; }
1094
+ .ds-247420 .app-topbar > .app-topbar-theme { flex: 0 0 auto; }
1094
1095
  .ds-247420 .app-topbar nav { display: flex; gap: 4px; font-size: var(--fs-sm); flex-wrap: wrap; }
1095
1096
  .ds-247420 .app-topbar nav a { flex: 0 0 auto; }
1096
1097
  .ds-247420 .app-topbar nav a {
@@ -1654,6 +1655,13 @@
1654
1655
  margin: 0; font: inherit; font-size: inherit; font-weight: inherit;
1655
1656
  letter-spacing: inherit; text-transform: inherit; color: inherit;
1656
1657
  }
1658
+ /* Category glyph beside a panel title (kits / previews / decks / docs on the
1659
+ homepage) — same inline-svg vocabulary as icons.js, sized to sit on the
1660
+ text baseline rather than dominating it. */
1661
+ .ds-247420 .ds-panel-title-glyph {
1662
+ display: inline-flex; align-items: center; gap: var(--space-1-5, 6px);
1663
+ }
1664
+ .ds-247420 .ds-panel-title-glyph .ds-icon { flex-shrink: 0; color: var(--fg-3); }
1657
1665
  .ds-247420 .panel-body { padding: var(--space-2) var(--space-3) var(--space-3); }
1658
1666
  .ds-247420 .panel-body > * { margin: 0; }
1659
1667
  /* One-line explanatory caption under a panel's title — e.g. distinguishing
@@ -1694,6 +1702,14 @@
1694
1702
  transition: background var(--dur-snap) var(--ease), box-shadow var(--dur-base) var(--ease-spring);
1695
1703
  }
1696
1704
  .ds-247420 .row + .row { margin-top: 2px; }
1705
+ /* Mobile tap-target floor: at compact/comfortable density on a touch
1706
+ viewport the padding-only row height can fall under the 44px effective
1707
+ tap target (WCAG 2.5.5), especially at [data-density="compact"] (0.75x).
1708
+ Force a min-height on narrow/coarse-pointer viewports only, so the dense
1709
+ desktop mono/list layout (file-row, index-row) is untouched above 640px. */
1710
+ @media (max-width: 640px), (pointer: coarse) {
1711
+ .ds-247420 .row, .ds-247420 a.row, .ds-247420 button.row, .ds-247420 .row[role="button"] { min-height: 44px; }
1712
+ }
1697
1713
  /* Interactive rows (anchor/button wrappers) get a hairline lift on hover,
1698
1714
  matching the btn/panel elevation language — non-interactive rows (plain
1699
1715
  divs used as static list items) are unaffected since the selector needs a
@@ -1955,6 +1971,18 @@
1955
1971
  display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
1956
1972
  justify-content: flex-start; margin-top: var(--space-hair, 4px);
1957
1973
  }
1974
+ /* Hero CTA labels are content-driven (e.g. "GitHub", proper nouns from
1975
+ home.yaml) and the site's voice is deliberately all-lowercase everywhere
1976
+ else. Force the rendered case here rather than hand-lowercasing every
1977
+ proper-noun label at the content layer, so a future CTA label doesn't
1978
+ silently reintroduce Title Case. */
1979
+ .ds-247420 .ds-hero-actions .btn { text-transform: lowercase; }
1980
+ /* Filter input above the homepage's "ui kits" panel — reuses the same
1981
+ .input token the search kit's own topbar query box uses, just placed
1982
+ inline above the panel instead of in a topbar slot. */
1983
+ .ds-247420 .ds-kits-panel-wrap { display: flex; flex-direction: column; gap: var(--space-2, 10px); }
1984
+ .ds-247420 .ds-kits-filter { display: flex; }
1985
+ .ds-247420 .ds-kits-filter-input { width: 100%; max-width: 32ch; }
1958
1986
  /* Below this width the aside card's own internal rhythm (stat rows still
1959
1987
  stacked vertically at full width) is already correct for a narrow column —
1960
1988
  no separate breakpoint override needed now that .ds-hero is always a
@@ -2034,6 +2062,7 @@
2034
2062
  white-space: nowrap; will-change: transform;
2035
2063
  animation: ds-marquee-run 28s linear infinite;
2036
2064
  }
2065
+ .ds-247420 .ds-marquee-run { display: inline-flex; align-items: center; gap: var(--space-5); }
2037
2066
  .ds-247420 .ds-marquee-item { display: inline-flex; align-items: center; gap: var(--space-5); }
2038
2067
  .ds-247420 .ds-marquee-sep { color: var(--accent-ink); }
2039
2068
  .ds-247420 .ds-marquee:hover .ds-marquee-track,
@@ -2960,6 +2989,12 @@
2960
2989
  display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
2961
2990
  gap: var(--space-3); align-items: start;
2962
2991
  }
2992
+ /* Mobile fallback: auto-fill can still pack 2 cramped columns down to ~320px
2993
+ viewports; force a single column below the shared mobile breakpoint
2994
+ (docs/responsive.md) so thumbnails and file rails always read as a list. */
2995
+ @media (max-width: 480px) {
2996
+ .ds-247420 .ds-file-grid-thumb { grid-template-columns: 1fr; }
2997
+ }
2963
2998
  .ds-247420 .ds-file-cell {
2964
2999
  position: relative;
2965
3000
  background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
@@ -3499,6 +3534,12 @@
3499
3534
  .ds-247420 .ds-demo-label { font-size: var(--fs-xs); font-weight: 500; margin: 0 0 var(--space-1); }
3500
3535
  .ds-247420 .ds-demo-desc { font-size: var(--fs-tiny); color: var(--fg-3); margin: 0 0 var(--space-2); }
3501
3536
 
3537
+ /* Per-preview backlink to the full token map/doc — names which token
3538
+ families the specimen above it demonstrates, then links out to the
3539
+ generated theme-map for the resolved values. */
3540
+ .ds-247420 .tokens-backlink { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); margin-top: 2px; }
3541
+ .ds-247420 .tokens-backlink a { color: inherit; }
3542
+
3502
3543
  @media (max-width: 768px) {
3503
3544
  .ds-247420 .ds-catalog { flex-direction: column; }
3504
3545
  .ds-247420 .ds-catalog-side { width: 100%; height: auto; position: static; border-right: 0; border-bottom: var(--bw-hair) solid var(--rule); }
@@ -5026,6 +5067,48 @@
5026
5067
  }
5027
5068
  }
5028
5069
 
5070
+ /* Stacking host for the imperative toast()/<Toast> component
5071
+ (src/components/editor-primitives/toast.js). One fixed-position column;
5072
+ individual toasts are appended/removed as siblings inside it rather than
5073
+ each toast fixed-positioning itself, so more than one toast in flight
5074
+ stacks instead of overlapping at the same bottom-right point. */
5075
+ .ds-247420 .ds-ep-toast-host {
5076
+ position: fixed; z-index: var(--z-toast);
5077
+ bottom: 24px; right: 24px;
5078
+ display: flex; flex-direction: column-reverse; gap: var(--space-2);
5079
+ pointer-events: none;
5080
+ }
5081
+ .ds-247420 .ds-ep-toast {
5082
+ pointer-events: auto;
5083
+ display: flex; align-items: center; gap: var(--space-3);
5084
+ background: var(--bg-2); color: var(--fg);
5085
+ border: 1px solid var(--rule);
5086
+ border-radius: var(--r-2);
5087
+ padding: var(--space-3) var(--space-4);
5088
+ max-width: 320px;
5089
+ box-shadow: var(--shadow-overlay);
5090
+ font-size: var(--fs-sm);
5091
+ }
5092
+ @media (prefers-reduced-motion: no-preference) {
5093
+ .ds-247420 .ds-ep-toast { animation: toast-slide-in 0.3s ease-out; }
5094
+ .ds-247420 .ds-ep-toast.leaving { animation: toast-slide-in 0.2s ease-in reverse; }
5095
+ }
5096
+ .ds-247420 .ds-ep-toast.kind-error { border-color: var(--danger, var(--warn)); }
5097
+ .ds-247420 .ds-ep-toast.kind-success { border-color: var(--green-2); }
5098
+ .ds-247420 .ds-ep-toast.kind-warning { border-color: var(--amber); }
5099
+ .ds-247420 .ds-ep-toast-msg { flex: 1; }
5100
+ .ds-247420 .ds-ep-toast-action {
5101
+ flex-shrink: 0;
5102
+ background: transparent; border: 0; color: var(--accent-ink);
5103
+ font: inherit; font-weight: 600; cursor: pointer; padding: 0;
5104
+ }
5105
+ .ds-247420 .ds-ep-toast-action:hover { text-decoration: underline; }
5106
+
5107
+ @media (max-width: 480px) {
5108
+ .ds-247420 .ds-ep-toast-host { bottom: 16px; right: 16px; left: 16px; }
5109
+ .ds-247420 .ds-ep-toast { max-width: none; }
5110
+ }
5111
+
5029
5112
  /* ============================================================
5030
5113
  Spinner — animated loading indicator
5031
5114
  ============================================================ */
@@ -5703,6 +5786,39 @@
5703
5786
  .ds-247420 .ds-live-log { height: auto; max-height: none; overflow: visible; }
5704
5787
  .ds-247420 .ds-stat, .ds-247420 .kpi-card { border: 1px solid var(--rule); }
5705
5788
  .ds-247420 .ds-session-row { break-inside: avoid; }
5789
+
5790
+ /* Receipt table (Receipt() in src/components/content/panel.js, `.kv`) — the
5791
+ project_page kit's "receipt" section, and any other kv-table consumer.
5792
+ On screen it inherits panel/token colors that can render as near-white
5793
+ text on a printer's assumed-white page background if the browser's
5794
+ "background graphics" print option is off (the common default); force
5795
+ the LIGHT-theme ink/paper tokens (real print-page colors, not a raw
5796
+ literal — --ink/--paper are the same "true black text on true white
5797
+ page" values the light theme already defines) and visible cell borders
5798
+ so it stays legible without relying on background-graphics printing at
5799
+ all. break-inside:avoid keeps a receipt from splitting a row across a
5800
+ page boundary. */
5801
+ .ds-247420 .kv { border-collapse: collapse; width: 100%; color: var(--ink); background: var(--paper); }
5802
+ .ds-247420 .kv tr { break-inside: avoid; }
5803
+ .ds-247420 .kv td { border: 1px solid var(--paper-3); padding: 4px 8px; color: var(--ink); }
5804
+
5805
+ /* Any button/interactive-only affordance still present inside otherwise-
5806
+ printable content (copy buttons, expand/collapse toggles, filter pills,
5807
+ the receipt/doc section's own action row) is chrome, not content. */
5808
+ .ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost, .ds-247420 .row-act, .ds-247420 .ds-filter-pills, .ds-247420 .app-search, .ds-247420 input[type="search"] { display: none; }
5809
+
5810
+ /* Force real ink-on-paper for body copy: panel/fg tokens are tuned for
5811
+ screen surfaces (including dark theme, where --panel-text can resolve
5812
+ near-white) and a printer defaults to a white page regardless of
5813
+ data-theme, so an unconverted dark-theme page would print near-invisible
5814
+ text without this override. Same --ink/--paper light-theme pair as the
5815
+ receipt table above, not a second raw literal. */
5816
+ /* No !important: source order already wins here (this rule is the last
5817
+ word inside its own @media print block, same as every other override in
5818
+ this file), and an unconditional !important on `body` would beat even a
5819
+ future print-specific consumer override with higher specificity. */
5820
+ .ds-247420 body, .ds-247420 .app-main, .ds-247420 .page-body, .ds-247420 .ds-lede { color: var(--ink); background: var(--paper); }
5821
+ .ds-247420 a { color: var(--ink); text-decoration: underline; }
5706
5822
  }
5707
5823
 
5708
5824
  /* ============================================================
@@ -6355,6 +6471,11 @@
6355
6471
  .ds-247420 .ds-btn-row-tight { gap: var(--space-1-75, 6px); }
6356
6472
  .ds-247420 .ds-key-input { flex: 1 1 160px; min-width: 0; font-family: var(--ff-mono); }
6357
6473
  .ds-247420 .ds-toggle-btn { min-width: 78px; }
6474
+ /* Side-by-side checked/unchecked reference pair (settings kit theme panel) --
6475
+ documents the visual difference between states in one static, non-live
6476
+ spot rather than requiring a viewer to toggle a real control back and
6477
+ forth to compare. */
6478
+ .ds-247420 .ds-toggle-state-sample { display: flex; align-items: center; gap: var(--space-1-5, 6px); }
6358
6479
  .ds-247420 .ds-toggle-label { margin-left: var(--space-2, 8px); color: inherit; opacity: 0.7; }
6359
6480
  .ds-247420 .ds-btn-warn { color: var(--warn); }
6360
6481
  /* Raw --mascot text measures 3.11:1 on paper (fails 4.5:1); --mascot-deep is
@@ -6497,6 +6618,14 @@
6497
6618
  display: flex; flex-direction: column; gap: 0;
6498
6619
  background: var(--ink); border-radius: var(--r-1);
6499
6620
  font-family: var(--ff-mono); font-size: var(--fs-micro); line-height: 1.65;
6621
+ /* Responsive strategy for long logs: cap the scrollback height and scroll
6622
+ vertically rather than growing the page indefinitely; long command/output
6623
+ lines wrap (see .cli .cmd's overflow-wrap: anywhere below) instead of
6624
+ scrolling horizontally, so wrapping is the chosen default over
6625
+ horizontal scroll for this kit. */
6626
+ max-height: 60vh;
6627
+ overflow-y: auto;
6628
+ overflow-wrap: anywhere;
6500
6629
  }
6501
6630
  /* .cli is authored in hero-content.css as a STANDALONE hero code block --
6502
6631
  20px/24px padding, --fs-lg type, --r-3 radius and its own --ink background
@@ -12479,6 +12608,16 @@
12479
12608
  color: var(--panel-text);
12480
12609
  overflow: hidden;
12481
12610
  }
12611
+ /* prefers-reduced-transparency: the dock's whole "non-occluding" idiom (see
12612
+ the comment above this block) relies on translucency + blur to let the
12613
+ viewport read through behind it; a user who has disabled see-through
12614
+ panel chrome gets a fully solid --panel-1 backing instead, same layout. */
12615
+ @media (prefers-reduced-transparency: reduce) {
12616
+ .ds-247420 .ds-ep-dock {
12617
+ background: var(--panel-1);
12618
+ -webkit-backdrop-filter: none; backdrop-filter: none;
12619
+ }
12620
+ }
12482
12621
  .ds-247420 .ds-ep-dock-left { left: 8px; }
12483
12622
  .ds-247420 .ds-ep-dock-right { right: 8px; }
12484
12623
  /* Collapsed: shrink to just the header strip, freeing the viewport. */