@blakesteve/roster 4.4.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -69
- package/dist/{Table-B3KkU-Bc.cjs → Table-C8f0KOSf.cjs} +2 -2
- package/dist/{Table-CJZFk__H.js → Table-DuLc2mEo.js} +7 -7
- package/dist/data-table.cjs.js +1 -1
- package/dist/data-table.es.js +6 -6
- package/dist/roster.cjs.js +2 -2
- package/dist/roster.css +1 -1
- package/dist/roster.es.js +233 -233
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -41,7 +41,10 @@ npm install @tanstack/react-table
|
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
```tsx
|
|
44
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
DataTable,
|
|
46
|
+
type RosterTableFeatures,
|
|
47
|
+
} from "@blakesteve/roster/data-table";
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
It is a peer rather than a bundled dependency because v9 types column
|
|
@@ -87,7 +90,7 @@ stripping padding off buttons and turning `border-transparent` into a visible
|
|
|
87
90
|
1px line. **Below `utilities`**, so your app's classes and variants such as
|
|
88
91
|
`dark:hidden` still win.
|
|
89
92
|
|
|
90
|
-
Layers are ordered by
|
|
93
|
+
Layers are ordered by _first registration_, so importing Roster before Tailwind
|
|
91
94
|
is the reliable arrangement. If you would rather not depend on import order at
|
|
92
95
|
all, declare the same line yourself at the top of your global stylesheet and it
|
|
93
96
|
holds regardless.
|
|
@@ -130,7 +133,9 @@ document head:
|
|
|
130
133
|
<script>
|
|
131
134
|
try {
|
|
132
135
|
var s = localStorage.getItem("roster-theme");
|
|
133
|
-
var dark = s
|
|
136
|
+
var dark = s
|
|
137
|
+
? s === "dark"
|
|
138
|
+
: matchMedia("(prefers-color-scheme: dark)").matches;
|
|
134
139
|
if (dark) document.documentElement.classList.add("dark");
|
|
135
140
|
} catch (e) {}
|
|
136
141
|
</script>
|
|
@@ -140,9 +145,157 @@ If you pass a custom `storageKey`, change the script to match — a mismatch mea
|
|
|
140
145
|
the script and the toggle disagree, which shows up as a flash on every reload.
|
|
141
146
|
|
|
142
147
|
`Navbar`'s `themeMode` prop is a different thing: it describes what palette the
|
|
143
|
-
bar paints
|
|
148
|
+
bar paints _itself_ with. Pair them with `themeMode="auto"` and the nav follows
|
|
144
149
|
whatever `ThemeToggle` sets.
|
|
145
150
|
|
|
151
|
+
### The UI font
|
|
152
|
+
|
|
153
|
+
Controls, labels and table cells render in `--roster-font-ui`. Set nothing and
|
|
154
|
+
they use a system sans stack, which is the point: without it they would inherit
|
|
155
|
+
whatever your app puts on `body`, and an app that reads in a serif would get
|
|
156
|
+
serif buttons and serif badges.
|
|
157
|
+
|
|
158
|
+
To match your own UI face, define the variable once:
|
|
159
|
+
|
|
160
|
+
```css
|
|
161
|
+
:root {
|
|
162
|
+
--roster-font-ui: "Archivo", ui-sans-serif, system-ui, sans-serif;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Two sets of components opt out. `Card` and `Link` inherit on purpose, because
|
|
167
|
+
they wrap your content and that text is not Roster's to restyle. `Eyebrow`,
|
|
168
|
+
`InlineCode`, `Stat`, `Pullquote`, `DescriptionList`, `MatchupCard` and
|
|
169
|
+
`Countdown` ask for a monospace face as a design decision.
|
|
170
|
+
|
|
171
|
+
### Solid fill contrast
|
|
172
|
+
|
|
173
|
+
`solid` is the one variant where a component picks both the background and the
|
|
174
|
+
text on it, so it can fail contrast on its own with no help from your app. Every
|
|
175
|
+
solid fill in `Badge`, `Pill` and `Button` is measured against WCAG AA (4.5:1)
|
|
176
|
+
by `src/contrast.test.ts`, at rest **and** on hover, in both themes.
|
|
177
|
+
|
|
178
|
+
Which foreground a family gets is decided per family, not by a rule:
|
|
179
|
+
|
|
180
|
+
- **White** on primary, error and neutral.
|
|
181
|
+
- **`gray-950`** on teal, success, orange, purple, info and amber — a mid-tone
|
|
182
|
+
fill cannot carry white. Solid teal with white text measured 2.49:1.
|
|
183
|
+
- Three of them flip: orange, purple and success take dark text in light mode
|
|
184
|
+
and white in dark, because Badge uses a darker fill in dark mode.
|
|
185
|
+
|
|
186
|
+
One consequence worth knowing if you retheme. A dark foreground assumes the fill
|
|
187
|
+
stays light. If you retint `--roster-teal-500` substantially darker, solid teal
|
|
188
|
+
becomes near-black on near-black — worse than the white it replaced. The
|
|
189
|
+
`Foundations/Solid fill contrast` story measures the rendered elements rather
|
|
190
|
+
than the tokens, so pointing it at your palette reports _your_ ratios.
|
|
191
|
+
|
|
192
|
+
Note also that a solid fill's contrast against the surface _behind_ it is a
|
|
193
|
+
separate requirement (WCAG 1.4.11, 3:1) and is not covered here. Solid amber on
|
|
194
|
+
a white page is 1.67:1, so it has effectively no visible edge.
|
|
195
|
+
|
|
196
|
+
### Focus
|
|
197
|
+
|
|
198
|
+
Every focusable control draws the same ring: `--roster-ring` for the ring
|
|
199
|
+
itself, `--roster-ring-offset` for the 2px band that separates it from the
|
|
200
|
+
control's own fill. Both flip with the theme — `primary-500` on white in light,
|
|
201
|
+
`primary-400` on `gray-950` in dark — which puts the indicator at 6.37:1 and
|
|
202
|
+
7.31:1 against the surface either side of it, where WCAG 1.4.11 asks for 3:1.
|
|
203
|
+
|
|
204
|
+
Retint it for your own accent:
|
|
205
|
+
|
|
206
|
+
```css
|
|
207
|
+
:root {
|
|
208
|
+
--roster-ring: #7c3aed;
|
|
209
|
+
}
|
|
210
|
+
.dark {
|
|
211
|
+
--roster-ring: #a78bfa;
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Set it in **both** scopes. Roster's own `.dark` rule has the same specificity
|
|
216
|
+
and comes later in the stylesheet, so a `:root`-only override is silently
|
|
217
|
+
discarded in dark mode.
|
|
218
|
+
|
|
219
|
+
The band matters more than it looks. Without it the ring sits directly on the
|
|
220
|
+
fill, and a `primary-500` ring on a `primary-600` button is 1.37:1 — which is
|
|
221
|
+
why the ring and its offset are a pair rather than two independent knobs.
|
|
222
|
+
|
|
223
|
+
### Motion
|
|
224
|
+
|
|
225
|
+
Two hand-rolled utilities, both of which stop for `prefers-reduced-motion`.
|
|
226
|
+
|
|
227
|
+
`animate-in` is the entrance, composed from modifiers the way
|
|
228
|
+
`tailwindcss-animate` does it — one keyframe reading four custom properties, and
|
|
229
|
+
each modifier setting one, so `fade-in-0 zoom-in-95 slide-in-from-top-2` combine
|
|
230
|
+
into a single animation rather than three fighting over `transform`. `Tooltip`
|
|
231
|
+
uses it, keyed off Radix's `data-side` so the panel always rises from the side it
|
|
232
|
+
is anchored on.
|
|
233
|
+
|
|
234
|
+
The suffixes are that plugin's, kept so anyone arriving from it keeps their
|
|
235
|
+
vocabulary. Each one is the value the modifier animates from: `-0` is an opacity,
|
|
236
|
+
`95` is a scale percentage, and `-2` is a step on Tailwind's spacing scale, so
|
|
237
|
+
`slide-in-from-top-2` starts `0.5rem` above its resting position. Only the steps
|
|
238
|
+
Roster's own components need are implemented; adding `-4` or `zoom-in-90` is one
|
|
239
|
+
line each.
|
|
240
|
+
|
|
241
|
+
`animate-in` on its own does nothing, by design: with no modifier the keyframe's
|
|
242
|
+
start values are the element's resting state. It is the engine, and a modifier is
|
|
243
|
+
what gives it somewhere to start. It fills `backwards`, so `animation-delay` can
|
|
244
|
+
stagger a group without every item flashing at rest first.
|
|
245
|
+
|
|
246
|
+
The default duration is 150ms, matching the plugin. At that speed a `-2` slide
|
|
247
|
+
covers 8px, which is right for a tooltip and reads as a twitch on anything
|
|
248
|
+
larger — `Foundations/Motion` in Storybook has controls for duration, easing,
|
|
249
|
+
direction and stagger to find what suits a bigger surface.
|
|
250
|
+
|
|
251
|
+
It is hand-rolled rather than a dependency: seven utilities does not justify a
|
|
252
|
+
package in a library that ships compiled CSS, and it keeps the stylesheet
|
|
253
|
+
self-contained — the same reasoning as not bundling a preflight.
|
|
254
|
+
|
|
255
|
+
`animate-shimmer` is a highlight travelling across a base, used by `Countdown`'s
|
|
256
|
+
`gradient` variant. Retint it with two variables:
|
|
257
|
+
|
|
258
|
+
```css
|
|
259
|
+
:root {
|
|
260
|
+
--roster-shimmer-base: #084063;
|
|
261
|
+
--roster-shimmer-highlight: #9bcce9;
|
|
262
|
+
}
|
|
263
|
+
.dark {
|
|
264
|
+
/* … */
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
The base is what carries the text whenever the highlight is elsewhere, so it has
|
|
269
|
+
to be readable on its own — it is also all you get under reduced motion, where
|
|
270
|
+
the sweep stops and the highlight parks off-frame. The highlight is deliberately
|
|
271
|
+
exempt from that bar: it is a specular pass on screen for a fraction of a second
|
|
272
|
+
per glyph, and holding it to 3:1 would flatten the effect.
|
|
273
|
+
|
|
274
|
+
### Scrollbars
|
|
275
|
+
|
|
276
|
+
`custom-scrollbar` gives any scrollable surface a slim themed scrollbar.
|
|
277
|
+
`Textarea` carries it already.
|
|
278
|
+
|
|
279
|
+
```css
|
|
280
|
+
:root {
|
|
281
|
+
--roster-scrollbar-thumb: #0f6498;
|
|
282
|
+
}
|
|
283
|
+
.dark {
|
|
284
|
+
--roster-scrollbar-thumb: #5ea3de;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Set it in both scopes — Roster's own `.dark` rule has equal specificity and comes
|
|
289
|
+
later, so a `:root`-only override is discarded in dark mode.
|
|
290
|
+
|
|
291
|
+
The default sits close to what the browser already draws, on purpose: a
|
|
292
|
+
component library should not repaint your scrollbars merely for being installed.
|
|
293
|
+
Color is the part that works everywhere. The 8px width and inset-pill thumb live
|
|
294
|
+
in a `::-webkit-scrollbar` block that only legacy engines reach. Every current
|
|
295
|
+
browser honors `scrollbar-width` / `scrollbar-color`, and drops the WebKit
|
|
296
|
+
pseudo-elements for any element that sets either of them, so on anything modern
|
|
297
|
+
`thin` is the whole shape control available.
|
|
298
|
+
|
|
146
299
|
### Components that render links
|
|
147
300
|
|
|
148
301
|
`Breadcrumbs` renders a plain `<a>` by default, which is right for a static
|
|
@@ -157,8 +310,8 @@ import NextLink from "next/link";
|
|
|
157
310
|
|
|
158
311
|
In an app with React Server Components, do that from a client component.
|
|
159
312
|
`linkComponent` is a function, and functions do not cross the RSC boundary —
|
|
160
|
-
passing it from a server component fails the render with
|
|
161
|
-
passed directly to Client
|
|
313
|
+
passing it from a server component fails the render with _Functions cannot be
|
|
314
|
+
passed directly to Client Components_. A small `"use client"` wrapper binds it
|
|
162
315
|
once, and the pages that use the wrapper stay server-rendered.
|
|
163
316
|
|
|
164
317
|
`Eyebrow` takes the other approach: `as` accepts any element and the props
|
|
@@ -192,58 +345,58 @@ function App() {
|
|
|
192
345
|
|
|
193
346
|
### Atoms
|
|
194
347
|
|
|
195
|
-
| Component
|
|
196
|
-
|
|
197
|
-
| `Avatar`
|
|
198
|
-
| `Badge`
|
|
199
|
-
| `Button`
|
|
200
|
-
| `Card`
|
|
201
|
-
| `Checkbox`
|
|
202
|
-
| `Disclosure`
|
|
203
|
-
| `Eyebrow`
|
|
204
|
-
| `InlineCode`
|
|
205
|
-
| `Input`
|
|
206
|
-
| `LabeledDivider`
|
|
207
|
-
| `Link`
|
|
208
|
-
| `PasswordInput`
|
|
209
|
-
| `Pill`
|
|
210
|
-
| `AvatarStrip`
|
|
211
|
-
| `CollapsibleSection` | Clamps any content (prose, chips, image grids) to a fixed height with a fade and expand/collapse toggle
|
|
212
|
-
| `LiquidTabs`
|
|
213
|
-
| `Select`
|
|
214
|
-
| `SegmentBar`
|
|
215
|
-
| `Stat`
|
|
216
|
-
| `Spinner`
|
|
217
|
-
| `Switch`
|
|
218
|
-
| `Textarea`
|
|
219
|
-
| `ThemeToggle`
|
|
220
|
-
| `Tooltip`
|
|
348
|
+
| Component | Description |
|
|
349
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
350
|
+
| `Avatar` | User avatar with image, initials fallback, and optional popover |
|
|
351
|
+
| `Badge` | Status label with semantic color schemes and fill variants |
|
|
352
|
+
| `Button` | Primary interactive element: solid, soft, outline, ghost, link variants |
|
|
353
|
+
| `Card` | Bordered surface container |
|
|
354
|
+
| `Checkbox` | Accessible checkbox with label support |
|
|
355
|
+
| `Disclosure` | Show/hide toggle using HeadlessUI |
|
|
356
|
+
| `Eyebrow` | Small tracked-out uppercase label above a heading or beside a rule; polymorphic via `as` |
|
|
357
|
+
| `InlineCode` | Inline `<code>` for identifiers in running prose |
|
|
358
|
+
| `Input` | Text input with label, error state, and icon slots |
|
|
359
|
+
| `LabeledDivider` | Horizontal rule carrying a label, with an optional trailing count |
|
|
360
|
+
| `Link` | Styled anchor with variant support |
|
|
361
|
+
| `PasswordInput` | Password field with a show/hide reveal toggle |
|
|
362
|
+
| `Pill` | Inline phrase chrome: social proof, live state, applied filters |
|
|
363
|
+
| `AvatarStrip` | Stacked avatar row with overflow chip, dismiss button, trailing slot, and label area |
|
|
364
|
+
| `CollapsibleSection` | Clamps any content (prose, chips, image grids) to a fixed height with a fade and expand/collapse toggle |
|
|
365
|
+
| `LiquidTabs` | Controlled tab strip with a liquid sliding pill indicator: pill and filled variants |
|
|
366
|
+
| `Select` | Dropdown selector |
|
|
367
|
+
| `SegmentBar` | Proportional horizontal bar divided into colored segments with optional legend |
|
|
368
|
+
| `Stat` | A single figure with its label and, optionally, where the figure came from |
|
|
369
|
+
| `Spinner` | Loading indicator |
|
|
370
|
+
| `Switch` | Toggle switch |
|
|
371
|
+
| `Textarea` | Multi-line text input |
|
|
372
|
+
| `ThemeToggle` | Flips class-based dark mode on the document root and remembers the choice; labels and icons are configurable |
|
|
373
|
+
| `Tooltip` | Radix-powered tooltip: hover/focus on desktop, tap-to-toggle on mobile |
|
|
221
374
|
|
|
222
375
|
### Molecules
|
|
223
376
|
|
|
224
|
-
| Component
|
|
225
|
-
|
|
226
|
-
| `Accordion`
|
|
227
|
-
| `Alert`
|
|
228
|
-
| `Breadcrumbs`
|
|
229
|
-
| `CallToAction`
|
|
230
|
-
| `DescriptionList` | Label and value pairs as a real `<dl>`: inline, stacked, or split
|
|
231
|
-
| `EmptyState`
|
|
232
|
-
| `ErrorState`
|
|
233
|
-
| `MatchupCard`
|
|
234
|
-
| `Pullquote`
|
|
377
|
+
| Component | Description |
|
|
378
|
+
| ----------------- | --------------------------------------------------------------------------- |
|
|
379
|
+
| `Accordion` | Collapsible content sections (single or multi-expand) |
|
|
380
|
+
| `Alert` | Inline notice strip with optional title and dismiss |
|
|
381
|
+
| `Breadcrumbs` | Navigation trail; pass `linkComponent` to keep navigation client-side |
|
|
382
|
+
| `CallToAction` | Prominent hero-style CTA block |
|
|
383
|
+
| `DescriptionList` | Label and value pairs as a real `<dl>`: inline, stacked, or split |
|
|
384
|
+
| `EmptyState` | Zero-data placeholder with icon and action slot |
|
|
385
|
+
| `ErrorState` | Error display with retry action |
|
|
386
|
+
| `MatchupCard` | Head-to-head comparison card |
|
|
387
|
+
| `Pullquote` | A line lifted out of prose, as `<figure>` + `<blockquote>` + `<figcaption>` |
|
|
235
388
|
|
|
236
389
|
### Organisms
|
|
237
390
|
|
|
238
|
-
| Component
|
|
239
|
-
|
|
240
|
-
| `ActionBar` | Sticky bottom action strip
|
|
241
|
-
| `Countdown` | Live countdown timer
|
|
391
|
+
| Component | Description |
|
|
392
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
393
|
+
| `ActionBar` | Sticky bottom action strip |
|
|
394
|
+
| `Countdown` | Live countdown timer |
|
|
242
395
|
| `DataTable` | Full-featured table with sorting and pagination via TanStack Table v9. Imported from `@blakesteve/roster/data-table` (see [DataTable columns](#datatable-columns)) |
|
|
243
|
-
| `Dialog`
|
|
244
|
-
| `Footer`
|
|
245
|
-
| `Navbar`
|
|
246
|
-
| `Table`
|
|
396
|
+
| `Dialog` | Modal dialog |
|
|
397
|
+
| `Footer` | Site footer |
|
|
398
|
+
| `Navbar` | Responsive navigation bar with mobile slide-out |
|
|
399
|
+
| `Table` | Static data table |
|
|
247
400
|
|
|
248
401
|
### DataTable columns
|
|
249
402
|
|
|
@@ -252,7 +405,10 @@ the table. `DataTable` registers sorting and pagination and exports that set as
|
|
|
252
405
|
`RosterTableFeatures`, so your columns name it:
|
|
253
406
|
|
|
254
407
|
```tsx
|
|
255
|
-
import {
|
|
408
|
+
import {
|
|
409
|
+
DataTable,
|
|
410
|
+
type RosterTableFeatures,
|
|
411
|
+
} from "@blakesteve/roster/data-table";
|
|
256
412
|
import { createColumnHelper, type ColumnDef } from "@tanstack/react-table";
|
|
257
413
|
|
|
258
414
|
type Player = { name: string; points: number };
|
|
@@ -287,9 +443,9 @@ Server Component it typechecks and then throws at render — use `/utils` there.
|
|
|
287
443
|
|
|
288
444
|
### Hooks
|
|
289
445
|
|
|
290
|
-
| Hook
|
|
291
|
-
|
|
292
|
-
| `useCountdown`
|
|
446
|
+
| Hook | Description |
|
|
447
|
+
| ---------------- | ------------------------------------------------------------------------------- |
|
|
448
|
+
| `useCountdown` | Countdown timer logic without the UI |
|
|
293
449
|
| `useKeySequence` | Fires a callback when a sequence of keys is typed in order. Ships `KONAMI_CODE` |
|
|
294
450
|
|
|
295
451
|
## Authoring components: the `rst:` prefix
|
|
@@ -299,9 +455,9 @@ Every class Roster emits carries an `rst:` prefix — `rst:flex`, `rst:bg-white`
|
|
|
299
455
|
not write the prefix and never see it.** It exists to stop a host app from
|
|
300
456
|
overriding Roster by accident.
|
|
301
457
|
|
|
302
|
-
Roster's stylesheet deliberately sits in a layer
|
|
458
|
+
Roster's stylesheet deliberately sits in a layer _below_ the host's `utilities`
|
|
303
459
|
so a consumer's `className` can override a component. Without a prefix that also
|
|
304
|
-
means the host wins any class-name
|
|
460
|
+
means the host wins any class-name _collision_ — including on Roster's own
|
|
305
461
|
internal elements, which the consumer never touches:
|
|
306
462
|
|
|
307
463
|
- an app that used `bg-white` anywhere defeated the Textarea's
|
|
@@ -320,7 +476,7 @@ node scripts/prefix-classes.mjs src/components/atoms/Thing/Thing.tsx # dry ru
|
|
|
320
476
|
APPLY=1 node scripts/prefix-classes.mjs src/components/atoms/Thing/Thing.tsx
|
|
321
477
|
```
|
|
322
478
|
|
|
323
|
-
Two things are deliberately never prefixed. `dark` is the
|
|
479
|
+
Two things are deliberately never prefixed. `dark` is the _consuming document's_
|
|
324
480
|
theme class, which Roster's own `@custom-variant dark` matches by name — Button
|
|
325
481
|
applies it directly for `surface="dark"`. And any class a consumer passes in,
|
|
326
482
|
such as `AvatarStrip`'s `ringClass`, stays exactly as they wrote it.
|
|
@@ -351,9 +507,10 @@ npx vitest run --project storybook
|
|
|
351
507
|
|
|
352
508
|
# Every emitted class carries the rst: prefix (runs as part of the build)
|
|
353
509
|
npm run check:prefix
|
|
510
|
+
npm run check:classes-emit
|
|
354
511
|
```
|
|
355
512
|
|
|
356
|
-
|
|
513
|
+
Three guards are worth knowing about, because the bugs they catch cannot be
|
|
357
514
|
reproduced from inside this repo.
|
|
358
515
|
|
|
359
516
|
`check:prefix` reads `dist/roster.css` and fails on any unprefixed class
|
|
@@ -361,10 +518,32 @@ selector. The collision it prevents only appears in an app with its own Tailwind
|
|
|
361
518
|
build, so asserting on a rendered component here would never see it — the check
|
|
362
519
|
has to be on the artifact.
|
|
363
520
|
|
|
521
|
+
`check:classes-emit` reads the same artifact and fails when a component
|
|
522
|
+
references a utility Tailwind never generated. Tailwind v4 builds utilities from
|
|
523
|
+
theme tokens, so a class naming a token that does not exist is not an error —
|
|
524
|
+
it simply produces no CSS, and the class sits in the component looking correct
|
|
525
|
+
while doing nothing. That is how the focus ring was inert: `Button` asked for
|
|
526
|
+
`ring-ring` and `ring-offset-background`, neither `--color-ring` nor
|
|
527
|
+
`--color-background` existed, and the ring fell back to `currentColor` — a
|
|
528
|
+
white ring on a white page. Nothing caught it, because typecheck cannot read a
|
|
529
|
+
class name and the unit tests assert a class is _present_ rather than that it
|
|
530
|
+
does anything.
|
|
531
|
+
|
|
532
|
+
It compares whole class names, variants included, so a misspelled variant fails
|
|
533
|
+
as readily as a misspelled utility. It reads component source only — `*.test.*`
|
|
534
|
+
and `*.stories.*` are skipped, because docs blurbs carry CSS code fences that
|
|
535
|
+
would false-positive, so a dead class in a story is not covered. Its
|
|
536
|
+
`KNOWN_DEAD` map is empty — the ten classes it was written to catch have all
|
|
537
|
+
been fixed. The map stays for the case
|
|
538
|
+
where a dead class cannot be fixed in the same sitting: add it there with a
|
|
539
|
+
reason and the build goes green on the state it inherited while still failing on
|
|
540
|
+
anything new. It also fails when a listed class starts emitting, so a fix cannot
|
|
541
|
+
leave a stale entry behind. Run it with `--verbose` to print the list.
|
|
542
|
+
|
|
364
543
|
`src/lib/utils.test.ts` pins `cn`. `tailwind-merge` has to be configured with the
|
|
365
544
|
prefix or it stops recognising Roster's classes as utilities and silently
|
|
366
545
|
degrades to concatenation: conflicting classes both survive and the winner falls
|
|
367
|
-
back to stylesheet order. The class string still
|
|
546
|
+
back to stylesheet order. The class string still _contains_ what you asked for,
|
|
368
547
|
so a snapshot passes while the browser is wrong.
|
|
369
548
|
|
|
370
549
|
## Building
|
|
@@ -375,15 +554,15 @@ npm run build
|
|
|
375
554
|
|
|
376
555
|
Output in `dist/`:
|
|
377
556
|
|
|
378
|
-
| File
|
|
379
|
-
|
|
380
|
-
| `roster.es.js`
|
|
381
|
-
| `roster.umd.js`
|
|
557
|
+
| File | Description |
|
|
558
|
+
| ------------------ | ------------------------------------------------------------------- |
|
|
559
|
+
| `roster.es.js` | ES module bundle |
|
|
560
|
+
| `roster.umd.js` | UMD bundle |
|
|
382
561
|
| `data-table.es.js` | DataTable entry, keeping the TanStack import out of the main bundle |
|
|
383
|
-
| `roster.css`
|
|
384
|
-
| `tokens.css`
|
|
385
|
-
| `preflight.css`
|
|
386
|
-
| `index.d.ts`
|
|
562
|
+
| `roster.css` | Compiled component styles, in the `roster` cascade layer |
|
|
563
|
+
| `tokens.css` | Design token CSS variables |
|
|
564
|
+
| `preflight.css` | Optional global reset (see Setup) |
|
|
565
|
+
| `index.d.ts` | TypeScript definitions |
|
|
387
566
|
|
|
388
567
|
## Contributing
|
|
389
568
|
|
|
@@ -395,4 +574,4 @@ Pull requests are welcome. Please:
|
|
|
395
574
|
|
|
396
575
|
## License
|
|
397
576
|
|
|
398
|
-
MIT © [Blake Ball](https://github.com/blakesteve)
|
|
577
|
+
MIT © [Blake Ball](https://github.com/blakesteve)
|