anentrypoint-design 0.0.340 → 0.0.341

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.340",
3
+ "version": "0.0.341",
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",
@@ -97,7 +97,7 @@ function renderPart(p, key) {
97
97
  });
98
98
  }
99
99
 
100
- export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typing, key, aicat, reactions, receipt, name, streaming, actions, incomplete, stopped, flat }) {
100
+ export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typing, key, aicat, reactions, receipt, name, streaming, actions, incomplete, stopped, flat, error, onRetry }) {
101
101
  _stats.messages += 1;
102
102
  // Support legacy 'who' prop, prefer 'role' with mapping:
103
103
  // 'user' -> 'you' (right-aligned, accent bubble)
@@ -144,6 +144,15 @@ export function ChatMessage({ role, who = 'them', avatar, text, parts, time, typ
144
144
  typeof stopped === 'string' ? stopped : 'stopped — this turn was cancelled before it finished')];
145
145
  if (incomplete) bodyNodes = [...bodyNodes, h('div', { key: '_incomplete', class: 'chat-msg-notice is-incomplete', role: 'status' },
146
146
  typeof incomplete === 'string' ? incomplete : 'connection dropped mid-turn — the response may be incomplete')];
147
+ // Inline per-turn error: unlike a global toast, this pins the failure to
148
+ // the specific turn that failed (docstudio pattern) with a retry action
149
+ // right there instead of forcing the user to hunt for what broke.
150
+ if (error) bodyNodes = [...bodyNodes, h('div', { key: '_error', class: 'chat-msg-notice is-error', role: 'alert' },
151
+ h('span', {}, typeof error === 'string' ? error : 'this turn failed'),
152
+ onRetry ? h('button', {
153
+ type: 'button', class: 'chat-msg-retry-btn',
154
+ onclick: (e) => { e.preventDefault(); onRetry(e); },
155
+ }, 'retry') : null)];
147
156
  const reactionRow = reactions && reactions.length
148
157
  ? h('div', { class: 'chat-reactions' },
149
158
  ...reactions.map((r, i) => h('span', { class: 'rxn' + (r.you ? ' you' : ''), key: 'r' + i, 'aria-label': `${r.emoji} reaction (${String(r.count)} ${String(r.count) === '1' ? 'reaction' : 'reactions'})${r.you ? ' - you reacted' : ''}` },
@@ -6,6 +6,18 @@ import * as webjsx from '../../vendor/webjsx/index.js';
6
6
  import { Btn, Heading, Lede, Dot, Icon } from './shell.js';
7
7
  const h = webjsx.createElement;
8
8
 
9
+ // Avatar — generic identity disc: an image when `src` resolves, else a
10
+ // letter fallback derived from `name`/`fallback`. Kit previously only had
11
+ // scoped one-offs (chat.js `.chat-avatar`, community.js `.cm-user-avatar`)
12
+ // duplicating this same letter-fallback logic; this is the reusable version.
13
+ export function Avatar({ name, src, fallback, size = 'md', key } = {}) {
14
+ const letter = fallback != null ? fallback
15
+ : (name ? String(name).trim().charAt(0).toUpperCase() || '?' : '?');
16
+ const cls = 'ds-avatar ds-avatar-' + size;
17
+ if (src) return h('img', { key, class: cls, src, alt: name || '', loading: 'lazy' });
18
+ return h('span', { key, class: cls, 'aria-hidden': !!name, role: name ? 'img' : undefined, 'aria-label': name || undefined }, letter);
19
+ }
20
+
9
21
  export function Panel({ title, count, right, style = '', class: className = '', children, kind, id }) {
10
22
  const cls = 'panel' + (kind ? ' panel-' + kind : '') + (className ? ' ' + className : '');
11
23
  return h('div', { class: cls, style, id: id || null },
@@ -147,8 +147,8 @@ export function FileRow({ name, type = 'other', size, modified, code, onOpen, on
147
147
  // grid does not flash from a bare spinner to a full list (predictable perceived
148
148
  // perf, the file-manager feel). `rows` controls how many ghost rows render.
149
149
  export function FileSkeleton({ rows = 12 } = {}) {
150
- return h('div', { class: 'ds-file-grid ds-file-skeleton', 'aria-hidden': 'true' },
151
- ...Array.from({ length: Math.max(1, rows) }, (_, i) => h('div', { key: 'sk' + i, class: 'ds-file-row ds-file-row-skeleton' },
150
+ return h('div', { class: 'ds-file-grid ds-file-skeleton', role: 'status', 'aria-busy': 'true', 'aria-label': 'loading files' },
151
+ ...Array.from({ length: Math.max(1, rows) }, (_, i) => h('div', { key: 'sk' + i, class: 'ds-file-row ds-file-row-skeleton', 'aria-hidden': 'true' },
152
152
  h('span', { class: 'ds-skel ds-skel-icon' }),
153
153
  h('span', { class: 'ds-skel ds-skel-title' }),
154
154
  h('span', { class: 'ds-skel ds-skel-meta' })))
package/src/components.js CHANGED
@@ -16,7 +16,7 @@ export {
16
16
  WorksList, WritingList, Manifesto, Section, PageHeader,
17
17
  Kpi, Sparkline, BarChart, Table, SearchInput, TextField, Select, EventList,
18
18
  HomeView, ProjectView, Form,
19
- Spinner, Skeleton, Alert, FilterPills
19
+ Spinner, Skeleton, Alert, FilterPills, Avatar
20
20
  } from './components/content.js';
21
21
 
22
22
  export {
@@ -372,3 +372,16 @@
372
372
  .ds-chat-layout { display: grid; grid-template-columns: minmax(0, 1fr) 280px; align-items: start; gap: var(--space-4); }
373
373
  .ds-chat-detail { display: block; position: sticky; top: 0; }
374
374
  }
375
+
376
+ /* Avatar — generic identity disc primitive (content.js Avatar). Sized
377
+ variants mirror the existing chat-avatar/community-avatar footprints so
378
+ any consumer gets a consistent disc without duplicating the CSS. */
379
+ .ds-avatar {
380
+ display: inline-flex; align-items: center; justify-content: center;
381
+ border-radius: 50%; background: var(--bg-3); color: var(--fg);
382
+ font-family: var(--ff-mono); font-weight: 600; text-transform: lowercase;
383
+ letter-spacing: 0.02em; user-select: none; flex-shrink: 0; object-fit: cover;
384
+ }
385
+ .ds-avatar-sm { width: 24px; height: 24px; font-size: 10px; }
386
+ .ds-avatar-md { width: 36px; height: 36px; font-size: 12px; }
387
+ .ds-avatar-lg { width: 48px; height: 48px; font-size: 15px; }