@adia-ai/web-modules 0.4.8 → 0.4.9
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/CHANGELOG.md +59 -0
- package/editor/editor-sidebar/editor-sidebar.a2ui.json +10 -0
- package/editor/editor-sidebar/editor-sidebar.d.ts +10 -0
- package/editor/editor-sidebar/editor-sidebar.js +13 -6
- package/editor/editor-sidebar/editor-sidebar.yaml +14 -0
- package/editor/index.d.ts +5 -0
- package/editor/index.js +1 -0
- package/editor/utils.d.ts +8 -0
- package/editor/utils.js +47 -0
- package/package.json +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,65 @@ Built from `@adia-ai/web-components` primitives.
|
|
|
11
11
|
|
|
12
12
|
_No pending changes._
|
|
13
13
|
|
|
14
|
+
## [0.4.9] - 2026-05-13
|
|
15
|
+
|
|
16
|
+
### Added — `<editor-sidebar>` `[persist]` attribute (§91c, FEEDBACK-04 #6)
|
|
17
|
+
|
|
18
|
+
Closes FEEDBACK-04 claim #6 discoverability gap. `<editor-sidebar>` has persisted pane width to `localStorage` since the module shipped, keyed by `[name]` (with `[slot]` fallback). The consumer's mental model expected `[persist="dts-layout"]` — that attribute name better describes what the surface does. v0.4.9 adds `[persist]` as the preferred attribute:
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<!-- Preferred (v0.4.9+) -->
|
|
22
|
+
<editor-sidebar slot="leading" collapsible persist="dts-layout">
|
|
23
|
+
<pane-ui resizable>...</pane-ui>
|
|
24
|
+
</editor-sidebar>
|
|
25
|
+
|
|
26
|
+
<!-- Back-compat (v0.4.x) — still works -->
|
|
27
|
+
<editor-sidebar slot="leading" collapsible name="dts-layout">
|
|
28
|
+
<pane-ui resizable>...</pane-ui>
|
|
29
|
+
</editor-sidebar>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Both map to the same `localStorage["adia-editor-sidebar-dts-layout"]` namespace. Precedence is `[persist]` > `[name]` > `[slot]` — if both `[persist]` and `[name]` are set, `[persist]` wins (more descriptive attribute beats the legacy alias). The `sidebar-toggle` event's `detail.name` reflects the chosen key.
|
|
33
|
+
|
|
34
|
+
`[name]` is now documented as deprecated; not scheduled for removal in v0.5.x.
|
|
35
|
+
|
|
36
|
+
**Migration:**
|
|
37
|
+
|
|
38
|
+
```diff
|
|
39
|
+
- <editor-sidebar collapsible name="dts-layout">
|
|
40
|
+
+ <editor-sidebar collapsible persist="dts-layout">
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Added — `isFocusInInput()` utility on `@adia-ai/web-modules/editor` (§90, FEEDBACK-04 P2 #5)
|
|
44
|
+
|
|
45
|
+
`FEEDBACK-04--adia-ui--2026-05-13.md` item #5: consumer building global keyboard shortcuts for an editor app hit the TypeScript ergonomics gap on `document.activeElement.isContentEditable` (the `Element` type doesn't have `isContentEditable`; only `HTMLElement` does). Every consumer reimplements the cast boilerplate.
|
|
46
|
+
|
|
47
|
+
Ships `isFocusInInput()` as a small helper:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { isFocusInInput } from '@adia-ai/web-modules/editor';
|
|
51
|
+
|
|
52
|
+
document.addEventListener('keydown', (e) => {
|
|
53
|
+
if (isFocusInInput()) return; // user is typing — don't fire shortcut
|
|
54
|
+
if (e.key === '/') openCommandPalette();
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Returns `true` when focus is inside `<input>` / `<textarea>` / any `contenteditable` host / or an AdiaUI text-input primitive (`<input-ui>`, `<textarea-ui>`, `<otp-input-ui>`, `<search-ui>`). The AdiaUI tag-name checks catch focus that lands on the host element (not just the inner native input).
|
|
59
|
+
|
|
60
|
+
**Files:**
|
|
61
|
+
- NEW `packages/web-modules/editor/utils.js` — implementation
|
|
62
|
+
- NEW `packages/web-modules/editor/utils.d.ts` — types
|
|
63
|
+
- NEW `packages/web-modules/editor/index.d.ts` — barrel re-export of the editor module types incl. `isFocusInInput`
|
|
64
|
+
- `packages/web-modules/editor/index.js` — re-export
|
|
65
|
+
- `packages/web-modules/package.json` — `./editor` exports gains `types` conditional; new explicit `./editor/utils` entry for direct subpath import
|
|
66
|
+
|
|
67
|
+
Two reachable import paths:
|
|
68
|
+
- `import { isFocusInInput } from '@adia-ai/web-modules/editor';` (via barrel)
|
|
69
|
+
- `import { isFocusInInput } from '@adia-ai/web-modules/editor/utils';` (direct subpath)
|
|
70
|
+
|
|
71
|
+
Both carry types via the new `types` conditionals.
|
|
72
|
+
|
|
14
73
|
## [0.4.8] - 2026-05-12
|
|
15
74
|
|
|
16
75
|
### Added — TypeScript declarations for all web-modules (FEEDBACK-02 #1, v0.4.8)
|
|
@@ -21,6 +21,16 @@
|
|
|
21
21
|
"component": {
|
|
22
22
|
"const": "EditorSidebar"
|
|
23
23
|
},
|
|
24
|
+
"name": {
|
|
25
|
+
"description": "Alias for [persist]; kept for v0.4.x back-compat. Deprecated —\nnew code should use [persist]. If both are set, [persist] wins.\n",
|
|
26
|
+
"type": "string",
|
|
27
|
+
"default": ""
|
|
28
|
+
},
|
|
29
|
+
"persist": {
|
|
30
|
+
"description": "localStorage key suffix. When set, the sidebar persists its pane\nwidth across reloads under `adia-editor-sidebar-{persist}`.\nPreferred over the [name] alias kept for v0.4.x back-compat.\nDefaults to [name] then [slot] if neither set.\n",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"default": ""
|
|
33
|
+
},
|
|
24
34
|
"resizing": {
|
|
25
35
|
"description": "Reflected — set during an active pointer-drag of the pane's\nresize handle. Used to disable transitions and visual treatments\nthat would feel laggy during drag.\n",
|
|
26
36
|
"type": "boolean",
|
|
@@ -38,6 +38,16 @@ export type EditorSidebarSidebarToggleEvent = CustomEvent<EditorSidebarSidebarTo
|
|
|
38
38
|
export class UIEditorSidebar extends UIElement {
|
|
39
39
|
/** Reflected — set when inner <pane-ui> width is at or below 96px snap threshold. */
|
|
40
40
|
collapsed: boolean;
|
|
41
|
+
/** Alias for [persist]; kept for v0.4.x back-compat. Deprecated —
|
|
42
|
+
new code should use [persist]. If both are set, [persist] wins.
|
|
43
|
+
*/
|
|
44
|
+
name: string;
|
|
45
|
+
/** localStorage key suffix. When set, the sidebar persists its pane
|
|
46
|
+
width across reloads under `adia-editor-sidebar-{persist}`.
|
|
47
|
+
Preferred over the [name] alias kept for v0.4.x back-compat.
|
|
48
|
+
Defaults to [name] then [slot] if neither set.
|
|
49
|
+
*/
|
|
50
|
+
persist: string;
|
|
41
51
|
/** Reflected — set during an active pointer-drag of the pane's
|
|
42
52
|
resize handle. Used to disable transitions and visual treatments
|
|
43
53
|
that would feel laggy during drag.
|
|
@@ -25,8 +25,11 @@
|
|
|
25
25
|
* [slot="leading"|"trailing"] — required, drives localStorage
|
|
26
26
|
* namespacing
|
|
27
27
|
* [collapsible] — opts in to programmatic collapse
|
|
28
|
-
* [
|
|
29
|
-
*
|
|
28
|
+
* [persist="<id>"] — optional override for the localStorage
|
|
29
|
+
* key (defaults to slot). Preferred over
|
|
30
|
+
* [name]; if both set, [persist] wins.
|
|
31
|
+
* [name="<id>"] — alias for [persist]; kept for v0.4.x
|
|
32
|
+
* back-compat. Deprecated; prefer [persist].
|
|
30
33
|
*
|
|
31
34
|
* Reflected attributes:
|
|
32
35
|
* [collapsed] — set when inner pane width ≤ SNAP_THRESHOLD
|
|
@@ -69,10 +72,14 @@ class EditorSidebar extends UIElement {
|
|
|
69
72
|
this.#pane = this.querySelector('pane-ui');
|
|
70
73
|
if (!this.#pane) return;
|
|
71
74
|
|
|
72
|
-
// Resolve storage key
|
|
75
|
+
// Resolve storage key. Source of truth is [persist], with [name] as an
|
|
76
|
+
// alias kept for back-compat — both map to the same `${STORAGE_PREFIX}${key}`
|
|
77
|
+
// localStorage namespace. If both are set, [persist] wins (more descriptive
|
|
78
|
+
// attribute should beat the legacy alias). Final fallback is [slot] so an
|
|
79
|
+
// un-named sidebar still namespaces itself per-position.
|
|
73
80
|
const slot = this.getAttribute('slot') || 'leading';
|
|
74
|
-
const
|
|
75
|
-
this.#storageKey = `${STORAGE_PREFIX}${
|
|
81
|
+
const key = this.getAttribute('persist') || this.getAttribute('name') || slot;
|
|
82
|
+
this.#storageKey = `${STORAGE_PREFIX}${key}`;
|
|
76
83
|
|
|
77
84
|
// Restore persisted width
|
|
78
85
|
this.#restoreWidth();
|
|
@@ -169,7 +176,7 @@ class EditorSidebar extends UIElement {
|
|
|
169
176
|
|
|
170
177
|
#emitToggle() {
|
|
171
178
|
const slot = this.getAttribute('slot') || 'leading';
|
|
172
|
-
const name = this.getAttribute('name') || slot;
|
|
179
|
+
const name = this.getAttribute('persist') || this.getAttribute('name') || slot;
|
|
173
180
|
this.dispatchEvent(new CustomEvent('sidebar-toggle', {
|
|
174
181
|
bubbles: true,
|
|
175
182
|
detail: { name, expanded: !this.collapsed },
|
|
@@ -37,6 +37,20 @@ props:
|
|
|
37
37
|
type: boolean
|
|
38
38
|
default: false
|
|
39
39
|
reflect: true
|
|
40
|
+
persist:
|
|
41
|
+
description: |
|
|
42
|
+
localStorage key suffix. When set, the sidebar persists its pane
|
|
43
|
+
width across reloads under `adia-editor-sidebar-{persist}`.
|
|
44
|
+
Preferred over the [name] alias kept for v0.4.x back-compat.
|
|
45
|
+
Defaults to [name] then [slot] if neither set.
|
|
46
|
+
type: string
|
|
47
|
+
default: ""
|
|
48
|
+
name:
|
|
49
|
+
description: |
|
|
50
|
+
Alias for [persist]; kept for v0.4.x back-compat. Deprecated —
|
|
51
|
+
new code should use [persist]. If both are set, [persist] wins.
|
|
52
|
+
type: string
|
|
53
|
+
default: ""
|
|
40
54
|
|
|
41
55
|
events:
|
|
42
56
|
sidebar-toggle:
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { EditorShell } from './editor-shell/editor-shell.js';
|
|
2
|
+
export { EditorToolbar } from './editor-toolbar/editor-toolbar.js';
|
|
3
|
+
export { EditorCanvas } from './editor-canvas/editor-canvas.js';
|
|
4
|
+
export { EditorSidebar } from './editor-sidebar/editor-sidebar.js';
|
|
5
|
+
export { isFocusInInput } from './utils.js';
|
package/editor/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { EditorShell } from './editor-shell/editor-shell.js';
|
|
|
2
2
|
export { EditorToolbar } from './editor-toolbar/editor-toolbar.js';
|
|
3
3
|
export { EditorCanvas } from './editor-canvas/editor-canvas.js';
|
|
4
4
|
export { EditorSidebar } from './editor-sidebar/editor-sidebar.js';
|
|
5
|
+
export { isFocusInInput } from './utils.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when keyboard focus is currently inside a text-input surface
|
|
3
|
+
* (`<input>`, `<textarea>`, any `contenteditable` host, or an AdiaUI
|
|
4
|
+
* `<input-ui>` / `<textarea-ui>` / `<otp-input-ui>` / `<search-ui>`).
|
|
5
|
+
* Use this to guard global keyboard shortcuts so they don't fire while
|
|
6
|
+
* the user is typing.
|
|
7
|
+
*/
|
|
8
|
+
export function isFocusInInput(): boolean;
|
package/editor/utils.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor utilities — small helpers paired with the editor-shell cluster.
|
|
3
|
+
*
|
|
4
|
+
* Kept here (not in `@adia-ai/web-components/core`) because they're
|
|
5
|
+
* editor-cluster-shaped — they're useful when implementing the kind of
|
|
6
|
+
* keyboard model an editor app needs (panel-aware shortcuts that
|
|
7
|
+
* shouldn't fire while the user is typing). Core is for primitive
|
|
8
|
+
* authoring; this is for product-shell wiring.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* True when keyboard focus is currently inside a text-input surface
|
|
13
|
+
* (`<input>`, `<textarea>`, or any `contenteditable` host). Use this
|
|
14
|
+
* to guard global keyboard shortcuts so they don't fire while the user
|
|
15
|
+
* is typing.
|
|
16
|
+
*
|
|
17
|
+
* Works against the standard DOM `document.activeElement` + the
|
|
18
|
+
* `HTMLElement.isContentEditable` property, with the TypeScript cast
|
|
19
|
+
* boilerplate hidden:
|
|
20
|
+
*
|
|
21
|
+
* // Before
|
|
22
|
+
* const active = document.activeElement as HTMLElement | null;
|
|
23
|
+
* if (active?.tagName === 'INPUT' || active?.isContentEditable) return;
|
|
24
|
+
*
|
|
25
|
+
* // After
|
|
26
|
+
* if (isFocusInInput()) return;
|
|
27
|
+
*
|
|
28
|
+
* Also recognizes the AdiaUI text-input primitives (`<input-ui>`,
|
|
29
|
+
* `<textarea-ui>`, `<otp-input-ui>`, `<search-ui>`) — they extend
|
|
30
|
+
* `UIFormElement` and host a focused native `<input>`/`<textarea>` in
|
|
31
|
+
* their light-DOM subtree, but a stricter check on `tagName` would miss
|
|
32
|
+
* focus that lands on the host element directly.
|
|
33
|
+
*
|
|
34
|
+
* @returns {boolean}
|
|
35
|
+
*/
|
|
36
|
+
export function isFocusInInput() {
|
|
37
|
+
const active = /** @type {HTMLElement | null} */ (document.activeElement);
|
|
38
|
+
if (!active) return false;
|
|
39
|
+
const tag = active.tagName;
|
|
40
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA') return true;
|
|
41
|
+
if (active.isContentEditable) return true;
|
|
42
|
+
// AdiaUI text-input primitives — focus may land on the host element
|
|
43
|
+
// when the inner native input isn't yet mounted, or on the inner
|
|
44
|
+
// native input itself (caught above).
|
|
45
|
+
if (tag === 'INPUT-UI' || tag === 'TEXTAREA-UI' || tag === 'OTP-INPUT-UI' || tag === 'SEARCH-UI') return true;
|
|
46
|
+
return false;
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-modules",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"description": "AdiaUI composite custom elements — shell, chat, editor, runtime clusters built from @adia-ai/web-components primitives. Subpath exports per cluster.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -11,7 +11,14 @@
|
|
|
11
11
|
"./chat": "./chat/index.js",
|
|
12
12
|
"./chat/*": "./chat/*/*.js",
|
|
13
13
|
"./chat/*.css": "./chat/*/*.css",
|
|
14
|
-
"./editor":
|
|
14
|
+
"./editor": {
|
|
15
|
+
"types": "./editor/index.d.ts",
|
|
16
|
+
"default": "./editor/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./editor/utils": {
|
|
19
|
+
"types": "./editor/utils.d.ts",
|
|
20
|
+
"default": "./editor/utils.js"
|
|
21
|
+
},
|
|
15
22
|
"./editor/*": "./editor/*/*.js",
|
|
16
23
|
"./editor/*.css": "./editor/*/*.css",
|
|
17
24
|
"./simple": "./simple/index.js",
|