@blurrow/ui 0.2.0 → 0.2.1

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 (271) hide show
  1. package/README.md +48 -36
  2. package/dist/Accordion.d.ts +17 -0
  3. package/dist/Accordion.js +138 -0
  4. package/dist/Accordion.js.map +1 -0
  5. package/dist/Alert.d.ts +13 -0
  6. package/dist/Alert.js +69 -0
  7. package/dist/Alert.js.map +1 -0
  8. package/dist/AuthorCard.d.ts +12 -0
  9. package/dist/AuthorCard.js +57 -0
  10. package/dist/AuthorCard.js.map +1 -0
  11. package/dist/Avatar.d.ts +21 -0
  12. package/dist/Avatar.js +96 -0
  13. package/dist/Avatar.js.map +1 -0
  14. package/dist/Badge.d.ts +12 -0
  15. package/dist/Badge.js +46 -0
  16. package/dist/Badge.js.map +1 -0
  17. package/dist/Banner.d.ts +15 -0
  18. package/dist/Banner.js +68 -0
  19. package/dist/Banner.js.map +1 -0
  20. package/dist/Breadcrumb.d.ts +13 -0
  21. package/dist/Breadcrumb.js +45 -0
  22. package/dist/Breadcrumb.js.map +1 -0
  23. package/dist/Button.d.ts +19 -0
  24. package/dist/Button.js +282 -0
  25. package/dist/Button.js.map +1 -0
  26. package/dist/ButtonGroup.d.ts +19 -0
  27. package/dist/ButtonGroup.js +62 -0
  28. package/dist/ButtonGroup.js.map +1 -0
  29. package/dist/Card.d.ts +40 -0
  30. package/dist/Card.js +175 -0
  31. package/dist/Card.js.map +1 -0
  32. package/dist/CardShell.d.ts +18 -0
  33. package/dist/CardShell.js +58 -0
  34. package/dist/CardShell.js.map +1 -0
  35. package/dist/Carousel.d.ts +22 -0
  36. package/dist/Carousel.js +247 -0
  37. package/dist/Carousel.js.map +1 -0
  38. package/dist/Checkbox.d.ts +15 -0
  39. package/dist/Checkbox.js +84 -0
  40. package/dist/Checkbox.js.map +1 -0
  41. package/dist/CloseButton.d.ts +12 -0
  42. package/dist/CloseButton.js +63 -0
  43. package/dist/CloseButton.js.map +1 -0
  44. package/dist/CodeBlock.d.ts +12 -0
  45. package/dist/CodeBlock.js +221 -0
  46. package/dist/CodeBlock.js.map +1 -0
  47. package/dist/ColorPicker.d.ts +24 -0
  48. package/dist/ColorPicker.js +366 -0
  49. package/dist/ColorPicker.js.map +1 -0
  50. package/dist/Combobox.d.ts +34 -0
  51. package/dist/Combobox.js +255 -0
  52. package/dist/Combobox.js.map +1 -0
  53. package/dist/CommandPalette.d.ts +25 -0
  54. package/dist/CommandPalette.js +304 -0
  55. package/dist/CommandPalette.js.map +1 -0
  56. package/dist/ContextMenu.d.ts +16 -0
  57. package/dist/ContextMenu.js +209 -0
  58. package/dist/ContextMenu.js.map +1 -0
  59. package/dist/DataList.d.ts +15 -0
  60. package/dist/DataList.js +42 -0
  61. package/dist/DataList.js.map +1 -0
  62. package/dist/DatePicker.d.ts +65 -0
  63. package/dist/DatePicker.js +391 -0
  64. package/dist/DatePicker.js.map +1 -0
  65. package/dist/DateRangePicker.d.ts +34 -0
  66. package/dist/DateRangePicker.js +180 -0
  67. package/dist/DateRangePicker.js.map +1 -0
  68. package/dist/Drawer.d.ts +17 -0
  69. package/dist/Drawer.js +132 -0
  70. package/dist/Drawer.js.map +1 -0
  71. package/dist/DropdownMenu.d.ts +23 -0
  72. package/dist/DropdownMenu.js +185 -0
  73. package/dist/DropdownMenu.js.map +1 -0
  74. package/dist/EmptyState.d.ts +13 -0
  75. package/dist/EmptyState.js +55 -0
  76. package/dist/EmptyState.js.map +1 -0
  77. package/dist/FieldMessage.d.ts +26 -0
  78. package/dist/FieldMessage.js +95 -0
  79. package/dist/FieldMessage.js.map +1 -0
  80. package/dist/FileUpload.d.ts +32 -0
  81. package/dist/FileUpload.js +253 -0
  82. package/dist/FileUpload.js.map +1 -0
  83. package/dist/Floating.d.ts +32 -0
  84. package/dist/Floating.js +95 -0
  85. package/dist/Floating.js.map +1 -0
  86. package/dist/HoverCard.d.ts +18 -0
  87. package/dist/HoverCard.js +90 -0
  88. package/dist/HoverCard.js.map +1 -0
  89. package/dist/Input.d.ts +17 -0
  90. package/dist/Input.js +96 -0
  91. package/dist/Input.js.map +1 -0
  92. package/dist/Kbd.d.ts +9 -0
  93. package/dist/Kbd.js +24 -0
  94. package/dist/Kbd.js.map +1 -0
  95. package/dist/Modal.d.ts +15 -0
  96. package/dist/Modal.js +109 -0
  97. package/dist/Modal.js.map +1 -0
  98. package/dist/NumberInput.d.ts +23 -0
  99. package/dist/NumberInput.js +162 -0
  100. package/dist/NumberInput.js.map +1 -0
  101. package/dist/OtpInput.d.ts +26 -0
  102. package/dist/OtpInput.js +173 -0
  103. package/dist/OtpInput.js.map +1 -0
  104. package/dist/Pagination.d.ts +11 -0
  105. package/dist/Pagination.js +148 -0
  106. package/dist/Pagination.js.map +1 -0
  107. package/dist/Popover.d.ts +13 -0
  108. package/dist/Popover.js +98 -0
  109. package/dist/Popover.js.map +1 -0
  110. package/dist/Progress.d.ts +12 -0
  111. package/dist/Progress.js +61 -0
  112. package/dist/Progress.js.map +1 -0
  113. package/dist/QuoteCard.d.ts +13 -0
  114. package/dist/QuoteCard.js +92 -0
  115. package/dist/QuoteCard.js.map +1 -0
  116. package/dist/Radio.d.ts +19 -0
  117. package/dist/Radio.js +161 -0
  118. package/dist/Radio.js.map +1 -0
  119. package/dist/RadioCards.d.ts +27 -0
  120. package/dist/RadioCards.js +205 -0
  121. package/dist/RadioCards.js.map +1 -0
  122. package/dist/ReactionBar.d.ts +15 -0
  123. package/dist/ReactionBar.js +92 -0
  124. package/dist/ReactionBar.js.map +1 -0
  125. package/dist/ReadingProgress.d.ts +8 -0
  126. package/dist/ReadingProgress.js +51 -0
  127. package/dist/ReadingProgress.js.map +1 -0
  128. package/dist/ReadingTime.d.ts +9 -0
  129. package/dist/ReadingTime.js +39 -0
  130. package/dist/ReadingTime.js.map +1 -0
  131. package/dist/Select.d.ts +20 -0
  132. package/dist/Select.js +244 -0
  133. package/dist/Select.js.map +1 -0
  134. package/dist/Separator.d.ts +14 -0
  135. package/dist/Separator.js +33 -0
  136. package/dist/Separator.js.map +1 -0
  137. package/dist/ShareButtons.d.ts +10 -0
  138. package/dist/ShareButtons.js +107 -0
  139. package/dist/ShareButtons.js.map +1 -0
  140. package/dist/Sidebar.d.ts +30 -0
  141. package/dist/Sidebar.js +140 -0
  142. package/dist/Sidebar.js.map +1 -0
  143. package/dist/Skeleton.d.ts +15 -0
  144. package/dist/Skeleton.js +67 -0
  145. package/dist/Skeleton.js.map +1 -0
  146. package/dist/Slider.d.ts +27 -0
  147. package/dist/Slider.js +182 -0
  148. package/dist/Slider.js.map +1 -0
  149. package/dist/Spinner.d.ts +12 -0
  150. package/dist/Spinner.js +24 -0
  151. package/dist/Spinner.js.map +1 -0
  152. package/dist/SpotlightCard.d.ts +17 -0
  153. package/dist/SpotlightCard.js +87 -0
  154. package/dist/SpotlightCard.js.map +1 -0
  155. package/dist/Stat.d.ts +19 -0
  156. package/dist/Stat.js +71 -0
  157. package/dist/Stat.js.map +1 -0
  158. package/dist/StatCard.d.ts +24 -0
  159. package/dist/StatCard.js +212 -0
  160. package/dist/StatCard.js.map +1 -0
  161. package/dist/Steps.d.ts +14 -0
  162. package/dist/Steps.js +94 -0
  163. package/dist/Steps.js.map +1 -0
  164. package/dist/Table.d.ts +21 -0
  165. package/dist/Table.js +93 -0
  166. package/dist/Table.js.map +1 -0
  167. package/dist/TableOfContents.d.ts +17 -0
  168. package/dist/TableOfContents.js +92 -0
  169. package/dist/TableOfContents.js.map +1 -0
  170. package/dist/Tabs.d.ts +17 -0
  171. package/dist/Tabs.js +123 -0
  172. package/dist/Tabs.js.map +1 -0
  173. package/dist/TagInput.d.ts +16 -0
  174. package/dist/TagInput.js +169 -0
  175. package/dist/TagInput.js.map +1 -0
  176. package/dist/Textarea.d.ts +13 -0
  177. package/dist/Textarea.js +74 -0
  178. package/dist/Textarea.js.map +1 -0
  179. package/dist/TimePicker.d.ts +28 -0
  180. package/dist/TimePicker.js +264 -0
  181. package/dist/TimePicker.js.map +1 -0
  182. package/dist/Timeline.d.ts +19 -0
  183. package/dist/Timeline.js +76 -0
  184. package/dist/Timeline.js.map +1 -0
  185. package/dist/Toast.d.ts +18 -0
  186. package/dist/Toast.js +318 -0
  187. package/dist/Toast.js.map +1 -0
  188. package/dist/Toggle.d.ts +13 -0
  189. package/dist/Toggle.js +84 -0
  190. package/dist/Toggle.js.map +1 -0
  191. package/dist/Tooltip.d.ts +13 -0
  192. package/dist/Tooltip.js +138 -0
  193. package/dist/Tooltip.js.map +1 -0
  194. package/dist/cli.js +172 -5
  195. package/dist/index.d.ts +68 -631
  196. package/dist/index.js +67 -5558
  197. package/dist/index.js.map +1 -1
  198. package/dist/registry/Accordion.tsx +6 -6
  199. package/dist/registry/Alert.tsx +13 -10
  200. package/dist/registry/AuthorCard.tsx +7 -7
  201. package/dist/registry/Avatar.tsx +5 -5
  202. package/dist/registry/Badge.tsx +12 -15
  203. package/dist/registry/Banner.tsx +15 -18
  204. package/dist/registry/Breadcrumb.tsx +3 -3
  205. package/dist/registry/Button.tsx +58 -69
  206. package/dist/registry/ButtonGroup.tsx +9 -9
  207. package/dist/registry/Card.tsx +15 -15
  208. package/dist/registry/CardShell.tsx +6 -6
  209. package/dist/registry/Carousel.tsx +19 -15
  210. package/dist/registry/Checkbox.tsx +14 -9
  211. package/dist/registry/CloseButton.tsx +2 -2
  212. package/dist/registry/CodeBlock.tsx +15 -15
  213. package/dist/registry/ColorPicker.tsx +404 -0
  214. package/dist/registry/Combobox.tsx +318 -0
  215. package/dist/registry/CommandPalette.tsx +31 -24
  216. package/dist/registry/ContextMenu.tsx +241 -0
  217. package/dist/registry/DataList.tsx +4 -4
  218. package/dist/registry/DatePicker.tsx +494 -0
  219. package/dist/registry/DateRangePicker.tsx +232 -0
  220. package/dist/registry/Drawer.tsx +17 -15
  221. package/dist/registry/DropdownMenu.tsx +39 -77
  222. package/dist/registry/EmptyState.tsx +8 -8
  223. package/dist/registry/FieldMessage.tsx +123 -0
  224. package/dist/registry/FileUpload.tsx +318 -0
  225. package/dist/registry/Floating.tsx +134 -0
  226. package/dist/registry/HoverCard.tsx +113 -0
  227. package/dist/registry/Input.tsx +54 -43
  228. package/dist/registry/Kbd.tsx +4 -5
  229. package/dist/registry/Modal.tsx +17 -15
  230. package/dist/registry/NumberInput.tsx +183 -0
  231. package/dist/registry/OtpInput.tsx +219 -0
  232. package/dist/registry/Pagination.tsx +15 -18
  233. package/dist/registry/Popover.tsx +40 -45
  234. package/dist/registry/Progress.tsx +4 -4
  235. package/dist/registry/QuoteCard.tsx +7 -7
  236. package/dist/registry/Radio.tsx +24 -21
  237. package/dist/registry/RadioCards.tsx +247 -0
  238. package/dist/registry/ReactionBar.tsx +5 -5
  239. package/dist/registry/ReadingProgress.tsx +2 -2
  240. package/dist/registry/ReadingTime.tsx +2 -2
  241. package/dist/registry/Select.tsx +28 -53
  242. package/dist/registry/Separator.tsx +52 -0
  243. package/dist/registry/ShareButtons.tsx +2 -2
  244. package/dist/registry/Sidebar.tsx +18 -18
  245. package/dist/registry/Skeleton.tsx +1 -1
  246. package/dist/registry/Slider.tsx +229 -0
  247. package/dist/registry/Spinner.tsx +32 -0
  248. package/dist/registry/SpotlightCard.tsx +6 -6
  249. package/dist/registry/Stat.tsx +4 -4
  250. package/dist/registry/StatCard.tsx +19 -19
  251. package/dist/registry/Steps.tsx +7 -7
  252. package/dist/registry/Table.tsx +12 -10
  253. package/dist/registry/TableOfContents.tsx +8 -8
  254. package/dist/registry/Tabs.tsx +6 -6
  255. package/dist/registry/TagInput.tsx +9 -9
  256. package/dist/registry/Textarea.tsx +5 -5
  257. package/dist/registry/TimePicker.tsx +315 -0
  258. package/dist/registry/Timeline.tsx +14 -14
  259. package/dist/registry/Toast.tsx +15 -12
  260. package/dist/registry/Toggle.tsx +7 -10
  261. package/dist/registry/Tooltip.tsx +21 -73
  262. package/dist/registry/styles.css +868 -62
  263. package/dist/registry/useFloatingPanel.ts +112 -0
  264. package/dist/styles.css +868 -62
  265. package/dist/useFloatingPanel.d.ts +24 -0
  266. package/dist/useFloatingPanel.js +89 -0
  267. package/dist/useFloatingPanel.js.map +1 -0
  268. package/dist/useModalBehavior.d.ts +15 -0
  269. package/dist/useModalBehavior.js +57 -0
  270. package/dist/useModalBehavior.js.map +1 -0
  271. package/package.json +1 -1
@@ -42,7 +42,7 @@ function MediaPlaceholder({ dark, bg, monogram }: { dark?: boolean; bg?: string;
42
42
  return (
43
43
  <div
44
44
  className={["relative w-full h-full flex items-center justify-center", bg ?? ""].join(" ")}
45
- style={bg ? undefined : { background: dark ? "var(--media-well-dark)" : "var(--media-well-light)" }}
45
+ style={bg ? undefined : { background: dark ? "var(--media-well-dark)" : "var(--media-well)" }}
46
46
  >
47
47
  {/* A faint dot grid fading out from the centre: a slot, not a hole */}
48
48
  <div
@@ -50,11 +50,11 @@ function MediaPlaceholder({ dark, bg, monogram }: { dark?: boolean; bg?: string;
50
50
  className="absolute inset-0"
51
51
  style={{
52
52
  backgroundImage: `radial-gradient(${
53
- bg ? "rgba(255,255,255,0.22)" : dark ? "rgba(255,255,255,0.09)" : "rgba(17,17,17,0.09)"
53
+ bg ? "var(--media-dots-on-colour)" : dark ? "var(--media-dots-dark)" : "var(--media-dots)"
54
54
  } 1px, transparent 1px)`,
55
55
  backgroundSize: "12px 12px",
56
- maskImage: "radial-gradient(70% 70% at 50% 50%, #000 0%, transparent 100%)",
57
- WebkitMaskImage: "radial-gradient(70% 70% at 50% 50%, #000 0%, transparent 100%)",
56
+ maskImage: "radial-gradient(70% 70% at 50% 50%, black 0%, transparent 100%)",
57
+ WebkitMaskImage: "radial-gradient(70% 70% at 50% 50%, black 0%, transparent 100%)",
58
58
  }}
59
59
  />
60
60
  {/* The title's initial, set huge and barely there and cropped by the
@@ -64,7 +64,7 @@ function MediaPlaceholder({ dark, bg, monogram }: { dark?: boolean; bg?: string;
64
64
  aria-hidden
65
65
  className={[
66
66
  "absolute -right-3 -bottom-[0.32em] text-[220px] font-semibold leading-none tracking-[-0.06em] select-none",
67
- dark ? "text-white/[0.045]" : "text-neutral-900/[0.045]",
67
+ dark ? "text-white/[0.045]" : "text-ink/[0.045]",
68
68
  ].join(" ")}
69
69
  >
70
70
  {monogram}
@@ -103,11 +103,11 @@ function IconTile({ dark, children }: { dark: boolean; children: React.ReactNode
103
103
  aria-hidden
104
104
  className={[
105
105
  "w-9 h-9 rounded-[11px] flex items-center justify-center shrink-0",
106
- dark ? "text-neutral-100" : "text-neutral-700",
106
+ dark ? "text-neutral-100" : "text-ink-label",
107
107
  ].join(" ")}
108
108
  style={{
109
- background: dark ? "var(--tile-dark)" : "var(--face-light)",
110
- boxShadow: dark ? "var(--tile-dark-shadow)" : "var(--tile-light-shadow)",
109
+ background: dark ? "var(--tile-dark)" : "var(--tile)",
110
+ boxShadow: dark ? "var(--tile-dark-shadow)" : "var(--tile-shadow)",
111
111
  }}
112
112
  >
113
113
  {children}
@@ -138,7 +138,7 @@ export function Card(props: CardProps) {
138
138
  rail={actions}
139
139
  >
140
140
  {/* Hairline under the media so it reads as set into the face */}
141
- <div className="relative h-52 shrink-0 overflow-hidden" style={{ boxShadow: "0 1px 0 rgba(17,17,17,0.07)" }}>
141
+ <div className="relative h-52 shrink-0 overflow-hidden" style={{ boxShadow: "0 1px 0 var(--divider)" }}>
142
142
  <Media image={image} imageSrc={imageSrc} imageAlt={imageAlt} bg={imageBg} />
143
143
  </div>
144
144
 
@@ -146,20 +146,20 @@ export function Card(props: CardProps) {
146
146
  {(title || badge) && (
147
147
  <div className="flex items-center gap-2">
148
148
  {title && (
149
- <h3 className="text-[17px] font-semibold text-neutral-900 tracking-[-0.015em] leading-snug">{title}</h3>
149
+ <h3 className="text-[17px] font-semibold text-ink tracking-[-0.015em] leading-snug">{title}</h3>
150
150
  )}
151
151
  {badge}
152
152
  </div>
153
153
  )}
154
154
  {subtitle && (
155
155
  // Line breaks in the copy are for centred layouts; let it flow here
156
- <p className="mt-1.5 text-[14px] text-neutral-600 leading-[1.55] text-pretty">
156
+ <p className="mt-1.5 text-[14px] text-ink-body leading-[1.55] text-pretty">
157
157
  {subtitle.replace(/\n/g, " ")}
158
158
  </p>
159
159
  )}
160
160
  {children}
161
161
  {note && (
162
- <p className="mt-auto pt-5 text-[12px] text-neutral-500 leading-relaxed text-pretty">{note}</p>
162
+ <p className="mt-auto pt-5 text-[12px] text-ink-muted leading-relaxed text-pretty">{note}</p>
163
163
  )}
164
164
  </div>
165
165
  </CardShell>
@@ -198,7 +198,7 @@ export function Card(props: CardProps) {
198
198
  className={[
199
199
  "text-[34px] font-medium leading-[1.02] tracking-[-0.04em] text-balance max-w-[14ch]",
200
200
  icon ? "mt-5" : "",
201
- dark ? "text-white" : "text-neutral-900",
201
+ dark ? "text-white" : "text-ink",
202
202
  ].join(" ")}
203
203
  >
204
204
  {title}
@@ -206,14 +206,14 @@ export function Card(props: CardProps) {
206
206
  )}
207
207
  <div className="mt-auto pt-8 flex flex-col gap-2">
208
208
  {subtitle && (
209
- <p className="text-[14px] leading-[1.45] tracking-[-0.005em] text-neutral-500">{subtitle}</p>
209
+ <p className={["text-[14px] leading-[1.45] tracking-[-0.005em]", dark ? "text-neutral-500" : "text-ink-muted"].join(" ")}>{subtitle}</p>
210
210
  )}
211
211
  {children}
212
212
  </div>
213
213
  </div>
214
214
  <div
215
215
  className="relative w-[40%] shrink-0 overflow-hidden"
216
- style={{ boxShadow: dark ? "-1px 0 0 rgba(255,255,255,0.07)" : "-1px 0 0 rgba(17,17,17,0.07)" }}
216
+ style={{ boxShadow: dark ? "-1px 0 0 var(--divider-dark)" : "-1px 0 0 var(--divider)" }}
217
217
  >
218
218
  <Media
219
219
  image={image}
@@ -43,16 +43,16 @@ export function CardShell({
43
43
  className,
44
44
  ].join(" ")}
45
45
  style={{
46
- background: dark ? "var(--card-bezel-dark)" : "var(--card-bezel-light)",
47
- boxShadow: dark ? "var(--card-dark-shadow)" : "var(--card-light-shadow)",
48
- ["--rim" as string]: dark ? "rgba(255,255,255,0.1)" : "rgba(255,255,255,1)",
46
+ background: dark ? "var(--card-bezel-dark)" : "var(--card-bezel)",
47
+ boxShadow: dark ? "var(--card-dark-shadow)" : "var(--card-shadow)",
48
+ ["--rim" as string]: dark ? "var(--card-dark-rim)" : "var(--card-rim)",
49
49
  } as React.CSSProperties}
50
50
  >
51
51
  <div
52
52
  className={["relative flex-1 min-h-0 rounded-[18px] overflow-hidden flex flex-col", faceClassName].join(" ")}
53
53
  style={{
54
- background: dark ? "var(--card-dark)" : "var(--card-light)",
55
- boxShadow: dark ? "var(--card-face-dark-shadow)" : "var(--card-face-light-shadow)",
54
+ background: dark ? "var(--card-dark)" : "var(--card)",
55
+ boxShadow: dark ? "var(--card-face-dark-shadow)" : "var(--card-face-shadow)",
56
56
  }}
57
57
  >
58
58
  {children}
@@ -66,7 +66,7 @@ export function CardShell({
66
66
  // rails come out the same height and line up across a row
67
67
  "min-h-10 flex items-center gap-2 text-[12.5px]",
68
68
  railKind === "text" ? "pl-[18px] pr-3 gap-2.5" : "",
69
- dark ? "text-neutral-400" : "text-neutral-500",
69
+ dark ? "text-neutral-400" : "text-ink-muted",
70
70
  ].join(" ")}
71
71
  >
72
72
  {rail}
@@ -64,8 +64,11 @@ export function Carousel({
64
64
  const goNext = () => go((currentIdxRef.current + 1) % items.length, "right");
65
65
  const goPrev = () => go((currentIdxRef.current - 1 + items.length) % items.length, "left");
66
66
 
67
+ // Kept current after each render so the autoplay timer never goes stale
67
68
  const goNextRef = useRef(goNext);
68
- goNextRef.current = goNext;
69
+ useEffect(() => {
70
+ goNextRef.current = goNext;
71
+ });
69
72
 
70
73
  useEffect(() => {
71
74
  if (!autoPlay || paused) return;
@@ -96,7 +99,8 @@ export function Carousel({
96
99
  const dy = e.clientY - dragRef.current.y;
97
100
  dragRef.current.active = false;
98
101
  if (Math.abs(dx) > THRESHOLD && Math.abs(dx) > Math.abs(dy) * 1.5) {
99
- dx < 0 ? goNextRef.current() : goPrev();
102
+ if (dx < 0) goNextRef.current();
103
+ else goPrev();
100
104
  }
101
105
  };
102
106
 
@@ -138,7 +142,7 @@ export function Carousel({
138
142
  "relative h-1.5 rounded-full overflow-hidden cursor-pointer",
139
143
  "transition-[width,background] duration-300 ease-[var(--ease-out-soft)]",
140
144
  "after:absolute after:-inset-2 after:content-['']",
141
- active ? "w-6 bg-neutral-900/15" : "w-1.5 bg-neutral-900/20 hover:bg-neutral-900/40",
145
+ active ? "w-6 bg-ink/15" : "w-1.5 bg-ink/20 hover:bg-ink/40",
142
146
  ].join(" ")}
143
147
  aria-label={`Go to slide ${i + 1}`}
144
148
  aria-current={active ? "true" : undefined}
@@ -149,7 +153,7 @@ export function Carousel({
149
153
  aria-hidden
150
154
  className={["absolute inset-0 rounded-full origin-left", autoPlay ? "carousel-progress" : ""].join(" ")}
151
155
  style={{
152
- background: "var(--face-dark)",
156
+ background: "var(--face-inverse)",
153
157
  animationDuration: `${interval}ms`,
154
158
  animationPlayState: paused ? "paused" : "running",
155
159
  }}
@@ -159,9 +163,9 @@ export function Carousel({
159
163
  );
160
164
  })}
161
165
  </div>
162
- <span className="text-[12px] font-medium text-neutral-600 tabular-nums">
166
+ <span className="text-[12px] font-medium text-ink-body tabular-nums">
163
167
  {currentIdx + 1}
164
- <span className="text-neutral-400"> / {items.length}</span>
168
+ <span className="text-ink-faint"> / {items.length}</span>
165
169
  </span>
166
170
  </div>
167
171
 
@@ -242,7 +246,7 @@ export function CarouselSlide({ theme = "dark", tint = "#8A8E7A", icon, title, m
242
246
  <div
243
247
  className="relative w-full h-full flex flex-col justify-end gap-6 p-8 overflow-hidden select-none"
244
248
  style={{
245
- background: theme === "dark" ? "var(--card-dark)" : theme === "light" ? "var(--card-light)" : tint,
249
+ background: theme === "dark" ? "var(--card-dark)" : theme === "light" ? "var(--card)" : tint,
246
250
  }}
247
251
  >
248
252
  <div
@@ -250,11 +254,11 @@ export function CarouselSlide({ theme = "dark", tint = "#8A8E7A", icon, title, m
250
254
  className="absolute inset-y-0 right-0 w-3/5"
251
255
  style={{
252
256
  backgroundImage: `radial-gradient(${
253
- theme === "tint" ? "rgba(255,255,255,0.22)" : dark ? "rgba(255,255,255,0.09)" : "rgba(17,17,17,0.08)"
257
+ theme === "tint" ? "var(--media-dots-on-colour)" : dark ? "var(--media-dots-dark)" : "var(--slide-dots)"
254
258
  } 1px, transparent 1px)`,
255
259
  backgroundSize: "12px 12px",
256
- maskImage: "radial-gradient(60% 70% at 70% 50%, #000 0%, transparent 100%)",
257
- WebkitMaskImage: "radial-gradient(60% 70% at 70% 50%, #000 0%, transparent 100%)",
260
+ maskImage: "radial-gradient(60% 70% at 70% 50%, black 0%, transparent 100%)",
261
+ WebkitMaskImage: "radial-gradient(60% 70% at 70% 50%, black 0%, transparent 100%)",
258
262
  }}
259
263
  />
260
264
  {icon && (
@@ -262,11 +266,11 @@ export function CarouselSlide({ theme = "dark", tint = "#8A8E7A", icon, title, m
262
266
  aria-hidden
263
267
  className={[
264
268
  "relative w-9 h-9 rounded-[11px] flex items-center justify-center mb-auto",
265
- dark ? "text-neutral-100" : "text-neutral-700",
269
+ dark ? "text-neutral-100" : "text-ink-label",
266
270
  ].join(" ")}
267
271
  style={{
268
- background: dark ? "var(--tile-dark)" : "var(--face-light)",
269
- boxShadow: dark ? "var(--tile-dark-shadow)" : "var(--tile-light-shadow)",
272
+ background: dark ? "var(--tile-dark)" : "var(--tile)",
273
+ boxShadow: dark ? "var(--tile-dark-shadow)" : "var(--tile-shadow)",
270
274
  }}
271
275
  >
272
276
  {icon}
@@ -276,13 +280,13 @@ export function CarouselSlide({ theme = "dark", tint = "#8A8E7A", icon, title, m
276
280
  <p
277
281
  className={[
278
282
  "text-[22px] font-medium leading-[1.2] tracking-[-0.015em] mb-2",
279
- dark ? "text-white" : "text-neutral-900",
283
+ dark ? "text-white" : "text-ink",
280
284
  ].join(" ")}
281
285
  >
282
286
  {title}
283
287
  </p>
284
288
  {meta && (
285
- <p className={["text-[13px]", theme === "tint" ? "text-white/65" : dark ? "text-neutral-400" : "text-neutral-500"].join(" ")}>
289
+ <p className={["text-[13px]", theme === "tint" ? "text-white/65" : dark ? "text-neutral-400" : "text-ink-muted"].join(" ")}>
286
290
  {meta}
287
291
  </p>
288
292
  )}
@@ -40,7 +40,7 @@ export function Checkbox({
40
40
  <div
41
41
  className={[
42
42
  "flex items-center justify-between gap-4 select-none",
43
- disabled ? "opacity-40 pointer-events-none" : "cursor-pointer",
43
+ disabled ? "opacity-40 pointer-events-none" : "cursor-pointer group/checkbox",
44
44
  className,
45
45
  ].join(" ")}
46
46
  onClick={toggle}
@@ -48,10 +48,10 @@ export function Checkbox({
48
48
  {(label || description) && (
49
49
  <div className="flex flex-col gap-0.5 min-w-0">
50
50
  {label && (
51
- <span id={`${uid}-label`} className="text-[13px] font-medium text-neutral-900 leading-snug">{label}</span>
51
+ <span id={`${uid}-label`} className="text-[13px] font-medium text-ink leading-snug">{label}</span>
52
52
  )}
53
53
  {description && (
54
- <span id={`${uid}-desc`} className="text-[12px] text-neutral-500 leading-relaxed">{description}</span>
54
+ <span id={`${uid}-desc`} className="text-[12px] text-ink-muted leading-relaxed">{description}</span>
55
55
  )}
56
56
  </div>
57
57
  )}
@@ -65,26 +65,31 @@ export function Checkbox({
65
65
  aria-describedby={description ? `${uid}-desc` : undefined}
66
66
  disabled={disabled}
67
67
  className={[
68
- "shrink-0 w-[22px] h-[22px] rounded-[7px] flex items-center justify-center cursor-pointer",
68
+ "shrink-0 w-[22px] h-[22px] rounded-[7px] flex items-center justify-center cursor-pointer text-ink-inverse",
69
69
  "transition-[box-shadow,transform,scale] duration-200 ease-out active:scale-90",
70
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink",
71
+ // an empty box answers the pointer like any other field
72
+ active ? "" : "group-hover/checkbox:[box-shadow:var(--field-shadow-hover)]",
70
73
  ].join(" ")}
71
74
  style={{
72
- background: active ? "var(--face-dark)" : "var(--field)",
73
- boxShadow: active ? "var(--face-dark-shadow)" : "var(--field-shadow)",
75
+ background: active ? "var(--face-inverse)" : "var(--field)",
76
+ boxShadow: active ? "var(--face-inverse-shadow)" : "var(--field-shadow)",
74
77
  }}
75
78
  >
76
79
  {active && (
77
80
  indeterminate ? (
78
81
  <span className="animate-checkbox-in">
79
82
  <svg width="10" height="2" viewBox="0 0 10 2" fill="none">
80
- <rect width="10" height="2" rx="1" fill="white" />
83
+ <rect width="10" height="2" rx="1" fill="currentColor" />
81
84
  </svg>
82
85
  </span>
83
86
  ) : (
84
- <svg width="13" height="10" viewBox="0 0 13 10" fill="none">
87
+ /* The mark is pressed into the face: it takes the inverse ink, so it
88
+ reads on the dark face in light mode and the pale one in dark */
89
+ <svg width="13" height="10" viewBox="0 0 13 10" fill="none" style={{ filter: "drop-shadow(var(--emboss-inverse))" }}>
85
90
  <path
86
91
  d="M1.5 5l3.5 3.5L11.5 1"
87
- stroke="white"
92
+ stroke="currentColor"
88
93
  strokeWidth="2"
89
94
  strokeLinecap="round"
90
95
  strokeLinejoin="round"
@@ -38,7 +38,7 @@ export function CloseButton({
38
38
  "focus-visible:outline-2 focus-visible:outline-offset-2",
39
39
  dark
40
40
  ? "text-white/45 hover:text-white focus-visible:outline-white"
41
- : "text-neutral-400 hover:text-neutral-900 focus-visible:outline-neutral-900",
41
+ : "text-ink-faint hover:text-ink focus-visible:outline-ink",
42
42
  s.box,
43
43
  className,
44
44
  ].join(" ")}
@@ -49,7 +49,7 @@ export function CloseButton({
49
49
  "absolute inset-0 rounded-[inherit] opacity-0 group-hover/close:opacity-100 transition-opacity duration-150",
50
50
  dark
51
51
  ? "[background:var(--tile-dark)] [box-shadow:var(--tile-dark-shadow)]"
52
- : "[background:var(--face-light)] [box-shadow:var(--face-light-shadow)]",
52
+ : "[background:var(--face)] [box-shadow:var(--face-shadow)]",
53
53
  ].join(" ")}
54
54
  />
55
55
  <svg
@@ -25,11 +25,11 @@ const KEYWORDS = new Set([
25
25
  const TOKEN_RE = /(\/\/.*$|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`|<\/?\s*[A-Z][a-zA-Z0-9.]*|<\/?\s*[a-z][a-zA-Z0-9-]*|=>|\b\d+(?:\.\d+)?\b|\b[a-zA-Z_$][a-zA-Z0-9_$]*\b)/;
26
26
 
27
27
  const TOKEN_STYLES: Record<string, string> = {
28
- keyword: "text-violet-600",
29
- string: "text-emerald-700",
30
- comment: "text-neutral-400 italic",
31
- tag: "text-sky-700",
32
- number: "text-amber-700",
28
+ keyword: "text-code-keyword",
29
+ string: "text-code-string",
30
+ comment: "text-ink-faint italic",
31
+ tag: "text-code-tag",
32
+ number: "text-code-number",
33
33
  };
34
34
 
35
35
  function classifyToken(val: string): string {
@@ -101,11 +101,11 @@ export function CodeBlock({
101
101
  <figcaption className="flex items-center justify-between gap-3 pl-3 pr-0.5 h-10">
102
102
  <div className="flex items-center gap-2 min-w-0">
103
103
  {title && (
104
- <span className="text-[12px] font-medium text-neutral-700 truncate">{title}</span>
104
+ <span className="text-[12px] font-medium text-ink-label truncate">{title}</span>
105
105
  )}
106
106
  {language && (
107
107
  <span
108
- className="text-[11px] font-semibold text-neutral-500 lowercase px-1.5 py-0.5 rounded-[5px]"
108
+ className="text-[11px] font-semibold text-ink-muted lowercase px-1.5 py-0.5 rounded-[5px]"
109
109
  style={{ background: "var(--well)", boxShadow: "var(--well-shadow)" }}
110
110
  >
111
111
  {language}
@@ -120,14 +120,14 @@ export function CodeBlock({
120
120
  type="button"
121
121
  onClick={handleCopy}
122
122
  aria-label={copied ? "copied to clipboard" : "copy code"}
123
- className="inline-flex items-center h-7 px-2.5 rounded-[8px] text-[11.5px] font-medium cursor-pointer transition-[color,transform,scale] duration-150 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-900"
123
+ className="inline-flex items-center h-7 px-2.5 rounded-[8px] text-[11.5px] font-medium cursor-pointer transition-[color,transform,scale] duration-150 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink"
124
124
  style={{
125
- background: "var(--face-light)",
126
- boxShadow: "var(--face-light-shadow)",
127
- color: copied ? "#047857" : undefined,
125
+ background: "var(--face)",
126
+ boxShadow: "var(--face-shadow)",
127
+ color: copied ? "var(--success-strong)" : undefined,
128
128
  }}
129
129
  >
130
- <span className="grid overflow-hidden text-neutral-600" style={{ color: "inherit" }}>
130
+ <span className="grid overflow-hidden text-ink-body" style={{ color: "inherit" }}>
131
131
  <span
132
132
  aria-hidden
133
133
  className="[grid-area:1/1] inline-flex items-center justify-center gap-1.5"
@@ -171,15 +171,15 @@ export function CodeBlock({
171
171
  <span aria-live="polite" className="sr-only">{copied ? "copied to clipboard" : ""}</span>
172
172
  </figcaption>
173
173
  <div
174
- className="bg-white rounded-[13px] overflow-x-auto scroll-thin"
174
+ className="bg-panel-face rounded-[13px] overflow-x-auto scroll-thin"
175
175
  style={{ boxShadow: "var(--panel-face-shadow)" }}
176
176
  >
177
- <pre className="py-4 px-4 text-[13px] leading-[1.7] font-mono text-neutral-800">
177
+ <pre className="py-4 px-4 text-[13px] leading-[1.7] font-mono text-ink-soft">
178
178
  <code>
179
179
  {lines.map((line, i) => (
180
180
  <div key={i} className="flex">
181
181
  {showLineNumbers && (
182
- <span aria-hidden className="select-none w-8 shrink-0 text-right pr-4 text-neutral-300 tabular-nums">
182
+ <span aria-hidden className="select-none w-8 shrink-0 text-right pr-4 text-ink-ghost tabular-nums">
183
183
  {i + 1}
184
184
  </span>
185
185
  )}