@charcuterie/ui 0.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 (223) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +161 -0
  3. package/dist/Alert/Alert.d.ts +88 -0
  4. package/dist/Alert/Alert.d.ts.map +1 -0
  5. package/dist/Alert/Alert.js +67 -0
  6. package/dist/Alert/Alert.js.map +1 -0
  7. package/dist/Badge/Badge.d.ts +54 -0
  8. package/dist/Badge/Badge.d.ts.map +1 -0
  9. package/dist/Badge/Badge.js +54 -0
  10. package/dist/Badge/Badge.js.map +1 -0
  11. package/dist/Badge/useIsTextClipped.d.ts +22 -0
  12. package/dist/Badge/useIsTextClipped.d.ts.map +1 -0
  13. package/dist/Badge/useIsTextClipped.js +57 -0
  14. package/dist/Badge/useIsTextClipped.js.map +1 -0
  15. package/dist/Button/Button.d.ts +58 -0
  16. package/dist/Button/Button.d.ts.map +1 -0
  17. package/dist/Button/Button.js +37 -0
  18. package/dist/Button/Button.js.map +1 -0
  19. package/dist/Card/Card.d.ts +44 -0
  20. package/dist/Card/Card.d.ts.map +1 -0
  21. package/dist/Card/Card.js +59 -0
  22. package/dist/Card/Card.js.map +1 -0
  23. package/dist/EmptyState/EmptyState.d.ts +42 -0
  24. package/dist/EmptyState/EmptyState.d.ts.map +1 -0
  25. package/dist/EmptyState/EmptyState.js +37 -0
  26. package/dist/EmptyState/EmptyState.js.map +1 -0
  27. package/dist/IconButton/IconButton.d.ts +34 -0
  28. package/dist/IconButton/IconButton.d.ts.map +1 -0
  29. package/dist/IconButton/IconButton.js +23 -0
  30. package/dist/IconButton/IconButton.js.map +1 -0
  31. package/dist/LiveStatusIndicator/LiveStatusIndicator.d.ts +37 -0
  32. package/dist/LiveStatusIndicator/LiveStatusIndicator.d.ts.map +1 -0
  33. package/dist/LiveStatusIndicator/LiveStatusIndicator.js +39 -0
  34. package/dist/LiveStatusIndicator/LiveStatusIndicator.js.map +1 -0
  35. package/dist/MediaTile/MediaTile.d.ts +46 -0
  36. package/dist/MediaTile/MediaTile.d.ts.map +1 -0
  37. package/dist/MediaTile/MediaTile.js +79 -0
  38. package/dist/MediaTile/MediaTile.js.map +1 -0
  39. package/dist/MediaTile/mediaStatus.d.ts +22 -0
  40. package/dist/MediaTile/mediaStatus.d.ts.map +1 -0
  41. package/dist/MediaTile/mediaStatus.js +24 -0
  42. package/dist/MediaTile/mediaStatus.js.map +1 -0
  43. package/dist/Modal/Modal.d.ts +66 -0
  44. package/dist/Modal/Modal.d.ts.map +1 -0
  45. package/dist/Modal/Modal.js +111 -0
  46. package/dist/Modal/Modal.js.map +1 -0
  47. package/dist/Modal/lockScrollBehind.d.ts +22 -0
  48. package/dist/Modal/lockScrollBehind.d.ts.map +1 -0
  49. package/dist/Modal/lockScrollBehind.js +48 -0
  50. package/dist/Modal/lockScrollBehind.js.map +1 -0
  51. package/dist/Popover/Popover.d.ts +66 -0
  52. package/dist/Popover/Popover.d.ts.map +1 -0
  53. package/dist/Popover/Popover.js +88 -0
  54. package/dist/Popover/Popover.js.map +1 -0
  55. package/dist/ProgressBar/ProgressBar.d.ts +51 -0
  56. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -0
  57. package/dist/ProgressBar/ProgressBar.js +50 -0
  58. package/dist/ProgressBar/ProgressBar.js.map +1 -0
  59. package/dist/ProgressBar/progressValue.d.ts +44 -0
  60. package/dist/ProgressBar/progressValue.d.ts.map +1 -0
  61. package/dist/ProgressBar/progressValue.js +55 -0
  62. package/dist/ProgressBar/progressValue.js.map +1 -0
  63. package/dist/SegmentedControl/SegmentedControl.d.ts +59 -0
  64. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -0
  65. package/dist/SegmentedControl/SegmentedControl.js +129 -0
  66. package/dist/SegmentedControl/SegmentedControl.js.map +1 -0
  67. package/dist/SegmentedControl/SegmentedOption.d.ts +28 -0
  68. package/dist/SegmentedControl/SegmentedOption.d.ts.map +1 -0
  69. package/dist/SegmentedControl/SegmentedOption.js +40 -0
  70. package/dist/SegmentedControl/SegmentedOption.js.map +1 -0
  71. package/dist/Skeleton/Skeleton.d.ts +30 -0
  72. package/dist/Skeleton/Skeleton.d.ts.map +1 -0
  73. package/dist/Skeleton/Skeleton.js +43 -0
  74. package/dist/Skeleton/Skeleton.js.map +1 -0
  75. package/dist/Spinner/Spinner.d.ts +37 -0
  76. package/dist/Spinner/Spinner.d.ts.map +1 -0
  77. package/dist/Spinner/Spinner.js +33 -0
  78. package/dist/Spinner/Spinner.js.map +1 -0
  79. package/dist/Tabs/TabTrigger.d.ts +32 -0
  80. package/dist/Tabs/TabTrigger.d.ts.map +1 -0
  81. package/dist/Tabs/TabTrigger.js +62 -0
  82. package/dist/Tabs/TabTrigger.js.map +1 -0
  83. package/dist/Tabs/Tabs.d.ts +95 -0
  84. package/dist/Tabs/Tabs.d.ts.map +1 -0
  85. package/dist/Tabs/Tabs.js +195 -0
  86. package/dist/Tabs/Tabs.js.map +1 -0
  87. package/dist/VisuallyHidden/VisuallyHidden.d.ts +25 -0
  88. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  89. package/dist/VisuallyHidden/VisuallyHidden.js +23 -0
  90. package/dist/VisuallyHidden/VisuallyHidden.js.map +1 -0
  91. package/dist/controlStyles.d.ts +50 -0
  92. package/dist/controlStyles.d.ts.map +1 -0
  93. package/dist/controlStyles.js +60 -0
  94. package/dist/controlStyles.js.map +1 -0
  95. package/dist/expectNoAxeViolations.testHelpers.d.ts +19 -0
  96. package/dist/expectNoAxeViolations.testHelpers.d.ts.map +1 -0
  97. package/dist/expectNoAxeViolations.testHelpers.js +32 -0
  98. package/dist/expectNoAxeViolations.testHelpers.js.map +1 -0
  99. package/dist/index.d.ts +75 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +55 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/intentStyles.d.ts +76 -0
  104. package/dist/intentStyles.d.ts.map +1 -0
  105. package/dist/intentStyles.js +150 -0
  106. package/dist/intentStyles.js.map +1 -0
  107. package/dist/mountStory.testHelpers.d.ts +30 -0
  108. package/dist/mountStory.testHelpers.d.ts.map +1 -0
  109. package/dist/mountStory.testHelpers.js +19 -0
  110. package/dist/mountStory.testHelpers.js.map +1 -0
  111. package/dist/statusIntent.d.ts +33 -0
  112. package/dist/statusIntent.d.ts.map +1 -0
  113. package/dist/statusIntent.js +99 -0
  114. package/dist/statusIntent.js.map +1 -0
  115. package/dist/styles.css +130 -0
  116. package/dist/testing/expectAgentDrivable.d.ts +53 -0
  117. package/dist/testing/expectAgentDrivable.d.ts.map +1 -0
  118. package/dist/testing/expectAgentDrivable.js +163 -0
  119. package/dist/testing/expectAgentDrivable.js.map +1 -0
  120. package/dist/testing/index.d.ts +11 -0
  121. package/dist/testing/index.d.ts.map +1 -0
  122. package/dist/testing/index.js +10 -0
  123. package/dist/testing/index.js.map +1 -0
  124. package/dist/toClassName.d.ts +12 -0
  125. package/dist/toClassName.d.ts.map +1 -0
  126. package/dist/toClassName.js +12 -0
  127. package/dist/toClassName.js.map +1 -0
  128. package/dist/tokens.d.ts +16 -0
  129. package/dist/tokens.d.ts.map +1 -0
  130. package/dist/tokens.js +16 -0
  131. package/dist/tokens.js.map +1 -0
  132. package/package.json +70 -0
  133. package/src/Alert/Alert.mdx +70 -0
  134. package/src/Alert/Alert.stories.tsx +218 -0
  135. package/src/Alert/Alert.test.tsx +112 -0
  136. package/src/Alert/Alert.tsx +166 -0
  137. package/src/Badge/Badge.mdx +43 -0
  138. package/src/Badge/Badge.stories.tsx +229 -0
  139. package/src/Badge/Badge.test.tsx +153 -0
  140. package/src/Badge/Badge.tsx +130 -0
  141. package/src/Badge/useIsTextClipped.ts +77 -0
  142. package/src/Button/Button.mdx +44 -0
  143. package/src/Button/Button.stories.tsx +175 -0
  144. package/src/Button/Button.test.tsx +114 -0
  145. package/src/Button/Button.tsx +125 -0
  146. package/src/Card/Card.mdx +53 -0
  147. package/src/Card/Card.stories.tsx +207 -0
  148. package/src/Card/Card.test.tsx +56 -0
  149. package/src/Card/Card.tsx +142 -0
  150. package/src/EmptyState/EmptyState.mdx +40 -0
  151. package/src/EmptyState/EmptyState.stories.tsx +183 -0
  152. package/src/EmptyState/EmptyState.test.tsx +41 -0
  153. package/src/EmptyState/EmptyState.tsx +114 -0
  154. package/src/IconButton/IconButton.mdx +34 -0
  155. package/src/IconButton/IconButton.stories.tsx +191 -0
  156. package/src/IconButton/IconButton.test.tsx +70 -0
  157. package/src/IconButton/IconButton.tsx +54 -0
  158. package/src/LiveStatusIndicator/LiveStatusIndicator.mdx +43 -0
  159. package/src/LiveStatusIndicator/LiveStatusIndicator.stories.tsx +199 -0
  160. package/src/LiveStatusIndicator/LiveStatusIndicator.test.tsx +63 -0
  161. package/src/LiveStatusIndicator/LiveStatusIndicator.tsx +116 -0
  162. package/src/MediaTile/MediaTile.mdx +51 -0
  163. package/src/MediaTile/MediaTile.stories.tsx +211 -0
  164. package/src/MediaTile/MediaTile.test.tsx +41 -0
  165. package/src/MediaTile/MediaTile.tsx +227 -0
  166. package/src/MediaTile/mediaStatus.ts +28 -0
  167. package/src/Modal/Modal.mdx +113 -0
  168. package/src/Modal/Modal.stories.tsx +272 -0
  169. package/src/Modal/Modal.test.tsx +248 -0
  170. package/src/Modal/Modal.tsx +228 -0
  171. package/src/Modal/lockScrollBehind.ts +59 -0
  172. package/src/Popover/Popover.mdx +102 -0
  173. package/src/Popover/Popover.stories.tsx +247 -0
  174. package/src/Popover/Popover.test.tsx +191 -0
  175. package/src/Popover/Popover.tsx +164 -0
  176. package/src/ProgressBar/ProgressBar.mdx +48 -0
  177. package/src/ProgressBar/ProgressBar.stories.tsx +232 -0
  178. package/src/ProgressBar/ProgressBar.test.tsx +74 -0
  179. package/src/ProgressBar/ProgressBar.tsx +172 -0
  180. package/src/ProgressBar/progressValue.test.ts +101 -0
  181. package/src/ProgressBar/progressValue.ts +87 -0
  182. package/src/SegmentedControl/SegmentedControl.mdx +71 -0
  183. package/src/SegmentedControl/SegmentedControl.stories.tsx +150 -0
  184. package/src/SegmentedControl/SegmentedControl.test.tsx +208 -0
  185. package/src/SegmentedControl/SegmentedControl.tsx +219 -0
  186. package/src/SegmentedControl/SegmentedOption.tsx +94 -0
  187. package/src/Skeleton/Skeleton.mdx +30 -0
  188. package/src/Skeleton/Skeleton.stories.tsx +130 -0
  189. package/src/Skeleton/Skeleton.test.tsx +47 -0
  190. package/src/Skeleton/Skeleton.tsx +106 -0
  191. package/src/Spinner/Spinner.mdx +36 -0
  192. package/src/Spinner/Spinner.stories.tsx +118 -0
  193. package/src/Spinner/Spinner.test.tsx +38 -0
  194. package/src/Spinner/Spinner.tsx +92 -0
  195. package/src/Tabs/TabTrigger.tsx +126 -0
  196. package/src/Tabs/Tabs.mdx +126 -0
  197. package/src/Tabs/Tabs.stories.tsx +187 -0
  198. package/src/Tabs/Tabs.test.tsx +283 -0
  199. package/src/Tabs/Tabs.tsx +333 -0
  200. package/src/VisuallyHidden/VisuallyHidden.mdx +29 -0
  201. package/src/VisuallyHidden/VisuallyHidden.stories.tsx +58 -0
  202. package/src/VisuallyHidden/VisuallyHidden.test.tsx +31 -0
  203. package/src/VisuallyHidden/VisuallyHidden.tsx +43 -0
  204. package/src/argTypes.storyHelpers.ts +115 -0
  205. package/src/board.storyHelpers.tsx +150 -0
  206. package/src/controlStyles.ts +79 -0
  207. package/src/expectNoAxeViolations.testHelpers.ts +41 -0
  208. package/src/icons.storyHelpers.tsx +116 -0
  209. package/src/index.ts +132 -0
  210. package/src/intentStyles.ts +207 -0
  211. package/src/mdxReferences.test.ts +95 -0
  212. package/src/mountStory.testHelpers.ts +41 -0
  213. package/src/sourceRules.test.ts +303 -0
  214. package/src/statusIntent.test.ts +136 -0
  215. package/src/statusIntent.ts +137 -0
  216. package/src/storyControls.test.ts +128 -0
  217. package/src/styles.css +130 -0
  218. package/src/tailwindCandidates.test.ts +377 -0
  219. package/src/testing/expectAgentDrivable.test.tsx +71 -0
  220. package/src/testing/expectAgentDrivable.ts +273 -0
  221. package/src/testing/index.ts +17 -0
  222. package/src/toClassName.ts +13 -0
  223. package/src/tokens.ts +16 -0
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CONTROL_SIZE_CLASS, ICON_CONTROL_SIZE_CLASS, } from "../controlStyles.js";
3
+ import { DISABLED_CLASS, FOCUS_RING_CLASS, INTENT_APPEARANCE_CLASS, INTENT_HOVER_CLASS, } from "../intentStyles.js";
4
+ import { Spinner } from "../Spinner/Spinner.js";
5
+ import { toClassName } from "../toClassName.js";
6
+ /**
7
+ * Hand-rolled in **seven repos**, each with its own
8
+ * primary/secondary/danger/ghost, and this is the component that
9
+ * erases the most duplication in the fleet.
10
+ *
11
+ * Four decisions worth knowing, all of them fixing something an
12
+ * inventoried repo gets wrong:
13
+ *
14
+ * - **`type="button"` by default.** A `<button>` inside a form
15
+ * submits it unless told otherwise, and "clicking the copy icon
16
+ * reloaded the page" is a bug every app in the fleet has shipped
17
+ * at least once.
18
+ * - **`isLoading` disables and announces.** The button goes
19
+ * `aria-busy`, the spinner replaces `iconStart` rather than
20
+ * being appended (so the label does not jump), and the label
21
+ * itself stays — a spinner that swallows the text leaves the
22
+ * user unsure what they pressed.
23
+ * - **`focus-visible`, never `focus`.** See `FOCUS_RING_CLASS`.
24
+ * - **Sizing comes from the density axis**, not from a prop table:
25
+ * `size="md"` is 2.25rem on a desktop and 3.25rem on the kiosk,
26
+ * with no prop change. `MIN_TOUCH_TARGET_CLASS` is available for
27
+ * a control that must clear 44px regardless.
28
+ *
29
+ * The accessible name is the children. `IconButton` exists because
30
+ * a glyph is not a name, and enforcing that in *this* component's
31
+ * types would mean rejecting `<Button>{icon} Copy</Button>`, which
32
+ * is fine.
33
+ */
34
+ export const Button = ({ appearance = "solid", children, className, iconEnd, iconStart, intent = "accent", isDisabled = false, isFullWidth = false, isLoading = false, loadingLabel = "Loading…", size = "md", sizing = "control", type = "button", ...buttonProps }) => (_jsxs("button", { ...buttonProps, "aria-busy": isLoading || undefined, className: toClassName("inline-flex cursor-pointer items-center justify-center rounded-md border font-medium whitespace-nowrap transition-colors duration-(--duration-fast) ease-standard select-none", sizing === "icon"
35
+ ? ICON_CONTROL_SIZE_CLASS[size]
36
+ : CONTROL_SIZE_CLASS[size], INTENT_APPEARANCE_CLASS[intent][appearance], INTENT_HOVER_CLASS[intent][appearance], FOCUS_RING_CLASS, DISABLED_CLASS, isFullWidth && "w-full", className), disabled: isDisabled || isLoading, type: type, children: [isLoading ? (_jsx(Spinner, { label: loadingLabel, size: size })) : (iconStart), children, iconEnd] }));
37
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/Button/Button.tsx"],"names":[],"mappings":";AASA,OAAO,EACL,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAwB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AA+B/C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EACrB,UAAU,GAAG,OAAO,EACpB,QAAQ,EACR,SAAS,EACT,OAAO,EACP,SAAS,EACT,MAAM,GAAG,QAAQ,EACjB,UAAU,GAAG,KAAK,EAClB,WAAW,GAAG,KAAK,EACnB,SAAS,GAAG,KAAK,EACjB,YAAY,GAAG,UAAU,EACzB,IAAI,GAAG,IAAI,EACX,MAAM,GAAG,SAAS,EAClB,IAAI,GAAG,QAAQ,EACf,GAAG,WAAW,EACF,EAAa,EAAE,CAAC,CAC5B,qBACM,WAAW,eACJ,SAAS,IAAI,SAAS,EACjC,SAAS,EAAE,WAAW,CACpB,+KAA+K,EAC/K,MAAM,KAAK,MAAM;QACf,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC;QAC/B,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAC5B,uBAAuB,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EAC3C,kBAAkB,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,EACtC,gBAAgB,EAChB,cAAc,EACd,WAAW,IAAI,QAAQ,EACvB,SAAS,CACV,EACD,QAAQ,EAAE,UAAU,IAAI,SAAS,EACjC,IAAI,EAAE,IAAI,aAET,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,OAAO,IAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAI,CAC7C,CAAC,CAAC,CAAC,CACF,SAAS,CACV,EAEA,QAAQ,EAER,OAAO,IACD,CACV,CAAA"}
@@ -0,0 +1,44 @@
1
+ import type { ElevationStep, SurfaceRole } from "@charcuterie/tokens";
2
+ import type { ComponentPropsWithRef, ReactNode } from "react";
3
+ export type CardSurface = Extract<SurfaceRole, "base" | "raised" | "sunken">;
4
+ export type CardPadding = "lg" | "md" | "none" | "sm";
5
+ export type CardProps = ComponentPropsWithRef<"section"> & {
6
+ /** Buttons or a badge, laid out beside the heading. */
7
+ actions?: ReactNode;
8
+ elevation?: ElevationStep;
9
+ footer?: ReactNode;
10
+ heading?: string;
11
+ headingLevel?: 2 | 3 | 4;
12
+ padding?: CardPadding;
13
+ surface?: CardSurface;
14
+ };
15
+ /**
16
+ * Exported only so the story can derive its `elevation` control from
17
+ * the same map the component indexes — `ElevationStep` comes from
18
+ * `@charcuterie/tokens`, which react-docgen will not follow, so the
19
+ * options have to be stated and this is the one statement of them
20
+ * that cannot drift.
21
+ */
22
+ export declare const ELEVATION_CLASS: Record<ElevationStep, string>;
23
+ /**
24
+ * Five repos, and the reason this is a P0 rather than a nicety is
25
+ * the `<section>`: give a card a heading and it becomes a landmark,
26
+ * so `getByRole("region", { name: "Bay 3" })` scopes every
27
+ * subsequent query to that card. Without it, an agent driving a
28
+ * 16-bay tower has sixteen identical "Start" buttons and no way to
29
+ * say which one it means.
30
+ *
31
+ * `aria-labelledby` rather than `aria-label`, because the heading is
32
+ * on screen already and stating the name twice is how the two drift
33
+ * apart.
34
+ *
35
+ * **Density is not a prop here.** mux-magic's inventory turned up a
36
+ * `CardDensityProvider` in the withdrawn bambuddy evidence, and it
37
+ * is the wrong shape for this fleet: density is a global axis on
38
+ * `<html>`, so a compact bay list is `data-density="compact"` on the
39
+ * page, not a context around the cards. `padding` remains a prop
40
+ * because a card wrapping a poster grid genuinely has none, which is
41
+ * a layout fact rather than a density one.
42
+ */
43
+ export declare const Card: ({ actions, children, className, elevation, footer, heading, headingLevel, padding, surface, ...sectionProps }: CardProps) => ReactNode;
44
+ //# sourceMappingURL=Card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/Card/Card.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACZ,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EACV,qBAAqB,EACrB,SAAS,EACV,MAAM,OAAO,CAAA;AAId,MAAM,MAAM,WAAW,GAAG,OAAO,CAC/B,WAAW,EACX,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAC7B,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAAA;AAErD,MAAM,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,CAAC,GAAG;IACzD,uDAAuD;IACvD,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,aAAa,CAAA;IACzB,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,OAAO,CAAC,EAAE,WAAW,CAAA;CACtB,CAAA;AAQD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAClC,aAAa,EACb,MAAM,CAMP,CAAA;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,IAAI,GAAI,+GAWlB,SAAS,KAAG,SAkDd,CAAA"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useUniqueId } from "@charcuterie/logic";
3
+ import { toClassName } from "../toClassName.js";
4
+ const SURFACE_CLASS = {
5
+ base: "bg-surface-base",
6
+ raised: "bg-surface-raised",
7
+ sunken: "bg-surface-sunken",
8
+ };
9
+ /**
10
+ * Exported only so the story can derive its `elevation` control from
11
+ * the same map the component indexes — `ElevationStep` comes from
12
+ * `@charcuterie/tokens`, which react-docgen will not follow, so the
13
+ * options have to be stated and this is the one statement of them
14
+ * that cannot drift.
15
+ */
16
+ export const ELEVATION_CLASS = {
17
+ none: "shadow-none",
18
+ low: "shadow-low",
19
+ medium: "shadow-medium",
20
+ high: "shadow-high",
21
+ };
22
+ const PADDING_CLASS = {
23
+ none: "p-0",
24
+ sm: "p-3",
25
+ md: "p-4",
26
+ lg: "p-6",
27
+ };
28
+ /**
29
+ * Five repos, and the reason this is a P0 rather than a nicety is
30
+ * the `<section>`: give a card a heading and it becomes a landmark,
31
+ * so `getByRole("region", { name: "Bay 3" })` scopes every
32
+ * subsequent query to that card. Without it, an agent driving a
33
+ * 16-bay tower has sixteen identical "Start" buttons and no way to
34
+ * say which one it means.
35
+ *
36
+ * `aria-labelledby` rather than `aria-label`, because the heading is
37
+ * on screen already and stating the name twice is how the two drift
38
+ * apart.
39
+ *
40
+ * **Density is not a prop here.** mux-magic's inventory turned up a
41
+ * `CardDensityProvider` in the withdrawn bambuddy evidence, and it
42
+ * is the wrong shape for this fleet: density is a global axis on
43
+ * `<html>`, so a compact bay list is `data-density="compact"` on the
44
+ * page, not a context around the cards. `padding` remains a prop
45
+ * because a card wrapping a poster grid genuinely has none, which is
46
+ * a layout fact rather than a density one.
47
+ */
48
+ export const Card = ({ actions, children, className, elevation = "low", footer, heading, headingLevel = 2, padding = "md", surface = "raised", ...sectionProps }) => {
49
+ const headingId = useUniqueId();
50
+ const Heading = `h${headingLevel}`;
51
+ return (_jsxs("section", { ...sectionProps, "aria-labelledby": heading ? headingId : undefined, className: toClassName(
52
+ // `@container` here, not on a wrapper, is what lets the
53
+ // header stack at narrow widths *inside a wide viewport* —
54
+ // a card in a sidebar and the same card full-bleed are the
55
+ // case a media query cannot tell apart, and the fleet's
56
+ // poster grids get it wrong at intermediate widths today.
57
+ "@container flex flex-col gap-3 rounded-lg border border-border-subtle text-content-primary", SURFACE_CLASS[surface], ELEVATION_CLASS[elevation], PADDING_CLASS[padding], className), children: [heading || actions ? (_jsxs("header", { className: "flex flex-col gap-2 cq-sm:flex-row cq-sm:items-start cq-sm:justify-between", children: [heading ? (_jsx(Heading, { className: "font-semibold text-md leading-tight", id: headingId, children: heading })) : null, actions ? (_jsx("div", { className: "flex shrink-0 items-center gap-1", children: actions })) : null] })) : null, children, footer ? (_jsx("footer", { className: "border-t border-border-subtle pt-3 text-content-secondary text-sm", children: footer })) : null] }));
58
+ };
59
+ //# sourceMappingURL=Card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/Card/Card.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAUhD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAoB/C,MAAM,aAAa,GAAgC;IACjD,IAAI,EAAE,iBAAiB;IACvB,MAAM,EAAE,mBAAmB;IAC3B,MAAM,EAAE,mBAAmB;CAC5B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAGxB;IACF,IAAI,EAAE,aAAa;IACnB,GAAG,EAAE,YAAY;IACjB,MAAM,EAAE,eAAe;IACvB,IAAI,EAAE,aAAa;CACpB,CAAA;AAED,MAAM,aAAa,GAAgC;IACjD,IAAI,EAAE,KAAK;IACX,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;IACT,EAAE,EAAE,KAAK;CACV,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,OAAO,EACP,QAAQ,EACR,SAAS,EACT,SAAS,GAAG,KAAK,EACjB,MAAM,EACN,OAAO,EACP,YAAY,GAAG,CAAC,EAChB,OAAO,GAAG,IAAI,EACd,OAAO,GAAG,QAAQ,EAClB,GAAG,YAAY,EACL,EAAa,EAAE;IACzB,MAAM,SAAS,GAAG,WAAW,EAAE,CAAA;IAE/B,MAAM,OAAO,GAAG,IAAI,YAAY,EAAW,CAAA;IAE3C,OAAO,CACL,sBACM,YAAY,qBACC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAChD,SAAS,EAAE,WAAW;QACpB,wDAAwD;QACxD,2DAA2D;QAC3D,2DAA2D;QAC3D,wDAAwD;QACxD,0DAA0D;QAC1D,4FAA4F,EAC5F,aAAa,CAAC,OAAO,CAAC,EACtB,eAAe,CAAC,SAAS,CAAC,EAC1B,aAAa,CAAC,OAAO,CAAC,EACtB,SAAS,CACV,aAEA,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,CACpB,kBAAQ,SAAS,EAAC,4EAA4E,aAC3F,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,OAAO,IACN,SAAS,EAAC,qCAAqC,EAC/C,EAAE,EAAE,SAAS,YAEZ,OAAO,GACA,CACX,CAAC,CAAC,CAAC,IAAI,EAEP,OAAO,CAAC,CAAC,CAAC,CACT,cAAK,SAAS,EAAC,kCAAkC,YAC9C,OAAO,GACJ,CACP,CAAC,CAAC,CAAC,IAAI,IACD,CACV,CAAC,CAAC,CAAC,IAAI,EAEP,QAAQ,EAER,MAAM,CAAC,CAAC,CAAC,CACR,iBAAQ,SAAS,EAAC,mEAAmE,YAClF,MAAM,GACA,CACV,CAAC,CAAC,CAAC,IAAI,IACA,CACX,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,42 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from "react";
2
+ export type EmptyStateSize = "md" | "sm";
3
+ export type EmptyStateProps = Omit<ComponentPropsWithRef<"div">, "children"> & {
4
+ /** Buttons, usually. Rendered under the description. */
5
+ action?: ReactNode;
6
+ description?: ReactNode;
7
+ /**
8
+ * A real heading element, and the level is the caller's because
9
+ * only the caller knows what it sits under. Getting this wrong
10
+ * breaks a screen reader's document outline, which is how the
11
+ * fleet's `<h2>`-with-a-`<button>`-inside pattern happened.
12
+ */
13
+ headingLevel?: 2 | 3 | 4;
14
+ heading: string;
15
+ icon?: ReactNode;
16
+ size?: EmptyStateSize;
17
+ };
18
+ /**
19
+ * **Six repos, eleven-plus copies** — plex-channels alone has five
20
+ * `li.empty`s and castkit six `.idle`s — and not one of them is a
21
+ * component. Every copy is a bare string in a `<div>`, so "no
22
+ * results" and "not started yet" and "the socket died" all look
23
+ * identical, and none of them is findable by role.
24
+ *
25
+ * Designed fresh rather than ported: the two repos that had a real
26
+ * `EmptyState` with typed variants were bambuddy and spoolbuddy,
27
+ * which are upstream projects rather than Kevin's code, so that
28
+ * evidence was withdrawn from the plan.
29
+ *
30
+ * The shape is deliberately flat — icon, heading, description,
31
+ * action — with **no variant enum**. An "empty" and an "error" empty
32
+ * state differ in wording and in whether there is a retry button,
33
+ * both of which are props already; a `variant="error"` that only
34
+ * changes a colour invites callers to encode meaning in the colour
35
+ * alone, which is the one thing a colour cannot carry.
36
+ *
37
+ * The heading is what makes it agent-drivable:
38
+ * `getByRole("heading", { name: "No discs queued" })` works, where
39
+ * `getByText` against eleven copies of "Nothing here" does not.
40
+ */
41
+ export declare const EmptyState: ({ action, className, description, heading, headingLevel, icon, size, ...divProps }: EmptyStateProps) => ReactNode;
42
+ //# sourceMappingURL=EmptyState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.d.ts","sourceRoot":"","sources":["../../src/EmptyState/EmptyState.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,SAAS,EACV,MAAM,OAAO,CAAA;AAId,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAA;AAExC,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,qBAAqB,CAAC,KAAK,CAAC,EAC5B,UAAU,CACX,GAAG;IACF,wDAAwD;IACxD,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,IAAI,CAAC,EAAE,cAAc,CAAA;CACtB,CAAA;AAUD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,GAAI,oFASxB,eAAe,KAAG,SA6CpB,CAAA"}
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { toClassName } from "../toClassName.js";
3
+ const SIZE_CLASS = {
4
+ sm: "gap-2 px-4 py-6 text-sm",
5
+ // An empty state in a 300px panel and the same one filling a
6
+ // dashboard want different air. Container-relative, so it is the
7
+ // *panel* that decides rather than the window.
8
+ md: "gap-3 px-6 py-10 text-md cq-md:gap-4 cq-md:px-8 cq-md:py-14",
9
+ };
10
+ /**
11
+ * **Six repos, eleven-plus copies** — plex-channels alone has five
12
+ * `li.empty`s and castkit six `.idle`s — and not one of them is a
13
+ * component. Every copy is a bare string in a `<div>`, so "no
14
+ * results" and "not started yet" and "the socket died" all look
15
+ * identical, and none of them is findable by role.
16
+ *
17
+ * Designed fresh rather than ported: the two repos that had a real
18
+ * `EmptyState` with typed variants were bambuddy and spoolbuddy,
19
+ * which are upstream projects rather than Kevin's code, so that
20
+ * evidence was withdrawn from the plan.
21
+ *
22
+ * The shape is deliberately flat — icon, heading, description,
23
+ * action — with **no variant enum**. An "empty" and an "error" empty
24
+ * state differ in wording and in whether there is a retry button,
25
+ * both of which are props already; a `variant="error"` that only
26
+ * changes a colour invites callers to encode meaning in the colour
27
+ * alone, which is the one thing a colour cannot carry.
28
+ *
29
+ * The heading is what makes it agent-drivable:
30
+ * `getByRole("heading", { name: "No discs queued" })` works, where
31
+ * `getByText` against eleven copies of "Nothing here" does not.
32
+ */
33
+ export const EmptyState = ({ action, className, description, heading, headingLevel = 2, icon, size = "md", ...divProps }) => {
34
+ const Heading = `h${headingLevel}`;
35
+ return (_jsx("div", { ...divProps, className: toClassName("@container", className), children: _jsxs("div", { className: toClassName("flex flex-col items-center justify-center text-center", SIZE_CLASS[size]), children: [icon ? (_jsx("span", { "aria-hidden": "true", className: "text-content-muted", children: icon })) : null, _jsx(Heading, { className: "font-semibold text-content-primary", children: heading }), description ? (_jsx("p", { className: "max-w-prose text-content-secondary", children: description })) : null, action ? (_jsx("div", { className: "mt-1", children: action })) : null] }) }));
36
+ };
37
+ //# sourceMappingURL=EmptyState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../../src/EmptyState/EmptyState.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAuB/C,MAAM,UAAU,GAAmC;IACjD,EAAE,EAAE,yBAAyB;IAC7B,6DAA6D;IAC7D,iEAAiE;IACjE,+CAA+C;IAC/C,EAAE,EAAE,6DAA6D;CAClE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,MAAM,EACN,SAAS,EACT,WAAW,EACX,OAAO,EACP,YAAY,GAAG,CAAC,EAChB,IAAI,EACJ,IAAI,GAAG,IAAI,EACX,GAAG,QAAQ,EACK,EAAa,EAAE;IAC/B,MAAM,OAAO,GAAG,IAAI,YAAY,EAAW,CAAA;IAE3C,OAAO,CACL,iBACM,QAAQ,EACZ,SAAS,EAAE,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,YAQ/C,eACE,SAAS,EAAE,WAAW,CACpB,uDAAuD,EACvD,UAAU,CAAC,IAAI,CAAC,CACjB,aAEA,IAAI,CAAC,CAAC,CAAC,CACN,8BACc,MAAM,EAClB,SAAS,EAAC,oBAAoB,YAE7B,IAAI,GACA,CACR,CAAC,CAAC,CAAC,IAAI,EAER,KAAC,OAAO,IAAC,SAAS,EAAC,oCAAoC,YACpD,OAAO,GACA,EAET,WAAW,CAAC,CAAC,CAAC,CACb,YAAG,SAAS,EAAC,oCAAoC,YAC9C,WAAW,GACV,CACL,CAAC,CAAC,CAAC,IAAI,EAEP,MAAM,CAAC,CAAC,CAAC,CACR,cAAK,SAAS,EAAC,MAAM,YAAE,MAAM,GAAO,CACrC,CAAC,CAAC,CAAC,IAAI,IACJ,GACF,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ButtonProps } from "../Button/Button.tsx";
3
+ export type IconButtonProps = Omit<ButtonProps, "aria-label" | "children" | "iconEnd" | "iconStart" | "sizing"> & {
4
+ /**
5
+ * Required, and this single line is most of the component's
6
+ * reason to exist. `label` cannot be defaulted, cannot be
7
+ * omitted, and is not a `ReactNode` — it becomes `aria-label`,
8
+ * which is a string by specification.
9
+ */
10
+ label: string;
11
+ /** The glyph. Anything — lucide, an inline SVG, a character. */
12
+ children: ReactNode;
13
+ };
14
+ /**
15
+ * Three repos, three strategies, and **none of them names the
16
+ * button**: mux-magic hand-writes five SVG components, castkit
17
+ * keeps an `ICON_PATHS` map, and plex-channels renders raw glyphs
18
+ * (`↶`, `↷`, `▶`, `⚙`, `≡`) straight into a `<button>`. A screen
19
+ * reader reads the last of those as "↶", and
20
+ * `getByRole("button", { name: "Undo" })` finds nothing at all —
21
+ * which is the concrete reason the fleet is not agent-drivable
22
+ * today.
23
+ *
24
+ * So the type system asks for the name. There is no way to render
25
+ * this component without one, and `expectAgentDrivable` in the
26
+ * story proves the name is the one Playwright will match on.
27
+ *
28
+ * **No icons ship here.** The library does not own an icon set —
29
+ * lucide (ISC) is the fleet recommendation — so `children` is
30
+ * whatever the app already has, and the icon is `aria-hidden` by
31
+ * virtue of the `aria-label` overriding the subtree name.
32
+ */
33
+ export declare const IconButton: ({ children, label, ...buttonProps }: IconButtonProps) => ReactNode;
34
+ //# sourceMappingURL=IconButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IconButton.d.ts","sourceRoot":"","sources":["../../src/IconButton/IconButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,WAAW,EACT,YAAY,GACZ,UAAU,GACV,SAAS,GACT,WAAW,GACX,QAAQ,CACX,GAAG;IACF;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,GAAI,qCAIxB,eAAe,KAAG,SAMpB,CAAA"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Button } from "../Button/Button.js";
3
+ /**
4
+ * Three repos, three strategies, and **none of them names the
5
+ * button**: mux-magic hand-writes five SVG components, castkit
6
+ * keeps an `ICON_PATHS` map, and plex-channels renders raw glyphs
7
+ * (`↶`, `↷`, `▶`, `⚙`, `≡`) straight into a `<button>`. A screen
8
+ * reader reads the last of those as "↶", and
9
+ * `getByRole("button", { name: "Undo" })` finds nothing at all —
10
+ * which is the concrete reason the fleet is not agent-drivable
11
+ * today.
12
+ *
13
+ * So the type system asks for the name. There is no way to render
14
+ * this component without one, and `expectAgentDrivable` in the
15
+ * story proves the name is the one Playwright will match on.
16
+ *
17
+ * **No icons ship here.** The library does not own an icon set —
18
+ * lucide (ISC) is the fleet recommendation — so `children` is
19
+ * whatever the app already has, and the icon is `aria-hidden` by
20
+ * virtue of the `aria-label` overriding the subtree name.
21
+ */
22
+ export const IconButton = ({ children, label, ...buttonProps }) => (_jsx(Button, { ...buttonProps, "aria-label": label, sizing: "icon", children: _jsx("span", { "aria-hidden": "true", className: "contents", children: children }) }));
23
+ //# sourceMappingURL=IconButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IconButton.js","sourceRoot":"","sources":["../../src/IconButton/IconButton.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAsB,CAAA;AAqB7C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,QAAQ,EACR,KAAK,EACL,GAAG,WAAW,EACE,EAAa,EAAE,CAAC,CAChC,KAAC,MAAM,OAAK,WAAW,gBAAc,KAAK,EAAE,MAAM,EAAC,MAAM,YACvD,8BAAkB,MAAM,EAAC,SAAS,EAAC,UAAU,YAC1C,QAAQ,GACJ,GACA,CACV,CAAA"}
@@ -0,0 +1,37 @@
1
+ import type { ConnectionStatus } from "@charcuterie/logic";
2
+ import type { ComponentPropsWithRef, ReactNode } from "react";
3
+ import { DOT_SIZE_CLASS } from "../controlStyles.ts";
4
+ export type LiveStatusIndicatorSize = keyof typeof DOT_SIZE_CLASS;
5
+ export type LiveStatusIndicatorProps = Omit<ComponentPropsWithRef<"span">, "children"> & {
6
+ /** Extra context, announced after the label. "3 of 4 bays." */
7
+ detail?: string;
8
+ isLabelVisible?: boolean;
9
+ /** Overrides the machine's own wording. Rarely wanted. */
10
+ label?: string;
11
+ size?: LiveStatusIndicatorSize;
12
+ status: ConnectionStatus;
13
+ };
14
+ /**
15
+ * Four repos, four different implementations, and **it is the thing
16
+ * users read most** — a wall-mounted panel showing stale data with a
17
+ * green dot is worse than one showing nothing.
18
+ *
19
+ * The second reason it is P0: all four collapse `connecting` and
20
+ * `reconnecting` into one state, which reads wrong on exactly the
21
+ * link that needs it. A user who has seen data wants "lost it,
22
+ * getting it back" (amber, moving), not the cold-start spinner they
23
+ * already sat through (blue) and not a dead link (red). That
24
+ * distinction is why `connectionTransitions` is one of the two
25
+ * machines `@charcuterie/logic` ships rather than something each app
26
+ * defines, and `getConnectionIntent` / `getConnectionLabel` are
27
+ * exhaustive switches over it — add a fifth state and this component
28
+ * stops compiling instead of rendering a grey dot.
29
+ *
30
+ * `role="status"` + `aria-live="polite"` on the wrapper, so a
31
+ * transition is announced without interrupting whatever the user is
32
+ * doing. `aria-live="assertive"` would be wrong here even for
33
+ * `disconnected`: it cuts off the sentence in progress, and the dot
34
+ * is not going anywhere.
35
+ */
36
+ export declare const LiveStatusIndicator: ({ className, detail, isLabelVisible, label, size, status, ...spanProps }: LiveStatusIndicatorProps) => ReactNode;
37
+ //# sourceMappingURL=LiveStatusIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveStatusIndicator.d.ts","sourceRoot":"","sources":["../../src/LiveStatusIndicator/LiveStatusIndicator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,KAAK,EACV,qBAAqB,EACrB,SAAS,EACV,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAapD,MAAM,MAAM,uBAAuB,GACjC,MAAM,OAAO,cAAc,CAAA;AAE7B,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,qBAAqB,CAAC,MAAM,CAAC,EAC7B,UAAU,CACX,GAAG;IACF,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,uBAAuB,CAAA;IAC9B,MAAM,EAAE,gBAAgB,CAAA;CACzB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,mBAAmB,GAAI,0EAQjC,wBAAwB,KAAG,SAkD7B,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DOT_SIZE_CLASS } from "../controlStyles.js";
3
+ import { INTENT_CONTENT_CLASS, INTENT_SOLID_FILL_CLASS, } from "../intentStyles.js";
4
+ import { getConnectionIntent, getConnectionLabel, getIsConnectionBusy, } from "../statusIntent.js";
5
+ import { toClassName } from "../toClassName.js";
6
+ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
7
+ /**
8
+ * Four repos, four different implementations, and **it is the thing
9
+ * users read most** — a wall-mounted panel showing stale data with a
10
+ * green dot is worse than one showing nothing.
11
+ *
12
+ * The second reason it is P0: all four collapse `connecting` and
13
+ * `reconnecting` into one state, which reads wrong on exactly the
14
+ * link that needs it. A user who has seen data wants "lost it,
15
+ * getting it back" (amber, moving), not the cold-start spinner they
16
+ * already sat through (blue) and not a dead link (red). That
17
+ * distinction is why `connectionTransitions` is one of the two
18
+ * machines `@charcuterie/logic` ships rather than something each app
19
+ * defines, and `getConnectionIntent` / `getConnectionLabel` are
20
+ * exhaustive switches over it — add a fifth state and this component
21
+ * stops compiling instead of rendering a grey dot.
22
+ *
23
+ * `role="status"` + `aria-live="polite"` on the wrapper, so a
24
+ * transition is announced without interrupting whatever the user is
25
+ * doing. `aria-live="assertive"` would be wrong here even for
26
+ * `disconnected`: it cuts off the sentence in progress, and the dot
27
+ * is not going anywhere.
28
+ */
29
+ export const LiveStatusIndicator = ({ className, detail, isLabelVisible = true, label, size = "md", status, ...spanProps }) => {
30
+ const intent = getConnectionIntent(status);
31
+ const statusLabel = label ?? getConnectionLabel(status);
32
+ return (_jsxs("span", { ...spanProps, "aria-label": statusLabel, "aria-live": "polite", className: toClassName("inline-flex items-center gap-2 text-sm", INTENT_CONTENT_CLASS[intent], className), role: "status", "data-status": status, children: [_jsx("span", { "aria-hidden": "true", className: toClassName("inline-block shrink-0 rounded-full", DOT_SIZE_CLASS[size], INTENT_SOLID_FILL_CLASS[intent],
33
+ // Only the two in-flight states move. A pulsing dot that
34
+ // never stops is the fleet's current "is it alive?"
35
+ // problem in a new costume.
36
+ getIsConnectionBusy(status) &&
37
+ "charcuterie-pulse") }), isLabelVisible ? (_jsx("span", { children: statusLabel })) : (_jsx(VisuallyHidden, { children: statusLabel })), detail ? (_jsx("span", { className: "text-content-muted", children: detail })) : null] }));
38
+ };
39
+ //# sourceMappingURL=LiveStatusIndicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveStatusIndicator.js","sourceRoot":"","sources":["../../src/LiveStatusIndicator/LiveStatusIndicator.tsx"],"names":[],"mappings":";AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAsC,CAAA;AAkBrE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,SAAS,EACT,MAAM,EACN,cAAc,GAAG,IAAI,EACrB,KAAK,EACL,IAAI,GAAG,IAAI,EACX,MAAM,EACN,GAAG,SAAS,EACa,EAAa,EAAE;IACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;IAE1C,MAAM,WAAW,GAAG,KAAK,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAEvD,OAAO,CACL,mBACM,SAAS,gBAKD,WAAW,eACb,QAAQ,EAClB,SAAS,EAAE,WAAW,CACpB,wCAAwC,EACxC,oBAAoB,CAAC,MAAM,CAAC,EAC5B,SAAS,CACV,EACD,IAAI,EAAC,QAAQ,iBAIA,MAAM,aAEnB,8BACc,MAAM,EAClB,SAAS,EAAE,WAAW,CACpB,oCAAoC,EACpC,cAAc,CAAC,IAAI,CAAC,EACpB,uBAAuB,CAAC,MAAM,CAAC;gBAC/B,yDAAyD;gBACzD,oDAAoD;gBACpD,4BAA4B;gBAC5B,mBAAmB,CAAC,MAAM,CAAC;oBACzB,mBAAmB,CACtB,GACD,EAED,cAAc,CAAC,CAAC,CAAC,CAChB,yBAAO,WAAW,GAAQ,CAC3B,CAAC,CAAC,CAAC,CACF,KAAC,cAAc,cAAE,WAAW,GAAkB,CAC/C,EAEA,MAAM,CAAC,CAAC,CAAC,CACR,eAAM,SAAS,EAAC,oBAAoB,YAAE,MAAM,GAAQ,CACrD,CAAC,CAAC,CAAC,IAAI,IACH,CACR,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,46 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from "react";
2
+ export type MediaTileRatio = "poster" | "square" | "video";
3
+ export type MediaTileProps = Omit<ComponentPropsWithRef<"figure">, "children"> & {
4
+ /**
5
+ * Required. The one thing three hand-rolled poster grids all
6
+ * omit — and a 200-tile page of unnamed images is unnavigable
7
+ * rather than merely imperfect.
8
+ */
9
+ alt: string;
10
+ aspectRatio?: MediaTileRatio;
11
+ /** A `Badge`, usually. Pinned inside the media box. */
12
+ badge?: ReactNode;
13
+ /** Shown in place of the image when it fails. */
14
+ fallback?: ReactNode;
15
+ href?: string;
16
+ src?: string;
17
+ subtitle?: ReactNode;
18
+ title: string;
19
+ };
20
+ /**
21
+ * Three repos, and shipping one of these is what makes
22
+ * plex-channels, image-viewer, and gallery-downloader look like one
23
+ * family instead of three.
24
+ *
25
+ * The interesting part is not the layout, it is the three states an
26
+ * image has and the fact that no hand-rolled version models them:
27
+ *
28
+ * - **Loading** shows a `Skeleton` at the tile's exact aspect ratio,
29
+ * so the grid does not reflow when 200 posters land. Layout shift
30
+ * is the thing users notice in these apps today.
31
+ * - **Error** keeps the tile's box and its name. An `<img>` with a
32
+ * broken `src` collapses to a glyph and takes the row's height
33
+ * with it; the fallback here is a `role="img"` carrying the same
34
+ * `alt`, so the tile stays findable and the grid stays a grid.
35
+ * - **Cached** is the case that bites: a `complete` image never
36
+ * fires `load`, so a naive `onLoad`-only implementation leaves a
37
+ * shimmering skeleton over a perfectly rendered poster forever.
38
+ * The effect below checks `complete`/`naturalWidth` on mount and
39
+ * on every `src` change.
40
+ *
41
+ * Those states are a `useStatus` machine rather than a
42
+ * `useState<string>`, which is what makes `loaded → error`
43
+ * impossible instead of merely unlikely — see `mediaStatus.ts`.
44
+ */
45
+ export declare const MediaTile: ({ alt, aspectRatio, badge, className, fallback, href, src, subtitle, title, ...figureProps }: MediaTileProps) => ReactNode;
46
+ //# sourceMappingURL=MediaTile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaTile.d.ts","sourceRoot":"","sources":["../../src/MediaTile/MediaTile.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,SAAS,EACV,MAAM,OAAO,CAAA;AAOd,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE1D,MAAM,MAAM,cAAc,GAAG,IAAI,CAC/B,qBAAqB,CAAC,QAAQ,CAAC,EAC/B,UAAU,CACX,GAAG;IACF;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,cAAc,CAAA;IAC5B,uDAAuD;IACvD,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAUD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,SAAS,GAAI,8FAWvB,cAAc,KAAG,SAoJnB,CAAA"}
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useStatus } from "@charcuterie/logic";
3
+ import { useEffect, useRef } from "react";
4
+ import { Skeleton } from "../Skeleton/Skeleton.js";
5
+ import { toClassName } from "../toClassName.js";
6
+ import { mediaTransitions } from "./mediaStatus.js";
7
+ const RATIO_CLASS = {
8
+ // 2:3 is the standard poster trim, which is what Plex, Kavita, and
9
+ // every physical sleeve in the collection actually are.
10
+ poster: "aspect-[2/3]",
11
+ square: "aspect-square",
12
+ video: "aspect-video",
13
+ };
14
+ /**
15
+ * Three repos, and shipping one of these is what makes
16
+ * plex-channels, image-viewer, and gallery-downloader look like one
17
+ * family instead of three.
18
+ *
19
+ * The interesting part is not the layout, it is the three states an
20
+ * image has and the fact that no hand-rolled version models them:
21
+ *
22
+ * - **Loading** shows a `Skeleton` at the tile's exact aspect ratio,
23
+ * so the grid does not reflow when 200 posters land. Layout shift
24
+ * is the thing users notice in these apps today.
25
+ * - **Error** keeps the tile's box and its name. An `<img>` with a
26
+ * broken `src` collapses to a glyph and takes the row's height
27
+ * with it; the fallback here is a `role="img"` carrying the same
28
+ * `alt`, so the tile stays findable and the grid stays a grid.
29
+ * - **Cached** is the case that bites: a `complete` image never
30
+ * fires `load`, so a naive `onLoad`-only implementation leaves a
31
+ * shimmering skeleton over a perfectly rendered poster forever.
32
+ * The effect below checks `complete`/`naturalWidth` on mount and
33
+ * on every `src` change.
34
+ *
35
+ * Those states are a `useStatus` machine rather than a
36
+ * `useState<string>`, which is what makes `loaded → error`
37
+ * impossible instead of merely unlikely — see `mediaStatus.ts`.
38
+ */
39
+ export const MediaTile = ({ alt, aspectRatio = "poster", badge, className, fallback, href, src, subtitle, title, ...figureProps }) => {
40
+ const imageRef = useRef(null);
41
+ const { can, reset, status, transitionTo } = useStatus({
42
+ initialState: "loading",
43
+ transitions: mediaTransitions,
44
+ });
45
+ useEffect(() => {
46
+ // A new `src` is a new load, including after a failure.
47
+ reset();
48
+ const image = imageRef.current;
49
+ if (!image?.complete) {
50
+ return;
51
+ }
52
+ // `complete` with no intrinsic width is a *failed* cached
53
+ // load, not a successful one — the distinction browsers only
54
+ // expose this way.
55
+ if (image.naturalWidth > 0) {
56
+ if (can("loaded")) {
57
+ transitionTo("loaded");
58
+ }
59
+ return;
60
+ }
61
+ if (can("error")) {
62
+ transitionTo("error");
63
+ }
64
+ }, [can, reset, transitionTo]);
65
+ const media = (_jsxs("div", { className: toClassName("relative overflow-hidden rounded-md bg-surface-sunken", RATIO_CLASS[aspectRatio]), children: [status === "error" ? (_jsx("div", { "aria-label": alt, className: "flex size-full flex-col items-center justify-center gap-1 p-2 text-center text-content-muted text-xs", role: "img", children: fallback ?? _jsx("span", { children: "Image unavailable" }) })) : (_jsxs(_Fragment, { children: [status === "loading" ? (_jsx(Skeleton, { className: "absolute inset-0 size-full" })) : null, _jsx("img", { alt: href ? "" : alt, className: toClassName("size-full object-cover transition-opacity duration-(--duration-normal) ease-standard", status === "loaded"
66
+ ? "opacity-100"
67
+ : "opacity-0"), decoding: "async", loading: "lazy", onError: () => {
68
+ if (can("error")) {
69
+ transitionTo("error");
70
+ }
71
+ }, onLoad: () => {
72
+ if (can("loaded")) {
73
+ transitionTo("loaded");
74
+ }
75
+ }, ref: imageRef, src: src })] })), badge ? (_jsx("div", { className: "absolute top-2 start-2", children: badge })) : null] }));
76
+ const caption = (_jsxs("figcaption", { className: "flex flex-col gap-0.5 pt-2", children: [_jsx("span", { className: "truncate font-medium text-content-primary text-sm cq-sm:text-md", children: title }), subtitle ? (_jsx("span", { className: "truncate text-content-muted text-xs", children: subtitle })) : null] }));
77
+ return (_jsx("figure", { ...figureProps, className: toClassName("@container flex flex-col", className), children: href ? (_jsxs("a", { "aria-label": title, className: "group flex flex-col rounded-md outline-offset-2 hover:opacity-90 focus-visible:outline-solid focus-visible:outline-(length:--focus-ring-width) focus-visible:outline-focus-ring", href: href, children: [media, caption] })) : (_jsxs(_Fragment, { children: [media, caption] })) }));
78
+ };
79
+ //# sourceMappingURL=MediaTile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaTile.js","sourceRoot":"","sources":["../../src/MediaTile/MediaTile.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { StatusTransitions } from "@charcuterie/logic";
2
+ export type MediaStatus = "error" | "loaded" | "loading";
3
+ /**
4
+ * A component-owned machine, and the smallest honest example of what
5
+ * `createStatus` is for.
6
+ *
7
+ * `@charcuterie/logic` ships only the two machines that are
8
+ * genuinely fleet-wide — connection and async request — precisely so
9
+ * that a machine like this one lives next to the thing it describes.
10
+ * Three states, two of them terminal-ish, and the edges matter:
11
+ *
12
+ * - `loaded → loading` and `error → loading` exist for a changed
13
+ * `src`. Without them a poster grid that repaints with new URLs
14
+ * keeps showing the old tile's error.
15
+ * - `loaded → error` does **not** exist. A browser does not fire
16
+ * `error` on an image it has already decoded, and an app that
17
+ * thinks it saw that is misreading its own event wiring — so the
18
+ * machine throws rather than flickering a fallback over a
19
+ * perfectly good poster.
20
+ */
21
+ export declare const mediaTransitions: StatusTransitions<MediaStatus>;
22
+ //# sourceMappingURL=mediaStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaStatus.d.ts","sourceRoot":"","sources":["../../src/MediaTile/mediaStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE3D,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,CAAC,WAAW,CAKzD,CAAA"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A component-owned machine, and the smallest honest example of what
3
+ * `createStatus` is for.
4
+ *
5
+ * `@charcuterie/logic` ships only the two machines that are
6
+ * genuinely fleet-wide — connection and async request — precisely so
7
+ * that a machine like this one lives next to the thing it describes.
8
+ * Three states, two of them terminal-ish, and the edges matter:
9
+ *
10
+ * - `loaded → loading` and `error → loading` exist for a changed
11
+ * `src`. Without them a poster grid that repaints with new URLs
12
+ * keeps showing the old tile's error.
13
+ * - `loaded → error` does **not** exist. A browser does not fire
14
+ * `error` on an image it has already decoded, and an app that
15
+ * thinks it saw that is misreading its own event wiring — so the
16
+ * machine throws rather than flickering a fallback over a
17
+ * perfectly good poster.
18
+ */
19
+ export const mediaTransitions = {
20
+ error: ["loading"],
21
+ loaded: ["loading"],
22
+ loading: ["error", "loaded"],
23
+ };
24
+ //# sourceMappingURL=mediaStatus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediaStatus.js","sourceRoot":"","sources":["../../src/MediaTile/mediaStatus.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B;IACE,KAAK,EAAE,CAAC,SAAS,CAAC;IAClB,MAAM,EAAE,CAAC,SAAS,CAAC;IACnB,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;CAC7B,CAAA"}