anentrypoint-design 0.0.216 → 0.0.218

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.216",
3
+ "version": "0.0.218",
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",
@@ -184,7 +184,7 @@ export function AgentChat(props = {}) {
184
184
  const msgHasBody = (m) => !!(m.content || (Array.isArray(m.parts) && m.parts.length));
185
185
  const lastMsgLastPart = lastMsg && Array.isArray(lastMsg.parts) && lastMsg.parts.length ? lastMsg.parts[lastMsg.parts.length - 1] : null;
186
186
  const showWorkingTail = busy && lastMsg && lastMsg.role === 'assistant' && msgHasBody(lastMsg)
187
- && lastMsgLastPart && lastMsgLastPart.kind === 'tool' && (lastMsgLastPart.status === 'done' || lastMsgLastPart.status === 'error');
187
+ && lastMsgLastPart && lastMsgLastPart.kind === 'tool' && lastMsgLastPart.status === 'running';
188
188
  const rows = messages.slice(msgStart).map((m, wi) => {
189
189
  const i = wi + msgStart; // absolute index — streaming/caret/actions logic keys off the real lastIdx
190
190
  const isAssistant = m.role === 'assistant';
@@ -164,27 +164,38 @@ const ICON_PATHS = {
164
164
  // rather than an h() vnode. Same path table, same viewBox/stroke contract as
165
165
  // Icon(); use innerHTML = iconMarkup(name). Keeps the icon paths upstream so
166
166
  // raw-DOM call sites never reintroduce decorative glyph literals.
167
- export function iconMarkup(name, { size = 16 } = {}) {
168
- // Accept the props-object shape too - every sibling component takes a
169
- // single object, so Icon({name}) is what the barrel trains consumers to try.
167
+ // The single SVG attribute contract (viewBox/stroke/linecap…) shared by both
168
+ // the markup-string and the vnode renderers below, so the icon shape is defined
169
+ // once. Insertion order is the serialized attribute order iconMarkup emits.
170
+ function iconAttrs(name, size) {
171
+ return {
172
+ class: 'ds-icon ds-icon-' + name,
173
+ width: String(size), height: String(size), viewBox: '0 0 24 24',
174
+ fill: 'none', stroke: 'currentColor', 'stroke-width': 'var(--ds-icon-stroke, 1.6)',
175
+ 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'aria-hidden': 'true',
176
+ };
177
+ }
178
+ // Normalize the (name) | ({name,size}) call shapes both renderers accept.
179
+ function iconArgs(name, size) {
170
180
  if (name && typeof name === 'object') ({ name, size = 16 } = name);
181
+ return { name, size };
182
+ }
183
+ // Raw-DOM consumers (no webjsx render in scope) need the SVG as a markup string
184
+ // rather than an h() vnode. Same path table + attr contract as Icon(); use
185
+ // innerHTML = iconMarkup(name). Keeps the icon paths upstream so raw-DOM call
186
+ // sites never reintroduce decorative glyph literals.
187
+ export function iconMarkup(name, { size = 16 } = {}) {
188
+ ({ name, size } = iconArgs(name, size));
171
189
  const inner = ICON_PATHS[name];
172
190
  if (!inner) return '';
173
- return '<svg class="ds-icon ds-icon-' + name + '" width="' + size + '" height="' + size +
174
- '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="var(--ds-icon-stroke, 1.6)"' +
175
- ' stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' + inner + '</svg>';
191
+ const attrs = Object.entries(iconAttrs(name, size)).map(([k, v]) => `${k}="${v}"`).join(' ');
192
+ return `<svg ${attrs}>${inner}</svg>`;
176
193
  }
177
194
  export function Icon(name, { size = 16 } = {}) {
178
- if (name && typeof name === 'object') ({ name, size = 16 } = name);
195
+ ({ name, size } = iconArgs(name, size));
179
196
  const inner = ICON_PATHS[name];
180
197
  if (!inner) return h('span', { class: 'glyph', 'aria-hidden': 'true' }, '');
181
- return h('svg', {
182
- class: 'ds-icon ds-icon-' + name,
183
- width: String(size), height: String(size), viewBox: '0 0 24 24',
184
- fill: 'none', stroke: 'currentColor', 'stroke-width': 'var(--ds-icon-stroke, 1.6)',
185
- 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'aria-hidden': 'true',
186
- dangerouslySetInnerHTML: { __html: inner }
187
- });
198
+ return h('svg', { ...iconAttrs(name, size), dangerouslySetInnerHTML: { __html: inner } });
188
199
  }
189
200
 
190
201
  export function Topbar({ brand = '247420', leaf = '', items = [], active = '', onNav, search } = {}) {
@@ -467,6 +478,7 @@ export function WorkspaceShell({ rail, sessions, main, pane, crumb, status, narr
467
478
  const keepPaneTrack = stableFrame && !hasPane;
468
479
  const railIsCollapsed = wsCollapsed('rail', railCollapsed);
469
480
  const paneIsCollapsed = hasPane ? wsCollapsed('pane', paneCollapsed) : true;
481
+ const sessionsIsCollapsed = wsCollapsed('sessions', false);
470
482
  const shellCls = 'ws-shell'
471
483
  + (railIsCollapsed ? ' ws-rail-collapsed' : '')
472
484
  + ((hasPane || keepPaneTrack) ? '' : ' ws-no-pane')
@@ -513,8 +525,9 @@ export function WorkspaceShell({ rail, sessions, main, pane, crumb, status, narr
513
525
  // full-width thread/grid). Hidden on mobile via CSS.
514
526
  hasSessions ? h('button', {
515
527
  class: 'ws-desktop-toggle ws-sessions-toggle', type: 'button',
516
- 'aria-label': 'collapse conversations', title: 'collapse conversations',
517
- 'aria-expanded': 'true', onclick: () => toggleWs('sessions'),
528
+ 'aria-label': sessionsIsCollapsed ? 'expand conversations' : 'collapse conversations',
529
+ title: sessionsIsCollapsed ? 'expand conversations' : 'collapse conversations',
530
+ 'aria-expanded': sessionsIsCollapsed ? 'false' : 'true', onclick: () => toggleWs('sessions'),
518
531
  }, Icon('chevron-left')) : null,
519
532
  h('div', { class: 'ws-crumb-main' }, crumb),
520
533
  // Desktop-only context-pane collapse, on the same crumb-level
package/src/markdown.js CHANGED
@@ -10,8 +10,12 @@ let _purify = null;
10
10
  let _failedAt = 0;
11
11
  const RETRY_BACKOFF_MS = 30000;
12
12
 
13
- const MARKED_URL = 'https://cdn.jsdelivr.net/npm/marked@15/+esm';
14
- const PURIFY_URL = 'https://cdn.jsdelivr.net/npm/dompurify@3/+esm';
13
+ // Pin to exact semver so the CDN cannot silently swap code under us.
14
+ // SRI cannot be applied to dynamic ESM imports in browsers (no importmap
15
+ // integrity support at design time); pinning the version is the best available
16
+ // mitigation for CDN-supply-chain risk on these two dependencies.
17
+ const MARKED_URL = 'https://cdn.jsdelivr.net/npm/marked@15.0.12/+esm';
18
+ const PURIFY_URL = 'https://cdn.jsdelivr.net/npm/dompurify@3.2.6/+esm';
15
19
 
16
20
  // True while the markdown stack is unavailable (escaped-fallback rendering).
17
21
  // Consumers (markdown-cache) use this to avoid caching degraded output.
@@ -40,7 +44,9 @@ export async function ensureReady() {
40
44
  return _ready;
41
45
  }
42
46
 
43
- function escapeHtml(s) {
47
+ // The single HTML-entity escape for the whole SDK (full set incl. quotes, so it
48
+ // is safe in attribute contexts too). page-html.js re-exports this as `escape`.
49
+ export function escapeHtml(s) {
44
50
  return String(s).replace(/[&<>"']/g, (c) => ({
45
51
  '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
46
52
  })[c]);
@@ -50,7 +56,7 @@ export async function renderMarkdown(src) {
50
56
  const ok = await ensureReady();
51
57
  if (!ok) return escapeHtml(src).replace(/\n/g, '<br>');
52
58
  const raw = _marked.parse(String(src));
53
- return _purify.sanitize(raw);
59
+ return _purify.sanitize(raw, { FORCE_BODY: true });
54
60
  }
55
61
 
56
62
  // Sanitize already-rendered HTML before it touches innerHTML. For any surface
@@ -60,5 +66,5 @@ export async function renderMarkdown(src) {
60
66
  export async function sanitizeHtml(html) {
61
67
  const ok = await ensureReady();
62
68
  if (!ok) return escapeHtml(html);
63
- return _purify.sanitize(String(html));
69
+ return _purify.sanitize(String(html), { FORCE_BODY: true });
64
70
  }
package/src/page-html.js CHANGED
@@ -16,9 +16,10 @@
16
16
  // cssHref, headExtra,
17
17
  // })
18
18
 
19
- export function escape(s) {
20
- return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
21
- }
19
+ // Single source of HTML escaping lives in markdown.js (full entity set). Kept
20
+ // the `escape` export name for backward compatibility with any consumer.
21
+ import { escapeHtml } from './markdown.js';
22
+ export const escape = escapeHtml;
22
23
 
23
24
  export function inlineMd(s) {
24
25
  return s