@_linked/primitives 1.2.4 → 1.3.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.
- package/CHANGELOG.md +24 -0
- package/lib/cjs/components/Badge.d.ts +9 -2
- package/lib/cjs/components/Badge.js.map +1 -1
- package/lib/cjs/components/Badge.module.css +2 -0
- package/lib/cjs/components/Heading.d.ts +16 -2
- package/lib/cjs/components/Heading.js +2 -2
- package/lib/cjs/components/Heading.js.map +1 -1
- package/lib/cjs/components/Heading.module.css +70 -72
- package/lib/cjs/components/Text.d.ts +3 -1
- package/lib/cjs/components/Text.js.map +1 -1
- package/lib/cjs/components/Typography.d.ts +7 -1
- package/lib/cjs/components/Typography.js.map +1 -1
- package/lib/cjs/components/elements.d.ts +42 -0
- package/lib/cjs/components/elements.js +27 -0
- package/lib/cjs/components/elements.js.map +1 -0
- package/lib/cjs/package.json +1 -1
- package/lib/esm/components/Badge.d.ts +9 -2
- package/lib/esm/components/Badge.js.map +1 -1
- package/lib/esm/components/Badge.module.css +2 -0
- package/lib/esm/components/Heading.d.ts +16 -2
- package/lib/esm/components/Heading.js +2 -2
- package/lib/esm/components/Heading.js.map +1 -1
- package/lib/esm/components/Heading.module.css +70 -72
- package/lib/esm/components/Text.d.ts +3 -1
- package/lib/esm/components/Text.js.map +1 -1
- package/lib/esm/components/Typography.d.ts +7 -1
- package/lib/esm/components/Typography.js.map +1 -1
- package/lib/esm/components/elements.d.ts +42 -0
- package/lib/esm/components/elements.js +26 -0
- package/lib/esm/components/elements.js.map +1 -0
- package/lib/esm/package.json +1 -1
- package/package.json +1 -1
- package/test/prop-unions-are-styled.test.mjs +53 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @\_linked/primitives
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#32](https://github.com/linked-fw/primitives/pull/32) [`ec82d1a`](https://github.com/linked-fw/primitives/commit/ec82d1abf39af62f8954f0cc4057dcd4ec7cabff) Thanks [@flyon](https://github.com/flyon)! - Widen the `as` and `color` prop unions so they describe what the components
|
|
8
|
+
actually render.
|
|
9
|
+
|
|
10
|
+
`Typography`, `Text` and `Heading` spread `as` straight into JSX, so every
|
|
11
|
+
intrinsic tag has always worked at runtime, but the types named four or six
|
|
12
|
+
tags each — `as="strong"`, `as="code"`, `as="small"` were type errors for
|
|
13
|
+
behaviour that works. They now take a shared, curated element union
|
|
14
|
+
(`TextElement` / `HeadingAsElement`, exported from `components/elements.js`)
|
|
15
|
+
covering phrasing and text-block elements. Void, interactive and SVG tags are
|
|
16
|
+
deliberately excluded: these components require `children` and type their props
|
|
17
|
+
as `HtmlHTMLAttributes<HTMLElement>`, so those tags could not be rendered
|
|
18
|
+
correctly anyway.
|
|
19
|
+
|
|
20
|
+
`Heading` gains an optional `level` prop. Its stylesheet keys off the tag
|
|
21
|
+
(`h1.Root`), so `<Heading as="p">` renders with no heading typography; `level`
|
|
22
|
+
applies a level's tokens to any tag. Omitting it changes nothing.
|
|
23
|
+
|
|
24
|
+
`Badge` gains `accent` and `secondary` colours, each with a real rule in
|
|
25
|
+
`Badge.module.css`, and the union is now the exported `BadgeColor` type.
|
|
26
|
+
|
|
3
27
|
## 1.2.4
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -6,7 +6,8 @@ import * as React from 'react';
|
|
|
6
6
|
* swap variation without new components —
|
|
7
7
|
*
|
|
8
8
|
* variant solid | soft | outline | ghost fill strength
|
|
9
|
-
* color neutral | primary |
|
|
9
|
+
* color neutral | primary | accent | secondary |
|
|
10
|
+
* success | warning | danger | info
|
|
10
11
|
* size small | medium | large
|
|
11
12
|
* shape pill | rounded
|
|
12
13
|
* dot leading status dot in the badge color
|
|
@@ -17,10 +18,16 @@ import * as React from 'react';
|
|
|
17
18
|
* variables with working fallbacks, so it renders sensibly out of the box and
|
|
18
19
|
* apps re-skin it from their theme without touching the component.
|
|
19
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* Every colour here has a `--_badge-color` rule in Badge.module.css — the union
|
|
23
|
+
* and the stylesheet are one list, so a colour can never type-check its way to
|
|
24
|
+
* an unstyled badge.
|
|
25
|
+
*/
|
|
26
|
+
export type BadgeColor = 'neutral' | 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
20
27
|
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
21
28
|
asChild?: boolean;
|
|
22
29
|
variant?: 'solid' | 'soft' | 'outline' | 'ghost';
|
|
23
|
-
color?:
|
|
30
|
+
color?: BadgeColor;
|
|
24
31
|
size?: 'small' | 'medium' | 'large';
|
|
25
32
|
shape?: 'pill' | 'rounded';
|
|
26
33
|
/** Leading status dot in the badge color. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../src/components/Badge.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,0EAAuC;AACvC,gEAAqD;AACrD,qDAA4C;
|
|
1
|
+
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../src/components/Badge.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,0EAAuC;AACvC,gEAAqD;AACrD,qDAA4C;AA8C5C,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAC5B,CACE,EAUC,EACD,GAAG,EACH,EAAE;QAZF,EACE,SAAS,EACT,OAAO,GAAG,MAAM,EAChB,KAAK,GAAG,SAAS,EACjB,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,MAAM,EACd,GAAG,GAAG,KAAK,EACX,OAAO,GAAG,KAAK,EACf,QAAQ,OAET,EADI,KAAK,cATV,gFAUC,CADS;IAIV,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,iBAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAErC,OAAO,CACL,oBAAC,IAAI,kBACH,SAAS,EAAE,IAAA,eAAE,EACX,0BAAK,CAAC,IAAI,EACV,0BAAK,CAAC,OAAO,CAAC,EACd,0BAAK,CAAC,KAAK,CAAC,EACZ,0BAAK,CAAC,IAAI,CAAC,EACX,0BAAK,CAAC,KAAK,CAAC,EACZ,SAAS,CACV,EACD,GAAG,EAAE,GAAG,IACJ,KAAK,GAER,OAAO,CAAC,CAAC,CAAC,CACT,QAAQ,CACT,CAAC,CAAC,CAAC,CACF;QACG,GAAG,IAAI,8BAAM,SAAS,EAAE,0BAAK,CAAC,GAAG,wBAAgB;QACjD,QAAQ,CACR,CACJ,CACI,CACR,CAAC;AACJ,CAAC,CACF,CAAC;AAGO,sBAAK;AAFd,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC"}
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
/* ── color ─────────────────────────────────────────────────────────────── */
|
|
22
22
|
.neutral { --_badge-color: var(--badge-color-neutral, #64748b); }
|
|
23
23
|
.primary { --_badge-color: var(--badge-color-primary, var(--primary, #4f46e5)); }
|
|
24
|
+
.secondary { --_badge-color: var(--badge-color-secondary, var(--secondary, #475569)); }
|
|
25
|
+
.accent { --_badge-color: var(--badge-color-accent, var(--control-accent, var(--primary, #4f46e5))); }
|
|
24
26
|
.success { --_badge-color: var(--badge-color-success, #15803d); }
|
|
25
27
|
.warning { --_badge-color: var(--badge-color-warning, #b45309); }
|
|
26
28
|
.danger { --_badge-color: var(--badge-color-danger, #b91c1c); }
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { HeadingAsElement } from './elements.js';
|
|
2
3
|
interface HeadingProps extends React.HtmlHTMLAttributes<HTMLElement> {
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The tag to render. `h1`–`h6` pick up that level's heading tokens from the
|
|
6
|
+
* tag itself; any other container renders with no heading typography unless
|
|
7
|
+
* you also pass {@link HeadingProps.level}.
|
|
8
|
+
*/
|
|
9
|
+
as: HeadingAsElement;
|
|
10
|
+
/**
|
|
11
|
+
* Visual heading level, independent of the tag. Use it when the heading is
|
|
12
|
+
* visual rather than semantic — a stat card's big number is a `p`, not an
|
|
13
|
+
* `h2`. Omitted, nothing is added: `as="h3"` styles as an h3 and `as="p"`
|
|
14
|
+
* stays unstyled, exactly as before.
|
|
15
|
+
*/
|
|
16
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
4
17
|
children: React.ReactNode;
|
|
5
18
|
}
|
|
6
|
-
declare const Heading: ({ as: Component, className, children, ...props }: HeadingProps) => React.JSX.Element;
|
|
19
|
+
declare const Heading: ({ as: Component, level, className, children, ...props }: HeadingProps) => React.JSX.Element;
|
|
7
20
|
export { Heading };
|
|
21
|
+
export type { HeadingProps };
|
|
@@ -52,8 +52,8 @@ const React = __importStar(require("react"));
|
|
|
52
52
|
const Heading_module_css_1 = __importDefault(require("./Heading.module.css"));
|
|
53
53
|
const ClassNames_1 = require("@_linked/react/utils/ClassNames");
|
|
54
54
|
const Heading = (_a) => {
|
|
55
|
-
var { as: Component, className, children } = _a, props = __rest(_a, ["as", "className", "children"]);
|
|
56
|
-
const combinedClassName = (0, ClassNames_1.cl)(Heading_module_css_1.default.Root, className);
|
|
55
|
+
var { as: Component, level, className, children } = _a, props = __rest(_a, ["as", "level", "className", "children"]);
|
|
56
|
+
const combinedClassName = (0, ClassNames_1.cl)(Heading_module_css_1.default.Root, level ? Heading_module_css_1.default[`level${level}`] : undefined, className);
|
|
57
57
|
return (React.createElement(Component, Object.assign({ className: combinedClassName }, props), children));
|
|
58
58
|
};
|
|
59
59
|
exports.Heading = Heading;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Heading.js","sourceRoot":"","sources":["../../../src/components/Heading.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,8EAAyC;AACzC,gEAAqD;
|
|
1
|
+
{"version":3,"file":"Heading.js","sourceRoot":"","sources":["../../../src/components/Heading.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,8EAAyC;AACzC,gEAAqD;AAmBrD,MAAM,OAAO,GAAG,CAAC,EAMF,EAAE,EAAE;QANF,EACf,EAAE,EAAE,SAAS,EACb,KAAK,EACL,SAAS,EACT,QAAQ,OAEK,EADV,KAAK,cALO,wCAMhB,CADS;IAER,MAAM,iBAAiB,GAAG,IAAA,eAAE,EAC1B,4BAAK,CAAC,IAAI,EACV,KAAK,CAAC,CAAC,CAAC,4BAAK,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EAC1C,SAAS,CACV,CAAC;IAEF,OAAO,CACL,oBAAC,SAAS,kBAAC,SAAS,EAAE,iBAAiB,IAAM,KAAK,GAC/C,QAAQ,CACC,CACb,CAAC;AACJ,CAAC,CAAC;AAEO,0BAAO"}
|
|
@@ -1,83 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
/* Two selectors per level: the tag itself (an `h2` is an h2, no extra props
|
|
2
|
+
needed) and an explicit `level` class for a heading that is visual rather
|
|
3
|
+
than semantic — `<Heading as="p" level={2}>` on a stat card. */
|
|
4
|
+
|
|
5
|
+
h1.Root,
|
|
6
|
+
.Root.level1 {
|
|
7
|
+
font-size: var(--heading-1-font-size);
|
|
8
|
+
font-family: var(--heading-1-font-family);
|
|
9
|
+
font-weight: var(--heading-1-font-weight);
|
|
10
|
+
line-height: var(--heading-1-line-height);
|
|
11
|
+
letter-spacing: var(--heading-1-letter-spacing);
|
|
12
|
+
color: var(--heading-1-color);
|
|
13
|
+
font-style: var(--heading-1-font-style);
|
|
14
|
+
margin-top: var(--heading-1-margin-top);
|
|
15
|
+
margin-bottom: var(--heading-1-margin-bottom);
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
h2
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
18
|
+
h2.Root,
|
|
19
|
+
.Root.level2 {
|
|
20
|
+
font-size: var(--heading-2-font-size);
|
|
21
|
+
font-family: var(--heading-2-font-family);
|
|
22
|
+
font-weight: var(--heading-2-font-weight);
|
|
23
|
+
line-height: var(--heading-2-line-height);
|
|
24
|
+
letter-spacing: var(--heading-2-letter-spacing);
|
|
25
|
+
color: var(--heading-2-color);
|
|
26
|
+
font-style: var(--heading-2-font-style);
|
|
27
|
+
margin-top: var(--heading-2-margin-top);
|
|
28
|
+
margin-bottom: var(--heading-2-margin-bottom);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
h3
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
31
|
+
h3.Root,
|
|
32
|
+
.Root.level3 {
|
|
33
|
+
font-size: var(--heading-3-font-size);
|
|
34
|
+
font-family: var(--heading-3-font-family);
|
|
35
|
+
font-weight: var(--heading-3-font-weight);
|
|
36
|
+
line-height: var(--heading-3-line-height);
|
|
37
|
+
letter-spacing: var(--heading-3-letter-spacing);
|
|
38
|
+
color: var(--heading-3-color);
|
|
39
|
+
font-style: var(--heading-3-font-style);
|
|
40
|
+
margin-top: var(--heading-3-margin-top);
|
|
41
|
+
margin-bottom: var(--heading-3-margin-bottom);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
h4
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
44
|
+
h4.Root,
|
|
45
|
+
.Root.level4 {
|
|
46
|
+
font-size: var(--heading-4-font-size);
|
|
47
|
+
font-family: var(--heading-4-font-family);
|
|
48
|
+
font-weight: var(--heading-4-font-weight);
|
|
49
|
+
line-height: var(--heading-4-line-height);
|
|
50
|
+
letter-spacing: var(--heading-4-letter-spacing);
|
|
51
|
+
color: var(--heading-4-color);
|
|
52
|
+
font-style: var(--heading-4-font-style);
|
|
53
|
+
margin-top: var(--heading-4-margin-top);
|
|
54
|
+
margin-bottom: var(--heading-4-margin-bottom);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
h5
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
57
|
+
h5.Root,
|
|
58
|
+
.Root.level5 {
|
|
59
|
+
font-size: var(--heading-5-font-size);
|
|
60
|
+
font-family: var(--heading-5-font-family);
|
|
61
|
+
font-weight: var(--heading-5-font-weight);
|
|
62
|
+
line-height: var(--heading-5-line-height);
|
|
63
|
+
letter-spacing: var(--heading-5-letter-spacing);
|
|
64
|
+
color: var(--heading-5-color);
|
|
65
|
+
font-style: var(--heading-5-font-style);
|
|
66
|
+
margin-top: var(--heading-5-margin-top);
|
|
67
|
+
margin-bottom: var(--heading-5-margin-bottom);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
h6
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
70
|
+
h6.Root,
|
|
71
|
+
.Root.level6 {
|
|
72
|
+
font-size: var(--heading-6-font-size);
|
|
73
|
+
font-family: var(--heading-6-font-family);
|
|
74
|
+
font-weight: var(--heading-6-font-weight);
|
|
75
|
+
line-height: var(--heading-6-line-height);
|
|
76
|
+
letter-spacing: var(--heading-6-letter-spacing);
|
|
77
|
+
color: var(--heading-6-color);
|
|
78
|
+
font-style: var(--heading-6-font-style);
|
|
79
|
+
margin-top: var(--heading-6-margin-top);
|
|
80
|
+
margin-bottom: var(--heading-6-margin-bottom);
|
|
83
81
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { TextElement } from './elements.js';
|
|
2
3
|
interface TextProps extends React.HtmlHTMLAttributes<HTMLElement> {
|
|
3
|
-
|
|
4
|
+
/** The tag to render — see {@link TextElement}. */
|
|
5
|
+
as?: TextElement;
|
|
4
6
|
size?: 'small' | 'medium' | 'large' | 'default';
|
|
5
7
|
children: React.ReactNode;
|
|
6
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Text.js","sourceRoot":"","sources":["../../../src/components/Text.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,wEAAsC;AACtC,gEAAqD;
|
|
1
|
+
{"version":3,"file":"Text.js","sourceRoot":"","sources":["../../../src/components/Text.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,wEAAsC;AACtC,gEAAqD;AASrD,MAAM,IAAI,GAAG,CAAC,EAKF,EAAE,EAAE;QALF,EACZ,EAAE,EAAE,SAAS,GAAG,GAAG,EACnB,IAAI,GAAG,SAAS,EAChB,QAAQ,OAEE,EADP,KAAK,cAJI,0BAKb,CADS;IAER,OAAO,CACL,oBAAC,SAAS,kBAAC,SAAS,EAAE,IAAA,eAAE,EAAC,yBAAK,CAAC,IAAI,EAAE,yBAAK,CAAC,IAAI,CAAC,CAAC,IAAM,KAAK,GACzD,QAAQ,CACC,CACb,CAAC;AACJ,CAAC,CAAC;AAEO,oBAAI"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { TextElement } from './elements.js';
|
|
2
3
|
interface TypographyProps extends React.HtmlHTMLAttributes<HTMLElement> {
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The tag to render. Spread straight into JSX and styled tag-agnostically, so
|
|
6
|
+
* every element in {@link TextElement} renders correctly — see `elements.ts`
|
|
7
|
+
* for why this is a curated list and not every intrinsic element.
|
|
8
|
+
*/
|
|
9
|
+
as?: TextElement;
|
|
4
10
|
size?: 'small' | 'medium' | 'large' | 'default';
|
|
5
11
|
children: React.ReactNode;
|
|
6
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Typography.js","sourceRoot":"","sources":["../../../src/components/Typography.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,oFAA4C;AAC5C,gEAAqD;
|
|
1
|
+
{"version":3,"file":"Typography.js","sourceRoot":"","sources":["../../../src/components/Typography.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAA+B;AAE/B,oFAA4C;AAC5C,gEAAqD;AAarD,MAAM,UAAU,GAAG,CAAC,EAMF,EAAE,EAAE;QANF,EAClB,EAAE,EAAE,SAAS,GAAG,GAAG,EACnB,IAAI,GAAG,SAAS,EAChB,SAAS,EACT,QAAQ,OAEQ,EADb,KAAK,cALU,uCAMnB,CADS;IAER,MAAM,iBAAiB,GAAG,IAAA,eAAE,EAAC,+BAAK,CAAC,IAAI,EAAE,+BAAK,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;IAEjE,OAAO,CACL,oBAAC,SAAS,kBAAC,SAAS,EAAE,iBAAiB,IAAM,KAAK,GAC/C,QAAQ,CACC,CACb,CAAC;AACJ,CAAC,CAAC;AAEO,gCAAU"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element unions for the `as` prop of the typographic primitives.
|
|
3
|
+
*
|
|
4
|
+
* These components spread `as` straight into JSX, so at runtime *any* intrinsic
|
|
5
|
+
* tag works. The types used to name a handful of tags each, which made ordinary
|
|
6
|
+
* usage (`as="strong"`, `as="code"`, `as="small"`) a type error for behaviour
|
|
7
|
+
* that has always worked.
|
|
8
|
+
*
|
|
9
|
+
* We deliberately do NOT use `keyof React.JSX.IntrinsicElements`:
|
|
10
|
+
*
|
|
11
|
+
* - these components take required `children`, and React throws at runtime for
|
|
12
|
+
* a void element with children (`<input>`, `<img>`, `<br>`, `<hr>`…), so the
|
|
13
|
+
* full key set would type-check code that crashes;
|
|
14
|
+
* - their props are `React.HtmlHTMLAttributes<HTMLElement>`, which cannot carry
|
|
15
|
+
* element-specific attributes (`href`, `type`, `value`), so interactive and
|
|
16
|
+
* form tags would be offered without the attributes that make them useful;
|
|
17
|
+
* - `svg`/`math` and the SVG child tags take a different attribute namespace
|
|
18
|
+
* entirely.
|
|
19
|
+
*
|
|
20
|
+
* What is left — every HTML element that holds phrasing or flow content and is
|
|
21
|
+
* styled purely by the component's own class — is exactly the set below. It is
|
|
22
|
+
* wide enough that drift is unlikely, and honest about what the component can
|
|
23
|
+
* actually render.
|
|
24
|
+
*/
|
|
25
|
+
/** Inline (phrasing) elements: text-level semantics. */
|
|
26
|
+
export type PhrasingElement = 'span' | 'label' | 'strong' | 'em' | 'b' | 'i' | 'u' | 's' | 'small' | 'mark' | 'code' | 'kbd' | 'samp' | 'var' | 'sub' | 'sup' | 'abbr' | 'cite' | 'dfn' | 'q' | 'time' | 'data' | 'del' | 'ins' | 'bdi' | 'bdo' | 'output' | 'ruby' | 'rt' | 'rp';
|
|
27
|
+
/** Block-level containers that hold text. */
|
|
28
|
+
export type TextBlockElement = 'p' | 'div' | 'pre' | 'blockquote' | 'address' | 'figcaption' | 'caption' | 'legend' | 'summary' | 'li' | 'dt' | 'dd' | 'td' | 'th';
|
|
29
|
+
/** The six HTML heading levels. */
|
|
30
|
+
export type HeadingElement = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
31
|
+
/**
|
|
32
|
+
* Anything `Typography` / `Text` can render: inline text, a text block, or a
|
|
33
|
+
* heading tag (a caption-styled heading is a normal thing to want).
|
|
34
|
+
*/
|
|
35
|
+
export type TextElement = PhrasingElement | TextBlockElement | HeadingElement;
|
|
36
|
+
/**
|
|
37
|
+
* Anything `Heading` can render. A heading is often visual rather than
|
|
38
|
+
* semantic — a stat card's big number is a `p`, not an `h2` — so the non-heading
|
|
39
|
+
* containers are allowed too. See `Heading`'s `level` prop for the styling that
|
|
40
|
+
* goes with them.
|
|
41
|
+
*/
|
|
42
|
+
export type HeadingAsElement = HeadingElement | TextBlockElement | PhrasingElement;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Element unions for the `as` prop of the typographic primitives.
|
|
4
|
+
*
|
|
5
|
+
* These components spread `as` straight into JSX, so at runtime *any* intrinsic
|
|
6
|
+
* tag works. The types used to name a handful of tags each, which made ordinary
|
|
7
|
+
* usage (`as="strong"`, `as="code"`, `as="small"`) a type error for behaviour
|
|
8
|
+
* that has always worked.
|
|
9
|
+
*
|
|
10
|
+
* We deliberately do NOT use `keyof React.JSX.IntrinsicElements`:
|
|
11
|
+
*
|
|
12
|
+
* - these components take required `children`, and React throws at runtime for
|
|
13
|
+
* a void element with children (`<input>`, `<img>`, `<br>`, `<hr>`…), so the
|
|
14
|
+
* full key set would type-check code that crashes;
|
|
15
|
+
* - their props are `React.HtmlHTMLAttributes<HTMLElement>`, which cannot carry
|
|
16
|
+
* element-specific attributes (`href`, `type`, `value`), so interactive and
|
|
17
|
+
* form tags would be offered without the attributes that make them useful;
|
|
18
|
+
* - `svg`/`math` and the SVG child tags take a different attribute namespace
|
|
19
|
+
* entirely.
|
|
20
|
+
*
|
|
21
|
+
* What is left — every HTML element that holds phrasing or flow content and is
|
|
22
|
+
* styled purely by the component's own class — is exactly the set below. It is
|
|
23
|
+
* wide enough that drift is unlikely, and honest about what the component can
|
|
24
|
+
* actually render.
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
//# sourceMappingURL=elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../../../src/components/elements.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
package/lib/cjs/package.json
CHANGED
|
@@ -6,7 +6,8 @@ import * as React from 'react';
|
|
|
6
6
|
* swap variation without new components —
|
|
7
7
|
*
|
|
8
8
|
* variant solid | soft | outline | ghost fill strength
|
|
9
|
-
* color neutral | primary |
|
|
9
|
+
* color neutral | primary | accent | secondary |
|
|
10
|
+
* success | warning | danger | info
|
|
10
11
|
* size small | medium | large
|
|
11
12
|
* shape pill | rounded
|
|
12
13
|
* dot leading status dot in the badge color
|
|
@@ -17,10 +18,16 @@ import * as React from 'react';
|
|
|
17
18
|
* variables with working fallbacks, so it renders sensibly out of the box and
|
|
18
19
|
* apps re-skin it from their theme without touching the component.
|
|
19
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* Every colour here has a `--_badge-color` rule in Badge.module.css — the union
|
|
23
|
+
* and the stylesheet are one list, so a colour can never type-check its way to
|
|
24
|
+
* an unstyled badge.
|
|
25
|
+
*/
|
|
26
|
+
export type BadgeColor = 'neutral' | 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
20
27
|
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
21
28
|
asChild?: boolean;
|
|
22
29
|
variant?: 'solid' | 'soft' | 'outline' | 'ghost';
|
|
23
|
-
color?:
|
|
30
|
+
color?: BadgeColor;
|
|
24
31
|
size?: 'small' | 'medium' | 'large';
|
|
25
32
|
shape?: 'pill' | 'rounded';
|
|
26
33
|
/** Leading status dot in the badge color. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../src/components/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,oBAAoB,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../../src/components/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,oBAAoB,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AA8C5C,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAC5B,CACE,EACE,SAAS,EACT,OAAO,GAAG,MAAM,EAChB,KAAK,GAAG,SAAS,EACjB,IAAI,GAAG,QAAQ,EACf,KAAK,GAAG,MAAM,EACd,GAAG,GAAG,KAAK,EACX,OAAO,GAAG,KAAK,EACf,QAAQ,EACR,GAAG,KAAK,EACT,EACD,GAAG,EACH,EAAE;IACF,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAErC,OAAO,CACL,oBAAC,IAAI,IACH,SAAS,EAAE,EAAE,CACX,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,OAAO,CAAC,EACd,KAAK,CAAC,KAAK,CAAC,EACZ,KAAK,CAAC,IAAI,CAAC,EACX,KAAK,CAAC,KAAK,CAAC,EACZ,SAAS,CACV,EACD,GAAG,EAAE,GAAG,KACJ,KAAK,IAER,OAAO,CAAC,CAAC,CAAC,CACT,QAAQ,CACT,CAAC,CAAC,CAAC,CACF;QACG,GAAG,IAAI,8BAAM,SAAS,EAAE,KAAK,CAAC,GAAG,wBAAgB;QACjD,QAAQ,CACR,CACJ,CACI,CACR,CAAC;AACJ,CAAC,CACF,CAAC;AACF,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC;AAE5B,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
/* ── color ─────────────────────────────────────────────────────────────── */
|
|
22
22
|
.neutral { --_badge-color: var(--badge-color-neutral, #64748b); }
|
|
23
23
|
.primary { --_badge-color: var(--badge-color-primary, var(--primary, #4f46e5)); }
|
|
24
|
+
.secondary { --_badge-color: var(--badge-color-secondary, var(--secondary, #475569)); }
|
|
25
|
+
.accent { --_badge-color: var(--badge-color-accent, var(--control-accent, var(--primary, #4f46e5))); }
|
|
24
26
|
.success { --_badge-color: var(--badge-color-success, #15803d); }
|
|
25
27
|
.warning { --_badge-color: var(--badge-color-warning, #b45309); }
|
|
26
28
|
.danger { --_badge-color: var(--badge-color-danger, #b91c1c); }
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { HeadingAsElement } from './elements.js';
|
|
2
3
|
interface HeadingProps extends React.HtmlHTMLAttributes<HTMLElement> {
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The tag to render. `h1`–`h6` pick up that level's heading tokens from the
|
|
6
|
+
* tag itself; any other container renders with no heading typography unless
|
|
7
|
+
* you also pass {@link HeadingProps.level}.
|
|
8
|
+
*/
|
|
9
|
+
as: HeadingAsElement;
|
|
10
|
+
/**
|
|
11
|
+
* Visual heading level, independent of the tag. Use it when the heading is
|
|
12
|
+
* visual rather than semantic — a stat card's big number is a `p`, not an
|
|
13
|
+
* `h2`. Omitted, nothing is added: `as="h3"` styles as an h3 and `as="p"`
|
|
14
|
+
* stays unstyled, exactly as before.
|
|
15
|
+
*/
|
|
16
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
4
17
|
children: React.ReactNode;
|
|
5
18
|
}
|
|
6
|
-
declare const Heading: ({ as: Component, className, children, ...props }: HeadingProps) => React.JSX.Element;
|
|
19
|
+
declare const Heading: ({ as: Component, level, className, children, ...props }: HeadingProps) => React.JSX.Element;
|
|
7
20
|
export { Heading };
|
|
21
|
+
export type { HeadingProps };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import style from './Heading.module.css';
|
|
3
3
|
import { cl } from '@_linked/react/utils/ClassNames';
|
|
4
|
-
const Heading = ({ as: Component, className, children, ...props }) => {
|
|
5
|
-
const combinedClassName = cl(style.Root, className);
|
|
4
|
+
const Heading = ({ as: Component, level, className, children, ...props }) => {
|
|
5
|
+
const combinedClassName = cl(style.Root, level ? style[`level${level}`] : undefined, className);
|
|
6
6
|
return (React.createElement(Component, { className: combinedClassName, ...props }, children));
|
|
7
7
|
};
|
|
8
8
|
export { Heading };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Heading.js","sourceRoot":"","sources":["../../../src/components/Heading.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,sBAAsB,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"Heading.js","sourceRoot":"","sources":["../../../src/components/Heading.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,sBAAsB,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;AAmBrD,MAAM,OAAO,GAAG,CAAC,EACf,EAAE,EAAE,SAAS,EACb,KAAK,EACL,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACK,EAAE,EAAE;IACjB,MAAM,iBAAiB,GAAG,EAAE,CAC1B,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EAC1C,SAAS,CACV,CAAC;IAEF,OAAO,CACL,oBAAC,SAAS,IAAC,SAAS,EAAE,iBAAiB,KAAM,KAAK,IAC/C,QAAQ,CACC,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -1,83 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
/* Two selectors per level: the tag itself (an `h2` is an h2, no extra props
|
|
2
|
+
needed) and an explicit `level` class for a heading that is visual rather
|
|
3
|
+
than semantic — `<Heading as="p" level={2}>` on a stat card. */
|
|
4
|
+
|
|
5
|
+
h1.Root,
|
|
6
|
+
.Root.level1 {
|
|
7
|
+
font-size: var(--heading-1-font-size);
|
|
8
|
+
font-family: var(--heading-1-font-family);
|
|
9
|
+
font-weight: var(--heading-1-font-weight);
|
|
10
|
+
line-height: var(--heading-1-line-height);
|
|
11
|
+
letter-spacing: var(--heading-1-letter-spacing);
|
|
12
|
+
color: var(--heading-1-color);
|
|
13
|
+
font-style: var(--heading-1-font-style);
|
|
14
|
+
margin-top: var(--heading-1-margin-top);
|
|
15
|
+
margin-bottom: var(--heading-1-margin-bottom);
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
h2
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
18
|
+
h2.Root,
|
|
19
|
+
.Root.level2 {
|
|
20
|
+
font-size: var(--heading-2-font-size);
|
|
21
|
+
font-family: var(--heading-2-font-family);
|
|
22
|
+
font-weight: var(--heading-2-font-weight);
|
|
23
|
+
line-height: var(--heading-2-line-height);
|
|
24
|
+
letter-spacing: var(--heading-2-letter-spacing);
|
|
25
|
+
color: var(--heading-2-color);
|
|
26
|
+
font-style: var(--heading-2-font-style);
|
|
27
|
+
margin-top: var(--heading-2-margin-top);
|
|
28
|
+
margin-bottom: var(--heading-2-margin-bottom);
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
h3
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
31
|
+
h3.Root,
|
|
32
|
+
.Root.level3 {
|
|
33
|
+
font-size: var(--heading-3-font-size);
|
|
34
|
+
font-family: var(--heading-3-font-family);
|
|
35
|
+
font-weight: var(--heading-3-font-weight);
|
|
36
|
+
line-height: var(--heading-3-line-height);
|
|
37
|
+
letter-spacing: var(--heading-3-letter-spacing);
|
|
38
|
+
color: var(--heading-3-color);
|
|
39
|
+
font-style: var(--heading-3-font-style);
|
|
40
|
+
margin-top: var(--heading-3-margin-top);
|
|
41
|
+
margin-bottom: var(--heading-3-margin-bottom);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
h4
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
44
|
+
h4.Root,
|
|
45
|
+
.Root.level4 {
|
|
46
|
+
font-size: var(--heading-4-font-size);
|
|
47
|
+
font-family: var(--heading-4-font-family);
|
|
48
|
+
font-weight: var(--heading-4-font-weight);
|
|
49
|
+
line-height: var(--heading-4-line-height);
|
|
50
|
+
letter-spacing: var(--heading-4-letter-spacing);
|
|
51
|
+
color: var(--heading-4-color);
|
|
52
|
+
font-style: var(--heading-4-font-style);
|
|
53
|
+
margin-top: var(--heading-4-margin-top);
|
|
54
|
+
margin-bottom: var(--heading-4-margin-bottom);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
h5
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
57
|
+
h5.Root,
|
|
58
|
+
.Root.level5 {
|
|
59
|
+
font-size: var(--heading-5-font-size);
|
|
60
|
+
font-family: var(--heading-5-font-family);
|
|
61
|
+
font-weight: var(--heading-5-font-weight);
|
|
62
|
+
line-height: var(--heading-5-line-height);
|
|
63
|
+
letter-spacing: var(--heading-5-letter-spacing);
|
|
64
|
+
color: var(--heading-5-color);
|
|
65
|
+
font-style: var(--heading-5-font-style);
|
|
66
|
+
margin-top: var(--heading-5-margin-top);
|
|
67
|
+
margin-bottom: var(--heading-5-margin-bottom);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
|
-
h6
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
70
|
+
h6.Root,
|
|
71
|
+
.Root.level6 {
|
|
72
|
+
font-size: var(--heading-6-font-size);
|
|
73
|
+
font-family: var(--heading-6-font-family);
|
|
74
|
+
font-weight: var(--heading-6-font-weight);
|
|
75
|
+
line-height: var(--heading-6-line-height);
|
|
76
|
+
letter-spacing: var(--heading-6-letter-spacing);
|
|
77
|
+
color: var(--heading-6-color);
|
|
78
|
+
font-style: var(--heading-6-font-style);
|
|
79
|
+
margin-top: var(--heading-6-margin-top);
|
|
80
|
+
margin-bottom: var(--heading-6-margin-bottom);
|
|
83
81
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { TextElement } from './elements.js';
|
|
2
3
|
interface TextProps extends React.HtmlHTMLAttributes<HTMLElement> {
|
|
3
|
-
|
|
4
|
+
/** The tag to render — see {@link TextElement}. */
|
|
5
|
+
as?: TextElement;
|
|
4
6
|
size?: 'small' | 'medium' | 'large' | 'default';
|
|
5
7
|
children: React.ReactNode;
|
|
6
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Text.js","sourceRoot":"","sources":["../../../src/components/Text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,mBAAmB,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"Text.js","sourceRoot":"","sources":["../../../src/components/Text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,mBAAmB,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;AASrD,MAAM,IAAI,GAAG,CAAC,EACZ,EAAE,EAAE,SAAS,GAAG,GAAG,EACnB,IAAI,GAAG,SAAS,EAChB,QAAQ,EACR,GAAG,KAAK,EACE,EAAE,EAAE;IACd,OAAO,CACL,oBAAC,SAAS,IAAC,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,KAAM,KAAK,IACzD,QAAQ,CACC,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import type { TextElement } from './elements.js';
|
|
2
3
|
interface TypographyProps extends React.HtmlHTMLAttributes<HTMLElement> {
|
|
3
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The tag to render. Spread straight into JSX and styled tag-agnostically, so
|
|
6
|
+
* every element in {@link TextElement} renders correctly — see `elements.ts`
|
|
7
|
+
* for why this is a curated list and not every intrinsic element.
|
|
8
|
+
*/
|
|
9
|
+
as?: TextElement;
|
|
4
10
|
size?: 'small' | 'medium' | 'large' | 'default';
|
|
5
11
|
children: React.ReactNode;
|
|
6
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Typography.js","sourceRoot":"","sources":["../../../src/components/Typography.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,yBAAyB,CAAC;AAC5C,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"Typography.js","sourceRoot":"","sources":["../../../src/components/Typography.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,MAAM,yBAAyB,CAAC;AAC5C,OAAO,EAAE,EAAE,EAAE,MAAM,iCAAiC,CAAC;AAarD,MAAM,UAAU,GAAG,CAAC,EAClB,EAAE,EAAE,SAAS,GAAG,GAAG,EACnB,IAAI,GAAG,SAAS,EAChB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACQ,EAAE,EAAE;IACpB,MAAM,iBAAiB,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;IAEjE,OAAO,CACL,oBAAC,SAAS,IAAC,SAAS,EAAE,iBAAiB,KAAM,KAAK,IAC/C,QAAQ,CACC,CACb,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element unions for the `as` prop of the typographic primitives.
|
|
3
|
+
*
|
|
4
|
+
* These components spread `as` straight into JSX, so at runtime *any* intrinsic
|
|
5
|
+
* tag works. The types used to name a handful of tags each, which made ordinary
|
|
6
|
+
* usage (`as="strong"`, `as="code"`, `as="small"`) a type error for behaviour
|
|
7
|
+
* that has always worked.
|
|
8
|
+
*
|
|
9
|
+
* We deliberately do NOT use `keyof React.JSX.IntrinsicElements`:
|
|
10
|
+
*
|
|
11
|
+
* - these components take required `children`, and React throws at runtime for
|
|
12
|
+
* a void element with children (`<input>`, `<img>`, `<br>`, `<hr>`…), so the
|
|
13
|
+
* full key set would type-check code that crashes;
|
|
14
|
+
* - their props are `React.HtmlHTMLAttributes<HTMLElement>`, which cannot carry
|
|
15
|
+
* element-specific attributes (`href`, `type`, `value`), so interactive and
|
|
16
|
+
* form tags would be offered without the attributes that make them useful;
|
|
17
|
+
* - `svg`/`math` and the SVG child tags take a different attribute namespace
|
|
18
|
+
* entirely.
|
|
19
|
+
*
|
|
20
|
+
* What is left — every HTML element that holds phrasing or flow content and is
|
|
21
|
+
* styled purely by the component's own class — is exactly the set below. It is
|
|
22
|
+
* wide enough that drift is unlikely, and honest about what the component can
|
|
23
|
+
* actually render.
|
|
24
|
+
*/
|
|
25
|
+
/** Inline (phrasing) elements: text-level semantics. */
|
|
26
|
+
export type PhrasingElement = 'span' | 'label' | 'strong' | 'em' | 'b' | 'i' | 'u' | 's' | 'small' | 'mark' | 'code' | 'kbd' | 'samp' | 'var' | 'sub' | 'sup' | 'abbr' | 'cite' | 'dfn' | 'q' | 'time' | 'data' | 'del' | 'ins' | 'bdi' | 'bdo' | 'output' | 'ruby' | 'rt' | 'rp';
|
|
27
|
+
/** Block-level containers that hold text. */
|
|
28
|
+
export type TextBlockElement = 'p' | 'div' | 'pre' | 'blockquote' | 'address' | 'figcaption' | 'caption' | 'legend' | 'summary' | 'li' | 'dt' | 'dd' | 'td' | 'th';
|
|
29
|
+
/** The six HTML heading levels. */
|
|
30
|
+
export type HeadingElement = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
31
|
+
/**
|
|
32
|
+
* Anything `Typography` / `Text` can render: inline text, a text block, or a
|
|
33
|
+
* heading tag (a caption-styled heading is a normal thing to want).
|
|
34
|
+
*/
|
|
35
|
+
export type TextElement = PhrasingElement | TextBlockElement | HeadingElement;
|
|
36
|
+
/**
|
|
37
|
+
* Anything `Heading` can render. A heading is often visual rather than
|
|
38
|
+
* semantic — a stat card's big number is a `p`, not an `h2` — so the non-heading
|
|
39
|
+
* containers are allowed too. See `Heading`'s `level` prop for the styling that
|
|
40
|
+
* goes with them.
|
|
41
|
+
*/
|
|
42
|
+
export type HeadingAsElement = HeadingElement | TextBlockElement | PhrasingElement;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element unions for the `as` prop of the typographic primitives.
|
|
3
|
+
*
|
|
4
|
+
* These components spread `as` straight into JSX, so at runtime *any* intrinsic
|
|
5
|
+
* tag works. The types used to name a handful of tags each, which made ordinary
|
|
6
|
+
* usage (`as="strong"`, `as="code"`, `as="small"`) a type error for behaviour
|
|
7
|
+
* that has always worked.
|
|
8
|
+
*
|
|
9
|
+
* We deliberately do NOT use `keyof React.JSX.IntrinsicElements`:
|
|
10
|
+
*
|
|
11
|
+
* - these components take required `children`, and React throws at runtime for
|
|
12
|
+
* a void element with children (`<input>`, `<img>`, `<br>`, `<hr>`…), so the
|
|
13
|
+
* full key set would type-check code that crashes;
|
|
14
|
+
* - their props are `React.HtmlHTMLAttributes<HTMLElement>`, which cannot carry
|
|
15
|
+
* element-specific attributes (`href`, `type`, `value`), so interactive and
|
|
16
|
+
* form tags would be offered without the attributes that make them useful;
|
|
17
|
+
* - `svg`/`math` and the SVG child tags take a different attribute namespace
|
|
18
|
+
* entirely.
|
|
19
|
+
*
|
|
20
|
+
* What is left — every HTML element that holds phrasing or flow content and is
|
|
21
|
+
* styled purely by the component's own class — is exactly the set below. It is
|
|
22
|
+
* wide enough that drift is unlikely, and honest about what the component can
|
|
23
|
+
* actually render.
|
|
24
|
+
*/
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=elements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../../../src/components/elements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
package/lib/esm/package.json
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import test from 'node:test';
|
|
4
|
+
|
|
5
|
+
const read = (name) =>
|
|
6
|
+
readFileSync(new URL(`../src/components/${name}`, import.meta.url), 'utf8');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A widened union is only an improvement if every value it now admits is
|
|
10
|
+
* actually styled — a `color` the stylesheet has never heard of is a worse
|
|
11
|
+
* outcome than the type error it replaced. These tests keep the unions and the
|
|
12
|
+
* stylesheets in step.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
test('every BadgeColor has a --_badge-color rule', () => {
|
|
16
|
+
const source = read('Badge.tsx');
|
|
17
|
+
const stylesheet = read('Badge.module.css');
|
|
18
|
+
|
|
19
|
+
const union = source.match(/export type BadgeColor =([^;]+);/);
|
|
20
|
+
assert.ok(union, 'BadgeColor union not found in Badge.tsx');
|
|
21
|
+
|
|
22
|
+
const colors = [...union[1].matchAll(/'([a-z-]+)'/g)].map((m) => m[1]);
|
|
23
|
+
assert.ok(colors.length >= 6, `expected the full colour set, got ${colors}`);
|
|
24
|
+
|
|
25
|
+
for (const color of colors) {
|
|
26
|
+
assert.match(
|
|
27
|
+
stylesheet,
|
|
28
|
+
new RegExp(`\\.${color}\\s*\\{[^}]*--_badge-color:`),
|
|
29
|
+
`Badge color "${color}" is in the type union but has no rule in Badge.module.css`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('every Heading level has a .Root.levelN rule, and h1-h6 stay tag-styled', () => {
|
|
35
|
+
const source = read('Heading.tsx');
|
|
36
|
+
const stylesheet = read('Heading.module.css');
|
|
37
|
+
|
|
38
|
+
const levels = source.match(/level\?:([^;]+);/);
|
|
39
|
+
assert.ok(levels, 'level prop not found in Heading.tsx');
|
|
40
|
+
|
|
41
|
+
for (const level of [...levels[1].matchAll(/\d/g)].map((m) => m[0])) {
|
|
42
|
+
assert.match(
|
|
43
|
+
stylesheet,
|
|
44
|
+
new RegExp(`\\.Root\\.level${level}\\s*[,{]`),
|
|
45
|
+
`Heading level ${level} is accepted but has no .Root.level${level} rule`
|
|
46
|
+
);
|
|
47
|
+
assert.match(
|
|
48
|
+
stylesheet,
|
|
49
|
+
new RegExp(`h${level}\\.Root\\s*[,{]`),
|
|
50
|
+
`<h${level}> no longer picks up its heading tokens from the tag alone`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
});
|