@ps1ui/core 0.0.1 → 0.2.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/README.md +49 -0
- package/dist/base.css +56 -0
- package/dist/components/Anchor/Anchor.d.mts +2 -0
- package/dist/components/Anchor/Anchor.mjs.map +1 -1
- package/dist/components/Button/Button.d.mts +7 -1
- package/dist/components/Button/Button.mjs.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.mts +1 -0
- package/dist/components/Checkbox/Checkbox.mjs.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.d.mts +3 -0
- package/dist/components/CodeBlock/CodeBlock.mjs.map +1 -1
- package/dist/components/Container/Container.d.mts +8 -0
- package/dist/components/Container/Container.mjs.map +1 -1
- package/dist/components/Details/Details.d.mts +1 -0
- package/dist/components/Details/Details.mjs.map +1 -1
- package/dist/components/Grid/Grid.d.mts +8 -0
- package/dist/components/Grid/Grid.mjs.map +1 -1
- package/dist/components/GridItem/GridItem.d.mts +4 -0
- package/dist/components/GridItem/GridItem.mjs.map +1 -1
- package/dist/components/Heading/Heading.d.mts +4 -0
- package/dist/components/Heading/Heading.mjs.map +1 -1
- package/dist/components/List/List.d.mts +2 -0
- package/dist/components/List/List.mjs.map +1 -1
- package/dist/components/Stack/Stack.d.mts +14 -0
- package/dist/components/Stack/Stack.mjs.map +1 -1
- package/dist/components/Text/Text.d.mts +9 -1
- package/dist/components/Text/Text.mjs.map +1 -1
- package/dist/components/Textarea/Textarea.d.mts +7 -0
- package/dist/components/Textarea/Textarea.mjs +14 -0
- package/dist/components/Textarea/Textarea.mjs.map +1 -0
- package/dist/components.css +85 -159
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/styles.css +206 -7
- package/package.json +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
@ps1ui/core
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<i>For engineers who think in monospace.</i>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://koki-develop.github.io/ps1ui/">Documentation</a> | <a href="https://koki-develop.github.io/ps1ui/getting-started/">Getting Started</a> | <a href="https://koki-develop.github.io/ps1ui/components/">Components</a> | <a href="https://koki-develop.github.io/ps1ui/storybook/">Storybook</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
React 19 is a peer dependency — install it alongside the package.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @ps1ui/core react react-dom
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Getting Started
|
|
22
|
+
|
|
23
|
+
Import the stylesheet once at your app's entry point. The JS entry ships no styles — the CSS brings the design tokens, the dark canvas, and every component's styles.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import "@ps1ui/core/styles.css";
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Wrap your tree in `PS1Root`. It establishes the container-query context that responsive props resolve against — without it, responsive props silently fall back to their `base` values.
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import "@ps1ui/core/styles.css";
|
|
33
|
+
import { PS1Root, Button, Heading } from "@ps1ui/core";
|
|
34
|
+
|
|
35
|
+
export function App() {
|
|
36
|
+
return (
|
|
37
|
+
<PS1Root>
|
|
38
|
+
<Heading level={1}>Hello, PS1 UI</Heading>
|
|
39
|
+
<Button variant="primary">Click me</Button>
|
|
40
|
+
</PS1Root>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Browse the full component catalog at [koki-develop.github.io/ps1ui/components](https://koki-develop.github.io/ps1ui/components/).
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
[MIT](./LICENSE)
|
package/dist/base.css
CHANGED
|
@@ -19,6 +19,17 @@
|
|
|
19
19
|
--ps1ui-color-primary-active: #3fb950;
|
|
20
20
|
--ps1ui-color-primary-fg: #0b0f14;
|
|
21
21
|
--ps1ui-color-accent: #ffa657;
|
|
22
|
+
/* Destructive / error signalling. Hue sits in the rose-coral band the code
|
|
23
|
+
palette already inhabits (--ps1ui-code-keyword / -tag / -deleted) so the
|
|
24
|
+
surface reads as one system; luminance is tuned so the base color hits
|
|
25
|
+
≥ 4.5:1 vs BOTH --ps1ui-color-bg and --ps1ui-color-surface (verified by
|
|
26
|
+
Text.contrast.test.tsx) and danger-fg on each danger-* fill hits the
|
|
27
|
+
same threshold (verified by Button.contrast.test.tsx). Hover/active
|
|
28
|
+
progressively darken while staying above contrast. */
|
|
29
|
+
--ps1ui-color-danger: #ff7d8d;
|
|
30
|
+
--ps1ui-color-danger-hover: #f0637a;
|
|
31
|
+
--ps1ui-color-danger-active: #e04a60;
|
|
32
|
+
--ps1ui-color-danger-fg: #0b0f14;
|
|
22
33
|
--ps1ui-color-focus-ring-soft: color-mix(in srgb, var(--ps1ui-color-primary) 14%, transparent);
|
|
23
34
|
--ps1ui-shadow-focus-ring: 0 0 0 3px var(--ps1ui-color-focus-ring-soft);
|
|
24
35
|
|
|
@@ -88,6 +99,7 @@
|
|
|
88
99
|
|
|
89
100
|
--ps1ui-transition-fast: 120ms ease;
|
|
90
101
|
}
|
|
102
|
+
|
|
91
103
|
/* ==========================================================================
|
|
92
104
|
* Reset
|
|
93
105
|
* --------------------------------------------------------------------------
|
|
@@ -107,6 +119,7 @@
|
|
|
107
119
|
* layouts unless you set display:inline explicitly), <ul>/<ol> lose their
|
|
108
120
|
* bullets. Locked in by src/styles/reset.test.tsx.
|
|
109
121
|
* ========================================================================== */
|
|
122
|
+
|
|
110
123
|
/* Box model + border baseline. Applied to `*` only — NOT to ::before/::after
|
|
111
124
|
/::backdrop/::file-selector-button. Pseudo-elements with border-drawn
|
|
112
125
|
glyphs (the classic rotated-L checkmark, tooltip carets, radio-dot rings)
|
|
@@ -120,6 +133,7 @@
|
|
|
120
133
|
box-sizing: border-box;
|
|
121
134
|
border: 0 solid;
|
|
122
135
|
}
|
|
136
|
+
|
|
123
137
|
body,
|
|
124
138
|
blockquote,
|
|
125
139
|
dl,
|
|
@@ -140,6 +154,7 @@ pre,
|
|
|
140
154
|
ul {
|
|
141
155
|
margin: 0;
|
|
142
156
|
}
|
|
157
|
+
|
|
143
158
|
fieldset,
|
|
144
159
|
legend,
|
|
145
160
|
menu,
|
|
@@ -147,6 +162,7 @@ ol,
|
|
|
147
162
|
ul {
|
|
148
163
|
padding: 0;
|
|
149
164
|
}
|
|
165
|
+
|
|
150
166
|
html {
|
|
151
167
|
color-scheme: dark;
|
|
152
168
|
line-height: 1.5;
|
|
@@ -157,11 +173,13 @@ html {
|
|
|
157
173
|
tab-size: 4;
|
|
158
174
|
text-rendering: optimizeLegibility;
|
|
159
175
|
}
|
|
176
|
+
|
|
160
177
|
body {
|
|
161
178
|
min-height: 100dvh;
|
|
162
179
|
-webkit-font-smoothing: antialiased;
|
|
163
180
|
-moz-osx-font-smoothing: grayscale;
|
|
164
181
|
}
|
|
182
|
+
|
|
165
183
|
/* Heading responsibility belongs to <Heading>; raw h1..h6 inherit so a bare
|
|
166
184
|
<h1> outside <Heading> doesn't blow up to the UA default. */
|
|
167
185
|
h1,
|
|
@@ -175,15 +193,18 @@ h6 {
|
|
|
175
193
|
text-wrap: balance;
|
|
176
194
|
overflow-wrap: break-word;
|
|
177
195
|
}
|
|
196
|
+
|
|
178
197
|
p {
|
|
179
198
|
text-wrap: pretty;
|
|
180
199
|
overflow-wrap: break-word;
|
|
181
200
|
}
|
|
201
|
+
|
|
182
202
|
ol,
|
|
183
203
|
ul,
|
|
184
204
|
menu {
|
|
185
205
|
list-style: none;
|
|
186
206
|
}
|
|
207
|
+
|
|
187
208
|
img,
|
|
188
209
|
svg,
|
|
189
210
|
video,
|
|
@@ -195,17 +216,20 @@ object {
|
|
|
195
216
|
display: block;
|
|
196
217
|
vertical-align: middle;
|
|
197
218
|
}
|
|
219
|
+
|
|
198
220
|
img,
|
|
199
221
|
video {
|
|
200
222
|
max-width: 100%;
|
|
201
223
|
height: auto;
|
|
202
224
|
}
|
|
225
|
+
|
|
203
226
|
/* Anchor responsibility belongs to <Anchor>; raw <a> inherits color/decoration
|
|
204
227
|
so it doesn't paint as UA blue underline against the dark canvas. */
|
|
205
228
|
a {
|
|
206
229
|
color: inherit;
|
|
207
230
|
text-decoration: inherit;
|
|
208
231
|
}
|
|
232
|
+
|
|
209
233
|
/* UA still refuses to inherit font/color into form controls in 2026.
|
|
210
234
|
Inherit font-feature-settings / font-variation-settings too so JetBrains
|
|
211
235
|
Mono Variable's axes stay live inside <input> / <textarea>. */
|
|
@@ -224,13 +248,16 @@ textarea,
|
|
|
224
248
|
border-radius: 0;
|
|
225
249
|
opacity: 1;
|
|
226
250
|
}
|
|
251
|
+
|
|
227
252
|
:where(select:is([multiple], [size])) optgroup {
|
|
228
253
|
font-weight: bolder;
|
|
229
254
|
}
|
|
255
|
+
|
|
230
256
|
button,
|
|
231
257
|
select {
|
|
232
258
|
text-transform: none;
|
|
233
259
|
}
|
|
260
|
+
|
|
234
261
|
button,
|
|
235
262
|
input:where([type="button"], [type="reset"], [type="submit"]),
|
|
236
263
|
::file-selector-button {
|
|
@@ -238,12 +265,15 @@ input:where([type="button"], [type="reset"], [type="submit"]),
|
|
|
238
265
|
appearance: button;
|
|
239
266
|
-webkit-appearance: button;
|
|
240
267
|
}
|
|
268
|
+
|
|
241
269
|
button {
|
|
242
270
|
cursor: pointer;
|
|
243
271
|
}
|
|
272
|
+
|
|
244
273
|
textarea {
|
|
245
274
|
resize: vertical;
|
|
246
275
|
}
|
|
276
|
+
|
|
247
277
|
/* `in srgb` for consistency with the library's other color-mix calls. The
|
|
248
278
|
space is irrelevant when mixing with `transparent` (premultiplied-alpha
|
|
249
279
|
interpolation, CSS Color 4), so diverging from Tailwind Preflight's oklab
|
|
@@ -256,23 +286,28 @@ textarea {
|
|
|
256
286
|
opacity: 1;
|
|
257
287
|
color: color-mix(in srgb, currentcolor 55%, transparent);
|
|
258
288
|
}
|
|
289
|
+
|
|
259
290
|
::-webkit-date-and-time-value {
|
|
260
291
|
min-height: 1lh;
|
|
261
292
|
text-align: inherit;
|
|
262
293
|
}
|
|
294
|
+
|
|
263
295
|
::-webkit-datetime-edit {
|
|
264
296
|
display: inline-flex;
|
|
265
297
|
padding: 0;
|
|
266
298
|
}
|
|
299
|
+
|
|
267
300
|
::-webkit-datetime-edit-fields-wrapper {
|
|
268
301
|
padding: 0;
|
|
269
302
|
}
|
|
303
|
+
|
|
270
304
|
::-webkit-inner-spin-button,
|
|
271
305
|
::-webkit-outer-spin-button {
|
|
272
306
|
-webkit-appearance: none;
|
|
273
307
|
margin: 0;
|
|
274
308
|
height: auto;
|
|
275
309
|
}
|
|
310
|
+
|
|
276
311
|
/* number spinner: Chromium is already handled by ::-webkit-inner/outer-spin-button
|
|
277
312
|
{ appearance: none } above. Firefox needs its own vendor prefix — the unprefixed
|
|
278
313
|
`appearance: textfield` is deprecated per CSS UI Level 4 (moved to compatibility
|
|
@@ -280,27 +315,34 @@ textarea {
|
|
|
280
315
|
input[type="number"] {
|
|
281
316
|
-moz-appearance: textfield;
|
|
282
317
|
}
|
|
318
|
+
|
|
283
319
|
[type="search"] {
|
|
284
320
|
-webkit-appearance: textfield;
|
|
285
321
|
outline-offset: -2px;
|
|
286
322
|
}
|
|
323
|
+
|
|
287
324
|
::-webkit-search-decoration,
|
|
288
325
|
::-webkit-search-cancel-button {
|
|
289
326
|
-webkit-appearance: none;
|
|
290
327
|
}
|
|
328
|
+
|
|
291
329
|
:-moz-ui-invalid {
|
|
292
330
|
box-shadow: none;
|
|
293
331
|
}
|
|
332
|
+
|
|
294
333
|
:-moz-focusring:where(:not(iframe)) {
|
|
295
334
|
outline: auto;
|
|
296
335
|
}
|
|
336
|
+
|
|
297
337
|
b,
|
|
298
338
|
strong {
|
|
299
339
|
font-weight: bolder;
|
|
300
340
|
}
|
|
341
|
+
|
|
301
342
|
small {
|
|
302
343
|
font-size: 80%;
|
|
303
344
|
}
|
|
345
|
+
|
|
304
346
|
code,
|
|
305
347
|
kbd,
|
|
306
348
|
samp,
|
|
@@ -308,14 +350,17 @@ pre {
|
|
|
308
350
|
font-family: var(--ps1ui-font-mono);
|
|
309
351
|
font-size: 1em;
|
|
310
352
|
}
|
|
353
|
+
|
|
311
354
|
abbr:where([title]) {
|
|
312
355
|
-webkit-text-decoration: underline dotted;
|
|
313
356
|
text-decoration: underline dotted;
|
|
314
357
|
}
|
|
358
|
+
|
|
315
359
|
q::before,
|
|
316
360
|
q::after {
|
|
317
361
|
content: "";
|
|
318
362
|
}
|
|
363
|
+
|
|
319
364
|
/* Keeps sub/sup from expanding the parent line-height. */
|
|
320
365
|
sub,
|
|
321
366
|
sup {
|
|
@@ -324,34 +369,42 @@ sup {
|
|
|
324
369
|
position: relative;
|
|
325
370
|
vertical-align: baseline;
|
|
326
371
|
}
|
|
372
|
+
|
|
327
373
|
sub {
|
|
328
374
|
bottom: -0.25em;
|
|
329
375
|
}
|
|
376
|
+
|
|
330
377
|
sup {
|
|
331
378
|
top: -0.5em;
|
|
332
379
|
}
|
|
380
|
+
|
|
333
381
|
table {
|
|
334
382
|
text-indent: 0;
|
|
335
383
|
border-color: inherit;
|
|
336
384
|
border-collapse: collapse;
|
|
337
385
|
}
|
|
386
|
+
|
|
338
387
|
hr {
|
|
339
388
|
height: 0;
|
|
340
389
|
color: inherit;
|
|
341
390
|
border-top: 1px solid;
|
|
342
391
|
}
|
|
392
|
+
|
|
343
393
|
summary {
|
|
344
394
|
display: list-item;
|
|
345
395
|
}
|
|
396
|
+
|
|
346
397
|
/* [hidden] would lose to `display: flex` etc. without this. */
|
|
347
398
|
[hidden]:where(:not([hidden="until-found"])) {
|
|
348
399
|
display: none !important;
|
|
349
400
|
}
|
|
401
|
+
|
|
350
402
|
@media (prefers-reduced-motion: no-preference) {
|
|
351
403
|
html {
|
|
352
404
|
interpolate-size: allow-keywords;
|
|
353
405
|
}
|
|
354
406
|
}
|
|
407
|
+
|
|
355
408
|
/* ==========================================================================
|
|
356
409
|
* Ambient environment
|
|
357
410
|
* --------------------------------------------------------------------------
|
|
@@ -363,15 +416,18 @@ summary {
|
|
|
363
416
|
* area would reveal the light UA default and flash white on scroll. `color`
|
|
364
417
|
* and `font-family` cascade down to `body` and descendants naturally.
|
|
365
418
|
* ========================================================================== */
|
|
419
|
+
|
|
366
420
|
html {
|
|
367
421
|
background: var(--ps1ui-color-bg);
|
|
368
422
|
color: var(--ps1ui-color-fg);
|
|
369
423
|
font-family: var(--ps1ui-font-mono);
|
|
370
424
|
}
|
|
425
|
+
|
|
371
426
|
::-moz-selection {
|
|
372
427
|
background: var(--ps1ui-color-primary);
|
|
373
428
|
color: var(--ps1ui-color-primary-fg);
|
|
374
429
|
}
|
|
430
|
+
|
|
375
431
|
::selection {
|
|
376
432
|
background: var(--ps1ui-color-primary);
|
|
377
433
|
color: var(--ps1ui-color-primary-fg);
|
|
@@ -2,7 +2,9 @@ import { ComponentPropsWithoutRef, ElementType } from "react";
|
|
|
2
2
|
//#region src/components/Anchor/Anchor.d.ts
|
|
3
3
|
type AnchorVariant = "primary" | "subtle";
|
|
4
4
|
type AnchorOwnProps<E extends ElementType> = {
|
|
5
|
+
/** Element or component to render instead of the native <a> — e.g. a router Link. */
|
|
5
6
|
as?: E;
|
|
7
|
+
/** Visual style: "primary" for standalone links, "subtle" for links inside running text. */
|
|
6
8
|
variant?: AnchorVariant;
|
|
7
9
|
};
|
|
8
10
|
type AnchorProps<E extends ElementType = "a"> = AnchorOwnProps<E> & Omit<ComponentPropsWithoutRef<E>, keyof AnchorOwnProps<E>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Anchor.mjs","names":[],"sources":["../../../src/components/Anchor/Anchor.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementType } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type AnchorVariant = \"primary\" | \"subtle\";\n\ntype AnchorOwnProps<E extends ElementType> = {\n as?: E;\n variant?: AnchorVariant;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow —\n// same reasoning as Text: with a polymorphic `as` prop TypeScript cannot correctly narrow the\n// `ref` prop's type. Anchor accepts both string tags and React component types (`as={NextLink}`),\n// so a loose ref type would silently accept mismatched refs; dropping ref from the prop type is\n// safer than a misleading loose type.\nexport type AnchorProps<E extends ElementType = \"a\"> = AnchorOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof AnchorOwnProps<E>>;\n\nexport function Anchor<E extends ElementType = \"a\">({\n as,\n variant = \"primary\",\n className,\n ...rest\n}: AnchorProps<E>) {\n const tag = as ?? \"a\";\n const classes = cx(\"ps1ui-anchor\", `ps1ui-anchor--${variant}`, className);\n return createElement(tag, { ...rest, className: classes });\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Anchor.mjs","names":[],"sources":["../../../src/components/Anchor/Anchor.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementType } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type AnchorVariant = \"primary\" | \"subtle\";\n\ntype AnchorOwnProps<E extends ElementType> = {\n /** Element or component to render instead of the native <a> — e.g. a router Link. */\n as?: E;\n /** Visual style: \"primary\" for standalone links, \"subtle\" for links inside running text. */\n variant?: AnchorVariant;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow —\n// same reasoning as Text: with a polymorphic `as` prop TypeScript cannot correctly narrow the\n// `ref` prop's type. Anchor accepts both string tags and React component types (`as={NextLink}`),\n// so a loose ref type would silently accept mismatched refs; dropping ref from the prop type is\n// safer than a misleading loose type.\nexport type AnchorProps<E extends ElementType = \"a\"> = AnchorOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof AnchorOwnProps<E>>;\n\nexport function Anchor<E extends ElementType = \"a\">({\n as,\n variant = \"primary\",\n className,\n ...rest\n}: AnchorProps<E>) {\n const tag = as ?? \"a\";\n const classes = cx(\"ps1ui-anchor\", `ps1ui-anchor--${variant}`, className);\n return createElement(tag, { ...rest, className: classes });\n}\n"],"mappings":";;;AAqBA,SAAgB,OAAoC,EAClD,IACA,UAAU,WACV,WACA,GAAG,QACc;CACjB,MAAM,MAAM,MAAM;CAClB,MAAM,UAAU,GAAG,gBAAgB,iBAAiB,WAAW,SAAS;CACxE,OAAO,cAAc,KAAK;EAAE,GAAG;EAAM,WAAW;CAAQ,CAAC;AAC3D"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, ElementType } from "react";
|
|
2
2
|
//#region src/components/Button/Button.d.ts
|
|
3
|
-
type ButtonVariant = "primary" | "secondary";
|
|
3
|
+
type ButtonVariant = "primary" | "secondary" | "danger";
|
|
4
4
|
type ButtonOwnProps<E extends ElementType> = {
|
|
5
|
+
/** Element or component to render instead of the native <button> — e.g. "a" or a router Link. */
|
|
5
6
|
as?: E;
|
|
7
|
+
/** Visual style: "primary" for the main action, "secondary" for supporting actions, "danger" for destructive actions. */
|
|
6
8
|
variant?: ButtonVariant;
|
|
7
9
|
};
|
|
8
10
|
/**
|
|
@@ -16,6 +18,10 @@ type ButtonOwnProps<E extends ElementType> = {
|
|
|
16
18
|
* unavailable, render a native `<Button disabled>` (or no link at all) instead of a
|
|
17
19
|
* link. Untyped JS callers and `as={Component}` escapes that pass `disabled` anyway
|
|
18
20
|
* get a leaked no-op attribute — no visual or behavioral disabling happens.
|
|
21
|
+
*
|
|
22
|
+
* `type` on the native tag: when rendering a native <button>, `type` defaults to
|
|
23
|
+
* "button" (not the browser's implicit "submit"), so a Button inside a <form>
|
|
24
|
+
* never submits implicitly — pass type="submit" explicitly to submit.
|
|
19
25
|
*/
|
|
20
26
|
type ButtonProps<E extends ElementType = "button"> = ButtonOwnProps<E> & Omit<ComponentPropsWithoutRef<E>, keyof ButtonOwnProps<E>>;
|
|
21
27
|
declare function Button<E extends ElementType = "button">({ as, variant, className, ...rest }: ButtonProps<E>): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.mjs","names":[],"sources":["../../../src/components/Button/Button.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementType } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type ButtonVariant = \"primary\" | \"secondary\";\n\ntype ButtonOwnProps<E extends ElementType> = {\n as?: E;\n variant?: ButtonVariant;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow —\n// same reasoning as Anchor / Text: with a polymorphic `as` prop TypeScript cannot correctly\n// narrow the `ref` prop's type against the resolved element E. Button accepts both string tags\n// (`as=\"a\"`) and React component types (`as={NextLink}`) so consumers can render a link that\n// looks like a button; a loose ref type would silently accept mismatched refs, so dropping ref\n// from the prop type is safer than a misleading loose type.\n/**\n * Props for {@link Button}. Derived from the props of the rendered element `E`,\n * so what's accepted follows the `as` target.\n *\n * `disabled` and polymorphism: `disabled` only exists on form elements, so\n * `<Button as=\"a\" href=\"…\" disabled>` is a type error (`ComponentPropsWithoutRef<\"a\">`\n * has no `disabled` — locked in by `Button.test-d.tsx`). This is intentional and\n * matches the ARIA Authoring Practices: links are not disabled. When the action is\n * unavailable, render a native `<Button disabled>` (or no link at all) instead of a\n * link. Untyped JS callers and `as={Component}` escapes that pass `disabled` anyway\n * get a leaked no-op attribute — no visual or behavioral disabling happens.\n */\nexport type ButtonProps<E extends ElementType = \"button\"> = ButtonOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof ButtonOwnProps<E>>;\n\nexport function Button<E extends ElementType = \"button\">({\n as,\n variant = \"primary\",\n className,\n ...rest\n}: ButtonProps<E>) {\n const tag: ElementType = as ?? \"button\";\n const classes = cx(\"ps1ui-button\", `ps1ui-button--${variant}`, className);\n const props: Record<string, unknown> = { ...rest, className: classes };\n // `type=\"button\"` is a defensive default so a native <button> inside a <form> never\n // submits implicitly. It only makes sense on the native tag — <a>, <NextLink>, and\n // other host/component targets have no such attribute, and stamping one on them\n // would leak an invalid attribute through to the DOM. Explicit callers still win.\n if (tag === \"button\" && props.type === undefined) {\n props.type = \"button\";\n }\n return createElement(tag, props);\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Button.mjs","names":[],"sources":["../../../src/components/Button/Button.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementType } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type ButtonVariant = \"primary\" | \"secondary\" | \"danger\";\n\ntype ButtonOwnProps<E extends ElementType> = {\n /** Element or component to render instead of the native <button> — e.g. \"a\" or a router Link. */\n as?: E;\n /** Visual style: \"primary\" for the main action, \"secondary\" for supporting actions, \"danger\" for destructive actions. */\n variant?: ButtonVariant;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow —\n// same reasoning as Anchor / Text: with a polymorphic `as` prop TypeScript cannot correctly\n// narrow the `ref` prop's type against the resolved element E. Button accepts both string tags\n// (`as=\"a\"`) and React component types (`as={NextLink}`) so consumers can render a link that\n// looks like a button; a loose ref type would silently accept mismatched refs, so dropping ref\n// from the prop type is safer than a misleading loose type.\n/**\n * Props for {@link Button}. Derived from the props of the rendered element `E`,\n * so what's accepted follows the `as` target.\n *\n * `disabled` and polymorphism: `disabled` only exists on form elements, so\n * `<Button as=\"a\" href=\"…\" disabled>` is a type error (`ComponentPropsWithoutRef<\"a\">`\n * has no `disabled` — locked in by `Button.test-d.tsx`). This is intentional and\n * matches the ARIA Authoring Practices: links are not disabled. When the action is\n * unavailable, render a native `<Button disabled>` (or no link at all) instead of a\n * link. Untyped JS callers and `as={Component}` escapes that pass `disabled` anyway\n * get a leaked no-op attribute — no visual or behavioral disabling happens.\n *\n * `type` on the native tag: when rendering a native <button>, `type` defaults to\n * \"button\" (not the browser's implicit \"submit\"), so a Button inside a <form>\n * never submits implicitly — pass type=\"submit\" explicitly to submit.\n */\nexport type ButtonProps<E extends ElementType = \"button\"> = ButtonOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof ButtonOwnProps<E>>;\n\nexport function Button<E extends ElementType = \"button\">({\n as,\n variant = \"primary\",\n className,\n ...rest\n}: ButtonProps<E>) {\n const tag: ElementType = as ?? \"button\";\n const classes = cx(\"ps1ui-button\", `ps1ui-button--${variant}`, className);\n const props: Record<string, unknown> = { ...rest, className: classes };\n // `type=\"button\"` is a defensive default so a native <button> inside a <form> never\n // submits implicitly. It only makes sense on the native tag — <a>, <NextLink>, and\n // other host/component targets have no such attribute, and stamping one on them\n // would leak an invalid attribute through to the DOM. Explicit callers still win.\n if (tag === \"button\" && props.type === undefined) {\n props.type = \"button\";\n }\n return createElement(tag, props);\n}\n"],"mappings":";;;AAsCA,SAAgB,OAAyC,EACvD,IACA,UAAU,WACV,WACA,GAAG,QACc;CACjB,MAAM,MAAmB,MAAM;CAC/B,MAAM,UAAU,GAAG,gBAAgB,iBAAiB,WAAW,SAAS;CACxE,MAAM,QAAiC;EAAE,GAAG;EAAM,WAAW;CAAQ;CAKrE,IAAI,QAAQ,YAAY,MAAM,SAAS,KAAA,GACrC,MAAM,OAAO;CAEf,OAAO,cAAc,KAAK,KAAK;AACjC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ComponentProps } from "react";
|
|
2
2
|
//#region src/components/Checkbox/Checkbox.d.ts
|
|
3
3
|
type CheckboxProps = Omit<ComponentProps<"input">, "type"> & {
|
|
4
|
+
/** Render the indeterminate ("mixed") visual state. Purely visual — checked is unaffected. */
|
|
4
5
|
indeterminate?: boolean;
|
|
5
6
|
};
|
|
6
7
|
declare function Checkbox({ className, indeterminate, ref: forwardedRef, ...rest }: CheckboxProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.mjs","names":[],"sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport { useLayoutEffect, useRef, type ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { useMergedRef } from \"../../utils/useMergedRef\";\n\nexport type CheckboxProps = Omit<ComponentProps<\"input\">, \"type\"> & {\n indeterminate?: boolean;\n};\n\nexport function Checkbox({\n className,\n indeterminate = false,\n ref: forwardedRef,\n ...rest\n}: CheckboxProps) {\n const localRef = useRef<HTMLInputElement>(null);\n\n // useLayoutEffect syncs .indeterminate before paint, avoiding a ✓-glyph flash on mount.\n useLayoutEffect(() => {\n localRef.current!.indeterminate = indeterminate;\n }, [indeterminate]);\n\n // Both the indeterminate sync above and the caller get the <input> node.\n const mergedRef = useMergedRef(localRef, forwardedRef);\n\n return (\n <input {...rest} ref={mergedRef} type=\"checkbox\" className={cx(\"ps1ui-checkbox\", className)} />\n );\n}\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"Checkbox.mjs","names":[],"sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport { useLayoutEffect, useRef, type ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { useMergedRef } from \"../../utils/useMergedRef\";\n\nexport type CheckboxProps = Omit<ComponentProps<\"input\">, \"type\"> & {\n /** Render the indeterminate (\"mixed\") visual state. Purely visual — checked is unaffected. */\n indeterminate?: boolean;\n};\n\nexport function Checkbox({\n className,\n indeterminate = false,\n ref: forwardedRef,\n ...rest\n}: CheckboxProps) {\n const localRef = useRef<HTMLInputElement>(null);\n\n // useLayoutEffect syncs .indeterminate before paint, avoiding a ✓-glyph flash on mount.\n useLayoutEffect(() => {\n localRef.current!.indeterminate = indeterminate;\n }, [indeterminate]);\n\n // Both the indeterminate sync above and the caller get the <input> node.\n const mergedRef = useMergedRef(localRef, forwardedRef);\n\n return (\n <input {...rest} ref={mergedRef} type=\"checkbox\" className={cx(\"ps1ui-checkbox\", className)} />\n );\n}\n"],"mappings":";;;;;;AAWA,SAAgB,SAAS,EACvB,WACA,gBAAgB,OAChB,KAAK,cACL,GAAG,QACa;CAChB,MAAM,WAAW,OAAyB,IAAI;CAG9C,sBAAsB;EACpB,SAAS,QAAS,gBAAgB;CACpC,GAAG,CAAC,aAAa,CAAC;CAGlB,MAAM,YAAY,aAAa,UAAU,YAAY;CAErD,OACE,oBAAC,SAAD;EAAO,GAAI;EAAM,KAAK;EAAW,MAAK;EAAW,WAAW,GAAG,kBAAkB,SAAS;CAAI,CAAA;AAElG"}
|
|
@@ -2,8 +2,11 @@ import { CodeBlockLanguage } from "./refractor.mjs";
|
|
|
2
2
|
import { ComponentProps } from "react";
|
|
3
3
|
//#region src/components/CodeBlock/CodeBlock.d.ts
|
|
4
4
|
type CodeBlockProps = Omit<ComponentProps<"pre">, "children"> & {
|
|
5
|
+
/** Code to render. Takes precedence over children; use it where JSX children get rewrapped (e.g. Astro islands). */
|
|
5
6
|
code?: string;
|
|
7
|
+
/** Code to render, as the element's only child. */
|
|
6
8
|
children?: string;
|
|
9
|
+
/** Prism language name or alias. Unknown or omitted values render as plain text. */
|
|
7
10
|
language?: CodeBlockLanguage | (string & {});
|
|
8
11
|
};
|
|
9
12
|
declare function CodeBlock({ code, children, language, className, onBlur, ref: forwardedRef, ...rest }: CodeBlockProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.mjs","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["\"use client\";\n\nimport { Fragment, useLayoutEffect, useMemo, type ComponentProps } from \"react\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport { toJsxRuntime } from \"hast-util-to-jsx-runtime\";\nimport { cx } from \"../../utils/cx\";\nimport { useMergedRef } from \"../../utils/useMergedRef\";\nimport { useScrollableFocus } from \"../../utils/useScrollableFocus\";\nimport { refractor, type CodeBlockLanguage } from \"./refractor\";\n\nexport type { CodeBlockLanguage };\n\n// `language` is a new prop (not the native HTML `lang` attribute). HTML `lang`\n// is a BCP47 natural-language tag (\"en\", \"ja\") — a different concept that\n// remains part of the base <pre> attrs and passes through untouched. See\n// CodeBlock.test.tsx for the passthrough assertion.\n//\n// `code` is an alternative to `children` for environments that wrap JSX\n// children on the way to a React tree — e.g. Astro's `.astro` → React island\n// boundary rewraps `children` as an AstroComponentInstance, breaking the\n// `children: string` contract. Named props are passed through as-is, so\n// `<CodeBlock code={snippet}>` survives that boundary. `code` wins when both\n// are supplied; the same string appears in the rendered DOM either way.\nexport type CodeBlockProps = Omit<ComponentProps<\"pre\">, \"children\"> & {\n code?: string;\n children?: string;\n // `CodeBlockLanguage | (string & {})` is TypeScript's \"loose union\" pattern:\n // canonical language names surface in autocomplete, but aliases (`ts`, `html`, ...)\n // and dynamically-sourced strings (e.g. from a markdown fenced-code parser) still\n // pass through the type and are resolved at runtime via refractor's alias table.\n language?: CodeBlockLanguage | (string & {});\n};\n\nexport function CodeBlock({\n code,\n children,\n language,\n className,\n onBlur,\n ref: forwardedRef,\n ...rest\n}: CodeBlockProps) {\n // `code` takes precedence — see the type doc for the Astro/RSC-wrapped-children\n // rationale. Empty string is the \"neither provided\" fallback so the component\n // renders a valid empty <pre> instead of throwing on `.highlight(undefined)`.\n const source = code ?? children ?? \"\";\n // `registered` captures both \"language was provided\" and \"refractor knows it\" —\n // used for the highlight path, the language-<x> class, and to keep the class\n // off unhighlighted blocks (so downstream tools and consumer Prism themes\n // don't mistake a raw-text fallback for a highlighted block).\n //\n // useMemo keyed on (children, language) collapses repeated tokenization when a\n // frequently-re-rendering parent forces this component to re-render with the\n // same code — Prism tokenization of a multi-KB snippet + hast → JSX rebuild\n // is not cheap.\n const { highlighted, registered } = useMemo(() => {\n const isRegistered = !!language && refractor.registered(language);\n return {\n registered: isRegistered,\n highlighted: isRegistered\n ? toJsxRuntime(refractor.highlight(source, language), { Fragment, jsx, jsxs })\n : source,\n };\n }, [source, language]);\n\n // Keyboard reachability of the <pre> (its own scroll container) — tabIndex\n // only while the code actually overflows, kept while focused, safe-side\n // under static SSR — is the shared useScrollableFocus contract (see the\n // hook's header for the full account). The overflowing content is the\n // inline <code>, whose box a ResizeObserver can't watch, so content-driven\n // re-measures are keyed on the source string instead.\n const { scrollerRef, tabIndex, measure } = useScrollableFocus<HTMLPreElement>();\n useLayoutEffect(() => measure(), [measure, source]);\n\n // Merge the caller's ref with the hook's so both get the <pre> node.\n const mergedRef = useMergedRef(scrollerRef, forwardedRef);\n\n return (\n <pre\n // oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- axe scrollable-region-focusable requires the <pre> be keyboard-reachable when its content overflows; useScrollableFocus gates this on measured overflow so short snippets stay out of the tab order.\n tabIndex={tabIndex}\n {...rest}\n ref={mergedRef}\n className={cx(\"ps1ui-codeblock\", className)}\n // Chained (not spread) so the caller's handler still runs: the\n // re-measure drops the kept-while-focused tab stop once focus leaves —\n // see useScrollableFocus.\n onBlur={(event) => {\n onBlur?.(event);\n measure();\n }}\n >\n <code className={registered ? `language-${language}` : undefined}>{highlighted}</code>\n </pre>\n );\n}\n"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"CodeBlock.mjs","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["\"use client\";\n\nimport { Fragment, useLayoutEffect, useMemo, type ComponentProps } from \"react\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport { toJsxRuntime } from \"hast-util-to-jsx-runtime\";\nimport { cx } from \"../../utils/cx\";\nimport { useMergedRef } from \"../../utils/useMergedRef\";\nimport { useScrollableFocus } from \"../../utils/useScrollableFocus\";\nimport { refractor, type CodeBlockLanguage } from \"./refractor\";\n\nexport type { CodeBlockLanguage };\n\n// `language` is a new prop (not the native HTML `lang` attribute). HTML `lang`\n// is a BCP47 natural-language tag (\"en\", \"ja\") — a different concept that\n// remains part of the base <pre> attrs and passes through untouched. See\n// CodeBlock.test.tsx for the passthrough assertion.\n//\n// `code` is an alternative to `children` for environments that wrap JSX\n// children on the way to a React tree — e.g. Astro's `.astro` → React island\n// boundary rewraps `children` as an AstroComponentInstance, breaking the\n// `children: string` contract. Named props are passed through as-is, so\n// `<CodeBlock code={snippet}>` survives that boundary. `code` wins when both\n// are supplied; the same string appears in the rendered DOM either way.\nexport type CodeBlockProps = Omit<ComponentProps<\"pre\">, \"children\"> & {\n /** Code to render. Takes precedence over children; use it where JSX children get rewrapped (e.g. Astro islands). */\n code?: string;\n /** Code to render, as the element's only child. */\n children?: string;\n // `CodeBlockLanguage | (string & {})` is TypeScript's \"loose union\" pattern:\n // canonical language names surface in autocomplete, but aliases (`ts`, `html`, ...)\n // and dynamically-sourced strings (e.g. from a markdown fenced-code parser) still\n // pass through the type and are resolved at runtime via refractor's alias table.\n /** Prism language name or alias. Unknown or omitted values render as plain text. */\n language?: CodeBlockLanguage | (string & {});\n};\n\nexport function CodeBlock({\n code,\n children,\n language,\n className,\n onBlur,\n ref: forwardedRef,\n ...rest\n}: CodeBlockProps) {\n // `code` takes precedence — see the type doc for the Astro/RSC-wrapped-children\n // rationale. Empty string is the \"neither provided\" fallback so the component\n // renders a valid empty <pre> instead of throwing on `.highlight(undefined)`.\n const source = code ?? children ?? \"\";\n // `registered` captures both \"language was provided\" and \"refractor knows it\" —\n // used for the highlight path, the language-<x> class, and to keep the class\n // off unhighlighted blocks (so downstream tools and consumer Prism themes\n // don't mistake a raw-text fallback for a highlighted block).\n //\n // useMemo keyed on (children, language) collapses repeated tokenization when a\n // frequently-re-rendering parent forces this component to re-render with the\n // same code — Prism tokenization of a multi-KB snippet + hast → JSX rebuild\n // is not cheap.\n const { highlighted, registered } = useMemo(() => {\n const isRegistered = !!language && refractor.registered(language);\n return {\n registered: isRegistered,\n highlighted: isRegistered\n ? toJsxRuntime(refractor.highlight(source, language), { Fragment, jsx, jsxs })\n : source,\n };\n }, [source, language]);\n\n // Keyboard reachability of the <pre> (its own scroll container) — tabIndex\n // only while the code actually overflows, kept while focused, safe-side\n // under static SSR — is the shared useScrollableFocus contract (see the\n // hook's header for the full account). The overflowing content is the\n // inline <code>, whose box a ResizeObserver can't watch, so content-driven\n // re-measures are keyed on the source string instead.\n const { scrollerRef, tabIndex, measure } = useScrollableFocus<HTMLPreElement>();\n useLayoutEffect(() => measure(), [measure, source]);\n\n // Merge the caller's ref with the hook's so both get the <pre> node.\n const mergedRef = useMergedRef(scrollerRef, forwardedRef);\n\n return (\n <pre\n // oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- axe scrollable-region-focusable requires the <pre> be keyboard-reachable when its content overflows; useScrollableFocus gates this on measured overflow so short snippets stay out of the tab order.\n tabIndex={tabIndex}\n {...rest}\n ref={mergedRef}\n className={cx(\"ps1ui-codeblock\", className)}\n // Chained (not spread) so the caller's handler still runs: the\n // re-measure drops the kept-while-focused tab stop once focus leaves —\n // see useScrollableFocus.\n onBlur={(event) => {\n onBlur?.(event);\n measure();\n }}\n >\n <code className={registered ? `language-${language}` : undefined}>{highlighted}</code>\n </pre>\n );\n}\n"],"mappings":";;;;;;;;;AAoCA,SAAgB,UAAU,EACxB,MACA,UACA,UACA,WACA,QACA,KAAK,cACL,GAAG,QACc;CAIjB,MAAM,SAAS,QAAQ,YAAY;CAUnC,MAAM,EAAE,aAAa,eAAe,cAAc;EAChD,MAAM,eAAe,CAAC,CAAC,YAAY,UAAU,WAAW,QAAQ;EAChE,OAAO;GACL,YAAY;GACZ,aAAa,eACT,aAAa,UAAU,UAAU,QAAQ,QAAQ,GAAG;IAAE;IAAU;IAAK;GAAK,CAAC,IAC3E;EACN;CACF,GAAG,CAAC,QAAQ,QAAQ,CAAC;CAQrB,MAAM,EAAE,aAAa,UAAU,YAAY,mBAAmC;CAC9E,sBAAsB,QAAQ,GAAG,CAAC,SAAS,MAAM,CAAC;CAGlD,MAAM,YAAY,aAAa,aAAa,YAAY;CAExD,OACE,oBAAC,OAAD;EAEY;EACV,GAAI;EACJ,KAAK;EACL,WAAW,GAAG,mBAAmB,SAAS;EAI1C,SAAS,UAAU;GACjB,SAAS,KAAK;GACd,QAAQ;EACV;YAEA,oBAAC,QAAD;GAAM,WAAW,aAAa,YAAY,aAAa,KAAA;aAAY;EAAkB,CAAA;CAClF,CAAA;AAET"}
|
|
@@ -4,7 +4,15 @@ import { ComponentProps } from "react";
|
|
|
4
4
|
//#region src/components/Container/Container.d.ts
|
|
5
5
|
type ContainerSize = "sm" | "md" | "lg" | "xl" | "full";
|
|
6
6
|
type ContainerProps = ComponentProps<"div"> & {
|
|
7
|
+
/**
|
|
8
|
+
* Max-width preset; "full" removes the cap.
|
|
9
|
+
* @default "lg"
|
|
10
|
+
*/
|
|
7
11
|
size?: Responsive<ContainerSize>;
|
|
12
|
+
/**
|
|
13
|
+
* Horizontal padding on the space scale.
|
|
14
|
+
* @default "lg"
|
|
15
|
+
*/
|
|
8
16
|
px?: Responsive<SpaceScale>;
|
|
9
17
|
};
|
|
10
18
|
declare function Container({ size, px, className, style, ...rest }: ContainerProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Container.mjs","names":[],"sources":["../../../src/components/Container/Container.tsx"],"sourcesContent":["import type { ComponentProps, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\nimport { spaceToVar, type SpaceScale } from \"../../utils/spacing\";\n\nexport type ContainerSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport type ContainerProps = ComponentProps<\"div\"> & {\n size?: Responsive<ContainerSize>;\n px?: Responsive<SpaceScale>;\n};\n\n// size → max-width. `full` maps to `none` (unbounded), the rest reference\n// the --ps1ui-container-* max-width tokens in tokens.css.\nconst sizeToVar = (v: ContainerSize): string =>\n v === \"full\" ? \"none\" : `var(--ps1ui-container-${v})`;\n\nexport function Container({ size, px, className, style, ...rest }: ContainerProps) {\n const sizeVars = resolveResponsive(size, \"--_container-size\", sizeToVar);\n const pxVars = resolveResponsive(px, \"--_container-px\", spaceToVar);\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...sizeVars,\n ...pxVars,\n } as CSSProperties;\n return <div {...rest} className={cx(\"ps1ui-container\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"Container.mjs","names":[],"sources":["../../../src/components/Container/Container.tsx"],"sourcesContent":["import type { ComponentProps, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\nimport { spaceToVar, type SpaceScale } from \"../../utils/spacing\";\n\nexport type ContainerSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport type ContainerProps = ComponentProps<\"div\"> & {\n /**\n * Max-width preset; \"full\" removes the cap.\n * @default \"lg\"\n */\n size?: Responsive<ContainerSize>;\n /**\n * Horizontal padding on the space scale.\n * @default \"lg\"\n */\n px?: Responsive<SpaceScale>;\n};\n\n// size → max-width. `full` maps to `none` (unbounded), the rest reference\n// the --ps1ui-container-* max-width tokens in tokens.css.\nconst sizeToVar = (v: ContainerSize): string =>\n v === \"full\" ? \"none\" : `var(--ps1ui-container-${v})`;\n\nexport function Container({ size, px, className, style, ...rest }: ContainerProps) {\n const sizeVars = resolveResponsive(size, \"--_container-size\", sizeToVar);\n const pxVars = resolveResponsive(px, \"--_container-px\", spaceToVar);\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...sizeVars,\n ...pxVars,\n } as CSSProperties;\n return <div {...rest} className={cx(\"ps1ui-container\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;AAsBA,MAAM,aAAa,MACjB,MAAM,SAAS,SAAS,yBAAyB,EAAE;AAErD,SAAgB,UAAU,EAAE,MAAM,IAAI,WAAW,OAAO,GAAG,QAAwB;CACjF,MAAM,WAAW,kBAAkB,MAAM,qBAAqB,SAAS;CACvE,MAAM,SAAS,kBAAkB,IAAI,mBAAmB,UAAU;CAGlE,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;EACH,GAAG;CACL;CACA,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,GAAG,mBAAmB,SAAS;EAAG,OAAO;CAAc,CAAA;AAC1F"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ComponentProps, ReactNode } from "react";
|
|
2
2
|
//#region src/components/Details/Details.d.ts
|
|
3
3
|
type DetailsProps = ComponentProps<"details"> & {
|
|
4
|
+
/** Content of the always-visible summary row. */
|
|
4
5
|
summary: ReactNode;
|
|
5
6
|
};
|
|
6
7
|
declare function Details({ summary, children, className, ...rest }: DetailsProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Details.mjs","names":[],"sources":["../../../src/components/Details/Details.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type DetailsProps = ComponentProps<\"details\"> & {\n summary: ReactNode;\n};\n\nexport function Details({ summary, children, className, ...rest }: DetailsProps) {\n return (\n <details {...rest} className={cx(\"ps1ui-details\", className)}>\n <summary className=\"ps1ui-details__summary\">{summary}</summary>\n <div className=\"ps1ui-details__body\">{children}</div>\n </details>\n );\n}\n"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Details.mjs","names":[],"sources":["../../../src/components/Details/Details.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type DetailsProps = ComponentProps<\"details\"> & {\n /** Content of the always-visible summary row. */\n summary: ReactNode;\n};\n\nexport function Details({ summary, children, className, ...rest }: DetailsProps) {\n return (\n <details {...rest} className={cx(\"ps1ui-details\", className)}>\n <summary className=\"ps1ui-details__summary\">{summary}</summary>\n <div className=\"ps1ui-details__body\">{children}</div>\n </details>\n );\n}\n"],"mappings":";;;AAQA,SAAgB,QAAQ,EAAE,SAAS,UAAU,WAAW,GAAG,QAAsB;CAC/E,OACE,qBAAC,WAAD;EAAS,GAAI;EAAM,WAAW,GAAG,iBAAiB,SAAS;YAA3D,CACE,oBAAC,WAAD;GAAS,WAAU;aAA0B;EAAiB,CAAA,GAC9D,oBAAC,OAAD;GAAK,WAAU;GAAuB;EAAc,CAAA,CAC7C;;AAEb"}
|
|
@@ -4,7 +4,15 @@ import { ComponentProps } from "react";
|
|
|
4
4
|
//#region src/components/Grid/Grid.d.ts
|
|
5
5
|
type GridGap = SpaceScale;
|
|
6
6
|
type GridProps = ComponentProps<"div"> & {
|
|
7
|
+
/**
|
|
8
|
+
* Number of equal-width columns.
|
|
9
|
+
* @default 1
|
|
10
|
+
*/
|
|
7
11
|
columns?: Responsive<number>;
|
|
12
|
+
/**
|
|
13
|
+
* Gap between cells on the space scale.
|
|
14
|
+
* @default "md"
|
|
15
|
+
*/
|
|
8
16
|
gap?: Responsive<GridGap>;
|
|
9
17
|
};
|
|
10
18
|
declare function Grid({ columns, gap, className, style, ...rest }: GridProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Grid.mjs","names":[],"sources":["../../../src/components/Grid/Grid.tsx"],"sourcesContent":["import type { ComponentProps, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { safePositiveInt } from \"../../utils/numbers\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\nimport { spaceToVar, type SpaceScale } from \"../../utils/spacing\";\n\nexport type GridGap = SpaceScale;\n\nexport type GridProps = ComponentProps<\"div\"> & {\n columns?: Responsive<number>;\n gap?: Responsive<GridGap>;\n};\n\nexport function Grid({ columns, gap, className, style, ...rest }: GridProps) {\n // `repeat(N, ...)` requires N ≥ 1 integer — `safePositiveInt` clamps at\n // the system boundary. See utils/numbers.ts for the full rationale.\n const columnsVars = resolveResponsive(columns, \"--_grid-columns\", safePositiveInt);\n const gapVars = resolveResponsive(gap, \"--_grid-gap\", spaceToVar);\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...columnsVars,\n ...gapVars,\n } as CSSProperties;\n return <div {...rest} className={cx(\"ps1ui-grid\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"Grid.mjs","names":[],"sources":["../../../src/components/Grid/Grid.tsx"],"sourcesContent":["import type { ComponentProps, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { safePositiveInt } from \"../../utils/numbers\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\nimport { spaceToVar, type SpaceScale } from \"../../utils/spacing\";\n\nexport type GridGap = SpaceScale;\n\nexport type GridProps = ComponentProps<\"div\"> & {\n /**\n * Number of equal-width columns.\n * @default 1\n */\n columns?: Responsive<number>;\n /**\n * Gap between cells on the space scale.\n * @default \"md\"\n */\n gap?: Responsive<GridGap>;\n};\n\nexport function Grid({ columns, gap, className, style, ...rest }: GridProps) {\n // `repeat(N, ...)` requires N ≥ 1 integer — `safePositiveInt` clamps at\n // the system boundary. See utils/numbers.ts for the full rationale.\n const columnsVars = resolveResponsive(columns, \"--_grid-columns\", safePositiveInt);\n const gapVars = resolveResponsive(gap, \"--_grid-gap\", spaceToVar);\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...columnsVars,\n ...gapVars,\n } as CSSProperties;\n return <div {...rest} className={cx(\"ps1ui-grid\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,KAAK,EAAE,SAAS,KAAK,WAAW,OAAO,GAAG,QAAmB;CAG3E,MAAM,cAAc,kBAAkB,SAAS,mBAAmB,eAAe;CACjF,MAAM,UAAU,kBAAkB,KAAK,eAAe,UAAU;CAGhE,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;EACH,GAAG;CACL;CACA,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,GAAG,cAAc,SAAS;EAAG,OAAO;CAAc,CAAA;AACrF"}
|
|
@@ -2,6 +2,10 @@ import { Responsive } from "../../utils/responsive.mjs";
|
|
|
2
2
|
import { ComponentProps } from "react";
|
|
3
3
|
//#region src/components/GridItem/GridItem.d.ts
|
|
4
4
|
type GridItemProps = ComponentProps<"div"> & {
|
|
5
|
+
/**
|
|
6
|
+
* Number of grid columns the item spans.
|
|
7
|
+
* @default 1
|
|
8
|
+
*/
|
|
5
9
|
colSpan?: Responsive<number>;
|
|
6
10
|
};
|
|
7
11
|
declare function GridItem({ colSpan, className, style, ...rest }: GridItemProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GridItem.mjs","names":[],"sources":["../../../src/components/GridItem/GridItem.tsx"],"sourcesContent":["import type { ComponentProps, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { safePositiveInt } from \"../../utils/numbers\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\n\nexport type GridItemProps = ComponentProps<\"div\"> & {\n colSpan?: Responsive<number>;\n};\n\nexport function GridItem({ colSpan, className, style, ...rest }: GridItemProps) {\n // `grid-column: span N` requires N ≥ 1 integer — `safePositiveInt` clamps\n // at the system boundary. See utils/numbers.ts for the full rationale.\n const colSpanVars = resolveResponsive(colSpan, \"--_griditem-col-span\", safePositiveInt);\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...colSpanVars,\n } as CSSProperties;\n return <div {...rest} className={cx(\"ps1ui-griditem\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"GridItem.mjs","names":[],"sources":["../../../src/components/GridItem/GridItem.tsx"],"sourcesContent":["import type { ComponentProps, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { safePositiveInt } from \"../../utils/numbers\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\n\nexport type GridItemProps = ComponentProps<\"div\"> & {\n /**\n * Number of grid columns the item spans.\n * @default 1\n */\n colSpan?: Responsive<number>;\n};\n\nexport function GridItem({ colSpan, className, style, ...rest }: GridItemProps) {\n // `grid-column: span N` requires N ≥ 1 integer — `safePositiveInt` clamps\n // at the system boundary. See utils/numbers.ts for the full rationale.\n const colSpanVars = resolveResponsive(colSpan, \"--_griditem-col-span\", safePositiveInt);\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...colSpanVars,\n } as CSSProperties;\n return <div {...rest} className={cx(\"ps1ui-griditem\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;AAaA,SAAgB,SAAS,EAAE,SAAS,WAAW,OAAO,GAAG,QAAuB;CAG9E,MAAM,cAAc,kBAAkB,SAAS,wBAAwB,eAAe;CAGtF,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;CACL;CACA,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,GAAG,kBAAkB,SAAS;EAAG,OAAO;CAAc,CAAA;AACzF"}
|
|
@@ -7,9 +7,13 @@ type HeadingElement = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
|
|
7
7
|
type HeadingSize = "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
|
|
8
8
|
type HeadingWeight = FontWeight;
|
|
9
9
|
type HeadingOwnProps<E extends HeadingElement> = {
|
|
10
|
+
/** Semantic level: renders the matching h1–h6 tag and sets the default size and weight. */
|
|
10
11
|
level: HeadingLevel;
|
|
12
|
+
/** Heading tag to render when it should differ from level — visual defaults stay driven by level. */
|
|
11
13
|
as?: E;
|
|
14
|
+
/** Font size. Defaults to the level's size. */
|
|
12
15
|
size?: Responsive<HeadingSize>;
|
|
16
|
+
/** Font weight. Defaults to the level's weight. */
|
|
13
17
|
weight?: Responsive<HeadingWeight>;
|
|
14
18
|
};
|
|
15
19
|
type HeadingProps<E extends HeadingElement = HeadingElement> = HeadingOwnProps<E> & Omit<ComponentPropsWithoutRef<E>, keyof HeadingOwnProps<E>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Heading.mjs","names":[],"sources":["../../../src/components/Heading/Heading.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { resolveResponsive, withResponsiveBase, type Responsive } from \"../../utils/responsive\";\nimport { fontSizeToVar, weightToValue, type FontWeight } from \"../../utils/typography\";\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\nexport type HeadingElement = \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n\nexport type HeadingSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n// HeadingWeight is a re-export of the shared FontWeight scale. Keeping a\n// component-local alias preserves the public type name (backwards compat)\n// while the underlying scale stays single-sourced in utils/typography.ts.\nexport type HeadingWeight = FontWeight;\n\ntype HeadingOwnProps<E extends HeadingElement> = {\n level: HeadingLevel;\n as?: E;\n size?: Responsive<HeadingSize>;\n weight?: Responsive<HeadingWeight>;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow —\n// same reasoning as Text: with a polymorphic `as` prop TypeScript cannot correctly narrow the\n// `ref` type. All h1-h6 do resolve to HTMLHeadingElement so ref would happen to work today, but\n// keeping the polymorphic pattern consistent avoids surprises if the tag set ever widens.\nexport type HeadingProps<E extends HeadingElement = HeadingElement> = HeadingOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof HeadingOwnProps<E>>;\n\n// Exhaustive over HeadingLevel so a new level cannot be added without classifying its defaults.\nconst LEVEL_DEFAULTS: Record<HeadingLevel, { size: HeadingSize; weight: HeadingWeight }> = {\n 1: { size: \"3xl\", weight: \"bold\" },\n 2: { size: \"2xl\", weight: \"semibold\" },\n 3: { size: \"xl\", weight: \"semibold\" },\n 4: { size: \"lg\", weight: \"semibold\" },\n 5: { size: \"md\", weight: \"medium\" },\n 6: { size: \"sm\", weight: \"medium\" },\n};\n\nexport function Heading<E extends HeadingElement = HeadingElement>({\n level,\n as,\n size: sizeProp,\n weight: weightProp,\n className,\n style,\n ...rest\n}: HeadingProps<E>) {\n const tag = as ?? (`h${level}` as HeadingElement);\n const defaults = LEVEL_DEFAULTS[level];\n // `withResponsiveBase` bakes the level's default in at the `base`\n // breakpoint when the caller either omits the prop entirely or passes a\n // responsive object with no `base` entry. Concretely, `<Heading level={1}\n // size={{ md: \"2xl\" }}>` renders as level 1's default `3xl` at base, then\n // `2xl` at the md breakpoint — matching the intuition \"level sets the\n // default; the object overrides at specific widths\".\n const size = withResponsiveBase(sizeProp, defaults.size);\n const weight = withResponsiveBase(weightProp, defaults.weight);\n\n const sizeVars = resolveResponsive(size, \"--_heading-size\", fontSizeToVar);\n const weightVars = resolveResponsive(weight, \"--_heading-weight\", weightToValue);\n\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...sizeVars,\n ...weightVars,\n } as CSSProperties;\n\n return createElement(tag, {\n ...rest,\n className: cx(\"ps1ui-heading\", className),\n style: mergedStyle,\n });\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"Heading.mjs","names":[],"sources":["../../../src/components/Heading/Heading.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { resolveResponsive, withResponsiveBase, type Responsive } from \"../../utils/responsive\";\nimport { fontSizeToVar, weightToValue, type FontWeight } from \"../../utils/typography\";\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\nexport type HeadingElement = \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n\nexport type HeadingSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\";\n// HeadingWeight is a re-export of the shared FontWeight scale. Keeping a\n// component-local alias preserves the public type name (backwards compat)\n// while the underlying scale stays single-sourced in utils/typography.ts.\nexport type HeadingWeight = FontWeight;\n\ntype HeadingOwnProps<E extends HeadingElement> = {\n /** Semantic level: renders the matching h1–h6 tag and sets the default size and weight. */\n level: HeadingLevel;\n /** Heading tag to render when it should differ from level — visual defaults stay driven by level. */\n as?: E;\n /** Font size. Defaults to the level's size. */\n size?: Responsive<HeadingSize>;\n /** Font weight. Defaults to the level's weight. */\n weight?: Responsive<HeadingWeight>;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow —\n// same reasoning as Text: with a polymorphic `as` prop TypeScript cannot correctly narrow the\n// `ref` type. All h1-h6 do resolve to HTMLHeadingElement so ref would happen to work today, but\n// keeping the polymorphic pattern consistent avoids surprises if the tag set ever widens.\nexport type HeadingProps<E extends HeadingElement = HeadingElement> = HeadingOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof HeadingOwnProps<E>>;\n\n// Exhaustive over HeadingLevel so a new level cannot be added without classifying its defaults.\nconst LEVEL_DEFAULTS: Record<HeadingLevel, { size: HeadingSize; weight: HeadingWeight }> = {\n 1: { size: \"3xl\", weight: \"bold\" },\n 2: { size: \"2xl\", weight: \"semibold\" },\n 3: { size: \"xl\", weight: \"semibold\" },\n 4: { size: \"lg\", weight: \"semibold\" },\n 5: { size: \"md\", weight: \"medium\" },\n 6: { size: \"sm\", weight: \"medium\" },\n};\n\nexport function Heading<E extends HeadingElement = HeadingElement>({\n level,\n as,\n size: sizeProp,\n weight: weightProp,\n className,\n style,\n ...rest\n}: HeadingProps<E>) {\n const tag = as ?? (`h${level}` as HeadingElement);\n const defaults = LEVEL_DEFAULTS[level];\n // `withResponsiveBase` bakes the level's default in at the `base`\n // breakpoint when the caller either omits the prop entirely or passes a\n // responsive object with no `base` entry. Concretely, `<Heading level={1}\n // size={{ md: \"2xl\" }}>` renders as level 1's default `3xl` at base, then\n // `2xl` at the md breakpoint — matching the intuition \"level sets the\n // default; the object overrides at specific widths\".\n const size = withResponsiveBase(sizeProp, defaults.size);\n const weight = withResponsiveBase(weightProp, defaults.weight);\n\n const sizeVars = resolveResponsive(size, \"--_heading-size\", fontSizeToVar);\n const weightVars = resolveResponsive(weight, \"--_heading-weight\", weightToValue);\n\n // Caller style first, internal `--_*` vars win — see Text.tsx. Cast because\n // csstype has no index signature for `--*` keys (React 19 included).\n const mergedStyle: CSSProperties = {\n ...style,\n ...sizeVars,\n ...weightVars,\n } as CSSProperties;\n\n return createElement(tag, {\n ...rest,\n className: cx(\"ps1ui-heading\", className),\n style: mergedStyle,\n });\n}\n"],"mappings":";;;;;AAkCA,MAAM,iBAAqF;CACzF,GAAG;EAAE,MAAM;EAAO,QAAQ;CAAO;CACjC,GAAG;EAAE,MAAM;EAAO,QAAQ;CAAW;CACrC,GAAG;EAAE,MAAM;EAAM,QAAQ;CAAW;CACpC,GAAG;EAAE,MAAM;EAAM,QAAQ;CAAW;CACpC,GAAG;EAAE,MAAM;EAAM,QAAQ;CAAS;CAClC,GAAG;EAAE,MAAM;EAAM,QAAQ;CAAS;AACpC;AAEA,SAAgB,QAAmD,EACjE,OACA,IACA,MAAM,UACN,QAAQ,YACR,WACA,OACA,GAAG,QACe;CAClB,MAAM,MAAM,MAAO,IAAI;CACvB,MAAM,WAAW,eAAe;CAOhC,MAAM,OAAO,mBAAmB,UAAU,SAAS,IAAI;CACvD,MAAM,SAAS,mBAAmB,YAAY,SAAS,MAAM;CAE7D,MAAM,WAAW,kBAAkB,MAAM,mBAAmB,aAAa;CACzE,MAAM,aAAa,kBAAkB,QAAQ,qBAAqB,aAAa;CAI/E,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;EACH,GAAG;CACL;CAEA,OAAO,cAAc,KAAK;EACxB,GAAG;EACH,WAAW,GAAG,iBAAiB,SAAS;EACxC,OAAO;CACT,CAAC;AACH"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ComponentProps, ReactElement } from "react";
|
|
2
2
|
//#region src/components/List/List.d.ts
|
|
3
3
|
type ListProps = ({
|
|
4
|
+
/** Render an <ol> with numbered markers instead of an <ul>. */
|
|
4
5
|
ordered?: false;
|
|
5
6
|
} & ComponentProps<"ul">) | ({
|
|
7
|
+
/** Render an <ol> with numbered markers instead of an <ul>. */
|
|
6
8
|
ordered: true;
|
|
7
9
|
} & Omit<ComponentProps<"ol">, "type">);
|
|
8
10
|
declare function List(props: ListProps): ReactElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"List.mjs","names":[],"sources":["../../../src/components/List/List.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentProps, ReactElement } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\n// Discriminated union: an unordered <List> shouldn't typecheck with <ol>-only\n// attributes (start / reversed) and shouldn't type its ref as HTMLOListElement.\n// `type` is dropped from the ordered variant because the visible marker is\n// drawn by `::before`, not the browser's `::marker`, so `type=\"a\"` would\n// silently not affect the visible numbering.\nexport type ListProps =\n | ({ ordered?: false
|
|
1
|
+
{"version":3,"file":"List.mjs","names":[],"sources":["../../../src/components/List/List.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentProps, ReactElement } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\n// Discriminated union: an unordered <List> shouldn't typecheck with <ol>-only\n// attributes (start / reversed) and shouldn't type its ref as HTMLOListElement.\n// `type` is dropped from the ordered variant because the visible marker is\n// drawn by `::before`, not the browser's `::marker`, so `type=\"a\"` would\n// silently not affect the visible numbering.\nexport type ListProps =\n | ({\n /** Render an <ol> with numbered markers instead of an <ul>. */\n ordered?: false;\n } & ComponentProps<\"ul\">)\n | ({\n /** Render an <ol> with numbered markers instead of an <ul>. */\n ordered: true;\n } & Omit<ComponentProps<\"ol\">, \"type\">);\n\n// Return type annotated so tsdown emits a small ReactElement in the .d.mts\n// instead of the wide DetailedReactHTMLElement createElement infers for a\n// `\"ol\" | \"ul\"` tag union.\nexport function List(props: ListProps): ReactElement {\n const { ordered = false, className, ...rest } = props;\n const tag = ordered ? \"ol\" : \"ul\";\n return createElement(tag, {\n // Safari's a11y tree drops list semantics (\"list, N items\") when the\n // computed `list-style-type` is `none` — the global reset applies that,\n // so `role=\"list\"` restores VoiceOver's announcement. Placed before\n // `...rest` so a caller can override with a different role.\n role: \"list\",\n ...rest,\n className: cx(\n \"ps1ui-list\",\n ordered ? \"ps1ui-list--ordered\" : \"ps1ui-list--unordered\",\n className,\n ),\n });\n}\n"],"mappings":";;;AAsBA,SAAgB,KAAK,OAAgC;CACnD,MAAM,EAAE,UAAU,OAAO,WAAW,GAAG,SAAS;CAEhD,OAAO,cADK,UAAU,OAAO,MACH;EAKxB,MAAM;EACN,GAAG;EACH,WAAW,GACT,cACA,UAAU,wBAAwB,yBAClC,SACF;CACF,CAAC;AACH"}
|