@charcuterie/ui 4.18.2 → 4.19.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/dist/DataTable/DataTable.d.ts +6 -1
- package/dist/DataTable/DataTable.d.ts.map +1 -1
- package/dist/DataTable/DataTable.js +104 -8
- package/dist/DataTable/DataTable.js.map +1 -1
- package/dist/MetricCard/MetricCard.d.ts +14 -0
- package/dist/MetricCard/MetricCard.d.ts.map +1 -0
- package/dist/MetricCard/MetricCard.js +10 -0
- package/dist/MetricCard/MetricCard.js.map +1 -0
- package/dist/SortableTableHeader/SortableTableHeader.js +1 -1
- package/dist/SortableTableHeader/SortableTableHeader.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/styles.css +46 -0
- package/package.json +1 -1
- package/src/DataTable/DataTable.mdx +11 -3
- package/src/DataTable/DataTable.stories.tsx +80 -0
- package/src/DataTable/DataTable.test.tsx +125 -2
- package/src/DataTable/DataTable.tsx +194 -17
- package/src/MetricCard/MetricCard.mdx +26 -0
- package/src/MetricCard/MetricCard.stories.tsx +104 -0
- package/src/MetricCard/MetricCard.test.tsx +64 -0
- package/src/MetricCard/MetricCard.tsx +51 -0
- package/src/SortableTableHeader/SortableTableHeader.tsx +1 -1
- package/src/index.ts +3 -0
- package/src/markdownEditorCodeMirror/MarkdownView.test.tsx +8 -4
- package/src/sourceRules.test.ts +2 -1
- package/src/styles.css +46 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { CategoricalIndex } from "@charcuterie/tokens"
|
|
2
|
+
import type { ReactNode } from "react"
|
|
3
|
+
import { Card, type CardProps } from "../Card/Card.tsx"
|
|
4
|
+
import { CATEGORICAL_CONTENT_CLASS } from "../categoricalStyles.ts"
|
|
5
|
+
import { toClassName } from "../toClassName.ts"
|
|
6
|
+
|
|
7
|
+
export type MetricCardProps = Omit<CardProps, "actions"> & {
|
|
8
|
+
/** A stable category colour, independent of success/failure intent. */
|
|
9
|
+
categorical?: CategoricalIndex
|
|
10
|
+
/** App-supplied decoration; the visible heading names the metric. */
|
|
11
|
+
icon?: ReactNode
|
|
12
|
+
/** Already formatted by the app, including the unit when needed. */
|
|
13
|
+
value: ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** One prominent measure, a coloured icon and edge, and app-owned supporting content. */
|
|
17
|
+
export const MetricCard = ({
|
|
18
|
+
categorical,
|
|
19
|
+
children,
|
|
20
|
+
icon,
|
|
21
|
+
value,
|
|
22
|
+
...cardProps
|
|
23
|
+
}: MetricCardProps): ReactNode => (
|
|
24
|
+
<Card
|
|
25
|
+
{...cardProps}
|
|
26
|
+
accentEdge={
|
|
27
|
+
cardProps.accentEdge ??
|
|
28
|
+
(categorical ? { categorical } : undefined)
|
|
29
|
+
}
|
|
30
|
+
actions={
|
|
31
|
+
icon ? (
|
|
32
|
+
<span
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
className={toClassName(
|
|
35
|
+
"inline-flex size-7 items-center justify-center",
|
|
36
|
+
categorical
|
|
37
|
+
? CATEGORICAL_CONTENT_CLASS[categorical]
|
|
38
|
+
: undefined,
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
{icon}
|
|
42
|
+
</span>
|
|
43
|
+
) : undefined
|
|
44
|
+
}
|
|
45
|
+
>
|
|
46
|
+
<p className="min-w-0 wrap-anywhere font-semibold text-2xl tabular-nums">
|
|
47
|
+
{value}
|
|
48
|
+
</p>
|
|
49
|
+
{children}
|
|
50
|
+
</Card>
|
|
51
|
+
)
|
|
@@ -95,7 +95,7 @@ export const SortableTableHeader = ({
|
|
|
95
95
|
// uppercased and letterspaced, which strips the word shapes
|
|
96
96
|
// readers use at small sizes. A column header is the label
|
|
97
97
|
// for everything under it, so it is content.
|
|
98
|
-
"flex w-full cursor-pointer items-center gap-1.5 bg-transparent px-3 py-2 text-start font-medium text-content-secondary text-sm uppercase tracking-wide transition-colors duration-(--duration-fast) ease-standard",
|
|
98
|
+
"flex w-full cursor-pointer items-center gap-1.5 bg-transparent px-3 py-2 text-start wrap-normal font-medium text-content-secondary text-sm uppercase tracking-wide transition-colors duration-(--duration-fast) ease-standard",
|
|
99
99
|
"hover:text-content-primary",
|
|
100
100
|
FOCUS_RING_CLASS,
|
|
101
101
|
)}
|
package/src/index.ts
CHANGED
|
@@ -158,6 +158,7 @@ export {
|
|
|
158
158
|
export type {
|
|
159
159
|
DataTableColumn,
|
|
160
160
|
DataTableProps,
|
|
161
|
+
DataTableReflowAt,
|
|
161
162
|
DataTableSelection,
|
|
162
163
|
DataTableSort,
|
|
163
164
|
} from "./DataTable/DataTable.tsx"
|
|
@@ -316,6 +317,8 @@ export type {
|
|
|
316
317
|
MenuProps,
|
|
317
318
|
} from "./Menu/Menu.tsx"
|
|
318
319
|
export { Menu } from "./Menu/Menu.tsx"
|
|
320
|
+
export type { MetricCardProps } from "./MetricCard/MetricCard.tsx"
|
|
321
|
+
export { MetricCard } from "./MetricCard/MetricCard.tsx"
|
|
319
322
|
export type { ModalProps } from "./Modal/Modal.tsx"
|
|
320
323
|
export { Modal } from "./Modal/Modal.tsx"
|
|
321
324
|
export type {
|
|
@@ -367,10 +367,14 @@ test.each([
|
|
|
367
367
|
async (_case, name) => {
|
|
368
368
|
const { canvas } = await mountStory(NestedLinkText)
|
|
369
369
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
370
|
+
// CodeMirror finishes its viewport decorations on a scheduled frame.
|
|
371
|
+
// Wait for the accessible anchor rather than assuming mount means paint.
|
|
372
|
+
const link = await waitFor(() =>
|
|
373
|
+
expectAgentDrivable(canvas, {
|
|
374
|
+
name,
|
|
375
|
+
role: "link",
|
|
376
|
+
}),
|
|
377
|
+
)
|
|
374
378
|
|
|
375
379
|
await expect(link.tagName).toBe("A")
|
|
376
380
|
},
|
package/src/sourceRules.test.ts
CHANGED
|
@@ -621,7 +621,8 @@ test("the barrel is the only place components are re-exported", async () => {
|
|
|
621
621
|
// ValuePairs owns compact label-over-value summaries.
|
|
622
622
|
// Chart shares portable SVG geometry with Preact and image consumers.
|
|
623
623
|
// TableViewport owns readable comparisons and full-window expansion.
|
|
624
|
-
|
|
624
|
+
// MetricCard shares prominent values and category-coloured icons through Card.
|
|
625
|
+
expect(componentNames.length).toBe(75)
|
|
625
626
|
|
|
626
627
|
for (const name of componentNames) {
|
|
627
628
|
expect(barrel).toContain(`export { ${name} }`)
|
package/src/styles.css
CHANGED
|
@@ -260,3 +260,49 @@
|
|
|
260
260
|
th:first-child {
|
|
261
261
|
z-index: 3;
|
|
262
262
|
}
|
|
263
|
+
|
|
264
|
+
/* Column width utilities describe comparison columns, never labelled list cells.
|
|
265
|
+
These rules are unlayered, like the component's existing structural styles,
|
|
266
|
+
so a consumer's cq-lg:w-32 cannot crush a list reflowing at cq-xl. */
|
|
267
|
+
.charcuterie-data-table[data-layout="stacked"]
|
|
268
|
+
> table
|
|
269
|
+
> :is(thead, tbody)
|
|
270
|
+
> tr
|
|
271
|
+
> :is(th, td) {
|
|
272
|
+
inline-size: auto;
|
|
273
|
+
min-inline-size: 0;
|
|
274
|
+
max-inline-size: none;
|
|
275
|
+
}
|
|
276
|
+
@container (width < 32rem) {
|
|
277
|
+
.charcuterie-data-table[data-reflow-at="md"]
|
|
278
|
+
> table
|
|
279
|
+
> :is(thead, tbody)
|
|
280
|
+
> tr
|
|
281
|
+
> :is(th, td) {
|
|
282
|
+
inline-size: auto;
|
|
283
|
+
min-inline-size: 0;
|
|
284
|
+
max-inline-size: none;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
@container (width < 48rem) {
|
|
288
|
+
.charcuterie-data-table[data-reflow-at="lg"]
|
|
289
|
+
> table
|
|
290
|
+
> :is(thead, tbody)
|
|
291
|
+
> tr
|
|
292
|
+
> :is(th, td) {
|
|
293
|
+
inline-size: auto;
|
|
294
|
+
min-inline-size: 0;
|
|
295
|
+
max-inline-size: none;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
@container (width < 64rem) {
|
|
299
|
+
.charcuterie-data-table[data-reflow-at="xl"]
|
|
300
|
+
> table
|
|
301
|
+
> :is(thead, tbody)
|
|
302
|
+
> tr
|
|
303
|
+
> :is(th, td) {
|
|
304
|
+
inline-size: auto;
|
|
305
|
+
min-inline-size: 0;
|
|
306
|
+
max-inline-size: none;
|
|
307
|
+
}
|
|
308
|
+
}
|