@motion-proto/live-tokens 0.5.0 → 0.6.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/README.md CHANGED
@@ -127,13 +127,56 @@ The components carry their own design-token aliases (declared inside each `.svel
127
127
 
128
128
  ### Styles
129
129
 
130
+ Editor chrome (`ui-editor.css`, `ui-form-controls.css`) and the icon font are
131
+ **auto-loaded by the editor pages themselves**; you don't import them. The
132
+ only stylesheet a consumer needs is a `tokens.css` declaring the design-token
133
+ CSS variables on `:root`.
134
+
135
+ You can use the package's default as a starting point:
136
+
137
+ ```ts
138
+ import '@motion-proto/live-tokens/starter/tokens.css';
139
+ import '@motion-proto/live-tokens/starter/site.css'; // optional: themed h1/p/a styles
140
+ import '@motion-proto/live-tokens/starter/fonts.css'; // optional: Fraunces + Manrope @font-face
141
+ ```
142
+
143
+ …or copy `node_modules/@motion-proto/live-tokens/src/styles/tokens.css` into
144
+ your project and edit. The editor will seed `themes/default.json` on first
145
+ run and you can promote your edits back into the file.
146
+
147
+ ## Consuming live-tokens from scratch
148
+
149
+ The minimum a consumer needs after `npm install @motion-proto/live-tokens`:
150
+
151
+ ```ts
152
+ // src/main.ts
153
+ import '@motion-proto/live-tokens/starter/tokens.css';
154
+ import { mount } from 'svelte';
155
+ import App from './App.svelte';
156
+
157
+ mount(App, { target: document.getElementById('app')! });
158
+ ```
159
+
160
+ ```svelte
161
+ <!-- src/App.svelte -->
162
+ <script lang="ts">
163
+ import Editor from '@motion-proto/live-tokens/editor';
164
+ </script>
165
+
166
+ <Editor />
167
+ ```
168
+
130
169
  ```ts
131
- import '@motion-proto/live-tokens/styles/ui-editor.css';
132
- import '@motion-proto/live-tokens/styles/form-controls.css';
133
- import '@motion-proto/live-tokens/styles/fonts.css';
170
+ // vite.config.ts
171
+ import { defineConfig } from 'vite';
172
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
173
+
174
+ export default defineConfig({
175
+ plugins: [svelte()],
176
+ });
134
177
  ```
135
178
 
136
- You'll also need your own `src/styles/tokens.css` declaring your design tokens as CSS variables on `:root`. Start from the package's default (`node_modules/@motion-proto/live-tokens/src/styles/tokens.css`) and overlay your overrides or let the editor seed `themes/default.json` on first run and promote it.
179
+ No `css: 'injected'` workaround, no `optimizeDeps` excludes `vite build` works as-is. (You'll want the full `themeFileApi` plugin from the Quick install section above when you're ready to persist edits to disk.)
137
180
 
138
181
  ## Greenfield? Use the starter
139
182
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 6/7.",
6
6
  "keywords": [
@@ -29,11 +29,12 @@
29
29
  "src/pages/ComponentEditorPage.svelte",
30
30
  "src/pages/ComponentEditorPage.svelte.d.ts",
31
31
  "src/styles/ui-editor.css",
32
- "src/styles/form-controls.css",
32
+ "src/styles/ui-form-controls.css",
33
33
  "src/styles/fonts.css",
34
34
  "src/styles/fonts",
35
35
  "src/styles/_padding.scss",
36
36
  "src/styles/tokens.css",
37
+ "src/styles/site.css",
37
38
  "src/data",
38
39
  "src/assets",
39
40
  "dist-plugin",
@@ -77,8 +78,9 @@
77
78
  "require": "./dist-plugin/index.cjs"
78
79
  },
79
80
  "./styles/ui-editor.css": "./src/styles/ui-editor.css",
80
- "./styles/form-controls.css": "./src/styles/form-controls.css",
81
- "./styles/fonts.css": "./src/styles/fonts.css"
81
+ "./starter/tokens.css": "./src/styles/tokens.css",
82
+ "./starter/site.css": "./src/styles/site.css",
83
+ "./starter/fonts.css": "./src/styles/fonts.css"
82
84
  },
83
85
  "scripts": {
84
86
  "dev": "vite",
@@ -90,7 +92,10 @@
90
92
  "build:plugin": "tsup src/vite-plugin/index.ts --out-dir dist-plugin --format esm,cjs --dts --external vite --platform node --clean",
91
93
  "build:lib": "npm run build:plugin",
92
94
  "deploy:local": "bash scripts/deploy-local.sh",
93
- "prepublishOnly": "npm run build:lib"
95
+ "check:no-style-imports": "node scripts/check-no-style-imports.mjs",
96
+ "check:editor-font-isolation": "node scripts/check-editor-font-isolation.mjs",
97
+ "check:smoke-install": "bash scripts/smoke-install.sh",
98
+ "prepublishOnly": "npm run check:no-style-imports && npm run check:editor-font-isolation && npm run build:lib && npm run check:smoke-install"
94
99
  },
95
100
  "peerDependencies": {
96
101
  "sass": "^1.0",
@@ -117,7 +117,7 @@
117
117
 
118
118
  <label>
119
119
  <span>Cancel button (left)</span>
120
- <select class="form-select" value={cancelVariant} onchange={setCancelVariant}>
120
+ <select class="ui-form-select" value={cancelVariant} onchange={setCancelVariant}>
121
121
  {#each BUTTON_VARIANTS as v}
122
122
  <option value={v}>{variantLabel(v)}</option>
123
123
  {/each}
@@ -125,7 +125,7 @@
125
125
  </label>
126
126
  <label>
127
127
  <span>Confirm button (right)</span>
128
- <select class="form-select" value={confirmVariant} onchange={setConfirmVariant}>
128
+ <select class="ui-form-select" value={confirmVariant} onchange={setConfirmVariant}>
129
129
  {#each BUTTON_VARIANTS as v}
130
130
  <option value={v}>{variantLabel(v)}</option>
131
131
  {/each}
@@ -122,7 +122,7 @@
122
122
  </label>
123
123
  <label>
124
124
  <span>Right button</span>
125
- <select class="form-select" bind:value={rightOption}>
125
+ <select class="ui-form-select" bind:value={rightOption}>
126
126
  {#each BUTTON_VARIANT_OPTIONS as v}
127
127
  <option value={v}>{variantLabel(v)}</option>
128
128
  {/each}
@@ -130,7 +130,7 @@
130
130
  </label>
131
131
  <label>
132
132
  <span>Left button</span>
133
- <select class="form-select" bind:value={leftOption}>
133
+ <select class="ui-form-select" bind:value={leftOption}>
134
134
  {#each BUTTON_VARIANT_OPTIONS as v}
135
135
  <option value={v}>{variantLabel(v)}</option>
136
136
  {/each}
@@ -499,7 +499,7 @@
499
499
 
500
500
  .cfm-title-row {
501
501
  display: flex;
502
- align-items: baseline;
502
+ align-items: center;
503
503
  gap: var(--ui-space-12);
504
504
  flex-wrap: wrap;
505
505
  }
@@ -518,6 +518,7 @@
518
518
  display: inline-flex;
519
519
  align-items: center;
520
520
  gap: var(--ui-space-6);
521
+ margin-left: auto;
521
522
  height: 26px;
522
523
  padding: 0 14px;
523
524
  font-size: var(--ui-font-size-xs);
@@ -8,6 +8,14 @@
8
8
  import { componentRegistryEntries, validateRegistryAgainstServerScan } from '../component-editor/registry';
9
9
  import { listComponents } from '../lib/componentConfigService';
10
10
  import { selectedComponent } from '../lib/editorViewStore';
11
+ // Editor chrome + form controls + icon font must be JS imports (not @import
12
+ // inside the style block) so Vite resolves them via the module graph
13
+ // regardless of how the consumer compiles Svelte CSS (external ?lang.css vs
14
+ // injected); otherwise the @import URLs leak to the browser and 404 against
15
+ // the consumer's root.
16
+ import '../styles/ui-editor.css';
17
+ import '../styles/ui-form-controls.css';
18
+ import '@fortawesome/fontawesome-free/css/all.min.css';
11
19
 
12
20
  let drawerOpen = $state(true);
13
21
 
@@ -167,7 +175,6 @@
167
175
  </div>
168
176
 
169
177
  <style>
170
- @import '../styles/ui-editor.css';
171
178
  .components-shell {
172
179
  --rail-w: 48px;
173
180
  display: grid;
@@ -5,6 +5,14 @@
5
5
  import { installEditorKeybindings } from '../lib/editorKeybindings';
6
6
  import { initializeEditorStore } from '../lib/editorStore';
7
7
  import { storageKey } from '../lib/editorConfig';
8
+ // Editor chrome + form controls + icon font must be JS imports (not @import
9
+ // inside the style block) so Vite resolves them via the module graph
10
+ // regardless of how the consumer compiles Svelte CSS (external ?lang.css vs
11
+ // injected); otherwise the @import URLs leak to the browser and 404 against
12
+ // the consumer's root.
13
+ import '../styles/ui-editor.css';
14
+ import '../styles/ui-form-controls.css';
15
+ import '@fortawesome/fontawesome-free/css/all.min.css';
8
16
 
9
17
  const inOverlay = typeof window !== 'undefined' && window.parent !== window;
10
18
 
@@ -46,8 +54,6 @@
46
54
  </div>
47
55
 
48
56
  <style>
49
- @import '../styles/ui-editor.css';
50
-
51
57
  .editor-page {
52
58
  min-height: 100vh;
53
59
  background: black;
@@ -0,0 +1,138 @@
1
+ /*
2
+ * Site Styles — global typography for the themed pages
3
+ *
4
+ * Unscoped element selectors (h1, h2, p, a, ul li, …) consume the design
5
+ * tokens in tokens.css and recolor with the user's theme. Loaded globally
6
+ * from main.ts.
7
+ *
8
+ * Pair with: ui-editor.css (--ui-* chrome, opposite scope — neutral and
9
+ * theme-immune; only loaded on editor pages).
10
+ */
11
+
12
+ h1 {
13
+ font-family: var(--font-display);
14
+ font-size: var(--font-size-4xl);
15
+ font-weight: var(--font-weight-semibold);
16
+ color: var(--text-primary);
17
+ margin: 0 0 var(--space-12);
18
+ line-height: var(--line-height-sm);
19
+ overflow-wrap: break-word;
20
+ }
21
+
22
+ h2 {
23
+ font-family: var(--font-serif);
24
+ font-size: var(--font-size-2xl);
25
+ font-weight: var(--font-weight-semibold);
26
+ color: var(--text-primary);
27
+ letter-spacing: 0.01em;
28
+ margin: var(--space-32) 0 var(--space-12);
29
+ line-height: var(--line-height-sm);
30
+ overflow-wrap: break-word;
31
+ }
32
+
33
+ h3 {
34
+ font-family: var(--font-serif);
35
+ font-size: var(--font-size-xl);
36
+ font-weight: var(--font-weight-normal);
37
+ color: var(--text-primary);
38
+ margin: var(--space-24) 0 var(--space-8);
39
+ line-height: var(--line-height-sm);
40
+ overflow-wrap: break-word;
41
+ }
42
+
43
+ @media (max-width: 768px) {
44
+ h1 {
45
+ line-height: 1.1;
46
+ margin-bottom: var(--space-8);
47
+ }
48
+
49
+ h2 {
50
+ line-height: 1.15;
51
+ margin-top: var(--space-24);
52
+ }
53
+
54
+ h3 {
55
+ line-height: 1.2;
56
+ margin-top: var(--space-20);
57
+ }
58
+ }
59
+
60
+ p {
61
+ font-family: var(--font-serif);
62
+ font-size: var(--font-size-md);
63
+ color: var(--text-secondary);
64
+ line-height: var(--line-height-md);
65
+ margin: 0 0 14px;
66
+ }
67
+
68
+ p:last-child {
69
+ margin-bottom: 0;
70
+ }
71
+
72
+ a {
73
+ color: var(--text-brand);
74
+ text-decoration: none;
75
+ transition: color var(--duration-150);
76
+ }
77
+
78
+ a:hover {
79
+ color: var(--color-brand-300);
80
+ text-decoration: underline;
81
+ }
82
+
83
+ strong {
84
+ color: var(--text-primary);
85
+ font-weight: var(--font-weight-semibold);
86
+ }
87
+
88
+ ul {
89
+ padding-left: var(--space-24);
90
+ margin: var(--space-12) 0;
91
+ }
92
+
93
+ ul li {
94
+ font-family: var(--font-serif);
95
+ font-size: var(--font-size-md);
96
+ color: var(--text-secondary);
97
+ line-height: 1.75;
98
+ margin-bottom: var(--space-4);
99
+ }
100
+
101
+ ul li::marker {
102
+ color: var(--text-tertiary);
103
+ }
104
+
105
+ ol {
106
+ padding-left: var(--space-24);
107
+ margin: var(--space-12) 0;
108
+ }
109
+
110
+ ol li {
111
+ font-family: var(--font-sans);
112
+ font-size: var(--font-size-md);
113
+ color: var(--text-secondary);
114
+ line-height: 1.6;
115
+ margin-bottom: var(--space-4);
116
+ }
117
+
118
+ ol li::marker {
119
+ color: var(--text-tertiary);
120
+ font-weight: var(--font-weight-semibold);
121
+ }
122
+
123
+ hr {
124
+ border: none;
125
+ border-top: 1px solid var(--border-neutral-faint);
126
+ margin: var(--space-32) 0;
127
+ }
128
+
129
+ blockquote {
130
+ margin: var(--space-16) 0;
131
+ padding: var(--space-12) var(--space-20);
132
+ border: 1px solid var(--color-brand-500);
133
+ border-left: 4px solid var(--color-brand-500);
134
+ background: var(--surface-neutral-high);
135
+ border-radius: 0 var(--radius-md) var(--radius-md) 0;
136
+ color: var(--text-secondary);
137
+ font-style: italic;
138
+ }
@@ -1298,3 +1298,27 @@
1298
1298
  --sectiondivider-special-description-font-weight: var(--font-weight-normal);
1299
1299
  --sectiondivider-special-description-line-height: var(--line-height-md);
1300
1300
  }
1301
+
1302
+ /* component-aliases:start */
1303
+ :root:root {
1304
+ /* button (default_01) */
1305
+ --button-primary-radius: var(--radius-full);
1306
+ --button-primary-hover-radius: var(--radius-full);
1307
+ --button-primary-disabled-radius: var(--radius-full);
1308
+ --button-secondary-radius: var(--radius-full);
1309
+ --button-secondary-hover-radius: var(--radius-full);
1310
+ --button-secondary-disabled-radius: var(--radius-full);
1311
+ --button-outline-radius: var(--radius-full);
1312
+ --button-outline-hover-radius: var(--radius-full);
1313
+ --button-outline-disabled-radius: var(--radius-full);
1314
+ --button-success-radius: var(--radius-full);
1315
+ --button-success-hover-radius: var(--radius-full);
1316
+ --button-success-disabled-radius: var(--radius-full);
1317
+ --button-danger-radius: var(--radius-full);
1318
+ --button-danger-hover-radius: var(--radius-full);
1319
+ --button-danger-disabled-radius: var(--radius-full);
1320
+ --button-warning-radius: var(--radius-full);
1321
+ --button-warning-hover-radius: var(--radius-full);
1322
+ --button-warning-disabled-radius: var(--radius-full);
1323
+ }
1324
+ /* component-aliases:end */
@@ -0,0 +1,186 @@
1
+ /* Editor form controls — `--ui-*` tokens only. Theme-immune; see CONVENTIONS.md. */
2
+
3
+ /* ========================================
4
+ Form Field Layouts
5
+ ======================================== */
6
+
7
+ /* Vertical Layout - Label Above Input/Select */
8
+ /* Usage: Add .ui-form-field-vertical to container div wrapping label + input/select */
9
+ .ui-form-field-vertical {
10
+ display: flex;
11
+ flex-direction: column;
12
+ align-items: stretch;
13
+ gap: var(--ui-space-4);
14
+ }
15
+
16
+ .ui-form-label {
17
+ margin-bottom: 0;
18
+ font-size: var(--ui-font-size-md);
19
+ color: var(--ui-text-primary);
20
+ font-weight: var(--ui-font-weight-normal);
21
+ }
22
+
23
+ /* Horizontal Layout - Label Beside Input/Select */
24
+ /* Usage: Add .ui-form-field-horizontal to container div wrapping label + input/select */
25
+ .ui-form-field-horizontal {
26
+ display: flex;
27
+ justify-content: space-between;
28
+ align-items: center;
29
+ gap: var(--ui-space-8);
30
+ }
31
+
32
+ .ui-form-field-horizontal .ui-form-label {
33
+ white-space: nowrap;
34
+ }
35
+
36
+ /* Inline Layout - Label and Input/Select Close Together */
37
+ /* Usage: Add .ui-form-field-inline to container div wrapping label + input/select */
38
+ .ui-form-field-inline {
39
+ display: flex;
40
+ align-items: center;
41
+ gap: var(--ui-space-12);
42
+ }
43
+
44
+ .ui-form-field-inline .ui-form-label {
45
+ white-space: nowrap;
46
+ flex-shrink: 0;
47
+ }
48
+
49
+ .ui-form-field-inline .ui-form-select,
50
+ .ui-form-field-inline .ui-form-input {
51
+ flex-shrink: 0;
52
+ }
53
+
54
+ /* ========================================
55
+ Form Control Styling
56
+ ======================================== */
57
+
58
+ /* Select/Dropdown Styling */
59
+ .ui-form-select {
60
+ /* No vertical padding - let min-height and line-height center text naturally */
61
+ padding: 0 var(--ui-space-16);
62
+ min-height: 2.375rem; /* ~38px to match button height */
63
+ background: var(--ui-surface-lowest) !important;
64
+ border: 1px solid var(--ui-border-default) !important;
65
+ border-radius: var(--ui-radius-md);
66
+ color: var(--ui-text-primary) !important;
67
+ font-family: var(--ui-font-sans);
68
+ font-size: var(--ui-font-size-md);
69
+ font-weight: var(--ui-font-weight-normal);
70
+ line-height: var(--ui-line-height-normal);
71
+ vertical-align: middle;
72
+ cursor: pointer;
73
+ transition: all var(--ui-transition-fast);
74
+ /* Prevent clipping */
75
+ overflow: visible !important;
76
+ box-sizing: border-box !important;
77
+ /* Reset browser defaults */
78
+ -webkit-appearance: none;
79
+ -moz-appearance: none;
80
+ appearance: none;
81
+ /* Custom dropdown arrow */
82
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888' d='M6 8L1 3h10z'/%3E%3C/svg%3E") !important;
83
+ background-repeat: no-repeat !important;
84
+ background-position: right var(--ui-space-12) center !important;
85
+ padding-right: var(--ui-space-32) !important;
86
+ }
87
+
88
+ .ui-form-select:hover:not(:disabled) {
89
+ background-color: var(--ui-surface-low) !important;
90
+ border-color: var(--ui-border-medium) !important;
91
+ }
92
+
93
+ .ui-form-select:focus {
94
+ outline: none;
95
+ border-color: var(--ui-border-strong) !important;
96
+ box-shadow: 0 0 0 2px hsla(0, 58%, 50%, 0.2);
97
+ }
98
+
99
+ .ui-form-select:focus-visible {
100
+ outline: 2px solid var(--ui-highlight);
101
+ outline-offset: 2px;
102
+ }
103
+
104
+ .ui-form-select:active:not(:disabled) {
105
+ background-color: var(--ui-surface) !important;
106
+ }
107
+
108
+ .ui-form-select:disabled {
109
+ background-color: var(--ui-surface-lowest) !important;
110
+ border-color: var(--ui-border-faint) !important;
111
+ color: var(--ui-text-disabled) !important;
112
+ cursor: not-allowed;
113
+ }
114
+
115
+ /* Option Styling - Critical for Legibility */
116
+ /* Note: Most option styling is controlled by browser/OS and cannot be fully overridden */
117
+ /* These styles apply where browsers allow (limited support in Chrome/Firefox) */
118
+ .ui-form-select option {
119
+ background-color: var(--ui-surface-lowest) !important;
120
+ color: var(--ui-text-primary) !important;
121
+ padding: var(--ui-space-8) var(--ui-space-12);
122
+ min-height: 2rem;
123
+ font-size: var(--ui-font-size-md);
124
+ font-family: var(--ui-font-sans);
125
+ line-height: var(--ui-line-height-normal);
126
+ }
127
+
128
+ /* Disabled options */
129
+ .ui-form-select option:disabled {
130
+ color: var(--ui-text-disabled) !important;
131
+ }
132
+
133
+ /* Input Field Styling */
134
+ .ui-form-input {
135
+ padding: var(--ui-space-8);
136
+ background: var(--ui-surface-lowest);
137
+ border: 1px solid var(--ui-border-default);
138
+ border-radius: var(--ui-radius-md);
139
+ color: var(--ui-text-primary);
140
+ font-family: var(--ui-font-sans);
141
+ font-size: var(--ui-font-size-md);
142
+ transition: border-color var(--ui-transition-fast);
143
+ }
144
+
145
+ .ui-form-input:hover:not(:disabled) {
146
+ border-color: var(--ui-border-strong);
147
+ background: var(--ui-surface-low);
148
+ }
149
+
150
+ .ui-form-input:focus {
151
+ outline: none;
152
+ border-color: var(--ui-border-strong);
153
+ box-shadow: 0 0 0 3px hsla(240, 5%, 38%, 0.2);
154
+ }
155
+
156
+ .ui-form-input:disabled {
157
+ background: var(--ui-surface-lowest);
158
+ border-color: var(--ui-border-faint);
159
+ color: var(--ui-text-disabled);
160
+ cursor: not-allowed;
161
+ }
162
+
163
+ /* Placeholder text styling */
164
+ .ui-form-input::placeholder {
165
+ color: var(--ui-text-muted);
166
+ }
167
+
168
+ /* Number input spinner buttons */
169
+ .ui-form-input[type="number"]::-webkit-inner-spin-button,
170
+ .ui-form-input[type="number"]::-webkit-outer-spin-button {
171
+ opacity: 1;
172
+ }
173
+
174
+ /* Checkbox and Radio Styling */
175
+ .ui-form-checkbox,
176
+ .ui-form-radio {
177
+ cursor: pointer;
178
+ width: var(--ui-space-16);
179
+ height: var(--ui-space-16);
180
+ accent-color: var(--ui-gray-600);
181
+ }
182
+
183
+ .ui-form-checkbox:disabled,
184
+ .ui-form-radio:disabled {
185
+ cursor: not-allowed;
186
+ }
@@ -189,7 +189,7 @@
189
189
  style="font-family: {slotCssValue(slot)};{stack.variable === '--font-display' ? ' font-size: var(--ui-font-size-2xl);' : ''}"
190
190
  >The quick brown fox jumps over the lazy dog</span>
191
191
  <select
192
- class="form-select slot-select"
192
+ class="ui-form-select slot-select"
193
193
  value={slotKey(slot)}
194
194
  onchange={(e) => onSelectChange(e, stack.variable, i)}
195
195
  >
@@ -252,7 +252,7 @@
252
252
  {#if addMode === 'google'}
253
253
  <input
254
254
  type="text"
255
- class="form-input"
255
+ class="ui-form-input"
256
256
  placeholder="Search Google Fonts (e.g. Inter)"
257
257
  bind:value={googleQuery}
258
258
  />
@@ -271,7 +271,7 @@
271
271
  {:else if addMode === 'url'}
272
272
  <input
273
273
  type="text"
274
- class="form-input"
274
+ class="ui-form-input"
275
275
  placeholder="https://fonts.googleapis.com/css2?family=... or Typekit URL"
276
276
  bind:value={urlInput}
277
277
  />
@@ -310,7 +310,7 @@
310
310
  <div class="pf-detected">Couldn't auto-detect families (CORS or no metadata). Name them:</div>
311
311
  <input
312
312
  type="text"
313
- class="form-input"
313
+ class="ui-form-input"
314
314
  placeholder="Comma-separated family names"
315
315
  bind:value={urlManualFamilies}
316
316
  />
@@ -318,7 +318,7 @@
318
318
  {/if}
319
319
  {:else if addMode === 'fontface'}
320
320
  <textarea
321
- class="form-input pf-textarea"
321
+ class="ui-form-input pf-textarea"
322
322
  placeholder={'Paste one or more @font-face { ... } rules'}
323
323
  rows="6"
324
324
  bind:value={fontFaceText}
@@ -1,188 +0,0 @@
1
- /* Form Controls - Global Styling for Dropdowns, Selects, Inputs */
2
- /* Ensures consistent, legible styling across the application */
3
-
4
- /* ========================================
5
- Form Field Layouts
6
- ======================================== */
7
-
8
- /* Vertical Layout - Label Above Input/Select */
9
- /* Usage: Add .form-field-vertical to container div wrapping label + input/select */
10
- .form-field-vertical {
11
- display: flex;
12
- flex-direction: column;
13
- align-items: stretch;
14
- gap: var(--space-4);
15
- }
16
-
17
- .form-label {
18
- margin-bottom: 0;
19
- font-size: var(--font-size-md);
20
- color: var(--text-primary);
21
- font-weight: var(--font-weight-light);
22
- }
23
-
24
- /* Horizontal Layout - Label Beside Input/Select */
25
- /* Usage: Add .form-field-horizontal to container div wrapping label + input/select */
26
- .form-field-horizontal {
27
- display: flex;
28
- justify-content: space-between;
29
- align-items: center;
30
- gap: var(--space-8);
31
- }
32
-
33
- .form-field-horizontal .form-label {
34
- white-space: nowrap;
35
- }
36
-
37
- /* Inline Layout - Label and Input/Select Close Together */
38
- /* Usage: Add .form-field-inline to container div wrapping label + input/select */
39
- .form-field-inline {
40
- display: flex;
41
- align-items: center;
42
- gap: var(--space-12);
43
- }
44
-
45
- .form-field-inline .form-label {
46
- white-space: nowrap;
47
- flex-shrink: 0;
48
- }
49
-
50
- .form-field-inline .form-select,
51
- .form-field-inline .form-input {
52
- flex-shrink: 0;
53
- }
54
-
55
- /* ========================================
56
- Form Control Styling
57
- ======================================== */
58
-
59
- /* Select/Dropdown Styling - Design System Compliant */
60
- .form-select {
61
- /* Base styling using design system colors */
62
- /* No vertical padding - let min-height and line-height center text naturally */
63
- padding: 0 var(--space-16);
64
- min-height: 2.375rem; /* ~38px to match button height */
65
- background: var(--surface-neutral-lowest) !important;
66
- border: 1px solid var(--border-neutral) !important;
67
- border-radius: var(--radius-md);
68
- color: var(--text-primary) !important;
69
- font-family: var(--font-sans);
70
- font-size: var(--font-size-md);
71
- font-weight: var(--font-weight-light);
72
- line-height: var(--line-height-md);
73
- vertical-align: middle;
74
- cursor: pointer;
75
- transition: all var(--duration-150);
76
- /* Prevent clipping */
77
- overflow: visible !important;
78
- box-sizing: border-box !important;
79
- /* Reset browser defaults */
80
- -webkit-appearance: none;
81
- -moz-appearance: none;
82
- appearance: none;
83
- /* Custom dropdown arrow */
84
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888' d='M6 8L1 3h10z'/%3E%3C/svg%3E") !important;
85
- background-repeat: no-repeat !important;
86
- background-position: right var(--space-12) center !important;
87
- padding-right: var(--space-32) !important;
88
- }
89
-
90
- .form-select:hover:not(:disabled) {
91
- background-color: var(--surface-neutral-low) !important;
92
- border-color: var(--border-neutral-medium) !important;
93
- }
94
-
95
- .form-select:focus {
96
- outline: none;
97
- border-color: var(--border-neutral-strong) !important;
98
- box-shadow: 0 0 0 2px hsla(0, 58%, 50%, 0.2);
99
- }
100
-
101
- .form-select:focus-visible {
102
- outline: 2px solid var(--color-brand-500);
103
- outline-offset: 2px;
104
- }
105
-
106
- .form-select:active:not(:disabled) {
107
- background-color: var(--surface-neutral) !important;
108
- }
109
-
110
- .form-select:disabled {
111
- background-color: var(--surface-neutral-lowest) !important;
112
- border-color: var(--border-neutral-faint) !important;
113
- color: var(--text-disabled) !important;
114
- cursor: not-allowed;
115
- }
116
-
117
- /* Option Styling - Critical for Legibility */
118
- /* Note: Most option styling is controlled by browser/OS and cannot be fully overridden */
119
- /* These styles apply where browsers allow (limited support in Chrome/Firefox) */
120
- .form-select option {
121
- background-color: var(--surface-neutral-lowest) !important;
122
- color: var(--text-primary) !important;
123
- padding: var(--space-8) var(--space-12);
124
- min-height: 2rem;
125
- font-size: var(--font-size-md);
126
- font-family: var(--font-sans);
127
- line-height: var(--line-height-md);
128
- }
129
-
130
- /* Disabled options */
131
- .form-select option:disabled {
132
- color: var(--text-disabled) !important;
133
- }
134
-
135
- /* Input Field Styling */
136
- .form-input {
137
- padding: var(--space-8);
138
- background: var(--surface-neutral-lowest);
139
- border: 1px solid var(--border-neutral);
140
- border-radius: var(--radius-md);
141
- color: var(--text-primary);
142
- font-family: var(--font-sans);
143
- font-size: var(--font-size-md);
144
- transition: border-color var(--duration-150);
145
- }
146
-
147
- .form-input:hover:not(:disabled) {
148
- border-color: var(--border-neutral-strong);
149
- background: var(--surface-neutral-low);
150
- }
151
-
152
- .form-input:focus {
153
- outline: none;
154
- border-color: var(--border-neutral-strong);
155
- box-shadow: 0 0 0 3px hsla(240, 5%, 38%, 0.2);
156
- }
157
-
158
- .form-input:disabled {
159
- background: var(--surface-neutral-lowest);
160
- border-color: var(--border-neutral-faint);
161
- color: var(--text-disabled);
162
- cursor: not-allowed;
163
- }
164
-
165
- /* Placeholder text styling */
166
- .form-input::placeholder {
167
- color: var(--text-muted);
168
- }
169
-
170
- /* Number input spinner buttons */
171
- .form-input[type="number"]::-webkit-inner-spin-button,
172
- .form-input[type="number"]::-webkit-outer-spin-button {
173
- opacity: 1;
174
- }
175
-
176
- /* Checkbox and Radio Styling */
177
- .form-checkbox,
178
- .form-radio {
179
- cursor: pointer;
180
- width: var(--space-16);
181
- height: var(--space-16);
182
- accent-color: var(--color-neutral-400);
183
- }
184
-
185
- .form-checkbox:disabled,
186
- .form-radio:disabled {
187
- cursor: not-allowed;
188
- }