anentrypoint-design 0.0.211 → 0.0.212

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.211",
3
+ "version": "0.0.212",
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",
@@ -6,8 +6,8 @@ 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
- export function Panel({ title, count, right, style = '', children, kind, id }) {
10
- const cls = 'panel' + (kind ? ' panel-' + kind : '');
9
+ export function Panel({ title, count, right, style = '', class: className = '', children, kind, id }) {
10
+ const cls = 'panel' + (kind ? ' panel-' + kind : '') + (className ? ' ' + className : '');
11
11
  return h('div', { class: cls, style, id: id || null },
12
12
  title != null ? h('div', { class: 'panel-head' },
13
13
  h('span', {}, title),
@@ -4,10 +4,6 @@ import * as webjsx from '../../vendor/webjsx/index.js';
4
4
  import { Btn, Icon } from './shell.js';
5
5
  const h = webjsx.createElement;
6
6
 
7
- // Minimum column width for the responsive file grid (minmax floor). Named so
8
- // the magic 240px isn't buried in the gridTemplateColumns string.
9
- const FILE_GRID_MIN_COL = '240px';
10
-
11
7
  const FILE_TYPES = ['dir', 'image', 'video', 'audio', 'code', 'text', 'archive', 'document', 'symlink', 'other'];
12
8
  const TYPE_ICON = {
13
9
  dir: 'folder', image: 'file-image', video: 'file-video', audio: 'file-audio', code: 'file-code',
@@ -178,7 +174,7 @@ export function sortFiles(files = [], sort = 'name', dir = 'asc') {
178
174
  const FILE_GRID_CAP = 200;
179
175
 
180
176
  export function FileGrid({ files = [], onOpen, onAction, onUp, emptyText = 'No files here yet',
181
- columns = 'auto', sort, filter, loading = false,
177
+ sort, filter, loading = false,
182
178
  shown, onShowMore, actions, busy,
183
179
  // Canonical multi-select contract (shared with
184
180
  // SessionDashboard): selected/onToggleSelect.
@@ -200,16 +196,11 @@ export function FileGrid({ files = [], onOpen, onAction, onUp, emptyText = 'No f
200
196
  const capped = files.length > limit;
201
197
  const visible = capped ? files.slice(0, limit) : files;
202
198
  const isThumb = density === 'thumb';
199
+ // NOTE: the old `columns`-driven data-columns card-mode was removed - it placed
200
+ // flex list-rows into a 2-4 col grid (squashed rows, mis-sized actions) and was
201
+ // a half-wired third layout never exposed by the density radiogroup (list/
202
+ // compact/thumb). Thumb density is the canonical multi-column grid.
203
203
  const gridAttrs = {};
204
- if (!isThumb && columns !== 'auto' && columns > 0) {
205
- const col = Math.max(1, Math.min(4, Math.floor(columns)));
206
- gridAttrs['data-columns'] = String(col);
207
- gridAttrs.style = {
208
- display: 'grid',
209
- gridTemplateColumns: `repeat(${col}, minmax(${FILE_GRID_MIN_COL}, 1fr))`,
210
- gap: 'var(--space-3)'
211
- };
212
- }
213
204
  // Multi-select bookkeeping. Entries are keyed by path (fallback name); a
214
205
  // locked/EACCES entry is never selectable — bulk mutations would fail on it.
215
206
  const entryKeyOf = (f) => f.path || f.name;
@@ -257,19 +248,24 @@ export function FileGrid({ files = [], onOpen, onAction, onUp, emptyText = 'No f
257
248
  onclick: () => { if (density !== k) onDensity(k); },
258
249
  }, label)))
259
250
  : null;
260
- const controlsKids = [selectAllCtl, head,
261
- (selectAllCtl || head) && densityCtl ? h('span', { key: 'spread', class: 'spread' }) : null,
251
+ // One toolbar baseline: filter + select-all + sort sit left, density is
252
+ // pushed right by the spread. The filter used to be a separate right-aligned
253
+ // strip ABOVE controls, giving two strips with conflicting alignment.
254
+ const filterCtl = filter ? h('input', {
255
+ key: 'filter',
256
+ class: 'ds-file-filter-input', type: 'search',
257
+ value: filter.value || '', placeholder: filter.placeholder || 'Filter files',
258
+ 'aria-label': filter.placeholder || 'Filter files in this directory',
259
+ oninput: (e) => filter.onInput && filter.onInput(e.target.value),
260
+ }) : null;
261
+ const leftKids = [filterCtl, selectAllCtl, head].filter(Boolean);
262
+ const controlsKids = [
263
+ ...leftKids,
264
+ (leftKids.length && densityCtl) ? h('span', { key: 'spread', class: 'spread' }) : null,
262
265
  densityCtl].filter(Boolean);
263
266
  const controls = controlsKids.length
264
267
  ? h('div', { class: 'ds-file-controls' }, ...controlsKids)
265
268
  : null;
266
- const filterBar = filter ? h('div', { class: 'ds-file-filter' },
267
- h('input', {
268
- class: 'ds-file-filter-input', type: 'search',
269
- value: filter.value || '', placeholder: filter.placeholder || 'Filter files',
270
- 'aria-label': filter.placeholder || 'Filter files in this directory',
271
- oninput: (e) => filter.onInput && filter.onInput(e.target.value),
272
- })) : null;
273
269
  // role=group not listbox: the rows contain real <button> action controls, so
274
270
  // listbox/option semantics are invalid (an option can't host interactive
275
271
  // children). Keyboard nav still works via roving focus over the open buttons.
@@ -311,8 +307,8 @@ export function FileGrid({ files = [], onOpen, onAction, onUp, emptyText = 'No f
311
307
  onclick: () => onShowMore(Math.min(files.length, limit + FILE_GRID_CAP)) },
312
308
  'show ' + Math.min(FILE_GRID_CAP, files.length - limit) + ' more') : null)
313
309
  : null;
314
- return (controls || filterBar || more)
315
- ? h('div', { class: 'ds-file-listing' }, filterBar, controls, grid, more)
310
+ return (controls || more)
311
+ ? h('div', { class: 'ds-file-listing' }, controls, grid, more)
316
312
  : grid;
317
313
  }
318
314
 
@@ -171,7 +171,9 @@ export function SessionCard({ session = {}, onStop, onOpen, onView, active = fal
171
171
  // sessions with no cost source (external tally rows) simply omit the segment.
172
172
  const tokText = s.tokens != null ? (typeof s.tokens === 'number' ? s.tokens.toLocaleString() : s.tokens) + ' tok' : null;
173
173
  const costText = s.cost != null ? (typeof s.cost === 'number' ? '$' + s.cost.toFixed(4) : String(s.cost)) : null;
174
- const statBits = [elapsedText, s.counter != null ? s.counter : null, tokText, costText].filter((x) => x != null && x !== '');
174
+ // Cost is rendered as its own emphasized segment (not buried in the mono run)
175
+ // so the command-center cost-at-a-glance signal is scannable.
176
+ const statBits = [elapsedText, s.counter != null ? s.counter : null, tokText].filter((x) => x != null && x !== '');
175
177
  const activityBits = [
176
178
  s.currentTool ? 'running: ' + s.currentTool : null,
177
179
  s.lastActivity ? 'last ' + s.lastActivity : null,
@@ -195,7 +197,10 @@ export function SessionCard({ session = {}, onStop, onOpen, onView, active = fal
195
197
  ].filter(Boolean));
196
198
  const meta = h('div', { class: 'ds-dash-meta' }, ...[
197
199
  s.cwd ? h('span', { class: 'ds-dash-cwd', title: s.cwd }, s.cwd) : null,
198
- statBits.length ? h('span', { class: 'ds-dash-stat' }, statBits.join(' · ')) : null,
200
+ (statBits.length || costText) ? h('span', { class: 'ds-dash-stat' },
201
+ statBits.join(' · '),
202
+ costText ? h('span', { class: 'ds-dash-stat-cost' }, (statBits.length ? ' · ' : '') + costText) : null
203
+ ) : null,
199
204
  activityBits.length ? h('span', { class: 'ds-dash-activity' }, activityBits.join(' · ')) : null,
200
205
  ].filter(Boolean));
201
206
  const actions = h('div', { class: 'ds-dash-actions', role: 'group', 'aria-label': 'session actions' }, ...[
@@ -318,8 +318,13 @@ function toggleWs(which) {
318
318
 
319
319
  // Column resize: read the current rendered track width and write a clamped inline
320
320
  // --ws-<col>-w on .ws-shell (inline overrides the fluid clamp base), persisted.
321
- const WS_RESIZE_CLAMP = { rail: [60, 360], sessions: [200, 520], pane: [240, 560] };
322
- function wsResize(col, dx) {
321
+ // Bounds are derived from the CSS fluid clamp() floors/ceilings in app-shell.css
322
+ // (--ws-rail-w clamp(200,16vw,260); sessions clamp(248,22vw,360); pane
323
+ // clamp(288,24vw,420)) so a drag/arrow can never shrink a column below its
324
+ // designed floor (the collapsed rail is a SEPARATE class, not a resize target)
325
+ // nor grow past the ultrawide ceiling.
326
+ const WS_RESIZE_CLAMP = { rail: [200, 260], sessions: [248, 360], pane: [288, 420] };
327
+ function wsResize(col, dx, persist = true) {
323
328
  const shell = document.querySelector('.ws-shell');
324
329
  if (!shell) return;
325
330
  const track = shell.querySelector('.ws-' + col);
@@ -327,7 +332,11 @@ function wsResize(col, dx) {
327
332
  const [lo, hi] = WS_RESIZE_CLAMP[col] || [120, 600];
328
333
  const next = Math.max(lo, Math.min(hi, Math.round(cur + dx)));
329
334
  shell.style.setProperty('--ws-' + col + '-w', next + 'px');
330
- try { localStorage.setItem('ds.ws.w.' + col, String(next)); } catch (_) {}
335
+ const handle = shell.querySelector('.ws-resizer-' + col);
336
+ if (handle) handle.setAttribute('aria-valuenow', String(next));
337
+ // Commit to storage only on a settled move (pointerup / keyboard), not on
338
+ // every pointermove frame (that fired dozens of synchronous writes per drag).
339
+ if (persist) { try { localStorage.setItem('ds.ws.w.' + col, String(next)); } catch (_) {} }
331
340
  }
332
341
  function seedWsWidths(el) {
333
342
  if (!el) return;
@@ -340,22 +349,35 @@ function seedWsWidths(el) {
340
349
  }
341
350
  function WsResizer(col) {
342
351
  const onKey = (e) => {
343
- if (e.key === 'ArrowLeft') { e.preventDefault(); wsResize(col, -16); }
344
- else if (e.key === 'ArrowRight') { e.preventDefault(); wsResize(col, 16); }
352
+ if (e.key === 'ArrowLeft') { e.preventDefault(); wsResize(col, -16, true); }
353
+ else if (e.key === 'ArrowRight') { e.preventDefault(); wsResize(col, 16, true); }
345
354
  };
346
355
  const onDown = (e) => {
347
356
  e.preventDefault();
348
357
  let lastX = e.clientX;
349
- const move = (ev) => { const dx = ev.clientX - lastX; lastX = ev.clientX; wsResize(col, dx); };
350
- const up = () => { document.removeEventListener('pointermove', move); document.removeEventListener('pointerup', up); document.body.style.cursor = ''; };
358
+ const move = (ev) => { const dx = ev.clientX - lastX; lastX = ev.clientX; wsResize(col, dx, false); };
359
+ const up = () => {
360
+ document.removeEventListener('pointermove', move);
361
+ document.removeEventListener('pointerup', up);
362
+ document.body.style.cursor = '';
363
+ wsResize(col, 0, true); // commit the settled width once
364
+ };
351
365
  document.addEventListener('pointermove', move);
352
366
  document.addEventListener('pointerup', up);
353
367
  document.body.style.cursor = 'col-resize';
354
368
  };
369
+ const [lo, hi] = WS_RESIZE_CLAMP[col] || [120, 600];
370
+ // Seed aria-valuenow from the rendered track width so AT announces real widths.
371
+ const seedNow = (el) => {
372
+ if (!el) return;
373
+ const track = el.closest('.ws-shell') && el.closest('.ws-shell').querySelector('.ws-' + col);
374
+ if (track) el.setAttribute('aria-valuenow', String(Math.round(track.getBoundingClientRect().width)));
375
+ };
355
376
  return h('div', {
356
377
  class: 'ws-resizer ws-resizer-' + col, role: 'separator', tabindex: '0',
357
378
  'aria-orientation': 'vertical', 'aria-label': 'resize ' + col + ' column (arrow keys)',
358
- onpointerdown: onDown, onkeydown: onKey,
379
+ 'aria-valuemin': String(lo), 'aria-valuemax': String(hi),
380
+ onpointerdown: onDown, onkeydown: onKey, ref: seedNow,
359
381
  });
360
382
  }
361
383
 
@@ -550,8 +572,8 @@ export function WorkspaceRail({ brand = '247420', action, items = [], footer } =
550
572
  );
551
573
  }
552
574
 
553
- export function Heading({ level = 1, children, style = '', 'aria-level': ariaLevel }) {
554
- return h('h' + level, { style, 'aria-level': ariaLevel != null ? String(ariaLevel) : null }, children);
575
+ export function Heading({ level = 1, children, style = '', class: className = '', 'aria-level': ariaLevel }) {
576
+ return h('h' + level, { class: className || null, style, 'aria-level': ariaLevel != null ? String(ariaLevel) : null }, children);
555
577
  }
556
578
 
557
579
  export function Lede({ children }) {