@ps1ui/core 0.0.1 → 0.1.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/components/Anchor/Anchor.d.mts +2 -0
- package/dist/components/Anchor/Anchor.mjs.map +1 -1
- package/dist/components/Button/Button.d.mts +6 -0
- 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 +8 -0
- package/dist/components/Text/Text.mjs.map +1 -1
- package/dist/components.css +6 -6
- package/dist/styles.css +6 -6
- package/package.json +2 -2
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)
|
|
@@ -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"}
|
|
@@ -2,7 +2,9 @@ import { ComponentPropsWithoutRef, ElementType } from "react";
|
|
|
2
2
|
//#region src/components/Button/Button.d.ts
|
|
3
3
|
type ButtonVariant = "primary" | "secondary";
|
|
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. */
|
|
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\";\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,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"}
|
|
@@ -7,10 +7,24 @@ type StackGap = SpaceScale;
|
|
|
7
7
|
type StackAlign = "start" | "center" | "end" | "stretch" | "baseline";
|
|
8
8
|
type StackJustify = "start" | "center" | "end" | "between" | "around" | "evenly";
|
|
9
9
|
type StackProps = ComponentProps<"div"> & {
|
|
10
|
+
/**
|
|
11
|
+
* Main-axis direction.
|
|
12
|
+
* @default "column"
|
|
13
|
+
*/
|
|
10
14
|
direction?: Responsive<StackDirection>;
|
|
15
|
+
/**
|
|
16
|
+
* Gap between items on the space scale.
|
|
17
|
+
* @default "md"
|
|
18
|
+
*/
|
|
11
19
|
gap?: Responsive<StackGap>;
|
|
20
|
+
/** Cross-axis alignment (align-items). */
|
|
12
21
|
align?: Responsive<StackAlign>;
|
|
22
|
+
/** Main-axis distribution (justify-content). */
|
|
13
23
|
justify?: Responsive<StackJustify>;
|
|
24
|
+
/**
|
|
25
|
+
* Wrap items onto multiple lines instead of overflowing.
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
14
28
|
wrap?: Responsive<boolean>;
|
|
15
29
|
};
|
|
16
30
|
declare function Stack({ direction, gap, align, justify, wrap, className, style, ...rest }: StackProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stack.mjs","names":[],"sources":["../../../src/components/Stack/Stack.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 StackDirection = \"row\" | \"column\";\nexport type StackGap = SpaceScale;\nexport type StackAlign = \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\";\nexport type StackJustify = \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\";\n\nexport type StackProps = ComponentProps<\"div\"> & {\n direction?: Responsive<StackDirection>;\n gap?: Responsive<StackGap>;\n align?: Responsive<StackAlign>;\n justify?: Responsive<StackJustify>;\n wrap?: Responsive<boolean>;\n};\n\n// direction values pass straight through — CSS flex-direction accepts\n// `row` / `column` (and `row-reverse` / `column-reverse`, which the union\n// deliberately excludes; add those to the union if the API ever grows).\nconst directionToValue = (v: StackDirection): string => v;\n\n// Flexbox uses `flex-start` / `flex-end` in the box-alignment spec. The\n// StackAlign union exposes the shorter `start` / `end` alias for terseness;\n// the transform remaps them so the CSS variable holds a valid `align-items`\n// value directly.\nconst alignToValue = (v: StackAlign): string => {\n switch (v) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n default:\n return v;\n }\n};\n\n// Same treatment as `alignToValue`, plus expansions for the `space-*`\n// justify-content variants.\nconst justifyToValue = (v: StackJustify): string => {\n switch (v) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n case \"between\":\n return \"space-between\";\n case \"around\":\n return \"space-around\";\n case \"evenly\":\n return \"space-evenly\";\n default:\n return v;\n }\n};\n\n// boolean → CSS flex-wrap keyword.\nconst wrapToValue = (v: boolean): string => (v ? \"wrap\" : \"nowrap\");\n\nexport function Stack({\n direction,\n gap,\n align,\n justify,\n wrap,\n className,\n style,\n ...rest\n}: StackProps) {\n const directionVars = resolveResponsive(direction, \"--_stack-direction\", directionToValue);\n const gapVars = resolveResponsive(gap, \"--_stack-gap\", spaceToVar);\n const alignVars = resolveResponsive(align, \"--_stack-align\", alignToValue);\n const justifyVars = resolveResponsive(justify, \"--_stack-justify\", justifyToValue);\n const wrapVars = resolveResponsive(wrap, \"--_stack-wrap\", wrapToValue);\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 ...directionVars,\n ...gapVars,\n ...alignVars,\n ...justifyVars,\n ...wrapVars,\n } as CSSProperties;\n\n return <div {...rest} className={cx(\"ps1ui-stack\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"Stack.mjs","names":[],"sources":["../../../src/components/Stack/Stack.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 StackDirection = \"row\" | \"column\";\nexport type StackGap = SpaceScale;\nexport type StackAlign = \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\";\nexport type StackJustify = \"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\";\n\nexport type StackProps = ComponentProps<\"div\"> & {\n /**\n * Main-axis direction.\n * @default \"column\"\n */\n direction?: Responsive<StackDirection>;\n /**\n * Gap between items on the space scale.\n * @default \"md\"\n */\n gap?: Responsive<StackGap>;\n /** Cross-axis alignment (align-items). */\n align?: Responsive<StackAlign>;\n /** Main-axis distribution (justify-content). */\n justify?: Responsive<StackJustify>;\n /**\n * Wrap items onto multiple lines instead of overflowing.\n * @default false\n */\n wrap?: Responsive<boolean>;\n};\n\n// direction values pass straight through — CSS flex-direction accepts\n// `row` / `column` (and `row-reverse` / `column-reverse`, which the union\n// deliberately excludes; add those to the union if the API ever grows).\nconst directionToValue = (v: StackDirection): string => v;\n\n// Flexbox uses `flex-start` / `flex-end` in the box-alignment spec. The\n// StackAlign union exposes the shorter `start` / `end` alias for terseness;\n// the transform remaps them so the CSS variable holds a valid `align-items`\n// value directly.\nconst alignToValue = (v: StackAlign): string => {\n switch (v) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n default:\n return v;\n }\n};\n\n// Same treatment as `alignToValue`, plus expansions for the `space-*`\n// justify-content variants.\nconst justifyToValue = (v: StackJustify): string => {\n switch (v) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n case \"between\":\n return \"space-between\";\n case \"around\":\n return \"space-around\";\n case \"evenly\":\n return \"space-evenly\";\n default:\n return v;\n }\n};\n\n// boolean → CSS flex-wrap keyword.\nconst wrapToValue = (v: boolean): string => (v ? \"wrap\" : \"nowrap\");\n\nexport function Stack({\n direction,\n gap,\n align,\n justify,\n wrap,\n className,\n style,\n ...rest\n}: StackProps) {\n const directionVars = resolveResponsive(direction, \"--_stack-direction\", directionToValue);\n const gapVars = resolveResponsive(gap, \"--_stack-gap\", spaceToVar);\n const alignVars = resolveResponsive(align, \"--_stack-align\", alignToValue);\n const justifyVars = resolveResponsive(justify, \"--_stack-justify\", justifyToValue);\n const wrapVars = resolveResponsive(wrap, \"--_stack-wrap\", wrapToValue);\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 ...directionVars,\n ...gapVars,\n ...alignVars,\n ...justifyVars,\n ...wrapVars,\n } as CSSProperties;\n\n return <div {...rest} className={cx(\"ps1ui-stack\", className)} style={mergedStyle} />;\n}\n"],"mappings":";;;;;AAmCA,MAAM,oBAAoB,MAA8B;AAMxD,MAAM,gBAAgB,MAA0B;CAC9C,QAAQ,GAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAIA,MAAM,kBAAkB,MAA4B;CAClD,QAAQ,GAAR;EACE,KAAK,SACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAGA,MAAM,eAAe,MAAwB,IAAI,SAAS;AAE1D,SAAgB,MAAM,EACpB,WACA,KACA,OACA,SACA,MACA,WACA,OACA,GAAG,QACU;CACb,MAAM,gBAAgB,kBAAkB,WAAW,sBAAsB,gBAAgB;CACzF,MAAM,UAAU,kBAAkB,KAAK,gBAAgB,UAAU;CACjE,MAAM,YAAY,kBAAkB,OAAO,kBAAkB,YAAY;CACzE,MAAM,cAAc,kBAAkB,SAAS,oBAAoB,cAAc;CACjF,MAAM,WAAW,kBAAkB,MAAM,iBAAiB,WAAW;CAIrE,MAAM,cAA6B;EACjC,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;CACL;CAEA,OAAO,oBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,GAAG,eAAe,SAAS;EAAG,OAAO;CAAc,CAAA;AACtF"}
|
|
@@ -7,10 +7,18 @@ type TextVariant = "body" | "muted" | "subtle" | "primary" | "accent";
|
|
|
7
7
|
type TextSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
8
8
|
type TextWeight = FontWeight;
|
|
9
9
|
type TextOwnProps<E extends TextElement> = {
|
|
10
|
+
/** Element to render. */
|
|
10
11
|
as?: E;
|
|
12
|
+
/** Color variant. */
|
|
11
13
|
variant?: TextVariant;
|
|
14
|
+
/**
|
|
15
|
+
* Font size on the type scale.
|
|
16
|
+
* @default "sm"
|
|
17
|
+
*/
|
|
12
18
|
size?: Responsive<TextSize>;
|
|
19
|
+
/** Font weight. */
|
|
13
20
|
weight?: Responsive<TextWeight>;
|
|
21
|
+
/** Truncate overflowing text with an ellipsis instead of wrapping. */
|
|
14
22
|
truncate?: boolean;
|
|
15
23
|
};
|
|
16
24
|
type TextProps<E extends TextElement = "p"> = TextOwnProps<E> & Omit<ComponentPropsWithoutRef<E>, keyof TextOwnProps<E>>;
|
|
@@ -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 as?: E;\n variant?: TextVariant;\n size?: Responsive<TextSize>;\n weight?: Responsive<TextWeight>;\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":";;;;;
|
|
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"}
|
package/dist/components.css
CHANGED
|
@@ -782,13 +782,13 @@
|
|
|
782
782
|
color: var(--ps1ui-color-fg);
|
|
783
783
|
}
|
|
784
784
|
|
|
785
|
-
/* List — semantic <ul>/<ol> wrapper with
|
|
785
|
+
/* List — semantic <ul>/<ol> wrapper with plain-text markers.
|
|
786
786
|
|
|
787
787
|
The global reset in base.css sets `list-style: none` on every <ul>/<ol>,
|
|
788
788
|
which strips the UA bullet/number glyph. List re-introduces a marker via
|
|
789
789
|
`::before` on each direct <li> — `-` for unordered, `NN.` for ordered —
|
|
790
790
|
so the "reset removes bullets" side effect turns into an on-brand
|
|
791
|
-
|
|
791
|
+
plain-text glyph rather than a hole.
|
|
792
792
|
|
|
793
793
|
The ordered marker uses `counter(list-item)` — the browser-maintained
|
|
794
794
|
list-item counter that already honours `<ol start>`, `<ol reversed>`,
|
|
@@ -1104,7 +1104,7 @@
|
|
|
1104
1104
|
display: none;
|
|
1105
1105
|
}
|
|
1106
1106
|
|
|
1107
|
-
/*
|
|
1107
|
+
/* Glyph disclosure marker: `▸` when closed, `▾` when open. Fixed
|
|
1108
1108
|
inline-block width so the summary text baseline stays put across states —
|
|
1109
1109
|
the two glyphs don't measure identically in the JetBrains Mono fallback
|
|
1110
1110
|
monospace stack. Colored with fg-muted so the arrow reads as chrome, not
|
|
@@ -1402,7 +1402,7 @@
|
|
|
1402
1402
|
}
|
|
1403
1403
|
}
|
|
1404
1404
|
|
|
1405
|
-
/* Table — semantic <table> with
|
|
1405
|
+
/* Table — semantic <table> with box-drawing-style grid borders, wrapped in a
|
|
1406
1406
|
horizontal-scroll container.
|
|
1407
1407
|
|
|
1408
1408
|
Scroll wrapper: `display: table` boxes don't honor overflow, so Table.tsx
|
|
@@ -1414,8 +1414,8 @@
|
|
|
1414
1414
|
high-contrast mode; the grouped rule restores a real outline).
|
|
1415
1415
|
|
|
1416
1416
|
Grid borders: `border-collapse: collapse` + a uniform 1px cell border in
|
|
1417
|
-
--ps1ui-color-border draw the closed single-stroke grid a
|
|
1418
|
-
|
|
1417
|
+
--ps1ui-color-border draw the closed single-stroke grid a box-drawing
|
|
1418
|
+
table (┌─┬─┐) renders — collapsing is what merges adjacent
|
|
1419
1419
|
cell edges into one shared rule. The header row separates on two axes:
|
|
1420
1420
|
a surface background and a border-strong bottom rule. That rule is
|
|
1421
1421
|
declared on the <th> (cell origin) deliberately — in border-collapse
|
package/dist/styles.css
CHANGED
|
@@ -975,13 +975,13 @@ html {
|
|
|
975
975
|
line-height: 1.6;
|
|
976
976
|
color: var(--ps1ui-color-fg);
|
|
977
977
|
}
|
|
978
|
-
/* List — semantic <ul>/<ol> wrapper with
|
|
978
|
+
/* List — semantic <ul>/<ol> wrapper with plain-text markers.
|
|
979
979
|
|
|
980
980
|
The global reset in base.css sets `list-style: none` on every <ul>/<ol>,
|
|
981
981
|
which strips the UA bullet/number glyph. List re-introduces a marker via
|
|
982
982
|
`::before` on each direct <li> — `-` for unordered, `NN.` for ordered —
|
|
983
983
|
so the "reset removes bullets" side effect turns into an on-brand
|
|
984
|
-
|
|
984
|
+
plain-text glyph rather than a hole.
|
|
985
985
|
|
|
986
986
|
The ordered marker uses `counter(list-item)` — the browser-maintained
|
|
987
987
|
list-item counter that already honours `<ol start>`, `<ol reversed>`,
|
|
@@ -1261,7 +1261,7 @@ html {
|
|
|
1261
1261
|
.ps1ui-details__summary::-webkit-details-marker {
|
|
1262
1262
|
display: none;
|
|
1263
1263
|
}
|
|
1264
|
-
/*
|
|
1264
|
+
/* Glyph disclosure marker: `▸` when closed, `▾` when open. Fixed
|
|
1265
1265
|
inline-block width so the summary text baseline stays put across states —
|
|
1266
1266
|
the two glyphs don't measure identically in the JetBrains Mono fallback
|
|
1267
1267
|
monospace stack. Colored with fg-muted so the arrow reads as chrome, not
|
|
@@ -1519,7 +1519,7 @@ html {
|
|
|
1519
1519
|
--_wrap: var(--_wrap-xl);
|
|
1520
1520
|
}
|
|
1521
1521
|
}
|
|
1522
|
-
/* Table — semantic <table> with
|
|
1522
|
+
/* Table — semantic <table> with box-drawing-style grid borders, wrapped in a
|
|
1523
1523
|
horizontal-scroll container.
|
|
1524
1524
|
|
|
1525
1525
|
Scroll wrapper: `display: table` boxes don't honor overflow, so Table.tsx
|
|
@@ -1531,8 +1531,8 @@ html {
|
|
|
1531
1531
|
high-contrast mode; the grouped rule restores a real outline).
|
|
1532
1532
|
|
|
1533
1533
|
Grid borders: `border-collapse: collapse` + a uniform 1px cell border in
|
|
1534
|
-
--ps1ui-color-border draw the closed single-stroke grid a
|
|
1535
|
-
|
|
1534
|
+
--ps1ui-color-border draw the closed single-stroke grid a box-drawing
|
|
1535
|
+
table (┌─┬─┐) renders — collapsing is what merges adjacent
|
|
1536
1536
|
cell edges into one shared rule. The header row separates on two axes:
|
|
1537
1537
|
a surface background and a border-strong bottom rule. That rule is
|
|
1538
1538
|
declared on the <th> (cell origin) deliberately — in border-collapse
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ps1ui/core",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"homepage": "https://github.com/koki-develop/ps1ui",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "koki-develop <kou.pg.0131@gmail.com>",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"build-storybook": "storybook build"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@fontsource-variable/jetbrains-mono": "
|
|
56
|
+
"@fontsource-variable/jetbrains-mono": "5.2.8",
|
|
57
57
|
"hast-util-to-jsx-runtime": "2.3.6",
|
|
58
58
|
"refractor": "5.0.0"
|
|
59
59
|
},
|