@charcuterie/ui 4.0.0 → 4.1.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.
Files changed (45) hide show
  1. package/dist/ActionTiles/ActionTiles.d.ts +66 -8
  2. package/dist/ActionTiles/ActionTiles.d.ts.map +1 -1
  3. package/dist/ActionTiles/ActionTiles.js +88 -11
  4. package/dist/ActionTiles/ActionTiles.js.map +1 -1
  5. package/dist/PortraitTiles/PortraitAvatar.d.ts +21 -0
  6. package/dist/PortraitTiles/PortraitAvatar.d.ts.map +1 -0
  7. package/dist/PortraitTiles/PortraitAvatar.js +29 -0
  8. package/dist/PortraitTiles/PortraitAvatar.js.map +1 -0
  9. package/dist/PortraitTiles/PortraitTiles.d.ts +162 -0
  10. package/dist/PortraitTiles/PortraitTiles.d.ts.map +1 -0
  11. package/dist/PortraitTiles/PortraitTiles.js +263 -0
  12. package/dist/PortraitTiles/PortraitTiles.js.map +1 -0
  13. package/dist/PortraitTiles/portraitColour.d.ts +49 -0
  14. package/dist/PortraitTiles/portraitColour.d.ts.map +1 -0
  15. package/dist/PortraitTiles/portraitColour.js +55 -0
  16. package/dist/PortraitTiles/portraitColour.js.map +1 -0
  17. package/dist/categoricalStyles.d.ts +27 -0
  18. package/dist/categoricalStyles.d.ts.map +1 -1
  19. package/dist/categoricalStyles.js +49 -0
  20. package/dist/categoricalStyles.js.map +1 -1
  21. package/dist/index.d.ts +4 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/tileStyles.d.ts +15 -0
  26. package/dist/tileStyles.d.ts.map +1 -1
  27. package/dist/tileStyles.js +26 -1
  28. package/dist/tileStyles.js.map +1 -1
  29. package/package.json +2 -2
  30. package/src/ActionTiles/ActionTiles.mdx +64 -6
  31. package/src/ActionTiles/ActionTiles.stories.tsx +107 -2
  32. package/src/ActionTiles/ActionTiles.test.tsx +205 -5
  33. package/src/ActionTiles/ActionTiles.tsx +274 -110
  34. package/src/PortraitTiles/PortraitAvatar.tsx +49 -0
  35. package/src/PortraitTiles/PortraitTiles.mdx +153 -0
  36. package/src/PortraitTiles/PortraitTiles.stories.tsx +403 -0
  37. package/src/PortraitTiles/PortraitTiles.test.tsx +399 -0
  38. package/src/PortraitTiles/PortraitTiles.tsx +577 -0
  39. package/src/PortraitTiles/portraitColour.test.ts +39 -0
  40. package/src/PortraitTiles/portraitColour.ts +67 -0
  41. package/src/RadioGroup/RadioGroup.stories.tsx +39 -0
  42. package/src/categoricalStyles.ts +57 -0
  43. package/src/index.ts +9 -0
  44. package/src/sourceRules.test.ts +15 -1
  45. package/src/tileStyles.ts +30 -1
@@ -139,6 +139,45 @@ export const Tiles: Story = {
139
139
  },
140
140
  }
141
141
 
142
+ /**
143
+ * The tile at all three sizes.
144
+ *
145
+ * `AllVariants` above covers the three heights of a **row**, and
146
+ * every tile story took the default `md` — so the largest tile had
147
+ * no snapshot at all, and `TILE_PADDING_CLASS.lg` could be changed
148
+ * without a single pixel moving in the report. It was, on
149
+ * 2026-09-02, when `lg` grew to a landing-page tile's padding.
150
+ *
151
+ * The padding is shared with `ActionTiles` through `tileStyles.ts`,
152
+ * which is the promise this board is here to photograph.
153
+ */
154
+ export const TileSizes: Story = {
155
+ args: {
156
+ items: IMPORT_ITEMS,
157
+ itemShape: "tile",
158
+ label: "On import",
159
+ },
160
+ render: (controlProps) => (
161
+ <StorySection title="One box at three sizes, and the same box ActionTiles reads from.">
162
+ <StoryGrid columns={3}>
163
+ {(["sm", "md", "lg"] as const).map((size) => (
164
+ <StoryCell
165
+ align="stretch"
166
+ key={size}
167
+ label={size}
168
+ >
169
+ <RadioGroup
170
+ {...controlProps}
171
+ label={`On import at ${size}`}
172
+ size={size}
173
+ />
174
+ </StoryCell>
175
+ ))}
176
+ </StoryGrid>
177
+ </StorySection>
178
+ ),
179
+ }
180
+
142
181
  /**
143
182
  * A tile may lead with an icon. The library ships none — these are
144
183
  * story-only SVGs, exactly what an app passes — and the icon is
@@ -242,3 +242,60 @@ export const CATEGORICAL_CONTENT_CLASS: Record<
242
242
  9: "text-categorical-9-content",
243
243
  10: "text-categorical-10-content",
244
244
  }
245
+
246
+ /**
247
+ * The hover BORDER, which `CATEGORICAL_HOVER_CLASS` deliberately
248
+ * does not carry.
249
+ *
250
+ * That map answers "what does this surface do under the pointer",
251
+ * and a `Badge` has no border state to change. A tile does: it is a
252
+ * bordered card, and the whole point of colouring one is that the
253
+ * box reacts in its own hue rather than in the neutral
254
+ * `border-strong` every other box uses. Kept separate rather than
255
+ * added as a fifth appearance key, because an appearance is a claim
256
+ * about the fill and this is not one.
257
+ *
258
+ * Written out in full for the reason this file opens with.
259
+ */
260
+ export const CATEGORICAL_HOVER_BORDER_CLASS: Record<
261
+ CategoricalIndex,
262
+ string
263
+ > = {
264
+ 1: "hover:border-categorical-1-border",
265
+ 2: "hover:border-categorical-2-border",
266
+ 3: "hover:border-categorical-3-border",
267
+ 4: "hover:border-categorical-4-border",
268
+ 5: "hover:border-categorical-5-border",
269
+ 6: "hover:border-categorical-6-border",
270
+ 7: "hover:border-categorical-7-border",
271
+ 8: "hover:border-categorical-8-border",
272
+ 9: "hover:border-categorical-9-border",
273
+ 10: "hover:border-categorical-10-border",
274
+ }
275
+
276
+ /**
277
+ * A halo the width of a ring, in the hue's SURFACE.
278
+ *
279
+ * `surface` and not `border`: this sits directly against the solid
280
+ * fill it surrounds, so it is a soft step out of the colour rather
281
+ * than a second line around it. `PortraitTiles` draws it around a
282
+ * face, where a hard outline reads as a frame and this reads as
283
+ * light.
284
+ *
285
+ * Written out in full for the reason this file opens with.
286
+ */
287
+ export const CATEGORICAL_RING_CLASS: Record<
288
+ CategoricalIndex,
289
+ string
290
+ > = {
291
+ 1: "ring-categorical-1-surface",
292
+ 2: "ring-categorical-2-surface",
293
+ 3: "ring-categorical-3-surface",
294
+ 4: "ring-categorical-4-surface",
295
+ 5: "ring-categorical-5-surface",
296
+ 6: "ring-categorical-6-surface",
297
+ 7: "ring-categorical-7-surface",
298
+ 8: "ring-categorical-8-surface",
299
+ 9: "ring-categorical-9-surface",
300
+ 10: "ring-categorical-10-surface",
301
+ }
package/src/index.ts CHANGED
@@ -39,6 +39,7 @@ export type {
39
39
  export { Accordion } from "./Accordion/Accordion.tsx"
40
40
  export type {
41
41
  ActionTileItem,
42
+ ActionTilesAccent,
42
43
  ActionTilesProps,
43
44
  } from "./ActionTiles/ActionTiles.tsx"
44
45
  export { ActionTiles } from "./ActionTiles/ActionTiles.tsx"
@@ -129,7 +130,9 @@ export { copyText } from "./CopyButton/copyText.ts"
129
130
  export {
130
131
  CATEGORICAL_APPEARANCE_CLASS,
131
132
  CATEGORICAL_CONTENT_CLASS,
133
+ CATEGORICAL_HOVER_BORDER_CLASS,
132
134
  CATEGORICAL_HOVER_CLASS,
135
+ CATEGORICAL_RING_CLASS,
133
136
  CATEGORICAL_SOLID_FILL_CLASS,
134
137
  } from "./categoricalStyles.ts"
135
138
  export type { BadgeSize } from "./controlStyles.ts"
@@ -325,6 +328,12 @@ export type {
325
328
  export { Picker } from "./Picker/Picker.tsx"
326
329
  export type { PopoverProps } from "./Popover/Popover.tsx"
327
330
  export { Popover } from "./Popover/Popover.tsx"
331
+ export type {
332
+ PortraitTileItem,
333
+ PortraitTilesLayout,
334
+ PortraitTilesProps,
335
+ } from "./PortraitTiles/PortraitTiles.tsx"
336
+ export { PortraitTiles } from "./PortraitTiles/PortraitTiles.tsx"
328
337
  export type {
329
338
  ProgressBarProps,
330
339
  ProgressBarSize,
@@ -236,6 +236,14 @@ test("a container-query component is never storied in a shrink-to-fit cell", ()
236
236
  "Main",
237
237
  "MarkdownEditor",
238
238
  "MediaTile",
239
+ // `PortraitTiles` declares its container on the SET rather than
240
+ // on a tile, and that is the whole design: the question is not
241
+ // "how wide is this one face" but "does this picker have room to
242
+ // stack". A phone shows one full-width column of rows; a wall
243
+ // display shows a row of tall columns. Querying a tile would
244
+ // answer neither, because a track is about the same width in
245
+ // both.
246
+ "PortraitTiles",
239
247
  // `Stepper`'s container is the one that decides whether a
240
248
  // `horizontal` sequence is actually horizontal. Below `--cq-md`
241
249
  // it falls back to the vertical column, because four steps side
@@ -571,7 +579,13 @@ test("the barrel is the only place components are re-exported", async () => {
571
579
  // `isRange` is right there and wrong here for a reason that is
572
580
  // written down — a second text field is still a text field, while a
573
581
  // second thumb cannot share one `aria-valuenow`.
574
- expect(componentNames.length).toBe(64)
582
+ //
583
+ // `PortraitTiles` is +1 -> 65. It is the points-market kid picker:
584
+ // a face, a name and one number, which is a different question
585
+ // from `ActionTiles`' "what do you want to do" and would have
586
+ // meant one component whose icon is sometimes a 20px glyph beside
587
+ // a title and sometimes a 144px circle above it.
588
+ expect(componentNames.length).toBe(65)
575
589
 
576
590
  for (const name of componentNames) {
577
591
  expect(barrel).toContain(`export { ${name} }`)
package/src/tileStyles.ts CHANGED
@@ -38,7 +38,36 @@ export const TILE_PADDING_CLASS: Record<
38
38
  > = {
39
39
  sm: "px-3 py-2.5",
40
40
  md: "px-3.5 py-3",
41
- lg: "px-4 py-3.5",
41
+ // `lg` is the landing-page tile — mux-magic's "Pick a tool",
42
+ // Gallery Downloader's two cards — where the tile is the only
43
+ // thing on the page and reads as a panel rather than as a row.
44
+ // It was `px-4 py-3.5`, which is a control's padding wearing a
45
+ // card's name, and the owner called the result "very boring"
46
+ // when it shipped in QueuePilot.
47
+ lg: "px-6 py-5",
48
+ }
49
+
50
+ /**
51
+ * What a tile with an accent edge adds to its LEADING padding.
52
+ *
53
+ * The bar is drawn by `Card`'s accent-edge pseudo-element, which is
54
+ * an overlay rather than a border — so it takes no space in the box
55
+ * model and lands on top of the text unless the tile makes room for
56
+ * it. `Card` has the same arrangement and the same answer.
57
+ *
58
+ * A separate map rather than a second full padding scale, because
59
+ * only the leading side changes and the shared box is the promise
60
+ * the 2026-09-01 record made. It is applied ONLY when an edge is
61
+ * drawn: a radio tile has no bar, and giving it this padding would
62
+ * be dead space on the side its own control sits on.
63
+ */
64
+ export const TILE_ACCENT_EDGE_PADDING_CLASS: Record<
65
+ ControlSize,
66
+ string
67
+ > = {
68
+ sm: "ps-4",
69
+ md: "ps-4.5",
70
+ lg: "ps-7",
42
71
  }
43
72
 
44
73
  /**