@design.estate/dees-catalog 9.6.0 → 9.6.2

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/readme.hints.md DELETED
@@ -1,1233 +0,0 @@
1
- ## Forms and inputs — September 2026
2
-
3
- - Shared field CSS and `inputLayout` live in `dees-input-base`; use `.field-control` for a single border/focus owner and `.input-action` for compound actions. Keep integrated table editors on their existing cell-owned focus path.
4
- - `ts_web/demos/inputs.ts` owns the 18-input workspace fixture and focused examples. The showcase saves real form values; do not rebuild view toggles or omit the compound controls from coverage.
5
- - Compound fields span the settings row. Grouped forms must not clip rings or anchored suggestions. Test editor, grouped, disabled and coarse-pointer layouts.
6
- - Phone/IBAN event targets are retargeted at shadow boundaries: read the native input from `composedPath()[0]`, and publish one compound change per edit.
7
- - Input hosts delegate focus; form Enter skips disabled fields and leaves buttons, composition, pickers and multiline editing in control of their own keys.
8
- - Search-select is an empty source, not a registered input. Dropdown already supports search. Use exact Lit property bindings and verified public events in examples.
9
-
10
- !!! Please pay attention to the following points when writing the readme: !!!
11
- * Give a short rundown of components and a few points abput specific features on each.
12
- * Try to list all components in a summary.
13
- * Then list all components with a short description.
14
-
15
- ## Catalog design and demos
16
-
17
- - `ts_web/elements/00theme.ts` owns shared control, surface, spacing, and typography tokens. Controls use 8px corners, grouped surfaces 12px, and modal windows 20px. Modal and dropdown surfaces are opaque.
18
- - `DeesModal` owns a native `<dialog>` focus scope. A sidebar reserves 400px on desktop and 520px at viewport widths up to 600px unless `height` overrides it; content scrolls within the viewport-clamped frame. Do not measure each selected panel and resize the window on navigation.
19
- - `00overlay.ts` locates the invoking node's open dialog across slots and shadow roots. Transient controls must stay inside that dialog. A global body portal with a large z-index cannot escape the native top layer.
20
- - `DeesFormSubmit.focus()` only focuses. Use `submit()` to gather and dispatch values. Demo forms must give every field a real `key`; validation feedback and application submission rules are separate concerns.
21
- - `ts_web/demos/templates.ts` owns demo layout only. `workspace.ts` provides the shared form fixture. Pages cover a working composition, foundations, inputs, and overlay scenarios; component galleries retain specific variants. Use `DeesPanel.title/subtitle`, `DeesButton`'s `clicked` event, and text-safe local results.
22
- - The preview runs through `pnpm run watch` on port 3002. Workbench appearance is controlled by its route (`dark` / `bright`), so do not add a competing theme toggle to a page.
23
- - `DeesStatsGrid` measures its own width with a connection-owned `ResizeObserver`; configured minimum tile width and gap determine columns, and each span is clamped to those columns. Its single tile body owns title/value/context spacing; the unused default tile header is hidden through the tile's public part. Keep metric actions as native controls and dispatch anchored composed context-menu events to preserve dialog ownership and focus restoration.
24
- - `DeesDataviewStatusobject` renders status explanations and distinct shapes, wraps values through its own size container, and reports clipboard failure without claiming success. In-flight copy requests are invalidated on disconnect. The shared `demos/operations.ts` fixture powers deterministic scenario changes and manual samples for both overview demos.
25
-
26
- ## Agent Chat Architecture
27
-
28
- - Harness presentation is shared through `harness.styles.ts`: neutral 12px cards, 28px action controls, sentence-case status pills and small opacity pulses. Running surfaces do not animate. Session selection changes the inset color and border without moving text or changing drag geometry. Brief outcome flashes and the existing scroll-edge fades remain.
29
- - Harness demos use `demoPage` or `demoApp` from the catalog helpers. Keep scenario controls outside the chat window; preserve each component's events, state examples and bounded scrolling when changing layouts.
30
-
31
- - `DeesHarnessSessionList` resource associations are controlled projections. Resources and associations remain host-owned; component-originated attach, detach, and reassign requests use `requestResourceAssociation()` and reconcile only when fresh `resourceAssociations` arrive.
32
- - Resource association normalization accepts the first valid record per known resource and ignores incomplete metadata, unknown references, or later duplicate records without mutating inputs. A missing `eligibleSessionIdsByResourceId` entry means no attach/reassign target; existing authoritative associations still render and can detach.
33
- - Resource pointer dragging is a separate gesture from session grip reordering. It targets an eligible whole session article, never creates a session drop slot, and never emits `harness-session-move`.
34
- - `DeesHarnessMessageList` owns transcript ordering and responsive tool grouping. Consecutive tools use one generic keyed-grid pipeline partitioned by descriptor layout: compact with compact, subtask with subtask, and full-row tools spanning every column. Never move cards between active and historical owners when status changes.
35
- - The transcript scroll box is the named inline-size container. Tool columns must respond to its content width so opening the session panel naturally reduces the column count.
36
- - Group identity is retained through front-window eviction while any card remains. Untouched projected subtasks collapse individually on completion without adding a second grid-level disclosure; other tools keep descriptor or user disclosure state.
37
- - `IHarnessToolCall.subtask` is an authoritative bounded child-session preview owned by the host. dees-catalog never fetches or subscribes to a runtime.
38
- - Existing child messages may receive deltas with one `parentMessageId`. Newly introduced child messages require a complete parent `tool-update` snapshot first.
39
- - `markdownWhileStreaming` defaults to true across chat, message-list, message, and tool-card hosts. Setting it false at an outer host keeps outer and nested child streams plain until the final message-end parse; forward it through render bindings and never add it to timeline rebuild conditions.
40
- - Inline subagent streams stop after one level through `allowSubtaskStreams`; deeper sessions use `harness-subtask-open`. A projection's `subtask.sessionId` is authoritative for drill-in; calls without a projection continue to use the existing `childSessionId` field.
41
- - Busy subtask cards slot Agent Brief into the nested message list's scroll flow. Terminal subtasks remove the nested chat and render Agent Brief, then Result, then the bottom drill-in action.
42
- - Subtask scroll surfaces hide visual scrollbars and toggle 40px top/bottom fades from actual remaining scroll content; never show an edge fade when already at that edge.
43
- - Authoritative child status controls subtask activity and untouched default expansion. Grid membership depends only on whether a message has a tool call.
44
- - Transcript resize-follow reacts to content growth only. Disclosure shrink must not repeatedly repin the outer scroll box.
45
- - `DeesHarnessOverflowText` owns the shared 40px right-edge fade and overflow-only reveal animation used by tool-card subtitles and Tools & Subagents activity text. It runs on hover and once after the initial two-second delay.
46
- - The session sidebar derives Tools & Subagents from top-level tool messages in the current retained transcript window; it never caches evicted history or includes tools inside child projections.
47
-
48
- ## PDF Components
49
-
50
- - `PdfManager` creates one local module `Worker` per load and acquires the `PDFWorker` and loading task as that load progresses. Failures and aborts release every level acquired so far; successful callers release the returned document on URL change, replacement, or disconnect.
51
- - Keep PDF.js imported from the installed `pdfjs-dist` package. Runtime CDN imports and worker fallbacks are not allowed.
52
- - `DeesPdfViewer` uses the PDF.js `TextLayer` class. Cleanup closes render admission, starts document release to interrupt PDF.js operations, and settles release and tracked pipelines together within a bounded deadline.
53
- - PDF component loads are keyed by connection epoch and URL so stale loads cannot update detached, reconnected, or repurposed elements.
54
-
55
- ## Chart Components
56
-
57
- ### dees-chart-area
58
- - Uses Lightweight Charts; bar, donut, gauge and radar use ECharts.
59
- - `series` is an array of named series with `{ x, y }` samples, not an ApexCharts data shape.
60
- - Update the `series` property; see the current README for realtime/range options.
61
- - Shared chart demos use deterministic samples and explicit next/reset controls.
62
- - Engines are disposed on detach and re-created on reconnect. Empty series clear
63
- the plot instead of substituting sample data.
64
- - `yAxisFormatter` controls value-axis and legend labels; bound decimal precision.
65
-
66
- ### dees-chart-log
67
- - Server log viewer component (not a chart despite the name)
68
- - Terminal-style interface with monospace font
69
- - Supports log levels: debug, info, warn, error, success
70
- - Features:
71
- - Auto-scroll toggle
72
- - Clear logs button
73
- - Colored log levels
74
- - Timestamp with milliseconds
75
- - Source labels for log entries
76
- - Maximum 1000 entries (configurable)
77
- - Light/dark theme support
78
- - Demo includes realistic server log simulation
79
- - Note: In demos, buttons use `@clicked` event (not `@click`)
80
- - Demo uses global reference to access log element (window.__demoLogElement)
81
-
82
- ## UI Components
83
-
84
- ### dees-button-group
85
- - Arranges slotted action buttons with an optional label and horizontal/vertical direction.
86
- - Does not own a selected value. Use `dees-input-multitoggle` for segmented view,
87
- mode or filter selection; use App UI tabs for content-panel navigation.
88
-
89
- ## Form Components
90
-
91
- ### dees-input-radio
92
- - Radio button component with proper group behavior
93
- - Properties:
94
- - `name`: Group name for mutually exclusive selection
95
- - `key`: Unique identifier for the radio option
96
- - `value`: Boolean indicating selection state
97
- - `label`: Display label
98
- - Features:
99
- - Automatic group management (radios with same name are mutually exclusive)
100
- - Cannot be deselected by clicking (proper radio behavior)
101
- - Form integration: Radio groups are collected by name, value is the selected radio's key
102
- - Works both inside and outside forms
103
- - Supports disabled state
104
- - Fixed: Radio buttons now properly deselect others in the group on first click
105
- - Note: When using in forms, set both `name` (for grouping) and `key` (for the value)
106
-
107
- ## WYSIWYG Editor Architecture
108
-
109
- ### Recent Refactoring (2025-06-24)
110
-
111
- The WYSIWYG editor has been refactored to improve maintainability and separation of concerns:
112
-
113
- #### New Handler Classes
114
-
115
- 1. **WysiwygBlockOperations** (`wysiwyg.blockoperations.ts`)
116
- - Manages all block-related operations
117
- - Methods: createBlock, insertBlockAfter, removeBlock, findBlock, focusBlock, etc.
118
- - Centralized block manipulation logic
119
-
120
- 2. **WysiwygInputHandler** (`wysiwyg.inputhandler.ts`)
121
- - Handles all input events for blocks
122
- - Manages block content updates based on type
123
- - Detects block type transformations
124
- - Handles slash commands
125
- - Manages auto-save with debouncing
126
-
127
- 3. **WysiwygKeyboardHandler** (`wysiwyg.keyboardhandler.ts`)
128
- - Handles all keyboard events
129
- - Manages formatting shortcuts (Cmd/Ctrl + B/I/U/K)
130
- - Handles special keys: Tab, Enter, Backspace
131
- - Manages slash menu navigation
132
-
133
- 4. **WysiwygDragDropHandler** (`wysiwyg.dragdrophandler.ts`)
134
- - Manages drag and drop operations
135
- - Tracks drag state
136
- - Handles visual feedback during drag
137
- - Manages block reordering
138
-
139
- 5. **WysiwygModalManager** (`wysiwyg.modalmanager.ts`)
140
- - Static methods for showing modals
141
- - Language selection for code blocks
142
- - Block settings modal
143
- - Reusable modal patterns
144
-
145
- #### Main Component Updates
146
-
147
- The main `DeesInputWysiwyg` component now:
148
- - Instantiates handler classes in `connectedCallback`
149
- - Delegates complex operations to appropriate handlers
150
- - Maintains cleaner, more focused code
151
- - Better separation of concerns
152
-
153
- #### Benefits
154
- - Reduced main component size from 1100+ lines
155
- - Each handler class is focused on a single responsibility
156
- - Easier to test individual components
157
- - Better code organization
158
- - Improved maintainability
159
-
160
- #### Fixed Issues
161
- - Enter key no longer duplicates content in new blocks
162
- - Removed problematic `setBlockContents()` method
163
- - Content is now managed directly through DOM properties
164
- - Better timing for block creation and focus
165
- - Slash menu no longer disappears immediately on first "/" press
166
- - Focus is properly maintained when slash menu opens
167
- - Removed duplicate event handling methods from main component
168
- - Simplified focus management throughout the editor
169
-
170
- #### Additional Refactoring (2025-06-24 - Part 2)
171
- - **Removed duplicate code**: handleBlockInput and handleBlockKeyDown methods removed from main component
172
- - **Simplified focus management**: Removed complex lifecycle methods and timers
173
- - **Fixed slash menu behavior**: Changed to click events and proper event prevention
174
- - **dees-wysiwyg-block component**: Now uses static HTML rendering for better content control
175
- - **Improved formatting preservation**: HTML formatting (bold, italic, etc.) properly preserved in all block types
176
-
177
- #### Notes
178
- - All input handling now goes through WysiwygInputHandler
179
- - All keyboard handling goes through WysiwygKeyboardHandler
180
- - The slash menu uses click events instead of mousedown for better UX
181
- - Focus is maintained using requestAnimationFrame for better timing
182
- - The refactoring maintains all existing functionality with improved reliability
183
-
184
- ### Global Menu Architecture (2025-06-24 - Part 3)
185
-
186
- The slash menu and formatting menu have been refactored to render globally instead of inside the wysiwyg component. This fixes focus loss issues that were occurring when the menus were re-rendered with the component.
187
-
188
- #### Key Components:
189
-
190
- 1. **DeesSlashMenu** (`dees-slash-menu.ts`)
191
- - Singleton component that renders globally in the document body
192
- - Accessed via `DeesSlashMenu.getInstance()`
193
- - Manages its own visibility, position, and filtering
194
- - Emits callbacks when items are selected
195
-
196
- 2. **DeesFormattingMenu** (`dees-formatting-menu.ts`)
197
- - Singleton component that renders globally in the document body
198
- - Accessed via `DeesFormattingMenu.getInstance()`
199
- - Shows when text is selected
200
- - Applies formatting commands via callback
201
-
202
- 3. **Integration in DeesInputWysiwyg**
203
- - Stores singleton instances: `private slashMenu = DeesSlashMenu.getInstance()`
204
- - Shows menus with absolute positioning
205
- - Menus handle their own rendering and state management
206
-
207
- #### Benefits:
208
- - No focus loss when menus appear/disappear
209
- - Better performance (menus don't re-render with component)
210
- - Cleaner separation of concerns
211
- - Menus persist across component updates
212
-
213
- #### Usage:
214
- ```typescript
215
- // Show slash menu
216
- this.slashMenu.show(
217
- { x: cursorX, y: cursorY },
218
- (type: string) => this.insertBlock(type)
219
- );
220
-
221
- // Show formatting menu
222
- this.formattingMenu.show(
223
- { x: selectionX, y: selectionY },
224
- (command: string) => this.applyFormat(command)
225
- );
226
- ```
227
-
228
- #### Previous Issues Fixed:
229
- - Slash menu was disappearing immediately on first "/" press
230
- - Focus was lost when menus appeared
231
- - Text selection was not working properly
232
- - Cursor position was lost after menu interactions
233
-
234
- ### Arrow Key Navigation (2025-06-24 - Part 4)
235
-
236
- Enhanced arrow key handling for seamless navigation between blocks:
237
-
238
- #### Features:
239
- 1. **ArrowUp at block start**: Automatically navigates to the end of the previous block
240
- 2. **ArrowDown at block end**: Automatically navigates to the beginning of the next block
241
- 3. **Smart detection**: Checks actual cursor position within the block content
242
- 4. **Slash menu integration**: When slash menu is open, arrow keys navigate menu items instead
243
- 5. **No focus loss**: Navigation maintains focus throughout
244
-
245
- #### Implementation:
246
- - Added `handleArrowUp()` and `handleArrowDown()` methods to `WysiwygKeyboardHandler`
247
- - Smart cursor position detection for different block types (text, lists, etc.)
248
- - Helper method `getLastTextNode()` for finding the last text position in complex HTML
249
- - Prevents default behavior only when navigating between blocks
250
- - Skips divider blocks during navigation
251
-
252
- ### Focus Management Improvements (2025-06-24 - Part 5)
253
-
254
- Enhanced focus management to prevent focus loss during various operations:
255
-
256
- #### Key Improvements:
257
-
258
- 1. **Formatting Without execCommand**:
259
- - Replaced deprecated `document.execCommand` with modern DOM manipulation
260
- - Proper selection restoration after formatting
261
- - Async formatting operations to maintain focus
262
-
263
- 2. **Link Dialog**:
264
- - Replaced `prompt()` with custom modal dialog
265
- - Maintains focus context during async operations
266
- - Auto-focuses input field in modal
267
-
268
- 3. **Robust Focus Methods**:
269
- - Double `requestAnimationFrame` for DOM update timing
270
- - Fallback focus attempts with microtasks
271
- - Contenteditable attribute verification
272
-
273
- 4. **Cursor Positioning**:
274
- - Enhanced `setCursorToStart/End` with edge case handling
275
- - Zero-width space insertion for empty elements
276
- - Recursive node traversal for complex HTML structures
277
-
278
- 5. **Async Keyboard Shortcuts**:
279
- - Formatting shortcuts use Promise resolution
280
- - Prevents focus loss during rapid keyboard input
281
-
282
- #### Implementation Details:
283
- - `focusWithCursor()` method now handles empty blocks and complex HTML
284
- - `applyFormat()` is async and properly restores selection
285
- - Link creation no longer uses blocking `prompt()` dialog
286
- - All focus operations use proper timing with RAF and microtasks
287
-
288
- ### Focus Loss Prevention for Menus (2025-06-24 - Part 6)
289
-
290
- Fixed focus loss issues when slash menu and formatting menu appear:
291
-
292
- #### Key Fixes:
293
-
294
- 1. **Timeout Reduction**:
295
- - Replaced 50ms setTimeout with requestAnimationFrame
296
- - Immediate focus attempt before falling back to RAF
297
- - Reduced delay when inserting blocks
298
-
299
- 2. **Menu Focus Prevention**:
300
- - Added `tabindex="-1"` to prevent menus from taking focus
301
- - Added focus event prevention on menus
302
- - Menus now use mousedown prevention consistently
303
-
304
- 3. **Blur Event Handling**:
305
- - Skip value updates when slash menu is visible
306
- - Prevent auto-save during slash menu interaction
307
- - Maintain focus after menu appears with RAF
308
-
309
- 4. **Block Focus Optimization**:
310
- - Try immediate focus if block element exists
311
- - Fall back to RAF only when necessary
312
- - Consistent focus handling across all block types
313
-
314
- #### Implementation:
315
- - `handleBlockBlur()` checks if slash menu is visible before updating
316
- - `scheduleAutoSave()` skips saving when slash menu is open
317
- - Slash menu show adds RAF to restore focus if lost
318
- - Reduced timing delays throughout the focus chain
319
-
320
- ### Slash Command Cleanup (2025-06-24 - Part 7)
321
-
322
- Fixed the issue where "/" remained in the editor after selecting a block type:
323
-
324
- #### The Fix:
325
-
326
- 1. **In `insertBlock()`**:
327
- - Clear slash command before transforming block type
328
- - Use regex `/^\/[^\s]*\s*/` to match slash + filter text
329
- - Trim the result to ensure clean content
330
- - Set content to empty for transformed blocks
331
-
332
- 2. **Improved Content Handling**:
333
- - Wait for `updateComplete` before focusing
334
- - Ensure lists start with empty content
335
- - Consistent cleanup in both `insertBlock` and `closeSlashMenu`
336
-
337
- 3. **Edge Cases**:
338
- - Handle filtered commands (e.g., "/hea" for heading)
339
- - Clear content even with partial matches
340
- - Proper content reset for all block types
341
-
342
- Now when selecting a block type from the slash menu, the "/" and any filter text is properly removed before the block transformation occurs.
343
-
344
- ### Enhanced Enter Key and Block Settings (2025-06-24 - Part 8)
345
-
346
- Added two major improvements to the wysiwyg editor:
347
-
348
- #### 1. Smart Enter Key Behavior:
349
-
350
- When pressing Enter, content after the cursor is now moved to the next block:
351
-
352
- - **Content Splitting**: Uses Range API to extract content after cursor
353
- - **HTML Preservation**: Maintains formatting when splitting blocks
354
- - **Clean Split**: Current block keeps content before cursor, new block gets content after
355
- - **Empty Block**: If cursor is at end, creates empty new block
356
-
357
- Implementation in `WysiwygKeyboardHandler.handleEnter()`:
358
- ```typescript
359
- // Clone the range to extract content after cursor
360
- const afterRange = range.cloneRange();
361
- afterRange.selectNodeContents(target);
362
- afterRange.setStart(range.endContainer, range.endOffset);
363
-
364
- // Extract content after cursor
365
- const afterContent = afterRange.extractContents();
366
- ```
367
-
368
- #### 2. Block Type Changing via Settings Menu:
369
-
370
- The block settings menu (three dots) now includes block type selection:
371
-
372
- - **Type Selector Grid**: Shows all available block types with icons
373
- - **Smart Metadata Handling**:
374
- - Clears code language when changing from code block
375
- - Clears list type when changing from list
376
- - Prompts for language when changing to code block
377
- - **Visual Feedback**: Currently selected type is highlighted
378
- - **Instant Update**: Block transforms immediately on selection
379
-
380
- Features:
381
- - Works for all block types (not just code blocks)
382
- - Preserves content during type transformation
383
- - Handles special cases like code block language selection
384
- - Modal closes automatically after selection
385
-
386
- ### Complete WYSIWYG Refactoring (2025-06-24 - Part 9)
387
-
388
- Major architectural improvements to fix Enter key behavior and left arrow focus loss:
389
-
390
- #### 1. Async Operation Architecture:
391
- - All focus operations are now async with proper Promise handling
392
- - `insertBlockAfter()` waits for component updates before focusing
393
- - `focusBlock()` ensures DOM is ready with `updateComplete`
394
- - Eliminated arbitrary timeouts in favor of proper async/await
395
-
396
- #### 2. Enter Key Split Content Fix:
397
- - Added `getSplitContent()` method to block component
398
- - Properly extracts content before/after cursor using Range API
399
- - Updates current block and creates new block atomically
400
- - Content after cursor correctly moves to new block
401
-
402
- ```typescript
403
- // In block component
404
- public getSplitContent(): { before: string; after: string } | null {
405
- const beforeRange = range.cloneRange();
406
- beforeRange.selectNodeContents(this.blockElement);
407
- beforeRange.setEnd(range.startContainer, range.startOffset);
408
- // ... extract and return split content
409
- }
410
- ```
411
-
412
- #### 3. Arrow Key Navigation:
413
- - Added ArrowLeft/ArrowRight handlers for block boundaries
414
- - Prevents focus loss when navigating between blocks
415
- - Only intercepts at block boundaries, normal navigation otherwise
416
- - All arrow key operations are async for proper timing
417
-
418
- #### 4. Interface Architecture:
419
- Created `wysiwyg.interfaces.ts` with proper typing:
420
- - `IWysiwygComponent` - Main component contract
421
- - `IBlockOperations` - Block operation methods
422
- - `IWysiwygBlockComponent` - Block component interface
423
- - `IBlockEventHandlers` - Event handler signatures
424
-
425
- #### 5. Focus Management Improvements:
426
- - Eliminated double RAF in favor of single async flow
427
- - Focus operations wait for DOM updates via `updateComplete`
428
- - Proper cursor positioning after all operations
429
- - No more focus loss during navigation
430
-
431
- #### Key Changes:
432
- 1. Keyboard handler methods are now async
433
- 2. Block operations return Promises
434
- 3. Enter key properly splits content at cursor
435
- 4. Arrow keys handle block navigation without focus loss
436
- 5. All timing is handled via proper async/await patterns
437
-
438
- The refactoring eliminates race conditions and timing issues that were causing focus loss and content duplication problems.
439
-
440
- ### Programmatic Rendering Solution (2025-06-24 - Part 10)
441
-
442
- Fixed persistent focus loss issue by implementing fully programmatic rendering:
443
-
444
- #### The Problem:
445
- - User would click in a block, type text, then press arrow keys and lose focus
446
- - Root cause: Lit was re-rendering components when block content was mutated
447
- - Even with shouldUpdate() preventing re-renders, parent re-evaluation caused focus loss
448
-
449
- #### The Solution:
450
-
451
- 1. **Static Parent Rendering**:
452
- - Parent component renders only once with empty editor content div
453
- - All blocks are created and managed programmatically via DOM manipulation
454
- - No Lit re-renders triggered by state changes
455
-
456
- 2. **Manual Block Management**:
457
- - `renderBlocksProgrammatically()` creates all block elements manually
458
- - `createBlockElement()` builds block wrapper with all event handlers
459
- - `updateBlockElement()` replaces individual blocks when needed
460
- - No reactive properties trigger parent re-renders
461
-
462
- 3. **Content Update Strategy**:
463
- - During typing, content is NOT immediately synced to data model
464
- - Auto-save delayed to 2 seconds to avoid interference
465
- - Content synced from DOM only on blur or before save
466
- - `syncAllBlockContent()` reads from DOM when needed
467
-
468
- 4. **Focus Preservation**:
469
- - Block components prevent re-renders with `shouldUpdate()`
470
- - Parent never re-renders after initial load
471
- - Focus remains stable during all editing operations
472
- - Arrow key navigation works without focus loss
473
-
474
- 5. **Implementation Details**:
475
- ```typescript
476
- // Parent render method - static after first render
477
- render(): TemplateResult {
478
- return html`
479
- <div class="editor-content" id="editor-content">
480
- <!-- Blocks rendered programmatically -->
481
- </div>
482
- `;
483
- }
484
-
485
- // All block operations use DOM manipulation
486
- private renderBlocksProgrammatically() {
487
- this.editorContentRef.innerHTML = '';
488
- this.blocks.forEach(block => {
489
- const blockWrapper = this.createBlockElement(block);
490
- this.editorContentRef.appendChild(blockWrapper);
491
- });
492
- }
493
- ```
494
-
495
- This approach completely eliminates focus loss by taking full control of the DOM and preventing any framework-induced re-renders during editing.
496
-
497
- ### Code Refactoring and Cleanup (2025-06-24 - Part 11)
498
-
499
- Completed comprehensive refactoring to ensure clean, maintainable code with separated concerns:
500
-
501
- #### Refactoring Changes:
502
-
503
- 1. **Drag and Drop Handler Cleanup**:
504
- - Removed all `requestUpdate()` calls from drag handler
505
- - Handler now only updates internal state
506
- - Parent component handles DOM updates programmatically
507
- - Simplified drag state management
508
-
509
- 2. **Unused Code Removal**:
510
- - Removed duplicate `showBlockSettingsModal` method (using WysiwygModalManager)
511
- - Removed duplicate `showLanguageSelectionModal` method
512
- - Removed unused `renderBlock` method
513
- - Cleaned up unused imports (WysiwygBlocks, ISlashMenuItem)
514
-
515
- 3. **Import Cleanup**:
516
- - Removed unused type imports
517
- - Organized imports logically
518
- - Kept only necessary dependencies
519
-
520
- 4. **Separated Concerns**:
521
- - Modal management in WysiwygModalManager
522
- - Block operations in WysiwygBlockOperations
523
- - Input handling in WysiwygInputHandler
524
- - Keyboard handling in WysiwygKeyboardHandler
525
- - Drag/drop in WysiwygDragDropHandler
526
- - Each class has a single responsibility
527
-
528
- 5. **Programmatic DOM Management**:
529
- - All DOM updates happen through explicit methods
530
- - No reactive re-renders during user interaction
531
- - Manual class management for drag states
532
- - Direct DOM manipulation for performance
533
-
534
- 6. **Test Files Created**:
535
- - `test-focus-fix.html` - Verifies focus management
536
- - `test-drag-drop.html` - Tests drag and drop functionality
537
- - `test-comprehensive.html` - Tests all features together
538
-
539
- The refactoring follows the principles in instructions.md:
540
- - Uses static templates with manual DOM operations
541
- - Maintains separated concerns in different classes
542
- - Results in clean, concise, and manageable code
543
-
544
- ## Z-Index Management System (2025-12-24)
545
-
546
- A comprehensive z-index management system has been implemented to fix overlay stacking conflicts:
547
-
548
- ### The Problem:
549
- - Modals were hiding dropdown overlays
550
- - Context menus appeared behind modals
551
- - Inconsistent z-index values across components
552
- - No clear hierarchy for overlay stacking
553
-
554
- ### The Solution:
555
-
556
- #### 1. Central Z-Index Constants (`00zindex.ts`):
557
- Created a centralized file defining all z-index layers:
558
-
559
- ```typescript
560
- export const zIndexLayers = {
561
- // Base layer: Regular content
562
- base: {
563
- content: 'auto',
564
- inputElements: 1,
565
- },
566
- // Fixed UI elements
567
- fixed: {
568
- appBar: 10,
569
- sideMenu: 10,
570
- mobileNav: 250,
571
- },
572
- // Overlay backdrops
573
- backdrop: {
574
- dropdown: 1999,
575
- modal: 2999,
576
- contextMenu: 3999,
577
- },
578
- // Interactive overlays
579
- overlay: {
580
- dropdown: 2000, // Dropdowns and select menus
581
- modal: 3000, // Modal dialogs
582
- contextMenu: 4000, // Context menus and tooltips
583
- toast: 5000, // Toast notifications
584
- },
585
- // Special cases
586
- modalDropdown: 3500, // Dropdowns inside modals
587
- wysiwygMenus: 4500, // Editor formatting menus
588
- }
589
- ```
590
-
591
- #### 2. Updated Components:
592
- - **dees-modal**: Changed from 2000 to 3000
593
- - **dees-windowlayer**: Changed from 200-201 to 1999-2000 (used by dropdowns)
594
- - **dees-contextmenu**: Changed from 10000 to 4000
595
- - **dees-toast**: Changed from 10000 to 5000
596
- - **wysiwyg menus**: Changed from 10000 to 4500
597
- - **dees-appui-profiledropdown**: Uses new dropdown z-index (2000)
598
-
599
- #### 3. Stacking Order (bottom to top):
600
- 1. Regular page content (auto)
601
- 2. Fixed navigation elements (10-250)
602
- 3. Dropdown backdrop (1999)
603
- 4. Dropdown content (2000)
604
- 5. Modal backdrop (2999)
605
- 6. Modal content (3000)
606
- 7. Context menu (4000)
607
- 8. WYSIWYG menus (4500)
608
- 9. Toast notifications (5000)
609
-
610
- #### 4. Key Benefits:
611
- - Dropdowns now appear above modals
612
- - Context menus appear above dropdowns and modals
613
- - Toast notifications always appear on top
614
- - Consistent and predictable stacking behavior
615
- - Easy to adjust hierarchy by modifying central constants
616
-
617
- #### 5. Testing:
618
- Created `test-zindex.demo.ts` to verify stacking behavior with:
619
- - Modal containing dropdown
620
- - Context menu on modal
621
- - Toast notifications
622
- - Complex overlay combinations
623
-
624
- ### Usage:
625
- Import and use the z-index constants in any component:
626
- ```typescript
627
- import { zIndexLayers } from './00zindex.js';
628
-
629
- // In styles
630
- z-index: ${zIndexLayers.overlay.modal};
631
- ```
632
-
633
- This system ensures proper stacking order for all overlay components and prevents z-index conflicts.
634
-
635
- ## TC39 Standard Decorators Migration (2025-01-17)
636
-
637
- Successfully migrated from experimental TypeScript decorators to standard TC39 decorators as recommended by Lit 3.x documentation.
638
-
639
- ### Migration Overview:
640
-
641
- #### 1. Changes Made:
642
- - **Added `accessor` keyword** to all `@property` and `@state` decorated fields across 69 component files
643
- - **Updated tsconfig.json**: Removed `experimentalDecorators: true` and `useDefineForClassFields: false`
644
- - **Fixed optional properties**: Changed `accessor prop?: Type` to `accessor prop: Type | undefined = undefined`
645
- - **Removed incompatible decorators**: Removed `@query` and non-reactive `@state` decorators from regular fields
646
-
647
- #### 2. Key Pattern Changes:
648
-
649
- **Before (Experimental Decorators):**
650
- ```typescript
651
- @property({ type: String })
652
- public value: string = '';
653
-
654
- @property({ type: Boolean })
655
- public disabled?: boolean;
656
- ```
657
-
658
- **After (Standard TC39 Decorators):**
659
- ```typescript
660
- @property({ type: String })
661
- accessor value: string = '';
662
-
663
- @property({ type: Boolean })
664
- accessor disabled: boolean | undefined = undefined;
665
- ```
666
-
667
- #### 3. Important Rules:
668
- - **@property and @state**: MUST use `accessor` keyword for reactive properties
669
- - **@query decorators**: Should NOT use `accessor` (they work with regular fields)
670
- - **Optional properties**: Cannot use `?` syntax with accessor, must use `| undefined = undefined`
671
- - **Private fields**: Non-reactive private fields should not use decorators
672
-
673
- #### 4. TypeScript Configuration:
674
- ```json
675
- {
676
- "compilerOptions": {
677
- "target": "ES2022",
678
- "module": "NodeNext",
679
- "moduleResolution": "NodeNext"
680
- }
681
- }
682
- ```
683
- Note: `experimentalDecorators` defaults to false, and `useDefineForClassFields` defaults to true with ES2022 target.
684
-
685
- #### 5. Build Results:
686
- - ✅ Build successful with standard decorators
687
- - ✅ Tests passing (7/8 - same as before migration)
688
- - ✅ No bundle size changes reported
689
- - ✅ All components working correctly
690
-
691
- #### 6. Files Modified:
692
- - 69 component files with decorator updates
693
- - 16 files with optional property fixes
694
- - 3 files with @query decorator removals
695
- - tsconfig.json configuration update
696
-
697
- ### Why This Migration:
698
-
699
- According to Lit's documentation (https://lit.dev/docs/components/decorators/#decorator-versions):
700
- - TC39 standard decorators are the future-proof approach
701
- - Provides better TypeScript integration
702
- - Aligns with JavaScript specification
703
- - While bundle sizes are slightly larger, the standardization benefits outweigh this
704
-
705
- ### Testing:
706
- - All unit tests passing
707
- - Manual testing of key components verified
708
- - No regressions detected
709
- - Focus management and interactions working correctly
710
-
711
- ## Enhanced AppUI API (2025-12-08)
712
-
713
- The `dees-appui` component has been enhanced with a unified configuration API for building real-world applications.
714
-
715
- ### New Modules:
716
-
717
- 1. **ViewRegistry** (`view.registry.ts`)
718
- - Manages view definitions and their lifecycle
719
- - Supports tag names, element classes, and template functions as view content
720
- - Methods: register, get, renderView, findByRoute
721
-
722
- 2. **AppRouter** (`app.router.ts`)
723
- - Built-in routing with hash or history mode
724
- - External router support for framework integration
725
- - Methods: navigate, back, forward, onRouteChange
726
-
727
- 3. **StateManager** (`state.manager.ts`)
728
- - Persists UI state (collapsed menus, selections, current view)
729
- - Supports localStorage, sessionStorage, or memory storage
730
- - Methods: save, load, update, clear
731
-
732
- ### New Interfaces (in `interfaces/appconfig.ts`):
733
-
734
- ```typescript
735
- interface IAppConfig {
736
- branding?: { logoIcon?: string; logoText?: string };
737
- appBar?: IAppBarConfig;
738
- views: IViewDefinition[];
739
- mainMenu?: IMainMenuConfig;
740
- routing?: IRoutingConfig;
741
- statePersistence?: IStatePersistenceConfig;
742
- onViewChange?: (viewId: string, view: IViewDefinition) => void;
743
- }
744
-
745
- interface IViewDefinition {
746
- id: string;
747
- name: string;
748
- iconName?: string;
749
- content: string | (new () => HTMLElement) | (() => TemplateResult);
750
- secondaryMenu?: ISecondaryMenuGroup[];
751
- contentTabs?: ITab[];
752
- route?: string;
753
- }
754
-
755
- interface IRoutingConfig {
756
- mode: 'hash' | 'history' | 'external' | 'none';
757
- basePath?: string;
758
- defaultView?: string;
759
- syncUrl?: boolean;
760
- }
761
- ```
762
-
763
- ### New Public Methods on DeesAppui:
764
-
765
- ```typescript
766
- // Configure with unified config
767
- configure(config: IAppConfig): void
768
-
769
- // Navigation
770
- navigateToView(viewId: string): boolean
771
- getCurrentView(): IViewDefinition | undefined
772
-
773
- // State management
774
- getUIState(): IAppUIState
775
- restoreUIState(state: IAppUIState): void
776
- saveState(): void
777
- loadState(): boolean
778
-
779
- // Access internals
780
- getViewRegistry(): ViewRegistry
781
- getRouter(): AppRouter | null
782
- ```
783
-
784
- ### Usage Example (New Unified Config API):
785
-
786
- ```typescript
787
- import type { IAppConfig } from '@design.estate/dees-catalog';
788
-
789
- const config: IAppConfig = {
790
- branding: { logoIcon: 'lucide:box', logoText: 'My App' },
791
- views: [
792
- { id: 'dashboard', name: 'Dashboard', iconName: 'lucide:home', content: 'my-dashboard' },
793
- { id: 'settings', name: 'Settings', iconName: 'lucide:settings', content: 'my-settings' },
794
- ],
795
- mainMenu: {
796
- sections: [{ views: ['dashboard'] }],
797
- bottomItems: ['settings'],
798
- },
799
- routing: { mode: 'hash', defaultView: 'dashboard' },
800
- statePersistence: { enabled: true, storage: 'localStorage' },
801
- };
802
-
803
- html`<dees-appui .config=${config}></dees-appui>`;
804
- ```
805
-
806
- ### Backward Compatibility:
807
-
808
- The existing property-based API still works:
809
-
810
- ```typescript
811
- html`
812
- <dees-appui
813
- .mainmenuGroups=${groups}
814
- .secondarymenuGroups=${secondaryGroups}
815
- @mainmenu-tab-select=${handler}
816
- >
817
- <div slot="maincontent">...</div>
818
- </dees-appui>
819
- `;
820
- ```
821
-
822
- ### Key Features:
823
-
824
- - **Declarative View Registry**: Map menu items to view components
825
- - **Built-in Routing**: Hash or history mode with URL synchronization
826
- - **External Router Support**: Integrate with Angular Router or other frameworks
827
- - **State Persistence**: Save/restore collapsed menus, selections, and current view
828
- - **View-specific Menus**: Each view can define its own secondary menu and tabs
829
- - **Full Backward Compatibility**: Existing code continues to work
830
-
831
- ## AppUI Bottom Bar (2026-01-03)
832
-
833
- Added a new `dees-appui-bottombar` component similar to `dees-workspace-bottombar`, providing a 24px fixed-height status bar at the bottom of the app shell.
834
-
835
- ### Features:
836
- - **Generic status widgets**: Configurable widgets with icon, label, status colors, loading spinner
837
- - **App-specific actions**: Quick action buttons with icons and tooltips
838
- - **Always visible**: Fixed 24px height at the bottom of the app
839
- - **Status colors**: idle, active (blue), success (green), warning (yellow), error (red)
840
- - **Context menus**: Widgets can have right-click context menus
841
-
842
- ### New Interfaces (in `interfaces/appconfig.ts`):
843
-
844
- ```typescript
845
- interface IBottomBarWidget {
846
- id: string;
847
- iconName?: string;
848
- label?: string;
849
- status?: 'idle' | 'active' | 'success' | 'warning' | 'error';
850
- tooltip?: string;
851
- loading?: boolean;
852
- onClick?: () => void;
853
- contextMenuItems?: IBottomBarContextMenuItem[];
854
- position?: 'left' | 'right';
855
- order?: number;
856
- }
857
-
858
- interface IBottomBarAction {
859
- id: string;
860
- iconName: string;
861
- tooltip?: string;
862
- onClick: () => void | Promise<void>;
863
- disabled?: boolean;
864
- position?: 'left' | 'right';
865
- }
866
-
867
- interface IBottomBarConfig {
868
- visible?: boolean;
869
- widgets?: IBottomBarWidget[];
870
- actions?: IBottomBarAction[];
871
- }
872
- ```
873
-
874
- ### Usage via configure():
875
-
876
- ```typescript
877
- const config: IAppConfig = {
878
- // ... other config
879
- bottomBar: {
880
- visible: true,
881
- widgets: [
882
- {
883
- id: 'status',
884
- iconName: 'lucide:activity',
885
- label: 'System Online',
886
- status: 'success',
887
- tooltip: 'All systems operational',
888
- onClick: () => console.log('Status clicked'),
889
- },
890
- {
891
- id: 'notifications',
892
- iconName: 'lucide:bell',
893
- label: '3 notifications',
894
- status: 'warning',
895
- position: 'left',
896
- },
897
- {
898
- id: 'version',
899
- iconName: 'lucide:gitBranch',
900
- label: 'v1.2.3',
901
- position: 'right',
902
- },
903
- ],
904
- actions: [
905
- {
906
- id: 'terminal',
907
- iconName: 'lucide:terminal',
908
- tooltip: 'Open Terminal',
909
- position: 'right',
910
- onClick: () => console.log('Terminal clicked'),
911
- },
912
- ],
913
- },
914
- };
915
- ```
916
-
917
- ### Programmatic API:
918
-
919
- ```typescript
920
- // Add/update/remove widgets
921
- appui.bottomBar.addWidget({ id: 'status', ... });
922
- appui.bottomBar.updateWidget('status', { status: 'error', label: 'Error!' });
923
- appui.bottomBar.removeWidget('status');
924
- appui.bottomBar.clearWidgets();
925
-
926
- // Add/remove actions
927
- appui.bottomBar.addAction({ id: 'refresh', iconName: 'lucide:refreshCw', ... });
928
- appui.bottomBar.removeAction('refresh');
929
- appui.bottomBar.clearActions();
930
-
931
- // Visibility control
932
- appui.setBottomBarVisible(false);
933
- appui.getBottomBarVisible();
934
- ```
935
-
936
- ### Files:
937
- - `ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.ts` - Main component
938
- - `ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.demo.ts` - Demo
939
- - `ts_web/elements/interfaces/appconfig.ts` - New interfaces added
940
-
941
- ## Media Components (2026-01-26)
942
-
943
- New media viewer components and a unified preview composite component.
944
-
945
- ### Directory: `ts_web/elements/00group-media/`
946
-
947
- #### dees-image-viewer
948
- - Image display with zoom, pan, fit, and download controls
949
- - Properties: `src`, `alt`, `fit` ('contain'|'cover'|'actual'), `showToolbar`
950
- - Features: mouse wheel zoom, click-drag pan, double-click toggle, checkerboard transparency background
951
- - Toolbar matches PDF viewer pattern (48px height, 32px buttons, 16px icons, 6px border-radius)
952
-
953
- #### dees-audio-viewer
954
- - Audio player with waveform visualization via Web Audio API
955
- - Properties: `src`, `title`, `artist`, `showWaveform`, `autoplay`, `loop`
956
- - Features: canvas waveform rendering, play/pause, seek, volume control, mute toggle, loop toggle
957
- - Uses `HTMLAudioElement` for playback, `AudioContext.decodeAudioData` for waveform data
958
-
959
- #### dees-video-viewer
960
- - Video player with custom overlay controls
961
- - Properties: `src`, `poster`, `showControls`, `autoplay`, `loop`, `muted`
962
- - Features: custom controls bar with gradient, seekbar, volume slider, fullscreen toggle, auto-hide controls, 16:9 aspect ratio
963
-
964
- ### dees-preview (Composite Component)
965
- - Auto-detects content type and delegates to the appropriate viewer
966
- - Directory: `ts_web/elements/00group-media/dees-preview/`
967
- - Properties: `url`, `file` (File object), `base64`, `textContent`, `contentType` (override), `language`, `mimeType`, `filename`, `showToolbar`, `showFilename`
968
- - Content type detection priority: explicit override → MIME type → file extension → fallback
969
- - Renders: image→DeesImageViewer, pdf→DeesPdfViewer, code→DeesDataviewCodebox, audio→DeesAudioViewer, video→DeesVideoViewer, text→pre, unknown→placeholder
970
- - Header bar with file type icon, filename, and type badge
971
-
972
- ### dees-dataview-codebox modification
973
- - Removed `<dees-windowcontrols>` elements from the appbar (Step 1 of the plan)
974
- - Now shows clean centered filename title bar without fake window buttons
975
-
976
- ### Icon Sizing Convention
977
- - All `dees-icon` elements in buttons need explicit `font-size: 16px` CSS rule
978
- - Toolbar buttons: 32px × 32px, border-radius: 6px
979
- - Placeholder/error icons: `font-size: 32px`
980
- - Pattern: `.button-class dees-icon { font-size: 16px; }`
981
-
982
- ## Thumbnail Component System (2026-01-27)
983
-
984
- A family of 200×260px content preview cards with a shared abstract base class. All tiles support lazy loading (IntersectionObserver with 200px margin), hover lift effect, click events, loading/error states, and three sizes (small: 150×195, default: 200×260, large: 250×325).
985
-
986
- ### Architecture
987
-
988
- - **DeesThumbnailBase** (`dees-thumbnail-shared/DeesThumbnailBase.ts`) — Abstract base class extending DeesElement
989
- - Common properties: `clickable`, `loading`, `error`, `size`, `label`
990
- - IntersectionObserver lazy loading via `onBecameVisible()` hook
991
- - Click dispatch via `tile-click` CustomEvent (detail from `getTileClickDetail()`)
992
- - Subclasses implement `renderTileContent(): TemplateResult`
993
-
994
- ### Components
995
-
996
- | Tag | Class | Description |
997
- |-----|-------|-------------|
998
- | `dees-thumbnail-pdf` | `DeesThumbnailPdf` | PDF page thumbnail with hover-to-browse pages. Canvas-rendered via PDF.js/CanvasPool. |
999
- | `dees-thumbnail-image` | `DeesThumbnailImage` | Image thumbnail with `object-fit: cover`, dimension detection on load |
1000
- | `dees-thumbnail-audio` | `DeesThumbnailAudio` | Music icon + mini waveform (AudioContext decode), duration badge |
1001
- | `dees-thumbnail-video` | `DeesThumbnailVideo` | Auto-captured first frame, duration badge, hover muted auto-preview |
1002
- | `dees-thumbnail-note` | `DeesThumbnailNote` | First ~12 lines of text in monospace, gradient fade, optional language badge |
1003
- | `dees-thumbnail-folder` | `DeesThumbnailFolder` | 2×2 grid of mini-previews (thumbnails or type icons), item count badge |
1004
-
1005
- ### Removed Legacy Names
1006
-
1007
- - `dees-pdf-preview`, `dees-pdf`, and `dees-tile-pdf` are removed and have no compatibility wrappers.
1008
- - Use `dees-pdf-viewer` for full documents and `dees-thumbnail-pdf` for grid previews.
1009
-
1010
- ### File Structure
1011
-
1012
- All thumbnail components live in `ts_web/elements/00group-media/dees-thumbnail-*/`:
1013
- - `component.ts` — Main component class
1014
- - `demo.ts` — Demo function
1015
- - `index.ts` — Re-export
1016
- - `styles.ts` — (PDF thumbnail only) Component-specific styles
1017
- - Shared base: `dees-thumbnail-shared/{DeesThumbnailBase,styles,index}.ts`
1018
-
1019
- ### Interface: IThumbnailFolderItem
1020
- ```typescript
1021
- interface IThumbnailFolderItem {
1022
- type: 'pdf' | 'image' | 'audio' | 'video' | 'note' | 'folder' | 'unknown';
1023
- thumbnailSrc?: string;
1024
- name: string;
1025
- }
1026
- ```
1027
-
1028
- ## StatsGrid Enhancements (2026-01-12)
1029
-
1030
- ### Column Spanning
1031
-
1032
- Tiles can now span multiple columns using the `columnSpan` property. This is useful for wider visualizations like the CPU cores tile.
1033
-
1034
- ```typescript
1035
- const tile: IStatsTile = {
1036
- id: 'wide-tile',
1037
- title: 'Wide Tile',
1038
- value: 100,
1039
- type: 'cpuCores',
1040
- columnSpan: 2, // Spans 2 columns
1041
- coresData: [...]
1042
- };
1043
- ```
1044
-
1045
- Note: On smaller screens where only 1 column fits, tiles will automatically fall back to single column width.
1046
-
1047
- ### CPU Cores Tile Type
1048
-
1049
- New tile type `cpuCores` for visualizing multi-core CPU usage with vertical bars:
1050
-
1051
- ```typescript
1052
- interface ICpuCore {
1053
- id: string | number;
1054
- usage: number; // 0-100
1055
- label?: string;
1056
- }
1057
-
1058
- const cpuTile: IStatsTile = {
1059
- id: 'cpu-cores',
1060
- title: 'CPU Cores',
1061
- value: 0, // Not used, avg is calculated from coresData
1062
- type: 'cpuCores',
1063
- icon: 'lucide:cpu',
1064
- columnSpan: 2, // Recommended for 8+ cores
1065
- coresData: [
1066
- { id: 0, usage: 45, label: '0' },
1067
- { id: 1, usage: 72, label: '1' },
1068
- // ... more cores
1069
- ],
1070
- description: 'Intel i7 - 8 cores'
1071
- };
1072
- ```
1073
-
1074
- Features:
1075
- - Vertical bars showing individual core usage
1076
- - Color-coded: green (<50%), yellow (50-80%), red (>80%)
1077
- - Shows average usage in header
1078
- - Core labels shown for 16 or fewer cores
1079
- - Tooltips show exact usage per core
1080
- - Responsive: bars flex to fill available width
1081
-
1082
- ### Available Tile Types:
1083
- - `number` - Simple numeric display
1084
- - `gauge` - Semi-circular gauge with thresholds
1085
- - `percentage` - Progress bar (0-100%)
1086
- - `trend` - Sparkline with recent data
1087
- - `text` - Text value display
1088
- - `multiPercentage` - Multiple progress bars
1089
- - `cpuCores` - Vertical bar visualization for CPU cores
1090
-
1091
- ## Component Group Taxonomy (2026-01-27)
1092
-
1093
- All components are organized into `00group-*` directories with 14 groups visible in the wcctools sidebar. The `demoGroups` property (plural, `string[]`) replaces the old `demoGroup` (singular). Components can belong to multiple groups.
1094
-
1095
- ### Group Directories
1096
- | Directory | Group Name | Count |
1097
- |-----------|-----------|-------|
1098
- | `00group-appui` | App UI | 10 |
1099
- | `00group-button` | Button | 3 |
1100
- | `00group-chart` | Chart | 2 |
1101
- | `00group-dataview` | Data View | 4 |
1102
- | `00group-feedback` | Feedback | 6 |
1103
- | `00group-form` | Form | 2 |
1104
- | `00group-input` | Input | 18 |
1105
- | `00group-layout` | Layout | 7 |
1106
- | `00group-media` | Media | 11 (viewers + PDF + thumbnails) |
1107
- | `00group-overlay` | Overlay | 4 |
1108
- | `00group-simple` | Simple | 3 |
1109
- | `00group-utility` | Utility | 5 |
1110
- | `00group-workspace` | Workspace | 9 |
1111
- | `00group-runtime` | (internal) | - |
1112
-
1113
- ### Multi-Group Components
1114
- Some components appear in multiple groups via `demoGroups = ['Primary', 'Secondary']`:
1115
- - `dees-chart-log`: Chart, Workspace
1116
- - `dees-dataview-codebox`: Data View, Workspace
1117
- - `dees-input-code`: Input, Workspace
1118
- - `dees-input-wysiwyg`: Input, Workspace
1119
- - `dees-form-submit`: Form, Button
1120
- - `dees-preview`: Media, Data View
1121
- - `dees-pdf-viewer` / `dees-thumbnail-pdf`: Media, PDF
1122
- - `dees-stepper`: Layout, Form
1123
- - `dees-label`: Layout, Input
1124
- - `dees-toast`: Feedback, Overlay
1125
- - `dees-actionbar`: Feedback, Overlay
1126
-
1127
- ### Import Conventions
1128
- - Within same group: `import '../sibling-component/file.js'`
1129
- - Cross-group (from depth-2): `import '../../00group-X/component/file.js'`
1130
- - Shared utilities: `import '../../00plugins.js'`, `import '../../00theme.js'`, etc.
1131
-
1132
- ### Key Notes
1133
- - The old `demoGroup` property (singular, string) is fully removed
1134
- - All 79 components with demos use `demoGroups` (plural, string[])
1135
- - `00group-pdf` no longer exists; PDF components are in `00group-media`
1136
- - `dees-search` and `dees-tooltip` remain standalone (no demos)
1137
- ## Harness group decisions (2026-07)
1138
-
1139
- - Markdown in `00group-harness` uses `domtools.plugins.smartmarkdown` (GFM, sanitized remark pipeline) — zero new dependencies, same path as dees-speechbubble and dees-workspace-markdown. `HarnessMarkdown` singleton adds an LRU cache (200 entries) and rewrites links to `target="_blank" rel="noopener noreferrer"`. Fenced code gets lazy highlight.js via `DeesServiceLibLoader` after the final (non-streaming) parse only.
1140
- - Tool cards resolve their kind through `DeesHarnessToolRegistry.default` (open set + `kind` override), so consumers register custom tools without forking components; `server__tool` names auto-classify as MCP with annotation badges. Optional descriptor `layout` metadata controls compact, full-row, or subtask-only grid packing and defaults to compact.
1141
- - The syntax palette moved to the shared `ts_web/elements/00syntax.ts` (`syntaxPaletteStyles` + `syntaxScopeStyles`); codebox and harness markdown consume it — don't re-declare `--syntax-*`/hljs scope colors per component.
1142
- - `dees-dataview-codebox` diff mode: set `codeBefore` (against `codeToDisplay`) or a pre-computed `unifiedDiff` patch; `diffView` uses exported `TDiffView = 'inline' | 'split'`. The app-bar toggle emits bubbling/composed `diff-view-change` with `IDiffViewChangeDetail`; split mode has one shared vertical owner with independently scrolling horizontal panes. Use `showDiffLineNumbers=false` for unpositioned snippets. Engine lives dependency-free in `codebox.diff.ts` (LCS + intraline segments + context folding + `toUnifiedDiff`). Tool cards use it for file-write bodies via `diffBlock(before, after, { language, filename, view, unifiedDiff, showLineNumbers })`, preserve numeric patch hunks, hide unknown gutters, and retain the selected view for the current call.
1143
- - Terminal tool cards keep their capped body pinned to live output until the user scrolls up. Pointer leave schedules a five-second repin, pointer enter cancels it, and the inner log surface stays black in both themes.
1144
-
1145
- ## dees-simple-login multi-method rework (2026-07)
1146
-
1147
- - **The catalog owns no WebAuthn protocol.** A passkey ceremony needs server-issued options and server-side verification, so `@simplewebauthn/browser` is deliberately *not* a dependency. Two mutually exclusive plug-in modes: no handler set → the component dispatches `passkey-login` / `passkey-register` / `provider-login` and stops; handler set (`passkeyLoginHandler` etc.) → the component awaits it, owns the busy state, turns a rejection into that method's error, and does **not** dispatch the request event. Suppressing the event in handler mode is what makes a double-started ceremony impossible — two concurrent `navigator.credentials.get()` calls reject each other.
1148
- - **`login` is the one exception**: it is a notification, not a request, and always fires with dees-form's detail verbatim (`{ data: { username, password } }`) because cloudly, dcrouter and gitops depend on it.
1149
- - **Configuration decides availability, `methodOrder` only reorders.** `passkey` (false), `providers` ([]), `password` (true) decide *whether* a method renders; `methodOrder` decides the sequence and appends anything it omits, so an incomplete order can never silently hide a configured method. Default therefore resolves to `['password']`, so the zero-configuration card is the same username/password form with the same API surface. It is **not** pixel-identical to the pre-rework component: three deliberate visual changes ship with it — the submit button is now card-width (the pre-existing `dees-tile dees-form-submit { width: 100% }` never worked because the host is `inline-block`), `.subheader` moved from `--dees-color-text-muted` (0.30 alpha, ~2:1) to `--dees-color-text-secondary`, and `.loginContainer` gained `box-sizing`, `padding` and `overflow-y: auto` so a tall multi-method card scrolls instead of clipping.
1150
- - **Shadow-DOM reach-in is a real contract.** All three consumers do `shadowRoot.querySelector('dees-form')` then `form.setStatus()` / `form.reset()`, and cloudly's `switchToLoginContent()` hand-reverses the inline styles `switchToSlottedContent()` sets. So: `.loginContainer` / `.login` / `.slotContainer` must keep their names and inline-style choreography, the password `dees-form` must stay the first and only form in shadow order, and the `formData` listener is bound declaratively (`@formData`) because the form is now conditionally rendered and a one-shot `firstUpdated` hook-up would silently stop firing.
1151
- - **Do not bind `.text` on the credentials `dees-form-submit`.** `dees-form.setStatus(state, text)` writes that property imperatively, and `dees-form.reset()` ends with `setStatus('normal', 'Submit')`. A Lit property binding would clobber a consumer's status text on the next render, so the label is slotted instead — which also means `labels.passwordSubmit` is read at first render only.
1152
- - The credentials form is wrapped in `dees-tile` **only when password is the sole method**. Once the column holds other methods the column is the card, and a nested tile would inset the fields 24px against full-width buttons and read as a stray box.
1153
- - Additive primitive gaps closed on the way: `dees-button.fullWidth` (`full-width` attribute — the host being `inline-block` meant `width: 100%` never stretched the `inline-flex` face; the opt-in path also adds `min-width: 0` + label ellipsis), the same forwarded on `dees-form-submit`, `dees-input-text.autocomplete` (needed for `username webauthn` conditional mediation), and `--dees-spinner-color` on `dees-spinner` (it hard-coded `--dees-color-text-primary`, painting a near-black arc on an accent button face in bright theme).
1154
- - **Never mark a pending `dees-button` disabled** — `.button.disabled { opacity: 0.5 }` washes out the spinner. Guard re-entry in the handler instead; only *sibling* buttons get `disabled`.
1155
- - Known pre-existing gaps this rework did **not** change: `--dees-color-text-secondary` is 3.44:1 in bright theme (sub-AA for 13px copy); `--dees-color-accent-primary` with white text is 3.65–4.02:1; `dees-tile`'s 16px heading padding vs the 24px content padding this component sets leaves an 8px misalignment; `dees-spinner`'s success/error faces still hard-code `--dees-color-text-primary`.
1156
-
1157
- ## dees-button keyboard operability (2026-07)
1158
-
1159
- `dees-button` renders its face as a `<div class="button">`, so it had no keyboard affordance at all — nothing built on it (including every action in `dees-simple-login`) was reachable by Tab. Fixed in the primitive rather than per consumer.
1160
-
1161
- - The face carries `role="button"`, `tabindex` (`0`, or `-1` when `disabled`), `aria-disabled`, and `aria-busy` while `status === 'pending'`. A pending button stays focusable on purpose — pulling focus mid-ceremony strands the user.
1162
- - **Enter activates on keydown, Space on keyup**, matching native buttons. Space keydown is swallowed so the page cannot scroll under a focused button. Verified with real CDP key events: Space activates without moving a scrollable ancestor's `scrollTop`.
1163
- - **Keyboard activation goes through a real `click()` on the face, not a direct `clicked` dispatch.** `dees-workspace-diff-editor` (5 call sites) and `profilepicture.modal` (2) bind plain `@click` on `dees-button` rather than `@clicked`; only a real click drives both. `pointer-events: none` does not block a programmatic `click()`, so inertness is enforced in `activateFromKeyboard()` — refusing `disabled` *and* any non-`normal` status, because the status faces already set `pointer-events: none` for the mouse.
1164
- - `DeesButton.focus()` / `.blur()` forward to the face; without that, `host.focus()` is a silent no-op.
1165
- - **`dees-form-submit.focus()` is NOT a focus method — it submits.** `dees-form.addBehaviours()` calls `getSubmitButton()?.focus()` to implement "Enter in the last field submits the form". An earlier attempt to make it forward focus properly broke that; it must stay as-is. Keyboard focus reaches the submit through the inner `dees-button` face instead. Pinned by a test.
1166
- - The `:focus-visible` ring uses the **opaque** `--dees-color-accent-primary`, not `--dees-color-focus-ring`. That shared token is a 0.45/0.55 alpha and composites to 1.85:1 (bright) / 2.31:1 (dark) against the surface behind the button — under the 3:1 WCAG 2.2 SC 1.4.11 wants, and a navy hairline on a dark canvas. Raising the alpha on the token itself would fix every other control too and is the wider change.
1167
- ### Focus containment across the login/app crossfade
1168
-
1169
- Both halves of `dees-simple-login` live in the DOM permanently, stacked and cross-faded with `opacity` + `pointer-events`. That was sufficient only while nothing inside them could hold focus. Once `dees-button` faces became focusable, `pointer-events: none` stopped containing anything — it does not remove a tab stop, and keyboard activation deliberately bypasses it — so the hidden half became reachable in both directions: Tab out of the password form into the invisible app shell, or Tab back into the invisible login card after signing in and start a passkey ceremony there.
1170
-
1171
- `inert` is the only thing that removes a hidden-but-rendered subtree from focus and the accessibility tree. It is derived from each container's effective `pointer-events` via a `MutationObserver` on the inline styles, **not** from an internal flag, because consumers reverse the transition by hand: cloudly's `switchToLoginContent()` writes `.login` / `.loginContainer` / `.slotContainer` inline styles directly and knows nothing about `inert`. Keying off a flag it cannot reset would leave its login card permanently inert after a session expiry. Observe only `attributeFilter: ['style']` — `inert` reflects to its own attribute and would otherwise re-trigger the observer.
1172
-
1173
- ### Open follow-ups from this change (separate decisions, deliberately not done here)
1174
-
1175
- - **`--dees-color-focus-ring` is still sub-3:1 for every control other than `dees-button`.** Inputs, dropdowns and the rest still use the shared token at 0.45/0.55 alpha, which composites to 1.85:1 (bright) / 2.31:1 (dark). `dees-button` was fixed locally by switching its ring to the opaque accent, so the catalog is now *inconsistent*: one control has a compliant focus indicator and the others do not. Raising the token's alpha is the wider fix and needs its own review across every control that reads it.
1176
- - **`dees-button-exit` is unaudited and very likely has the same keyboard defect.** It renders a decorative X glyph (`.maincontainer` + two line divs) with no click handler, no `role` and no `tabindex`; consumers wire clicks on the host. It is not a `dees-button` consumer, so the keyboard fix does not reach it.
1177
-
1178
- - Consumer audit: 16 non-demo components use `dees-button`. None wrap it in a `role="menu"/"listbox"/"option"/"tab"` container, none attach keyboard handlers to the button or an ancestor of it (`dees-harness-composer` and `dees-harness-question-card` bind keydown on their own `textarea`/`input`), `dees-modal` has no focus trap, `dees-button-group` only slots, and no component binds both `@click` and `@clicked` on the same button — so no double activation and no nested-role reporting change.
1179
-
1180
-
1181
- ## Shared workspace controls and chart formatting
1182
-
1183
- - `dees-input-multitoggle` owns segmented view/mode selectors. `dees-button-group`
1184
- only arranges actions; radio groups own radio-style form choices. Start with
1185
- the task chooser and exact tag index in `readme.md` before adding custom markup.
1186
- - Run `node scripts/check-component-docs.cjs` to check registered tag coverage,
1187
- source links and section anchors. Use `--write-index` after adding components
1188
- or API sections; update the task chooser and examples manually.
1189
- - Multitoggle `change` means a changed value; `option-activate` also reports
1190
- reselecting the current value. Codebox uses activation to pin an automatic
1191
- Inline/Split layout, while composer keeps its Shift+Tab mode shortcut.
1192
- - Lightweight Charts asks the price formatter to format fractional scale values
1193
- even for integer samples. Bound precision in `yAxisFormatter`; otherwise the
1194
- engine can reserve most of a narrow chart for potential long labels. The
1195
- workspace demo uses rounded thousands, and the default Mbps formatter uses
1196
- at most two decimal places.
1197
- - App UI caches inactive views with `display:none`; scope browser locators to
1198
- the active view. Chart startup can wait until the component enters the viewport.
1199
- After watch rebuilds, verify the new behavior before capturing screenshots.
1200
-
1201
- ## Simple family composition and motion
1202
-
1203
- - The Simple catalog group contains `dees-simple-login`, `dees-simple-appdash`
1204
- and `dees-shopping-productcard`. Their demos use shared theme wrappers and
1205
- actual input/button/table primitives; see the README task chooser first.
1206
- - Login's `.loginContainer`, `.login`, `.slotContainer`, password form keys and
1207
- externally managed submit status are shipped consumer contracts. Keep the
1208
- password-only tile handle even when flattening its visual parts. The brand
1209
- slot is separate from authenticated content. Move focus through public input
1210
- and button `focus()` methods; a dees-button face currently has `role=button`
1211
- on a div, so querying a native `button` silently misses it.
1212
- - `changeSubject` is an RxJS subject, not a DOM event. Quantity controls emit
1213
- `newValue` for user increments/decrements; product cards translate it to
1214
- `quantityChange`. Their checkbox independently emits `selectionChange`.
1215
- - Dashboard notices live in normal flow above the content. The terminal mounts
1216
- in the content wrapper, forwards a consumer-owned runtime, and uses a request
1217
- counter to cancel pending creation during rapid toggles or disconnect.
1218
- - Preserve the subtle sidebar motion: submenu grid reveal, chevron rotation,
1219
- hover fades, and transform/opacity on rail contents. Resizing the main grid
1220
- every animation frame causes unnecessary content reflow. Closed submenus
1221
- become inert immediately; reduced-motion disables the visual transitions.
1222
- - `test.dees-simple-components.chromium.ts` covers navigation, dynamic views,
1223
- notice synchronization, narrow layout, terminal cancellation and independent
1224
- selection/quantity events. Existing login and button tests cover the retained
1225
- authentication and keyboard contracts.
1226
- ## Workspace composition
1227
-
1228
- - `dees-workspace.demo.ts` owns Studio Notes, a real WebContainer project with dependency-free Node scripts. Do not gate the catalog behind package installation or substitute fake terminal output. The workspace shows connection errors in its existing shell.
1229
- - Documents and terminal sessions use `dees-appui-tabs`; use its `appearance="sidebar"` for flat lists and `--dees-tabs-font-size` for compact controls. Preserve item badges for dirty documents and process results. Terminal sessions move beneath the terminal on narrow containers.
1230
- - `dees-input-multitoggle` owns segmented selections across the catalog. Small controls use 28px geometry, a quiet rail, concentric corners, and the shared motion tokens. Keep string/keyed/boolean events, wrapping, and reduced motion intact.
1231
- - File-tree selection reveals ancestors. Resize handles support pointer cancellation and keyboard resizing. Save All marks only successfully written, still-current contents clean; external conflicts do not auto-discard a draft after a timeout.
1232
- - Use `DeesModal.prompt` for name dialogs: Enter, IME, cancellation, validation, and async errors belong there. Never query private modal wrapper classes to recover form values. The former `.modal .content` selector silently prevented file creation after the modal redesign.
1233
- - Terminal labels use the existing manager's rename operation through shared `IMenuItem.onRename`; preserve session IDs, processes, and scrollback. File and terminal selections share `--dees-color-sidebar-selection` with primary text: use a raised neutral fill with a slight tint, not the saturated text-selection blue. The collapsed explorer's plus action reuses file-tree creation and opens the new document.