@hackcove/ui-react 0.8.3 → 0.9.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.
- package/README.md +18 -9
- package/dist/AppShell.d.ts +15 -3
- package/dist/AppShell.js +29 -11
- package/dist/AppShellMenu.d.ts +13 -0
- package/dist/AppShellMenu.js +42 -0
- package/dist/Avatar.d.ts +8 -4
- package/dist/Avatar.js +11 -3
- package/dist/AvatarStack.js +1 -0
- package/dist/Callout.d.ts +8 -2
- package/dist/Callout.js +3 -3
- package/dist/Card.d.ts +2 -0
- package/dist/Card.js +14 -8
- package/dist/CardParts.d.ts +6 -0
- package/dist/CardParts.js +6 -0
- package/dist/Cluster.d.ts +9 -4
- package/dist/Cluster.js +12 -5
- package/dist/Dialog.d.ts +4 -2
- package/dist/Dialog.js +9 -3
- package/dist/EmptyState.d.ts +7 -1
- package/dist/EmptyState.js +3 -2
- package/dist/Field.d.ts +8 -1
- package/dist/Field.js +4 -2
- package/dist/Image.d.ts +46 -0
- package/dist/Image.js +42 -0
- package/dist/KeyValueList.d.ts +4 -2
- package/dist/KeyValueList.js +3 -3
- package/dist/ListRow.d.ts +3 -1
- package/dist/ListRow.js +6 -6
- package/dist/MediaTile.d.ts +37 -0
- package/dist/MediaTile.js +19 -0
- package/dist/PageLayouts.d.ts +10 -3
- package/dist/PageLayouts.js +15 -4
- package/dist/Pill.d.ts +24 -6
- package/dist/Pill.js +72 -16
- package/dist/ScrollStrip.d.ts +21 -0
- package/dist/ScrollStrip.js +12 -0
- package/dist/Stack.d.ts +15 -1
- package/dist/Stack.js +12 -2
- package/dist/StatTile.d.ts +2 -2
- package/dist/StatTile.js +2 -0
- package/dist/Table.d.ts +29 -12
- package/dist/Table.js +25 -11
- package/dist/TableEditCell.d.ts +19 -0
- package/dist/TableEditCell.js +58 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/size.d.ts +1 -1
- package/dist/typography.d.ts +34 -10
- package/dist/typography.js +43 -13
- package/package.json +1 -1
package/dist/typography.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Children, } from "react";
|
|
3
3
|
import { cx } from "./cx.js";
|
|
4
4
|
/** Colour token → slate/violet utility, which a theme remaps. */
|
|
@@ -17,6 +17,11 @@ export const TEXT_TONE = {
|
|
|
17
17
|
warn: "text-amber-700",
|
|
18
18
|
danger: "text-red-700",
|
|
19
19
|
};
|
|
20
|
+
const ALIGN = {
|
|
21
|
+
start: "text-start",
|
|
22
|
+
center: "text-center",
|
|
23
|
+
end: "text-end",
|
|
24
|
+
};
|
|
20
25
|
/**
|
|
21
26
|
* Build a semantic component that pins `variantClass` (size + weight + tracking)
|
|
22
27
|
* and a default colour. The scale/weight for each role therefore lives in exactly
|
|
@@ -42,9 +47,19 @@ function inlineRole(displayName, defaultAs, variantClass, defaultColor) {
|
|
|
42
47
|
* The one place a pinned role renders. The few roles with an opt-in prop of their own are
|
|
43
48
|
* written by hand, not by `typography`, and call this too.
|
|
44
49
|
*/
|
|
45
|
-
function pinned(defaultAs, variantClass, defaultColor, { as, color, tone, numeric, mono, truncate, children, ...rest }) {
|
|
50
|
+
function pinned(defaultAs, variantClass, defaultColor, { as, color, tone, numeric, mono, truncate, align, children, ...rest }) {
|
|
46
51
|
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",
|
|
52
|
+
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", layoutClass(align, truncate)), children: children }));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The alignment, and the box it needs. An aligned run is block-level, so text-align has a box to set
|
|
56
|
+
* the text in. A truncated run clips: inline-block by default, a block when it is aligned too.
|
|
57
|
+
*/
|
|
58
|
+
function layoutClass(align, truncate) {
|
|
59
|
+
const box = truncate
|
|
60
|
+
? cx("min-w-0 truncate align-bottom", align ? "block" : "inline-block")
|
|
61
|
+
: align && "block";
|
|
62
|
+
return cx(align && ALIGN[align], box);
|
|
48
63
|
}
|
|
49
64
|
/** The text of `children` when it is all strings and numbers: what a truncated run shows on hover. */
|
|
50
65
|
function plainText(children) {
|
|
@@ -71,11 +86,16 @@ export const PageHeading = typography("PageHeading", "h1", "text-3xl/9 font-bold
|
|
|
71
86
|
/**
|
|
72
87
|
* Top-level section header. `h2`, text-base/6 semibold, primary text. `rule` sets
|
|
73
88
|
* a hairline under it (the `Divider` line colour) with the space either side of
|
|
74
|
-
* the line built in.
|
|
89
|
+
* the line built in. `description` is a muted line under the heading, outside the `<h2>`, so the
|
|
90
|
+
* heading's name stays the title; the rule then sits under the description.
|
|
75
91
|
*/
|
|
76
|
-
export function SectionHeading({ rule, ...props }) {
|
|
77
|
-
const
|
|
78
|
-
|
|
92
|
+
export function SectionHeading({ rule, description, ...props }) {
|
|
93
|
+
const hairline = "mb-4 border-b border-slate-200/70 pb-2";
|
|
94
|
+
const hasDescription = description != null && description !== false;
|
|
95
|
+
if (!hasDescription) {
|
|
96
|
+
return pinned("h2", cx(rule && hairline, "text-base/6 font-semibold"), "default", props);
|
|
97
|
+
}
|
|
98
|
+
return (_jsxs("div", { className: cx("flex flex-col gap-1", rule && hairline), children: [pinned("h2", "text-base/6 font-semibold", "default", props), _jsx(Text, { as: "p", color: "tertiary", children: description })] }));
|
|
79
99
|
}
|
|
80
100
|
const SUBSECTION_SIZE = {
|
|
81
101
|
sm: "text-sm/5 font-semibold",
|
|
@@ -93,7 +113,7 @@ export function SubsectionHeading({ size = "md", ...props }) {
|
|
|
93
113
|
// --- Inline roles (inline by default) --------------------------------------
|
|
94
114
|
/**
|
|
95
115
|
* Small all-caps label above a group. `span`, text-xs semibold uppercase, tertiary. `tone`,
|
|
96
|
-
* `numeric`, `mono` and `
|
|
116
|
+
* `numeric`, `mono`, `truncate` and `align` are opt-in, as on `Text`.
|
|
97
117
|
*/
|
|
98
118
|
export const Overline = inlineRole("Overline", "span", "text-xs font-semibold uppercase tracking-wide", "tertiary");
|
|
99
119
|
/**
|
|
@@ -103,10 +123,14 @@ export const Overline = inlineRole("Overline", "span", "text-xs font-semibold up
|
|
|
103
123
|
* `preserveNewlines` keeps the line breaks in the text (a user-typed note); runs of spaces still collapse.
|
|
104
124
|
* `tone` colours it by meaning (`positive` for "Saved.", `danger` for an error; it wins over `color`),
|
|
105
125
|
* `numeric` sets tabular figures, `mono` the monospace face, and `truncate` cuts it to one line with an
|
|
106
|
-
* ellipsis (the full text becomes its `title`).
|
|
126
|
+
* ellipsis (the full text becomes its `title`). `align` sets it at `start`, `center` or `end`.
|
|
127
|
+
* `italic` slants it, `breakWords` breaks a long unbroken string at the edge of its box, and `minWidth="amount"`
|
|
128
|
+
* fixes a width and right-aligns the figure in it (a column of amounts lines up); it does not take `align`.
|
|
107
129
|
*/
|
|
108
|
-
export function Text({ strong, preserveNewlines, ...props }) {
|
|
109
|
-
return pinned("span", textVariant(strong, preserveNewlines, true), strong ? "default" : "secondary",
|
|
130
|
+
export function Text({ strong, preserveNewlines, minWidth, italic, breakWords, ...props }) {
|
|
131
|
+
return pinned("span", cx(textVariant(strong, preserveNewlines, true), italic && "italic", breakWords && "break-words", minWidth === "amount" && "inline-block min-w-24 text-end"), strong ? "default" : "secondary",
|
|
132
|
+
// An amount is always in tabular figures, so it lines up; `numeric` already emits them.
|
|
133
|
+
{ ...props, numeric: props.numeric || minWidth === "amount" });
|
|
110
134
|
}
|
|
111
135
|
/**
|
|
112
136
|
* The supporting line under a `Dialog` title: `Text as="p"` without the measure, so
|
|
@@ -118,5 +142,11 @@ export function HeaderText({ children }) {
|
|
|
118
142
|
function textVariant(strong, preserveNewlines, measure) {
|
|
119
143
|
return cx(preserveNewlines && "whitespace-pre-line", measure && "max-w-[72ch]", "text-sm/5", strong ? "font-medium" : "font-normal");
|
|
120
144
|
}
|
|
121
|
-
/**
|
|
122
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Fine print / metadata. `span` (inline; `as="p"` for a block), text-xs/4 normal, tertiary. Takes `tone`,
|
|
147
|
+
* `numeric`, `mono`, `truncate` and `align` like `Text`, and `italic` for a muted hint and `breakWords`
|
|
148
|
+
* for a long unbroken string such as a URL.
|
|
149
|
+
*/
|
|
150
|
+
export function Caption({ italic, breakWords, ...props }) {
|
|
151
|
+
return pinned("span", cx("text-xs/4 font-normal", italic && "italic", breakWords && "break-words"), "tertiary", props);
|
|
152
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hackcove/ui-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
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
5
|
"keywords": [
|
|
6
6
|
"components",
|