@godxjp/ui 19.5.0 → 19.6.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/dist/components/general/typography.d.ts +7 -1
- package/dist/components/general/typography.js +20 -5
- package/dist/props/components/general.prop.d.ts +31 -1
- package/dist/styles/focus-ring.css +9 -1
- package/dist/styles/text-layout.css +11 -0
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/text.css +7 -0
- package/docs/general/typography.tsx +84 -1
- package/package.json +2 -2
|
@@ -5,7 +5,9 @@ export type { TextProp, TextProp as TextProps, HeadingProp, HeadingProp as Headi
|
|
|
5
5
|
* font-medium text-muted-foreground">`.
|
|
6
6
|
*/
|
|
7
7
|
export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
|
|
8
|
-
as?: "span" | "p" | "div" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
8
|
+
as?: "span" | "p" | "div" | "a" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
9
|
+
asChild?: import("../../props/index.js").AsChildProp;
|
|
10
|
+
link?: boolean;
|
|
9
11
|
size?: import("../../props/index.js").TextSizeProp;
|
|
10
12
|
tone?: import("../../props/index.js").TextToneProp;
|
|
11
13
|
weight?: import("../../props/index.js").FontWeightProp;
|
|
@@ -15,6 +17,10 @@ export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttrib
|
|
|
15
17
|
tabular?: boolean;
|
|
16
18
|
mono?: boolean;
|
|
17
19
|
htmlFor?: string;
|
|
20
|
+
href?: string;
|
|
21
|
+
target?: React.HTMLAttributeAnchorTarget;
|
|
22
|
+
rel?: string;
|
|
23
|
+
download?: React.AnchorHTMLAttributes<HTMLAnchorElement>["download"];
|
|
18
24
|
} & React.RefAttributes<HTMLElement>>;
|
|
19
25
|
/**
|
|
20
26
|
* Heading — h1..h4 sized from the `--heading-h*` tokens. `level` sets both the size token and the
|
|
@@ -3,16 +3,21 @@ import { cn } from "../../lib/utils.js";
|
|
|
3
3
|
const Text = React.forwardRef(
|
|
4
4
|
({
|
|
5
5
|
as = "span",
|
|
6
|
+
asChild = false,
|
|
6
7
|
size = "sm",
|
|
7
|
-
|
|
8
|
+
// `link` is an affordance, not a colour: it only moves the DEFAULT tone, so
|
|
9
|
+
// `link tone="destructive"` is a destructive link rather than an argument between two rules.
|
|
10
|
+
tone,
|
|
8
11
|
weight = "regular",
|
|
9
12
|
align,
|
|
10
13
|
truncate,
|
|
11
14
|
clamp,
|
|
12
15
|
tabular,
|
|
13
16
|
mono,
|
|
17
|
+
link,
|
|
14
18
|
className,
|
|
15
19
|
style,
|
|
20
|
+
children,
|
|
16
21
|
...props
|
|
17
22
|
}, ref) => {
|
|
18
23
|
const clampLines = typeof clamp === "number" && Number.isFinite(clamp) && clamp >= 1 ? Math.floor(clamp) : void 0;
|
|
@@ -28,11 +33,11 @@ const Text = React.forwardRef(
|
|
|
28
33
|
);
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
|
-
|
|
32
|
-
ref,
|
|
36
|
+
const typography = {
|
|
33
37
|
"data-slot": "text",
|
|
34
38
|
"data-size": size,
|
|
35
|
-
"data-tone": tone,
|
|
39
|
+
"data-tone": tone ?? (link ? "primary" : "default"),
|
|
40
|
+
"data-link": link ? "" : void 0,
|
|
36
41
|
"data-weight": weight,
|
|
37
42
|
"data-align": align,
|
|
38
43
|
"data-truncate": truncate && clampLines === void 0 ? "" : void 0,
|
|
@@ -42,7 +47,17 @@ const Text = React.forwardRef(
|
|
|
42
47
|
"data-mono": mono ? "" : void 0,
|
|
43
48
|
className: cn("ui-text", className),
|
|
44
49
|
...props
|
|
45
|
-
}
|
|
50
|
+
};
|
|
51
|
+
if (asChild) {
|
|
52
|
+
const child = React.Children.only(children);
|
|
53
|
+
return React.cloneElement(child, {
|
|
54
|
+
...typography,
|
|
55
|
+
...child.props,
|
|
56
|
+
ref,
|
|
57
|
+
className: cn(typography.className, child.props.className)
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return React.createElement(as, { ref, ...typography }, children);
|
|
46
61
|
}
|
|
47
62
|
);
|
|
48
63
|
Text.displayName = "Text";
|
|
@@ -4,7 +4,25 @@ import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSize
|
|
|
4
4
|
/** @see Text — typographic primitive; replaces hand-rolled `<span className="text-[13px] …">`. */
|
|
5
5
|
export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
|
|
6
6
|
/** Render element. Default `span`. */
|
|
7
|
-
as?: "span" | "p" | "div" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
7
|
+
as?: "span" | "p" | "div" | "a" | "label" | "strong" | "em" | "small" | "code" | "kbd" | "dt" | "dd" | "caption" | "abbr";
|
|
8
|
+
/**
|
|
9
|
+
* Render the typography onto the child element instead of emitting one — for a router link
|
|
10
|
+
* (`<Text asChild link><Link href=…>…</Link></Text>`). The child owns the element and its
|
|
11
|
+
* navigation; Text owns the type step, tone, weight and truncation.
|
|
12
|
+
*/
|
|
13
|
+
asChild?: AsChildProp;
|
|
14
|
+
/**
|
|
15
|
+
* This text IS a link: underline on hover and on keyboard focus, at the token underline offset,
|
|
16
|
+
* and the focus mark every other interactive element draws.
|
|
17
|
+
*
|
|
18
|
+
* It is an AFFORDANCE, not a colour — `tone` still owns the colour and simply defaults to
|
|
19
|
+
* `primary` here, so a destructive link (`link tone="destructive"`) reads destructive and still
|
|
20
|
+
* underlines. Use this INSTEAD of `className="text-primary hover:underline"`, and instead of
|
|
21
|
+
* `Button variant="link"` whenever the link sits in running content: `.ui-button` is a control
|
|
22
|
+
* box (`white-space: nowrap`, `flex-shrink: 0`, a `--control-height` tier and inline padding),
|
|
23
|
+
* so in a table cell it cannot wrap and cannot share the cell's line height.
|
|
24
|
+
*/
|
|
25
|
+
link?: boolean;
|
|
8
26
|
/** Size from the type scale — never an arbitrary px. Default `sm` (base). */
|
|
9
27
|
size?: TextSizeProp;
|
|
10
28
|
/** Semantic colour intent. Default `default` (foreground). */
|
|
@@ -24,6 +42,18 @@ export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
|
|
|
24
42
|
/** Monospace family (codes, ids). */
|
|
25
43
|
mono?: boolean;
|
|
26
44
|
htmlFor?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Anchor attributes, for `as="a"` (and for the `<a>` a router link supplies under `asChild`).
|
|
47
|
+
*
|
|
48
|
+
* Declared explicitly rather than by widening the base to `AnchorHTMLAttributes`, and for the
|
|
49
|
+
* same reason `htmlFor` is declared explicitly for `as="label"`: the element union is the
|
|
50
|
+
* contract, so each polymorphic branch names the attributes it actually accepts instead of every
|
|
51
|
+
* span silently offering an `href` it will never render.
|
|
52
|
+
*/
|
|
53
|
+
href?: string;
|
|
54
|
+
target?: React.HTMLAttributeAnchorTarget;
|
|
55
|
+
rel?: string;
|
|
56
|
+
download?: React.AnchorHTMLAttributes<HTMLAnchorElement>["download"];
|
|
27
57
|
};
|
|
28
58
|
/** @see Heading — h1..h4 sized from the `--heading-h*` tokens. */
|
|
29
59
|
export type HeadingProp = Omit<React.HTMLAttributes<HTMLHeadingElement>, "color"> & {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
.ui-carousel-dot,
|
|
24
24
|
.ui-rating-star,
|
|
25
25
|
a.ui-list-row,
|
|
26
|
+
.ui-text[data-link],
|
|
26
27
|
.sb-nav-item,
|
|
27
28
|
.sb-user,
|
|
28
29
|
.tb-icon-btn
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
.ui-carousel-dot,
|
|
66
67
|
.ui-rating-star,
|
|
67
68
|
a.ui-list-row,
|
|
69
|
+
.ui-text[data-link],
|
|
68
70
|
.sb-nav-item,
|
|
69
71
|
.sb-user,
|
|
70
72
|
.tb-icon-btn
|
|
@@ -81,7 +83,13 @@
|
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
:root[data-focus-outline="on"]
|
|
84
|
-
:is(
|
|
86
|
+
:is(
|
|
87
|
+
.ui-input,
|
|
88
|
+
.ui-control,
|
|
89
|
+
.ui-control-multiline,
|
|
90
|
+
.ui-control-trigger,
|
|
91
|
+
.ui-tag-input
|
|
92
|
+
):focus-visible,
|
|
85
93
|
:root[data-focus-outline="on"] .ui-control-trigger[data-state="open"],
|
|
86
94
|
:root[data-focus-outline="on"] .ui-tag-input:focus-within,
|
|
87
95
|
:root[data-focus-outline="on"] .ui-control-composite-field:focus-within,
|
|
@@ -107,6 +107,17 @@
|
|
|
107
107
|
overflow: hidden;
|
|
108
108
|
min-width: 0;
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
[data-slot="text"][data-link] {
|
|
112
|
+
text-decoration-line: none;
|
|
113
|
+
text-underline-offset: var(--text-link-underline-offset);
|
|
114
|
+
text-decoration-thickness: var(--text-link-underline-width);
|
|
115
|
+
}
|
|
116
|
+
[data-slot="text"][data-link]:hover,
|
|
117
|
+
[data-slot="text"][data-link]:focus-visible {
|
|
118
|
+
text-decoration-line: underline;
|
|
119
|
+
}
|
|
120
|
+
|
|
110
121
|
[data-slot="text"][data-tabular] {
|
|
111
122
|
font-variant-numeric: tabular-nums;
|
|
112
123
|
}
|
package/dist/tokens/base.css
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { Button, Heading, Text } from "@godxjp/ui/general";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
Table,
|
|
9
|
+
TableBody,
|
|
10
|
+
TableCell,
|
|
11
|
+
TableHead,
|
|
12
|
+
TableHeader,
|
|
13
|
+
TableRow,
|
|
14
|
+
} from "@godxjp/ui/data-display";
|
|
3
15
|
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
4
16
|
|
|
5
17
|
/**
|
|
@@ -146,6 +158,77 @@ export default function Demo() {
|
|
|
146
158
|
</Flex>
|
|
147
159
|
</CardContent>
|
|
148
160
|
</Card>
|
|
161
|
+
|
|
162
|
+
<Card>
|
|
163
|
+
<CardHeader>
|
|
164
|
+
<CardTitle level={2}>Links in running content</CardTitle>
|
|
165
|
+
<CardDescription>
|
|
166
|
+
link は色ではなく「これはリンクである」という手がかりです。ホバーだけでなく
|
|
167
|
+
キーボードフォーカスでも下線が出るため、hover: だけのユーティリティでは
|
|
168
|
+
届かない利用者にも伝わります。色は tone のままなので、tone="destructive"
|
|
169
|
+
のリンクは destructive のまま下線を引きます。
|
|
170
|
+
</CardDescription>
|
|
171
|
+
</CardHeader>
|
|
172
|
+
<CardContent>
|
|
173
|
+
<Flex direction="col" gap="md">
|
|
174
|
+
<Flex direction="row" gap="md" wrap align="center">
|
|
175
|
+
<Text as="a" href="#typography" link>
|
|
176
|
+
既定 · tone は primary
|
|
177
|
+
</Text>
|
|
178
|
+
<Text as="a" href="#typography" link tone="destructive">
|
|
179
|
+
取り消す
|
|
180
|
+
</Text>
|
|
181
|
+
<Text as="a" href="#typography" link size="xs" tone="muted">
|
|
182
|
+
すべての通知を見る
|
|
183
|
+
</Text>
|
|
184
|
+
</Flex>
|
|
185
|
+
|
|
186
|
+
{/* The case Button variant="link" cannot serve. `.ui-button` is a control box —
|
|
187
|
+
* white-space: nowrap, flex-shrink: 0, a --control-height tier and inline padding —
|
|
188
|
+
* so in a cell it neither wraps to a second line nor shares the row's line box.
|
|
189
|
+
* `<Text link>` is text, so it does both. */}
|
|
190
|
+
<Table>
|
|
191
|
+
<TableHeader>
|
|
192
|
+
<TableRow>
|
|
193
|
+
<TableHead>キー</TableHead>
|
|
194
|
+
<TableHead>件名</TableHead>
|
|
195
|
+
</TableRow>
|
|
196
|
+
</TableHeader>
|
|
197
|
+
<TableBody>
|
|
198
|
+
<TableRow>
|
|
199
|
+
<TableCell>
|
|
200
|
+
<Text size="xs" mono tone="muted">
|
|
201
|
+
PKG-128
|
|
202
|
+
</Text>
|
|
203
|
+
</TableCell>
|
|
204
|
+
<TableCell>
|
|
205
|
+
<Text as="a" href="#typography" link>
|
|
206
|
+
ログイン画面の余白が狭く、パスワード再設定リンクが本文と重なって見える
|
|
207
|
+
</Text>
|
|
208
|
+
</TableCell>
|
|
209
|
+
</TableRow>
|
|
210
|
+
<TableRow>
|
|
211
|
+
<TableCell>
|
|
212
|
+
<Text size="xs" mono tone="muted">
|
|
213
|
+
PKG-129
|
|
214
|
+
</Text>
|
|
215
|
+
</TableCell>
|
|
216
|
+
<TableCell>
|
|
217
|
+
<Text as="a" href="#typography" link>
|
|
218
|
+
請求書PDFの明細行
|
|
219
|
+
</Text>
|
|
220
|
+
</TableCell>
|
|
221
|
+
</TableRow>
|
|
222
|
+
</TableBody>
|
|
223
|
+
</Table>
|
|
224
|
+
|
|
225
|
+
<Text size="xs" tone="muted">
|
|
226
|
+
アクション(送信・展開)にはリンク風の Button variant="link"
|
|
227
|
+
を使います。本文の中のリンクは Text link です。
|
|
228
|
+
</Text>
|
|
229
|
+
</Flex>
|
|
230
|
+
</CardContent>
|
|
231
|
+
</Card>
|
|
149
232
|
</Flex>
|
|
150
233
|
</PageContainer>
|
|
151
234
|
);
|