@adia-ai/web-components 0.6.9 → 0.6.10
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
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.6.10] — 2026-05-21
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`<table-toolbar-ui>` — one-shot dev-mode `console.warn` when unknown opt-out attributes are set (claims-ui FB-04 enhancement).** Triggered by claims-ui FB-04 (RESPONSE-04, v0.6.9 §379): consumers writing `<table-toolbar-ui searchable>` (or `exportable` / `sortable` / `filterable` / `columns-visible`) thinking those attributes toggle visibility saw silent no-ops — the canonical attrs are `no-search` / `no-filter` / `no-sort` / `no-columns`. Pre-v0.6.10 behavior: the unknown attrs simply did nothing. Post-fix: a one-shot `console.warn` per element fires from `connected()`, names the unknown attrs, and points consumers at `npx adia-ai-doc table-toolbar` and the yaml SoT for the canonical reference. Pattern: warn-once-per-element via static `WeakSet` (`UITableToolbar._warnedUnknownAttrs`), matching the `tooltip-ui._warnedMissing` discipline. Scope: case-insensitive attrs starting with `search` / `export` / `sort` / `filter` / `column`, minus the 4 canonical opt-outs. Standard HTML/ARIA attrs (`id`, `class`, `role`, `aria-*`, `data-*`) are never flagged. Pinned by 12 new vitest cases in `table-toolbar.test.js`.
|
|
7
|
+
|
|
8
|
+
### Internal
|
|
9
|
+
- **`scripts/release/check-browser-safe.mjs` — strict-by-default + `/bin/` allowlist.** Flipped `STRICT = args.has('--strict')` → `STRICT = !args.has('--loose')` to match the convention shared by the other 6 release gates (`check:absolute-imports`, `check:no-self-import-css`, `check:scope-bare-descendants`, `check:lightningcss-build`, `check:rolldown-glob`, `check:with-css-pairing`). Paired with `/\/bin\//` added to `NODE_ONLY_PATTERNS` — silences the only pre-existing warning (`packages/web-components/bin/doc.mjs`, the `adia-ui-doc` CLI shipped v0.6.7). The CLI's `node:fs` / `node:path` / `node:url` imports are by design (#!/usr/bin/env node shebang); the broad `/bin/` pattern covers any future package-bin CLIs. Tracked at journal §378 as deferred-to-v0.6.10. No consumer-facing API change.
|
|
10
|
+
|
|
3
11
|
## [0.6.9] — 2026-05-21
|
|
4
12
|
|
|
5
13
|
### Fixed
|
|
@@ -138,10 +138,21 @@ export class UITableToolbar extends UIElement {
|
|
|
138
138
|
#docListenerRaf = null;
|
|
139
139
|
#sortIndicatorRafs = new Set();
|
|
140
140
|
|
|
141
|
+
// §381 (v0.6.10, slice F): one-shot dev-mode warning when consumers
|
|
142
|
+
// set common-but-unknown opt-out attributes (e.g. `searchable`,
|
|
143
|
+
// `exportable`, `sortable`) thinking they control table-toolbar
|
|
144
|
+
// visibility. Canonical attrs are `no-search` / `no-filter` /
|
|
145
|
+
// `no-sort` / `no-columns`. WeakSet pinned static so each element
|
|
146
|
+
// warns at most once even across reconnects.
|
|
147
|
+
static _warnedUnknownAttrs = new WeakSet();
|
|
148
|
+
static _CANONICAL_OPT_OUT_ATTRS = new Set(['no-search', 'no-filter', 'no-sort', 'no-columns']);
|
|
149
|
+
static _OPT_OUT_PREFIX_RE = /^(search|export|sort|filter|column)/i;
|
|
150
|
+
|
|
141
151
|
// ── Lifecycle ────────────────────────────────────────────────────────────
|
|
142
152
|
|
|
143
153
|
connected() {
|
|
144
154
|
this.setAttribute('role', 'toolbar');
|
|
155
|
+
this.#warnUnknownOptOutAttrs();
|
|
145
156
|
this.#stamp();
|
|
146
157
|
this.#resolveTarget();
|
|
147
158
|
this.#syncFromTarget();
|
|
@@ -165,6 +176,44 @@ export class UITableToolbar extends UIElement {
|
|
|
165
176
|
this.#updateTitle();
|
|
166
177
|
}
|
|
167
178
|
|
|
179
|
+
// ── Unknown opt-out attribute warning (§381, v0.6.10 slice F) ────────────
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Warn once (per element) when the consumer sets attributes that look
|
|
183
|
+
* like opt-outs but aren't canonical. Triggered by claims-ui FB-04:
|
|
184
|
+
* consumers set `searchable` / `exportable` / `sortable` thinking they
|
|
185
|
+
* toggle visibility; the canonical attrs are `no-search`/`no-filter`/
|
|
186
|
+
* `no-sort`/`no-columns`. Silent no-op was the previous behavior —
|
|
187
|
+
* confusing UX. Pattern: warn-once-per-element via static WeakSet.
|
|
188
|
+
*
|
|
189
|
+
* Scope: attributes whose names start with `search`, `export`, `sort`,
|
|
190
|
+
* `filter`, `column` (case-insensitive). Canonical attrs are
|
|
191
|
+
* subtracted before the warn fires. Standard HTML/ARIA attrs (`id`,
|
|
192
|
+
* `class`, `role`, `aria-*`, `data-*`, etc.) are never flagged.
|
|
193
|
+
*
|
|
194
|
+
* Pinned by table-toolbar.test.js.
|
|
195
|
+
*/
|
|
196
|
+
#warnUnknownOptOutAttrs() {
|
|
197
|
+
if (UITableToolbar._warnedUnknownAttrs.has(this)) return;
|
|
198
|
+
const unknowns = [];
|
|
199
|
+
for (const attr of this.attributes) {
|
|
200
|
+
const name = attr.name.toLowerCase();
|
|
201
|
+
if (UITableToolbar._CANONICAL_OPT_OUT_ATTRS.has(name)) continue;
|
|
202
|
+
if (!UITableToolbar._OPT_OUT_PREFIX_RE.test(name)) continue;
|
|
203
|
+
unknowns.push(name);
|
|
204
|
+
}
|
|
205
|
+
if (unknowns.length === 0) return;
|
|
206
|
+
UITableToolbar._warnedUnknownAttrs.add(this);
|
|
207
|
+
const list = unknowns.map((n) => `"${n}"`).join(', ');
|
|
208
|
+
// eslint-disable-next-line no-console
|
|
209
|
+
console.warn(
|
|
210
|
+
`[table-toolbar-ui] Unknown opt-out attribute(s) ${list}. ` +
|
|
211
|
+
`Canonical opt-out attrs are: no-search, no-filter, no-sort, no-columns. ` +
|
|
212
|
+
`See packages/web-components/components/table-toolbar/table-toolbar.yaml ` +
|
|
213
|
+
`or run \`npx adia-ui-doc table-toolbar\` for the full attribute reference.`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
168
217
|
// ── Target resolution ────────────────────────────────────────────────────
|
|
169
218
|
|
|
170
219
|
#resolveTarget() {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* table-toolbar-ui tests
|
|
3
|
+
*
|
|
4
|
+
* Pinning the §381 (v0.6.10 slice F) one-shot dev-mode warning for
|
|
5
|
+
* unknown opt-out attributes. Triggered by claims-ui FB-04: consumers
|
|
6
|
+
* set `searchable` / `exportable` / `sortable` thinking they toggle
|
|
7
|
+
* visibility; canonical attrs are `no-search`/`no-filter`/`no-sort`/
|
|
8
|
+
* `no-columns`. Previous behavior: silent no-op.
|
|
9
|
+
*
|
|
10
|
+
* Contract:
|
|
11
|
+
* 1. Unknown attrs matching /^(search|export|sort|filter|column)/i
|
|
12
|
+
* → console.warn fires once per element with the attr names listed
|
|
13
|
+
* 2. Canonical attrs (no-search/no-filter/no-sort/no-columns) → no warn
|
|
14
|
+
* 3. Unrelated attrs (id, class, role, aria-*, data-*) → no warn
|
|
15
|
+
* 4. Multiple unknown attrs in one declaration → single warn (one warn
|
|
16
|
+
* per element, all unknown attrs in the message)
|
|
17
|
+
* 5. Repeated reconnects of the same element → still one warn total
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
21
|
+
import '../../core/element.js';
|
|
22
|
+
import './table-toolbar.js';
|
|
23
|
+
|
|
24
|
+
const tick = () => new Promise((r) => queueMicrotask(r));
|
|
25
|
+
|
|
26
|
+
function mount(html) {
|
|
27
|
+
const wrap = document.createElement('div');
|
|
28
|
+
wrap.innerHTML = html;
|
|
29
|
+
document.body.appendChild(wrap);
|
|
30
|
+
return wrap.firstElementChild;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('table-toolbar-ui — unknown opt-out attribute warning (§381 / FB-04)', () => {
|
|
34
|
+
beforeEach(() => { document.body.innerHTML = ''; });
|
|
35
|
+
|
|
36
|
+
it('warns when an unknown `searchable` attribute is set', async () => {
|
|
37
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
38
|
+
mount('<table-toolbar-ui searchable></table-toolbar-ui>');
|
|
39
|
+
await tick();
|
|
40
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
41
|
+
const msg = warn.mock.calls[0][0];
|
|
42
|
+
expect(msg).toContain('[table-toolbar-ui]');
|
|
43
|
+
expect(msg).toContain('"searchable"');
|
|
44
|
+
expect(msg).toContain('no-search');
|
|
45
|
+
warn.mockRestore();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('warns when an unknown `exportable` attribute is set', async () => {
|
|
49
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
50
|
+
mount('<table-toolbar-ui exportable></table-toolbar-ui>');
|
|
51
|
+
await tick();
|
|
52
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
53
|
+
const msg = warn.mock.calls[0][0];
|
|
54
|
+
expect(msg).toContain('"exportable"');
|
|
55
|
+
warn.mockRestore();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('warns when an unknown `sortable` attribute is set', async () => {
|
|
59
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
60
|
+
mount('<table-toolbar-ui sortable></table-toolbar-ui>');
|
|
61
|
+
await tick();
|
|
62
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(warn.mock.calls[0][0]).toContain('"sortable"');
|
|
64
|
+
warn.mockRestore();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('warns when an unknown `filterable` attribute is set', async () => {
|
|
68
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
69
|
+
mount('<table-toolbar-ui filterable></table-toolbar-ui>');
|
|
70
|
+
await tick();
|
|
71
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(warn.mock.calls[0][0]).toContain('"filterable"');
|
|
73
|
+
warn.mockRestore();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('warns when an unknown `columns-visible` attribute is set', async () => {
|
|
77
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
78
|
+
mount('<table-toolbar-ui columns-visible></table-toolbar-ui>');
|
|
79
|
+
await tick();
|
|
80
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(warn.mock.calls[0][0]).toContain('"columns-visible"');
|
|
82
|
+
warn.mockRestore();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('does NOT warn on canonical no-search', async () => {
|
|
86
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
87
|
+
mount('<table-toolbar-ui no-search></table-toolbar-ui>');
|
|
88
|
+
await tick();
|
|
89
|
+
expect(warn).not.toHaveBeenCalled();
|
|
90
|
+
warn.mockRestore();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('does NOT warn on canonical no-filter / no-sort / no-columns', async () => {
|
|
94
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
95
|
+
mount('<table-toolbar-ui no-filter no-sort no-columns></table-toolbar-ui>');
|
|
96
|
+
await tick();
|
|
97
|
+
expect(warn).not.toHaveBeenCalled();
|
|
98
|
+
warn.mockRestore();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('does NOT warn on unrelated attributes (id, class, role, aria-*, data-*)', async () => {
|
|
102
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
103
|
+
mount('<table-toolbar-ui id="x" class="y" role="toolbar" aria-label="z" data-test="ok"></table-toolbar-ui>');
|
|
104
|
+
await tick();
|
|
105
|
+
expect(warn).not.toHaveBeenCalled();
|
|
106
|
+
warn.mockRestore();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('does NOT warn on canonical attrs even when placeholder is also set', async () => {
|
|
110
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
111
|
+
mount('<table-toolbar-ui no-search no-sort placeholder="Find..."></table-toolbar-ui>');
|
|
112
|
+
await tick();
|
|
113
|
+
expect(warn).not.toHaveBeenCalled();
|
|
114
|
+
warn.mockRestore();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('emits a single warn that names all unknown opt-out attrs', async () => {
|
|
118
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
119
|
+
mount('<table-toolbar-ui searchable exportable sortable></table-toolbar-ui>');
|
|
120
|
+
await tick();
|
|
121
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
122
|
+
const msg = warn.mock.calls[0][0];
|
|
123
|
+
expect(msg).toContain('"searchable"');
|
|
124
|
+
expect(msg).toContain('"exportable"');
|
|
125
|
+
expect(msg).toContain('"sortable"');
|
|
126
|
+
warn.mockRestore();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('warns at most once per element across reconnects', async () => {
|
|
130
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
131
|
+
const el = mount('<table-toolbar-ui searchable></table-toolbar-ui>');
|
|
132
|
+
await tick();
|
|
133
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
134
|
+
// Disconnect + reconnect.
|
|
135
|
+
el.remove();
|
|
136
|
+
document.body.appendChild(el);
|
|
137
|
+
await tick();
|
|
138
|
+
expect(warn).toHaveBeenCalledTimes(1); // unchanged
|
|
139
|
+
warn.mockRestore();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('mixes canonical + unknown — names only the unknown in the warning', async () => {
|
|
143
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
144
|
+
mount('<table-toolbar-ui no-search searchable></table-toolbar-ui>');
|
|
145
|
+
await tick();
|
|
146
|
+
expect(warn).toHaveBeenCalledTimes(1);
|
|
147
|
+
const msg = warn.mock.calls[0][0];
|
|
148
|
+
expect(msg).toContain('"searchable"');
|
|
149
|
+
expect(msg).not.toContain('"no-search"');
|
|
150
|
+
warn.mockRestore();
|
|
151
|
+
});
|
|
152
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
4
4
|
"description": "AdiaUI web components \u2014 vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|