@takazudo/zdtp 0.1.0-next.0
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 +107 -0
- package/LICENSE +21 -0
- package/README.md +1044 -0
- package/dist/apply/apply-token-overrides.d.ts +81 -0
- package/dist/apply/apply-token-overrides.d.ts.map +1 -0
- package/dist/apply/build-apply-overrides.d.ts +71 -0
- package/dist/apply/build-apply-overrides.d.ts.map +1 -0
- package/dist/apply/route-tokens-to-files.d.ts +65 -0
- package/dist/apply/route-tokens-to-files.d.ts.map +1 -0
- package/dist/apply/tier-resolver.d.ts +75 -0
- package/dist/apply/tier-resolver.d.ts.map +1 -0
- package/dist/apply-modal.d.ts +49 -0
- package/dist/apply-modal.d.ts.map +1 -0
- package/dist/astro/DesignTokenPanelHost.astro +76 -0
- package/dist/astro/host-adapter.d.ts +47 -0
- package/dist/astro/host-adapter.d.ts.map +1 -0
- package/dist/astro/host-adapter.js +81 -0
- package/dist/astro/index.d.ts +30 -0
- package/dist/astro/index.d.ts.map +1 -0
- package/dist/astro/index.js +54 -0
- package/dist/bin/cors.d.ts +24 -0
- package/dist/bin/cors.d.ts.map +1 -0
- package/dist/bin/parse-args.d.ts +38 -0
- package/dist/bin/parse-args.d.ts.map +1 -0
- package/dist/bin/server.d.ts +23 -0
- package/dist/bin/server.d.ts.map +1 -0
- package/dist/bin/server.js +283 -0
- package/dist/color-schemes-CgzOBqGO.js +85 -0
- package/dist/components/color-picker/color-picker.d.ts +64 -0
- package/dist/components/color-picker/color-picker.d.ts.map +1 -0
- package/dist/components/color-picker/custom-slider.d.ts +25 -0
- package/dist/components/color-picker/custom-slider.d.ts.map +1 -0
- package/dist/components/color-picker/index.d.ts +3 -0
- package/dist/components/color-picker/index.d.ts.map +1 -0
- package/dist/config/cluster-config.d.ts +135 -0
- package/dist/config/cluster-config.d.ts.map +1 -0
- package/dist/config/color-scheme-utils.d.ts +105 -0
- package/dist/config/color-scheme-utils.d.ts.map +1 -0
- package/dist/config/color-schemes.d.ts +83 -0
- package/dist/config/color-schemes.d.ts.map +1 -0
- package/dist/config/panel-config.d.ts +258 -0
- package/dist/config/panel-config.d.ts.map +1 -0
- package/dist/controls/pill-slider-row.d.ts +37 -0
- package/dist/controls/pill-slider-row.d.ts.map +1 -0
- package/dist/controls/role-button.d.ts +18 -0
- package/dist/controls/role-button.d.ts.map +1 -0
- package/dist/controls/sanitize-css-value.d.ts +22 -0
- package/dist/controls/sanitize-css-value.d.ts.map +1 -0
- package/dist/controls/select-row.d.ts +26 -0
- package/dist/controls/select-row.d.ts.map +1 -0
- package/dist/controls/slider-row.d.ts +34 -0
- package/dist/controls/slider-row.d.ts.map +1 -0
- package/dist/controls/text-row.d.ts +28 -0
- package/dist/controls/text-row.d.ts.map +1 -0
- package/dist/controls/tier-ref-selector.d.ts +33 -0
- package/dist/controls/tier-ref-selector.d.ts.map +1 -0
- package/dist/controls/tooltip.d.ts +44 -0
- package/dist/controls/tooltip.d.ts.map +1 -0
- package/dist/export-modal.d.ts +33 -0
- package/dist/export-modal.d.ts.map +1 -0
- package/dist/highlight/find-elements.d.ts +113 -0
- package/dist/highlight/find-elements.d.ts.map +1 -0
- package/dist/highlight/highlight-orchestrator.d.ts +24 -0
- package/dist/highlight/highlight-orchestrator.d.ts.map +1 -0
- package/dist/highlight/highlight-overlay.d.ts +43 -0
- package/dist/highlight/highlight-overlay.d.ts.map +1 -0
- package/dist/highlight/highlight-settings-popover.d.ts +25 -0
- package/dist/highlight/highlight-settings-popover.d.ts.map +1 -0
- package/dist/highlight/highlight-state.d.ts +87 -0
- package/dist/highlight/highlight-state.d.ts.map +1 -0
- package/dist/highlight/highlight-toggle-button.d.ts +34 -0
- package/dist/highlight/highlight-toggle-button.d.ts.map +1 -0
- package/dist/import-modal.d.ts +33 -0
- package/dist/import-modal.d.ts.map +1 -0
- package/dist/index.d.ts +105 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5480 -0
- package/dist/load-routing-XyKgftpe.js +353 -0
- package/dist/manifest-DCReQE0k.js +24 -0
- package/dist/panel-config-DP2_P7dD.js +332 -0
- package/dist/panel.d.ts +3 -0
- package/dist/panel.d.ts.map +1 -0
- package/dist/route-tokens-to-files-1DvmWBdj.js +41 -0
- package/dist/server/create-apply-handler.d.ts +48 -0
- package/dist/server/create-apply-handler.d.ts.map +1 -0
- package/dist/server/index.d.ts +24 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +10 -0
- package/dist/server/load-routing.d.ts +39 -0
- package/dist/server/load-routing.d.ts.map +1 -0
- package/dist/server/path-safety.d.ts +36 -0
- package/dist/server/path-safety.d.ts.map +1 -0
- package/dist/server/serialize-write.d.ts +7 -0
- package/dist/server/serialize-write.d.ts.map +1 -0
- package/dist/state/persist.d.ts +39 -0
- package/dist/state/persist.d.ts.map +1 -0
- package/dist/state/tweak-state.d.ts +344 -0
- package/dist/state/tweak-state.d.ts.map +1 -0
- package/dist/tabs/_generic-item-editor.d.ts +23 -0
- package/dist/tabs/_generic-item-editor.d.ts.map +1 -0
- package/dist/tabs/color-tab.d.ts +55 -0
- package/dist/tabs/color-tab.d.ts.map +1 -0
- package/dist/tabs/font-tab.d.ts +22 -0
- package/dist/tabs/font-tab.d.ts.map +1 -0
- package/dist/tabs/generic-tab.d.ts +43 -0
- package/dist/tabs/generic-tab.d.ts.map +1 -0
- package/dist/tabs/size-tab.d.ts +20 -0
- package/dist/tabs/size-tab.d.ts.map +1 -0
- package/dist/tabs/spacing-tab.d.ts +23 -0
- package/dist/tabs/spacing-tab.d.ts.map +1 -0
- package/dist/testing.d.ts +81 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +23 -0
- package/dist/tokens/manifest.d.ts +148 -0
- package/dist/tokens/manifest.d.ts.map +1 -0
- package/dist/tokens/tier-model.d.ts +89 -0
- package/dist/tokens/tier-model.d.ts.map +1 -0
- package/dist/tweak-state-DSJa5csL.js +624 -0
- package/dist/utils/color-convert.d.ts +7 -0
- package/dist/utils/color-convert.d.ts.map +1 -0
- package/dist/utils/color-hsla.d.ts +9 -0
- package/dist/utils/color-hsla.d.ts.map +1 -0
- package/dist/utils/color-oklch.d.ts +51 -0
- package/dist/utils/color-oklch.d.ts.map +1 -0
- package/dist/utils/design-token-serde.d.ts +193 -0
- package/dist/utils/design-token-serde.d.ts.map +1 -0
- package/dist/utils/structural-equal.d.ts +22 -0
- package/dist/utils/structural-equal.d.ts.map +1 -0
- package/dist/zdtp.css +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { default as t } from "./DesignTokenPanelHost.astro";
|
|
2
|
+
import { s as d } from "../panel-config-DP2_P7dD.js";
|
|
3
|
+
import { c as r } from "../color-schemes-CgzOBqGO.js";
|
|
4
|
+
import { F as g, G as f, a as l, S as z } from "../manifest-DCReQE0k.js";
|
|
5
|
+
const e = {
|
|
6
|
+
colorScheme: "Default Dark",
|
|
7
|
+
colorMode: !1
|
|
8
|
+
}, c = {
|
|
9
|
+
bg: 9,
|
|
10
|
+
fg: 11,
|
|
11
|
+
surface: 10,
|
|
12
|
+
muted: 8,
|
|
13
|
+
accent: 5,
|
|
14
|
+
accentHover: 14,
|
|
15
|
+
link: 4,
|
|
16
|
+
codeBg: 0,
|
|
17
|
+
codeFg: 7,
|
|
18
|
+
success: 2,
|
|
19
|
+
danger: 1,
|
|
20
|
+
warning: 3,
|
|
21
|
+
info: 4,
|
|
22
|
+
price: 12,
|
|
23
|
+
sold: 13,
|
|
24
|
+
active: 14
|
|
25
|
+
}, s = {
|
|
26
|
+
bg: "--zd-semantic-bg",
|
|
27
|
+
fg: "--zd-semantic-fg",
|
|
28
|
+
surface: "--zd-semantic-surface",
|
|
29
|
+
muted: "--zd-semantic-muted",
|
|
30
|
+
accent: "--zd-semantic-accent",
|
|
31
|
+
accentHover: "--zd-semantic-accent-hover",
|
|
32
|
+
link: "--zd-semantic-link",
|
|
33
|
+
codeBg: "--zd-semantic-code-bg",
|
|
34
|
+
codeFg: "--zd-semantic-code-fg",
|
|
35
|
+
success: "--zd-semantic-success",
|
|
36
|
+
danger: "--zd-semantic-danger",
|
|
37
|
+
warning: "--zd-semantic-warning",
|
|
38
|
+
info: "--zd-semantic-info",
|
|
39
|
+
price: "--zd-semantic-price",
|
|
40
|
+
sold: "--zd-semantic-sold",
|
|
41
|
+
active: "--zd-semantic-active"
|
|
42
|
+
};
|
|
43
|
+
export {
|
|
44
|
+
t as DesignTokenPanelHost,
|
|
45
|
+
g as FONT_GROUP_ORDER,
|
|
46
|
+
f as GROUP_ORDER,
|
|
47
|
+
l as GROUP_TITLES,
|
|
48
|
+
s as SEMANTIC_CSS_NAMES,
|
|
49
|
+
c as SEMANTIC_DEFAULTS_ZD,
|
|
50
|
+
z as SIZE_GROUP_ORDER,
|
|
51
|
+
r as colorSchemes,
|
|
52
|
+
e as panelSettings,
|
|
53
|
+
d as setPanelColorPresets
|
|
54
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure CORS helpers for the `zdtp-server` bin.
|
|
3
|
+
*
|
|
4
|
+
* Origin matching is **case-sensitive on the entire scheme + host + port**
|
|
5
|
+
* string — wildcards and pattern matching are intentionally not supported.
|
|
6
|
+
* The browser sends the origin verbatim; the bin operator declares the exact
|
|
7
|
+
* allowed origins via repeated `--allow-origin` flags.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* @param origin The `Origin` header from the incoming request, or
|
|
11
|
+
* null/undefined if the header was absent.
|
|
12
|
+
* @param allowList The exact-match allow-list configured at bin startup.
|
|
13
|
+
* @returns true iff `origin` is a non-empty string present in `allowList`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isOriginAllowed(origin: string | null | undefined, allowList: readonly string[]): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Build the four `Access-Control-Allow-*` headers for a successful CORS
|
|
18
|
+
* response (preflight 204 OR the wrapped POST /apply response). The caller
|
|
19
|
+
* is responsible for only calling this when `isOriginAllowed` returned true,
|
|
20
|
+
* so the echoed origin value is always one the operator has explicitly
|
|
21
|
+
* permitted.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildCorsHeaders(origin: string): Record<string, string>;
|
|
24
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/bin/cors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAIT;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOvE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-function argv parser for the `zdtp-server` bin.
|
|
3
|
+
*
|
|
4
|
+
* No external dependencies — only standard JS/TS — so this module is trivially
|
|
5
|
+
* unit-testable and can be imported safely from non-Node contexts (although in
|
|
6
|
+
* practice the bin file is the only consumer).
|
|
7
|
+
*
|
|
8
|
+
* Surface (matches the parse-args contract):
|
|
9
|
+
*
|
|
10
|
+
* --root <dir> repo root; default: process.cwd() (parser leaves null)
|
|
11
|
+
* --write-root <path> REQUIRED; absolute or relative-to-root
|
|
12
|
+
* --routing <path> REQUIRED; routing JSON file path
|
|
13
|
+
* --port <number> default 24681
|
|
14
|
+
* --host <addr> default 127.0.0.1
|
|
15
|
+
* --allow-origin <origin> repeatable; required at least once for browser POST
|
|
16
|
+
* --quiet suppress per-request logs
|
|
17
|
+
* --help print usage and exit 0
|
|
18
|
+
*
|
|
19
|
+
* On invalid input, throws a descriptive `Error`. The bin entry catches it,
|
|
20
|
+
* writes the message to stderr, and exits 1.
|
|
21
|
+
*/
|
|
22
|
+
export interface ParsedArgs {
|
|
23
|
+
root: string | null;
|
|
24
|
+
writeRoot: string | null;
|
|
25
|
+
routing: string | null;
|
|
26
|
+
port: number;
|
|
27
|
+
host: string;
|
|
28
|
+
allowOrigins: string[];
|
|
29
|
+
quiet: boolean;
|
|
30
|
+
help: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare const HELP_TEXT = "Usage: zdtp-server [options]\n\nRun a small Node http server that wraps the design-token apply handler.\n\nOptions:\n --root <dir> Repo root used as the CWD reference for routing\n paths. Defaults to the current working directory.\n --write-root <path> REQUIRED. Absolute or root-relative path to the\n single directory the bin is allowed to write into.\n --routing <path> REQUIRED. Path to the routing JSON file\n (prefix -> repo-relative CSS file path).\n --port <number> TCP port to bind. Default: 24681.\n --host <addr> Host/interface to bind. Default: 127.0.0.1.\n Use 0.0.0.0 to expose on the LAN (off by default).\n --allow-origin <origin> Origin allowed to POST to /apply. Repeatable.\n At least one is required for any browser to apply.\n --quiet Suppress per-request logs.\n --help Print this message and exit.\n\nExamples:\n zdtp-server \\\n --write-root tokens \\\n --routing ./my.routing.json \\\n --allow-origin http://localhost:34434\n";
|
|
33
|
+
/**
|
|
34
|
+
* Parse a raw argv array (typically `process.argv.slice(2)`) into a
|
|
35
|
+
* `ParsedArgs` record. Throws on malformed input — the bin handles the throw.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
38
|
+
//# sourceMappingURL=parse-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-args.d.ts","sourceRoot":"","sources":["../../src/bin/parse-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,SAAS,6qCAwBrB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA4E7D"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `zdtp-server` bin entry.
|
|
3
|
+
*
|
|
4
|
+
* The `#!/usr/bin/env node` shebang is intentionally NOT in this source file —
|
|
5
|
+
* Vite/Rollup re-injects it via `output.banner` (see vite.config.ts) onto the
|
|
6
|
+
* emitted `dist/bin/server.js`. That keeps the bundled file as the single
|
|
7
|
+
* source of truth for the executable header and avoids esbuild rejecting a
|
|
8
|
+
* double-shebang in the build output.
|
|
9
|
+
*
|
|
10
|
+
* Wraps the framework-agnostic `createApplyHandler` from `../server` in a tiny
|
|
11
|
+
* Node `http` server that:
|
|
12
|
+
*
|
|
13
|
+
* - parses argv via `parseArgs`
|
|
14
|
+
* - resolves --root / --write-root / --routing
|
|
15
|
+
* - loads the routing JSON via `loadRoutingFromFile`
|
|
16
|
+
* - serves OPTIONS/POST /apply with CORS gating, plus GET /healthz, plus
|
|
17
|
+
* 404/405 for everything else
|
|
18
|
+
* - logs apply outcomes (unless --quiet)
|
|
19
|
+
* - exits 1 with a friendly stderr message on EADDRINUSE
|
|
20
|
+
* - shuts down gracefully on SIGINT/SIGTERM
|
|
21
|
+
*/
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/bin/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync as H } from "node:fs";
|
|
3
|
+
import { createServer as C } from "node:http";
|
|
4
|
+
import { resolve as d } from "node:path";
|
|
5
|
+
import { l as x, c as N } from "../load-routing-XyKgftpe.js";
|
|
6
|
+
function g(t, e) {
|
|
7
|
+
return typeof t != "string" || t.length === 0 || e.length === 0 ? !1 : e.includes(t);
|
|
8
|
+
}
|
|
9
|
+
function w(t) {
|
|
10
|
+
return {
|
|
11
|
+
"Access-Control-Allow-Origin": t,
|
|
12
|
+
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
13
|
+
"Access-Control-Allow-Headers": "content-type",
|
|
14
|
+
"Access-Control-Max-Age": "600"
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const k = 24681, b = "127.0.0.1", $ = `Usage: zdtp-server [options]
|
|
18
|
+
|
|
19
|
+
Run a small Node http server that wraps the design-token apply handler.
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--root <dir> Repo root used as the CWD reference for routing
|
|
23
|
+
paths. Defaults to the current working directory.
|
|
24
|
+
--write-root <path> REQUIRED. Absolute or root-relative path to the
|
|
25
|
+
single directory the bin is allowed to write into.
|
|
26
|
+
--routing <path> REQUIRED. Path to the routing JSON file
|
|
27
|
+
(prefix -> repo-relative CSS file path).
|
|
28
|
+
--port <number> TCP port to bind. Default: ${k}.
|
|
29
|
+
--host <addr> Host/interface to bind. Default: ${b}.
|
|
30
|
+
Use 0.0.0.0 to expose on the LAN (off by default).
|
|
31
|
+
--allow-origin <origin> Origin allowed to POST to /apply. Repeatable.
|
|
32
|
+
At least one is required for any browser to apply.
|
|
33
|
+
--quiet Suppress per-request logs.
|
|
34
|
+
--help Print this message and exit.
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
zdtp-server \\
|
|
38
|
+
--write-root tokens \\
|
|
39
|
+
--routing ./my.routing.json \\
|
|
40
|
+
--allow-origin http://localhost:34434
|
|
41
|
+
`;
|
|
42
|
+
function v(t) {
|
|
43
|
+
const e = {
|
|
44
|
+
root: null,
|
|
45
|
+
writeRoot: null,
|
|
46
|
+
routing: null,
|
|
47
|
+
port: k,
|
|
48
|
+
host: b,
|
|
49
|
+
allowOrigins: [],
|
|
50
|
+
quiet: !1,
|
|
51
|
+
help: !1
|
|
52
|
+
};
|
|
53
|
+
let o = 0;
|
|
54
|
+
for (; o < t.length; ) {
|
|
55
|
+
const n = t[o];
|
|
56
|
+
switch (n) {
|
|
57
|
+
case "--help":
|
|
58
|
+
case "-h":
|
|
59
|
+
e.help = !0, o += 1;
|
|
60
|
+
break;
|
|
61
|
+
case "--quiet":
|
|
62
|
+
e.quiet = !0, o += 1;
|
|
63
|
+
break;
|
|
64
|
+
case "--root":
|
|
65
|
+
e.root = c(t, o, "--root"), o += 2;
|
|
66
|
+
break;
|
|
67
|
+
case "--write-root":
|
|
68
|
+
e.writeRoot = c(t, o, "--write-root"), o += 2;
|
|
69
|
+
break;
|
|
70
|
+
case "--routing":
|
|
71
|
+
e.routing = c(t, o, "--routing"), o += 2;
|
|
72
|
+
break;
|
|
73
|
+
case "--host":
|
|
74
|
+
e.host = c(t, o, "--host"), o += 2;
|
|
75
|
+
break;
|
|
76
|
+
case "--port": {
|
|
77
|
+
const s = c(t, o, "--port"), r = Number(s);
|
|
78
|
+
if (!Number.isInteger(r) || r < 0 || r > 65535)
|
|
79
|
+
throw new Error(`--port must be an integer in 0..65535 (got ${JSON.stringify(s)})`);
|
|
80
|
+
e.port = r, o += 2;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case "--allow-origin": {
|
|
84
|
+
const s = c(t, o, "--allow-origin");
|
|
85
|
+
e.allowOrigins.push(s), o += 2;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
default:
|
|
89
|
+
throw new Error(`Unknown option: ${n}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (e.help) return e;
|
|
93
|
+
if (!e.writeRoot)
|
|
94
|
+
throw new Error("--write-root is required (the only directory the bin will write into)");
|
|
95
|
+
if (!e.routing)
|
|
96
|
+
throw new Error("--routing is required (path to the routing JSON file)");
|
|
97
|
+
return e;
|
|
98
|
+
}
|
|
99
|
+
function c(t, e, o) {
|
|
100
|
+
const n = t[e + 1];
|
|
101
|
+
if (typeof n != "string" || n.startsWith("--"))
|
|
102
|
+
throw new Error(`${o} requires a value`);
|
|
103
|
+
return n;
|
|
104
|
+
}
|
|
105
|
+
const y = "/apply", D = "/healthz";
|
|
106
|
+
function L(t) {
|
|
107
|
+
const e = d(t.root ?? process.cwd()), o = d(e, t.writeRoot), n = d(e, t.routing);
|
|
108
|
+
return {
|
|
109
|
+
rootDir: e,
|
|
110
|
+
writeRoot: o,
|
|
111
|
+
routingPath: n,
|
|
112
|
+
port: t.port,
|
|
113
|
+
host: t.host,
|
|
114
|
+
allowOrigins: t.allowOrigins,
|
|
115
|
+
quiet: t.quiet
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function a(t, e, o) {
|
|
119
|
+
const n = JSON.stringify(o);
|
|
120
|
+
t.statusCode = e, t.setHeader("Content-Type", "application/json"), t.setHeader("Content-Length", Buffer.byteLength(n).toString()), t.end(n);
|
|
121
|
+
}
|
|
122
|
+
const O = 1048576;
|
|
123
|
+
function U(t) {
|
|
124
|
+
return new Promise((e, o) => {
|
|
125
|
+
const n = [];
|
|
126
|
+
let s = 0;
|
|
127
|
+
t.on("data", (r) => {
|
|
128
|
+
if (s += r.byteLength, s > O) {
|
|
129
|
+
e(413), t.destroy();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
n.push(r);
|
|
133
|
+
}), t.on("end", () => e(Buffer.concat(n).toString("utf-8"))), t.on("error", o);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function I(t) {
|
|
137
|
+
const e = new Headers();
|
|
138
|
+
for (const [o, n] of Object.entries(t.headers))
|
|
139
|
+
if (Array.isArray(n))
|
|
140
|
+
for (const s of n) e.append(o, s);
|
|
141
|
+
else typeof n == "string" && e.set(o, n);
|
|
142
|
+
return e;
|
|
143
|
+
}
|
|
144
|
+
async function j(t, e, o) {
|
|
145
|
+
t.statusCode = e.status, e.headers.forEach((s, r) => {
|
|
146
|
+
t.setHeader(r, s);
|
|
147
|
+
});
|
|
148
|
+
for (const [s, r] of Object.entries(o))
|
|
149
|
+
t.setHeader(s, r);
|
|
150
|
+
const n = await e.text();
|
|
151
|
+
t.end(n);
|
|
152
|
+
}
|
|
153
|
+
function q(t, e) {
|
|
154
|
+
if (!t)
|
|
155
|
+
try {
|
|
156
|
+
const o = JSON.parse(e);
|
|
157
|
+
if (!o.ok || !Array.isArray(o.updated)) return;
|
|
158
|
+
const n = o.updated.reduce(
|
|
159
|
+
(i, l) => i + (Array.isArray(l.changed) ? l.changed.length : 0),
|
|
160
|
+
0
|
|
161
|
+
), s = o.updated.length, r = o.updated.filter((i) => Array.isArray(i.changed) && i.changed.length > 0).map((i) => i.file);
|
|
162
|
+
console.log(
|
|
163
|
+
`[design-token-panel] applied ${n} tokens to ${s} files (changed: ${r.length > 0 ? r.join(", ") : "none"})`
|
|
164
|
+
);
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function F(t) {
|
|
169
|
+
const { applyHandler: e, config: o } = t;
|
|
170
|
+
return async function(s, r) {
|
|
171
|
+
const i = s.url ?? "/", l = (s.method ?? "GET").toUpperCase(), u = typeof s.headers.origin == "string" ? s.headers.origin : null;
|
|
172
|
+
try {
|
|
173
|
+
if (i === D && l === "GET") {
|
|
174
|
+
a(r, 200, {
|
|
175
|
+
ok: !0,
|
|
176
|
+
writeRoot: o.writeRoot,
|
|
177
|
+
routing: o.routingPath,
|
|
178
|
+
port: o.port
|
|
179
|
+
});
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (i === y) {
|
|
183
|
+
if (l === "OPTIONS") {
|
|
184
|
+
if (!g(u, o.allowOrigins)) {
|
|
185
|
+
a(r, 403, { ok: !1, error: "Origin not allowed" });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const S = w(u);
|
|
189
|
+
for (const [P, E] of Object.entries(S))
|
|
190
|
+
r.setHeader(P, E);
|
|
191
|
+
r.statusCode = 204, r.end();
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (l !== "POST") {
|
|
195
|
+
r.setHeader("Allow", "POST, OPTIONS"), a(r, 405, { ok: !1, error: "Method not allowed" });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const p = s.headers["content-type"];
|
|
199
|
+
if (typeof p != "string" || !p.toLowerCase().includes("application/json")) {
|
|
200
|
+
a(r, 415, { ok: !1, error: "Content-Type must be application/json" });
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (!g(u, o.allowOrigins)) {
|
|
204
|
+
a(r, 403, { ok: !1, error: "Origin not allowed" });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const f = await U(s);
|
|
208
|
+
if (f === 413) {
|
|
209
|
+
a(r, 413, {
|
|
210
|
+
ok: !1,
|
|
211
|
+
error: "Payload Too Large",
|
|
212
|
+
limit: O
|
|
213
|
+
});
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const m = f, A = new Request(`http://localhost${y}`, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
headers: I(s),
|
|
219
|
+
body: m
|
|
220
|
+
}), h = await e(A), R = await h.clone().text(), T = w(u);
|
|
221
|
+
await j(r, h, T), q(o.quiet, R);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
a(r, 404, { ok: !1, error: "Not found" });
|
|
225
|
+
} catch (p) {
|
|
226
|
+
console.error("[design-token-panel] Unhandled error:", p), r.headersSent ? r.end() : a(r, 500, { ok: !1, error: "Internal server error" });
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function _(t, e) {
|
|
231
|
+
t.on("error", (n) => {
|
|
232
|
+
n.code === "EADDRINUSE" && (console.error(`[design-token-panel] port ${e} already in use`), process.exit(1)), console.error("[design-token-panel] Server error:", n), process.exit(1);
|
|
233
|
+
});
|
|
234
|
+
const o = (n) => {
|
|
235
|
+
t.close(() => {
|
|
236
|
+
process.exit(0);
|
|
237
|
+
}), setTimeout(() => {
|
|
238
|
+
console.error(`[design-token-panel] force-exiting after ${n}`), process.exit(0);
|
|
239
|
+
}, 5e3).unref();
|
|
240
|
+
};
|
|
241
|
+
process.on("SIGINT", o), process.on("SIGTERM", o);
|
|
242
|
+
}
|
|
243
|
+
function B() {
|
|
244
|
+
let t;
|
|
245
|
+
try {
|
|
246
|
+
t = v(process.argv.slice(2));
|
|
247
|
+
} catch (r) {
|
|
248
|
+
console.error(`[design-token-panel] ${r.message}`), console.error(""), console.error("Run --help for usage."), process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
t.help && (process.stdout.write($), process.exit(0));
|
|
251
|
+
const e = L(t);
|
|
252
|
+
let o;
|
|
253
|
+
try {
|
|
254
|
+
o = x(e.routingPath);
|
|
255
|
+
} catch (r) {
|
|
256
|
+
console.error(`[design-token-panel] Failed to load routing: ${r.message}`), process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
const n = N({
|
|
259
|
+
rootDir: e.rootDir,
|
|
260
|
+
writeRoot: e.writeRoot,
|
|
261
|
+
routing: o
|
|
262
|
+
}), s = C(F({ applyHandler: n, config: e }));
|
|
263
|
+
_(s, e.port), s.listen(e.port, e.host, () => {
|
|
264
|
+
if (!e.quiet) {
|
|
265
|
+
const r = s.address(), i = typeof r == "object" && r ? r.port : e.port;
|
|
266
|
+
console.log(
|
|
267
|
+
`[design-token-panel] listening on http://${e.host}:${i} (writeRoot: ${e.writeRoot})`
|
|
268
|
+
), e.allowOrigins.length === 0 && console.log(
|
|
269
|
+
"[design-token-panel] WARNING: no --allow-origin set; browser POST /apply will be rejected."
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
const G = (() => {
|
|
275
|
+
if (typeof process.argv[1] != "string") return !1;
|
|
276
|
+
try {
|
|
277
|
+
const t = H(process.argv[1]), e = new URL(`file://${d(t)}`).href, o = import.meta.url;
|
|
278
|
+
return e === o;
|
|
279
|
+
} catch {
|
|
280
|
+
return !1;
|
|
281
|
+
}
|
|
282
|
+
})();
|
|
283
|
+
G && B();
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const e = {
|
|
2
|
+
"Default Light": {
|
|
3
|
+
background: 9,
|
|
4
|
+
foreground: 11,
|
|
5
|
+
cursor: 6,
|
|
6
|
+
selectionBg: 11,
|
|
7
|
+
selectionFg: 10,
|
|
8
|
+
palette: [
|
|
9
|
+
"#303030",
|
|
10
|
+
"#dd3131",
|
|
11
|
+
"#266538",
|
|
12
|
+
"#a83838",
|
|
13
|
+
"#3277c8",
|
|
14
|
+
"#a35e0f",
|
|
15
|
+
"#90a1b9",
|
|
16
|
+
"#7a5218",
|
|
17
|
+
"#6b6b6b",
|
|
18
|
+
"#e2ddda",
|
|
19
|
+
"#ece9e9",
|
|
20
|
+
"#303030",
|
|
21
|
+
"#5b99dc",
|
|
22
|
+
"#b89ee7",
|
|
23
|
+
"#8590a0",
|
|
24
|
+
"#b91c1c"
|
|
25
|
+
],
|
|
26
|
+
shikiTheme: "catppuccin-latte",
|
|
27
|
+
semantic: {
|
|
28
|
+
surface: 10,
|
|
29
|
+
muted: 8,
|
|
30
|
+
accent: 5,
|
|
31
|
+
accentHover: 14,
|
|
32
|
+
codeBg: 10,
|
|
33
|
+
codeFg: 11,
|
|
34
|
+
success: 2,
|
|
35
|
+
danger: 1,
|
|
36
|
+
warning: 3,
|
|
37
|
+
info: 4
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"Default Dark": {
|
|
41
|
+
background: 9,
|
|
42
|
+
// p11 (light gray) — not p15. The example palette repurposes p15 as a
|
|
43
|
+
// brand-red accent, so pinning `foreground` to p15 would paint the
|
|
44
|
+
// panel's fg swatch red and make every `fg`-mapped semantic resolve
|
|
45
|
+
// to red. p11 aligns with SEMANTIC_DEFAULTS_ZD.fg (also 11).
|
|
46
|
+
foreground: 11,
|
|
47
|
+
cursor: 6,
|
|
48
|
+
selectionBg: 10,
|
|
49
|
+
selectionFg: 11,
|
|
50
|
+
palette: [
|
|
51
|
+
"#1c1c1c",
|
|
52
|
+
"#da6871",
|
|
53
|
+
"#93bb77",
|
|
54
|
+
"#dfbb77",
|
|
55
|
+
"#5caae9",
|
|
56
|
+
"#c074d6",
|
|
57
|
+
"#90a1b9",
|
|
58
|
+
"#a0a0a0",
|
|
59
|
+
"#888888",
|
|
60
|
+
"18",
|
|
61
|
+
"#383838",
|
|
62
|
+
"#e0e0e0",
|
|
63
|
+
"#d69a66",
|
|
64
|
+
"#c074d6",
|
|
65
|
+
"#a7c0e3",
|
|
66
|
+
"#b91c1c"
|
|
67
|
+
],
|
|
68
|
+
shikiTheme: "vitesse-dark",
|
|
69
|
+
semantic: {
|
|
70
|
+
surface: 0,
|
|
71
|
+
muted: 8,
|
|
72
|
+
accent: 12,
|
|
73
|
+
accentHover: 14,
|
|
74
|
+
codeBg: 10,
|
|
75
|
+
codeFg: 11,
|
|
76
|
+
success: 2,
|
|
77
|
+
danger: 1,
|
|
78
|
+
warning: 3,
|
|
79
|
+
info: 4
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
export {
|
|
84
|
+
e as c
|
|
85
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ColorPicker — dual-mode (OKLCH | HSL) color picker for the design-token panel.
|
|
3
|
+
*
|
|
4
|
+
* Renders as a "popover body only" component — the parent is responsible for
|
|
5
|
+
* mounting/unmounting based on an open/closed boolean. No trigger swatch, no
|
|
6
|
+
* portal, no createPortal.
|
|
7
|
+
*
|
|
8
|
+
* Issue #175 (Wave 2 of the OKLCH Picker epic, issue #174-base).
|
|
9
|
+
*
|
|
10
|
+
* Design rules (see packages/zudo-design-token-panel/CLAUDE.md):
|
|
11
|
+
* - All interactive elements use <div role="button" tabIndex={0}> with
|
|
12
|
+
* explicit Enter/Space onKeyDown handlers. Native button and heading tags
|
|
13
|
+
* are not used (hostile-host policy).
|
|
14
|
+
* - BEM class names: tokenpanel-color-picker-* (locked external contract).
|
|
15
|
+
* - usePopoverClose: pointerdown + Escape only — NO scroll listener.
|
|
16
|
+
* - Mode persisted to localStorage under key tokenpanel.colorPicker.mode.
|
|
17
|
+
* - Alpha always shown; alpha ∈ [0, 100] scale throughout.
|
|
18
|
+
* - useSyncedHex: incoming color prop ignored while isDraggingRef.current.
|
|
19
|
+
*/
|
|
20
|
+
import type { JSX } from 'preact';
|
|
21
|
+
export type ColorPickerMode = 'oklch' | 'hsl';
|
|
22
|
+
export interface ColorPickerProps {
|
|
23
|
+
/** Current hex color (#RRGGBB or #RRGGBBAA). Source of truth. */
|
|
24
|
+
color: string;
|
|
25
|
+
/** Called when the user commits a new color via any sub-control. */
|
|
26
|
+
onChange: (hex: string) => void;
|
|
27
|
+
/** Optional label rendered in the picker header. */
|
|
28
|
+
label?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Initial mode. The runtime mode is uncontrolled inside the component
|
|
31
|
+
* and persisted via localStorage[LOCAL_STORAGE_KEY]. Defaults to 'oklch'.
|
|
32
|
+
*/
|
|
33
|
+
defaultMode?: ColorPickerMode;
|
|
34
|
+
/** Element to anchor the popover against (popover sits below/above it). */
|
|
35
|
+
anchorRef: React.RefObject<HTMLElement | null>;
|
|
36
|
+
/** Called when the picker requests to close itself (Escape / outside click). */
|
|
37
|
+
onClose: () => void;
|
|
38
|
+
}
|
|
39
|
+
export declare const LOCAL_STORAGE_KEY = "tokenpanel.colorPicker.mode";
|
|
40
|
+
/**
|
|
41
|
+
* Compute a `position: fixed` style that places the popover below (or above,
|
|
42
|
+
* if flipped) the anchor element, then clamps all edges inside the viewport.
|
|
43
|
+
*
|
|
44
|
+
* When vertical space is scarce on both sides, the popover is pinned to the
|
|
45
|
+
* top edge (top = pad) and given a max-height + overflow: auto so it scrolls
|
|
46
|
+
* rather than clips.
|
|
47
|
+
*/
|
|
48
|
+
export declare function getFixedPopoverStyle(anchor: HTMLElement | null, estW: number, estH: number): JSX.CSSProperties;
|
|
49
|
+
/**
|
|
50
|
+
* Close the popover on outside pointerdown or Escape key.
|
|
51
|
+
*
|
|
52
|
+
* Deliberately does NOT close on scroll — a scroll event on the host page
|
|
53
|
+
* should not dismiss an in-flight color edit.
|
|
54
|
+
*/
|
|
55
|
+
export declare function usePopoverClose(containerRef: React.RefObject<HTMLElement | null>, onClose: () => void): void;
|
|
56
|
+
/**
|
|
57
|
+
* ColorPicker — popover body only.
|
|
58
|
+
*
|
|
59
|
+
* The parent renders `{isOpen && <ColorPicker ... />}`. This component does
|
|
60
|
+
* NOT render a trigger swatch and does NOT use createPortal.
|
|
61
|
+
*/
|
|
62
|
+
export declare function ColorPicker({ color, onChange, label, defaultMode, anchorRef, onClose, }: ColorPickerProps): JSX.Element;
|
|
63
|
+
export default ColorPicker;
|
|
64
|
+
//# sourceMappingURL=color-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color-picker.d.ts","sourceRoot":"","sources":["../../../src/components/color-picker/color-picker.tsx"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;GAkBG;AAUH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAiBlC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,KAAK,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,2EAA2E;IAC3E,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC/C,gFAAgF;IAChF,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAID,eAAO,MAAM,iBAAiB,gCAAgC,CAAC;AAyJ/D;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,GAAG,CAAC,aAAa,CAuCnB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACjD,OAAO,EAAE,MAAM,IAAI,GAClB,IAAI,CA2BN;AAID;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAqB,EACrB,SAAS,EACT,OAAO,GACR,EAAE,gBAAgB,GAAG,GAAG,CAAC,OAAO,CAyehC;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { JSX } from 'preact';
|
|
2
|
+
export interface SliderConfig {
|
|
3
|
+
key: string;
|
|
4
|
+
/** Single-character label, e.g. 'L', 'H'. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Full accessible label, e.g. 'Lightness', 'Hue'. */
|
|
7
|
+
ariaLabel: string;
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
step: number;
|
|
11
|
+
/** Format the numeric value for display in the value span. */
|
|
12
|
+
format: (v: number) => string;
|
|
13
|
+
}
|
|
14
|
+
export interface CustomSliderProps {
|
|
15
|
+
config: SliderConfig;
|
|
16
|
+
value: number;
|
|
17
|
+
/** CSS gradient string applied to the track div's background. */
|
|
18
|
+
gradient: string;
|
|
19
|
+
onChange: (next: number) => void;
|
|
20
|
+
onDragStart: () => void;
|
|
21
|
+
onDragEnd: () => void;
|
|
22
|
+
}
|
|
23
|
+
export declare function CustomSlider({ config, value, gradient, onChange, onDragStart, onDragEnd, }: CustomSliderProps): JSX.Element;
|
|
24
|
+
export default CustomSlider;
|
|
25
|
+
//# sourceMappingURL=custom-slider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-slider.d.ts","sourceRoot":"","sources":["../../../src/components/color-picker/custom-slider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAWlC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAoCD,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,SAAS,GACV,EAAE,iBAAiB,GAAG,GAAG,CAAC,OAAO,CA+LjC;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/color-picker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC"}
|