anentrypoint-design 0.0.323 → 0.0.325

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.
Files changed (62) hide show
  1. package/README.md +22 -2
  2. package/app-shell.css +24 -4793
  3. package/colors_and_type.css +43 -0
  4. package/dist/247420.css +104 -49
  5. package/dist/247420.js +82 -19
  6. package/package.json +20 -8
  7. package/scripts/lint-glyphs.mjs +105 -0
  8. package/scripts/lint-null-children.mjs +129 -0
  9. package/src/bootstrap.js +10 -1
  10. package/src/community-app.js +3 -3
  11. package/src/components/chat-message-parts.js +356 -0
  12. package/src/components/chat.js +28 -324
  13. package/src/components/content.js +9 -5
  14. package/src/components/data-density.js +15 -10
  15. package/src/components/editor-primitives.js +2 -2
  16. package/src/components/files-modals.js +5 -4
  17. package/src/components/files.js +5 -1
  18. package/src/components/freddie/helpers.js +46 -8
  19. package/src/components/freddie.js +1 -9
  20. package/src/components/interaction-primitives.js +6 -6
  21. package/src/components/sessions.js +15 -0
  22. package/src/components/shell.js +8 -8
  23. package/src/components/theme-toggle.js +2 -2
  24. package/src/components.js +1 -1
  25. package/src/css/app-shell/base.css +157 -0
  26. package/src/css/app-shell/catalog-theme.css +140 -0
  27. package/src/css/app-shell/chat-basic.css +12 -0
  28. package/src/css/app-shell/chat-polish.css +459 -0
  29. package/src/css/app-shell/data-density.css +147 -0
  30. package/src/css/app-shell/files.css +709 -0
  31. package/src/css/app-shell/hero-content.css +405 -0
  32. package/src/css/app-shell/kits-appended.css +361 -0
  33. package/src/css/app-shell/loading-alerts.css +120 -0
  34. package/src/css/app-shell/panel-row.css +177 -0
  35. package/src/css/app-shell/primitives.css +197 -0
  36. package/src/css/app-shell/responsive.css +266 -0
  37. package/src/css/app-shell/responsive2-workspace.css +465 -0
  38. package/src/css/app-shell/row-print.css +75 -0
  39. package/src/css/app-shell/sidebar-misc.css +79 -0
  40. package/src/css/app-shell/states-interactions.css +707 -0
  41. package/src/css/app-shell/topbar.css +319 -0
  42. package/src/deck-stage.js +6 -4
  43. package/src/highlight.js +20 -4
  44. package/src/i18n.js +58 -0
  45. package/src/index.js +22 -7
  46. package/src/kits/os/freddie/pages-chat.js +5 -5
  47. package/src/kits/os/freddie/pages-core.js +1 -1
  48. package/src/kits/os/freddie/pages-os.js +1 -1
  49. package/src/kits/os/freddie/pages-tools.js +2 -2
  50. package/src/kits/os/terminal-app.js +1 -1
  51. package/src/kits/os/wm.js +38 -0
  52. package/src/kits/slides/deck-stage-overlay.js +68 -0
  53. package/src/kits/slides/deck-stage-state.js +81 -0
  54. package/src/kits/slides/deck-stage-style.js +117 -0
  55. package/src/kits/slides/deck-stage.js +167 -0
  56. package/src/kits/slides/index.js +5 -0
  57. package/src/lint.js +10 -0
  58. package/src/markdown.js +89 -11
  59. package/src/page-html.js +121 -4
  60. package/src/theme.js +7 -7
  61. package/src/uid.js +16 -0
  62. package/src/kits/os/freddie/helpers.js +0 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.323",
3
+ "version": "0.0.325",
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",
@@ -15,12 +15,12 @@
15
15
  "import": "./src/kits/spoint/index.js",
16
16
  "default": "./src/kits/spoint/index.js"
17
17
  },
18
- "./kits/spoint/loading-screen.js": "./src/kits/spoint/loading-screen.js",
19
- "./kits/spoint/loading-screen.css": "./src/kits/spoint/loading-screen.css",
20
- "./kits/spoint/game-hud.js": "./src/kits/spoint/game-hud.js",
21
- "./kits/spoint/game-hud.css": "./src/kits/spoint/game-hud.css",
22
- "./kits/spoint/host-join-lobby.js": "./src/kits/spoint/host-join-lobby.js",
23
- "./kits/spoint/host-join-lobby.css": "./src/kits/spoint/host-join-lobby.css",
18
+ "./kits/spoint/*": "./src/kits/spoint/*",
19
+ "./kits/slides": {
20
+ "import": "./src/kits/slides/index.js",
21
+ "default": "./src/kits/slides/index.js"
22
+ },
23
+ "./kits/slides/deck-stage.js": "./src/kits/slides/deck-stage.js",
24
24
  "./kits/os": {
25
25
  "import": "./src/kits/os/index.js",
26
26
  "default": "./src/kits/os/index.js"
@@ -51,13 +51,23 @@
51
51
  "default": "./src/page-html.js"
52
52
  },
53
53
  "./src/page-html.js": "./src/page-html.js",
54
+ "./html-escape.js": "./src/html-escape.js",
55
+ "./components/shell.js": "./src/components/shell.js",
56
+ "./components/files.js": "./src/components/files.js",
57
+ "./components/files-modals.js": "./src/components/files-modals.js",
54
58
  "./web-components/ds-chat.js": "./src/web-components/ds-chat.js",
55
59
  "./web-components/freddie-chat.js": "./src/web-components/freddie-chat.js",
60
+ "./lint": {
61
+ "import": "./src/lint.js",
62
+ "default": "./src/lint.js"
63
+ },
56
64
  "./package.json": "./package.json"
57
65
  },
58
66
  "files": [
59
67
  "dist",
60
68
  "src",
69
+ "scripts/lint-glyphs.mjs",
70
+ "scripts/lint-null-children.mjs",
61
71
  "vendor/webjsx",
62
72
  "colors_and_type.css",
63
73
  "app-shell.css",
@@ -66,10 +76,12 @@
66
76
  "README.md"
67
77
  ],
68
78
  "scripts": {
79
+ "lint": "node scripts/lint.mjs",
69
80
  "lint:tokens": "node scripts/lint-tokens.mjs",
70
81
  "build": "node scripts/build.mjs",
71
82
  "lint:null-children": "node scripts/lint-null-children.mjs",
72
- "lint:classes": "node scripts/lint-classes.mjs"
83
+ "lint:classes": "node scripts/lint-classes.mjs",
84
+ "tokens": "node scripts/generate-tokens-json.mjs"
73
85
  },
74
86
  "repository": {
75
87
  "type": "git",
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ // Decorative-glyph guard: fail the build if any source file hard-codes a
3
+ // decorative unicode glyph (arrows, bullets, checks, stars, status dots, etc.).
4
+ // The design system bans these — chrome must read as one coherent line-icon set
5
+ // (the Icon() SVG component) or industry-standard ASCII, never machine-shaped
6
+ // ornament. This is the durable companion to lint-tokens.mjs: without it, the
7
+ // next hand-edit silently re-introduces a glyph the sweep removed.
8
+ //
9
+ // Run standalone (`node scripts/lint-glyphs.mjs`) or as part of build.mjs.
10
+ import fs from 'node:fs';
11
+ import path from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+
14
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
+ const root = path.resolve(__dirname, '..');
16
+
17
+ // Directories scanned recursively for source files. dist/ is generated,
18
+ // node_modules/ is vendored, vendor/ is third-party (webjsx), .gm/ is the
19
+ // plugkit spool — none are hand-authored design surfaces.
20
+ const SCAN_DIRS = ['src', 'ui_kits', 'slides', 'site'];
21
+ const SCAN_EXT = new Set(['.js', '.mjs', '.css', '.html']);
22
+ // The bundled root CSS files (app-shell.css, chat.css, etc.) are the design
23
+ // system's shipped styling but live at the repo root, outside SCAN_DIRS — they
24
+ // previously escaped the glyph lint entirely (box-drawing comment dividers
25
+ // slipped through). Scan them explicitly so a decorative glyph in shipped CSS
26
+ // fails the build.
27
+ const SCAN_ROOT_FILES = [
28
+ 'app-shell.css', 'chat.css', 'colors_and_type.css', 'community.css',
29
+ 'community-app.css', 'editor-primitives.css', 'app-surfaces.css',
30
+ 'marketing.css',
31
+ ];
32
+
33
+ // Files that are DELIBERATE glyph showcases or documentation of the unicode
34
+ // surface itself — exempt wholesale.
35
+ const EXEMPT_FILES = new Set([
36
+ 'preview/icons-unicode.html', // a deliberate catalog of unicode icons
37
+ ]);
38
+
39
+ // The banned decorative-glyph class. NOT included (intentionally allowed):
40
+ // ⌘ ⇧ ⌥ ⌃ ⇪ ⏎ ⌫ (Mac/keyboard key symbols — industry-standard, not decorative)
41
+ // · (middle-dot separator), — (em-dash), … (ellipsis), › ‹ » « (text seps left to authors)
42
+ // functional JS operators (=>, ??, ?., >=, <=) — those are ASCII, never matched here
43
+ const GLYPH_RE = /[●○◆◉◈▸▾▴◀▶★☆✓✗✕✖✔⟶⇒•◦‣◔↓↑→←⏸⏭ℹ⚠⚒◈▷▭▰◎◐▢↗◌▤▦♪§◫⊞❖✷✢⟳↻↺⥁⟲⌛⏳♻]/;
44
+
45
+ // Per-file allowlist: a line is exempt if it contains the substring AND the
46
+ // file matches. Keep tiny and audited.
47
+ const ALLOW = {
48
+ // (currently none — the sweep left zero intentional decorative glyphs)
49
+ };
50
+
51
+ function isAllowed(rel, line) {
52
+ const list = ALLOW[rel] || [];
53
+ return list.some((s) => line.includes(s));
54
+ }
55
+
56
+ function walk(dir, acc) {
57
+ let entries;
58
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); }
59
+ catch { return acc; }
60
+ for (const e of entries) {
61
+ const full = path.join(dir, e.name);
62
+ if (e.isDirectory()) walk(full, acc);
63
+ else if (SCAN_EXT.has(path.extname(e.name))) acc.push(full);
64
+ }
65
+ return acc;
66
+ }
67
+
68
+ // Returns the array of violation strings (empty == clean). Pure; no exit/log.
69
+ export function findGlyphViolations() {
70
+ const violations = [];
71
+ const files = [];
72
+ for (const d of SCAN_DIRS) walk(path.join(root, d), files);
73
+ for (const f of SCAN_ROOT_FILES) { const p = path.join(root, f); if (fs.existsSync(p)) files.push(p); }
74
+ for (const file of files) {
75
+ const rel = path.relative(root, file).split(path.sep).join('/');
76
+ if (EXEMPT_FILES.has(rel)) continue;
77
+ const src = fs.readFileSync(file, 'utf8');
78
+ src.split(/\r?\n/).forEach((line, i) => {
79
+ if (GLYPH_RE.test(line) && !isAllowed(rel, line)) {
80
+ violations.push(`${rel}:${i + 1}: ${line.trim().slice(0, 100)}`);
81
+ }
82
+ });
83
+ }
84
+ return violations;
85
+ }
86
+
87
+ // Throws on violation; build.mjs calls this so a regression fails the build
88
+ // even under runners (flatspace) that skip npm lifecycle hooks.
89
+ export function lintGlyphsOrThrow() {
90
+ const violations = findGlyphViolations();
91
+ if (violations.length) {
92
+ const msg = '[lint-glyphs] FAIL — decorative unicode glyphs in source '
93
+ + '(use the Icon() SVG component or industry-standard ASCII like -> [x] *):\n '
94
+ + violations.join('\n ')
95
+ + `\n[lint-glyphs] ${violations.length} violation(s). If a glyph is a genuine product-design icon, route it through Icon() or add the file to EXEMPT_FILES / the audited ALLOW list in scripts/lint-glyphs.mjs.`;
96
+ throw new Error(msg);
97
+ }
98
+ console.log('[lint-glyphs] OK — no decorative glyphs in ' + SCAN_DIRS.join('/') + ' (all icons via Icon()/ASCII).');
99
+ }
100
+
101
+ // CLI entry: `node scripts/lint-glyphs.mjs`.
102
+ if (process.argv[1] && process.argv[1].endsWith('lint-glyphs.mjs')) {
103
+ try { lintGlyphsOrThrow(); }
104
+ catch (e) { console.error(e.message); process.exit(1); }
105
+ }
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ // Null-children guard: webjsx applyDiff crashes ("Cannot read properties of
3
+ // undefined (reading 'key')") when a bare null sits among VElement siblings in
4
+ // a children array. The kit discipline is to .filter(Boolean) every children
5
+ // array that contains a conditional vnode — this lint makes the discipline
6
+ // durable instead of comment-maintained (two live crashes are on record: the
7
+ // agentgui 4th and 10th runs).
8
+ //
9
+ // Detection (kept narrow to avoid prop-object false positives): every
10
+ // top-level array literal is bracket-matched; it is flagged iff
11
+ // (a) an ELEMENT-level member starts a vnode call (`h(` or `Component(`), AND
12
+ // (b) an ELEMENT-level member token is `? null` / `: null` (conditional child), AND
13
+ // (c) the closing `]` is not followed (whitespace-tolerant) by `.filter(`.
14
+ // Element-level means at the bracket depth of the array itself, so
15
+ // `{ tabindex: disabled ? '-1' : null }` props never match.
16
+ //
17
+ // Run standalone (`node scripts/lint-null-children.mjs`) or via build.mjs.
18
+ import fs from 'node:fs';
19
+ import path from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
23
+ const root = path.resolve(__dirname, '..');
24
+ const SCAN_DIRS = ['src'];
25
+ const SCAN_EXT = new Set(['.js', '.mjs']);
26
+
27
+ // Per-file allowlist of line numbers or substrings audited as safe.
28
+ const ALLOW = {};
29
+
30
+ function* walk(dir) {
31
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
32
+ const p = path.join(dir, e.name);
33
+ if (e.isDirectory()) {
34
+ if (e.name === 'node_modules' || e.name === 'vendor') continue;
35
+ yield* walk(p);
36
+ } else if (SCAN_EXT.has(path.extname(e.name))) yield p;
37
+ }
38
+ }
39
+
40
+ // Blanks out `//` line-comment content (replacing with spaces, keeping
41
+ // newlines and length so reported line numbers stay accurate) before the
42
+ // bracket-matching pass below. Without this, an apostrophe inside ANY
43
+ // comment anywhere in the file (e.g. "the kit's own") is read as opening a
44
+ // string literal by the naive scanner, silently corrupting bracket-depth
45
+ // tracking for the rest of the file - a false positive here, or worse, a
46
+ // false NEGATIVE that hides a real missing .filter(Boolean) elsewhere.
47
+ // Comments living inside actual string/template literals (rare, but a `//`
48
+ // can appear in a URL string) are left alone via the same inStr tracking.
49
+ function stripLineComments(src) {
50
+ const out = src.split('');
51
+ let inStr = null;
52
+ for (let i = 0; i < out.length; i++) {
53
+ const c = out[i];
54
+ if (inStr) {
55
+ if (c === '\\') { i++; continue; }
56
+ if (c === inStr) inStr = null;
57
+ continue;
58
+ }
59
+ if (c === "'" || c === '"' || c === '`') { inStr = c; continue; }
60
+ if (c === '/' && out[i + 1] === '/') {
61
+ let j = i;
62
+ while (j < out.length && out[j] !== '\n') out[j++] = ' ';
63
+ i = j - 1;
64
+ }
65
+ }
66
+ return out.join('');
67
+ }
68
+
69
+ function findViolations(src) {
70
+ const scan = stripLineComments(src);
71
+ const out = [];
72
+ for (let i = 0; i < scan.length; i++) {
73
+ if (scan[i] !== '[') continue;
74
+ // bracket-match this array literal, tracking element-level segments
75
+ let depth = 0, j = i, inStr = null, elemStart = i + 1;
76
+ const elems = [];
77
+ for (; j < scan.length; j++) {
78
+ const c = scan[j];
79
+ if (inStr) {
80
+ if (c === '\\') j++;
81
+ else if (c === inStr) inStr = null;
82
+ continue;
83
+ }
84
+ if (c === "'" || c === '"' || c === '`') { inStr = c; continue; }
85
+ if (c === '[' || c === '(' || c === '{') depth++;
86
+ else if (c === ']' || c === ')' || c === '}') {
87
+ depth--;
88
+ if (depth === 0 && c === ']') { elems.push(scan.slice(elemStart, j)); break; }
89
+ } else if (c === ',' && depth === 1) { elems.push(scan.slice(elemStart, j)); elemStart = j + 1; }
90
+ }
91
+ if (j >= scan.length) continue;
92
+ const after = scan.slice(j + 1, j + 24);
93
+ if (/^\s*\.filter\(/.test(after)) continue;
94
+ const hasVnode = elems.some((e) => /(^|\s|\(|,)(h\(|[A-Z][A-Za-z0-9]*\()/.test(e.trim()));
95
+ // conditional-child tail: the ELEMENT itself ends in `: null` or `? ... : null`
96
+ const hasCondNull = elems.some((e) => /[?:]\s*null\s*$/.test(e.trim()));
97
+ if (hasVnode && hasCondNull) {
98
+ const line = src.slice(0, i).split('\n').length;
99
+ out.push(line);
100
+ i = j; // skip past this array
101
+ }
102
+ }
103
+ return out;
104
+ }
105
+
106
+ export function lintNullChildrenOrThrow() {
107
+ const failures = [];
108
+ for (const dir of SCAN_DIRS) {
109
+ const abs = path.join(root, dir);
110
+ if (!fs.existsSync(abs)) continue;
111
+ for (const file of walk(abs)) {
112
+ const rel = path.relative(root, file);
113
+ const src = fs.readFileSync(file, 'utf8');
114
+ const allow = ALLOW[rel] || [];
115
+ for (const line of findViolations(src)) {
116
+ if (allow.includes(line)) continue;
117
+ failures.push(rel + ':' + line);
118
+ }
119
+ }
120
+ }
121
+ if (failures.length) {
122
+ throw new Error('[lint-null-children] conditional null among vnode siblings without .filter(Boolean):\n ' + failures.join('\n '));
123
+ }
124
+ console.log('[lint-null-children] OK — every conditional-children array is filter(Boolean)\'d.');
125
+ }
126
+
127
+ if (import.meta.url === 'file://' + process.argv[1] || process.argv[1]?.endsWith('lint-null-children.mjs')) {
128
+ lintNullChildrenOrThrow();
129
+ }
package/src/bootstrap.js CHANGED
@@ -5,9 +5,18 @@ import * as webjsx from '../vendor/webjsx/index.js';
5
5
  import * as motion from './motion.js';
6
6
  import { register } from './debug.js';
7
7
 
8
+ // Tracks nodes already mounted via mountKit() so a second mountKit() call
9
+ // onto the same root fails loud instead of silently layering a second
10
+ // applyDiff/motion loop on one DOM node.
11
+ const _mountedKitRoots = new WeakSet();
12
+
8
13
  export function mountKit({ root, view, screen, animateOnMount = true } = {}) {
9
- if (!root) throw new Error('mountKit: root required');
14
+ if (!root) throw new Error('mountKit: root required (received ' + (root === null ? 'null' : typeof root) + ')');
10
15
  if (typeof view !== 'function') throw new Error('mountKit: view fn required');
16
+ if (_mountedKitRoots.has(root)) {
17
+ throw new Error('mountKit: this root is already mounted — call the returned render()/schedule() to re-render, do not mountKit() the same root twice');
18
+ }
19
+ _mountedKitRoots.add(root);
11
20
  if (screen && typeof document !== 'undefined') document.body.dataset.screenLabel = screen;
12
21
  motion.installMotion();
13
22
  let scheduled = false;
@@ -214,8 +214,8 @@ export function mountCommunityApp(root, adapter = {}) {
214
214
  ),
215
215
  // overlays
216
216
  ctx.open ? ContextMenu({ items: ctx.items, anchor: { x: ctx.x, y: ctx.y }, onClose: () => { ctx = { ...ctx, open: false }; render(); } }) : null,
217
- emoji.open ? EmojiPicker({ open: true, anchorX: emoji.x, anchorY: emoji.y, onSelect: (em) => { try { emoji.onSelect && emoji.onSelect(em); } catch (_) {} emoji = { ...emoji, open: false }; render(); }, onClose: () => { emoji = { ...emoji, open: false }; render(); } }) : null,
218
- palette.open ? CommandPalette({ open: true, items: palette.items, onSelect: (it) => { try { palette.onSelect && palette.onSelect(it); } catch (_) {} palette = { ...palette, open: false }; render(); }, onClose: () => { palette = { ...palette, open: false }; render(); } }) : null,
217
+ emoji.open ? EmojiPicker({ open: true, anchorX: emoji.x, anchorY: emoji.y, onSelect: (em) => { try { emoji.onSelect && emoji.onSelect(em); } catch (_) { /* swallow: consumer onSelect callback must not break overlay close/re-render */ } emoji = { ...emoji, open: false }; render(); }, onClose: () => { emoji = { ...emoji, open: false }; render(); } }) : null,
218
+ palette.open ? CommandPalette({ open: true, items: palette.items, onSelect: (it) => { try { palette.onSelect && palette.onSelect(it); } catch (_) { /* swallow: consumer onSelect callback must not break overlay close/re-render */ } palette = { ...palette, open: false }; render(); }, onClose: () => { palette = { ...palette, open: false }; render(); } }) : null,
219
219
  // global overlays (visibility driven by adapter snapshot)
220
220
  s.showAuthModal ? AuthModal({ open: true, mode: s.authMode || 'extension', error: s.authError || '', busy: !!s.authBusy, onModeChange: (m) => A.setAuthMode && A.setAuthMode(m), onConnectExtension: () => A.authExtension && A.authExtension(), onGenerate: () => A.authGenerate && A.authGenerate(), onImport: (k) => A.authImport && A.authImport(k), onClose: () => A.closeAuth && A.closeAuth() }) : null,
221
221
  BootOverlay({ progress: s.bootProgress || 0, phase: s.bootPhase || '', errored: !!s.bootErrored, visible: !!s.bootVisible }),
@@ -255,5 +255,5 @@ export function mountCommunityApp(root, adapter = {}) {
255
255
  });
256
256
 
257
257
  render();
258
- return { render, api, destroy: () => { if (unsub) try { unsub(); } catch (_) {} } };
258
+ return { render, api, destroy: () => { if (unsub) try { unsub(); } catch (_) { /* swallow: unsubscribe failure during teardown is non-fatal */ } } };
259
259
  }