@startsimpli/ui 0.4.92 → 0.4.94

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 (25) hide show
  1. package/package.json +3 -3
  2. package/src/components/dashboard/DashboardSection.tsx +36 -5
  3. package/src/components/dashboard/MetricCard.tsx +4 -1
  4. package/src/components/dashboard/StatTile.tsx +20 -1
  5. package/src/components/states/Absence.tsx +156 -0
  6. package/src/components/states/Caveat.tsx +167 -0
  7. package/src/components/states/EmptyState.tsx +39 -10
  8. package/src/components/states/Footnote.tsx +171 -0
  9. package/src/components/states/__tests__/caveat-and-absence.test.tsx +662 -0
  10. package/src/components/states/index.ts +7 -1
  11. package/src/components/ui/card.tsx +37 -6
  12. package/src/components/unified-table/__tests__/components/TablePagination.test.tsx +62 -5
  13. package/src/components/unified-table/__tests__/hooks/usePagination.test.ts +22 -0
  14. package/src/components/unified-table/__tests__/utils/border-tokens.test.ts +61 -0
  15. package/src/components/unified-table/components/BulkActionBar/index.tsx +1 -1
  16. package/src/components/unified-table/components/DataTableCore/index.tsx +1 -1
  17. package/src/components/unified-table/components/MobileView/Card.tsx +1 -1
  18. package/src/components/unified-table/components/TableFilters/index.tsx +2 -2
  19. package/src/components/unified-table/components/TablePagination/index.tsx +19 -5
  20. package/src/components/unified-table/hooks/usePagination.ts +12 -0
  21. package/src/components/unified-table/utils/themes.ts +8 -5
  22. package/src/theme/__tests__/type-scale.test.tsx +145 -0
  23. package/src/theme/contract.ts +5 -0
  24. package/src/theme/index.ts +10 -0
  25. package/src/theme/type-scale.ts +119 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The type scale — packages/ui's contract for how big text is.
3
+ *
4
+ * Before this existed, every consumer picked font sizes by hand and the ladder
5
+ * collapsed: across one app 77% of all text was `text-sm` or `text-xs`, two
6
+ * ADJACENT steps, so a card title and its body differed by 1.5px and were told
7
+ * apart only by weight. The same "big number" was rendered at seven different
8
+ * sizes on seven screens because there was no rule to point at.
9
+ *
10
+ * There are seven roles, named for the job the text does, not for its size.
11
+ * Pick the role; the scale picks the pixels. The ladder is a deliberate 4:1
12
+ * from `display` down to `caption`, so any two adjacent roles are visibly
13
+ * different — that is the whole point.
14
+ *
15
+ * display 48px / 800 the one hero figure on a screen
16
+ * stat 32px / 800 a metric's value in a tile
17
+ * heading 20px / 700 a section header
18
+ * cardTitle 18px / 600 the name of a card
19
+ * body 16px / 400 prose and table cells
20
+ * muted 14px / 400 supporting copy under a title
21
+ * caption 12px / 400 labels, kickers, timestamps
22
+ *
23
+ * Mirrors packages/ui-native/src/tokens.ts + styles.ts, so a screen reads the
24
+ * same on web and iOS.
25
+ *
26
+ * SIZE and LINE-HEIGHT come from CSS variables (packages/ui/theme/contract.css),
27
+ * so an app reshapes the whole estate by overriding seven numbers — the same way
28
+ * `--radius` reshapes every corner. Each utility carries the default inline as a
29
+ * `var()` fallback, so a component still renders correctly in an app that has
30
+ * not adopted the contract file.
31
+ *
32
+ * WEIGHT and TRACKING are fixed per role, deliberately. They are what makes a
33
+ * role recognisable; an app that wants a lighter heading wants a different
34
+ * design, not a different token.
35
+ *
36
+ * Usage:
37
+ * import { TYPE_SCALE } from '@startsimpli/ui/theme'
38
+ * <h2 className={cn(TYPE_SCALE.heading, 'text-foreground')}>{title}</h2>
39
+ *
40
+ * The scale sets size/weight/leading only. COLOUR stays separate and must come
41
+ * from a theme token (`text-foreground`, `text-muted-foreground`) — never a
42
+ * `gray-*` literal, or the component is light-locked and unreadable on a dark
43
+ * tenant.
44
+ */
45
+
46
+ export type TypeScaleRole =
47
+ | 'display'
48
+ | 'stat'
49
+ | 'heading'
50
+ | 'cardTitle'
51
+ | 'body'
52
+ | 'muted'
53
+ | 'caption'
54
+
55
+ /** Tailwind utilities for each role. Compose with a colour token. */
56
+ export const TYPE_SCALE: Record<TypeScaleRole, string> = {
57
+ display:
58
+ 'text-[length:var(--text-display-size,3rem)] leading-[var(--text-display-leading,1.05)] font-extrabold tracking-tight',
59
+ stat: 'text-[length:var(--text-stat-size,2rem)] leading-[var(--text-stat-leading,1.1)] font-extrabold tracking-tight tabular-nums',
60
+ heading:
61
+ 'text-[length:var(--text-heading-size,1.25rem)] leading-[var(--text-heading-leading,1.3)] font-bold tracking-tight',
62
+ cardTitle:
63
+ 'text-[length:var(--text-card-title-size,1.125rem)] leading-[var(--text-card-title-leading,1.4)] font-semibold',
64
+ body: 'text-[length:var(--text-body-size,1rem)] leading-[var(--text-body-leading,1.5)] font-normal',
65
+ muted:
66
+ 'text-[length:var(--text-muted-size,0.875rem)] leading-[var(--text-muted-leading,1.5)] font-normal',
67
+ caption:
68
+ 'text-[length:var(--text-caption-size,0.75rem)] leading-[var(--text-caption-leading,1.4)] font-normal',
69
+ }
70
+
71
+ /**
72
+ * The roles in visual order, largest first. Useful for rendering the ladder in
73
+ * a harness and for tests that assert the steps stay distinct.
74
+ */
75
+ export const TYPE_SCALE_ORDER: readonly TypeScaleRole[] = [
76
+ 'display',
77
+ 'stat',
78
+ 'heading',
79
+ 'cardTitle',
80
+ 'body',
81
+ 'muted',
82
+ 'caption',
83
+ ] as const
84
+
85
+ /** Default size of each role, in rem — the fallback baked into the utilities. */
86
+ export const TYPE_SCALE_DEFAULTS: Record<TypeScaleRole, number> = {
87
+ display: 3,
88
+ stat: 2,
89
+ heading: 1.25,
90
+ cardTitle: 1.125,
91
+ body: 1,
92
+ muted: 0.875,
93
+ caption: 0.75,
94
+ }
95
+
96
+ /** CSS custom properties an app may override to reshape the scale. */
97
+ export const TYPE_SCALE_TOKENS = [
98
+ '--text-display-size',
99
+ '--text-display-leading',
100
+ '--text-stat-size',
101
+ '--text-stat-leading',
102
+ '--text-heading-size',
103
+ '--text-heading-leading',
104
+ '--text-card-title-size',
105
+ '--text-card-title-leading',
106
+ '--text-body-size',
107
+ '--text-body-leading',
108
+ '--text-muted-size',
109
+ '--text-muted-leading',
110
+ '--text-caption-size',
111
+ '--text-caption-leading',
112
+ ] as const
113
+
114
+ export type TypeScaleToken = (typeof TYPE_SCALE_TOKENS)[number]
115
+
116
+ /** `typeClass('heading')` — the utilities for a role, for dynamic call sites. */
117
+ export function typeClass(role: TypeScaleRole): string {
118
+ return TYPE_SCALE[role]
119
+ }