@ps1ui/core 0.1.0 → 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/dist/base.css +56 -0
- package/dist/components/Button/Button.d.mts +2 -2
- package/dist/components/Button/Button.mjs.map +1 -1
- package/dist/components/Text/Text.d.mts +1 -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 +79 -153
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/styles.css +200 -1
- package/package.json +3 -3
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);
|
|
@@ -1,10 +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
5
|
/** Element or component to render instead of the native <button> — e.g. "a" or a router Link. */
|
|
6
6
|
as?: E;
|
|
7
|
-
/** Visual style: "primary" for the main action, "secondary" for supporting actions. */
|
|
7
|
+
/** Visual style: "primary" for the main action, "secondary" for supporting actions, "danger" for destructive actions. */
|
|
8
8
|
variant?: ButtonVariant;
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
@@ -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 /** 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. */\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
|
+
{"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"}
|
|
@@ -3,7 +3,7 @@ import { FontWeight } from "../../utils/typography.mjs";
|
|
|
3
3
|
import { CSSProperties, ComponentPropsWithoutRef } from "react";
|
|
4
4
|
//#region src/components/Text/Text.d.ts
|
|
5
5
|
type TextElement = "p" | "span" | "div" | "label" | "strong" | "em" | "small";
|
|
6
|
-
type TextVariant = "body" | "muted" | "subtle" | "primary" | "accent";
|
|
6
|
+
type TextVariant = "body" | "muted" | "subtle" | "primary" | "accent" | "danger";
|
|
7
7
|
type TextSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
8
8
|
type TextWeight = FontWeight;
|
|
9
9
|
type TextOwnProps<E extends TextElement> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Text.mjs","names":[],"sources":["../../../src/components/Text/Text.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\nimport { fontSizeToVar, weightToValue, type FontWeight } from \"../../utils/typography\";\n\nexport type TextElement = \"p\" | \"span\" | \"div\" | \"label\" | \"strong\" | \"em\" | \"small\";\n\nexport type TextVariant = \"body\" | \"muted\" | \"subtle\" | \"primary\" | \"accent\";\nexport type TextSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n// TextWeight 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 TextWeight = FontWeight;\n\ntype TextOwnProps<E extends TextElement> = {\n /** Element to render. */\n as?: E;\n /** Color variant. */\n variant?: TextVariant;\n /**\n * Font size on the type scale.\n * @default \"sm\"\n */\n size?: Responsive<TextSize>;\n /** Font weight. */\n weight?: Responsive<TextWeight>;\n /** Truncate overflowing text with an ellipsis instead of wrapping. */\n truncate?: boolean;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow.\n// With the polymorphic `as` prop, TypeScript cannot narrow the `ref` prop's type against the\n// resolved element E — allowing `ref` here would silently accept mismatched ref types\n// (e.g. a ref typed for HTMLParagraphElement on `<Text as=\"span\" ref={…} />`). Keeping `ref`\n// out of the prop type entirely is safer than a misleading loose type; don't switch this\n// to ComponentProps for consistency with the other components.\nexport type TextProps<E extends TextElement = \"p\"> = TextOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof TextOwnProps<E>>;\n\n// Exhaustive over TextElement so adding a tag without classifying it fails to typecheck,\n// instead of silently leaving truncate's inline-block fix un-applied for that tag.\nconst INLINE_TEXT_ELEMENTS: Record<TextElement, boolean> = {\n p: false,\n div: false,\n span: true,\n label: true,\n strong: true,\n em: true,\n small: true,\n};\n\nexport function Text<E extends TextElement = \"p\">({\n as,\n variant = \"body\",\n size,\n weight,\n truncate = false,\n className,\n style,\n ...rest\n}: TextProps<E>) {\n const tag = as ?? \"p\";\n const sizeVars = resolveResponsive(size, \"--_text-size\", fontSizeToVar);\n const weightVars = resolveResponsive(weight, \"--_text-weight\", weightToValue);\n\n const classes = cx(\n \"ps1ui-text\",\n `ps1ui-text--${variant}`,\n truncate && \"ps1ui-text--truncate\",\n truncate && INLINE_TEXT_ELEMENTS[tag] && \"ps1ui-text--truncate-inline\",\n className,\n );\n\n // Caller style first, resolved vars last: `--_*` is the reserved internal\n // prefix and wins on purpose — responsive values are prop-controlled. Cast\n // because 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, { ...rest, className: classes, style: mergedStyle });\n}\n"],"mappings":";;;;;AA0CA,MAAM,uBAAqD;CACzD,GAAG;CACH,KAAK;CACL,MAAM;CACN,OAAO;CACP,QAAQ;CACR,IAAI;CACJ,OAAO;AACT;AAEA,SAAgB,KAAkC,EAChD,IACA,UAAU,QACV,MACA,QACA,WAAW,OACX,WACA,OACA,GAAG,QACY;CACf,MAAM,MAAM,MAAM;CAClB,MAAM,WAAW,kBAAkB,MAAM,gBAAgB,aAAa;CACtE,MAAM,aAAa,kBAAkB,QAAQ,kBAAkB,aAAa;CAE5E,MAAM,UAAU,GACd,cACA,eAAe,WACf,YAAY,wBACZ,YAAY,qBAAqB,QAAQ,+BACzC,SACF;CAKA,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;EACH,GAAG;CACL;CAEA,OAAO,cAAc,KAAK;EAAE,GAAG;EAAM,WAAW;EAAS,OAAO;CAAY,CAAC;AAC/E"}
|
|
1
|
+
{"version":3,"file":"Text.mjs","names":[],"sources":["../../../src/components/Text/Text.tsx"],"sourcesContent":["import { createElement } from \"react\";\nimport type { ComponentPropsWithoutRef, CSSProperties } from \"react\";\nimport { cx } from \"../../utils/cx\";\nimport { resolveResponsive, type Responsive } from \"../../utils/responsive\";\nimport { fontSizeToVar, weightToValue, type FontWeight } from \"../../utils/typography\";\n\nexport type TextElement = \"p\" | \"span\" | \"div\" | \"label\" | \"strong\" | \"em\" | \"small\";\n\nexport type TextVariant = \"body\" | \"muted\" | \"subtle\" | \"primary\" | \"accent\" | \"danger\";\nexport type TextSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n// TextWeight 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 TextWeight = FontWeight;\n\ntype TextOwnProps<E extends TextElement> = {\n /** Element to render. */\n as?: E;\n /** Color variant. */\n variant?: TextVariant;\n /**\n * Font size on the type scale.\n * @default \"sm\"\n */\n size?: Responsive<TextSize>;\n /** Font weight. */\n weight?: Responsive<TextWeight>;\n /** Truncate overflowing text with an ellipsis instead of wrapping. */\n truncate?: boolean;\n};\n\n// Deliberate exception to the general \"use ComponentProps<'tag'>\" rule other components follow.\n// With the polymorphic `as` prop, TypeScript cannot narrow the `ref` prop's type against the\n// resolved element E — allowing `ref` here would silently accept mismatched ref types\n// (e.g. a ref typed for HTMLParagraphElement on `<Text as=\"span\" ref={…} />`). Keeping `ref`\n// out of the prop type entirely is safer than a misleading loose type; don't switch this\n// to ComponentProps for consistency with the other components.\nexport type TextProps<E extends TextElement = \"p\"> = TextOwnProps<E> &\n Omit<ComponentPropsWithoutRef<E>, keyof TextOwnProps<E>>;\n\n// Exhaustive over TextElement so adding a tag without classifying it fails to typecheck,\n// instead of silently leaving truncate's inline-block fix un-applied for that tag.\nconst INLINE_TEXT_ELEMENTS: Record<TextElement, boolean> = {\n p: false,\n div: false,\n span: true,\n label: true,\n strong: true,\n em: true,\n small: true,\n};\n\nexport function Text<E extends TextElement = \"p\">({\n as,\n variant = \"body\",\n size,\n weight,\n truncate = false,\n className,\n style,\n ...rest\n}: TextProps<E>) {\n const tag = as ?? \"p\";\n const sizeVars = resolveResponsive(size, \"--_text-size\", fontSizeToVar);\n const weightVars = resolveResponsive(weight, \"--_text-weight\", weightToValue);\n\n const classes = cx(\n \"ps1ui-text\",\n `ps1ui-text--${variant}`,\n truncate && \"ps1ui-text--truncate\",\n truncate && INLINE_TEXT_ELEMENTS[tag] && \"ps1ui-text--truncate-inline\",\n className,\n );\n\n // Caller style first, resolved vars last: `--_*` is the reserved internal\n // prefix and wins on purpose — responsive values are prop-controlled. Cast\n // because 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, { ...rest, className: classes, style: mergedStyle });\n}\n"],"mappings":";;;;;AA0CA,MAAM,uBAAqD;CACzD,GAAG;CACH,KAAK;CACL,MAAM;CACN,OAAO;CACP,QAAQ;CACR,IAAI;CACJ,OAAO;AACT;AAEA,SAAgB,KAAkC,EAChD,IACA,UAAU,QACV,MACA,QACA,WAAW,OACX,WACA,OACA,GAAG,QACY;CACf,MAAM,MAAM,MAAM;CAClB,MAAM,WAAW,kBAAkB,MAAM,gBAAgB,aAAa;CACtE,MAAM,aAAa,kBAAkB,QAAQ,kBAAkB,aAAa;CAE5E,MAAM,UAAU,GACd,cACA,eAAe,WACf,YAAY,wBACZ,YAAY,qBAAqB,QAAQ,+BACzC,SACF;CAKA,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;EACH,GAAG;CACL;CAEA,OAAO,cAAc,KAAK;EAAE,GAAG;EAAM,WAAW;EAAS,OAAO;CAAY,CAAC;AAC/E"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
//#region src/components/Textarea/Textarea.d.ts
|
|
3
|
+
type TextareaProps = ComponentProps<"textarea">;
|
|
4
|
+
declare function Textarea({ className, ...rest }: TextareaProps): import("react").JSX.Element;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { Textarea, TextareaProps };
|
|
7
|
+
//# sourceMappingURL=Textarea.d.mts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { cx } from "../../utils/cx.mjs";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/Textarea/Textarea.tsx
|
|
4
|
+
function Textarea({ className, ...rest }) {
|
|
5
|
+
const classes = cx("ps1ui-textarea", className);
|
|
6
|
+
return /* @__PURE__ */ jsx("textarea", {
|
|
7
|
+
...rest,
|
|
8
|
+
className: classes
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { Textarea };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=Textarea.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Textarea.mjs","names":[],"sources":["../../../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { cx } from \"../../utils/cx\";\n\nexport type TextareaProps = ComponentProps<\"textarea\">;\n\nexport function Textarea({ className, ...rest }: TextareaProps) {\n const classes = cx(\"ps1ui-textarea\", className);\n return <textarea {...rest} className={classes} />;\n}\n"],"mappings":";;;AAKA,SAAgB,SAAS,EAAE,WAAW,GAAG,QAAuB;CAC9D,MAAM,UAAU,GAAG,kBAAkB,SAAS;CAC9C,OAAO,oBAAC,YAAD;EAAU,GAAI;EAAM,WAAW;CAAU,CAAA;AAClD"}
|