@dsh-plugin/dsh-ui-experience 0.0.1 → 1.0.0-dev.43485427852

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/lib/client.js CHANGED
@@ -1,467 +1,535 @@
1
- "use strict";
2
- (() => {
3
- // src/shared.ts
4
- var REMOTE_SERVICE = "uiExperience";
5
- var BOOT_ATTRIBUTE = "data-dsh-uix-matugen";
6
- var DEFAULT_COLORS_PATH = "~/.local/state/quickshell/user/generated/colors.json";
7
- var DEFAULT_TOKENS_PATH = "~/.local/state/quickshell/user/generated/dsh-tokens.json";
8
-
9
- // src/client.ts
10
- var SOURCE = "@dsh-plugin/dsh-ui-experience";
11
- var POLL_MS = 2e3;
12
- var IDLE_TICKS = 15;
13
- var BORDER_WIDTH = /^(?:0|[0-9]+(?:\.[0-9]+)?(?:px|rem|em))$/;
14
- function uiExperienceRemoteContribution(zod) {
15
- const codec = (name, schema) => ({
16
- mode: "strict",
17
- typeSymbol: `${SOURCE}/shared#${name}`,
18
- create: schema
19
- });
20
- const descriptor = (method, shape, typeName) => ({
21
- id: `${SOURCE}#${REMOTE_SERVICE}/${method}`,
22
- service: REMOTE_SERVICE,
23
- namespace: REMOTE_SERVICE,
24
- method,
25
- invocation: { kind: "direct" },
26
- parameters: [{
27
- name: "args",
28
- wire: "args",
29
- source: "json",
30
- codec: codec(typeName, () => zod.object(shape())),
31
- strictCodec: codec(typeName, () => zod.strictObject(shape()))
32
- }],
33
- result: codec(`${method}Result`, () => zod.object({}))
34
- });
35
- return {
36
- package: SOURCE,
37
- descriptors: [
38
- descriptor("poll", () => ({ known: zod.string().optional() }), "PollArgs"),
39
- descriptor("setActive", () => ({ active: zod.boolean().optional() }), "SetActiveArgs"),
40
- descriptor("setPaths", () => ({ colorsPath: zod.string().optional(), tokensPath: zod.string().optional() }), "SetPathsArgs")
41
- ]
42
- };
43
- }
44
- var DICTS = {
45
- zh: {
46
- "palette.title": "Matugen \u914D\u8272\u8DDF\u968F",
47
- "palette.description": "\u5C06\u7CFB\u7EDF matugen \u751F\u6210\u7684 Material You \u914D\u8272\u53E0\u52A0\u5728\u5F53\u524D\u4E3B\u9898\u4E0A\uFF0C\u914D\u8272\u6587\u4EF6\u91CD\u65B0\u751F\u6210\u540E\u81EA\u52A8\u8DDF\u968F",
48
- "palette.persist-failed": "\u5F00\u5173\u72B6\u6001\u4FDD\u5B58\u5931\u8D25",
49
- "palette.save-failed": "\u8DEF\u5F84\u4FDD\u5B58\u5931\u8D25",
50
- "palette.saved": "\u5DF2\u4FDD\u5B58",
51
- "palette.paths": "\u914D\u8272\u6587\u4EF6\u8DEF\u5F84",
52
- "palette.colors-path": "matugen \u989C\u8272\u6587\u4EF6",
53
- "palette.tokens-path": "DSH \u4EE4\u724C\u6587\u4EF6\uFF08\u5B58\u5728\u65F6\u4F18\u5148\uFF09",
54
- "palette.save": "\u4FDD\u5B58",
55
- "palette.reset": "\u6062\u590D\u9ED8\u8BA4",
56
- "palette.paths-hint": "\u652F\u6301\u4EE5 ~ \u5F00\u5934\u7684\u8DEF\u5F84\uFF0C\u6216\u7EDD\u5BF9\u8DEF\u5F84\u3002\u4EE4\u724C\u6587\u4EF6\u5B58\u5728\u65F6\u4F18\u5148\u4F7F\u7528\uFF0C\u5426\u5219\u8BFB\u53D6\u989C\u8272\u6587\u4EF6\u5E76\u6620\u5C04\u3002"
57
- },
58
- en: {
59
- "palette.title": "Matugen palette sync",
60
- "palette.description": "Overlay the system matugen Material You palette on the current theme; follows the file when matugen regenerates it",
61
- "palette.persist-failed": "Failed to save the switch state",
62
- "palette.save-failed": "Failed to save the paths",
63
- "palette.saved": "Saved",
64
- "palette.paths": "Palette file paths",
65
- "palette.colors-path": "matugen colors file",
66
- "palette.tokens-path": "DSH token file (preferred when present)",
67
- "palette.save": "Save",
68
- "palette.reset": "Restore defaults",
69
- "palette.paths-hint": "Paths may start with ~, or be absolute. The token file wins when it exists; otherwise the colors file is read and mapped."
70
- }
71
- };
72
- var CSS = `
73
- .dsh-uix-row{display:block;padding:16px 0;border-bottom:0.5px solid var(--dsw-alias-border-l2)}
74
- .dsh-uix-head{display:flex;align-items:center;justify-content:space-between;gap:24px}
75
- .dsh-uix-text{min-width:0}
76
- .dsh-uix-title{font-size:14px;line-height:22px}
77
- .dsh-uix-desc{margin-top:4px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
78
- .dsh-uix-error{margin-top:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}
79
- .dsh-uix-notice{margin-top:6px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-success-primary)}
80
- .dsh-uix-disclosure{margin-top:8px;padding:0;border:0;background:none;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;cursor:pointer}
81
- .dsh-uix-disclosure:hover{color:var(--dsw-alias-label-primary)}
82
- .dsh-uix-disclosure:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);outline-offset:2px;border-radius:4px}
83
- .dsh-uix-paths{margin-top:10px;display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:8px;background:var(--dsw-alias-bg-layer-1)}
84
- .dsh-uix-field{display:flex;flex-direction:column;gap:4px}
85
- .dsh-uix-label{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}
86
- .dsh-uix-input{box-sizing:border-box;width:100%;height:32px;padding:0 10px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-input-major);color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family,monospace);font-size:12px;outline:none}
87
- .dsh-uix-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);outline-offset:1px}
88
- .dsh-uix-actions{display:flex;gap:8px}
89
- .dsh-uix-button{height:28px;padding:0 12px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:12px;cursor:pointer}
90
- .dsh-uix-button:hover:enabled{background:var(--dsw-alias-interactive-bg-hover)}
91
- .dsh-uix-button:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);outline-offset:2px}
92
- .dsh-uix-button-primary{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-on-color)}
93
- .dsh-uix-button:disabled{opacity:.5;cursor:default}
94
- .dsh-uix-hint{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
95
- .dsh-uix-switch{box-sizing:border-box;position:relative;flex:0 0 auto;width:36px;height:20px;padding:2px;border:0;border-radius:999px;background:var(--dsw-alias-border-l3);cursor:pointer}
96
- .dsh-uix-switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}
97
- .dsh-uix-switch:disabled{cursor:default;opacity:.5}
98
- .dsh-uix-switch:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);outline-offset:2px}
99
- .dsh-uix-switch-thumb{display:block;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary-foreground);transition:transform .12s ease}
100
- .dsh-uix-switch[aria-checked=false] .dsh-uix-switch-thumb{background:var(--dsw-alias-switch-thumb)}
101
- .dsh-uix-switch[aria-checked=true] .dsh-uix-switch-thumb{transform:translate(16px)}
102
- `;
103
- function registerClient() {
104
- window.__ModuleLoader__.load({
105
- id: SOURCE,
106
- factory(require2) {
107
- const React = require2("react");
108
- const zod = require2("zod");
109
- const h = React.createElement;
110
- function run(registry, ctx, gateway) {
111
- const t = ctx.locale.bind("ui-experience");
112
- ctx.effect(() => ctx.locale.register("ui-experience", DICTS), "ui-experience: dictionaries");
113
- ctx.effect(() => {
114
- const sheet = document.createElement("style");
115
- sheet.textContent = CSS;
116
- document.head.appendChild(sheet);
117
- return () => {
118
- sheet.remove();
119
- };
120
- }, "ui-experience: row styles");
121
- let disposed = false;
122
- let known;
123
- let bootstrapped = false;
124
- let writing = false;
125
- let inflight = false;
126
- let idleTick = 0;
127
- let lastRpcProblem = "";
128
- let lastPaletteProblem = "";
129
- let paintedWidth = "";
130
- let disposeOverride;
131
- let borderSheet;
132
- let view = {
133
- active: false,
134
- borderWidth: "0.5px",
135
- paths: { colors: DEFAULT_COLORS_PATH, tokens: DEFAULT_TOKENS_PATH },
136
- problem: "",
137
- notice: "",
138
- saving: false
139
- };
140
- const listeners = /* @__PURE__ */ new Set();
141
- const publish = (patch) => {
142
- view = { ...view, ...patch };
143
- for (const listener of listeners) listener();
144
- };
145
- const toOverrides = (modes) => {
146
- const out = {};
147
- for (const [token, dark] of Object.entries(modes.dark)) {
148
- const light = modes.light[token] ?? dark;
149
- if (typeof light === "string" && light !== "") out[token] = { light, dark };
150
- }
151
- return out;
152
- };
153
- const clearOverride = () => {
154
- disposeOverride?.();
155
- disposeOverride = void 0;
156
- };
157
- const applyPalette = (modes) => {
158
- if (disposed) return;
159
- clearOverride();
160
- try {
161
- disposeOverride = registry.overrideTokens(SOURCE, toOverrides(modes));
162
- } catch (error) {
163
- const message = `theme override rejected: ${error.message}`;
164
- console.error(`ui-experience: ${message}`);
165
- publish({ problem: message });
166
- }
167
- };
168
- const applyBorder = (width) => {
169
- if (disposed) return;
170
- if (!BORDER_WIDTH.test(width)) {
171
- const message = `borderWidth ${JSON.stringify(width)} is not a CSS length; borders left untouched`;
172
- console.error(`ui-experience: ${message}`);
173
- publish({ problem: message });
174
- return;
175
- }
176
- if (width === paintedWidth) return;
177
- paintedWidth = width;
178
- borderSheet?.remove();
179
- borderSheet = document.createElement("style");
180
- borderSheet.textContent = `body :where(*:not([data-dsh-uix-keep-border])){border-width:${width} !important}`;
181
- document.head.appendChild(borderSheet);
182
- };
183
- const clearBorder = () => {
184
- borderSheet?.remove();
185
- borderSheet = void 0;
186
- paintedWidth = "";
187
- };
188
- const setBootAttribute = (on) => {
189
- if (on) document.documentElement.setAttribute(BOOT_ATTRIBUTE, "");
190
- else document.documentElement.removeAttribute(BOOT_ATTRIBUTE);
191
- };
192
- const teardown = () => {
193
- clearOverride();
194
- clearBorder();
195
- setBootAttribute(false);
196
- };
197
- const unwrap = (raw) => {
198
- const envelope = raw;
199
- if (envelope.ok === false) throw new Error(envelope.error?.message ?? "remote call failed");
200
- return envelope.value;
201
- };
202
- const adopt = (answer) => {
203
- if (answer.paths.colors !== view.paths.colors || answer.paths.tokens !== view.paths.tokens || answer.borderWidth !== view.borderWidth) {
204
- publish({ paths: answer.paths, borderWidth: answer.borderWidth });
205
- }
206
- if (!bootstrapped) {
207
- bootstrapped = true;
208
- setBootAttribute(answer.active);
209
- publish({ active: answer.active });
210
- } else if (!writing && view.active !== answer.active) {
211
- publish({ active: answer.active });
212
- if (answer.active) {
213
- setBootAttribute(true);
214
- if (answer.status === "ok" && answer.tokens !== void 0) applyPalette(answer.tokens);
215
- applyBorder(answer.borderWidth);
216
- } else {
217
- teardown();
218
- }
219
- }
220
- if (answer.status !== "ok") {
221
- if (answer.message !== lastPaletteProblem) {
222
- lastPaletteProblem = answer.message;
223
- console.error(`ui-experience: palette unavailable: ${answer.message}`);
224
- }
225
- publish({ problem: answer.message });
226
- return;
227
- }
228
- if (lastPaletteProblem !== "") {
229
- lastPaletteProblem = "";
230
- publish({ problem: "" });
231
- }
232
- if (answer.changed) {
233
- known = answer.version;
234
- if (view.active && answer.tokens !== void 0) applyPalette(answer.tokens);
235
- }
236
- if (view.active) applyBorder(answer.borderWidth);
237
- };
238
- const poll = async () => {
239
- if (disposed || inflight) return;
240
- if (bootstrapped && !view.active) {
241
- idleTick = (idleTick + 1) % IDLE_TICKS;
242
- if (idleTick !== 0) return;
243
- } else {
244
- idleTick = 0;
245
- }
246
- inflight = true;
247
- let answer;
248
- try {
249
- answer = unwrap(await gateway.poll({ known }));
250
- } catch (error) {
251
- const message = error.message;
252
- if (message !== lastRpcProblem) {
253
- lastRpcProblem = message;
254
- console.error(`ui-experience: poll RPC failed: ${message}`);
255
- }
256
- return;
257
- } finally {
258
- inflight = false;
259
- }
260
- if (disposed) return;
261
- lastRpcProblem = "";
262
- adopt(answer);
263
- };
264
- const setActive = async (next) => {
265
- if (disposed || writing) return;
266
- writing = true;
267
- publish({ saving: true, problem: "", notice: "" });
268
- try {
269
- if (!next) {
270
- await gateway.setActive({ active: false });
271
- if (disposed) return;
272
- publish({ active: false });
273
- teardown();
274
- return;
275
- }
276
- const answer = unwrap(await gateway.poll({}));
277
- if (disposed) return;
278
- if (answer.status !== "ok") {
279
- publish({ problem: answer.message });
280
- return;
281
- }
282
- const tokens = answer.tokens;
283
- if (tokens === void 0) throw new Error("poll returned no tokens for an activation request");
284
- await gateway.setActive({ active: true });
285
- if (disposed) return;
286
- known = answer.version;
287
- bootstrapped = true;
288
- setBootAttribute(true);
289
- publish({ active: true, paths: answer.paths, notice: t("palette.saved") });
290
- applyPalette(tokens);
291
- applyBorder(answer.borderWidth);
292
- } catch (error) {
293
- const message = error.message;
294
- console.error(`ui-experience: failed to save the switch state: ${message}`);
295
- publish({ problem: `${t("palette.persist-failed")}: ${message}` });
296
- } finally {
297
- writing = false;
298
- publish({ saving: false });
299
- }
300
- };
301
- const savePaths = async (colors, tokens) => {
302
- if (disposed || writing) return;
303
- writing = true;
304
- publish({ saving: true, problem: "", notice: "" });
305
- try {
306
- const saved = unwrap(await gateway.setPaths({ colorsPath: colors, tokensPath: tokens }));
307
- if (disposed) return;
308
- const probe = unwrap(await gateway.poll({}));
309
- if (disposed) return;
310
- known = probe.status === "ok" ? probe.version : void 0;
311
- publish({
312
- paths: saved.paths,
313
- notice: probe.status === "ok" ? t("palette.saved") : "",
314
- problem: probe.status === "ok" ? "" : probe.message
315
- });
316
- if (probe.status === "ok" && view.active && probe.tokens !== void 0) applyPalette(probe.tokens);
317
- } catch (error) {
318
- const message = error.message;
319
- console.error(`ui-experience: failed to save the palette paths: ${message}`);
320
- publish({ problem: `${t("palette.save-failed")}: ${message}` });
321
- } finally {
322
- writing = false;
323
- publish({ saving: false });
324
- }
325
- };
326
- function PaletteRow(props) {
327
- const tr = props.t ?? t;
328
- const [state, setState] = React.useState(view);
329
- const [open, setOpen] = React.useState(false);
330
- const [colors, setColors] = React.useState(view.paths.colors);
331
- const [tokens, setTokens] = React.useState(view.paths.tokens);
332
- React.useEffect(() => {
333
- const listener = () => {
334
- setState(view);
335
- };
336
- listeners.add(listener);
337
- return () => {
338
- listeners.delete(listener);
339
- };
340
- }, []);
341
- React.useEffect(() => {
342
- setColors(state.paths.colors);
343
- setTokens(state.paths.tokens);
344
- }, [state.paths]);
345
- const status = state.problem !== "" ? h("div", { className: "dsh-uix-error", role: "alert" }, state.problem) : state.notice !== "" ? h("div", { className: "dsh-uix-notice" }, state.notice) : null;
346
- const field = (label, value, placeholder, set) => h(
347
- "label",
348
- { className: "dsh-uix-field" },
349
- h("span", { className: "dsh-uix-label" }, label),
350
- h("input", {
351
- className: "dsh-uix-input",
352
- type: "text",
353
- value,
354
- placeholder,
355
- spellCheck: false,
356
- onChange: (event) => {
357
- set(event.target.value);
358
- }
359
- })
360
- );
361
- const editor = open ? h(
362
- "div",
363
- { className: "dsh-uix-paths" },
364
- field(tr("palette.colors-path"), colors, DEFAULT_COLORS_PATH, setColors),
365
- field(tr("palette.tokens-path"), tokens, DEFAULT_TOKENS_PATH, setTokens),
366
- h(
367
- "div",
368
- { className: "dsh-uix-actions" },
369
- h("button", {
370
- type: "button",
371
- className: "dsh-uix-button dsh-uix-button-primary",
372
- disabled: state.saving,
373
- onClick: () => {
374
- void savePaths(colors.trim(), tokens.trim());
375
- }
376
- }, tr("palette.save")),
377
- h("button", {
378
- type: "button",
379
- className: "dsh-uix-button",
380
- disabled: state.saving,
381
- onClick: () => {
382
- void savePaths(DEFAULT_COLORS_PATH, DEFAULT_TOKENS_PATH);
383
- }
384
- }, tr("palette.reset"))
385
- ),
386
- h("div", { className: "dsh-uix-hint" }, tr("palette.paths-hint"))
387
- ) : null;
388
- return h(
389
- "div",
390
- { className: "dsh-uix-row" },
391
- h(
392
- "div",
393
- { className: "dsh-uix-head" },
394
- h(
395
- "div",
396
- { className: "dsh-uix-text" },
397
- h("div", { className: "dsh-uix-title" }, tr("palette.title")),
398
- h("div", { className: "dsh-uix-desc" }, tr("palette.description"))
399
- ),
400
- h("button", {
401
- type: "button",
402
- role: "switch",
403
- "aria-checked": state.active,
404
- "aria-label": tr("palette.title"),
405
- disabled: state.saving,
406
- className: "dsh-uix-switch",
407
- onClick: () => {
408
- void setActive(!state.active);
409
- }
410
- }, h("span", { className: "dsh-uix-switch-thumb", "aria-hidden": true }))
411
- ),
412
- status,
413
- h("button", {
414
- type: "button",
415
- className: "dsh-uix-disclosure",
416
- "aria-expanded": open,
417
- onClick: () => {
418
- setOpen(!open);
419
- }
420
- }, `${open ? "\u25BE" : "\u25B8"} ${tr("palette.paths")}`),
421
- editor
422
- );
423
- }
424
- ctx.effect(() => ctx.slots.inject("settings.general.item", () => ctx.slots.register({
425
- name: "settings.general.item",
426
- id: "ui-experience.palette",
427
- order: 10.5,
428
- locale: "ui-experience"
429
- }, PaletteRow)), "ui-experience: settings row");
430
- ctx.effect(() => ctx.timer.interval(() => {
431
- void poll();
432
- }, POLL_MS), "ui-experience: palette polling");
433
- ctx.effect(() => {
434
- return () => {
435
- disposed = true;
436
- teardown();
437
- };
438
- }, "ui-experience: palette override");
439
- void poll();
440
- }
441
- return {
442
- inject: ["slots", "locale", "timer", "theme", "remote"],
443
- async apply(ctx) {
444
- const theme = ctx.get("theme");
445
- if (theme === void 0) {
446
- console.error("ui-experience: ctx.theme is unavailable; the bundle cannot apply palettes");
447
- return;
448
- }
449
- const unmount = await ctx.remote.$mount(uiExperienceRemoteContribution(zod));
450
- ctx.effect(() => () => {
451
- unmount().catch((error) => {
452
- console.error(`ui-experience: remote unmount failed: ${error.message}`);
453
- });
454
- }, "ui-experience: remote namespace");
455
- const gateway = ctx.get(`remote.${REMOTE_SERVICE}`);
456
- if (gateway === void 0) {
457
- console.error("ui-experience: the remote namespace was not installed after mounting the contribution");
458
- return;
459
- }
460
- run(theme, ctx, gateway);
461
- }
462
- };
463
- }
464
- });
465
- }
466
- registerClient();
467
- })();
1
+ "use strict";
2
+ (() => {
3
+ // src/shared.ts
4
+ var REMOTE_SERVICE = "uiExperience";
5
+ var BOOT_ATTRIBUTE = "data-dsh-uix-matugen";
6
+ var DEFAULT_COLORS_PATH = "~/.local/state/quickshell/user/generated/colors.json";
7
+ var DEFAULT_TOKENS_PATH = "~/.local/state/quickshell/user/generated/dsh-tokens.json";
8
+
9
+ // src/styles.ts
10
+ var ROW_CSS = `
11
+ /* Row chrome: AppearanceRow.module.css .group \u2014 16/0 padding, hairline
12
+ separator, column gap 8 (the section column strips the last separator). */
13
+ .dsh-uix-row{display:flex;flex-direction:column;gap:8px;padding:16px 0;border-bottom:0.5px solid var(--dsw-alias-border-l2)}
14
+ .dsh-uix-head{display:flex;align-items:center;justify-content:space-between;gap:24px}
15
+ .dsh-uix-text{display:flex;flex-direction:column;gap:4px;min-width:0}
16
+
17
+ /* Title and description: FontSizeRow.module.css .title / .desc \u2014
18
+ 14/400/22 label-primary and 12/400/18 label-tertiary. */
19
+ .dsh-uix-title{font-size:14px;font-weight:400;line-height:22px;color:var(--dsw-alias-label-primary)}
20
+ .dsh-uix-desc{font-size:12px;font-weight:400;line-height:18px;color:var(--dsw-alias-label-tertiary)}
21
+
22
+ /* Feedback lines: ConfigField.module.css .field p \u2014 12px, no margin. The
23
+ success line reuses the same metrics with the success token. */
24
+ .dsh-uix-problem{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-state-error-primary)}
25
+ .dsh-uix-notice{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-state-success-primary)}
26
+
27
+ /* Disclosure target: sized like the field label it introduces, with the
28
+ shared hover wash and focus ring instead of a colour-only affordance. */
29
+ /* Disclosure: FontSizeRow.module.css .expander \u2014 a 24px icon button whose
30
+ chevron rotates 180deg while expanded, beside the label text. */
31
+ .dsh-uix-disclosure{display:inline-flex;align-items:center;gap:4px;align-self:flex-start;margin-top:4px;padding:0;border:0;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12px;line-height:1.5;cursor:pointer}
32
+ .dsh-uix-disclosure:hover{color:var(--dsw-alias-label-secondary)}
33
+ .dsh-uix-disclosure:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);outline-offset:2px;border-radius:var(--dsw-radius-xs)}
34
+ .dsh-uix-disclosure-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:var(--dsw-radius-xs)}
35
+ .dsh-uix-disclosure:hover .dsh-uix-disclosure-icon{background:var(--dsw-alias-interactive-bg-hover)}
36
+ .dsh-uix-disclosure-icon svg{transition:transform 150ms ease}
37
+ .dsh-uix-disclosure[aria-expanded=true] .dsh-uix-disclosure-icon svg{transform:rotate(180deg)}
38
+
39
+ /* Path fields: ConfigField.module.css .field, .field + .field, .head label,
40
+ and .field input. The input is sized by padding, not a fixed height. */
41
+ .dsh-uix-form{display:flex;flex-direction:column}
42
+ .dsh-uix-field{display:flex;flex-direction:column;gap:6px;padding:12px 0}
43
+ .dsh-uix-field+.dsh-uix-field{border-top:0.5px solid var(--dsw-alias-border-l2)}
44
+ .dsh-uix-label{font-size:13px;font-weight:500;line-height:1.5;color:var(--dsw-alias-label-primary)}
45
+ /* Input primitive: Input.module.css .wrap / .input / placeholder \u2014 the
46
+ wrapper owns the 32px box and the border, the inner input is transparent.
47
+ The same page's font-family fields render through this primitive. */
48
+ .dsh-uix-input-wrap{display:inline-flex;align-items:center;gap:6px;box-sizing:border-box;width:100%;height:32px;padding:0 8px;border:0.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1)}
49
+ .dsh-uix-input-wrap:focus-within{border-color:var(--dsw-alias-state-business-primary)}
50
+ .dsh-uix-input{flex:1;min-width:0;border:none;outline:none;background:transparent;font:inherit;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary)}
51
+ .dsh-uix-input::placeholder{color:var(--dsw-alias-label-dimmed)}
52
+ .dsh-uix-hint{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}
53
+
54
+ /* Form footer and its save action: the configuration form's footer and save
55
+ button (13px, 5/14 padding, radius md, inverted fill). */
56
+ .dsh-uix-footer{display:flex;align-items:center;gap:8px;padding-top:16px}
57
+ .dsh-uix-save{appearance:none;border:1px solid transparent;border-radius:var(--dsw-radius-md);padding:5px 14px;font:inherit;font-size:13px;line-height:1.5;cursor:pointer;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
58
+ .dsh-uix-save:disabled{cursor:not-allowed;opacity:.4}
59
+
60
+ /* Secondary action: primitives Button.module.css .outline \u2014 inset hairline
61
+ that keeps its width independent of the border, plus the shared wash. */
62
+ .dsh-uix-reset{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;border:0.5px solid transparent;border-radius:var(--dsw-radius-md);padding:5px 14px;font:inherit;font-size:13px;line-height:1.5;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary);box-shadow:inset 0 0 0 var(--dsh-hairline-width,0.5px) var(--dsh-button-outline-color,var(--dsw-alias-border-l3))}
63
+ .dsh-uix-reset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
64
+ .dsh-uix-reset:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}
65
+ .dsh-uix-reset:disabled{cursor:not-allowed;opacity:.4}
66
+ .dsh-uix-save:focus-visible,.dsh-uix-reset:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-alias-state-business-primary);outline-offset:2px}
67
+
68
+ /* Switch: Switch.module.css \u2014 36x20 track, 2px inset, 16px thumb, keyed off
69
+ aria-checked so the visual state cannot disagree with assistive technology.
70
+ corner-shape opts the capsule and the thumb out of the superellipse. */
71
+ .dsh-uix-switch{box-sizing:border-box;position:relative;flex:0 0 auto;width:36px;height:20px;padding:2px;border:0;border-radius:999px;corner-shape:round;background:var(--dsw-alias-border-l3);cursor:pointer}
72
+ .dsh-uix-switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}
73
+ .dsh-uix-switch:disabled{cursor:default;opacity:.5}
74
+ .dsh-uix-switch:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
75
+ .dsh-uix-switch-thumb{display:block;width:16px;height:16px;border-radius:50%;corner-shape:round;background:var(--dsw-alias-label-primary-foreground);transition:transform 120ms ease}
76
+ .dsh-uix-switch[aria-checked=false] .dsh-uix-switch-thumb{background:var(--dsw-alias-switch-thumb)}
77
+ .dsh-uix-switch[aria-checked=true] .dsh-uix-switch-thumb{transform:translate(16px)}
78
+ `;
79
+
80
+ // src/client.ts
81
+ var SOURCE = "@dsh-plugin/dsh-ui-experience";
82
+ var POLL_MS = 2e3;
83
+ var IDLE_TICKS = 15;
84
+ var BORDER_WIDTH = /^(?:0|[0-9]+(?:\.[0-9]+)?(?:px|rem|em))$/;
85
+ function uiExperienceRemoteContribution(zod) {
86
+ const codec = (name, schema) => ({
87
+ mode: "strict",
88
+ typeSymbol: `${SOURCE}/shared#${name}`,
89
+ create: schema
90
+ });
91
+ const descriptor = (method, shape, typeName) => ({
92
+ id: `${SOURCE}#${REMOTE_SERVICE}/${method}`,
93
+ service: REMOTE_SERVICE,
94
+ namespace: REMOTE_SERVICE,
95
+ method,
96
+ invocation: { kind: "direct" },
97
+ parameters: [{
98
+ name: "args",
99
+ wire: "args",
100
+ source: "json",
101
+ codec: codec(typeName, () => zod.object(shape())),
102
+ strictCodec: codec(typeName, () => zod.strictObject(shape()))
103
+ }],
104
+ result: codec(`${method}Result`, () => zod.object({}))
105
+ });
106
+ return {
107
+ package: SOURCE,
108
+ descriptors: [
109
+ descriptor("poll", () => ({ known: zod.string().optional() }), "PollArgs"),
110
+ descriptor("setActive", () => ({ active: zod.boolean().optional() }), "SetActiveArgs"),
111
+ descriptor("setPaths", () => ({ colorsPath: zod.string().optional(), tokensPath: zod.string().optional() }), "SetPathsArgs")
112
+ ]
113
+ };
114
+ }
115
+ var DICTS = {
116
+ zh: {
117
+ "palette.title": "Matugen \u914D\u8272\u8DDF\u968F",
118
+ "palette.description": "\u5C06\u7CFB\u7EDF matugen \u751F\u6210\u7684 Material You \u914D\u8272\u53E0\u52A0\u5728\u5F53\u524D\u4E3B\u9898\u4E0A\uFF0C\u914D\u8272\u6587\u4EF6\u91CD\u65B0\u751F\u6210\u540E\u81EA\u52A8\u8DDF\u968F",
119
+ "palette.persist-failed": "\u5F00\u5173\u72B6\u6001\u4FDD\u5B58\u5931\u8D25",
120
+ "palette.save-failed": "\u8DEF\u5F84\u4FDD\u5B58\u5931\u8D25",
121
+ "palette.saved": "\u5DF2\u4FDD\u5B58",
122
+ "palette.paths": "\u914D\u8272\u6587\u4EF6\u8DEF\u5F84",
123
+ "palette.colors-path": "matugen \u989C\u8272\u6587\u4EF6",
124
+ "palette.tokens-path": "DSH \u4EE4\u724C\u6587\u4EF6\uFF08\u5B58\u5728\u65F6\u4F18\u5148\uFF09",
125
+ "palette.save": "\u4FDD\u5B58",
126
+ "palette.reset": "\u6062\u590D\u9ED8\u8BA4",
127
+ "palette.paths-hint": "\u652F\u6301\u4EE5 ~ \u5F00\u5934\u7684\u8DEF\u5F84\uFF0C\u6216\u7EDD\u5BF9\u8DEF\u5F84\u3002\u989C\u8272\u6587\u4EF6\u63D0\u4F9B\u5B8C\u6574\u6620\u5C04\uFF0C\u4EE4\u724C\u6587\u4EF6\u91CC\u5217\u51FA\u7684 token \u9010\u9879\u8986\u76D6\u3002"
128
+ },
129
+ en: {
130
+ "palette.title": "Matugen palette sync",
131
+ "palette.description": "Overlay the system matugen Material You palette on the current theme; follows the file when matugen regenerates it",
132
+ "palette.persist-failed": "Failed to save the switch state",
133
+ "palette.save-failed": "Failed to save the paths",
134
+ "palette.saved": "Saved",
135
+ "palette.paths": "Palette file paths",
136
+ "palette.colors-path": "matugen colors file",
137
+ "palette.tokens-path": "DSH token file (preferred when present)",
138
+ "palette.save": "Save",
139
+ "palette.reset": "Restore defaults",
140
+ "palette.paths-hint": "Paths may start with ~, or be absolute. The colors file supplies the full mapping; tokens listed in the token file override it item by item."
141
+ }
142
+ };
143
+ function registerClient() {
144
+ window.__ModuleLoader__.load({
145
+ id: SOURCE,
146
+ factory(require2) {
147
+ const React = require2("react");
148
+ const zod = require2("zod");
149
+ const h = React.createElement;
150
+ function run(registry, ctx, gateway) {
151
+ const t = ctx.locale.bind("ui-experience");
152
+ ctx.effect(() => ctx.locale.register("ui-experience", DICTS), "ui-experience: dictionaries");
153
+ ctx.effect(() => {
154
+ const sheet = document.createElement("style");
155
+ sheet.textContent = ROW_CSS;
156
+ document.head.appendChild(sheet);
157
+ return () => {
158
+ sheet.remove();
159
+ };
160
+ }, "ui-experience: row styles");
161
+ let disposed = false;
162
+ let known;
163
+ let bootstrapped = false;
164
+ let writing = false;
165
+ let inflight = false;
166
+ let idleTick = 0;
167
+ let lastRpcProblem = "";
168
+ let lastPaletteProblem = "";
169
+ let paintedWidth = "";
170
+ let disposeOverride;
171
+ let borderSheet;
172
+ let view = {
173
+ active: false,
174
+ borderWidth: "0.5px",
175
+ paths: { colors: DEFAULT_COLORS_PATH, tokens: DEFAULT_TOKENS_PATH },
176
+ problem: "",
177
+ notice: "",
178
+ saving: false
179
+ };
180
+ const listeners = /* @__PURE__ */ new Set();
181
+ const publish = (patch) => {
182
+ view = { ...view, ...patch };
183
+ for (const listener of listeners) listener();
184
+ };
185
+ const toOverrides = (modes) => {
186
+ const out = {};
187
+ for (const [token, dark] of Object.entries(modes.dark)) {
188
+ const light = modes.light[token] ?? dark;
189
+ if (typeof light === "string" && light !== "") out[token] = { light, dark };
190
+ }
191
+ return out;
192
+ };
193
+ const clearOverride = () => {
194
+ disposeOverride?.();
195
+ disposeOverride = void 0;
196
+ };
197
+ const applyPalette = (modes) => {
198
+ if (disposed) return;
199
+ clearOverride();
200
+ try {
201
+ disposeOverride = registry.overrideTokens(SOURCE, toOverrides(modes));
202
+ } catch (error) {
203
+ const message = `theme override rejected: ${error.message}`;
204
+ console.error(`ui-experience: ${message}`);
205
+ publish({ problem: message });
206
+ }
207
+ };
208
+ const applyBorder = (width) => {
209
+ if (disposed) return;
210
+ if (!BORDER_WIDTH.test(width)) {
211
+ const message = `borderWidth ${JSON.stringify(width)} is not a CSS length; borders left untouched`;
212
+ console.error(`ui-experience: ${message}`);
213
+ publish({ problem: message });
214
+ return;
215
+ }
216
+ if (width === paintedWidth) return;
217
+ paintedWidth = width;
218
+ borderSheet?.remove();
219
+ borderSheet = document.createElement("style");
220
+ borderSheet.textContent = `body :where(*:not([data-dsh-uix-keep-border])){border-width:${width} !important}`;
221
+ document.head.appendChild(borderSheet);
222
+ };
223
+ const clearBorder = () => {
224
+ borderSheet?.remove();
225
+ borderSheet = void 0;
226
+ paintedWidth = "";
227
+ };
228
+ const setBootAttribute = (on) => {
229
+ if (on) document.documentElement.setAttribute(BOOT_ATTRIBUTE, "");
230
+ else document.documentElement.removeAttribute(BOOT_ATTRIBUTE);
231
+ };
232
+ const teardown = () => {
233
+ clearOverride();
234
+ clearBorder();
235
+ setBootAttribute(false);
236
+ };
237
+ const unwrap = (raw) => {
238
+ const envelope = raw;
239
+ if (envelope.ok === false) throw new Error(envelope.error?.message ?? "remote call failed");
240
+ return envelope.value;
241
+ };
242
+ const adopt = (answer) => {
243
+ if (answer.paths.colors !== view.paths.colors || answer.paths.tokens !== view.paths.tokens || answer.borderWidth !== view.borderWidth) {
244
+ publish({ paths: answer.paths, borderWidth: answer.borderWidth });
245
+ }
246
+ if (!bootstrapped) {
247
+ bootstrapped = true;
248
+ setBootAttribute(answer.active);
249
+ publish({ active: answer.active });
250
+ } else if (!writing && view.active !== answer.active) {
251
+ publish({ active: answer.active });
252
+ if (answer.active) {
253
+ setBootAttribute(true);
254
+ if (answer.status === "ok" && answer.tokens !== void 0) applyPalette(answer.tokens);
255
+ applyBorder(answer.borderWidth);
256
+ } else {
257
+ teardown();
258
+ }
259
+ }
260
+ if (answer.status !== "ok") {
261
+ if (answer.message !== lastPaletteProblem) {
262
+ lastPaletteProblem = answer.message;
263
+ console.error(`ui-experience: palette unavailable: ${answer.message}`);
264
+ }
265
+ publish({ problem: answer.message });
266
+ return;
267
+ }
268
+ if (lastPaletteProblem !== "") {
269
+ lastPaletteProblem = "";
270
+ publish({ problem: "" });
271
+ }
272
+ if (answer.changed) {
273
+ known = answer.version;
274
+ if (view.active && answer.tokens !== void 0) applyPalette(answer.tokens);
275
+ }
276
+ if (view.active) applyBorder(answer.borderWidth);
277
+ };
278
+ const poll = async () => {
279
+ if (disposed || inflight) return;
280
+ if (bootstrapped && !view.active) {
281
+ idleTick = (idleTick + 1) % IDLE_TICKS;
282
+ if (idleTick !== 0) return;
283
+ } else {
284
+ idleTick = 0;
285
+ }
286
+ inflight = true;
287
+ let answer;
288
+ try {
289
+ answer = unwrap(await gateway.poll({ known }));
290
+ } catch (error) {
291
+ const message = error.message;
292
+ if (message !== lastRpcProblem) {
293
+ lastRpcProblem = message;
294
+ console.error(`ui-experience: poll RPC failed: ${message}`);
295
+ }
296
+ return;
297
+ } finally {
298
+ inflight = false;
299
+ }
300
+ if (disposed) return;
301
+ lastRpcProblem = "";
302
+ adopt(answer);
303
+ };
304
+ const setActive = async (next) => {
305
+ if (disposed || writing) return;
306
+ writing = true;
307
+ publish({ saving: true, problem: "", notice: "" });
308
+ try {
309
+ if (!next) {
310
+ await gateway.setActive({ active: false });
311
+ if (disposed) return;
312
+ publish({ active: false });
313
+ teardown();
314
+ return;
315
+ }
316
+ const answer = unwrap(await gateway.poll({}));
317
+ if (disposed) return;
318
+ if (answer.status !== "ok") {
319
+ publish({ problem: answer.message });
320
+ return;
321
+ }
322
+ const tokens = answer.tokens;
323
+ if (tokens === void 0) throw new Error("poll returned no tokens for an activation request");
324
+ await gateway.setActive({ active: true });
325
+ if (disposed) return;
326
+ known = answer.version;
327
+ bootstrapped = true;
328
+ setBootAttribute(true);
329
+ publish({ active: true, paths: answer.paths, notice: t("palette.saved") });
330
+ applyPalette(tokens);
331
+ applyBorder(answer.borderWidth);
332
+ } catch (error) {
333
+ const message = error.message;
334
+ console.error(`ui-experience: failed to save the switch state: ${message}`);
335
+ publish({ problem: `${t("palette.persist-failed")}: ${message}` });
336
+ } finally {
337
+ writing = false;
338
+ publish({ saving: false });
339
+ }
340
+ };
341
+ const savePaths = async (colors, tokens) => {
342
+ if (disposed || writing) return;
343
+ writing = true;
344
+ publish({ saving: true, problem: "", notice: "" });
345
+ try {
346
+ const saved = unwrap(await gateway.setPaths({ colorsPath: colors, tokensPath: tokens }));
347
+ if (disposed) return;
348
+ const probe = unwrap(await gateway.poll({}));
349
+ if (disposed) return;
350
+ known = probe.status === "ok" ? probe.version : void 0;
351
+ publish({
352
+ paths: saved.paths,
353
+ notice: probe.status === "ok" ? t("palette.saved") : "",
354
+ problem: probe.status === "ok" ? "" : probe.message
355
+ });
356
+ if (probe.status === "ok" && view.active && probe.tokens !== void 0) applyPalette(probe.tokens);
357
+ } catch (error) {
358
+ const message = error.message;
359
+ console.error(`ui-experience: failed to save the palette paths: ${message}`);
360
+ publish({ problem: `${t("palette.save-failed")}: ${message}` });
361
+ } finally {
362
+ writing = false;
363
+ publish({ saving: false });
364
+ }
365
+ };
366
+ function PaletteRow(props) {
367
+ const tr = props.t ?? t;
368
+ const [state, setState] = React.useState(view);
369
+ const [open, setOpen] = React.useState(false);
370
+ const [colors, setColors] = React.useState(view.paths.colors);
371
+ const [tokens, setTokens] = React.useState(view.paths.tokens);
372
+ React.useEffect(() => {
373
+ const listener = () => {
374
+ setState(view);
375
+ };
376
+ listeners.add(listener);
377
+ return () => {
378
+ listeners.delete(listener);
379
+ };
380
+ }, []);
381
+ React.useEffect(() => {
382
+ setColors(state.paths.colors);
383
+ setTokens(state.paths.tokens);
384
+ }, [state.paths]);
385
+ const status = state.problem !== "" ? h("p", { className: "dsh-uix-problem", role: "alert" }, state.problem) : state.notice !== "" ? h("p", { className: "dsh-uix-notice" }, state.notice) : null;
386
+ const field = (label, value, placeholder, set, hint) => h(
387
+ "label",
388
+ { className: "dsh-uix-field" },
389
+ h("span", { className: "dsh-uix-label" }, label),
390
+ h(
391
+ "span",
392
+ { className: "dsh-uix-input-wrap" },
393
+ h("input", {
394
+ className: "dsh-uix-input",
395
+ type: "text",
396
+ value,
397
+ placeholder,
398
+ spellCheck: false,
399
+ autoComplete: "off",
400
+ onChange: (event) => {
401
+ set(event.target.value);
402
+ }
403
+ })
404
+ ),
405
+ hint ?? null
406
+ );
407
+ const editor = open ? h(
408
+ "div",
409
+ { className: "dsh-uix-form" },
410
+ field(tr("palette.colors-path"), colors, DEFAULT_COLORS_PATH, setColors),
411
+ field(
412
+ tr("palette.tokens-path"),
413
+ tokens,
414
+ DEFAULT_TOKENS_PATH,
415
+ setTokens,
416
+ h("p", { className: "dsh-uix-hint" }, tr("palette.paths-hint"))
417
+ ),
418
+ h(
419
+ "div",
420
+ { className: "dsh-uix-footer" },
421
+ h("button", {
422
+ type: "button",
423
+ className: "dsh-uix-save",
424
+ disabled: state.saving,
425
+ onClick: () => {
426
+ void savePaths(colors.trim(), tokens.trim());
427
+ }
428
+ }, tr("palette.save")),
429
+ h("button", {
430
+ type: "button",
431
+ className: "dsh-uix-reset",
432
+ disabled: state.saving,
433
+ onClick: () => {
434
+ void savePaths(DEFAULT_COLORS_PATH, DEFAULT_TOKENS_PATH);
435
+ }
436
+ }, tr("palette.reset"))
437
+ )
438
+ ) : null;
439
+ return h(
440
+ "div",
441
+ { className: "dsh-uix-row" },
442
+ h(
443
+ "div",
444
+ { className: "dsh-uix-head" },
445
+ h(
446
+ "div",
447
+ { className: "dsh-uix-text" },
448
+ h("div", { className: "dsh-uix-title" }, tr("palette.title")),
449
+ h("div", { className: "dsh-uix-desc" }, tr("palette.description"))
450
+ ),
451
+ h("button", {
452
+ type: "button",
453
+ role: "switch",
454
+ "aria-checked": state.active,
455
+ "aria-label": tr("palette.title"),
456
+ disabled: state.saving,
457
+ className: "dsh-uix-switch",
458
+ onClick: () => {
459
+ void setActive(!state.active);
460
+ }
461
+ }, h("span", { className: "dsh-uix-switch-thumb", "aria-hidden": true }))
462
+ ),
463
+ status,
464
+ h(
465
+ "button",
466
+ {
467
+ type: "button",
468
+ className: "dsh-uix-disclosure",
469
+ "aria-expanded": open,
470
+ onClick: () => {
471
+ setOpen(!open);
472
+ }
473
+ },
474
+ h(
475
+ "span",
476
+ { className: "dsh-uix-disclosure-icon" },
477
+ h("svg", {
478
+ viewBox: "0 0 16 16",
479
+ width: 14,
480
+ height: 14,
481
+ fill: "none",
482
+ stroke: "currentColor",
483
+ strokeWidth: 1,
484
+ "aria-hidden": true
485
+ }, h("path", { d: "M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6" }))
486
+ ),
487
+ h("span", null, tr("palette.paths"))
488
+ ),
489
+ editor
490
+ );
491
+ }
492
+ ctx.effect(() => ctx.slots.inject("settings.general.item", () => ctx.slots.register({
493
+ name: "settings.general.item",
494
+ id: "ui-experience.palette",
495
+ order: 10.5,
496
+ locale: "ui-experience"
497
+ }, PaletteRow)), "ui-experience: settings row");
498
+ ctx.effect(() => ctx.timer.interval(() => {
499
+ void poll();
500
+ }, POLL_MS), "ui-experience: palette polling");
501
+ ctx.effect(() => {
502
+ return () => {
503
+ disposed = true;
504
+ teardown();
505
+ };
506
+ }, "ui-experience: palette override");
507
+ void poll();
508
+ }
509
+ return {
510
+ inject: ["slots", "locale", "timer", "theme", "remote"],
511
+ async apply(ctx) {
512
+ const theme = ctx.get("theme");
513
+ if (theme === void 0) {
514
+ console.error("ui-experience: ctx.theme is unavailable; the bundle cannot apply palettes");
515
+ return;
516
+ }
517
+ const unmount = await ctx.remote.$mount(uiExperienceRemoteContribution(zod));
518
+ ctx.effect(() => () => {
519
+ unmount().catch((error) => {
520
+ console.error(`ui-experience: remote unmount failed: ${error.message}`);
521
+ });
522
+ }, "ui-experience: remote namespace");
523
+ const gateway = ctx.get(`remote.${REMOTE_SERVICE}`);
524
+ if (gateway === void 0) {
525
+ console.error("ui-experience: the remote namespace was not installed after mounting the contribution");
526
+ return;
527
+ }
528
+ run(theme, ctx, gateway);
529
+ }
530
+ };
531
+ }
532
+ });
533
+ }
534
+ registerClient();
535
+ })();