anentrypoint-design 0.0.191 → 0.0.192

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": "anentrypoint-design",
3
- "version": "0.0.191",
3
+ "version": "0.0.192",
4
4
  "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
5
  "type": "module",
6
6
  "main": "./dist/247420.js",
@@ -131,8 +131,28 @@ const ICON_PATHS = {
131
131
  'skip-forward': '<path d="M5 5v14l9-7z"/><path d="M19 5v14"/>',
132
132
  'chevron-left': '<path d="m15 6-6 6 6 6"/>',
133
133
  trash: '<path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13"/>',
134
- 'external-link': '<path d="M14 4h6v6M20 4l-9 9M19 13v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6"/>'
134
+ 'external-link': '<path d="M14 4h6v6M20 4l-9 9M19 13v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6"/>',
135
+ // theme-toggle icons (replace decorative sun/moon/contrast text glyphs)
136
+ sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/>',
137
+ moon: '<path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z"/>',
138
+ contrast: '<circle cx="12" cy="12" r="9"/><path d="M12 3v18a9 9 0 0 0 0-18z" fill="currentColor"/>',
139
+ // file-browser icons (replace folder/file emoji + arrow glyphs in fs apps)
140
+ folder: '<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>',
141
+ upload: '<path d="M12 16V4M7 9l5-5 5 5"/><path d="M5 20h14"/>',
142
+ download: '<path d="M12 4v12M7 11l5 5 5-5"/><path d="M5 20h14"/>',
143
+ 'corner-up-left': '<path d="M9 14 4 9l5-5"/><path d="M4 9h11a5 5 0 0 1 5 5v6"/>'
135
144
  };
145
+ // Raw-DOM consumers (no webjsx render in scope) need the SVG as a markup string
146
+ // rather than an h() vnode. Same path table, same viewBox/stroke contract as
147
+ // Icon(); use innerHTML = iconMarkup(name). Keeps the icon paths upstream so
148
+ // raw-DOM call sites never reintroduce decorative glyph literals.
149
+ export function iconMarkup(name, { size = 16 } = {}) {
150
+ const inner = ICON_PATHS[name];
151
+ if (!inner) return '';
152
+ return '<svg class="ds-icon ds-icon-' + name + '" width="' + size + '" height="' + size +
153
+ '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="var(--ds-icon-stroke, 1.6)"' +
154
+ ' stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' + inner + '</svg>';
155
+ }
136
156
  export function Icon(name, { size = 16 } = {}) {
137
157
  const inner = ICON_PATHS[name];
138
158
  if (!inner) return h('span', { class: 'glyph', 'aria-hidden': 'true' }, '');
@@ -79,6 +79,9 @@
79
79
  }
80
80
  .browser-app-btn:hover { background: var(--os-accent-soft); }
81
81
  .browser-app-btn:focus-visible { box-shadow: inset 0 0 0 1px var(--os-accent); }
82
+ /* Inert back/forward when there's no history in that direction. */
83
+ .browser-app-btn:disabled { opacity: 0.4; cursor: default; pointer-events: none; }
84
+ .browser-app-btn:disabled:hover { background: var(--os-bg-3); }
82
85
  .browser-app-url {
83
86
  flex: 1 1 auto;
84
87
  min-width: 0;
@@ -110,6 +113,9 @@
110
113
  text-transform: lowercase;
111
114
  min-height: 18px;
112
115
  }
116
+ /* Loading: a thin indeterminate bar under the toolbar. Error: red status row. */
117
+ .browser-app-loading .browser-app-bar { box-shadow: inset 0 -2px 0 var(--os-accent); }
118
+ .browser-app[data-error] .browser-app-status { color: var(--os-danger, #c0392b); }
113
119
 
114
120
  /* --- validator-app --- */
115
121
  .validator-app {
@@ -1,7 +1,10 @@
1
1
  // Browser-pane paint surface — URL bar + iframe slot + status row. Consumer owns iframe.
2
2
  // renderBrowserPane({initialUrl, callbacks: {onNavigate, onReload, onBack, onForward}})
3
- // -> {node, slot, setUrl, setStatus, dispose}.
3
+ // -> {node, slot, setUrl, setStatus, setNav, setLoading, setError, dispose}.
4
4
  // slot is the container the consumer should append its iframe to.
5
+ // setNav({canBack,canForward}) disables the back/forward buttons when history
6
+ // has no entry in that direction; setLoading(bool) toggles a loading state on
7
+ // the bar; setError(msg|null) surfaces a load failure in the status row.
5
8
 
6
9
  export function renderBrowserPane(opts = {}) {
7
10
  const { initialUrl = 'about:blank', callbacks = {} } = opts;
@@ -21,8 +24,14 @@ export function renderBrowserPane(opts = {}) {
21
24
  return b;
22
25
  };
23
26
  const backBtn = mkBtn('<', 'back');
27
+ backBtn.setAttribute('aria-label', 'Back');
24
28
  const fwdBtn = mkBtn('>', 'forward');
29
+ fwdBtn.setAttribute('aria-label', 'Forward');
25
30
  const reloadBtn = mkBtn('reload', 'reload');
31
+ reloadBtn.setAttribute('aria-label', 'Reload');
32
+ // Start with no history in either direction until the consumer says otherwise.
33
+ backBtn.disabled = true;
34
+ fwdBtn.disabled = true;
26
35
 
27
36
  const urlInput = document.createElement('input');
28
37
  urlInput.type = 'text';
@@ -44,6 +53,8 @@ export function renderBrowserPane(opts = {}) {
44
53
 
45
54
  const status = document.createElement('div');
46
55
  status.className = 'browser-app-status';
56
+ status.setAttribute('role', 'status');
57
+ status.setAttribute('aria-live', 'polite');
47
58
  status.textContent = '';
48
59
 
49
60
  node.append(bar, slot, status);
@@ -53,6 +64,22 @@ export function renderBrowserPane(opts = {}) {
53
64
  get slot() { return slot; },
54
65
  setUrl(u) { urlInput.value = u; },
55
66
  setStatus(s) { status.textContent = s; },
67
+ // Reflect history availability so disabled buttons read as inert.
68
+ setNav({ canBack = false, canForward = false } = {}) {
69
+ backBtn.disabled = !canBack;
70
+ fwdBtn.disabled = !canForward;
71
+ },
72
+ // Loading: tint the bar + announce; the consumer flips it off on load/error.
73
+ setLoading(on) {
74
+ node.classList.toggle('browser-app-loading', !!on);
75
+ if (on) { node.removeAttribute('data-error'); status.textContent = 'loading...'; }
76
+ },
77
+ // Error: persistent failure surfaced in the live status row.
78
+ setError(msg) {
79
+ node.classList.remove('browser-app-loading');
80
+ if (msg) { node.setAttribute('data-error', '1'); status.textContent = msg; }
81
+ else { node.removeAttribute('data-error'); }
82
+ },
56
83
  dispose() {},
57
84
  };
58
85
  }
@@ -139,6 +139,18 @@ html, body {
139
139
  }
140
140
  .os-menu .os-btn:hover { background: var(--panel-hover, var(--os-bg-2)); color: var(--os-fg); }
141
141
 
142
+ /* Collapsible "System" apps group inside the apps menu. thebird's os-shell.js
143
+ * builds the group structurally and toggles only the list's display; the static
144
+ * layout (column flow + indent + arrow alignment) lives here so no visual rule
145
+ * leaks back into thebird JS (zero-design-CSS contract). */
146
+ .os-menu-group { display: flex; flex-direction: column; gap: 2px; }
147
+ .os-menu-system-toggle { display: flex; align-items: center; gap: 6px; }
148
+ .os-menu-system-arrow { display: inline-flex; align-items: center; transition: transform 120ms ease; }
149
+ .os-menu-system-arrow .ds-icon { width: 14px; height: 14px; }
150
+ .os-menu-system-list { display: none; flex-direction: column; padding-left: 14px; }
151
+ .os-menu-system-toggle[aria-expanded="true"] + .os-menu-system-list { display: flex; }
152
+ @media (prefers-reduced-motion: reduce) { .os-menu-system-arrow { transition: none; } }
153
+
142
154
  .os-clock {
143
155
  color: var(--os-fg-2);
144
156
  font-variant-numeric: tabular-nums;
@@ -223,13 +235,19 @@ html, body {
223
235
  height: 14px !important;
224
236
  color: var(--os-fg-3);
225
237
  opacity: 0.4;
226
- font: 10px var(--os-mono);
227
- display: flex;
228
- align-items: flex-end;
229
- justify-content: flex-end;
230
- line-height: 1;
231
238
  }
232
- .wm-resize::after { content: '\25E2'; }
239
+ /* Resize grip via CSS gradient (matches wm.css); no decorative content glyph. */
240
+ .wm-resize::after {
241
+ content: '';
242
+ position: absolute;
243
+ right: 3px;
244
+ bottom: 3px;
245
+ width: 8px;
246
+ height: 8px;
247
+ background:
248
+ linear-gradient(135deg, transparent 0 45%, currentColor 45% 55%, transparent 55% 100%),
249
+ linear-gradient(135deg, transparent 0 70%, currentColor 70% 80%, transparent 80% 100%);
250
+ }
233
251
  .wm-body { background: var(--os-bg-1) !important; }
234
252
 
235
253
  .os-side-rail {
@@ -474,6 +492,17 @@ html, body {
474
492
  --os-bar-h: 34px !important;
475
493
  --os-bar-h-mobile: 34px !important;
476
494
  --os-dock-h: 34px !important;
495
+ /* Brand identity, scoped so it never leaks to other portfolio consumers.
496
+ * The base theme's auto/paper/ink presets let --accent drift to the bright
497
+ * --green-2 (#3A9A34) in ink mode; thebird's brand accent is the deep green
498
+ * #247420 (--green) in EVERY resolved mode, and its paper is the warm
499
+ * #F5F0E4 variant. Re-assert both here rather than forcing the consumer to
500
+ * opt into [data-theme="thebird"], which the OS boots past with
501
+ * data-theme="auto". --accent-bright is pinned too so the ink-mode
502
+ * --accent: var(--accent-bright, ...) chain still resolves to brand green. */
503
+ --accent: var(--green) !important;
504
+ --accent-bright: var(--green) !important;
505
+ --paper: #F5F0E4;
477
506
  }
478
507
  /* Window titlebar matches the 34px bar height; clamp so menubar/taskbar/titlebar
479
508
  * heights are uniform. */
@@ -511,11 +540,14 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
511
540
  .ds-247420 .wm-snap-preview {
512
541
  position: fixed;
513
542
  pointer-events: none;
543
+ display: none;
514
544
  z-index: 9050;
515
545
  background: color-mix(in oklab, var(--os-accent) 20%, transparent);
516
546
  border: 2px solid var(--os-accent);
517
547
  border-radius: 8px;
518
- transition: all 120ms ease;
548
+ /* Animate only geometry, never `all` — `transition: all` animated display/
549
+ * opacity too, producing a one-frame ghost on show (jank-pass fix). */
550
+ transition: left 80ms ease, top 80ms ease, width 80ms ease, height 80ms ease;
519
551
  }
520
552
  @media (prefers-reduced-motion: reduce) {
521
553
  .ds-247420 .wm-snap-preview { transition: none; }
@@ -807,11 +839,16 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
807
839
  .ds-247420 .fsb-list { flex: 1; min-height: 0; overflow: auto; padding: .3em 0; }
808
840
  .ds-247420 .fsb-row { display: flex; align-items: center; gap: .6em; padding: .35em .7em; cursor: pointer; border: 0; }
809
841
  .ds-247420 .fsb-row:hover { background: color-mix(in oklab, var(--fg) 6%, transparent); }
842
+ .ds-247420 .fsb-row:focus-visible { outline: 2px solid var(--os-accent); outline-offset: -2px; background: color-mix(in oklab, var(--fg) 6%, transparent); }
810
843
  .ds-247420 .fsb-icon { width: 1.3em; text-align: center; flex: 0 0 auto; }
811
844
  .ds-247420 .fsb-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
812
845
  .ds-247420 .fsb-size { opacity: .55; font-size: 11px; font-variant-numeric: tabular-nums; flex: 0 0 auto; }
813
846
  .ds-247420 .fsb-actions { display: flex; gap: .3em; flex: 0 0 auto; opacity: 0; }
814
- .ds-247420 .fsb-row:hover .fsb-actions { opacity: 1; }
847
+ /* Reveal row actions on hover OR keyboard focus-within OR coarse-pointer (touch),
848
+ * so they aren't hover-only dead controls for keyboard/touch users. */
849
+ .ds-247420 .fsb-row:hover .fsb-actions,
850
+ .ds-247420 .fsb-row:focus-within .fsb-actions { opacity: 1; }
851
+ @media (hover: none) { .ds-247420 .fsb-actions { opacity: 1; } }
815
852
  .ds-247420 .fsb-act { all: unset; cursor: pointer; padding: .1em .35em; border-radius: 5px; opacity: .7; font-size: 12px; }
816
853
  .ds-247420 .fsb-act:hover { opacity: 1; background: color-mix(in oklab, var(--fg) 12%, transparent); }
817
854
  .ds-247420 .fsb-empty { opacity: .5; padding: 1.5em; text-align: center; font-style: italic; }
@@ -829,13 +866,9 @@ html.ds-247420 { touch-action: pan-x pan-y; overscroll-behavior: none; -webkit-t
829
866
  .ds-247420 .wm-context-menu-item { display: block; width: 100%; padding: 7px 10px; border: none; border-radius: 4px; background: none; color: inherit; font-family: inherit; text-align: left; cursor: pointer; font-size: 13px; }
830
867
  .ds-247420 .wm-context-menu-item:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); }
831
868
 
832
- /* ---- wm snap preview (was: docs/wm.js snapPreviewEl cssText) ---- */
833
- .ds-247420 .wm-snap-preview { position: fixed; z-index: 9050; background: var(--os-accent, #247420); opacity: 0.22; border: 2px solid var(--os-accent, #247420); border-radius: 6px; pointer-events: none; display: none; transition: left 80ms ease, top 80ms ease, width 80ms ease, height 80ms ease; }
834
-
835
- /* ---- wm alt-tab switcher (was: docs/wm.js switcherEl cssText) ---- */
836
- .ds-247420 .wm-switcher { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); padding: 16px 20px; background: var(--panel-2, #1a1a1a); border: 1px solid var(--os-accent, #247420); border-radius: 8px; z-index: 9600; font-family: var(--ff-ui); color: var(--fg, #fff); min-width: 240px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); }
837
- .ds-247420 .wm-switcher-row { padding: 8px 12px; border-radius: 4px; margin: 2px 0; cursor: pointer; }
838
- .ds-247420 .wm-switcher-row.is-active { background: color-mix(in oklab, var(--os-accent) 25%, transparent); }
869
+ /* (legacy duplicate .wm-snap-preview + .wm-switcher-row/.is-active blocks
870
+ * removed superseded by the canonical .wm-snap-preview + .wm-switcher /
871
+ * .wm-switcher-item.active rules above; the JS now emits .wm-switcher-item.) */
839
872
 
840
873
  /* ---- todo app (was: docs/apps.js todo-app cssText) ---- */
841
874
  .ds-247420 .tb-todo-bar { display: flex; gap: 6px; margin-bottom: 8px; }
@@ -92,15 +92,22 @@
92
92
  background: transparent;
93
93
  color: var(--os-fg-3);
94
94
  opacity: 0.4;
95
- font: 10px var(--os-mono);
96
- line-height: 1;
97
- display: flex;
98
- align-items: flex-end;
99
- justify-content: flex-end;
100
95
  touch-action: none;
101
96
  }
102
97
  .wm-resize:hover { opacity: 0.7; }
103
- .wm-resize::after { content: '\25E2'; }
98
+ /* Resize grip drawn with CSS (two diagonal hairlines) instead of a decorative
99
+ * unicode content glyph; keeps the affordance, drops the glyph tell. */
100
+ .wm-resize::after {
101
+ content: '';
102
+ position: absolute;
103
+ right: 3px;
104
+ bottom: 3px;
105
+ width: 9px;
106
+ height: 9px;
107
+ background:
108
+ linear-gradient(135deg, transparent 0 45%, currentColor 45% 55%, transparent 55% 100%),
109
+ linear-gradient(135deg, transparent 0 70%, currentColor 70% 80%, transparent 80% 100%);
110
+ }
104
111
 
105
112
  .wm-win.wm-min .wm-body,
106
113
  .wm-win.wm-min .wm-resize { display: none; }