@adia-ai/web-components 0.8.31 → 0.8.32
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 +39 -0
- package/components/accordion/accordion.d.ts +2 -2
- package/components/action-list/action-list.class.js +6 -2
- package/components/action-list/action-list.d.ts +1 -1
- package/components/agent-artifact/agent-artifact.d.ts +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.d.ts +2 -2
- package/components/agent-questions/agent-questions.d.ts +1 -1
- package/components/agent-reasoning/agent-reasoning.d.ts +3 -3
- package/components/agent-suggestions/agent-suggestions.d.ts +1 -1
- package/components/agent-trace/agent-trace.d.ts +1 -1
- package/components/alert/alert.d.ts +2 -2
- package/components/anchor-bar/anchor-bar.d.ts +2 -2
- package/components/avatar/avatar.class.js +0 -1
- package/components/avatar/avatar.css +16 -2
- package/components/badge/badge.css +30 -2
- package/components/breadcrumb/breadcrumb.css +15 -3
- package/components/button/button.d.ts +1 -1
- package/components/calendar-grid/calendar-grid.d.ts +2 -2
- package/components/card/card.css +21 -0
- package/components/card/card.yaml +9 -0
- package/components/chart/chart.d.ts +4 -4
- package/components/chart-legend/chart-legend.d.ts +1 -1
- package/components/chat-thread/chat-input.css +1 -1
- package/components/chat-thread/chat-thread.d.ts +2 -2
- package/components/check/check.css +3 -3
- package/components/command/command.d.ts +2 -2
- package/components/context-menu/context-menu.d.ts +3 -3
- package/components/datetime-picker/datetime-picker.d.ts +5 -5
- package/components/demo-toggle/demo-toggle.d.ts +1 -1
- package/components/drawer/drawer.d.ts +2 -2
- package/components/heatmap/heatmap.d.ts +5 -5
- package/components/index.js +1 -0
- package/components/inline-edit/inline-edit.d.ts +4 -4
- package/components/input/input.a2ui.json +4 -1
- package/components/input/input.css +18 -0
- package/components/input/input.yaml +11 -1
- package/components/integration-card/integration-card.d.ts +4 -4
- package/components/link/link.d.ts +1 -1
- package/components/list/list.class.js +22 -7
- package/components/list/list.d.ts +1 -1
- package/components/list-window/list-window.d.ts +5 -5
- package/components/menu/menu.css +2 -2
- package/components/menu/menu.d.ts +1 -1
- package/components/modal/modal.d.ts +1 -1
- package/components/nav/nav.css +8 -0
- package/components/nav/nav.d.ts +1 -1
- package/components/nav-group/nav-group.css +58 -9
- package/components/nav-group/nav-group.d.ts +1 -1
- package/components/nav-item/nav-item.css +7 -4
- package/components/nav-item/nav-item.d.ts +1 -1
- package/components/noodles/noodles.d.ts +3 -3
- package/components/option-card/option-card.css +1 -1
- package/components/pagination/pagination.d.ts +1 -1
- package/components/pane/pane.d.ts +1 -1
- package/components/password-strength/password-strength.d.ts +1 -1
- package/components/radio/radio.a2ui.json +4 -3
- package/components/radio/radio.css +2 -2
- package/components/radio/radio.yaml +7 -14
- package/components/radio-group/radio-group.a2ui.json +118 -0
- package/components/radio-group/radio-group.class.js +75 -0
- package/components/radio-group/radio-group.css +31 -0
- package/components/radio-group/radio-group.d.ts +20 -0
- package/components/radio-group/radio-group.examples.md +37 -0
- package/components/radio-group/radio-group.js +17 -0
- package/components/radio-group/radio-group.yaml +114 -0
- package/components/stat/stat.css +12 -8
- package/components/stat/stat.js +66 -1
- package/components/stat/stat.yaml +3 -0
- package/components/stepper/stepper-item.a2ui.json +5 -0
- package/components/stepper/stepper-item.yaml +11 -0
- package/components/stepper/stepper.a2ui.json +38 -3
- package/components/stepper/stepper.class.js +199 -2
- package/components/stepper/stepper.css +30 -0
- package/components/stepper/stepper.d.ts +28 -1
- package/components/stepper/stepper.yaml +76 -2
- package/components/stream/stream.d.ts +3 -3
- package/components/swatch/swatch.d.ts +1 -1
- package/components/swiper/swiper.d.ts +3 -3
- package/components/table/table.a2ui.json +2 -2
- package/components/table/table.d.ts +7 -7
- package/components/table/table.yaml +9 -1
- package/components/table-toolbar/table-toolbar.d.ts +4 -4
- package/components/tabs/tabs.d.ts +1 -1
- package/components/tag/tag.a2ui.json +1 -1
- package/components/tag/tag.css +78 -13
- package/components/tag/tag.d.ts +12 -8
- package/components/tag/tag.examples.md +4 -4
- package/components/tag/tag.yaml +18 -7
- package/components/tags-input/tags-input.d.ts +4 -4
- package/components/timeline/timeline.d.ts +1 -1
- package/components/toc/toc.d.ts +1 -1
- package/components/toggle-group/toggle-group.d.ts +1 -1
- package/components/toggle-scheme/toggle-scheme.d.ts +1 -1
- package/components/tour/tour.d.ts +4 -4
- package/components/tree/tree.d.ts +1 -1
- package/core/icons-phosphor.js +129 -71
- package/core/provider.js +84 -23
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +89 -87
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/styles/api/sizing-fallback.css +32 -0
- package/styles/api/sizing.css +7 -3
- package/styles/components.css +1 -0
- package/styles/tokens.css +1 -0
package/core/icons-phosphor.js
CHANGED
|
@@ -37,36 +37,48 @@
|
|
|
37
37
|
* });
|
|
38
38
|
*
|
|
39
39
|
* Brace-list globs are statically analyzed; only the named files are
|
|
40
|
-
* emitted as chunks (or inlined when `eager: true`).
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* emitted as chunks (or inlined when `eager: true`). Better yet, in your OWN
|
|
41
|
+
* source you can skip globs entirely and use plain bare-specifier `?raw`
|
|
42
|
+
* imports (see `icons.js`'s JSDoc, loading path 3) — module resolution finds
|
|
43
|
+
* the package under any layout. If you do hand-write a glob, note it resolves
|
|
44
|
+
* by literal path join from YOUR file, not module resolution — see "Why there
|
|
45
|
+
* are three candidate globs" below.
|
|
44
46
|
*
|
|
45
|
-
* ## Why
|
|
47
|
+
* ## Why there are three candidate globs, not one (gh#287 · gh#340 · gh#786)
|
|
46
48
|
*
|
|
47
49
|
* `import.meta.glob` only accepts a small set of static forms (`/`-rooted,
|
|
48
50
|
* `./`, `../`, `**\/`, or a `#`-subpath with a literal `*`), and each resolves
|
|
49
51
|
* via a literal path join, not module resolution (confirmed against Vite 8's
|
|
50
|
-
* `toAbsoluteGlob`, gh#287).
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
52
|
+
* `toAbsoluteGlob`, gh#287). No single literal path exists that reaches
|
|
53
|
+
* `@phosphor-icons/core` under every package manager's `node_modules` layout,
|
|
54
|
+
* so this file probes THREE entry-relative candidates (resolved from this
|
|
55
|
+
* file's own directory, `core/`, one level inside `@adia-ai/web-components` —
|
|
56
|
+
* the published package ships at the same depth) and installs the first that
|
|
57
|
+
* matches anything:
|
|
58
|
+
*
|
|
59
|
+
* 1. `../node_modules/@phosphor-icons/core/…` — pnpm's nested layout.
|
|
60
|
+
* pnpm always populates a package's OWN local `node_modules` with its
|
|
61
|
+
* direct dependencies (a symlink into the store), regardless of what the
|
|
62
|
+
* consumer app hoists. gh#287's original fix; still first preference.
|
|
63
|
+
* 2. `../../../@phosphor-icons/core/…` — npm / yarn-classic hoisting in a
|
|
64
|
+
* consumer install. `core/` sits at
|
|
65
|
+
* `node_modules/@adia-ai/web-components/core/`, so three levels up IS
|
|
66
|
+
* the consumer's (or workspace root's) `node_modules`, where hoisting
|
|
67
|
+
* flattens transitive deps as siblings. This is the layout gh#786's
|
|
68
|
+
* npm-workspace consumer has — candidate 1 is structurally guaranteed
|
|
69
|
+
* to match zero files there.
|
|
70
|
+
* 3. `../../../node_modules/@phosphor-icons/core/…` — THIS repo's own
|
|
71
|
+
* checkout when `node_modules` is npm-shaped (gh#340: `npm ci` /
|
|
72
|
+
* `npm install` re-shape it). `core/` sits at
|
|
73
|
+
* `packages/web-components/core/`, so three levels up is the repo root
|
|
74
|
+
* and the hoisted copy lives in its `node_modules/`.
|
|
75
|
+
*
|
|
76
|
+
* A `/`-rooted glob is NOT among the candidates: it joins to Vite's
|
|
77
|
+
* CONFIGURED PROJECT ROOT, which only reaches `@phosphor-icons/core` when
|
|
78
|
+
* it happens to be hoisted to that exact root — the original gh#287 failure.
|
|
79
|
+
* Globs that match zero files are free: `import.meta.glob` returns `{}`
|
|
80
|
+
* without touching the filesystem at runtime, so the losing candidates cost
|
|
81
|
+
* nothing.
|
|
70
82
|
*
|
|
71
83
|
* ## Vite dep-optimizer pre-bundling (gh#287, second independent failure mode)
|
|
72
84
|
*
|
|
@@ -104,19 +116,50 @@
|
|
|
104
116
|
* to the manifest fetch below
|
|
105
117
|
*/
|
|
106
118
|
|
|
107
|
-
import { installIconLoaders } from './icons.js';
|
|
119
|
+
import { installIconLoaders, iconRegistryUnwired } from './icons.js';
|
|
108
120
|
|
|
109
|
-
let
|
|
121
|
+
let candidates;
|
|
110
122
|
let hasViteGlob = false;
|
|
111
123
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
// Three node_modules layouts, probed in order — see the JSDoc section
|
|
125
|
+
// "Why there are three candidate globs" above. Every glob string and its
|
|
126
|
+
// options object must stay a static literal (Vite's macro constraint), so
|
|
127
|
+
// the 18 calls can't be generated from a loop.
|
|
128
|
+
candidates = [
|
|
129
|
+
{
|
|
130
|
+
layout: 'pnpm-nested `../node_modules/@phosphor-icons/core`',
|
|
131
|
+
weights: {
|
|
132
|
+
regular: import.meta.glob('../node_modules/@phosphor-icons/core/assets/regular/*.svg', { query: '?raw', import: 'default' }),
|
|
133
|
+
thin: import.meta.glob('../node_modules/@phosphor-icons/core/assets/thin/*.svg', { query: '?raw', import: 'default' }),
|
|
134
|
+
light: import.meta.glob('../node_modules/@phosphor-icons/core/assets/light/*.svg', { query: '?raw', import: 'default' }),
|
|
135
|
+
bold: import.meta.glob('../node_modules/@phosphor-icons/core/assets/bold/*.svg', { query: '?raw', import: 'default' }),
|
|
136
|
+
fill: import.meta.glob('../node_modules/@phosphor-icons/core/assets/fill/*.svg', { query: '?raw', import: 'default' }),
|
|
137
|
+
duotone: import.meta.glob('../node_modules/@phosphor-icons/core/assets/duotone/*.svg', { query: '?raw', import: 'default' }),
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
layout: 'npm/yarn-hoisted sibling `../../../@phosphor-icons/core`',
|
|
142
|
+
weights: {
|
|
143
|
+
regular: import.meta.glob('../../../@phosphor-icons/core/assets/regular/*.svg', { query: '?raw', import: 'default' }),
|
|
144
|
+
thin: import.meta.glob('../../../@phosphor-icons/core/assets/thin/*.svg', { query: '?raw', import: 'default' }),
|
|
145
|
+
light: import.meta.glob('../../../@phosphor-icons/core/assets/light/*.svg', { query: '?raw', import: 'default' }),
|
|
146
|
+
bold: import.meta.glob('../../../@phosphor-icons/core/assets/bold/*.svg', { query: '?raw', import: 'default' }),
|
|
147
|
+
fill: import.meta.glob('../../../@phosphor-icons/core/assets/fill/*.svg', { query: '?raw', import: 'default' }),
|
|
148
|
+
duotone: import.meta.glob('../../../@phosphor-icons/core/assets/duotone/*.svg', { query: '?raw', import: 'default' }),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
layout: 'workspace-root `../../../node_modules/@phosphor-icons/core` (npm-shaped monorepo checkout)',
|
|
153
|
+
weights: {
|
|
154
|
+
regular: import.meta.glob('../../../node_modules/@phosphor-icons/core/assets/regular/*.svg', { query: '?raw', import: 'default' }),
|
|
155
|
+
thin: import.meta.glob('../../../node_modules/@phosphor-icons/core/assets/thin/*.svg', { query: '?raw', import: 'default' }),
|
|
156
|
+
light: import.meta.glob('../../../node_modules/@phosphor-icons/core/assets/light/*.svg', { query: '?raw', import: 'default' }),
|
|
157
|
+
bold: import.meta.glob('../../../node_modules/@phosphor-icons/core/assets/bold/*.svg', { query: '?raw', import: 'default' }),
|
|
158
|
+
fill: import.meta.glob('../../../node_modules/@phosphor-icons/core/assets/fill/*.svg', { query: '?raw', import: 'default' }),
|
|
159
|
+
duotone: import.meta.glob('../../../node_modules/@phosphor-icons/core/assets/duotone/*.svg', { query: '?raw', import: 'default' }),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
];
|
|
120
163
|
hasViteGlob = true;
|
|
121
164
|
} catch (err) {
|
|
122
165
|
// FB-08: distinguish "no Vite at all" (expected, ReferenceError) from
|
|
@@ -135,45 +178,60 @@ try {
|
|
|
135
178
|
}
|
|
136
179
|
|
|
137
180
|
if (hasViteGlob) {
|
|
138
|
-
//
|
|
139
|
-
// `{}` when zero files match (it does NOT
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
// producing this same empty-map symptom:
|
|
143
|
-
// 1. A packaging/bundler step re-nested this file at a different depth
|
|
144
|
-
// than it ships at (breaks the `../`-relative glob's one-level-inside
|
|
145
|
-
// assumption — see "Why the glob is entry-relative" above), a Yarn
|
|
146
|
-
// Berry PnP install (virtual/zip filesystem), or @phosphor-icons/core
|
|
147
|
-
// missing entirely.
|
|
148
|
-
// 2. Vite's dev-server `optimizeDeps` pre-bundled this package (see
|
|
149
|
-
// "Vite dep-optimizer pre-bundling" above) — confirmed empirically to
|
|
150
|
-
// transform the glob into a literal empty object, no exception.
|
|
151
|
-
const totalIcons = Object.values(weightModules).reduce(
|
|
181
|
+
// Install the first candidate layout whose globs matched anything.
|
|
182
|
+
// `import.meta.glob` returns `{}` when zero files match (it does NOT
|
|
183
|
+
// throw), so the losing layouts cost nothing.
|
|
184
|
+
const candidateTotal = (c) => Object.values(c.weights).reduce(
|
|
152
185
|
(sum, weight) => sum + Object.keys(weight).length, 0
|
|
153
186
|
);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
)
|
|
187
|
+
const matched = candidates.find(c => candidateTotal(c) > 0);
|
|
188
|
+
if (matched) {
|
|
189
|
+
installIconLoaders(matched.weights);
|
|
190
|
+
} else {
|
|
191
|
+
// Every candidate matched zero files. Two possibilities remain, and
|
|
192
|
+
// only one is a failure:
|
|
193
|
+
// - The consumer registers icons manually (installIconLoaders /
|
|
194
|
+
// registerIcon) and never wanted the auto-install path — gh#786's
|
|
195
|
+
// reporter. Their registration runs later in the same startup, so
|
|
196
|
+
// defer the verdict and stay silent once the registry is wired.
|
|
197
|
+
// - The registry genuinely ends up empty: Vite's dev-server
|
|
198
|
+
// optimizeDeps pre-bundled this package (esbuild rewrites the globs
|
|
199
|
+
// to empty literals, gh#287), @phosphor-icons/core is missing, or
|
|
200
|
+
// the install layout is one this file doesn't probe (e.g. Yarn PnP's
|
|
201
|
+
// virtual filesystem). Zero icons will render — fail loudly, once,
|
|
202
|
+
// naming the fix (gh#340's acceptance).
|
|
203
|
+
// Deliberately NOT calling installIconLoaders with empty maps here:
|
|
204
|
+
// that would mark the registry "ready", suppressing <icon-ui>'s own
|
|
205
|
+
// unwired-registry diagnostic and clobbering nothing-yet for manual
|
|
206
|
+
// consumers.
|
|
207
|
+
setTimeout(() => {
|
|
208
|
+
if (!iconRegistryUnwired()) return; // manual registration landed — working setup, no noise
|
|
209
|
+
console.error(
|
|
210
|
+
`[icons-phosphor] Zero-config icon auto-install failed: no Phosphor ` +
|
|
211
|
+
`SVGs found under any known node_modules layout (probed pnpm-nested ` +
|
|
212
|
+
`\`../node_modules/\`, npm/yarn-hoisted \`../../../\`, and workspace-root ` +
|
|
213
|
+
`\`../../../node_modules/\` — all relative to icons-phosphor.js), and no ` +
|
|
214
|
+
`icons were registered manually. Every <icon-ui> will render blank. ` +
|
|
215
|
+
`Fixes, most likely first:\n` +
|
|
216
|
+
`(1) Vite dev-server pre-bundling emptied the globs — exclude this ` +
|
|
217
|
+
`package from optimizeDeps in vite.config.js:\n` +
|
|
218
|
+
` optimizeDeps: { exclude: ['@adia-ai/web-components', '@adia-ai/web-modules'] }\n` +
|
|
219
|
+
`(2) @phosphor-icons/core is not installed, or your package manager ` +
|
|
220
|
+
`lays out node_modules somewhere this file doesn't probe (Yarn PnP is ` +
|
|
221
|
+
`not supported by the zero-config path).\n` +
|
|
222
|
+
`(3) Register the icons you use manually — this also silences this ` +
|
|
223
|
+
`error permanently:\n` +
|
|
224
|
+
` import { installIconLoaders } from '@adia-ai/web-components/core/icons';\n` +
|
|
225
|
+
` import caretRight from '@phosphor-icons/core/assets/regular/caret-right.svg?raw';\n` +
|
|
226
|
+
` installIconLoaders({\n` +
|
|
227
|
+
` regular: {\n` +
|
|
228
|
+
` '/node_modules/@phosphor-icons/core/assets/regular/caret-right.svg': caretRight,\n` +
|
|
229
|
+
` },\n` +
|
|
230
|
+
` });\n` +
|
|
231
|
+
`See the JSDoc header of icons-phosphor.js for the full recipe (gh#786).`
|
|
232
|
+
);
|
|
233
|
+
}, 0);
|
|
175
234
|
}
|
|
176
|
-
installIconLoaders(weightModules);
|
|
177
235
|
} else {
|
|
178
236
|
// Non-Vite static serving: fetch the build-time manifest in the
|
|
179
237
|
// background. No top-level await — module finishes loading immediately;
|
package/core/provider.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
import { UIElement } from './element.js';
|
|
26
26
|
import { defineIfFree } from './register.js';
|
|
27
27
|
import { BaseController } from './controller.js';
|
|
28
|
+
import { viewTransition } from '../traits/view-transition/view-transition.js';
|
|
28
29
|
|
|
29
30
|
// ═══════════════════════════════════════════════════════════════
|
|
30
31
|
// ADIA PROVIDER (inline — tiny base class)
|
|
@@ -163,6 +164,15 @@ export class RouteController extends BaseController {
|
|
|
163
164
|
// ═══════════════════════════════════════════════════════════════
|
|
164
165
|
|
|
165
166
|
export class UIRouter extends UIProvider {
|
|
167
|
+
// gh#815 slice 1 — every route/content swap this element performs (the
|
|
168
|
+
// fetched-content path in #loadContent AND the content-less data-route-path
|
|
169
|
+
// swap consumers drive directly via setRoutePath()) rides the shared
|
|
170
|
+
// view-transition trait. That installs `this.startTransition(callback)`,
|
|
171
|
+
// which no-ops to a synchronous callback under prefers-reduced-motion or
|
|
172
|
+
// when the API is unsupported — this element never re-implements either
|
|
173
|
+
// fallback itself.
|
|
174
|
+
static traits = [viewTransition];
|
|
175
|
+
|
|
166
176
|
#cache = new Map();
|
|
167
177
|
#ownCtrl = null;
|
|
168
178
|
#lastPath = null;
|
|
@@ -195,7 +205,32 @@ export class UIRouter extends UIProvider {
|
|
|
195
205
|
navigate(path) { this.#ctrl?.commands.navigate(path); }
|
|
196
206
|
replace(path) { this.#ctrl?.commands.replace(path); }
|
|
197
207
|
|
|
208
|
+
// Content-less usage (gh#815 slice 1): no `route.content` to fetch — a
|
|
209
|
+
// consumer's own CSS reveals children via `router-ui[data-route-path="…"]`
|
|
210
|
+
// selectors (embedded-app's tab routers do this) and the caller just wants
|
|
211
|
+
// the path attribute set. Routing that swap through the same trait as
|
|
212
|
+
// #loadContent gives it the identical no-flash guarantee instead of every
|
|
213
|
+
// consumer hand-rolling its own setAttribute + reduced-motion check.
|
|
214
|
+
setRoutePath(path) {
|
|
215
|
+
if (this.getAttribute('data-route-path') === path) return;
|
|
216
|
+
this.startTransition(() => { this.setAttribute('data-route-path', path); });
|
|
217
|
+
}
|
|
218
|
+
|
|
198
219
|
connected() {
|
|
220
|
+
// Sensible default (motion tokens, foundation/motion.css) — a consumer
|
|
221
|
+
// that wants a different feel sets data-view-transition-duration itself;
|
|
222
|
+
// this only fills the gap when they haven't. Set BEFORE super.connected()
|
|
223
|
+
// (a no-op here, but PR #819 review: viewTransition.setup() reads these
|
|
224
|
+
// attributes once at trait-apply time, which happens after connected()
|
|
225
|
+
// returns in full — keeping the defaults first in program order makes
|
|
226
|
+
// that dependency obvious at the call site, not just true by accident
|
|
227
|
+
// of UIElement's connectedCallback ordering).
|
|
228
|
+
if (!this.hasAttribute('data-view-transition-duration')) {
|
|
229
|
+
this.setAttribute('data-view-transition-duration', 'var(--a-duration)');
|
|
230
|
+
}
|
|
231
|
+
if (!this.hasAttribute('data-view-transition-easing')) {
|
|
232
|
+
this.setAttribute('data-view-transition-easing', 'var(--a-easing)');
|
|
233
|
+
}
|
|
199
234
|
super.connected();
|
|
200
235
|
document.addEventListener('click', this.#onClick);
|
|
201
236
|
}
|
|
@@ -251,30 +286,56 @@ export class UIRouter extends UIProvider {
|
|
|
251
286
|
if (nav !== this.#navSeq) return; // superseded while resolving
|
|
252
287
|
}
|
|
253
288
|
|
|
254
|
-
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
289
|
+
// gh#815 slice 1 — the actual pane swap (old content → new) rides the
|
|
290
|
+
// view-transition trait so the browser cross-fades instead of a bare
|
|
291
|
+
// synchronous replace. startTransition() already degrades to running
|
|
292
|
+
// this callback synchronously under prefers-reduced-motion or when the
|
|
293
|
+
// API is unsupported (view-transition.js owns both fallbacks).
|
|
294
|
+
//
|
|
295
|
+
// PR #819 review (CodeRabbit) — on a REAL view transition the browser
|
|
296
|
+
// runs this callback asynchronously (it has to capture the "old"
|
|
297
|
+
// snapshot first, which needs a render pass); startTransition() itself
|
|
298
|
+
// returns before that callback has necessarily run. Two consequences,
|
|
299
|
+
// both closed here:
|
|
300
|
+
// 1. the callback itself must re-check `nav` — a newer navigation can
|
|
301
|
+
// supersede this one during that async gap, same incident class
|
|
302
|
+
// #navSeq exists to prevent (see the class comment above), and
|
|
303
|
+
// without this guard a stale callback could paint old content
|
|
304
|
+
// OVER a newer navigation's already-painted content.
|
|
305
|
+
// 2. everything downstream of the paint (setup-module import,
|
|
306
|
+
// route-loaded emit) must wait for the paint to actually finish —
|
|
307
|
+
// `transition.updateCallbackDone` resolves once the callback's
|
|
308
|
+
// return value settles — or the setup module runs against the
|
|
309
|
+
// PREVIOUS route's DOM instead of the one it was written for.
|
|
310
|
+
const transition = this.startTransition(() => {
|
|
311
|
+
if (nav !== this.#navSeq) return; // superseded — never paint stale content
|
|
312
|
+
this.innerHTML = html;
|
|
313
|
+
// Re-stamp executable <script> tags so consumer demos can wire data via
|
|
314
|
+
// imperative JS APIs (the documented `el.items = […]` / `el.invoice = {…}`
|
|
315
|
+
// pattern used by plan-picker, invoice-detail, list-window et al). HTML
|
|
316
|
+
// assigned via innerHTML does NOT execute embedded <script> elements per
|
|
317
|
+
// the HTML spec; we replicate the canonical standalone-wrapper rehydration
|
|
318
|
+
// pattern by cloning each script + swapping the inert original. `<script
|
|
319
|
+
// type="application/json" …>` blocks are left untouched so the receiving
|
|
320
|
+
// custom element's connectedCallback can absorb them (the documented
|
|
321
|
+
// in-band data pattern; see PlanPicker.#absorbInlinePlansScript et al).
|
|
322
|
+
for (const oldScript of this.querySelectorAll('script')) {
|
|
323
|
+
const type = oldScript.getAttribute('type') || '';
|
|
324
|
+
// Skip data blocks — those are consumed by the runtime, not executed.
|
|
325
|
+
if (type === 'application/json' || type === 'application/ld+json') continue;
|
|
326
|
+
const newScript = document.createElement('script');
|
|
327
|
+
if (type) newScript.type = type;
|
|
328
|
+
if (oldScript.src) newScript.src = oldScript.src;
|
|
329
|
+
else newScript.textContent = oldScript.textContent;
|
|
330
|
+
oldScript.replaceWith(newScript);
|
|
331
|
+
}
|
|
332
|
+
this.scrollTo(0, 0);
|
|
333
|
+
(this.closest('section') || this.parentElement)?.scrollTo(0, 0);
|
|
276
334
|
|
|
277
|
-
|
|
335
|
+
if (route.title) document.title = route.title;
|
|
336
|
+
});
|
|
337
|
+
await transition.updateCallbackDone;
|
|
338
|
+
if (nav !== this.#navSeq) return; // superseded while the DOM update was in flight
|
|
278
339
|
|
|
279
340
|
// Auto-import setup module
|
|
280
341
|
if (route.content?.endsWith('.content.html')) {
|