emily-css 1.0.26 → 1.0.28
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 +268 -242
- package/package.json +59 -59
- package/src/generators.js +12 -2
- package/src/index.js +507 -6
- package/src/purge.js +3 -3
- package/templates/showcase.html +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,259 +4,285 @@ All notable changes to `emily-css` are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## v1.0.
|
|
7
|
+
## v1.0.28 — May 2026
|
|
8
8
|
|
|
9
|
-
**
|
|
10
|
-
|
|
11
|
-
### Added
|
|
12
|
-
- Expand utility coverage and typography scale
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
## v1.0.26 — May 2026
|
|
16
|
-
|
|
17
|
-
**Colour utilities now variable-based; fix grey text on dark surfaces**
|
|
18
|
-
|
|
19
|
-
### Fixed
|
|
20
|
-
- `generateColourUtilities` now emits `var(--color-*)` references instead of hardcoded hex values for all `text-*`, `bg-*`, `border-*`, and `accent-*` utilities. Consistent with how semantic colours and ring/fill/stroke utilities already worked. Enables theme-layer overrides without specificity hacks.
|
|
21
|
-
- Homepage "How it works" cards: `text-neutral-80` / `text-neutral-40` on `bg-dark` produced near-invisible text in light mode (contrast ~2.3:1). Fixed to `text-neutral-10` / `text-neutral-30` — matches the pattern used by the hero and CTA banner.
|
|
22
|
-
- Removed erroneous backslash in `h-2\.5` HTML class strings in `index.vue` (rendered fine via Vue template compilation, but confusing and inconsistent).
|
|
23
|
-
- Stripped null bytes from `pages/index.vue` (6) and `package.json` (339) in `emilyui-site`.
|
|
9
|
+
**added new utilities**
|
|
24
10
|
|
|
25
11
|
### Changed
|
|
26
|
-
-
|
|
12
|
+
- added new utilties and tests
|
|
27
13
|
|
|
28
14
|
---
|
|
29
|
-
|
|
30
|
-
## v1.0.25 — May 2026
|
|
31
|
-
|
|
32
|
-
**updaed colour**
|
|
33
|
-
|
|
34
|
-
### Fixed
|
|
35
|
-
- change colour on code
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
## v1.0.24 — May 2026
|
|
15
|
+
## v1.0.27 — May 2026
|
|
39
16
|
|
|
40
17
|
**colour system redesign — brand/accent tokens + semantic colours (v1.0.23)**
|
|
41
18
|
|
|
42
19
|
### Added
|
|
43
20
|
- colour system redesign — brand/accent tokens + semantic colours (v1.0.23)
|
|
44
21
|
|
|
45
|
-
---
|
|
46
|
-
## v1.0.23 — May 2026
|
|
47
|
-
|
|
48
|
-
**Colour system redesign: brand/accent naming + semantic colour tokens**
|
|
49
|
-
|
|
50
22
|
### Changed
|
|
51
|
-
-
|
|
52
|
-
- `btn-primary` and `btn-secondary` are now explicit separate colour tokens (no longer aliases)
|
|
53
|
-
- Default config generated by `emily-css init` updated to reflect new naming
|
|
54
|
-
|
|
55
|
-
### Added
|
|
56
|
-
- `semanticColours` config key: single-value colour tokens with no shade scale
|
|
57
|
-
- `generateSemanticColourUtilities()`: generates `bg-dark`, `text-dark`, `border-dark`, `fill-dark` etc.
|
|
58
|
-
- Semantic colour utilities automatically pick up `hover:`, `focus:`, `dark:`, and responsive variants
|
|
59
|
-
- Default config includes `dark: "#1A1A1A"` and `light: "#FAFAFA"` as semantic colour examples
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## v1.0.22 — May 2026
|
|
64
|
-
|
|
65
|
-
**· Improve purge extraction and package robustness tests**
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
## v1.0.21 — May 2026
|
|
69
|
-
|
|
70
|
-
**"Include bundled showcase template**
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
## v1.0.20 — May 2026
|
|
74
|
-
|
|
75
|
-
**replace folder structure template to tempalates**
|
|
76
|
-
|
|
77
|
-
### Fixed
|
|
78
|
-
- replace folder structure template to tempalates
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
## v1.0.19 — May 2026
|
|
82
|
-
|
|
83
|
-
**Add framework-aware output paths and bundled showcase template**
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
## v1.0.18 — May 2026
|
|
87
|
-
|
|
88
|
-
****
|
|
89
|
-
|
|
90
|
-
### Changed
|
|
91
|
-
- added more utitlies as a code block
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
## v1.0.17 — May 2026
|
|
95
|
-
|
|
96
|
-
**added new utilties, and added component patterns**
|
|
97
|
-
|
|
98
|
-
### Added
|
|
99
|
-
- added new utilties, and added component patterns
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
## v1.0.16 — May 2026
|
|
103
|
-
|
|
104
|
-
**feat: add Round 2 utility set — 156/156 tests passing**
|
|
105
|
-
|
|
106
|
-
### Added
|
|
107
|
-
- feat: add Round 2 utility set — 156/156 tests passing
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
## v1.0.15 — May 2026
|
|
111
|
-
|
|
112
|
-
**updated readme**
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
## v1.0.14 — May 2026
|
|
116
|
-
|
|
117
|
-
**updated readme**
|
|
118
|
-
|
|
119
|
-
### Changed
|
|
120
|
-
- updated readme
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
## v1.0.13 — May 2026
|
|
124
|
-
|
|
125
|
-
**added functionality to commit to github and then push to npm release**
|
|
126
|
-
|
|
127
|
-
### Added
|
|
128
|
-
- added functionality to commit to github and then push to npm release
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
## v1.0.12 — May 2026
|
|
132
|
-
|
|
133
|
-
****
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
## v1.0.11 — May 2026
|
|
137
|
-
|
|
138
|
-
****
|
|
139
|
-
|
|
140
|
-
---
|
|
141
|
-
## v1.0.10 — May 2026
|
|
142
|
-
|
|
143
|
-
**Changelog automation**
|
|
144
|
-
|
|
145
|
-
### Added
|
|
146
|
-
- Release script (`npm run release`) — reads git log, prompts for version bump, writes CHANGELOG.md, commits and tags automatically
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## v1.0.9 — May 2026
|
|
151
|
-
|
|
152
|
-
**Showcase server + code block utilities**
|
|
153
|
-
|
|
154
|
-
### Added
|
|
155
|
-
- Showcase server — run `npm run emily:showcase` to browse components on localhost:3456
|
|
156
|
-
- Code block utilities (`.code-window`, `.token-*`) in generated CSS — VSCode Dark+ style syntax highlighting
|
|
157
|
-
- `pre`/`code` base styles added to `@layer base`
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## v1.0.8 — May 2026
|
|
162
|
-
|
|
163
|
-
**Watch mode + build pipeline**
|
|
164
|
-
|
|
165
|
-
### Added
|
|
166
|
-
- Watch mode — `npx emily-css watch` rebuilds CSS automatically on config change
|
|
167
|
-
- Build + purge can now be chained in a single pipeline
|
|
168
|
-
- npm scripts wired into `package.json` during `npx emily-css init`
|
|
169
|
-
|
|
170
|
-
### Changed
|
|
171
|
-
- `init.js` provides a more guided setup experience with clearer prompts
|
|
172
|
-
- `bin/emilyui.js` updated to correctly route `watch`/`build`/`purge` subcommands
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## v1.0.7 — April 2026
|
|
177
|
-
|
|
178
|
-
**Purge regex fix**
|
|
179
|
-
|
|
180
|
-
### Fixed
|
|
181
|
-
- Purge crashed when class names contained regex metacharacters (`[`, `]`, `(`, `)`, `{`, `}`, etc). Previously only `:` and `.` were escaped — now uses full metacharacter escaping
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## v1.0.6 — April 2026
|
|
186
|
-
|
|
187
|
-
**Dist + font cleanup**
|
|
188
|
-
|
|
189
|
-
### Changed
|
|
190
|
-
- `dist/` and `fonts/` directories removed from git tracking
|
|
191
|
-
|
|
192
|
-
### Breaking changes
|
|
193
|
-
- If you were pulling `dist/emily.css` directly from GitHub, run `npx emily-css build` locally instead
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
## v1.0.5 — April 2026
|
|
198
|
-
|
|
199
|
-
**Split font system**
|
|
200
|
-
|
|
201
|
-
### Added
|
|
202
|
-
- Separate heading and body font config — `fontFamily.heading` and `fontFamily.body` are now independent
|
|
203
|
-
- Google Fonts CDN integration — fonts loaded via `@import` in generated CSS
|
|
204
|
-
- Font-specific tests added to test suite
|
|
205
|
-
|
|
206
|
-
### Changed
|
|
207
|
-
- Bundled font files removed from the npm package
|
|
208
|
-
- `emily.config.json` updated with split `fontFamily` structure
|
|
209
|
-
|
|
210
|
-
### Breaking changes
|
|
211
|
-
- If your config has `fontFamily` as a single string, update it to `{ "heading": "...", "body": "..." }`
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## v1.0.3 — April 2026
|
|
216
|
-
|
|
217
|
-
**Package size reduction**
|
|
218
|
-
|
|
219
|
-
### Changed
|
|
220
|
-
- Demo CSS removed from the published npm package
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
## v1.0.2 — April 2026
|
|
225
|
-
|
|
226
|
-
**Package distribution fix**
|
|
227
|
-
|
|
228
|
-
### Added
|
|
229
|
-
- `.npmignore` added — controls which files are included in the published package
|
|
230
|
-
- `dist` files explicitly declared in `package.json` `files` array
|
|
231
|
-
|
|
232
|
-
### Fixed
|
|
233
|
-
- Unnecessary files (tests, src, docs) were being included in the npm tarball
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## v1.0.1 — April 2026
|
|
238
|
-
|
|
239
|
-
**CLI rename fix**
|
|
240
|
-
|
|
241
|
-
### Fixed
|
|
242
|
-
- Internal references to old `emily-ui` CLI name updated to `emily-css`
|
|
243
|
-
|
|
244
|
-
### Breaking changes
|
|
245
|
-
- If you had scripts referencing `npx emily-ui`, update them to `npx emily-css`
|
|
246
|
-
|
|
247
|
-
---
|
|
248
|
-
|
|
249
|
-
## v1.0.0 — April 2026
|
|
250
|
-
|
|
251
|
-
**Initial release**
|
|
252
|
-
|
|
253
|
-
### Added
|
|
254
|
-
- 11,844 utility classes generated from `emily.config.json`
|
|
255
|
-
- OKLCH colour scale generation — one hex in, 10-shade scale out
|
|
256
|
-
- Responsive variants (`sm:` `md:` `lg:` `xl:` `2xl:`)
|
|
257
|
-
- State variants (`hover:` `focus-visible:` `active:` `disabled:` `dark:`)
|
|
258
|
-
- Purge system — strips unused classes, ~97% file size reduction
|
|
259
|
-
- Interactive setup wizard (`npx emily-css init`)
|
|
260
|
-
- 72 tests, all passing
|
|
23
|
+
- updated utilties and new showcase
|
|
261
24
|
|
|
262
25
|
---
|
|
26
|
+
# Changelog
|
|
27
|
+
|
|
28
|
+
All notable changes to `emily-css` are documented here.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## v1.0.26 — May 2026
|
|
33
|
+
|
|
34
|
+
**Expand utility coverage and typography scale**
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- Expand utility coverage and typography scale
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
## v1.0.26 — May 2026
|
|
41
|
+
|
|
42
|
+
**Colour utilities now variable-based; fix grey text on dark surfaces**
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- `generateColourUtilities` now emits `var(--color-*)` references instead of hardcoded hex values for all `text-*`, `bg-*`, `border-*`, and `accent-*` utilities. Consistent with how semantic colours and ring/fill/stroke utilities already worked. Enables theme-layer overrides without specificity hacks.
|
|
46
|
+
- Homepage "How it works" cards: `text-neutral-80` / `text-neutral-40` on `bg-dark` produced near-invisible text in light mode (contrast ~2.3:1). Fixed to `text-neutral-10` / `text-neutral-30` — matches the pattern used by the hero and CTA banner.
|
|
47
|
+
- Removed erroneous backslash in `h-2\.5` HTML class strings in `index.vue` (rendered fine via Vue template compilation, but confusing and inconsistent).
|
|
48
|
+
- Stripped null bytes from `pages/index.vue` (6) and `package.json` (339) in `emilyui-site`.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
- `tests/test.js`: updated `accent-brand-80` assertion to expect `var(--color-brand-80)` rather than hardcoded hex, matching the new generation behaviour.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## v1.0.25 — May 2026
|
|
56
|
+
|
|
57
|
+
**updaed colour**
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
- change colour on code
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
## v1.0.24 — May 2026
|
|
64
|
+
|
|
65
|
+
**colour system redesign — brand/accent tokens + semantic colours (v1.0.23)**
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
- colour system redesign — brand/accent tokens + semantic colours (v1.0.23)
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
## v1.0.23 — May 2026
|
|
72
|
+
|
|
73
|
+
**Colour system redesign: brand/accent naming + semantic colour tokens**
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
- Renamed `primary` colour token to `brand`, `secondary` to `accent` across config, utilities, and showcase
|
|
77
|
+
- `btn-primary` and `btn-secondary` are now explicit separate colour tokens (no longer aliases)
|
|
78
|
+
- Default config generated by `emily-css init` updated to reflect new naming
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
- `semanticColours` config key: single-value colour tokens with no shade scale
|
|
82
|
+
- `generateSemanticColourUtilities()`: generates `bg-dark`, `text-dark`, `border-dark`, `fill-dark` etc.
|
|
83
|
+
- Semantic colour utilities automatically pick up `hover:`, `focus:`, `dark:`, and responsive variants
|
|
84
|
+
- Default config includes `dark: "#1A1A1A"` and `light: "#FAFAFA"` as semantic colour examples
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## v1.0.22 — May 2026
|
|
90
|
+
|
|
91
|
+
**· Improve purge extraction and package robustness tests**
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
## v1.0.21 — May 2026
|
|
95
|
+
|
|
96
|
+
**"Include bundled showcase template**
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
## v1.0.20 — May 2026
|
|
100
|
+
|
|
101
|
+
**replace folder structure template to tempalates**
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
- replace folder structure template to tempalates
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
## v1.0.19 — May 2026
|
|
108
|
+
|
|
109
|
+
**Add framework-aware output paths and bundled showcase template**
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
## v1.0.18 — May 2026
|
|
113
|
+
|
|
114
|
+
****
|
|
115
|
+
|
|
116
|
+
### Changed
|
|
117
|
+
- added more utitlies as a code block
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
## v1.0.17 — May 2026
|
|
121
|
+
|
|
122
|
+
**added new utilties, and added component patterns**
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
- added new utilties, and added component patterns
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
## v1.0.16 — May 2026
|
|
129
|
+
|
|
130
|
+
**feat: add Round 2 utility set — 156/156 tests passing**
|
|
131
|
+
|
|
132
|
+
### Added
|
|
133
|
+
- feat: add Round 2 utility set — 156/156 tests passing
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
## v1.0.15 — May 2026
|
|
137
|
+
|
|
138
|
+
**updated readme**
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
## v1.0.14 — May 2026
|
|
142
|
+
|
|
143
|
+
**updated readme**
|
|
144
|
+
|
|
145
|
+
### Changed
|
|
146
|
+
- updated readme
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
## v1.0.13 — May 2026
|
|
150
|
+
|
|
151
|
+
**added functionality to commit to github and then push to npm release**
|
|
152
|
+
|
|
153
|
+
### Added
|
|
154
|
+
- added functionality to commit to github and then push to npm release
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
## v1.0.12 — May 2026
|
|
158
|
+
|
|
159
|
+
****
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
## v1.0.11 — May 2026
|
|
163
|
+
|
|
164
|
+
****
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
## v1.0.10 — May 2026
|
|
168
|
+
|
|
169
|
+
**Changelog automation**
|
|
170
|
+
|
|
171
|
+
### Added
|
|
172
|
+
- Release script (`npm run release`) — reads git log, prompts for version bump, writes CHANGELOG.md, commits and tags automatically
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## v1.0.9 — May 2026
|
|
177
|
+
|
|
178
|
+
**Showcase server + code block utilities**
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
- Showcase server — run `npm run emily:showcase` to browse components on localhost:3456
|
|
182
|
+
- Code block utilities (`.code-window`, `.token-*`) in generated CSS — VSCode Dark+ style syntax highlighting
|
|
183
|
+
- `pre`/`code` base styles added to `@layer base`
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## v1.0.8 — May 2026
|
|
188
|
+
|
|
189
|
+
**Watch mode + build pipeline**
|
|
190
|
+
|
|
191
|
+
### Added
|
|
192
|
+
- Watch mode — `npx emily-css watch` rebuilds CSS automatically on config change
|
|
193
|
+
- Build + purge can now be chained in a single pipeline
|
|
194
|
+
- npm scripts wired into `package.json` during `npx emily-css init`
|
|
195
|
+
|
|
196
|
+
### Changed
|
|
197
|
+
- `init.js` provides a more guided setup experience with clearer prompts
|
|
198
|
+
- `bin/emilyui.js` updated to correctly route `watch`/`build`/`purge` subcommands
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## v1.0.7 — April 2026
|
|
203
|
+
|
|
204
|
+
**Purge regex fix**
|
|
205
|
+
|
|
206
|
+
### Fixed
|
|
207
|
+
- Purge crashed when class names contained regex metacharacters (`[`, `]`, `(`, `)`, `{`, `}`, etc). Previously only `:` and `.` were escaped — now uses full metacharacter escaping
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## v1.0.6 — April 2026
|
|
212
|
+
|
|
213
|
+
**Dist + font cleanup**
|
|
214
|
+
|
|
215
|
+
### Changed
|
|
216
|
+
- `dist/` and `fonts/` directories removed from git tracking
|
|
217
|
+
|
|
218
|
+
### Breaking changes
|
|
219
|
+
- If you were pulling `dist/emily.css` directly from GitHub, run `npx emily-css build` locally instead
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## v1.0.5 — April 2026
|
|
224
|
+
|
|
225
|
+
**Split font system**
|
|
226
|
+
|
|
227
|
+
### Added
|
|
228
|
+
- Separate heading and body font config — `fontFamily.heading` and `fontFamily.body` are now independent
|
|
229
|
+
- Google Fonts CDN integration — fonts loaded via `@import` in generated CSS
|
|
230
|
+
- Font-specific tests added to test suite
|
|
231
|
+
|
|
232
|
+
### Changed
|
|
233
|
+
- Bundled font files removed from the npm package
|
|
234
|
+
- `emily.config.json` updated with split `fontFamily` structure
|
|
235
|
+
|
|
236
|
+
### Breaking changes
|
|
237
|
+
- If your config has `fontFamily` as a single string, update it to `{ "heading": "...", "body": "..." }`
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## v1.0.3 — April 2026
|
|
242
|
+
|
|
243
|
+
**Package size reduction**
|
|
244
|
+
|
|
245
|
+
### Changed
|
|
246
|
+
- Demo CSS removed from the published npm package
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## v1.0.2 — April 2026
|
|
251
|
+
|
|
252
|
+
**Package distribution fix**
|
|
253
|
+
|
|
254
|
+
### Added
|
|
255
|
+
- `.npmignore` added — controls which files are included in the published package
|
|
256
|
+
- `dist` files explicitly declared in `package.json` `files` array
|
|
257
|
+
|
|
258
|
+
### Fixed
|
|
259
|
+
- Unnecessary files (tests, src, docs) were being included in the npm tarball
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## v1.0.1 — April 2026
|
|
264
|
+
|
|
265
|
+
**CLI rename fix**
|
|
266
|
+
|
|
267
|
+
### Fixed
|
|
268
|
+
- Internal references to old `emily-ui` CLI name updated to `emily-css`
|
|
269
|
+
|
|
270
|
+
### Breaking changes
|
|
271
|
+
- If you had scripts referencing `npx emily-ui`, update them to `npx emily-css`
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## v1.0.0 — April 2026
|
|
276
|
+
|
|
277
|
+
**Initial release**
|
|
278
|
+
|
|
279
|
+
### Added
|
|
280
|
+
- 11,844 utility classes generated from `emily.config.json`
|
|
281
|
+
- OKLCH colour scale generation — one hex in, 10-shade scale out
|
|
282
|
+
- Responsive variants (`sm:` `md:` `lg:` `xl:` `2xl:`)
|
|
283
|
+
- State variants (`hover:` `focus-visible:` `active:` `disabled:` `dark:`)
|
|
284
|
+
- Purge system — strips unused classes, ~97% file size reduction
|
|
285
|
+
- Interactive setup wizard (`npx emily-css init`)
|
|
286
|
+
- 72 tests, all passing
|
|
287
|
+
|
|
288
|
+
---
|
package/package.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "emily-css",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A config-driven utility CSS framework. Define your brand once, generate the CSS.",
|
|
5
|
-
"main": "src/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"emily-css": "bin/emilyui.js"
|
|
8
|
-
},
|
|
9
|
-
"files": [
|
|
10
|
-
"bin/",
|
|
11
|
-
"src/",
|
|
12
|
-
"templates/",
|
|
13
|
-
"README.md",
|
|
14
|
-
"LICENSE",
|
|
15
|
-
"CHANGELOG.md"
|
|
16
|
-
],
|
|
17
|
-
"scripts": {
|
|
18
|
-
"build": "node src/index.js",
|
|
19
|
-
"dev": "nodemon src/index.js",
|
|
20
|
-
"dev:full": "nodemon src/index.js -- --keep-full",
|
|
21
|
-
"init": "node src/init.js",
|
|
22
|
-
"test": "node tests/test.js",
|
|
23
|
-
"emily:showcase": "node src/showcase.js",
|
|
24
|
-
"commit": "node scripts/commit.js",
|
|
25
|
-
"release": "node scripts/release.js",
|
|
26
|
-
"ship": "node scripts/ship.js",
|
|
27
|
-
"emily:build": "emily-css build",
|
|
28
|
-
"emily:watch": "emily-css watch",
|
|
29
|
-
"emily:help": "emily-css help"
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"css",
|
|
33
|
-
"design-system",
|
|
34
|
-
"components",
|
|
35
|
-
"config-driven",
|
|
36
|
-
"utility-css",
|
|
37
|
-
"accessibility",
|
|
38
|
-
"drupal",
|
|
39
|
-
"legacy",
|
|
40
|
-
"no-build-step"
|
|
41
|
-
],
|
|
42
|
-
"author": "Andy Terry",
|
|
43
|
-
"license": "MIT",
|
|
44
|
-
"engines": {
|
|
45
|
-
"node": ">=16.0.0"
|
|
46
|
-
},
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"nodemon": "^3.0.0"
|
|
49
|
-
},
|
|
50
|
-
"dependencies": {
|
|
51
|
-
"boxen": "^5.1.2",
|
|
52
|
-
"chalk": "^4.1.2",
|
|
53
|
-
"chokidar": "^5.0.0",
|
|
54
|
-
"cross-spawn": "^7.0.6",
|
|
55
|
-
"enquirer": "^2.4.1",
|
|
56
|
-
"fast-glob": "^3.3.3",
|
|
57
|
-
"ora": "^5.4.1"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "emily-css",
|
|
3
|
+
"version": "1.0.28",
|
|
4
|
+
"description": "A config-driven utility CSS framework. Define your brand once, generate the CSS.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"emily-css": "bin/emilyui.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"templates/",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"CHANGELOG.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "node src/index.js",
|
|
19
|
+
"dev": "nodemon src/index.js",
|
|
20
|
+
"dev:full": "nodemon src/index.js -- --keep-full",
|
|
21
|
+
"init": "node src/init.js",
|
|
22
|
+
"test": "node tests/test.js",
|
|
23
|
+
"emily:showcase": "node src/showcase.js",
|
|
24
|
+
"commit": "node scripts/commit.js",
|
|
25
|
+
"release": "node scripts/release.js",
|
|
26
|
+
"ship": "node scripts/ship.js",
|
|
27
|
+
"emily:build": "emily-css build",
|
|
28
|
+
"emily:watch": "emily-css watch",
|
|
29
|
+
"emily:help": "emily-css help"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"css",
|
|
33
|
+
"design-system",
|
|
34
|
+
"components",
|
|
35
|
+
"config-driven",
|
|
36
|
+
"utility-css",
|
|
37
|
+
"accessibility",
|
|
38
|
+
"drupal",
|
|
39
|
+
"legacy",
|
|
40
|
+
"no-build-step"
|
|
41
|
+
],
|
|
42
|
+
"author": "Andy Terry",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=16.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"nodemon": "^3.0.0"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"boxen": "^5.1.2",
|
|
52
|
+
"chalk": "^4.1.2",
|
|
53
|
+
"chokidar": "^5.0.0",
|
|
54
|
+
"cross-spawn": "^7.0.6",
|
|
55
|
+
"enquirer": "^2.4.1",
|
|
56
|
+
"fast-glob": "^3.3.3",
|
|
57
|
+
"ora": "^5.4.1"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/generators.js
CHANGED
|
@@ -424,6 +424,12 @@ function svgUtilities(colours) {
|
|
|
424
424
|
|
|
425
425
|
css += `.fill-current { fill: currentColor; }\n`;
|
|
426
426
|
css += `.stroke-current { stroke: currentColor; }\n`;
|
|
427
|
+
css += `.fill-white { fill: #FAFAFA; }\n`;
|
|
428
|
+
css += `.fill-black { fill: #111110; }\n`;
|
|
429
|
+
css += `.fill-transparent { fill: transparent; }\n`;
|
|
430
|
+
css += `.stroke-white { stroke: #FAFAFA; }\n`;
|
|
431
|
+
css += `.stroke-black { stroke: #111110; }\n`;
|
|
432
|
+
css += `.stroke-transparent { stroke: transparent; }\n`;
|
|
427
433
|
css += `.stroke-0 { stroke-width: 0; }\n`;
|
|
428
434
|
css += `.stroke-1 { stroke-width: 1; }\n`;
|
|
429
435
|
css += `.stroke-2 { stroke-width: 2; }\n`;
|
|
@@ -602,6 +608,10 @@ function accessibilityUtilities() {
|
|
|
602
608
|
return `/* Accessibility */
|
|
603
609
|
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
|
|
604
610
|
.not-sr-only { position: static; width: auto; height: auto; padding: 0; margin: 0; overflow: visible; clip: auto; white-space: normal; }
|
|
611
|
+
.sr-only-focusable:not(:focus):not(:focus-within) { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; }
|
|
612
|
+
.focus-ring:focus-visible { outline: 2px solid var(--color-brand-80); outline-offset: 2px; }
|
|
613
|
+
.focus-ring-inset:focus-visible { outline: 2px solid var(--color-brand-80); outline-offset: -2px; }
|
|
614
|
+
.focus-ring-none:focus-visible { outline: none; }
|
|
605
615
|
.focus-visible:focus { outline: 2px solid currentColor; outline-offset: 2px; }
|
|
606
616
|
.focus\\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; }
|
|
607
617
|
|
|
@@ -756,8 +766,8 @@ function divideUtilities(spacing, colours) {
|
|
|
756
766
|
css += `.divide-${colourName}-${shade} > * + * { border-color: var(--color-${colourName}-${shade}); }\n`;
|
|
757
767
|
});
|
|
758
768
|
});
|
|
759
|
-
css += `.divide-white > * + * { border-color: #
|
|
760
|
-
css += `.divide-black > * + * { border-color: #
|
|
769
|
+
css += `.divide-white > * + * { border-color: #FAFAFA; }\n`;
|
|
770
|
+
css += `.divide-black > * + * { border-color: #111110; }\n`;
|
|
761
771
|
css += `.divide-transparent > * + * { border-color: transparent; }\n`;
|
|
762
772
|
css += `\n`;
|
|
763
773
|
return css;
|
package/src/index.js
CHANGED
|
@@ -693,8 +693,8 @@ function generateBorderUtilities(config) {
|
|
|
693
693
|
css += `.border-none { border-style: none; }\n`;
|
|
694
694
|
css += `.border-transparent { border-color: transparent; }\n`;
|
|
695
695
|
css += `.border-current { border-color: currentColor; }\n`;
|
|
696
|
-
css += `.border-black { border-color: #
|
|
697
|
-
css += `.border-white { border-color: #
|
|
696
|
+
css += `.border-black { border-color: #111110; }\n`;
|
|
697
|
+
css += `.border-white { border-color: #FAFAFA; }\n`;
|
|
698
698
|
|
|
699
699
|
const baseRadius = config.spacing.borderRadius['base'] || '8px';
|
|
700
700
|
css += `.rounded { border-radius: ${baseRadius}; }\n`;
|
|
@@ -791,9 +791,15 @@ function generateColourUtilities(colours) {
|
|
|
791
791
|
});
|
|
792
792
|
});
|
|
793
793
|
|
|
794
|
-
css += `.bg-white { background-color: #
|
|
794
|
+
css += `.bg-white { background-color: #FAFAFA; }\n`;
|
|
795
|
+
css += `.bg-black { background-color: #111110; }\n`;
|
|
795
796
|
css += `.bg-transparent { background-color: transparent; }\n`;
|
|
796
|
-
css += `.
|
|
797
|
+
css += `.bg-current { background-color: currentColor; }\n`;
|
|
798
|
+
|
|
799
|
+
css += `.text-white { color: #FAFAFA; }\n`;
|
|
800
|
+
css += `.text-black { color: #111110; }\n`;
|
|
801
|
+
css += `.text-transparent { color: transparent; }\n`;
|
|
802
|
+
css += `.text-current { color: currentColor; }\n`;
|
|
797
803
|
|
|
798
804
|
css += `\n`;
|
|
799
805
|
return css;
|
|
@@ -812,6 +818,63 @@ function generateSemanticColourUtilities(semanticColours) {
|
|
|
812
818
|
return css;
|
|
813
819
|
}
|
|
814
820
|
|
|
821
|
+
// ============================================================================
|
|
822
|
+
// ARIA & DATA-STATE VARIANTS
|
|
823
|
+
// ============================================================================
|
|
824
|
+
// Generates ARIA attribute and data-state variants for all utility classes.
|
|
825
|
+
// Selectors target the attribute value directly so they work without JS —
|
|
826
|
+
// just toggle the attribute and the utility activates.
|
|
827
|
+
//
|
|
828
|
+
// Usage in HTML:
|
|
829
|
+
// aria-expanded: class="aria-expanded:block" aria-expanded="true"
|
|
830
|
+
// data-open: class="data-open:flex" data-state="open"
|
|
831
|
+
//
|
|
832
|
+
// Output examples:
|
|
833
|
+
// .aria-expanded\:block[aria-expanded="true"] { display: block; }
|
|
834
|
+
// .data-open\:flex[data-state="open"] { display: flex; }
|
|
835
|
+
|
|
836
|
+
function addAriaDataVariants(css) {
|
|
837
|
+
const variants = [
|
|
838
|
+
{ name: 'aria-expanded', selector: '[aria-expanded="true"]' },
|
|
839
|
+
{ name: 'aria-selected', selector: '[aria-selected="true"]' },
|
|
840
|
+
{ name: 'aria-current', selector: '[aria-current="page"]' },
|
|
841
|
+
{ name: 'aria-disabled', selector: '[aria-disabled="true"]' },
|
|
842
|
+
{ name: 'data-open', selector: '[data-state="open"]' },
|
|
843
|
+
{ name: 'data-closed', selector: '[data-state="closed"]' },
|
|
844
|
+
];
|
|
845
|
+
|
|
846
|
+
let variantCss = css;
|
|
847
|
+
|
|
848
|
+
variants.forEach(variant => {
|
|
849
|
+
let variantRules = '';
|
|
850
|
+
const lines = css.split('\n');
|
|
851
|
+
|
|
852
|
+
lines.forEach(line => {
|
|
853
|
+
if (line.startsWith('.') && line.includes('{')) {
|
|
854
|
+
const className = line.split('{')[0].trim();
|
|
855
|
+
// Skip already-variant lines (contain ':' in class name) and special selectors
|
|
856
|
+
if (
|
|
857
|
+
!className.startsWith(':root') &&
|
|
858
|
+
!className.includes('@') &&
|
|
859
|
+
!className.includes('::') &&
|
|
860
|
+
!className.includes(':')
|
|
861
|
+
) {
|
|
862
|
+
const classWithoutDot = className.substring(1);
|
|
863
|
+
const ariaSelector = `.${variant.name}\\:${classWithoutDot}${variant.selector}`;
|
|
864
|
+
const ariaRule = line.replace(className, ariaSelector);
|
|
865
|
+
variantRules += ariaRule + '\n';
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
if (variantRules) {
|
|
871
|
+
variantCss += `\n/* ARIA/data-state variant: ${variant.name} */\n` + variantRules;
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
return variantCss;
|
|
876
|
+
}
|
|
877
|
+
|
|
815
878
|
// ============================================================================
|
|
816
879
|
// DARK MODE VARIANTS
|
|
817
880
|
// ============================================================================
|
|
@@ -983,6 +1046,65 @@ function generatePatternComponents() {
|
|
|
983
1046
|
margin-inline: auto;
|
|
984
1047
|
}
|
|
985
1048
|
|
|
1049
|
+
.prose-emily {
|
|
1050
|
+
max-width: 65ch;
|
|
1051
|
+
margin-inline: auto;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.prose-emily > * + * {
|
|
1055
|
+
margin-top: var(--space-4, 1rem);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
.prose-emily h2,
|
|
1059
|
+
.prose-emily h3 {
|
|
1060
|
+
font-family: inherit;
|
|
1061
|
+
color: var(--color-neutral-90);
|
|
1062
|
+
line-height: 1.25;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.prose-emily h2 {
|
|
1066
|
+
font-size: var(--text-2xl, 24px);
|
|
1067
|
+
margin-top: var(--space-10, 2.5rem);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
.prose-emily h3 {
|
|
1071
|
+
font-size: var(--text-xl, 20px);
|
|
1072
|
+
margin-top: var(--space-8, 2rem);
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
.prose-emily p,
|
|
1076
|
+
.prose-emily li {
|
|
1077
|
+
color: var(--color-neutral-70);
|
|
1078
|
+
line-height: 1.75;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
.prose-emily ul,
|
|
1082
|
+
.prose-emily ol {
|
|
1083
|
+
padding-left: var(--space-6, 1.5rem);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
.prose-emily ul {
|
|
1087
|
+
list-style-type: disc;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
.prose-emily ol {
|
|
1091
|
+
list-style-type: decimal;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
.prose-emily a {
|
|
1095
|
+
color: var(--color-brand-80);
|
|
1096
|
+
text-decoration: underline;
|
|
1097
|
+
text-underline-offset: 2px;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
.prose-emily code {
|
|
1101
|
+
font-size: var(--text-sm, 14px);
|
|
1102
|
+
background-color: var(--color-neutral-10);
|
|
1103
|
+
border: 1px solid var(--color-neutral-20);
|
|
1104
|
+
border-radius: var(--space-1, 0.25rem);
|
|
1105
|
+
padding: 0.125rem 0.375rem;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
986
1108
|
/* ---- Composition ---- */
|
|
987
1109
|
|
|
988
1110
|
/* Vertical stack with consistent gap — replaces manual margin chains */
|
|
@@ -999,6 +1121,330 @@ function generatePatternComponents() {
|
|
|
999
1121
|
gap: var(--space-4, 1rem);
|
|
1000
1122
|
align-items: center;
|
|
1001
1123
|
}
|
|
1124
|
+
|
|
1125
|
+
/* ---- Layout ---- */
|
|
1126
|
+
|
|
1127
|
+
/* Constrained width container — 1100px max, full-width on small screens */
|
|
1128
|
+
.width-container {
|
|
1129
|
+
width: 100%;
|
|
1130
|
+
max-width: 1100px;
|
|
1131
|
+
margin-inline: auto;
|
|
1132
|
+
padding-inline: var(--space-4, 1rem);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
@media (min-width: 640px) {
|
|
1136
|
+
.width-container {
|
|
1137
|
+
padding-inline: var(--space-6, 1.5rem);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
@media (min-width: 1024px) {
|
|
1142
|
+
.width-container {
|
|
1143
|
+
padding-inline: var(--space-8, 2rem);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
@media (min-width: 1140px) {
|
|
1148
|
+
.width-container {
|
|
1149
|
+
padding-inline: 0;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/* ---- Forms ---- */
|
|
1154
|
+
|
|
1155
|
+
.field-container {
|
|
1156
|
+
display: flex;
|
|
1157
|
+
flex-direction: column;
|
|
1158
|
+
gap: var(--space-2, 0.5rem);
|
|
1159
|
+
margin-bottom: var(--space-6, 1.5rem);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
.field-container label {
|
|
1163
|
+
display: block;
|
|
1164
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
1165
|
+
color: var(--color-neutral-90);
|
|
1166
|
+
font-size: var(--text-base, 16px);
|
|
1167
|
+
line-height: 1.4;
|
|
1168
|
+
margin-bottom: var(--space-1, 0.25rem);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
fieldset {
|
|
1172
|
+
border: none;
|
|
1173
|
+
padding: 0;
|
|
1174
|
+
margin: 0 0 var(--space-6, 1.5rem);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
fieldset legend {
|
|
1178
|
+
display: block;
|
|
1179
|
+
font-size: var(--text-lg, 18px);
|
|
1180
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
1181
|
+
margin-bottom: var(--space-3, 0.75rem);
|
|
1182
|
+
color: var(--color-neutral-90);
|
|
1183
|
+
padding: 0;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
.form-hint {
|
|
1187
|
+
font-size: var(--text-sm, 14px);
|
|
1188
|
+
color: var(--color-neutral-60);
|
|
1189
|
+
margin-bottom: var(--space-1, 0.25rem);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
input[type="text"],
|
|
1193
|
+
input[type="email"],
|
|
1194
|
+
input[type="password"],
|
|
1195
|
+
input[type="number"],
|
|
1196
|
+
input[type="tel"],
|
|
1197
|
+
input[type="url"],
|
|
1198
|
+
input[type="search"],
|
|
1199
|
+
input[type="date"],
|
|
1200
|
+
select,
|
|
1201
|
+
textarea {
|
|
1202
|
+
width: 100%;
|
|
1203
|
+
max-width: 100%;
|
|
1204
|
+
padding: var(--space-3, 0.75rem) var(--space-4, 1rem);
|
|
1205
|
+
border: 2px solid var(--color-neutral-30);
|
|
1206
|
+
border-radius: 8px;
|
|
1207
|
+
background-color: #ffffff;
|
|
1208
|
+
color: var(--color-neutral-90);
|
|
1209
|
+
font-family: inherit;
|
|
1210
|
+
font-size: var(--text-base, 16px);
|
|
1211
|
+
line-height: var(--leading-base, 1.6);
|
|
1212
|
+
appearance: none;
|
|
1213
|
+
transition: border-color 200ms ease, box-shadow 200ms ease;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
select {
|
|
1217
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
|
1218
|
+
background-position: right var(--space-2, 0.5rem) center;
|
|
1219
|
+
background-repeat: no-repeat;
|
|
1220
|
+
background-size: 1.5em 1.5em;
|
|
1221
|
+
padding-right: var(--space-10, 2.5rem);
|
|
1222
|
+
cursor: pointer;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
textarea {
|
|
1226
|
+
min-height: 120px;
|
|
1227
|
+
resize: vertical;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
input[type="text"]:focus,
|
|
1231
|
+
input[type="email"]:focus,
|
|
1232
|
+
input[type="password"]:focus,
|
|
1233
|
+
input[type="number"]:focus,
|
|
1234
|
+
input[type="tel"]:focus,
|
|
1235
|
+
input[type="url"]:focus,
|
|
1236
|
+
input[type="search"]:focus,
|
|
1237
|
+
input[type="date"]:focus,
|
|
1238
|
+
select:focus,
|
|
1239
|
+
textarea:focus {
|
|
1240
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1241
|
+
outline-offset: 3px;
|
|
1242
|
+
border-color: var(--color-neutral-80);
|
|
1243
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.checkbox-group,
|
|
1247
|
+
.radio-group {
|
|
1248
|
+
display: flex;
|
|
1249
|
+
align-items: center;
|
|
1250
|
+
gap: var(--space-3, 0.75rem);
|
|
1251
|
+
margin-bottom: var(--space-4, 1rem);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
.checkbox-group label,
|
|
1255
|
+
.radio-group label {
|
|
1256
|
+
font-weight: var(--font-weight-normal, 400);
|
|
1257
|
+
margin-bottom: 0;
|
|
1258
|
+
cursor: pointer;
|
|
1259
|
+
font-size: var(--text-base, 16px);
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
input[type="checkbox"] {
|
|
1263
|
+
width: 1.5rem;
|
|
1264
|
+
height: 1.5rem;
|
|
1265
|
+
margin: 0;
|
|
1266
|
+
cursor: pointer;
|
|
1267
|
+
accent-color: var(--color-brand-80);
|
|
1268
|
+
flex-shrink: 0;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
input[type="checkbox"]:focus {
|
|
1272
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1273
|
+
outline-offset: 3px;
|
|
1274
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
input[type="radio"] {
|
|
1278
|
+
width: 1.5rem;
|
|
1279
|
+
height: 1.5rem;
|
|
1280
|
+
margin: 0;
|
|
1281
|
+
border-radius: 50%;
|
|
1282
|
+
appearance: none;
|
|
1283
|
+
background-color: #ffffff;
|
|
1284
|
+
border: 2px solid var(--color-neutral-30);
|
|
1285
|
+
display: grid;
|
|
1286
|
+
place-content: center;
|
|
1287
|
+
cursor: pointer;
|
|
1288
|
+
flex-shrink: 0;
|
|
1289
|
+
transition: background-color 200ms ease, border-color 200ms ease;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
input[type="radio"]::before {
|
|
1293
|
+
content: "";
|
|
1294
|
+
width: 0.75rem;
|
|
1295
|
+
height: 0.75rem;
|
|
1296
|
+
border-radius: 50%;
|
|
1297
|
+
transform: scale(0);
|
|
1298
|
+
transition: 120ms transform ease-in-out;
|
|
1299
|
+
background-color: var(--color-brand-80);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
input[type="radio"]:checked {
|
|
1303
|
+
border-color: var(--color-brand-80);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
input[type="radio"]:checked::before {
|
|
1307
|
+
transform: scale(1);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
input[type="radio"]:hover {
|
|
1311
|
+
background-color: var(--color-brand-10);
|
|
1312
|
+
border-color: var(--color-brand-80);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
input[type="radio"]:focus {
|
|
1316
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1317
|
+
outline-offset: 3px;
|
|
1318
|
+
border-radius: 50%;
|
|
1319
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
input[aria-invalid="true"] {
|
|
1323
|
+
border-color: var(--color-error-80) !important;
|
|
1324
|
+
border-width: 3px;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.form-error-message {
|
|
1328
|
+
font-size: var(--text-sm, 14px);
|
|
1329
|
+
font-weight: var(--font-weight-bold, 700);
|
|
1330
|
+
color: var(--color-error-80);
|
|
1331
|
+
margin-top: var(--space-1, 0.25rem);
|
|
1332
|
+
display: block;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
.error-summary {
|
|
1336
|
+
border: 4px solid var(--color-error-80);
|
|
1337
|
+
padding: var(--space-6, 1.5rem);
|
|
1338
|
+
margin-bottom: var(--space-8, 2rem);
|
|
1339
|
+
border-radius: 8px;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
.error-summary ul {
|
|
1343
|
+
list-style: disc;
|
|
1344
|
+
padding-left: var(--space-5, 1.25rem);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
.error-summary a {
|
|
1348
|
+
color: var(--color-error-80);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/* ---- Buttons ---- */
|
|
1352
|
+
|
|
1353
|
+
.btn {
|
|
1354
|
+
display: inline-flex;
|
|
1355
|
+
align-items: center;
|
|
1356
|
+
justify-content: center;
|
|
1357
|
+
padding: var(--space-3, 0.75rem) var(--space-6, 1.5rem);
|
|
1358
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
1359
|
+
border-radius: 8px;
|
|
1360
|
+
cursor: pointer;
|
|
1361
|
+
transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease;
|
|
1362
|
+
border: 2px solid transparent;
|
|
1363
|
+
text-align: center;
|
|
1364
|
+
min-height: 3rem;
|
|
1365
|
+
font-size: var(--text-base, 16px);
|
|
1366
|
+
text-decoration: none;
|
|
1367
|
+
font-family: inherit;
|
|
1368
|
+
line-height: 1;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
.btn-primary {
|
|
1372
|
+
background-color: var(--color-brand-80);
|
|
1373
|
+
color: #ffffff;
|
|
1374
|
+
border-color: transparent;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
.btn-primary:hover {
|
|
1378
|
+
background-color: var(--color-brand-90);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
.btn-primary:focus-visible {
|
|
1382
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1383
|
+
outline-offset: 3px;
|
|
1384
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
.btn-secondary {
|
|
1388
|
+
background-color: #ffffff;
|
|
1389
|
+
color: var(--color-accent-80);
|
|
1390
|
+
border-color: var(--color-accent-80);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
.btn-secondary:hover {
|
|
1394
|
+
background-color: var(--color-accent-10);
|
|
1395
|
+
color: var(--color-accent-90);
|
|
1396
|
+
border-color: var(--color-accent-90);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
.btn-secondary:focus-visible {
|
|
1400
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1401
|
+
outline-offset: 3px;
|
|
1402
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
.btn-ghost {
|
|
1406
|
+
background-color: transparent;
|
|
1407
|
+
color: var(--color-neutral-80);
|
|
1408
|
+
border-color: transparent;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
.btn-ghost:hover {
|
|
1412
|
+
background-color: var(--color-neutral-10);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
.btn-ghost:focus-visible {
|
|
1416
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1417
|
+
outline-offset: 3px;
|
|
1418
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
.btn-danger {
|
|
1422
|
+
background-color: var(--color-error-80);
|
|
1423
|
+
color: #ffffff;
|
|
1424
|
+
border-color: transparent;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
.btn-danger:hover {
|
|
1428
|
+
background-color: var(--color-error-90);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
.btn-danger:focus-visible {
|
|
1432
|
+
outline: 2px solid var(--color-neutral-80);
|
|
1433
|
+
outline-offset: 3px;
|
|
1434
|
+
box-shadow: 0 0 0 4px rgba(219, 39, 119, 0.1);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
.btn-sm {
|
|
1438
|
+
padding: var(--space-2, 0.5rem) var(--space-4, 1rem);
|
|
1439
|
+
font-size: var(--text-sm, 14px);
|
|
1440
|
+
min-height: 2.25rem;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
.btn-lg {
|
|
1444
|
+
padding: var(--space-4, 1rem) var(--space-8, 2rem);
|
|
1445
|
+
font-size: var(--text-lg, 18px);
|
|
1446
|
+
min-height: 3.5rem;
|
|
1447
|
+
}
|
|
1002
1448
|
`;
|
|
1003
1449
|
}
|
|
1004
1450
|
|
|
@@ -1097,6 +1543,7 @@ function buildFullFramework() {
|
|
|
1097
1543
|
utilityCss += filterUtilities();
|
|
1098
1544
|
|
|
1099
1545
|
utilityCss = addStateVariants(utilityCss);
|
|
1546
|
+
utilityCss = addAriaDataVariants(utilityCss);
|
|
1100
1547
|
utilityCss = addDarkModeVariants(utilityCss);
|
|
1101
1548
|
utilityCss = addResponsiveVariants(utilityCss, config);
|
|
1102
1549
|
|
|
@@ -1145,6 +1592,59 @@ function buildFullFramework() {
|
|
|
1145
1592
|
overflow-wrap: break-word;
|
|
1146
1593
|
}
|
|
1147
1594
|
|
|
1595
|
+
/* Base heading scale */
|
|
1596
|
+
h1 {
|
|
1597
|
+
font-size: var(--text-4xl, 36px);
|
|
1598
|
+
line-height: var(--leading-4xl, 1.3);
|
|
1599
|
+
font-weight: var(--font-weight-bold, 700);
|
|
1600
|
+
margin-bottom: var(--space-6, 1.5rem);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
h2 {
|
|
1604
|
+
font-size: var(--text-3xl, 30px);
|
|
1605
|
+
line-height: var(--leading-3xl, 1.4);
|
|
1606
|
+
font-weight: var(--font-weight-bold, 700);
|
|
1607
|
+
margin-bottom: var(--space-5, 1.25rem);
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
h3 {
|
|
1611
|
+
font-size: var(--text-2xl, 24px);
|
|
1612
|
+
line-height: var(--leading-2xl, 1.4);
|
|
1613
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
1614
|
+
margin-bottom: var(--space-4, 1rem);
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
h4 {
|
|
1618
|
+
font-size: var(--text-xl, 20px);
|
|
1619
|
+
line-height: var(--leading-xl, 1.6);
|
|
1620
|
+
font-weight: var(--font-weight-semibold, 600);
|
|
1621
|
+
margin-bottom: var(--space-3, 0.75rem);
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
h5 {
|
|
1625
|
+
font-size: var(--text-lg, 18px);
|
|
1626
|
+
line-height: var(--leading-lg, 1.6);
|
|
1627
|
+
font-weight: var(--font-weight-medium, 500);
|
|
1628
|
+
margin-bottom: var(--space-3, 0.75rem);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
h6 {
|
|
1632
|
+
font-size: var(--text-base, 16px);
|
|
1633
|
+
line-height: var(--leading-base, 1.6);
|
|
1634
|
+
font-weight: var(--font-weight-medium, 500);
|
|
1635
|
+
margin-bottom: var(--space-2, 0.5rem);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
p {
|
|
1639
|
+
font-size: var(--text-base, 16px);
|
|
1640
|
+
line-height: var(--leading-base, 1.6);
|
|
1641
|
+
margin-bottom: var(--space-4, 1rem);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
p:last-child {
|
|
1645
|
+
margin-bottom: 0;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1148
1648
|
code {
|
|
1149
1649
|
font-family: "Menlo", "Monaco", "Courier New", monospace;
|
|
1150
1650
|
font-size: 0.875em;
|
|
@@ -1268,8 +1768,8 @@ function build(options = {}) {
|
|
|
1268
1768
|
const fullCssPath = getFullCssPath(config);
|
|
1269
1769
|
const result = buildProductionCss();
|
|
1270
1770
|
|
|
1271
|
-
console.log('
|
|
1272
|
-
console.log('
|
|
1771
|
+
console.log('\u2713 Generated production CSS: ' + path.relative(process.cwd(), result.outputPath));
|
|
1772
|
+
console.log('\u2713 File size: ' + (result.outputSize / 1024).toFixed(2) + ' KB');
|
|
1273
1773
|
|
|
1274
1774
|
if (!options.keepFull && fs.existsSync(fullCssPath)) {
|
|
1275
1775
|
try {
|
|
@@ -1306,6 +1806,7 @@ module.exports = {
|
|
|
1306
1806
|
generateFlexboxUtilities,
|
|
1307
1807
|
generateGridUtilities,
|
|
1308
1808
|
addStateVariants,
|
|
1809
|
+
addAriaDataVariants,
|
|
1309
1810
|
addResponsiveVariants,
|
|
1310
1811
|
generateFontCSS,
|
|
1311
1812
|
codeUtilities,
|
package/src/purge.js
CHANGED
|
@@ -173,7 +173,7 @@ function purgeBlock(block, usedClasses) {
|
|
|
173
173
|
.replace(/:/g, "\\\\:");
|
|
174
174
|
|
|
175
175
|
const boundaryRegex = new RegExp(
|
|
176
|
-
`\\.${escapedUsed}(?::[\\w\\-]
|
|
176
|
+
`\\.${escapedUsed}(?::[\\w\\-]+|\\[|[\\s,>+~]|$)`,
|
|
177
177
|
);
|
|
178
178
|
|
|
179
179
|
if (boundaryRegex.test(selector)) return true;
|
|
@@ -275,5 +275,5 @@ function purgeCSS(css, scanDir, config) {
|
|
|
275
275
|
module.exports = {
|
|
276
276
|
purgeCSS,
|
|
277
277
|
getAllFiles,
|
|
278
|
-
extractClassNames
|
|
279
|
-
};
|
|
278
|
+
extractClassNames
|
|
279
|
+
};
|
package/templates/showcase.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>EmilyUI Showcase</title>
|
|
7
|
-
<link rel="stylesheet" href="
|
|
7
|
+
<link rel="stylesheet" href="../dist/emily.min.css">
|
|
8
8
|
<style>
|
|
9
9
|
html {
|
|
10
10
|
scroll-behavior: smooth;
|
|
@@ -949,7 +949,7 @@
|
|
|
949
949
|
|
|
950
950
|
<div class="lg:col-span-2">
|
|
951
951
|
<h3 class="font-bold mb-3">.center-screen</h3>
|
|
952
|
-
<div class="border border-neutral-20 rounded-t-lg overflow-hidden bg-neutral-80" style="min-height:
|
|
952
|
+
<div class="border border-neutral-20 rounded-t-lg overflow-hidden bg-neutral-80" style="min-height: 50vh; position: relative;">
|
|
953
953
|
<div class="center-screen" style="position: absolute;">
|
|
954
954
|
<div class="bg-white rounded-lg shadow-lg border border-neutral-20 p-6 text-center" style="max-width: 340px; width: 90%;">
|
|
955
955
|
<h4 class="text-lg font-bold mb-2">Confirm action</h4>
|