@hackcove/ui-react 0.0.0-stage → 0.8.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 (172) hide show
  1. package/LICENSE +21 -0
  2. package/MIGRATING.md +116 -0
  3. package/README.md +400 -2
  4. package/dist/AppShell.d.ts +97 -0
  5. package/dist/AppShell.js +106 -0
  6. package/dist/Avatar.d.ts +49 -0
  7. package/dist/Avatar.js +65 -0
  8. package/dist/AvatarStack.d.ts +29 -0
  9. package/dist/AvatarStack.js +26 -0
  10. package/dist/Badge.d.ts +14 -0
  11. package/dist/Badge.js +11 -0
  12. package/dist/Breadcrumbs.d.ts +28 -0
  13. package/dist/Breadcrumbs.js +30 -0
  14. package/dist/BulletList.d.ts +4 -0
  15. package/dist/BulletList.js +5 -0
  16. package/dist/Button.d.ts +78 -0
  17. package/dist/Button.js +133 -0
  18. package/dist/ButtonGroup.d.ts +15 -0
  19. package/dist/ButtonGroup.js +10 -0
  20. package/dist/Callout.d.ts +24 -0
  21. package/dist/Callout.js +28 -0
  22. package/dist/Card.d.ts +95 -0
  23. package/dist/Card.js +134 -0
  24. package/dist/CardBadge.d.ts +7 -0
  25. package/dist/CardBadge.js +12 -0
  26. package/dist/CardParts.d.ts +25 -0
  27. package/dist/CardParts.js +25 -0
  28. package/dist/Checkbox.d.ts +29 -0
  29. package/dist/Checkbox.js +36 -0
  30. package/dist/Chevron.d.ts +5 -0
  31. package/dist/Chevron.js +6 -0
  32. package/dist/Cluster.d.ts +51 -0
  33. package/dist/Cluster.js +38 -0
  34. package/dist/Code.d.ts +4 -0
  35. package/dist/Code.js +5 -0
  36. package/dist/CodeBlock.d.ts +27 -0
  37. package/dist/CodeBlock.js +12 -0
  38. package/dist/CodeExample.d.ts +17 -0
  39. package/dist/CodeExample.js +13 -0
  40. package/dist/CodeText.d.ts +7 -0
  41. package/dist/CodeText.js +21 -0
  42. package/dist/ColourSchemeToggle.d.ts +34 -0
  43. package/dist/ColourSchemeToggle.js +50 -0
  44. package/dist/Container.d.ts +22 -0
  45. package/dist/Container.js +13 -0
  46. package/dist/CopyButton.d.ts +17 -0
  47. package/dist/CopyButton.js +13 -0
  48. package/dist/CopyLine.d.ts +9 -0
  49. package/dist/CopyLine.js +7 -0
  50. package/dist/DateCalendar.d.ts +10 -0
  51. package/dist/DateCalendar.js +45 -0
  52. package/dist/DateField.d.ts +87 -0
  53. package/dist/DateField.js +100 -0
  54. package/dist/DateFieldCalendar.d.ts +6 -0
  55. package/dist/DateFieldCalendar.js +35 -0
  56. package/dist/Dialog.d.ts +26 -0
  57. package/dist/Dialog.js +18 -0
  58. package/dist/Disclosure.d.ts +15 -0
  59. package/dist/Disclosure.js +12 -0
  60. package/dist/Divider.d.ts +4 -0
  61. package/dist/Divider.js +5 -0
  62. package/dist/Drawer.d.ts +29 -0
  63. package/dist/Drawer.js +22 -0
  64. package/dist/EmptyState.d.ts +18 -0
  65. package/dist/EmptyState.js +14 -0
  66. package/dist/Field.d.ts +21 -0
  67. package/dist/Field.js +19 -0
  68. package/dist/FieldDialog.d.ts +28 -0
  69. package/dist/FieldDialog.js +34 -0
  70. package/dist/FileDrop.d.ts +17 -0
  71. package/dist/FileDrop.js +12 -0
  72. package/dist/FilterGroup.d.ts +7 -0
  73. package/dist/FilterGroup.js +6 -0
  74. package/dist/FormRow.d.ts +42 -0
  75. package/dist/FormRow.js +33 -0
  76. package/dist/Icon.d.ts +20 -0
  77. package/dist/Icon.js +13 -0
  78. package/dist/IconButton.d.ts +57 -0
  79. package/dist/IconButton.js +51 -0
  80. package/dist/Input.d.ts +22 -0
  81. package/dist/Input.js +22 -0
  82. package/dist/InputShell.d.ts +16 -0
  83. package/dist/InputShell.js +26 -0
  84. package/dist/Kbd.d.ts +6 -0
  85. package/dist/Kbd.js +5 -0
  86. package/dist/KeyValueList.d.ts +23 -0
  87. package/dist/KeyValueList.js +19 -0
  88. package/dist/Lightbox.d.ts +28 -0
  89. package/dist/Lightbox.js +44 -0
  90. package/dist/ListRow.d.ts +109 -0
  91. package/dist/ListRow.js +92 -0
  92. package/dist/Markdown.d.ts +9 -0
  93. package/dist/Markdown.js +43 -0
  94. package/dist/MetaList.d.ts +23 -0
  95. package/dist/MetaList.js +14 -0
  96. package/dist/OutlineRegion.d.ts +43 -0
  97. package/dist/OutlineRegion.js +27 -0
  98. package/dist/PageFade.d.ts +26 -0
  99. package/dist/PageFade.js +39 -0
  100. package/dist/PageHeader.d.ts +24 -0
  101. package/dist/PageHeader.js +14 -0
  102. package/dist/PageLayouts.d.ts +130 -0
  103. package/dist/PageLayouts.js +86 -0
  104. package/dist/Pill.d.ts +53 -0
  105. package/dist/Pill.js +34 -0
  106. package/dist/ProgressBar.d.ts +32 -0
  107. package/dist/ProgressBar.js +32 -0
  108. package/dist/RadioGroup.d.ts +48 -0
  109. package/dist/RadioGroup.js +39 -0
  110. package/dist/SearchInput.d.ts +8 -0
  111. package/dist/SearchInput.js +40 -0
  112. package/dist/SegmentedControl.d.ts +20 -0
  113. package/dist/SegmentedControl.js +31 -0
  114. package/dist/Select.d.ts +5 -0
  115. package/dist/Select.js +9 -0
  116. package/dist/SplitBar.d.ts +27 -0
  117. package/dist/SplitBar.js +15 -0
  118. package/dist/Stack.d.ts +70 -0
  119. package/dist/Stack.js +47 -0
  120. package/dist/StackedBar.d.ts +56 -0
  121. package/dist/StackedBar.js +35 -0
  122. package/dist/StatTile.d.ts +21 -0
  123. package/dist/StatTile.js +22 -0
  124. package/dist/StatusPages.d.ts +38 -0
  125. package/dist/StatusPages.js +57 -0
  126. package/dist/Steps.d.ts +17 -0
  127. package/dist/Steps.js +14 -0
  128. package/dist/StickyBar.d.ts +12 -0
  129. package/dist/StickyBar.js +10 -0
  130. package/dist/Table.d.ts +142 -0
  131. package/dist/Table.js +138 -0
  132. package/dist/Tabs.d.ts +40 -0
  133. package/dist/Tabs.js +49 -0
  134. package/dist/TextLink.d.ts +51 -0
  135. package/dist/TextLink.js +37 -0
  136. package/dist/Textarea.d.ts +12 -0
  137. package/dist/Textarea.js +8 -0
  138. package/dist/Timeline.d.ts +27 -0
  139. package/dist/Timeline.js +29 -0
  140. package/dist/Video.d.ts +13 -0
  141. package/dist/Video.js +9 -0
  142. package/dist/colourScheme.d.ts +21 -0
  143. package/dist/colourScheme.js +53 -0
  144. package/dist/control.d.ts +31 -0
  145. package/dist/control.js +38 -0
  146. package/dist/cx.d.ts +12 -0
  147. package/dist/cx.js +14 -0
  148. package/dist/highlight.d.ts +16 -0
  149. package/dist/highlight.js +292 -0
  150. package/dist/index.d.ts +70 -0
  151. package/dist/index.js +66 -0
  152. package/dist/isoDate.d.ts +5 -0
  153. package/dist/isoDate.js +16 -0
  154. package/dist/lift.harness.d.ts +2 -0
  155. package/dist/lift.harness.js +3 -0
  156. package/dist/link.d.ts +50 -0
  157. package/dist/link.js +25 -0
  158. package/dist/modal.d.ts +11 -0
  159. package/dist/modal.js +41 -0
  160. package/dist/props.d.ts +14 -0
  161. package/dist/props.js +1 -0
  162. package/dist/shownDate.d.ts +45 -0
  163. package/dist/shownDate.js +88 -0
  164. package/dist/size.d.ts +6 -0
  165. package/dist/size.js +1 -0
  166. package/dist/switcher.d.ts +88 -0
  167. package/dist/switcher.js +71 -0
  168. package/dist/typography.d.ts +123 -0
  169. package/dist/typography.js +120 -0
  170. package/dist/ui.d.ts +10 -0
  171. package/dist/ui.js +27 -0
  172. package/package.json +91 -4
@@ -0,0 +1,120 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Children, } from "react";
3
+ import { cx } from "./cx.js";
4
+ /** Colour token → slate/violet utility, which a theme remaps. */
5
+ const COLOR = {
6
+ default: "text-slate-900",
7
+ secondary: "text-slate-600",
8
+ tertiary: "text-slate-500",
9
+ muted: "text-slate-400",
10
+ brand: "text-violet-600",
11
+ };
12
+ /** Tone → text utility. Shared with `Table`'s cell tones, so the two never drift. */
13
+ export const TEXT_TONE = {
14
+ muted: "text-slate-500",
15
+ info: "text-blue-700",
16
+ positive: "text-emerald-700",
17
+ warn: "text-amber-700",
18
+ danger: "text-red-700",
19
+ };
20
+ /**
21
+ * Build a semantic component that pins `variantClass` (size + weight + tracking)
22
+ * and a default colour. The scale/weight for each role therefore lives in exactly
23
+ * one place (the call below), and callers can only vary the colour and the element —
24
+ * never the pinned size/weight, and never with a class.
25
+ */
26
+ function typography(displayName, defaultAs, variantClass, defaultColor) {
27
+ function Typography(props) {
28
+ return pinned(defaultAs, variantClass, defaultColor, props);
29
+ }
30
+ Typography.displayName = displayName;
31
+ return Typography;
32
+ }
33
+ /** `typography` for the inline roles, which also take `tone`, `numeric`, `mono` and `truncate`. */
34
+ function inlineRole(displayName, defaultAs, variantClass, defaultColor) {
35
+ function Inline(props) {
36
+ return pinned(defaultAs, variantClass, defaultColor, props);
37
+ }
38
+ Inline.displayName = displayName;
39
+ return Inline;
40
+ }
41
+ /**
42
+ * The one place a pinned role renders. The few roles with an opt-in prop of their own are
43
+ * written by hand, not by `typography`, and call this too.
44
+ */
45
+ function pinned(defaultAs, variantClass, defaultColor, { as, color, tone, numeric, mono, truncate, children, ...rest }) {
46
+ const Tag = as ?? defaultAs;
47
+ return (_jsx(Tag, { ...rest, ...(truncate ? { title: rest.title ?? plainText(children) } : {}), className: cx(variantClass, tone ? TEXT_TONE[tone] : COLOR[color ?? defaultColor], numeric && "tabular-nums", mono && "font-mono", truncate && "inline-block min-w-0 truncate align-bottom"), children: children }));
48
+ }
49
+ /** The text of `children` when it is all strings and numbers: what a truncated run shows on hover. */
50
+ function plainText(children) {
51
+ const parts = Children.toArray(children);
52
+ return parts.every((part) => typeof part === "string" || typeof part === "number")
53
+ ? parts.join("")
54
+ : undefined;
55
+ }
56
+ // --- Structural roles (block by default) -----------------------------------
57
+ /**
58
+ * Marketing-scale headline — the one line at the top of a public page. `h1`,
59
+ * text-4xl/tight semibold, primary text, growing to text-6xl on wider screens.
60
+ * `PageHeading`'s scale is deliberately dev-tool sized; a brochure
61
+ * hero needs a display scale, so it gets its own pinned role rather than callers
62
+ * overriding PageHeading's size.
63
+ */
64
+ export const Display = typography("Display", "h1", "text-4xl/[1.1] font-semibold tracking-tight sm:text-5xl/[1.05] lg:text-6xl/[1.05]", "default");
65
+ /** The supporting sentence under a `Display`. `p`, text-lg/7 normal, secondary. */
66
+ export const Lead = typography("Lead", "p", "text-lg/7 font-normal sm:text-xl/8", "secondary");
67
+ /** Page title. `h1`, text-2xl/8 semibold, primary text. */
68
+ export const PageHeading = typography("PageHeading", "h1", "text-2xl/8 font-semibold tracking-tight", "default");
69
+ /**
70
+ * Top-level section header. `h2`, text-base/6 semibold, primary text. `rule` sets
71
+ * a hairline under it (the `Divider` line colour) with the space either side of
72
+ * the line built in.
73
+ */
74
+ export function SectionHeading({ rule, ...props }) {
75
+ const variant = cx(rule && "mb-4 border-b border-slate-200/70 pb-2", "text-base/6 font-semibold");
76
+ return pinned("h2", variant, "default", props);
77
+ }
78
+ const SUBSECTION_SIZE = {
79
+ sm: "text-sm/5 font-semibold",
80
+ md: "text-base/6 font-semibold",
81
+ lg: "text-lg/7 font-semibold",
82
+ };
83
+ /**
84
+ * Nested header. `h3`, text-base/6 semibold, primary text. `size` steps it down for a dense card
85
+ * or up for a drawer or form-group title: `sm` (text-sm), `md` (default) or `lg`. `truncate` keeps it on
86
+ * one line and cuts it with an ellipsis where its container ends, the full text as the `title`.
87
+ */
88
+ export function SubsectionHeading({ size = "md", ...props }) {
89
+ return pinned("h3", SUBSECTION_SIZE[size], "default", props);
90
+ }
91
+ // --- Inline roles (inline by default) --------------------------------------
92
+ /**
93
+ * Small all-caps label above a group. `span`, text-xs semibold uppercase, tertiary. `tone`,
94
+ * `numeric`, `mono` and `truncate` are opt-in, as on `Text`.
95
+ */
96
+ export const Overline = inlineRole("Overline", "span", "text-xs font-semibold uppercase tracking-wide", "tertiary");
97
+ /**
98
+ * Running text. `span` (inline; `as="p"` for a paragraph), text-sm/5 normal, secondary. A block of it
99
+ * stops at a readable line length (`max-w-[72ch]`), wherever it sits. `strong` emphasises it:
100
+ * font-medium in the primary ink, unless `color` or `tone` says otherwise.
101
+ * `preserveNewlines` keeps the line breaks in the text (a user-typed note); runs of spaces still collapse.
102
+ * `tone` colours it by meaning (`positive` for "Saved.", `danger` for an error; it wins over `color`),
103
+ * `numeric` sets tabular figures, `mono` the monospace face, and `truncate` cuts it to one line with an
104
+ * ellipsis (the full text becomes its `title`).
105
+ */
106
+ export function Text({ strong, preserveNewlines, ...props }) {
107
+ return pinned("span", textVariant(strong, preserveNewlines, true), strong ? "default" : "secondary", props);
108
+ }
109
+ /**
110
+ * The supporting line under a `PageHeader` or `Dialog` title: `Text as="p"` without the measure, so
111
+ * it runs the width of its header. Internal; not exported from the package.
112
+ */
113
+ export function HeaderText({ children }) {
114
+ return pinned("p", textVariant(false, false, false), "secondary", { children });
115
+ }
116
+ function textVariant(strong, preserveNewlines, measure) {
117
+ return cx(preserveNewlines && "whitespace-pre-line", measure && "max-w-[72ch]", "text-sm/5", strong ? "font-medium" : "font-normal");
118
+ }
119
+ /** Fine print / metadata. `span` (inline; `as="p"` for a block), text-xs/4 normal, tertiary. Takes `tone`, `numeric`, `mono` and `truncate` like `Text`. */
120
+ export const Caption = inlineRole("Caption", "span", "text-xs/4 font-normal", "tertiary");
package/dist/ui.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { Passthrough } from "./props.js";
2
+ /** A coloured epic header row: a dot in the epic's colour + its label. */
3
+ export declare function EpicHeader({ color, label, ...rest }: {
4
+ /** The dot's colour, any CSS colour (the epic's own). */
5
+ color: string;
6
+ /** The epic's name. */
7
+ label: string;
8
+ } & Passthrough): import("react").JSX.Element;
9
+ /** Group items by their epic ref, ordered with real epics first (by ref) and "No epic" last. */
10
+ export declare function groupByEpic<T>(items: T[], epicOf: (t: T) => string | null): [string | null, T[]][];
package/dist/ui.js ADDED
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Small presentational primitives written against Tailwind's slate-based class vocabulary,
3
+ // which a theme remaps.
4
+ /** A coloured epic header row: a dot in the epic's colour + its label. */
5
+ export function EpicHeader({ color, label, ...rest }) {
6
+ return (_jsxs("div", { ...rest, className: "mb-1.5 mt-3 flex items-center gap-2 first:mt-0", children: [_jsx("span", { className: "inline-block h-2.5 w-2.5 rounded-full", style: { backgroundColor: color } }), _jsx("span", { className: "text-sm font-semibold text-slate-700", children: label })] }));
7
+ }
8
+ function compareEpics(a, b) {
9
+ if (a === null)
10
+ return 1;
11
+ if (b === null)
12
+ return -1;
13
+ return a < b ? -1 : 1;
14
+ }
15
+ /** Group items by their epic ref, ordered with real epics first (by ref) and "No epic" last. */
16
+ export function groupByEpic(items, epicOf) {
17
+ const groups = new Map();
18
+ for (const item of items) {
19
+ const key = epicOf(item) ?? null;
20
+ const group = groups.get(key);
21
+ if (group)
22
+ group.push(item);
23
+ else
24
+ groups.set(key, [item]);
25
+ }
26
+ return [...groups].toSorted(([a], [b]) => compareEpics(a, b));
27
+ }
package/package.json CHANGED
@@ -1,6 +1,93 @@
1
1
  {
2
2
  "name": "@hackcove/ui-react",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.8.1",
4
+ "description": "Hack Cove React components: primitives, typography roles and a safe Markdown renderer, written against Tailwind v4 utilities. Pair with a @hackcove/theme-* package.",
5
+ "keywords": [
6
+ "components",
7
+ "design-system",
8
+ "hackcove",
9
+ "markdown",
10
+ "react",
11
+ "tailwind",
12
+ "tailwindcss",
13
+ "ui"
14
+ ],
15
+ "homepage": "https://github.com/madangryscientist/hackcove/tree/main/packages/ui-react#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/madangryscientist/hackcove/issues"
18
+ },
19
+ "license": "MIT",
20
+ "author": {
21
+ "name": "Jacobus Langner",
22
+ "url": "https://github.com/madangryscientist"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/madangryscientist/hackcove.git",
27
+ "directory": "packages/ui-react"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "MIGRATING.md"
32
+ ],
33
+ "type": "module",
34
+ "sideEffects": false,
35
+ "types": "./dist/index.d.ts",
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/index.d.ts",
39
+ "import": "./dist/index.js"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "scripts": {
44
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
45
+ "typecheck": "tsc --noEmit",
46
+ "lint": "oxlint -c ../../.oxlintrc.json --type-aware --deny-warnings && bun ../../scripts/check-slop.ts",
47
+ "test": "vitest run",
48
+ "pack-check": "npm pack --dry-run && bun scripts/consumer-types.ts",
49
+ "prepack": "bun run build"
50
+ },
51
+ "dependencies": {
52
+ "@internationalized/date": "^3.12.4",
53
+ "react-aria-components": "^1.22.1"
54
+ },
55
+ "devDependencies": {
56
+ "@types/bun": "1.4.3",
57
+ "@types/react": "^19.3.0",
58
+ "@types/react-dom": "^19.3.0",
59
+ "jsdom": "^30.1.3",
60
+ "react": "^19.3.1",
61
+ "react-dom": "^19.3.1",
62
+ "tailwindcss": "^4.3.3",
63
+ "vitest": "5.0.5"
64
+ },
65
+ "peerDependencies": {
66
+ "@types/react": ">=18",
67
+ "@types/react-dom": ">=18",
68
+ "react": ">=18",
69
+ "react-dom": ">=18",
70
+ "tailwindcss": "^4"
71
+ },
72
+ "peerDependenciesMeta": {
73
+ "@types/react": {
74
+ "optional": true
75
+ },
76
+ "@types/react-dom": {
77
+ "optional": true
78
+ }
79
+ },
80
+ "nx": {
81
+ "name": "ui-react",
82
+ "tags": [
83
+ "kind:package"
84
+ ],
85
+ "targets": {
86
+ "build": {
87
+ "outputs": [
88
+ "{projectRoot}/dist"
89
+ ]
90
+ }
91
+ }
92
+ }
93
+ }