editor-shell 0.3.0 → 0.5.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/dist/{chunk-WJIHF6PY.js → chunk-3VMFPQGZ.js} +4 -61
- package/dist/chunk-3VMFPQGZ.js.map +1 -0
- package/dist/chunk-UB3KPBFP.js +1263 -0
- package/dist/chunk-UB3KPBFP.js.map +1 -0
- package/dist/icons/index.d.ts +189 -0
- package/dist/icons/index.js +3 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/panel/index.d.ts +99 -0
- package/dist/panel/index.js +100 -0
- package/dist/panel/index.js.map +1 -0
- package/dist/panel/panel.css +188 -0
- package/dist/rail/index.d.ts +3 -29
- package/dist/rail/index.js +2 -1
- package/package.json +11 -2
- package/dist/chunk-WJIHF6PY.js.map +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* editor-shell/panel.css — the settings-panel grammar.
|
|
3
|
+
*
|
|
4
|
+
* Values come from the shell token layer (`editor-shell/shell.css`), never from
|
|
5
|
+
* literals: this file is the storefront editor's approved panel design expressed
|
|
6
|
+
* once, so both editors read the same rules. Light only — neither editor has a
|
|
7
|
+
* dark mode.
|
|
8
|
+
*
|
|
9
|
+
* Two details are deliberate and were decided by measurement, not taste:
|
|
10
|
+
* · rows sit 20px apart while a label sits 7px from its own control, so a
|
|
11
|
+
* setting reads as ONE thing with air around it;
|
|
12
|
+
* · the label is small and grey, the value is larger and dark. Before that
|
|
13
|
+
* contrast existed, a merchant could not tell a name from a number.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/* ── the tab strip ─────────────────────────────────────────────────────────── */
|
|
17
|
+
|
|
18
|
+
.es-tabs {
|
|
19
|
+
display: flex;
|
|
20
|
+
gap: 2px;
|
|
21
|
+
padding: 0 14px;
|
|
22
|
+
border-bottom: 1px solid var(--es-divider);
|
|
23
|
+
background: var(--es-panel);
|
|
24
|
+
flex: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.es-tab {
|
|
28
|
+
border: 0;
|
|
29
|
+
background: transparent;
|
|
30
|
+
font: inherit;
|
|
31
|
+
font-size: 12px;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
color: var(--es-muted);
|
|
34
|
+
padding: 9px 10px 8px;
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
/* The active rule sits ON the strip's own border, not under it. */
|
|
37
|
+
border-bottom: 2px solid transparent;
|
|
38
|
+
margin-bottom: -1px;
|
|
39
|
+
display: inline-flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: 6px;
|
|
42
|
+
transition: color 0.12s;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.es-tab:hover { color: var(--es-text); }
|
|
46
|
+
|
|
47
|
+
.es-tab.is-active {
|
|
48
|
+
color: var(--es-accent-text);
|
|
49
|
+
border-bottom-color: var(--es-accent);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.es-tab-badge {
|
|
53
|
+
min-width: 16px;
|
|
54
|
+
height: 16px;
|
|
55
|
+
padding: 0 5px;
|
|
56
|
+
border-radius: 999px;
|
|
57
|
+
background: var(--es-accent);
|
|
58
|
+
color: var(--es-on-accent);
|
|
59
|
+
font-size: 10px;
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
display: inline-flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* ── a group: the soft pill row that folds ─────────────────────────────────── */
|
|
67
|
+
|
|
68
|
+
.es-group + .es-group { margin-top: 6px; }
|
|
69
|
+
|
|
70
|
+
.es-group-head {
|
|
71
|
+
width: 100%;
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 8px;
|
|
75
|
+
border: 0;
|
|
76
|
+
cursor: pointer;
|
|
77
|
+
text-align: left;
|
|
78
|
+
font: inherit;
|
|
79
|
+
font-size: 12px;
|
|
80
|
+
font-weight: 600;
|
|
81
|
+
color: var(--es-text);
|
|
82
|
+
background: var(--es-hover);
|
|
83
|
+
border-radius: var(--es-row-radius);
|
|
84
|
+
padding: 8px 11px;
|
|
85
|
+
margin: 20px 0 0;
|
|
86
|
+
transition: background 0.12s;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.es-group-head:hover { background: var(--es-chip-bg); }
|
|
90
|
+
|
|
91
|
+
.es-group-count {
|
|
92
|
+
min-width: 16px;
|
|
93
|
+
height: 16px;
|
|
94
|
+
padding: 0 5px;
|
|
95
|
+
border-radius: 999px;
|
|
96
|
+
background: var(--es-accent);
|
|
97
|
+
color: var(--es-on-accent);
|
|
98
|
+
font-size: 10px;
|
|
99
|
+
font-weight: 700;
|
|
100
|
+
display: inline-flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* The sign is drawn from aria-expanded so the open state has ONE home. */
|
|
106
|
+
.es-group-sign {
|
|
107
|
+
margin-left: auto;
|
|
108
|
+
width: 16px;
|
|
109
|
+
text-align: center;
|
|
110
|
+
color: var(--es-muted);
|
|
111
|
+
font-size: 14px;
|
|
112
|
+
line-height: 1;
|
|
113
|
+
flex: none;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.es-group-head[aria-expanded='true'] .es-group-sign::before { content: '−'; }
|
|
117
|
+
.es-group-head[aria-expanded='false'] .es-group-sign::before { content: '+'; }
|
|
118
|
+
|
|
119
|
+
/* `hidden` on the body is the fold; this only stops a flex/grid parent from
|
|
120
|
+
overriding the attribute's own display:none. */
|
|
121
|
+
.es-group-body[hidden] { display: none; }
|
|
122
|
+
.es-group-body > .es-field:first-child { margin-top: 14px; }
|
|
123
|
+
|
|
124
|
+
/* ── one setting ───────────────────────────────────────────────────────────── */
|
|
125
|
+
|
|
126
|
+
.es-field { margin-top: 20px; }
|
|
127
|
+
|
|
128
|
+
.es-field-head {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
gap: 8px;
|
|
132
|
+
margin-bottom: 7px;
|
|
133
|
+
min-height: 16px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.es-field-name {
|
|
137
|
+
display: inline-flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
gap: 8px;
|
|
140
|
+
min-width: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.es-field-icon {
|
|
144
|
+
width: 16px;
|
|
145
|
+
height: 16px;
|
|
146
|
+
flex: none;
|
|
147
|
+
color: var(--es-icon);
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.es-field-icon svg { width: 16px; height: 16px; }
|
|
154
|
+
|
|
155
|
+
.es-field-label {
|
|
156
|
+
font-size: 11px;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
color: var(--es-muted);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.es-field.is-changed .es-field-label { color: var(--es-accent-text); }
|
|
162
|
+
|
|
163
|
+
.es-field-value {
|
|
164
|
+
margin-left: auto;
|
|
165
|
+
font-size: 12px;
|
|
166
|
+
color: var(--es-text);
|
|
167
|
+
font-variant-numeric: tabular-nums;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.es-field-ctl {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 8px;
|
|
174
|
+
min-width: 0;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.es-field-hint {
|
|
178
|
+
margin: 7px 0 0;
|
|
179
|
+
padding-left: 24px;
|
|
180
|
+
font-size: 11px;
|
|
181
|
+
line-height: 1.45;
|
|
182
|
+
color: var(--es-muted);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@media (prefers-reduced-motion: reduce) {
|
|
186
|
+
.es-tab,
|
|
187
|
+
.es-group-head { transition: none; }
|
|
188
|
+
}
|
package/dist/rail/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
export { AddIcon, LayersIcon, MediaIcon, PageIcon as PagesIcon, IconProps as RailIconProps, SitemapIcon, StylesIcon } from '../icons/index.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* One entry in the rail. A rail item is either a *view switch* (Pages, Layers,
|
|
@@ -79,33 +80,6 @@ declare function EditorRail({ items, ariaLabel, className }: EditorRailProps): r
|
|
|
79
80
|
*/
|
|
80
81
|
declare function EditorRailButton({ label, icon, active, disabled, onSelect, className, }: EditorRailButtonProps): react.JSX.Element;
|
|
81
82
|
|
|
82
|
-
/**
|
|
83
|
-
* The rail's bespoke icon set — shipped WITH the rail so no editor has to reach
|
|
84
|
-
* for its own icon library (the storefront uses simple-icons, the admin portal
|
|
85
|
-
* heroicons; neither is this rail's source of truth). The five view glyphs are
|
|
86
|
-
* the exact paths the storefront editor's rail already draws, relocated here so
|
|
87
|
-
* the shared rail is visually identical to its reference; `AddIcon` is new.
|
|
88
|
-
*
|
|
89
|
-
* Pure SVG, no interactivity, no browser globals — these render fine inside a
|
|
90
|
-
* React Server Component. Sized 18×18 by default (the storefront's rail size);
|
|
91
|
-
* pass `size` to override, or let `.es-rail-btn svg` in rail.css drive it.
|
|
92
|
-
*/
|
|
93
|
-
type RailIconProps = Omit<SVGProps<SVGSVGElement>, 'children'> & {
|
|
94
|
-
size?: number;
|
|
95
|
-
};
|
|
96
|
-
/** Pages — a document with a folded corner and text lines. */
|
|
97
|
-
declare function PagesIcon(props: RailIconProps): react.JSX.Element;
|
|
98
|
-
/** Layers — stacked sheets (the section / component tree). */
|
|
99
|
-
declare function LayersIcon(props: RailIconProps): react.JSX.Element;
|
|
100
|
-
/** Styles — a paint droplet with palette dots (site styles). */
|
|
101
|
-
declare function StylesIcon(props: RailIconProps): react.JSX.Element;
|
|
102
|
-
/** Media — an image frame with a sun and a mountain (the media library). */
|
|
103
|
-
declare function MediaIcon(props: RailIconProps): react.JSX.Element;
|
|
104
|
-
/** Sitemap — a root node branching to two page nodes (the visual sitemap). */
|
|
105
|
-
declare function SitemapIcon(props: RailIconProps): react.JSX.Element;
|
|
106
|
-
/** Add — the quick-add "+", drawn in the same weight and cap style as the set. */
|
|
107
|
-
declare function AddIcon(props: RailIconProps): react.JSX.Element;
|
|
108
|
-
|
|
109
83
|
/**
|
|
110
84
|
* Rail design tokens — the ONE source both apps' rails converge on.
|
|
111
85
|
*
|
|
@@ -183,4 +157,4 @@ declare const railCssVars: {
|
|
|
183
157
|
readonly accentTint: "--es-rail-accent-tint";
|
|
184
158
|
};
|
|
185
159
|
|
|
186
|
-
export {
|
|
160
|
+
export { EditorRail, EditorRailButton, type EditorRailButtonProps, type EditorRailItem, type EditorRailProps, type RailTokens, railCssVars, railTokens };
|
package/dist/rail/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { EditorRail, EditorRailButton, railCssVars, railTokens } from '../chunk-3VMFPQGZ.js';
|
|
2
|
+
export { AddIcon, LayersIcon, MediaIcon, PageIcon as PagesIcon, SitemapIcon, StylesIcon } from '../chunk-UB3KPBFP.js';
|
|
2
3
|
//# sourceMappingURL=index.js.map
|
|
3
4
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "editor-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Shared editor-chrome primitives for the EFFICIENT editors: EditorRail (a Next-16-safe left icon-rail leaf), the shell token layer, and GoldTextInput — type in place and watch the markup formatting appear as you type.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Lewis Liu",
|
|
@@ -28,6 +28,15 @@
|
|
|
28
28
|
"types": "./dist/rail/index.d.ts",
|
|
29
29
|
"import": "./dist/rail/index.js"
|
|
30
30
|
},
|
|
31
|
+
"./icons": {
|
|
32
|
+
"types": "./dist/icons/index.d.ts",
|
|
33
|
+
"import": "./dist/icons/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./panel": {
|
|
36
|
+
"types": "./dist/panel/index.d.ts",
|
|
37
|
+
"import": "./dist/panel/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./panel.css": "./dist/panel/panel.css",
|
|
31
40
|
"./rail.css": "./dist/rail/rail.css",
|
|
32
41
|
"./shell": {
|
|
33
42
|
"types": "./dist/shell/index.d.ts",
|
|
@@ -68,7 +77,7 @@
|
|
|
68
77
|
"typescript": "^5.3.0"
|
|
69
78
|
},
|
|
70
79
|
"scripts": {
|
|
71
|
-
"build": "tsup && cp src/rail/rail.css dist/rail/rail.css && cp src/shell/shell.css dist/shell/shell.css && cp src/gold/gold.css dist/gold/gold.css",
|
|
80
|
+
"build": "tsup && cp src/rail/rail.css dist/rail/rail.css && cp src/shell/shell.css dist/shell/shell.css && cp src/gold/gold.css dist/gold/gold.css && cp src/panel/panel.css dist/panel/panel.css",
|
|
72
81
|
"dev": "tsup --watch",
|
|
73
82
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
74
83
|
"test": "node scripts/test.mjs",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rail/EditorRailButton.tsx","../src/rail/EditorRail.tsx","../src/rail/icons.tsx","../src/rail/tokens.ts"],"names":["jsx"],"mappings":"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","file":"chunk-WJIHF6PY.js","sourcesContent":["import type { EditorRailButtonProps } from './types';\n\n/**\n * A single rail button: an icon in a 34×34 square that hovers, highlights when\n * active, and dims when disabled. Look only — the caller owns the click.\n *\n * `aria-pressed` is emitted **only** when `active` is a real boolean, so a view\n * toggle announces its pressed state while an action button (the quick-add \"+\",\n * whose item omits `active`) stays a plain button rather than a stuck toggle.\n */\nexport function EditorRailButton({\n label,\n icon,\n active,\n disabled,\n onSelect,\n className,\n}: EditorRailButtonProps) {\n const classes = ['es-rail-btn', active ? 'is-active' : '', className ?? '']\n .filter(Boolean)\n .join(' ');\n\n return (\n <button\n type=\"button\"\n className={classes}\n title={label}\n aria-label={label}\n aria-pressed={typeof active === 'boolean' ? active : undefined}\n disabled={disabled}\n onClick={disabled ? undefined : onSelect}\n >\n {icon}\n </button>\n );\n}\n","import { EditorRailButton } from './EditorRailButton';\nimport type { EditorRailProps } from './types';\n\n/**\n * The shared left icon-rail — one slim vertical strip of icon buttons that every\n * EFFICIENT editor uses to switch panels (Pages / Layers / Styles / Media /\n * Sitemap) and to quick-add (\"+\"). It is a **pure presentational switcher**: give\n * it `items[]`, it draws them; which one is `active` and what each does is the\n * host's business.\n *\n * No `'use client'` here on purpose — the rail has no hooks or state, so it is a\n * plain module a Next-16 server component can import and even statically render.\n * It's interactive only through the `onSelect` props the host passes, and the\n * host owns its client boundary (both editors' chrome are already client\n * components), so baking a directive into this leaf would only narrow where it\n * can be imported.\n *\n * A vertical `toolbar` (not a `tablist`), because the rail mixes view *toggles*\n * with plain *actions* like the quick-add — a toolbar of buttons models that\n * honestly, where a tablist would force every button to pretend to be a tab.\n */\nexport function EditorRail({ items, ariaLabel = 'Editor', className }: EditorRailProps) {\n return (\n <div\n className={['es-rail', className ?? ''].filter(Boolean).join(' ')}\n role=\"toolbar\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n >\n {items.map((item) => (\n <EditorRailButton\n key={item.id}\n label={item.label}\n icon={item.icon}\n active={item.active}\n disabled={item.disabled}\n onSelect={item.onSelect}\n />\n ))}\n </div>\n );\n}\n","import type { ReactNode, SVGProps } from 'react';\n\n/**\n * The rail's bespoke icon set — shipped WITH the rail so no editor has to reach\n * for its own icon library (the storefront uses simple-icons, the admin portal\n * heroicons; neither is this rail's source of truth). The five view glyphs are\n * the exact paths the storefront editor's rail already draws, relocated here so\n * the shared rail is visually identical to its reference; `AddIcon` is new.\n *\n * Pure SVG, no interactivity, no browser globals — these render fine inside a\n * React Server Component. Sized 18×18 by default (the storefront's rail size);\n * pass `size` to override, or let `.es-rail-btn svg` in rail.css drive it.\n */\nexport type RailIconProps = Omit<SVGProps<SVGSVGElement>, 'children'> & { size?: number };\n\nfunction Glyph({ size = 18, children, ...rest }: RailIconProps & { children: ReactNode }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.7}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...rest}\n >\n {children}\n </svg>\n );\n}\n\n/** Pages — a document with a folded corner and text lines. */\nexport function PagesIcon(props: RailIconProps) {\n return (\n <Glyph {...props}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z\" />\n <path d=\"M14 3v5h5\" />\n <path d=\"M9 13h6M9 17h6\" />\n </Glyph>\n );\n}\n\n/** Layers — stacked sheets (the section / component tree). */\nexport function LayersIcon(props: RailIconProps) {\n return (\n <Glyph {...props}>\n <path d=\"M12 3l9 5-9 5-9-5 9-5z\" />\n <path d=\"M3 13l9 5 9-5\" />\n </Glyph>\n );\n}\n\n/** Styles — a paint droplet with palette dots (site styles). */\nexport function StylesIcon(props: RailIconProps) {\n return (\n <Glyph {...props}>\n <path d=\"M12 3c-4.5 0-8 3.4-8 7.6 0 3 2.2 4.9 4.8 4.9 1 0 1.6.7 1.6 1.5 0 .5-.3.9-.3 1.4 0 .9.8 1.6 1.9 1.6 4.4 0 8-3.6 8-8C20 6.4 16.5 3 12 3z\" />\n <circle cx=\"8.5\" cy=\"10\" r=\"0.6\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"7.8\" r=\"0.6\" fill=\"currentColor\" />\n <circle cx=\"15.5\" cy=\"10\" r=\"0.6\" fill=\"currentColor\" />\n </Glyph>\n );\n}\n\n/** Media — an image frame with a sun and a mountain (the media library). */\nexport function MediaIcon(props: RailIconProps) {\n return (\n <Glyph {...props}>\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\" />\n <circle cx=\"8.5\" cy=\"9.5\" r=\"1.5\" />\n <path d=\"M21 16l-5-5-6 6\" />\n </Glyph>\n );\n}\n\n/** Sitemap — a root node branching to two page nodes (the visual sitemap). */\nexport function SitemapIcon(props: RailIconProps) {\n return (\n <Glyph {...props}>\n <rect x=\"9\" y=\"3\" width=\"6\" height=\"4.5\" rx=\"1\" />\n <rect x=\"3\" y=\"16.5\" width=\"6\" height=\"4.5\" rx=\"1\" />\n <rect x=\"15\" y=\"16.5\" width=\"6\" height=\"4.5\" rx=\"1\" />\n <path d=\"M12 7.5v4M6 16.5v-2.5h12v2.5M18 16.5v-2.5\" />\n </Glyph>\n );\n}\n\n/** Add — the quick-add \"+\", drawn in the same weight and cap style as the set. */\nexport function AddIcon(props: RailIconProps) {\n return (\n <Glyph {...props}>\n <path d=\"M12 5v14M5 12h14\" />\n </Glyph>\n );\n}\n","/**\n * Rail design tokens — the ONE source both apps' rails converge on.\n *\n * Every value below is taken verbatim from the storefront editor's rail\n * (`efficient-shop` → `storefront-editor.css`, the `.sf-rail` / `.sf-rail-btn`\n * rules), which is the visual reference. The admin portal's hand-rolled rail had\n * drifted (button 36 vs 34, icon 20 vs 18, radius 8 vs 9, a Tailwind accent\n * instead of a CSS var); these tokens end that drift.\n *\n * Exposed BOTH ways, per the same value:\n * - `railTokens` — this JS object, for anything that needs the numbers/colours\n * in code (inline styles, a theme bridge, a Storybook control);\n * - `rail.css` — the stylesheet, which declares the identical values as CSS\n * custom properties on `.es-rail` (names listed in `railCssVars`).\n *\n * Numeric fields are pixel magnitudes (unitless) so they compose in code; the\n * CSS applies the `px`.\n */\nexport const railTokens = {\n /** Rail column width. `--sf-rail-w: 46px`. */\n railWidth: 46,\n /** Vertical padding inside the rail (top === bottom). */\n railPaddingY: 8,\n /** Gap between buttons. */\n railGap: 4,\n /** Rail card corner radius. `--sf-panel-radius: 12px`. */\n railRadius: 12,\n /** Button hit-area (square). */\n buttonSize: 34,\n /** Button corner radius. */\n buttonRadius: 9,\n /** Icon glyph size. */\n iconSize: 18,\n /** Hover/active colour transition. */\n transition: 'background 0.12s, color 0.12s',\n /** Disabled-button opacity. */\n disabledOpacity: 0.35,\n color: {\n /** Rail card background. `--sf-panel`. */\n background: '#ffffff',\n /** Rail card shadow. `--sf-panel-shadow`. */\n shadow: '0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.06)',\n /** Idle icon colour. `--sf-muted` (gray-500). */\n idle: '#6b7280',\n /** Hover background. `--sf-hover` (gray-100). */\n hoverBg: '#f3f4f6',\n /** Hover icon colour. `--sf-text` (gray-900). */\n hoverFg: '#111827',\n /** Active icon colour. `--sf-accent` (blue-600). */\n accent: '#2563eb',\n /** Active background. `--sf-accent-tint` (blue-50). */\n accentTint: '#eff6ff',\n },\n} as const;\n\nexport type RailTokens = typeof railTokens;\n\n/**\n * The CSS custom-property name behind each token. `rail.css` sets these on\n * `.es-rail`; override any of them on (or above) the rail element to re-theme it\n * — e.g. `style={{ ['--es-rail-accent']: brand }}` — without shipping new CSS.\n */\nexport const railCssVars = {\n railWidth: '--es-rail-w',\n railPaddingY: '--es-rail-pad-y',\n railGap: '--es-rail-gap',\n railRadius: '--es-rail-radius',\n buttonSize: '--es-rail-btn-size',\n buttonRadius: '--es-rail-btn-radius',\n iconSize: '--es-rail-icon-size',\n background: '--es-rail-bg',\n shadow: '--es-rail-shadow',\n idle: '--es-rail-fg',\n hoverBg: '--es-rail-hover-bg',\n hoverFg: '--es-rail-hover-fg',\n accent: '--es-rail-accent',\n accentTint: '--es-rail-accent-tint',\n} as const;\n"]}
|