@homepages/template-kit 0.8.1-dev-20260718224903 → 0.9.0-dev-20260719205406
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 +30 -1
- package/README.md +2 -2
- package/dist/canvas-core/chrome-css.d.ts +24 -0
- package/dist/canvas-core/chrome-css.js +403 -0
- package/dist/canvas-core/chrome.d.ts +49 -0
- package/dist/canvas-core/chrome.js +147 -0
- package/dist/canvas-core/frame.d.ts +20 -0
- package/dist/canvas-core/frame.js +23 -0
- package/dist/canvas-core/hidden-tabs.d.ts +16 -0
- package/dist/canvas-core/hidden-tabs.js +84 -0
- package/dist/canvas-core/resolve-target.js +55 -0
- package/dist/canvas-core/scroll.d.ts +10 -0
- package/dist/canvas-core/scroll.js +15 -0
- package/dist/canvas-core/section-dom.d.ts +6 -0
- package/dist/canvas-core/section-dom.js +43 -0
- package/dist/canvas-core/srcdoc.d.ts +8 -0
- package/dist/canvas-core/srcdoc.js +77 -0
- package/dist/canvas-core/types.d.ts +76 -0
- package/dist/canvas-core.d.ts +9 -0
- package/dist/canvas-core.js +9 -0
- package/dist/cli/check/css.js +2 -2
- package/dist/cli/check/loader.js +1 -1
- package/dist/cli/check/stages/deps.js +1 -1
- package/dist/cli/check/stages/size.js +2 -2
- package/dist/cli/check/stages/tree.js +1 -1
- package/dist/cli/check/stages/validate/index.js +1 -1
- package/dist/cli/check/stages/validate/nav-contract.js +1 -1
- package/dist/cli/check/stages/validate/orchestrator.js +1 -1
- package/dist/cli/check/workspace.js +2 -2
- package/dist/cli/dev/build-css.js +1 -1
- package/dist/cli/dev/discover.js +2 -2
- package/dist/cli/dev/inspect.js +1 -1
- package/dist/cli/dev/island-bootstrap.js +1 -1
- package/dist/cli/dev/island-canvas-bootstrap.js +37 -5
- package/dist/cli/dev/section-page.js +1 -1
- package/dist/cli/dev/server.js +9 -3
- package/dist/cli/dev/tailwind.js +1 -1
- package/dist/cli/dev/tsconfig-paths-plugin.js +1 -1
- package/dist/cli/dev/workspace.js +2 -2
- package/dist/cli/link/index.js +1 -1
- package/dist/cli/link/overlay.js +1 -1
- package/dist/cli/new/emit.js +1 -1
- package/dist/cli/new/index.js +1 -1
- package/dist/cli/new/scaffold-assets.js +2 -2
- package/dist/cli/pack/collect.js +1 -1
- package/dist/cli/pack/guards.js +1 -1
- package/dist/cli/pack/index.js +1 -1
- package/dist/cli/theme/generate.js +1 -1
- package/dist/cli/theme/load-theme.js +1 -1
- package/dist/dev-client/assets/index-CJa9G1Na.css +1 -0
- package/dist/dev-client/assets/index-C_1atZs4.js +450 -0
- package/dist/dev-client/index.html +2 -2
- package/dist/islands/client-directive.d.ts +7 -0
- package/dist/{eslint/is-client-file.js → islands/client-directive.js} +6 -3
- package/dist/islands/detect.d.ts +1 -1
- package/dist/islands/detect.js +1 -1
- package/dist/islands/discover.js +1 -1
- package/dist/islands/esbuild-plugin.js +1 -1
- package/dist/islands/wrap.js +1 -1
- package/dist/package.js +1 -1
- package/dist/rules.d.ts +176 -0
- package/dist/rules.js +209 -0
- package/dist/ssr.d.ts +2 -2
- package/dist/ssr.js +2 -2
- package/dist/tokens.css +21 -0
- package/guide/INDEX.md +2 -2
- package/guide/check.md +5 -5
- package/guide/dev.md +39 -30
- package/guide/eslint.md +13 -10
- package/guide/llms.txt +4 -3
- package/guide/quickstart.md +1 -1
- package/guide/rules/INDEX.md +3 -2
- package/guide/upgrading.md +18 -2
- package/package.json +8 -4
- package/tsconfig.json +1 -1
- package/dist/dev-client/assets/index-3Gn34X_P.js +0 -50
- package/dist/dev-client/assets/index-DxQeiHfu.css +0 -1
- package/dist/eslint/is-client-file.d.ts +0 -4
- package/dist/eslint/rules/image-bare-needs-reason.js +0 -43
- package/dist/eslint/rules/no-client-directive-in-contract.js +0 -31
- package/dist/eslint/rules/no-client-runtime-in-server.js +0 -103
- package/dist/eslint/rules/no-css-import-from-render-path.js +0 -29
- package/dist/eslint/rules/no-hex.js +0 -188
- package/dist/eslint/rules/no-inline-style.js +0 -27
- package/dist/eslint/rules/no-nondeterminism.js +0 -48
- package/dist/eslint/rules/no-raw-element.js +0 -38
- package/dist/eslint/rules/props-from-schema.js +0 -37
- package/dist/eslint/rules/require-island-editor.js +0 -74
- package/dist/eslint/rules/serializable-island-props.js +0 -112
- package/dist/eslint/rules/slot-marker-literal.js +0 -38
- package/dist/eslint.d.ts +0 -6
- package/dist/eslint.js +0 -80
- package/dist/rules/registry.js +0 -16
|
@@ -1,12 +1,35 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
|
|
4
4
|
//#region src/cli/dev/island-canvas-bootstrap.ts
|
|
5
5
|
const CACHE_DIR = ".tk-dev-cache";
|
|
6
6
|
const BOOTSTRAP_FILE = "island-canvas-bootstrap.js";
|
|
7
|
-
const BOOTSTRAP_SOURCE = `import
|
|
7
|
+
const BOOTSTRAP_SOURCE = `import RefreshRuntime from "/@react-refresh";
|
|
8
|
+
import { hydrateIslands, unmountIslands } from "@homepages/template-kit/island-runtime";
|
|
8
9
|
import { createElement, useLayoutEffect } from "react";
|
|
9
10
|
|
|
11
|
+
// React Refresh preamble. @vitejs/plugin-react compiles every client component
|
|
12
|
+
// to assert this ran and throws "can't detect preamble" otherwise, so any page
|
|
13
|
+
// that was not built by Vite's own index-html transform must supply it.
|
|
14
|
+
//
|
|
15
|
+
// It lives HERE, in the bootstrap, rather than in the page that loads the
|
|
16
|
+
// bootstrap, because the two canvas surfaces reach islands by different routes:
|
|
17
|
+
// the server-rendered ?canvas=1 page emits the preamble itself (section-page.ts)
|
|
18
|
+
// before this script, but the shared-kernel srcdoc canvas is assembled by
|
|
19
|
+
// canvas-core, whose CanvasAssets port carries stylesheets, an island map and
|
|
20
|
+
// ONE host script — it has no channel for a dev-only inline prelude, and adding
|
|
21
|
+
// one would push a Vite-specific concern into a kernel the app also ships.
|
|
22
|
+
// Emitting it from the one module both surfaces already load covers both.
|
|
23
|
+
//
|
|
24
|
+
// Guarded so the server-rendered page, which already installed it, does not
|
|
25
|
+
// re-enter injectIntoGlobalHook.
|
|
26
|
+
if (!window.__vite_plugin_react_preamble_installed__) {
|
|
27
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
28
|
+
window.$RefreshReg$ = () => {};
|
|
29
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
30
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
31
|
+
}
|
|
32
|
+
|
|
10
33
|
const SHIELD_CLASS = "tr-canvas-shield";
|
|
11
34
|
const LIVE_ATTR = "data-tr-live";
|
|
12
35
|
|
|
@@ -53,17 +76,26 @@ function makeShield(doc) {
|
|
|
53
76
|
}
|
|
54
77
|
|
|
55
78
|
// "fill-self": surface made position:relative, shield appended as its last
|
|
56
|
-
// child (unit cards). "fill-parent"
|
|
57
|
-
//
|
|
79
|
+
// child (unit cards). "fill-parent" (map canvas, slider viewport): the
|
|
80
|
+
// shield is an inset:0 sibling after the surface, so the surface's PARENT is
|
|
81
|
+
// made position:relative instead — otherwise the shield escapes to the
|
|
82
|
+
// initial containing block and covers the whole canvas. Idempotent in both
|
|
83
|
+
// modes.
|
|
58
84
|
function installShield(surface, mode) {
|
|
59
85
|
const doc = surface.ownerDocument;
|
|
86
|
+
const win = doc.defaultView;
|
|
60
87
|
if (mode === "fill-self") {
|
|
61
|
-
const pos =
|
|
88
|
+
const pos = win ? win.getComputedStyle(surface).position : "";
|
|
62
89
|
if (!pos || pos === "static") surface.style.position = "relative";
|
|
63
90
|
if (Array.from(surface.children).some((c) => c.classList.contains(SHIELD_CLASS))) return;
|
|
64
91
|
surface.appendChild(makeShield(doc));
|
|
65
92
|
return;
|
|
66
93
|
}
|
|
94
|
+
const parent = surface.parentElement;
|
|
95
|
+
if (parent) {
|
|
96
|
+
const pos = win ? win.getComputedStyle(parent).position : "";
|
|
97
|
+
if (!pos || pos === "static") parent.style.position = "relative";
|
|
98
|
+
}
|
|
67
99
|
const next = surface.nextElementSibling;
|
|
68
100
|
if (next && next.classList.contains(SHIELD_CLASS)) return;
|
|
69
101
|
surface.insertAdjacentElement("afterend", makeShield(doc));
|
|
@@ -26,7 +26,7 @@ function diagnosticsBanner(section, template, encodedSection) {
|
|
|
26
26
|
}
|
|
27
27
|
function islandBootstrap(islands, bootstrapUrl) {
|
|
28
28
|
if (Object.keys(islands).length === 0) return "";
|
|
29
|
-
const mapJson = JSON.stringify(islands).replace(/</g, "\\u003c");
|
|
29
|
+
const mapJson = JSON.stringify(islands).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
30
30
|
return `
|
|
31
31
|
${REACT_REFRESH_PREAMBLE}
|
|
32
32
|
<script>window.__TR_ISLAND_MAP = ${mapJson};<\/script>
|
package/dist/cli/dev/server.js
CHANGED
|
@@ -20,10 +20,10 @@ import { writeIslandCanvasBootstrap } from "./island-canvas-bootstrap.js";
|
|
|
20
20
|
import { resolveScreenshotPath } from "./screenshot-target.js";
|
|
21
21
|
import { createDevViteServer } from "./vite-server.js";
|
|
22
22
|
import { resolveWorkspace } from "./workspace.js";
|
|
23
|
-
import { existsSync } from "node:fs";
|
|
24
|
-
import { dirname, extname, join, resolve, sep } from "node:path";
|
|
25
23
|
import { readFile } from "node:fs/promises";
|
|
24
|
+
import { dirname, extname, join, resolve, sep } from "node:path";
|
|
26
25
|
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { existsSync } from "node:fs";
|
|
27
27
|
import { createServer } from "node:http";
|
|
28
28
|
|
|
29
29
|
//#region src/cli/dev/server.ts
|
|
@@ -166,6 +166,7 @@ async function sendTemplatePage(ctx, templateKey, canvas, res) {
|
|
|
166
166
|
canvas
|
|
167
167
|
}));
|
|
168
168
|
}
|
|
169
|
+
const INITIAL_CSS_REV = "0";
|
|
169
170
|
async function sendTemplateSchema(ctx, url, res) {
|
|
170
171
|
const templateKey = url.searchParams.get("template");
|
|
171
172
|
if (!templateKey) {
|
|
@@ -184,6 +185,7 @@ async function sendTemplateSchema(ctx, url, res) {
|
|
|
184
185
|
const load = (dir, file) => ctx.vite.ssrLoadModule(join(dir, file));
|
|
185
186
|
const instances = await resolveManifestInstances(template);
|
|
186
187
|
const out = [];
|
|
188
|
+
const islands = {};
|
|
187
189
|
for (const inst of instances) {
|
|
188
190
|
const { schemaSlots } = await loadSectionBundle(inst.sectionDir, load);
|
|
189
191
|
out.push({
|
|
@@ -192,10 +194,14 @@ async function sendTemplateSchema(ctx, url, res) {
|
|
|
192
194
|
fixture: inst.fixture,
|
|
193
195
|
slotSchema: projectSlotSchema(schemaSlots)
|
|
194
196
|
});
|
|
197
|
+
Object.assign(islands, await buildSectionIslandMap(ctx.workspace.root, ctx.workspace.templatesDir, inst.sectionDir));
|
|
195
198
|
}
|
|
196
199
|
sendJson(res, {
|
|
197
200
|
template: templateKey,
|
|
198
|
-
instances: out
|
|
201
|
+
instances: out,
|
|
202
|
+
islands,
|
|
203
|
+
bootstrapUrl: ctx.canvasIslandBootstrapUrl,
|
|
204
|
+
cssRev: INITIAL_CSS_REV
|
|
199
205
|
});
|
|
200
206
|
}
|
|
201
207
|
async function findSection(ctx, match) {
|
package/dist/cli/dev/tailwind.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveFromWorkspace } from "../check/resolve-tool.js";
|
|
2
|
-
import { existsSync, statSync } from "node:fs";
|
|
3
2
|
import { isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/dev/tsconfig-paths-plugin.ts
|
|
6
6
|
const RESOLVE_EXTENSIONS = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
3
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/dev/workspace.ts
|
|
6
6
|
/** Walk up from `cwd` to the nearest ancestor that contains a `templates/` dir. */
|
package/dist/cli/link/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { KIT_PKG_SUBPATH, findKitRoot, overlayKit, readLinkMarker } from "./overlay.js";
|
|
2
2
|
import { findWorkspaceRoot } from "../check/workspace.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { parseArgs, promisify } from "node:util";
|
|
5
4
|
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
7
|
|
|
8
8
|
//#region src/cli/link/index.ts
|
package/dist/cli/link/overlay.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { KIT_VERSION } from "../../index.js";
|
|
2
|
-
import { dirname, join, resolve } from "node:path";
|
|
3
2
|
import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/link/overlay.ts
|
|
6
6
|
const KIT_PKG_SUBPATH = join("node_modules", "@homepages", "template-kit");
|
package/dist/cli/new/emit.js
CHANGED
package/dist/cli/new/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { findWorkspaceRoot } from "../check/workspace.js";
|
|
2
2
|
import { emitTree } from "./emit.js";
|
|
3
3
|
import { sectionAssetsDir, templateAssetsDir } from "./scaffold-assets.js";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
4
|
import { join } from "node:path";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
6
|
|
|
7
7
|
//#region src/cli/new/index.ts
|
|
8
8
|
const KEY_RE = /^[a-z][a-z0-9-]*$/;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
1
|
import { dirname, join } from "node:path";
|
|
3
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
4
|
|
|
5
5
|
//#region src/cli/new/scaffold-assets.ts
|
|
6
6
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
function assetsRoot() {
|
|
8
8
|
const dist = join(here, "scaffold");
|
|
9
9
|
if (existsSync(dist)) return dist;
|
|
10
|
-
return join(here, "..", "..", "..", "..", "create-
|
|
10
|
+
return join(here, "..", "..", "..", "..", "create-workspace", "scaffold");
|
|
11
11
|
}
|
|
12
12
|
function templateAssetsDir() {
|
|
13
13
|
return join(assetsRoot(), "template");
|
package/dist/cli/pack/collect.js
CHANGED
package/dist/cli/pack/guards.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readLinkMarker } from "../link/overlay.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
//#region src/cli/pack/guards.ts
|
|
7
7
|
const depsSchema = z.object({
|
package/dist/cli/pack/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { collectTemplateFiles, contentHash } from "./collect.js";
|
|
|
4
4
|
import { preflightGuards } from "./guards.js";
|
|
5
5
|
import { buildPackManifest } from "./manifest.js";
|
|
6
6
|
import { buildZip } from "./zip.js";
|
|
7
|
-
import { join } from "node:path";
|
|
8
7
|
import { parseArgs } from "node:util";
|
|
9
8
|
import { readFile, writeFile } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
10
|
|
|
11
11
|
//#region src/cli/pack/index.ts
|
|
12
12
|
function refusal(lines) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TokenThemeSchema, compileThemeToCss } from "../../design-system/theme.js";
|
|
2
2
|
import { loadTheme } from "./load-theme.js";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
//#region src/cli/theme/generate.ts
|
|
7
7
|
const OUT_FILE = "theme.css";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadEsbuild } from "../check/resolve-tool.js";
|
|
2
|
-
import { join } from "node:path";
|
|
3
2
|
import { mkdir, readFile, rm, stat } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@theme inline{ --color-canvas: #ffffff; --color-line: #ebebe6; }:root{--frame: clamp(1px, calc(1px + (100vw - 1536px) * .0006076), 1.41667px);--content-follow: .25;--content: calc(1px + (var(--frame) - 1px) * var(--content-follow))}*{box-sizing:border-box}html,body,#root{margin:0;padding:0;height:100%;background:#0f1115;color:#e6e7eb;font:14px/1.5 ui-sans-serif,system-ui,-apple-system,Segoe UI,Helvetica,Arial,sans-serif}a{color:inherit;text-decoration:none}button,select,input,textarea{font:inherit;color:inherit;background:#1a1d24;border:1px solid #2c313a;border-radius:4px;padding:6px 10px}button{cursor:pointer}button:hover{background:#232831}button:disabled{opacity:.4;cursor:default}.empty{padding:40px;color:#9ca0a8;text-align:center}.boot-error{padding:24px;color:#ff8b8b;font:13px/1.5 ui-monospace,Menlo,monospace;white-space:pre-wrap}.canvas-mirror{display:flex;flex-direction:column;height:100%;min-height:0}.canvas-iframe{width:100%;height:100%;border:0;background:#fff}.home{max-width:880px;margin:0 auto;padding:40px 24px}.home-header{margin-bottom:28px}.home-title{font-size:15px;font-weight:600}.home-tagline{font-size:13px;color:#9ca0a8;margin-top:4px}.home-template{display:inline-flex;align-items:center;gap:8px;font-size:12px;color:#9ca0a8;margin-bottom:24px}.home-template select{min-width:160px}.home-tools{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.tool-card{display:flex;flex-direction:column;gap:12px;background:#14171c;border:1px solid #21252d;border-radius:8px;padding:20px}.tool-card h2{font-size:14px;font-weight:600;margin:0}.tool-card p{font-size:13px;color:#9ca0a8;margin:0;line-height:1.5}.tool-card .controls{display:flex;flex-direction:column;gap:8px}.tool-card label{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px;color:#9ca0a8}.tool-card label select{min-width:140px}.open-btn{margin-top:auto;text-align:center;padding:8px 12px;border:1px solid #2c313a;border-radius:6px;background:#1a1d24;color:inherit;cursor:pointer}.open-btn:hover{background:#232831}.open-btn:disabled{opacity:.4;cursor:default}.home-hint{font-size:12px;color:#6b7280}.canvas-mirror__stage{position:relative;min-height:0;flex:1;overflow:hidden}.canvas-mirror__stage .canvas-iframe{position:absolute;top:0;right:0;bottom:0;left:0}.canvas-mirror__sidebar{position:absolute;top:20px;right:20px;bottom:20px;z-index:20;width:calc(400 * var(--frame));display:flex;flex-direction:column;min-height:0}@media(max-width:1100px){.canvas-mirror__sidebar{width:388px}}.instance-panel{flex:1 1 auto;min-height:0;overflow-y:auto;border-left:1px solid #e5e7eb;padding:12px;background:#fff;font:13px system-ui,sans-serif;display:flex;flex-direction:column;gap:10px}.instance-panel__head{display:flex;align-items:flex-end;justify-content:space-between;gap:8px;padding-bottom:10px;border-bottom:1px solid #e5e7eb}.instance-panel__slot{display:flex;align-items:center;gap:8px}.instance-panel__type{color:#6b7280}.instance-panel__fill{margin-left:auto;padding:1px 7px;border-radius:999px;font-size:11px}.instance-panel__fill--filled{background:#dcfce7;color:#166534}.instance-panel__fill--empty{background:#f3f4f6;color:#6b7280}.instance-panel__fill--missing{background:#fee2e2;color:#991b1b}.instance-panel__fixture{display:flex;flex-direction:column;gap:3px;color:#6b7280}.instance-panel__json{width:100%;min-height:180px;font:12px ui-monospace,monospace;resize:vertical}.instance-panel__error{color:#b91c1c;white-space:pre-wrap}.instance-panel__actions{display:flex;gap:8px}.instance-panel__slot-editor{display:flex;flex-direction:column;gap:8px;padding:10px 0;border-top:1px solid #f0f1f3}.instance-panel__slot-editor:first-of-type{border-top:0;padding-top:0}.instance-panel__slot-editor--selected{border-left:3px solid #b8860b;padding-left:9px;margin-left:-12px}
|