@design.estate/dees-catalog 9.5.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/dist_bundle/bundle.js +1319 -1452
- package/dist_bundle/bundle.js.map +1 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.js +5 -4
- package/dist_ts_web/elements/00group-input/dees-input-base/dees-input-base.d.ts +1 -8
- package/dist_ts_web/elements/00group-input/dees-input-base/dees-input-base.js +7 -2
- package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.d.ts +21 -2
- package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.demo.d.ts +4 -0
- package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.demo.js +218 -193
- package/dist_ts_web/elements/00group-layout/dees-stepper/dees-stepper.js +288 -403
- package/dist_ts_web/elements/00group-layout/dees-stepper/styles.d.ts +1 -0
- package/dist_ts_web/elements/00group-layout/dees-stepper/styles.js +41 -0
- package/dist_ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.d.ts +1 -1
- package/dist_ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.js +5 -4
- package/package.json +2 -2
- package/readme.md +52 -3
- package/scripts/check-bdtheme-ratchet.cjs +2 -2
- package/scripts/check-packed-consumer.mjs +45 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-dataview/dees-table/dees-table.ts +3 -2
- package/ts_web/elements/00group-input/dees-input-base/dees-input-base.ts +6 -1
- package/ts_web/elements/00group-layout/dees-stepper/dees-stepper.demo.ts +142 -200
- package/ts_web/elements/00group-layout/dees-stepper/dees-stepper.ts +216 -400
- package/ts_web/elements/00group-layout/dees-stepper/styles.ts +41 -0
- package/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.ts +3 -3
- package/readme.hints.md +0 -1233
- package/readme.icons.md +0 -1849
- package/readme.info.md +0 -80
- package/readme.plan.md +0 -671
- package/readme.playbook.md +0 -820
- package/readme.theme-migration.md +0 -168
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.
|