eidotter 0.40.2 → 0.41.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 +13 -5
- package/dist/components/Accordion/components/AccordionFill.js +1 -1
- package/dist/components/Accordion/components/Section.js +1 -1
- package/dist/components/Alert/components/Alert.js +3 -2
- package/dist/components/Brand/components/Logo.d.ts +7 -7
- package/dist/components/Brand/components/Logo.js +10 -15
- package/dist/components/Brand/components/LogoGeometry.d.ts +28 -0
- package/dist/components/Brand/components/LogoGeometry.js +78 -0
- package/dist/components/Brand/components/Mark.d.ts +13 -6
- package/dist/components/Brand/components/Mark.js +14 -10
- package/dist/components/Brand/components/Wordmark.js +1 -1
- package/dist/components/Brand/components/markGeometry.d.ts +15 -0
- package/dist/components/Brand/components/markGeometry.js +20 -7
- package/dist/components/Breadcrumb/components/Breadcrumb.js +2 -2
- package/dist/components/Button/components/Button.js +1 -1
- package/dist/components/Card/components/Card.d.ts +5 -0
- package/dist/components/Card/components/Card.js +8 -2
- package/dist/components/CmdPalette/components/CmdPalette.d.ts +4 -3
- package/dist/components/CmdPalette/components/CmdPalette.js +17 -12
- package/dist/components/DecayStrip/components/DecayStrip.js +6 -1
- package/dist/components/DosDialog/components/DosDialog.d.ts +77 -0
- package/dist/components/DosDialog/components/DosDialog.js +59 -0
- package/dist/components/DosDialog/components/index.d.ts +2 -0
- package/dist/components/DosDialog/components/index.js +1 -0
- package/dist/components/DosDialog/index.d.ts +2 -0
- package/dist/components/DosDialog/index.js +1 -0
- package/dist/components/DosFigure/components/DosFigure.d.ts +2 -2
- package/dist/components/DosFigure/components/DosFigure.js +14 -7
- package/dist/components/DosWindow/components/DosWindow.d.ts +39 -0
- package/dist/components/DosWindow/components/DosWindow.js +23 -0
- package/dist/components/DosWindow/components/index.d.ts +2 -0
- package/dist/components/DosWindow/components/index.js +1 -0
- package/dist/components/DosWindow/index.d.ts +2 -0
- package/dist/components/DosWindow/index.js +1 -0
- package/dist/components/FilterBar/components/FilterBar.d.ts +7 -4
- package/dist/components/Footer/components/Footer.js +1 -1
- package/dist/components/Gauge/components/Gauge.js +19 -2
- package/dist/components/Header/components/Header.d.ts +29 -1
- package/dist/components/Header/components/Header.js +20 -5
- package/dist/components/Icon/components/Icon.d.ts +2 -0
- package/dist/components/Icon/components/Icon.js +5 -1
- package/dist/components/IconButton/components/IconButton.d.ts +44 -0
- package/dist/components/IconButton/components/IconButton.js +19 -0
- package/dist/components/IconButton/components/index.d.ts +2 -0
- package/dist/components/IconButton/components/index.js +1 -0
- package/dist/components/IconButton/index.d.ts +2 -0
- package/dist/components/IconButton/index.js +1 -0
- package/dist/components/Input/components/Input.js +1 -1
- package/dist/components/Lightbox/components/Lightbox.d.ts +10 -4
- package/dist/components/Lightbox/components/Lightbox.js +19 -11
- package/dist/components/Meter/components/Meter.js +7 -3
- package/dist/components/Meter/components/MeterGroup.js +3 -3
- package/dist/components/Modal/components/Modal.d.ts +18 -6
- package/dist/components/Modal/components/Modal.js +18 -9
- package/dist/components/Nav/components/Nav.js +5 -4
- package/dist/components/Notification/components/Notification.js +3 -2
- package/dist/components/Progress/components/Progress.js +8 -6
- package/dist/components/SeriesBars/components/SeriesBars.js +9 -8
- package/dist/components/Tag/components/Tag.d.ts +8 -1
- package/dist/components/Tag/components/Tag.js +5 -5
- package/dist/components/VitalsStrip/components/VitalsStrip.js +10 -7
- package/dist/components/registry.js +221 -19
- package/dist/eidotter.css +1 -1
- package/dist/hooks/useAnimatedDismiss.js +5 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.es.js +2174 -1600
- package/dist/index.umd.js +1 -1
- package/llms.txt +15 -7
- package/migrations/0.41.0.md +881 -0
- package/migrations/README.md +46 -0
- package/package.json +10 -2
- package/public/favicon.svg +1 -1
- package/src/styles/dos-utilities.css +6 -1
- package/src/styles/shadcn.css +52 -17
- package/src/styles/theme.amber-mono.css +4 -2
- package/src/styles/theme.amber-paper.css +106 -0
- package/src/styles/theme.cga-amber.css +3 -1
- package/src/styles/theme.cga-mode4-p0.css +3 -1
- package/src/styles/theme.cga-mode4-p1.css +3 -1
- package/src/styles/theme.cga-mode5.css +3 -1
- package/src/styles/theme.light.css +3 -1
- package/src/styles/tokens.css +5 -1
- package/tailwind.preset.cjs +23 -1
- package/dist/components/Brand/components/markGeometry.test.d.ts +0 -1
- package/dist/components/Connector/components/connectorGeometry.test.d.ts +0 -1
- package/dist/components/DecayStrip/components/resample.test.d.ts +0 -1
- package/dist/components/TimelineContainer/components/timelineUtils.test.d.ts +0 -1
- package/dist/components/TimelineContainer/components/useDrillDown.test.d.ts +0 -1
- package/dist/components/TimelineContainer/components/useSelection.test.d.ts +0 -1
- package/dist/components/TimelineContainer/components/useZoom.test.d.ts +0 -1
- package/dist/hooks/useTextScramble.test.d.ts +0 -1
- package/dist/hooks/useThemePortal.test.d.ts +0 -1
- package/dist/utils/health/formatValue.test.d.ts +0 -1
- package/dist/utils/health/healthPatterns.test.d.ts +0 -1
- package/dist/utils/health/resolveBand.test.d.ts +0 -1
- package/dist/utils/isSafeHref.test.d.ts +0 -1
- package/dist/utils/isSafeUrl.test.d.ts +0 -1
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
# Upgrading to eidotter 0.41.0
|
|
2
|
+
|
|
3
|
+
This guide is for developers and AI agents working in an app that consumes the
|
|
4
|
+
`eidotter` npm package. It assumes you have not seen the eidotter repository.
|
|
5
|
+
Everything here was checked against the 0.41.0 source and the published
|
|
6
|
+
`dist/` output. Linear ids (DMNC-xxxx) are references only; you do not need
|
|
7
|
+
access to them.
|
|
8
|
+
|
|
9
|
+
You are reading this from `node_modules/eidotter/migrations/0.41.0.md`, or from
|
|
10
|
+
the repository's `migrations/` folder. If you are upgrading across several
|
|
11
|
+
minors, read [`README.md`](./README.md) in this folder first.
|
|
12
|
+
|
|
13
|
+
## Who must act
|
|
14
|
+
|
|
15
|
+
Every consumer. 0.41.0 is a 0.x **minor**, so it carries visible changes, and a
|
|
16
|
+
caret range on 0.40 does not pick it up.
|
|
17
|
+
|
|
18
|
+
In three lines:
|
|
19
|
+
|
|
20
|
+
1. Body text has a 16px floor (Tailwind preset `text-xs`/`text-sm` are now
|
|
21
|
+
1rem), `eidotter/styles` stops leaking its CSS reset (fonts, link colours)
|
|
22
|
+
and its unused utilities into your app, and `text-secondary` is now a
|
|
23
|
+
visible tone, not near-black.
|
|
24
|
+
2. `Header` shows the logo lockup by default with uppercase nav, and Modal,
|
|
25
|
+
Lightbox, CmdPalette, Card, DosFigure, Alert, Notification, Logo and Mark
|
|
26
|
+
look different. Some overlay CSS classes are gone.
|
|
27
|
+
3. New shared pieces replace hand-rolled code: `IconButton`, `DosDialog`,
|
|
28
|
+
`DosWindow`, a `Header` `end` slot, the `amber-paper` theme and the
|
|
29
|
+
`eidotter/favicon.svg` asset.
|
|
30
|
+
|
|
31
|
+
No public prop was removed or renamed. A diff of every published `.d.ts` in
|
|
32
|
+
`dist/components` between 0.40.2 and 0.41.0 shows only additions. What can
|
|
33
|
+
break is CSS: your overrides, your reliance on leaked global styles, and
|
|
34
|
+
utility classes you used without having Tailwind yourself.
|
|
35
|
+
|
|
36
|
+
### Which sections apply to your stack
|
|
37
|
+
|
|
38
|
+
| Your stack | Read especially |
|
|
39
|
+
|---|---|
|
|
40
|
+
| Tailwind 3 or 4 with `eidotter/tailwind.preset` | 1 (16px floor), 3, 5, 6, 7 |
|
|
41
|
+
| Tailwind 4 without the preset | 1 (component sizes only), 3, 5, 6, 7 |
|
|
42
|
+
| No Tailwind (plain CSS, Astro, Vite React) | 2 (utilities removed), 4 (reset no longer leaks), 3, 5, 6, 7 |
|
|
43
|
+
| Next.js App Router (server components) | all of the above plus "RSC deep imports" |
|
|
44
|
+
|
|
45
|
+
## How to bump
|
|
46
|
+
|
|
47
|
+
0.x caret ranges stop at the next minor: `^0.40.2` means `>=0.40.2 <0.41.0`.
|
|
48
|
+
Older ranges such as `^0.38.0`, `^0.37.0` or `^0.33.0` are the same: none of
|
|
49
|
+
them reach 0.41.0. Change the range explicitly:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install eidotter@^0.41.0
|
|
53
|
+
# check what actually resolved
|
|
54
|
+
npm ls eidotter
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Install from the npm registry. Do not point the dependency at a local checkout
|
|
58
|
+
(`file:../eidotter`): `npm ci` passes, but CI, Docker and Vercel builds fail
|
|
59
|
+
with "Module not found".
|
|
60
|
+
|
|
61
|
+
Before you bump, save a copy of the old bundle. You need it for the class diff
|
|
62
|
+
in section 2:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cp node_modules/eidotter/dist/eidotter.css /tmp/eidotter-old.css
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If you are coming from older than 0.40, also read
|
|
69
|
+
"Jumping from older versions" at the end.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Breaking and visible changes
|
|
74
|
+
|
|
75
|
+
Each item is: what changed, how to find it in your code, what to do, how to
|
|
76
|
+
verify. Patterns use `rg` (ripgrep). If you only have grep, `grep -rnE` with the
|
|
77
|
+
same pattern works. Adjust the search roots (`src app components pages`) to
|
|
78
|
+
your repo.
|
|
79
|
+
|
|
80
|
+
### 1. 16px body-size floor; preset `text-xs` / `text-sm` are 1rem (DMNC-1579)
|
|
81
|
+
|
|
82
|
+
**What changed.** The Tailwind preset (`eidotter/tailwind.preset`) now maps
|
|
83
|
+
Tailwind's `text-xs` and `text-sm` to `1rem` with a `1.25rem` line height. A
|
|
84
|
+
new token `--typography-font-size-text-base` (1rem) and utility
|
|
85
|
+
`text-dos-text-base` exist. Inside eidotter, `Breadcrumb` (was 12px with 0.35em
|
|
86
|
+
tracking, now 16px with 0.1em), `Footer` (was 14px), `Input` label, description
|
|
87
|
+
and error text (were 12px) and the `Header` brand link render at 16px.
|
|
88
|
+
`Progress` sizes `sm`/`md`/`lg` render 16/20/22px.
|
|
89
|
+
|
|
90
|
+
The preset alias only affects apps that load the preset. The bundle
|
|
91
|
+
(`dist/eidotter.css`) no longer ships any stock `.text-xs` … `.text-9xl` rule,
|
|
92
|
+
so it no longer overrides your own Tailwind sizes (0.40 shipped an unlayered
|
|
93
|
+
`.text-xs{font-size:1rem}` that did).
|
|
94
|
+
|
|
95
|
+
**Find it.**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Tailwind classes that will now render at 16px (preset users)
|
|
99
|
+
rg -n '\btext-(xs|sm)\b' src app components pages
|
|
100
|
+
# overrides you added to bump eidotter components up to body size
|
|
101
|
+
rg -n -A4 '\.eidotter-(breadcrumb|footer|input|header__branding)' --glob '*.{css,scss}'
|
|
102
|
+
rg -n 'text-base' src app components | rg -i 'breadcrumb|footer|input|header'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**What to do.**
|
|
106
|
+
|
|
107
|
+
- Preset users: expect `text-xs`/`text-sm` text to grow to 16px. The floor is
|
|
108
|
+
deliberate (the DOS VGA cell is 9×16). Where a label now overflows on mobile,
|
|
109
|
+
shorten the label; do not widen its container.
|
|
110
|
+
- Delete per-element `font-size` / `text-base` overrides you added to
|
|
111
|
+
Breadcrumb, Footer, Input or the Header brand. They are now redundant.
|
|
112
|
+
- Prefer `text-dos-text-base` over `text-base` for body-size text in new code.
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
// before (0.40): forcing eidotter's small Breadcrumb up to body size
|
|
116
|
+
<div className="[&_.eidotter-breadcrumb]:text-base"><Breadcrumb items={crumbs} /></div>
|
|
117
|
+
// after (0.41): the component is already 16px
|
|
118
|
+
<Breadcrumb items={crumbs} />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Verify.** In the browser,
|
|
122
|
+
`getComputedStyle(document.querySelector('.eidotter-breadcrumb')).fontSize`
|
|
123
|
+
is `"16px"`. Check that no label wraps or overflows at 390px width.
|
|
124
|
+
|
|
125
|
+
### 2. Utilities removed from `dist/eidotter.css` (consumers without their own Tailwind)
|
|
126
|
+
|
|
127
|
+
**What changed.** The bundle used to contain every stock Tailwind utility
|
|
128
|
+
that appeared anywhere in eidotter's docs and stories. It now contains only the
|
|
129
|
+
stock utilities used by shipped component source. Apps that used those generic
|
|
130
|
+
classes in their own markup without running Tailwind themselves lose them. Apps
|
|
131
|
+
that run their own Tailwind are not affected, because their build generates the
|
|
132
|
+
classes.
|
|
133
|
+
|
|
134
|
+
eidotter's own token utilities stay available without Tailwind:
|
|
135
|
+
`text-dos-*`, `bg-dos-*`, `border-dos-*`, `shadow-dos-*`, `font-dos-*`
|
|
136
|
+
(including the `font-dos-bold` / `-semibold` / `-regular` aliases), `bg-cga-*`
|
|
137
|
+
and `text-cga-*`.
|
|
138
|
+
|
|
139
|
+
Examples of generic utilities that are gone:
|
|
140
|
+
|
|
141
|
+
- Layout and spacing: `mt-4`, `p-3`, `space-y-2`, `grid-cols-1`,
|
|
142
|
+
`grid-cols-2`, `md:grid-cols-2`, `md:grid-cols-4`, `lg:grid-cols-3`,
|
|
143
|
+
`col-span-2`, `max-w-3xl`, `max-w-5xl`, `min-h-screen`, `flex-grow`,
|
|
144
|
+
`flex-shrink`, `float-left`, `float-right`, `contents`, `isolate`,
|
|
145
|
+
`inline-grid`, `print:hidden`.
|
|
146
|
+
- Borders and radius: `border-t`, `border-r`, `border-l`, `border-x`,
|
|
147
|
+
`border-y`, `border-transparent`, `divide-x`, `divide-y`, `rounded`,
|
|
148
|
+
`rounded-t`, `rounded-b`, `rounded-l`, `rounded-r`.
|
|
149
|
+
- Typography: the stock sizes `text-xs`, `text-sm`, `text-base`, `text-lg`,
|
|
150
|
+
`text-xl`, plus `italic`, `capitalize`, `lowercase`, `antialiased`,
|
|
151
|
+
`text-wrap`.
|
|
152
|
+
|
|
153
|
+
That list is not exhaustive. Compute the exact diff for your installed versions.
|
|
154
|
+
|
|
155
|
+
**Find it.** After the bump, compare the saved old bundle with the new one and
|
|
156
|
+
search your code for each removed class:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
node -e '
|
|
160
|
+
const fs = require("fs");
|
|
161
|
+
const classes = (f) => new Set([...fs.readFileSync(f, "utf8")
|
|
162
|
+
.matchAll(/\.(-?[A-Za-z_](?:\\.|[A-Za-z0-9_-])*)/g)].map((m) => m[1].replace(/\\/g, "")));
|
|
163
|
+
const before = classes("/tmp/eidotter-old.css");
|
|
164
|
+
const after = classes("node_modules/eidotter/dist/eidotter.css");
|
|
165
|
+
console.log([...before].filter((c) => !after.has(c)).sort().join("\n"));
|
|
166
|
+
' > /tmp/eidotter-removed-classes.txt
|
|
167
|
+
wc -l /tmp/eidotter-removed-classes.txt
|
|
168
|
+
rg -n -w -F -f /tmp/eidotter-removed-classes.txt src app components pages \
|
|
169
|
+
--glob '*.{tsx,jsx,ts,js,astro,html,mdx,vue,svelte}'
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Review the hits by hand. A `-w` match on a short word such as `contents` or
|
|
173
|
+
`rounded` can be a false positive in prose. Ignore any eidotter token utility
|
|
174
|
+
(`*-dos-*`, `*-cga-*`) the diff lists; those remain supported.
|
|
175
|
+
|
|
176
|
+
**What to do.** For each real hit, pick one:
|
|
177
|
+
|
|
178
|
+
- Replace the utility with a semantic class or a plain CSS rule in your own
|
|
179
|
+
stylesheet using eidotter tokens:
|
|
180
|
+
|
|
181
|
+
```css
|
|
182
|
+
/* before: <p class="grid grid-cols-2 mt-4"> relied on eidotter's bundle */
|
|
183
|
+
/* after: your own CSS */
|
|
184
|
+
.intro { display: grid; grid-template-columns: 1fr 1fr; margin-top: var(--spacing-4); } /* 16px */
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
All token names are in `node_modules/eidotter/src/styles/tokens.css`.
|
|
188
|
+
- For display or body typography in raw HTML, the `.dos-*` classes from
|
|
189
|
+
`import 'eidotter/utilities'` (`.dos-body`, `.dos-caption`, `.dos-h1` …
|
|
190
|
+
`.dos-h5`, `.dos-label`, `.dos-code`) are another option.
|
|
191
|
+
- Or add Tailwind to the app and load `eidotter/tailwind.preset`, which
|
|
192
|
+
generates any of these classes on demand.
|
|
193
|
+
|
|
194
|
+
**Verify.** Rerun the `rg` command: no hits left that you did not deliberately
|
|
195
|
+
keep. Visually check the pages that had hits.
|
|
196
|
+
|
|
197
|
+
### 3. `text-secondary` changed meaning; use `text-on-accent` / `text-on-brand` / `text-on-light` (DMNC-1494)
|
|
198
|
+
|
|
199
|
+
**What changed.** `--color-semantic-text-secondary` (Tailwind
|
|
200
|
+
`text-dos-text-secondary`) used to resolve to the darkest CGA value: the same
|
|
201
|
+
near-black as the page background. That made it correct only for dark text on
|
|
202
|
+
an amber or light fill, and invisible everywhere else. It now resolves to a
|
|
203
|
+
visible, de-emphasised tone (the `light-gray` primitive on dark themes; warm
|
|
204
|
+
tan `#b87c1a` under amber-mono; near-black under the light theme). Three new
|
|
205
|
+
tokens name text-on-fill explicitly:
|
|
206
|
+
|
|
207
|
+
| Token | Tailwind | Use for |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| `--color-semantic-text-on-accent` | `text-dos-text-on-accent` | text/icons on a `background-accent` fill (eidotter uses it for the Button primary label, Badge accent, Tag filled, Tabs pills, FilterBar active, Switch thumb, Accordion header, Terminal title bar). This is the old `text-secondary` value. |
|
|
210
|
+
| `--color-semantic-text-on-brand` | `text-dos-text-on-brand` | text/icons on a brand-amber fill (`background-brand`; eidotter uses it for InlineLink hover/active and the IconButton hover glyph) |
|
|
211
|
+
| `--color-semantic-text-on-light` | `text-dos-text-on-light` | an unfilled element sitting on a light surface; near-black in every theme (eidotter uses it for `Nav` `modern` links) |
|
|
212
|
+
|
|
213
|
+
`text-on-accent` and `text-on-brand` are identical under amber-mono. They
|
|
214
|
+
differ in `cga-amber`, where the accent fill is blue and on-accent text is
|
|
215
|
+
light. So pick by the fill underneath, not by the colour you see today.
|
|
216
|
+
|
|
217
|
+
**Find it.**
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
rg -n 'text-dos-text-secondary|color-semantic-text-secondary|border-dos-text-secondary' \
|
|
221
|
+
src app components pages styles --glob '!node_modules'
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**What to do.** Look at what each hit sits on.
|
|
225
|
+
|
|
226
|
+
- Dark text on an accent fill (`bg-dos-bg-accent`): switch to `text-on-accent`.
|
|
227
|
+
On a brand fill (`bg-dos-bg-brand`): `text-on-brand`. Unfilled text on a
|
|
228
|
+
light surface: `text-on-light`.
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
// before
|
|
232
|
+
<span className="bg-dos-bg-accent text-dos-text-secondary">NEW</span>
|
|
233
|
+
// after
|
|
234
|
+
<span className="bg-dos-bg-accent text-dos-text-on-accent">NEW</span>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```css
|
|
238
|
+
/* before */ .chip--active { color: var(--color-semantic-text-secondary); }
|
|
239
|
+
/* after */ .chip--active { color: var(--color-semantic-text-on-accent); }
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
- De-emphasised text on a dark background: leave it. It is now visible, as you
|
|
243
|
+
intended.
|
|
244
|
+
|
|
245
|
+
**Verify.** Every former hit renders legibly in the default theme and in any
|
|
246
|
+
theme you offer (`light`, `amber-paper`). Check colours with
|
|
247
|
+
`getComputedStyle(el).color`; screenshots taken under WSL/Playwright can shift
|
|
248
|
+
amber hues.
|
|
249
|
+
|
|
250
|
+
### 4. `eidotter/styles` no longer leaks its CSS reset (fonts, link colours) (DMNC-1434)
|
|
251
|
+
|
|
252
|
+
**What changed.** Up to 0.40, `import 'eidotter/styles'` carried Tailwind's
|
|
253
|
+
preflight unlayered. Two parts of it overrode your app's styles whatever their
|
|
254
|
+
specificity: `a { color: inherit; text-decoration: inherit }` turned every link
|
|
255
|
+
the surrounding text colour, and `html, :host { font-family: … }` plus
|
|
256
|
+
Tailwind's default `--font-sans` / `--font-mono` / `--default-font-family` /
|
|
257
|
+
`--default-mono-font-family` variables set a system sans-serif and beat a
|
|
258
|
+
Tailwind v4 `@theme` font. 0.41.0 strips those. eidotter components style their
|
|
259
|
+
own fonts and anchors and render unchanged.
|
|
260
|
+
|
|
261
|
+
Who sees a difference: apps **without a preflight of their own** (no Tailwind)
|
|
262
|
+
that set no font on `html`/`body`. Bare text now shows the browser default font
|
|
263
|
+
(usually a serif), and plain `<a>` outside eidotter components shows the browser
|
|
264
|
+
link colour (blue/purple, underlined). Apps with their own Tailwind keep their
|
|
265
|
+
own preflight, which already resets links; for them the change only removes
|
|
266
|
+
the interference.
|
|
267
|
+
|
|
268
|
+
**Find it.**
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# do you set a font and link styles yourself?
|
|
272
|
+
rg -n 'font-family' --glob '*.{css,scss,astro}' src app styles
|
|
273
|
+
rg -n '(^|[\s,}])a\s*(,|\{|:)' --glob '*.{css,scss}' src app styles
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Then open the app with the new version and look for serif body text or blue
|
|
277
|
+
links.
|
|
278
|
+
|
|
279
|
+
**What to do.** Set what you relied on in your own global stylesheet:
|
|
280
|
+
|
|
281
|
+
```css
|
|
282
|
+
/* global.css — loaded after eidotter/styles */
|
|
283
|
+
html {
|
|
284
|
+
background: var(--color-semantic-background-primary);
|
|
285
|
+
color: var(--color-semantic-text-primary);
|
|
286
|
+
font-family: var(--typography-font-family-body); /* JetBrains Mono Nerd Font */
|
|
287
|
+
/* or var(--typography-font-family-primary) for Perfect DOS VGA 437 everywhere */
|
|
288
|
+
}
|
|
289
|
+
a { color: var(--color-semantic-text-accent); }
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
If you want the old "links look like the text around them" behaviour, add
|
|
293
|
+
`a { color: inherit; text-decoration: inherit; }` yourself. With Tailwind v4,
|
|
294
|
+
put such rules in `@layer base { … }` so your utilities still win.
|
|
295
|
+
|
|
296
|
+
**Verify.** `getComputedStyle(document.body).fontFamily` names your intended
|
|
297
|
+
font. A bare link outside eidotter components is not `rgb(0, 0, 238)` (the
|
|
298
|
+
browser default blue), unless you want it to be.
|
|
299
|
+
|
|
300
|
+
### 5. `Header`: lockup brand by default, quieter retro styling, uppercase nav, `end` slot (DMNC-1584)
|
|
301
|
+
|
|
302
|
+
**What changed.**
|
|
303
|
+
|
|
304
|
+
- **Default brand is the lockup.** When you pass `brandName` and no `children`,
|
|
305
|
+
the header now renders the eiDotter Logo (28px, glow) next to the name in
|
|
306
|
+
uppercase, wide-tracked DOS text. The new prop
|
|
307
|
+
`brand?: 'lockup' | 'mark' | 'text'` (default `'lockup'`) selects it.
|
|
308
|
+
`brand="text"` restores the 0.40 plain-text brand. Headers that pass their
|
|
309
|
+
own `children` as branding render unchanged.
|
|
310
|
+
- **Retro styling.** The strong amber glow becomes a soft glow under a 1px
|
|
311
|
+
dim-amber line. The brand link and the context-row return pill use brand
|
|
312
|
+
amber (`text-brand`) and lift to `text-brand-bright` on hover. Retro `Nav`
|
|
313
|
+
desktop and mobile-panel links and the MENU trigger use the same pair, and
|
|
314
|
+
their labels render uppercase (CSS `text-transform`, so your label strings
|
|
315
|
+
are unchanged). The `modern` variant is unchanged.
|
|
316
|
+
- **New `end` slot.** `end?: ReactNode` renders once: after the desktop nav on
|
|
317
|
+
wide screens, between the brand and the MENU trigger below 768px. Without it
|
|
318
|
+
the DOM is unchanged.
|
|
319
|
+
- **New `skipLinkTarget`.** `skipLinkTarget="#main"` renders a visually hidden
|
|
320
|
+
"Skip to content" link as the header's first child, shown on keyboard focus.
|
|
321
|
+
Off by default.
|
|
322
|
+
|
|
323
|
+
**Find it.**
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
rg -n -A8 '<Header\b' src app components pages # brandName without children?
|
|
327
|
+
rg -n 'eidotter-header|eidotter-nav' --glob '*.{css,scss}' src app styles
|
|
328
|
+
rg -n 'position:\s*absolute' --glob '*.{css,scss}' src app styles | rg -i 'header|toggle|theme'
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**What to do.**
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
// before (0.40): plain-text brand, theme toggle positioned by hand over the header
|
|
335
|
+
<div className="relative">
|
|
336
|
+
<Header brandName="MY SITE" items={nav} activeHref={pathname} />
|
|
337
|
+
<ThemeToggle className="absolute right-16 top-3" />
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
// after (0.41): keep the lockup (or brand="text" for the old look), toggle in `end`
|
|
341
|
+
<Header
|
|
342
|
+
brandName="MY SITE"
|
|
343
|
+
items={nav}
|
|
344
|
+
activeHref={pathname}
|
|
345
|
+
end={<ThemeToggle />}
|
|
346
|
+
skipLinkTarget="#main"
|
|
347
|
+
/>
|
|
348
|
+
<main id="main">…</main>
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
- Decide per site: lockup (default), `brand="mark"` (see "Adopt"), or
|
|
352
|
+
`brand="text"`.
|
|
353
|
+
- Delete CSS that recoloured the retro header/nav to brand amber or forced
|
|
354
|
+
uppercase on nav links. That is now the default.
|
|
355
|
+
- Delete CSS that targeted the old strong glow on `.eidotter-header--retro`.
|
|
356
|
+
- Keep `end` content compact: on mobile it clips before the brand name does.
|
|
357
|
+
- The `end` slot is `overflow: hidden` at every width. A dropdown, menu or
|
|
358
|
+
tooltip opened from it must render in a portal (React Aria popovers such as
|
|
359
|
+
`Select` already do); an in-flow popover is clipped.
|
|
360
|
+
|
|
361
|
+
**Verify.** At 390px the brand, the `end` content and the MENU trigger fit on
|
|
362
|
+
one line. At 1280px it reads brand, nav, then `end`. Tabbing from the address
|
|
363
|
+
bar focuses the skip link first, if you set one.
|
|
364
|
+
|
|
365
|
+
### 6. Overlays rebuilt on `DosDialog`; removed classes (DMNC-1592)
|
|
366
|
+
|
|
367
|
+
**What changed.** `Modal`, `Lightbox` and `CmdPalette` now render inside the
|
|
368
|
+
shared `DosDialog` shell: brand-coloured border with amber glow, square
|
|
369
|
+
corners, a blurred scrim, and a dark title strip (yellow title, `▸` marker,
|
|
370
|
+
uppercase, dim-amber rule). They enter and exit with a shared pop (scale 0.8
|
|
371
|
+
to 1, 150ms). Their z-index is `--z-index-modal` (1040). Modal was 50 and
|
|
372
|
+
Lightbox 60, so opening a Lightbox over an open Modal is no longer supported.
|
|
373
|
+
Props are unchanged except for additions (Modal gained `size` and
|
|
374
|
+
`isDismissable`).
|
|
375
|
+
|
|
376
|
+
Specific visible changes: Modal's yellow frame becomes the brand border and its
|
|
377
|
+
header becomes the strip; long Modal titles wrap. Lightbox gains a strip whose
|
|
378
|
+
title is the `[ n / N ]` counter, spans the viewport minus 32px, and its prev and
|
|
379
|
+
next arrows are pixel chevron `IconButton`s. CmdPalette's `▸ JUMP TO` head loses
|
|
380
|
+
its amber fill and becomes the dark strip; at phone width the box is capped at
|
|
381
|
+
viewport minus 32px.
|
|
382
|
+
|
|
383
|
+
**Removed classes.** CSS that targets these no longer matches anything:
|
|
384
|
+
|
|
385
|
+
| Component | Removed | Target instead |
|
|
386
|
+
|---|---|---|
|
|
387
|
+
| Modal | `eidotter-modal-overlay`, `eidotter-modal-overlay--entering`, `eidotter-modal-overlay--exiting`, `eidotter-modal`, `eidotter-modal--entering`, `eidotter-modal--exiting`, `eidotter-modal__header`, `eidotter-modal__title` | `eidotter-dialog__overlay`, `eidotter-dialog`, `eidotter-dialog__container`, `eidotter-dialog__head`, `eidotter-dialog__title` |
|
|
388
|
+
| Lightbox | `eidotter-lightbox-overlay`, `eidotter-lightbox-overlay--entering`, `eidotter-lightbox-overlay--exiting`, `eidotter-lightbox`, `eidotter-lightbox--entering`, `eidotter-lightbox--exiting` | the `eidotter-dialog*` classes above |
|
|
389
|
+
| CmdPalette | `eidotter-cmdpal-overlay`, `eidotter-cmdpal-overlay--entering`, `eidotter-cmdpal-overlay--exiting`, `eidotter-cmdpal`, `eidotter-cmdpal--entering`, `eidotter-cmdpal--exiting`, `eidotter-cmdpal__head` | the `eidotter-dialog*` classes; the head is `eidotter-dialog__head` |
|
|
390
|
+
| Card | `eidotter-card__header`, `eidotter-card__footer` | `eidotter-window__strip`, `eidotter-window__footer` |
|
|
391
|
+
| DosFigure | `eidotter-dos-figure__title` | `eidotter-window__strip`, `eidotter-window__title` |
|
|
392
|
+
| Mark | `eidotter-mark__blob`, `eidotter-mark__blob--morph` | the root `eidotter-mark` (the drawing is now an SVG) |
|
|
393
|
+
|
|
394
|
+
Still present: `eidotter-modal__container`, `__body`, `__footer`, `__close`;
|
|
395
|
+
`eidotter-lightbox__container`, `__counter`, `__close`, `__figure`, `__image`,
|
|
396
|
+
`__caption`, `__nav`; `eidotter-cmdpal__container`, `__input`, `__results`,
|
|
397
|
+
`__item*`, `__empty`, `__footer`, `__blink`, plus the new
|
|
398
|
+
`eidotter-cmdpal__text--bright` / `--muted`. The close and navigation classes
|
|
399
|
+
(`eidotter-modal__close`, `eidotter-lightbox__close`, `eidotter-lightbox__nav`,
|
|
400
|
+
`eidotter-nav__close`, `eidotter-alert__close`, `eidotter-notification__close`,
|
|
401
|
+
`eidotter-tag__close`) stay on the buttons as hooks, but their old visual
|
|
402
|
+
styles are gone: the buttons are now `IconButton`s (class
|
|
403
|
+
`eidotter-icon-button`).
|
|
404
|
+
|
|
405
|
+
The `eidotter-dialog*` classes are shared by every DosDialog. To restyle one
|
|
406
|
+
kind of overlay only, scope your rule by the component's container class,
|
|
407
|
+
which sits on the same element as `eidotter-dialog__container`:
|
|
408
|
+
`.eidotter-modal__container`, `.eidotter-lightbox__container` or
|
|
409
|
+
`.eidotter-cmdpal__container`. Modal and CmdPalette also merge your
|
|
410
|
+
`className` onto that element.
|
|
411
|
+
|
|
412
|
+
**Find it.**
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
rg -n 'eidotter-(modal-overlay|modal--|modal__header|modal__title|lightbox-overlay|lightbox--|cmdpal-overlay|cmdpal--|cmdpal__head|card__header|card__footer|dos-figure__title|mark__blob)' \
|
|
416
|
+
src app components pages styles
|
|
417
|
+
rg -n '\.eidotter-(modal|lightbox|cmdpal)\b' --glob '*.{css,scss}' src app styles
|
|
418
|
+
rg -n 'eidotter-(modal|lightbox|alert|notification|tag|nav)__close|eidotter-lightbox__nav' \
|
|
419
|
+
--glob '*.{css,scss}' src app styles
|
|
420
|
+
rg -n 'z-index' --glob '*.{css,scss}' src app styles | rg -i 'modal|lightbox|overlay|cmdpal'
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**What to do.**
|
|
424
|
+
|
|
425
|
+
- Delete overrides that restyled the old frame, header, scrim or enter/exit
|
|
426
|
+
animation. The new chrome is the house style; first see whether you still
|
|
427
|
+
need anything.
|
|
428
|
+
- Retarget what you still need, using the table above.
|
|
429
|
+
- Delete restyles of the close and prev/next buttons. The shared IconButton
|
|
430
|
+
already has hover, focus and disabled states.
|
|
431
|
+
- If your own fixed or sticky UI must sit above or below dialogs, compare it
|
|
432
|
+
against 1040, not 50 or 60.
|
|
433
|
+
|
|
434
|
+
```css
|
|
435
|
+
/* before (0.40) */
|
|
436
|
+
.eidotter-modal__header { background: var(--color-semantic-background-secondary); }
|
|
437
|
+
.eidotter-modal-overlay { backdrop-filter: blur(4px); }
|
|
438
|
+
/* after (0.41): usually delete both; if you must keep a tweak, retarget it */
|
|
439
|
+
.eidotter-modal__container .eidotter-dialog__head { /* … */ }
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Verify.** Open each Modal, Lightbox and CmdPalette in your app. Escape and a
|
|
443
|
+
backdrop click close them, focus returns to the trigger, and nothing of yours
|
|
444
|
+
paints over the dialog. A Modal with a long title wraps instead of clipping.
|
|
445
|
+
|
|
446
|
+
### 7. Other visible restyles
|
|
447
|
+
|
|
448
|
+
Each of these is CSS only, with no prop change. Search for overrides and
|
|
449
|
+
delete or retarget them.
|
|
450
|
+
|
|
451
|
+
- **Card** is built on `DosWindow`. The header becomes the dark strip (yellow
|
|
452
|
+
xs uppercase title, `▸` marker, dim-amber rule), and the footer becomes the
|
|
453
|
+
window footer. `elevated` is now the brand border plus `--shadow-drop`
|
|
454
|
+
instead of a near-black border with a 4px offset shadow. Find:
|
|
455
|
+
`rg -n 'eidotter-card' --glob '*.{css,scss}'`.
|
|
456
|
+
- **DosFigure** is built on `DosWindow`. The amber title bar with dark text
|
|
457
|
+
becomes the dark strip. Find: `rg -n 'eidotter-dos-figure' --glob '*.{css,scss}'`.
|
|
458
|
+
- **Alert and Notification** are square (no 4px radius) and their close is an
|
|
459
|
+
outlined 36×36 IconButton. Find:
|
|
460
|
+
`rg -n 'eidotter-(alert|notification)' --glob '*.{css,scss}'`.
|
|
461
|
+
- **Tag remove** is a bare IconButton with the pixel X instead of `[x]`. The
|
|
462
|
+
accessible name is still `Remove <label>`. Tests that query the text `[x]`
|
|
463
|
+
must query the button by role and name instead:
|
|
464
|
+
|
|
465
|
+
```ts
|
|
466
|
+
// before
|
|
467
|
+
screen.getByText('[x]');
|
|
468
|
+
// after
|
|
469
|
+
screen.getByRole('button', { name: 'Remove react' });
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Find: `rg -n "\[x\]" --glob '*.{test,spec}.{ts,tsx,js,jsx}'`.
|
|
473
|
+
- **Lightbox prev/next** are chevron IconButtons instead of `◀ ▶` text. Find
|
|
474
|
+
tests that query those glyphs: `rg -n '◀|▶' --glob '*.{test,spec}.*'`.
|
|
475
|
+
- **Logo and Mark** share one SVG drawing (DMNC-1586). Logo's flat yolk becomes
|
|
476
|
+
a lit yolk with highlights, and its glow drops from 6px to 5px. Mark renders
|
|
477
|
+
that SVG instead of a CSS blob. The `morph` prop now drives a slow breath
|
|
478
|
+
(scale to 1.045, 4.3s) and is off under reduced motion. Mark gains `glow`
|
|
479
|
+
(default `true`). `size`, `label`, `arms`, the ref and the root class
|
|
480
|
+
`eidotter-mark` are unchanged. Find:
|
|
481
|
+
`rg -n 'eidotter-(logo|mark)' --glob '*.{css,scss}'` and any copied favicon
|
|
482
|
+
(`rg --files | rg -i 'favicon|icon\.svg'`). Re-copy the favicon (see
|
|
483
|
+
"Adopt").
|
|
484
|
+
- **Motion.** Select's popover pops instead of dropping 4px. TimelineContainer
|
|
485
|
+
zoom views and the master-detail pane fade instead of rising. Several
|
|
486
|
+
components share keyframes now (`eidotter-pop-in/out`,
|
|
487
|
+
`eidotter-fade-in/out`, `eidotter-breathe`). If your CSS overrode eidotter's
|
|
488
|
+
internal keyframe names (`modal-crt-enter`, `cmdpal-enter`, `tag-enter`,
|
|
489
|
+
`badge-enter`, `alert-enter`, `notification-enter`, `select-pop-in`,
|
|
490
|
+
`eidotter-mark-morph`, `eidotter-card-enter`, `eidotter-inline-expand-fade`,
|
|
491
|
+
`eidotter-timeline-node-enter`, `eidotter-skeleton-breathe`,
|
|
492
|
+
`eidotter-health-breathe`, …), those names no longer exist. Find:
|
|
493
|
+
`rg -n 'modal-crt|cmdpal-|badge-enter|tag-enter|tag-exit|alert-enter|notification-enter|select-pop|backdrop-open|timeline-fade-in|master-detail-fade|blink-loading|eidotter-(mark-morph|card-enter|inline-expand-fade|timeline-node-enter|skeleton-breathe|health-breathe)' --glob '*.{css,scss}'`.
|
|
494
|
+
- **Progress** sizes are distinct again: `sm`/`md`/`lg` render 16/20/22px (were
|
|
495
|
+
16/16/18px).
|
|
496
|
+
|
|
497
|
+
### 8. Focus rings (DMNC-1436)
|
|
498
|
+
|
|
499
|
+
**What changed.** Keyboard focus is now a visible amber ring. `Button`'s ring
|
|
500
|
+
was cancelled under Tailwind v4 and shows again. `Input`, `Select` and the
|
|
501
|
+
Accordion header (`Section`) draw a 2px amber outline at 2px offset on
|
|
502
|
+
`:focus-visible`. Their focus border used to be invisible under amber-mono.
|
|
503
|
+
The Accordion header's flush box-shadow ring is replaced by that outline. The
|
|
504
|
+
CmdPalette input gets the same 2px outline. Under amber-mono the focus colour
|
|
505
|
+
(`--color-semantic-border-focus`) is now amber `#FFB000` (was amber-bright).
|
|
506
|
+
|
|
507
|
+
**Find it.** Look for focus styles you added to fill the gap; they may now
|
|
508
|
+
double up:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
rg -n -B2 -A4 'focus' --glob '*.{css,scss}' src app styles | rg 'eidotter-'
|
|
512
|
+
rg -n 'focus-visible:(outline|ring)' src app components | rg '<(Button|Input|Select|Section)\b'
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**What to do.** Delete your own focus outlines and rings on eidotter Button,
|
|
516
|
+
Input, Select and Accordion. Keep focus styles on your own elements.
|
|
517
|
+
|
|
518
|
+
**Verify.** Tab through a page: each eidotter control shows exactly one amber
|
|
519
|
+
ring.
|
|
520
|
+
|
|
521
|
+
### 9. Renamed variants
|
|
522
|
+
|
|
523
|
+
None at runtime. 0.41.0 corrects variant keys in the component registry
|
|
524
|
+
metadata used by eidotter's own tooling (DMNC-1459). No component prop or
|
|
525
|
+
variant value changed; Badge, Tag, Alert and Button props are as in 0.40.
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## Adopt the new pieces
|
|
530
|
+
|
|
531
|
+
Replace hand-rolled patterns with these. They are optional, but they are the
|
|
532
|
+
point of the release: one shared chrome instead of a slightly different copy
|
|
533
|
+
in every site.
|
|
534
|
+
|
|
535
|
+
All imports below use the barrel (`'eidotter'`), which is right for client
|
|
536
|
+
code. For Next.js server components, see "RSC deep imports" at the end of this
|
|
537
|
+
section.
|
|
538
|
+
|
|
539
|
+
### IconButton: every close, prev/next, remove icon control
|
|
540
|
+
|
|
541
|
+
An icon-only React Aria button: a 1px outlined square with an `Icon` glyph,
|
|
542
|
+
amber fill on hover, a 2px brand outline on focus, half opacity when disabled.
|
|
543
|
+
|
|
544
|
+
| Prop | Type | Default | Notes |
|
|
545
|
+
|---|---|---|---|
|
|
546
|
+
| `icon` | `IconName` | required | e.g. `'Close'`, `'Chevron Left'`, `'Chevron Right'`, `'Add'`, `'Check'` |
|
|
547
|
+
| `label` | `string` | required | becomes the `aria-label` |
|
|
548
|
+
| `size` | `'md' \| 'window'` | `'md'` | md is 36×36 with a 20px glyph; window is 28×28 with a 16px glyph for dense chrome |
|
|
549
|
+
| `variant` | `'outline' \| 'bare'` | `'outline'` | bare has no resting outline |
|
|
550
|
+
| `isDisabled`, `onPress`, `excludeFromTabOrder`, `className` | | | `onPress` receives a React Aria `PressEvent` |
|
|
551
|
+
|
|
552
|
+
Available icon names: `Info`, `Warning`, `Error`, `Done`, `Check`, `Close`,
|
|
553
|
+
`Chevron Up`, `Chevron Down`, `Chevron Left`, `Chevron Right`, `App`,
|
|
554
|
+
`Cancel` (a minus glyph, for minimize), `Fullscreen`, `Add`.
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
rg -n '(aria-label=.(close|dismiss|previous|next|remove)|>\s*(×|✕|x|\[x\]|◀|▶|‹|›)\s*<)' -i src app components
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
// before: a hand-rolled close button
|
|
562
|
+
<button className="close-btn" aria-label="Close" onClick={onClose}>×</button>
|
|
563
|
+
// after
|
|
564
|
+
import { IconButton } from 'eidotter';
|
|
565
|
+
<IconButton icon="Close" label="Close" onPress={onClose} />
|
|
566
|
+
<IconButton icon="Chevron Left" label="Previous image" onPress={prev} isDisabled={index === 0} />
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
IconButton is a client component (it carries `'use client'` in the deep-import
|
|
570
|
+
build).
|
|
571
|
+
|
|
572
|
+
### DosDialog: custom modal and overlay shells
|
|
573
|
+
|
|
574
|
+
Use `Modal` for an ordinary titled dialog (`isOpen`, `onOpenChange` /
|
|
575
|
+
`onClose`, `title`, `footer`, `size`, `isDismissable`). Use `DosDialog` when
|
|
576
|
+
you are building your own overlay shell, such as a settings sheet, a
|
|
577
|
+
search-results overlay, or a confirm dialog with custom chrome. React Aria
|
|
578
|
+
provides the focus trap, scroll lock, Escape and backdrop dismissal.
|
|
579
|
+
|
|
580
|
+
Props: `open` (required), `onOpenChange`, `placement` (`'center'` default |
|
|
581
|
+
`'top'`), `size` (`'sm'` 24rem, `'md'` 30rem default, `'lg'` 40rem, `'full'`),
|
|
582
|
+
`head` (`{ title, end?, marker?, decorative? }` or any ReactNode), `footer`,
|
|
583
|
+
`isDismissable` (default `true`), `aria-label` / `aria-labelledby`,
|
|
584
|
+
`className`. A non-decorative `head.title` renders as the `<h2>` and names the
|
|
585
|
+
dialog. Otherwise pass `aria-label`; in development an unnamed open dialog logs
|
|
586
|
+
a warning.
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
rg -n 'createPortal|role="dialog"|aria-modal|fixed inset-0' src app components
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
```tsx
|
|
593
|
+
import { useState } from 'react';
|
|
594
|
+
import { DosDialog, IconButton, Button } from 'eidotter';
|
|
595
|
+
|
|
596
|
+
function SettingsDialog() {
|
|
597
|
+
const [open, setOpen] = useState(false);
|
|
598
|
+
return (
|
|
599
|
+
<>
|
|
600
|
+
<Button onPress={() => setOpen(true)}>Settings</Button>
|
|
601
|
+
<DosDialog
|
|
602
|
+
open={open}
|
|
603
|
+
onOpenChange={setOpen}
|
|
604
|
+
size="sm"
|
|
605
|
+
head={{
|
|
606
|
+
title: 'SETTINGS',
|
|
607
|
+
end: <IconButton icon="Close" label="Close settings" onPress={() => setOpen(false)} />,
|
|
608
|
+
}}
|
|
609
|
+
footer={<Button onPress={() => setOpen(false)}>Done</Button>}
|
|
610
|
+
>
|
|
611
|
+
{/* your content */}
|
|
612
|
+
</DosDialog>
|
|
613
|
+
</>
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
DosDialog does not add a close button for you; pass one in `head.end` as
|
|
619
|
+
above. DosDialog is a client component.
|
|
620
|
+
|
|
621
|
+
### DosWindow: in-page window chrome
|
|
622
|
+
|
|
623
|
+
The same title strip as DosDialog on a brand border with `--shadow-drop`, but
|
|
624
|
+
in page flow, with no glow and no backdrop. Card and DosFigure are built on it.
|
|
625
|
+
Use it for panels you currently frame by hand with a border and a title bar.
|
|
626
|
+
|
|
627
|
+
Props: `title`, `marker` (default `true`, the `▸`), `active` (default `true`;
|
|
628
|
+
inactive dims the title), `controls` (IconButtons for the strip's end),
|
|
629
|
+
`footer`, `className`, plus any `<div>` attribute. With neither `title` nor
|
|
630
|
+
`controls` there is no strip. The strip title is a `<span>`, not a heading;
|
|
631
|
+
pass your own heading element as `title` if the window belongs in the document
|
|
632
|
+
outline.
|
|
633
|
+
|
|
634
|
+
```tsx
|
|
635
|
+
import { DosWindow, IconButton } from 'eidotter';
|
|
636
|
+
|
|
637
|
+
<DosWindow
|
|
638
|
+
title="SYSTEM.LOG"
|
|
639
|
+
controls={<IconButton icon="Close" label="Hide log" onPress={hideLog} />}
|
|
640
|
+
footer="3 entries"
|
|
641
|
+
>
|
|
642
|
+
<ul>…</ul>
|
|
643
|
+
</DosWindow>
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
DosWindow is server-safe: no hooks, no `'use client'`. In a Next.js server
|
|
647
|
+
component you can render it directly from `eidotter/components/DosWindow`. Put
|
|
648
|
+
any `controls` with `onPress` handlers in a client component, because a server
|
|
649
|
+
component cannot pass functions.
|
|
650
|
+
|
|
651
|
+
### CmdPalette: mount once, in the root layout
|
|
652
|
+
|
|
653
|
+
Mount one `<CmdPalette>` per site in the root layout, so ⌘K / Ctrl+K works on
|
|
654
|
+
every page. The default `hotkey` is `'mod+k'`; pass `hotkey={false}` to open it
|
|
655
|
+
yourself. `items` should list only that site's public routes. The palette
|
|
656
|
+
requests close on Escape, backdrop click and item selection through
|
|
657
|
+
`onOpenChange`.
|
|
658
|
+
|
|
659
|
+
```tsx
|
|
660
|
+
// components/SiteCmdPalette.tsx (Next.js App Router)
|
|
661
|
+
'use client';
|
|
662
|
+
import { useState } from 'react';
|
|
663
|
+
import { useRouter } from 'next/navigation';
|
|
664
|
+
import { CmdPalette, type CmdPaletteItem } from 'eidotter';
|
|
665
|
+
|
|
666
|
+
const routes = [
|
|
667
|
+
{ path: '/', label: 'HOME' },
|
|
668
|
+
{ path: '/about', label: 'ABOUT' },
|
|
669
|
+
];
|
|
670
|
+
|
|
671
|
+
export function SiteCmdPalette() {
|
|
672
|
+
const [open, setOpen] = useState(false);
|
|
673
|
+
const router = useRouter();
|
|
674
|
+
const items: CmdPaletteItem[] = routes.map((r) => ({
|
|
675
|
+
id: r.path,
|
|
676
|
+
label: r.label,
|
|
677
|
+
onSelect: () => router.push(r.path),
|
|
678
|
+
}));
|
|
679
|
+
return <CmdPalette open={open} onOpenChange={setOpen} items={items} />;
|
|
680
|
+
}
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
```tsx
|
|
684
|
+
// app/layout.tsx
|
|
685
|
+
import { SiteCmdPalette } from '@/components/SiteCmdPalette';
|
|
686
|
+
|
|
687
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
688
|
+
return (
|
|
689
|
+
<html lang="en">
|
|
690
|
+
<body>
|
|
691
|
+
{children}
|
|
692
|
+
<SiteCmdPalette />
|
|
693
|
+
</body>
|
|
694
|
+
</html>
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
- Astro: put the same component (with `onSelect: () => { window.location.href = r.path; }`)
|
|
700
|
+
in the base layout as `<SiteCmdPalette client:load />`.
|
|
701
|
+
- Vite with react-router: render it once next to `<Routes>` and navigate with
|
|
702
|
+
`useNavigate()`.
|
|
703
|
+
- Show a ⌘K hint (in the site `Footer` or the Header `end` slot) only where
|
|
704
|
+
the palette is mounted. Not in `footerHint`, which renders only inside the
|
|
705
|
+
open palette.
|
|
706
|
+
|
|
707
|
+
### `eidotter/favicon.svg`
|
|
708
|
+
|
|
709
|
+
The logomark favicon ships in the package (regenerated in 0.41.0 from the new
|
|
710
|
+
Logo drawing). It is an SVG only. Copy it into your app at build time instead of
|
|
711
|
+
committing a copy that goes stale:
|
|
712
|
+
|
|
713
|
+
```json
|
|
714
|
+
// package.json (any framework); for Next.js App Router change the target to app/icon.svg
|
|
715
|
+
{
|
|
716
|
+
"scripts": {
|
|
717
|
+
"copy-favicon": "node -e \"require('fs').copyFileSync(require.resolve('eidotter/favicon.svg'), 'public/favicon.svg')\"",
|
|
718
|
+
"predev": "npm run copy-favicon",
|
|
719
|
+
"prebuild": "npm run copy-favicon"
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
- **Next.js App Router:** copy to `app/icon.svg`. Next generates the
|
|
725
|
+
`<link rel="icon">` itself. Remove any old `app/favicon.ico` or `app/icon.*`
|
|
726
|
+
you no longer want.
|
|
727
|
+
- **Vite:** copy to `public/favicon.svg`, then in `index.html`:
|
|
728
|
+
`<link rel="icon" type="image/svg+xml" href="/favicon.svg" />`.
|
|
729
|
+
- **Astro:** copy to `public/favicon.svg`, then in the base layout `<head>`:
|
|
730
|
+
`<link rel="icon" type="image/svg+xml" href="/favicon.svg" />`.
|
|
731
|
+
|
|
732
|
+
Add the copied path to `.gitignore` if you generate it on every build.
|
|
733
|
+
|
|
734
|
+
### `amber-paper` theme and a theme toggle
|
|
735
|
+
|
|
736
|
+
A third theme next to the dark default and `light`: reverse video, with an
|
|
737
|
+
amber ground and near-black ink. Functional colour stays monochrome and there
|
|
738
|
+
is no phosphor glow. Themes are opt-in CSS plus an attribute (or class) on an
|
|
739
|
+
ancestor, usually `<html>`:
|
|
740
|
+
|
|
741
|
+
```ts
|
|
742
|
+
import 'eidotter/styles';
|
|
743
|
+
import 'eidotter/themes/light.css';
|
|
744
|
+
import 'eidotter/themes/amber-paper.css';
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
```html
|
|
748
|
+
<html data-theme="amber-paper"> <!-- or class="theme-amber-paper" -->
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
No attribute means the dark default. `data-theme="light"` is the light theme
|
|
752
|
+
(`eidotter/themes/light.css`). `data-theme="amber-mono"` is already in
|
|
753
|
+
`eidotter/styles`. The house convention is the amber/dark default, with other
|
|
754
|
+
themes offered through a toggle. A minimal toggle for the Header `end` slot:
|
|
755
|
+
|
|
756
|
+
```tsx
|
|
757
|
+
'use client';
|
|
758
|
+
import { useEffect, useState } from 'react';
|
|
759
|
+
import { Button } from 'eidotter';
|
|
760
|
+
|
|
761
|
+
const THEMES = ['default', 'light', 'amber-paper'] as const;
|
|
762
|
+
type Theme = (typeof THEMES)[number];
|
|
763
|
+
|
|
764
|
+
export function ThemeToggle() {
|
|
765
|
+
const [theme, setTheme] = useState<Theme>('default');
|
|
766
|
+
useEffect(() => {
|
|
767
|
+
try {
|
|
768
|
+
const saved = localStorage.getItem('theme') as Theme | null;
|
|
769
|
+
if (saved && THEMES.includes(saved)) setTheme(saved);
|
|
770
|
+
} catch {}
|
|
771
|
+
}, []);
|
|
772
|
+
useEffect(() => {
|
|
773
|
+
const root = document.documentElement;
|
|
774
|
+
if (theme === 'default') delete root.dataset.theme;
|
|
775
|
+
else root.dataset.theme = theme;
|
|
776
|
+
try { localStorage.setItem('theme', theme); } catch {}
|
|
777
|
+
}, [theme]);
|
|
778
|
+
const next = THEMES[(THEMES.indexOf(theme) + 1) % THEMES.length];
|
|
779
|
+
return (
|
|
780
|
+
<Button variant="secondary" size="sm" onPress={() => setTheme(next)}>
|
|
781
|
+
THEME: {theme.toUpperCase()}
|
|
782
|
+
</Button>
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
On server-rendered sites, set the attribute before first paint so a saved
|
|
788
|
+
theme does not flash. A tiny inline script in `<head>` does it:
|
|
789
|
+
`<script>try{var t=localStorage.getItem('theme');if(t&&t!=='default')document.documentElement.dataset.theme=t}catch(e){}</script>`.
|
|
790
|
+
In React, put `suppressHydrationWarning` on `<html>`.
|
|
791
|
+
|
|
792
|
+
Check your own CSS under amber-paper. Anything hard-coded to "dark background,
|
|
793
|
+
light text" breaks there; paint with `var(--color-semantic-*)` roles.
|
|
794
|
+
|
|
795
|
+
### Mark in the header
|
|
796
|
+
|
|
797
|
+
`<Header brand="mark" brandName="MY SITE" … />` shows the breathing Mark
|
|
798
|
+
(28px) instead of the static Logo. Use one or the other across a site.
|
|
799
|
+
Standalone: `import { Mark } from 'eidotter'`; `<Mark size={48} />`. Pass
|
|
800
|
+
`label=""` when it is decorative, and `morph={false}` for a still mark.
|
|
801
|
+
|
|
802
|
+
### RSC deep imports (Next.js server components)
|
|
803
|
+
|
|
804
|
+
The `eidotter` barrel is client-only. Importing it from a server component
|
|
805
|
+
fails. In server components, deep-import per component:
|
|
806
|
+
|
|
807
|
+
```tsx
|
|
808
|
+
import { DosWindow } from 'eidotter/components/DosWindow'; // server-safe
|
|
809
|
+
import { Header } from 'eidotter/components/Header'; // server-safe (its interactive bits are client leaves)
|
|
810
|
+
import { IconButton } from 'eidotter/components/IconButton'; // client reference
|
|
811
|
+
import { DosDialog } from 'eidotter/components/DosDialog'; // client reference
|
|
812
|
+
import { Logo, Mark } from 'eidotter/components/Brand';
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
Interactive components resolve as client references, so they render, but you
|
|
816
|
+
cannot pass them function props such as `onPress` from a server component;
|
|
817
|
+
wrap those in your own `'use client'` component. CSS still comes from one
|
|
818
|
+
`import 'eidotter/styles'` in the root layout.
|
|
819
|
+
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
## Upgrade checklist
|
|
823
|
+
|
|
824
|
+
Work top to bottom. Each step points at the section above that explains it.
|
|
825
|
+
|
|
826
|
+
- [ ] Read every guide in `node_modules/eidotter/migrations/` between your old
|
|
827
|
+
version and 0.41.0, oldest first (see `README.md` in that folder).
|
|
828
|
+
- [ ] `cp node_modules/eidotter/dist/eidotter.css /tmp/eidotter-old.css` (before the bump).
|
|
829
|
+
- [ ] `npm install eidotter@^0.41.0`, then `npm ls eidotter` shows 0.41.x. Commit the lockfile.
|
|
830
|
+
- [ ] No-Tailwind apps: run the class diff from section 2 and fix every real hit.
|
|
831
|
+
- [ ] No-preflight apps: set `html` font, colours and `a` colour yourself (section 4).
|
|
832
|
+
- [ ] Preset apps: review `text-xs` / `text-sm` hits; delete redundant 16px overrides (section 1).
|
|
833
|
+
- [ ] Replace `text-secondary` used on amber or light fills with `text-on-accent` (section 3).
|
|
834
|
+
- [ ] Header: choose `brand` (`lockup` default, `mark`, or `text`), move hand-placed header controls into `end`, consider `skipLinkTarget` (section 5).
|
|
835
|
+
- [ ] Delete or retarget CSS on removed classes (Modal, Lightbox, CmdPalette, Card, DosFigure, Mark) and on the old close and nav buttons (section 6).
|
|
836
|
+
- [ ] Delete overrides fighting the new Card, DosFigure, Alert, Notification, Logo and Mark looks, and references to retired keyframe names (section 7).
|
|
837
|
+
- [ ] Delete your own focus rings on eidotter Button, Input, Select and Accordion (section 8).
|
|
838
|
+
- [ ] Update tests that query `[x]`, `◀`, `▶`, the old classes or the old plain-text brand.
|
|
839
|
+
- [ ] Optional adoption: IconButton for icon controls, DosDialog / DosWindow for hand-rolled shells, one CmdPalette in the root layout, the favicon copy script, an amber-paper option in the theme toggle.
|
|
840
|
+
- [ ] Next.js: server components import from `eidotter/components/<Name>`, not the barrel.
|
|
841
|
+
- [ ] Run the app's lint, typecheck, tests and production build.
|
|
842
|
+
- [ ] Visual check at **390px** and **1280px** wide, on every page template: header (brand, nav, `end`, MENU), body text size and font, link colours, cards and figures, every dialog (open, Escape, backdrop click, focus return), alerts and notifications, keyboard focus rings, and every theme you offer. Verify colours with `getComputedStyle` rather than screenshots.
|
|
843
|
+
- [ ] Open the PR with before/after screenshots at both widths. **A human must
|
|
844
|
+
sign off on the visuals before merge.** Tests passing is not sufficient
|
|
845
|
+
for this release.
|
|
846
|
+
|
|
847
|
+
---
|
|
848
|
+
|
|
849
|
+
## Jumping from older versions
|
|
850
|
+
|
|
851
|
+
If your range was below `^0.40`, these also land when you bump. Each one is
|
|
852
|
+
additive or automatic unless noted. Details are in the eidotter
|
|
853
|
+
[CHANGELOG](https://github.com/CinimoDY/eiDotter/blob/main/CHANGELOG.md). It is
|
|
854
|
+
not shipped in the npm package; read it on GitHub.
|
|
855
|
+
|
|
856
|
+
- **0.38.0:** `article` entry kind for `TimelineContainer` (thumbnail strip and
|
|
857
|
+
summary when collapsed; gallery, body and read-more when expanded). Additive.
|
|
858
|
+
- **0.38.0:** `RetroEffects` `boot` no longer flashes content before the
|
|
859
|
+
turn-on; the cover now ships in the server HTML.
|
|
860
|
+
- **0.38.1:** fonts are no longer inlined into `dist/eidotter.css` (5.7MB down
|
|
861
|
+
to about 150KB). Your bundler must resolve the packaged font `url()`s; this
|
|
862
|
+
works out of the box in Vite, Astro and Next.js.
|
|
863
|
+
- **0.39.0:** connector-system navigation: `Header` `context` row, `Mark`,
|
|
864
|
+
`Connector`, `TimelineFeed`, `TimelinePage`. Additive.
|
|
865
|
+
- **0.39.0:** nav link hrefs (`Breadcrumb`, `Nav`, `Footer`, `Header brandHref`)
|
|
866
|
+
are sanitised; `javascript:` and similar render as plain text. `isSafeHref`
|
|
867
|
+
is exported.
|
|
868
|
+
- **0.40.0:** health and metabolism family: `Gauge`, `Meter`/`MeterGroup`,
|
|
869
|
+
`RangeBar`, `SeriesBars`, `DecayStrip`, `VitalsStrip`, plus `Stat`
|
|
870
|
+
`unit`/`note`/`target`. Additive, with no medical defaults.
|
|
871
|
+
- **0.40.0:** `InlineExpand` expands inline (marker-pen highlight, trailing
|
|
872
|
+
`[-]`). This is a visible redesign; recheck pages that use it.
|
|
873
|
+
- **0.40.1:** every prompt cursor (CommandPrompt, ChatInput, streaming
|
|
874
|
+
ChatMessage, Terminal) is the DOS underscore `_`, not a `█` block. Visible.
|
|
875
|
+
- **0.40.2:** `eidotter/favicon.svg` export (see "Adopt").
|
|
876
|
+
|
|
877
|
+
- **0.38.0 entry:** two-tier typography. Display text stays Perfect DOS VGA
|
|
878
|
+
437 and body text (`.dos-body`, `font-dos-body`) is JetBrains Mono Nerd Font.
|
|
879
|
+
|
|
880
|
+
Coming from 0.37 or older: also read the CHANGELOG entries for 0.33–0.37,
|
|
881
|
+
including the RSC deep imports `eidotter/components/<Name>` (0.37.1, DMNC-1130).
|