@toyonix/web-kit 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +68 -2
- package/config/eslint.js +68 -0
- package/config/prettier.js +20 -0
- package/config/tsconfig.base.json +22 -0
- package/dist/css/base.css +58 -0
- package/dist/css/components.css +915 -0
- package/dist/css/fonts/LICENSE-Newsreader.txt +93 -0
- package/dist/css/fonts/LICENSE-Space-Grotesk.txt +93 -0
- package/dist/css/fonts/LICENSE-Space-Mono.txt +93 -0
- package/dist/css/fonts/newsreader-latin-ext-opsz-italic.woff2 +0 -0
- package/dist/css/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
- package/dist/css/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
- package/dist/css/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
- package/dist/css/fonts/space-grotesk-latin-400-normal.woff2 +0 -0
- package/dist/css/fonts/space-grotesk-latin-500-normal.woff2 +0 -0
- package/dist/css/fonts/space-grotesk-latin-700-normal.woff2 +0 -0
- package/dist/css/fonts/space-grotesk-latin-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/space-grotesk-latin-ext-500-normal.woff2 +0 -0
- package/dist/css/fonts/space-grotesk-latin-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts/space-mono-latin-400-normal.woff2 +0 -0
- package/dist/css/fonts/space-mono-latin-700-normal.woff2 +0 -0
- package/dist/css/fonts/space-mono-latin-ext-400-normal.woff2 +0 -0
- package/dist/css/fonts/space-mono-latin-ext-700-normal.woff2 +0 -0
- package/dist/css/fonts.css +141 -0
- package/dist/css/index.css +10 -0
- package/dist/css/tailwind.css +46 -0
- package/dist/css/tokens.css +66 -0
- package/dist/env.d.ts +28 -0
- package/dist/env.js +62 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/next/index.d.ts +36 -0
- package/dist/next/index.js +103 -0
- package/dist/react/Alert.d.ts +8 -0
- package/dist/react/Alert.js +16 -0
- package/dist/react/AppLink.d.ts +11 -0
- package/dist/react/AppLink.js +12 -0
- package/dist/react/AppShell.d.ts +20 -0
- package/dist/react/AppShell.js +94 -0
- package/dist/react/Badge.d.ts +10 -0
- package/dist/react/Badge.js +29 -0
- package/dist/react/Button.d.ts +16 -0
- package/dist/react/Button.js +36 -0
- package/dist/react/Card.d.ts +21 -0
- package/dist/react/Card.js +61 -0
- package/dist/react/CodeBlock.d.ts +8 -0
- package/dist/react/CodeBlock.js +16 -0
- package/dist/react/Dialog.d.ts +16 -0
- package/dist/react/Dialog.js +33 -0
- package/dist/react/DropdownMenu.d.ts +12 -0
- package/dist/react/DropdownMenu.js +36 -0
- package/dist/react/Table.d.ts +5 -0
- package/dist/react/Table.js +15 -0
- package/dist/react/Tabs.d.ts +9 -0
- package/dist/react/Tabs.js +26 -0
- package/dist/react/ThemeScript.d.ts +9 -0
- package/dist/react/ThemeScript.js +15 -0
- package/dist/react/ThemeToggle.d.ts +5 -0
- package/dist/react/ThemeToggle.js +22 -0
- package/dist/react/Tooltip.d.ts +13 -0
- package/dist/react/Tooltip.js +21 -0
- package/dist/react/cx.d.ts +4 -0
- package/dist/react/cx.js +7 -0
- package/dist/react/form.d.ts +19 -0
- package/dist/react/form.js +76 -0
- package/dist/react/index.d.ts +21 -0
- package/dist/react/index.js +21 -0
- package/dist/react/layout.d.ts +7 -0
- package/dist/react/layout.js +29 -0
- package/dist/react/typography.d.ts +23 -0
- package/dist/react/typography.js +46 -0
- package/dist/react/use-registry.d.ts +9 -0
- package/dist/react/use-registry.js +41 -0
- package/dist/react/use-theme.d.ts +18 -0
- package/dist/react/use-theme.js +46 -0
- package/dist/registry/build.d.ts +28 -0
- package/dist/registry/build.js +91 -0
- package/dist/registry/index.d.ts +49 -0
- package/dist/registry/index.js +84 -0
- package/dist/slugs.d.ts +15 -0
- package/dist/slugs.js +37 -0
- package/dist/storage/index.d.ts +39 -0
- package/dist/storage/index.js +123 -0
- package/dist/theme.d.ts +19 -0
- package/dist/theme.js +26 -0
- package/package.json +111 -4
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "./cx.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { DropdownMenu } from "radix-ui";
|
|
5
|
+
//#region src/react/DropdownMenu.tsx
|
|
6
|
+
const DropdownMenu$1 = DropdownMenu.Root;
|
|
7
|
+
const DropdownMenuTrigger = DropdownMenu.Trigger;
|
|
8
|
+
const DropdownMenuGroup = DropdownMenu.Group;
|
|
9
|
+
function DropdownMenuContent({ className, sideOffset = 6, align = "start", ...props }) {
|
|
10
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu.Content, {
|
|
11
|
+
className: cx("tx-menu", className),
|
|
12
|
+
sideOffset,
|
|
13
|
+
align,
|
|
14
|
+
...props
|
|
15
|
+
}) });
|
|
16
|
+
}
|
|
17
|
+
function DropdownMenuItem({ className, ...props }) {
|
|
18
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Item, {
|
|
19
|
+
className: cx("tx-menu__item", className),
|
|
20
|
+
...props
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function DropdownMenuLabel({ className, ...props }) {
|
|
24
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Label, {
|
|
25
|
+
className: cx("tx-menu__label", className),
|
|
26
|
+
...props
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function DropdownMenuSeparator({ className, ...props }) {
|
|
30
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Separator, {
|
|
31
|
+
className: cx("tx-menu__separator", className),
|
|
32
|
+
...props
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { DropdownMenu$1 as DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
//#region src/react/Table.d.ts
|
|
3
|
+
/** A table in a bordered, scrollable frame. Use normal <thead>/<tbody>/<tr>/<th>/<td> inside. */
|
|
4
|
+
export declare function Table({ className, ...props }: ComponentProps<"table">): import("react").JSX.Element;
|
|
5
|
+
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { cx } from "./cx.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/react/Table.tsx
|
|
4
|
+
/** A table in a bordered, scrollable frame. Use normal <thead>/<tbody>/<tr>/<th>/<td> inside. */
|
|
5
|
+
function Table({ className, ...props }) {
|
|
6
|
+
return /* @__PURE__ */ jsx("div", {
|
|
7
|
+
className: "tx-table-wrap",
|
|
8
|
+
children: /* @__PURE__ */ jsx("table", {
|
|
9
|
+
className: cx("tx-table", className),
|
|
10
|
+
...props
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Table };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
import { Tabs } from "radix-ui";
|
|
3
|
+
//#region src/react/Tabs.d.ts
|
|
4
|
+
declare const Tabs$1: import("react").ForwardRefExoticComponent<Tabs.TabsProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
5
|
+
export declare function TabsList({ className, ...props }: ComponentProps<typeof Tabs.List>): import("react").JSX.Element;
|
|
6
|
+
export declare function TabsTrigger({ className, ...props }: ComponentProps<typeof Tabs.Trigger>): import("react").JSX.Element;
|
|
7
|
+
export declare function TabsContent({ className, ...props }: ComponentProps<typeof Tabs.Content>): import("react").JSX.Element;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { Tabs$1 as Tabs };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "./cx.js";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { Tabs } from "radix-ui";
|
|
5
|
+
//#region src/react/Tabs.tsx
|
|
6
|
+
const Tabs$1 = Tabs.Root;
|
|
7
|
+
function TabsList({ className, ...props }) {
|
|
8
|
+
return /* @__PURE__ */ jsx(Tabs.List, {
|
|
9
|
+
className: cx("tx-tabs__list", className),
|
|
10
|
+
...props
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function TabsTrigger({ className, ...props }) {
|
|
14
|
+
return /* @__PURE__ */ jsx(Tabs.Trigger, {
|
|
15
|
+
className: cx("tx-tabs__trigger", className),
|
|
16
|
+
...props
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function TabsContent({ className, ...props }) {
|
|
20
|
+
return /* @__PURE__ */ jsx(Tabs.Content, {
|
|
21
|
+
className: cx("tx-tabs__content", className),
|
|
22
|
+
...props
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { Tabs$1 as Tabs, TabsContent, TabsList, TabsTrigger };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/react/ThemeScript.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Put in <head> of the root layout. Sets html[data-theme] before first paint so there's no
|
|
4
|
+
* flash of the wrong theme. Pair it with <html suppressHydrationWarning>.
|
|
5
|
+
*/
|
|
6
|
+
export declare function ThemeScript({ nonce }: {
|
|
7
|
+
nonce?: string;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { THEME_SCRIPT } from "../theme.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/react/ThemeScript.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Put in <head> of the root layout. Sets html[data-theme] before first paint so there's no
|
|
6
|
+
* flash of the wrong theme. Pair it with <html suppressHydrationWarning>.
|
|
7
|
+
*/
|
|
8
|
+
function ThemeScript({ nonce }) {
|
|
9
|
+
return /* @__PURE__ */ jsx("script", {
|
|
10
|
+
nonce,
|
|
11
|
+
dangerouslySetInnerHTML: { __html: THEME_SCRIPT }
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { ThemeScript };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "./cx.js";
|
|
3
|
+
import { useTheme } from "./use-theme.js";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/react/ThemeToggle.tsx
|
|
6
|
+
function ThemeToggle({ className }) {
|
|
7
|
+
const { resolved, toggle } = useTheme();
|
|
8
|
+
const next = resolved === "dark" ? "light" : "dark";
|
|
9
|
+
return /* @__PURE__ */ jsx("button", {
|
|
10
|
+
type: "button",
|
|
11
|
+
className: cx("tx-icon-btn", className),
|
|
12
|
+
onClick: toggle,
|
|
13
|
+
"aria-label": `Switch to ${next} theme`,
|
|
14
|
+
title: `Switch to ${next} theme`,
|
|
15
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
16
|
+
"aria-hidden": "true",
|
|
17
|
+
children: "◐"
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { ThemeToggle };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/react/Tooltip.d.ts
|
|
3
|
+
export interface TooltipProps {
|
|
4
|
+
/** The tooltip text. */
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
/** The element the tooltip describes. Must accept a ref (a DOM element or forwardRef component). */
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
9
|
+
delayDuration?: number;
|
|
10
|
+
}
|
|
11
|
+
/** A tooltip. Self-contained: no provider needed. */
|
|
12
|
+
export declare function Tooltip({ content, children, side, delayDuration }: TooltipProps): import("react").JSX.Element;
|
|
13
|
+
//#endregion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Tooltip } from "radix-ui";
|
|
4
|
+
//#region src/react/Tooltip.tsx
|
|
5
|
+
/** A tooltip. Self-contained: no provider needed. */
|
|
6
|
+
function Tooltip$1({ content, children, side = "top", delayDuration = 300 }) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Tooltip.Provider, {
|
|
8
|
+
delayDuration,
|
|
9
|
+
children: /* @__PURE__ */ jsxs(Tooltip.Root, { children: [/* @__PURE__ */ jsx(Tooltip.Trigger, {
|
|
10
|
+
asChild: true,
|
|
11
|
+
children
|
|
12
|
+
}), /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Content, {
|
|
13
|
+
className: "tx-tooltip",
|
|
14
|
+
side,
|
|
15
|
+
sideOffset: 6,
|
|
16
|
+
children: content
|
|
17
|
+
}) })] })
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { Tooltip$1 as Tooltip };
|
package/dist/react/cx.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from "react";
|
|
2
|
+
//#region src/react/form.d.ts
|
|
3
|
+
export declare function Form({ className, ...props }: ComponentProps<"form">): import("react").JSX.Element;
|
|
4
|
+
/** A labelled field: the label wraps the control, so no id wiring is needed. */
|
|
5
|
+
export declare function Field({ label, hint, className, children, ...props }: ComponentProps<"label"> & {
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
hint?: ReactNode;
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
export declare function Input({ className, ...props }: ComponentProps<"input">): import("react").JSX.Element;
|
|
10
|
+
export declare function Select({ className, ...props }: ComponentProps<"select">): import("react").JSX.Element;
|
|
11
|
+
export declare function Textarea({ className, ...props }: ComponentProps<"textarea">): import("react").JSX.Element;
|
|
12
|
+
type ChoiceProps = Omit<ComponentProps<"input">, "type"> & {
|
|
13
|
+
label: ReactNode;
|
|
14
|
+
};
|
|
15
|
+
export declare function Checkbox({ label, className, ...props }: ChoiceProps): import("react").JSX.Element;
|
|
16
|
+
export declare function Radio({ label, className, ...props }: ChoiceProps): import("react").JSX.Element;
|
|
17
|
+
export declare function Switch({ label, className, ...props }: ChoiceProps): import("react").JSX.Element;
|
|
18
|
+
//#endregion
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { cx } from "./cx.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/react/form.tsx
|
|
4
|
+
function Form({ className, ...props }) {
|
|
5
|
+
return /* @__PURE__ */ jsx("form", {
|
|
6
|
+
className: cx("tx-form", className),
|
|
7
|
+
...props
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/** A labelled field: the label wraps the control, so no id wiring is needed. */
|
|
11
|
+
function Field({ label, hint, className, children, ...props }) {
|
|
12
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
13
|
+
className: cx("tx-field", className),
|
|
14
|
+
...props,
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx("span", {
|
|
17
|
+
className: "tx-label",
|
|
18
|
+
children: label
|
|
19
|
+
}),
|
|
20
|
+
children,
|
|
21
|
+
hint ? /* @__PURE__ */ jsx("span", {
|
|
22
|
+
className: "tx-hint",
|
|
23
|
+
children: hint
|
|
24
|
+
}) : null
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function Input({ className, ...props }) {
|
|
29
|
+
return /* @__PURE__ */ jsx("input", {
|
|
30
|
+
className: cx("tx-input", className),
|
|
31
|
+
...props
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function Select({ className, ...props }) {
|
|
35
|
+
return /* @__PURE__ */ jsx("select", {
|
|
36
|
+
className: cx("tx-select", className),
|
|
37
|
+
...props
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function Textarea({ className, ...props }) {
|
|
41
|
+
return /* @__PURE__ */ jsx("textarea", {
|
|
42
|
+
className: cx("tx-textarea", className),
|
|
43
|
+
...props
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function Checkbox({ label, className, ...props }) {
|
|
47
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
48
|
+
className: cx("tx-check", className),
|
|
49
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
50
|
+
type: "checkbox",
|
|
51
|
+
...props
|
|
52
|
+
}), label]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function Radio({ label, className, ...props }) {
|
|
56
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
57
|
+
className: cx("tx-check", className),
|
|
58
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
59
|
+
type: "radio",
|
|
60
|
+
...props
|
|
61
|
+
}), label]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function Switch({ label, className, ...props }) {
|
|
65
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
66
|
+
className: cx("tx-check", className),
|
|
67
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
68
|
+
type: "checkbox",
|
|
69
|
+
role: "switch",
|
|
70
|
+
className: "tx-switch",
|
|
71
|
+
...props
|
|
72
|
+
}), label]
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { Checkbox, Field, Form, Input, Radio, Select, Switch, Textarea };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cx } from "./cx.js";
|
|
2
|
+
import { AppShell, AppShellProps } from "./AppShell.js";
|
|
3
|
+
import { AppLink, AppLinkProps } from "./AppLink.js";
|
|
4
|
+
import { ThemeScript } from "./ThemeScript.js";
|
|
5
|
+
import { ThemeToggle } from "./ThemeToggle.js";
|
|
6
|
+
import { ThemeState, useTheme } from "./use-theme.js";
|
|
7
|
+
import { useRegistry } from "./use-registry.js";
|
|
8
|
+
import { Container, Row, Section, Stack } from "./layout.js";
|
|
9
|
+
import { Display, Eyebrow, Lead, Mark, Prose, SectionLabel } from "./typography.js";
|
|
10
|
+
import { Button, ButtonProps, ButtonRow, ButtonVariant, LinkButton, LinkButtonProps } from "./Button.js";
|
|
11
|
+
import { Card, CardBody, CardCta, CardGrid, CardMeta, CardProps, CardTitle, CardTop, LinkCard } from "./Card.js";
|
|
12
|
+
import { Badge, BadgeTone, Badges, Tag, Tags } from "./Badge.js";
|
|
13
|
+
import { Alert, AlertTone } from "./Alert.js";
|
|
14
|
+
import { Checkbox, Field, Form, Input, Radio, Select, Switch, Textarea } from "./form.js";
|
|
15
|
+
import { Table } from "./Table.js";
|
|
16
|
+
import { CodeBlock } from "./CodeBlock.js";
|
|
17
|
+
import { Dialog, DialogClose, DialogContent, DialogContentProps, DialogTrigger } from "./Dialog.js";
|
|
18
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "./DropdownMenu.js";
|
|
19
|
+
import { Tooltip, TooltipProps } from "./Tooltip.js";
|
|
20
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
21
|
+
export { Alert, type AlertTone, AppLink, type AppLinkProps, AppShell, type AppShellProps, Badge, type BadgeTone, Badges, Button, type ButtonProps, ButtonRow, type ButtonVariant, Card, CardBody, CardCta, CardGrid, CardMeta, type CardProps, CardTitle, CardTop, Checkbox, CodeBlock, Container, Dialog, DialogClose, DialogContent, type DialogContentProps, DialogTrigger, Display, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Eyebrow, Field, Form, Input, Lead, LinkButton, type LinkButtonProps, LinkCard, Mark, Prose, Radio, Row, Section, SectionLabel, Select, Stack, Switch, Table, Tabs, TabsContent, TabsList, TabsTrigger, Tag, Tags, Textarea, ThemeScript, type ThemeState, ThemeToggle, Tooltip, type TooltipProps, cx, useRegistry, useTheme };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cx } from "./cx.js";
|
|
2
|
+
import { useTheme } from "./use-theme.js";
|
|
3
|
+
import { ThemeToggle } from "./ThemeToggle.js";
|
|
4
|
+
import { useRegistry } from "./use-registry.js";
|
|
5
|
+
import { AppShell } from "./AppShell.js";
|
|
6
|
+
import { AppLink } from "./AppLink.js";
|
|
7
|
+
import { ThemeScript } from "./ThemeScript.js";
|
|
8
|
+
import { Container, Row, Section, Stack } from "./layout.js";
|
|
9
|
+
import { Display, Eyebrow, Lead, Mark, Prose, SectionLabel } from "./typography.js";
|
|
10
|
+
import { Button, ButtonRow, LinkButton } from "./Button.js";
|
|
11
|
+
import { Card, CardBody, CardCta, CardGrid, CardMeta, CardTitle, CardTop, LinkCard } from "./Card.js";
|
|
12
|
+
import { Badge, Badges, Tag, Tags } from "./Badge.js";
|
|
13
|
+
import { Alert } from "./Alert.js";
|
|
14
|
+
import { Checkbox, Field, Form, Input, Radio, Select, Switch, Textarea } from "./form.js";
|
|
15
|
+
import { Table } from "./Table.js";
|
|
16
|
+
import { CodeBlock } from "./CodeBlock.js";
|
|
17
|
+
import { Dialog, DialogClose, DialogContent, DialogTrigger } from "./Dialog.js";
|
|
18
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "./DropdownMenu.js";
|
|
19
|
+
import { Tooltip } from "./Tooltip.js";
|
|
20
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
21
|
+
export { Alert, AppLink, AppShell, Badge, Badges, Button, ButtonRow, Card, CardBody, CardCta, CardGrid, CardMeta, CardTitle, CardTop, Checkbox, CodeBlock, Container, Dialog, DialogClose, DialogContent, DialogTrigger, Display, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Eyebrow, Field, Form, Input, Lead, LinkButton, LinkCard, Mark, Prose, Radio, Row, Section, SectionLabel, Select, Stack, Switch, Table, Tabs, TabsContent, TabsList, TabsTrigger, Tag, Tags, Textarea, ThemeScript, ThemeToggle, Tooltip, cx, useRegistry, useTheme };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
//#region src/react/layout.d.ts
|
|
3
|
+
export declare function Container({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
4
|
+
export declare function Section({ className, ...props }: ComponentProps<"section">): import("react").JSX.Element;
|
|
5
|
+
export declare function Stack({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
6
|
+
export declare function Row({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { cx } from "./cx.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/react/layout.tsx
|
|
4
|
+
function Container({ className, ...props }) {
|
|
5
|
+
return /* @__PURE__ */ jsx("div", {
|
|
6
|
+
className: cx("tx-container", className),
|
|
7
|
+
...props
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
function Section({ className, ...props }) {
|
|
11
|
+
return /* @__PURE__ */ jsx("section", {
|
|
12
|
+
className: cx("tx-section", className),
|
|
13
|
+
...props
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function Stack({ className, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsx("div", {
|
|
18
|
+
className: cx("tx-stack", className),
|
|
19
|
+
...props
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function Row({ className, ...props }) {
|
|
23
|
+
return /* @__PURE__ */ jsx("div", {
|
|
24
|
+
className: cx("tx-row", className),
|
|
25
|
+
...props
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Container, Row, Section, Stack };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentProps, ComponentPropsWithoutRef } from "react";
|
|
2
|
+
//#region src/react/typography.d.ts
|
|
3
|
+
type HeadingLevel = "h1" | "h2" | "h3";
|
|
4
|
+
/** Big serif headline. Wrap words in <em> for the marker highlight. */
|
|
5
|
+
export declare function Display({ as: Tag, className, ...props }: ComponentProps<"h1"> & {
|
|
6
|
+
as?: HeadingLevel;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
8
|
+
/** Marker highlight for any inline text. */
|
|
9
|
+
export declare function Mark({ className, ...props }: ComponentProps<"em">): import("react").JSX.Element;
|
|
10
|
+
export declare function Lead({ className, ...props }: ComponentProps<"p">): import("react").JSX.Element;
|
|
11
|
+
/** Small mono uppercase line above a heading. */
|
|
12
|
+
export declare function Eyebrow({ className, ...props }: ComponentProps<"p">): import("react").JSX.Element;
|
|
13
|
+
/** Tilted serif tag that labels a page section. */
|
|
14
|
+
export declare function SectionLabel({ as: Tag, className, ...props }: ComponentProps<"h2"> & {
|
|
15
|
+
as?: HeadingLevel;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
17
|
+
/** Article typography (MDX output goes inside). `dropcap` styles the first paragraph's letter. */
|
|
18
|
+
export declare function Prose({ as: Tag, dropcap, className, ...props }: ComponentPropsWithoutRef<"article"> & {
|
|
19
|
+
as?: "article" | "div" | "section";
|
|
20
|
+
dropcap?: boolean;
|
|
21
|
+
}): import("react").JSX.Element;
|
|
22
|
+
//#endregion
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { cx } from "./cx.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/react/typography.tsx
|
|
4
|
+
/** Big serif headline. Wrap words in <em> for the marker highlight. */
|
|
5
|
+
function Display({ as: Tag = "h1", className, ...props }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(Tag, {
|
|
7
|
+
className: cx("tx-display", className),
|
|
8
|
+
...props
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
/** Marker highlight for any inline text. */
|
|
12
|
+
function Mark({ className, ...props }) {
|
|
13
|
+
return /* @__PURE__ */ jsx("em", {
|
|
14
|
+
className: cx("tx-mark", className),
|
|
15
|
+
...props
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function Lead({ className, ...props }) {
|
|
19
|
+
return /* @__PURE__ */ jsx("p", {
|
|
20
|
+
className: cx("tx-lead", className),
|
|
21
|
+
...props
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** Small mono uppercase line above a heading. */
|
|
25
|
+
function Eyebrow({ className, ...props }) {
|
|
26
|
+
return /* @__PURE__ */ jsx("p", {
|
|
27
|
+
className: cx("tx-eyebrow", className),
|
|
28
|
+
...props
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** Tilted serif tag that labels a page section. */
|
|
32
|
+
function SectionLabel({ as: Tag = "h2", className, ...props }) {
|
|
33
|
+
return /* @__PURE__ */ jsx(Tag, {
|
|
34
|
+
className: cx("tx-section-label", className),
|
|
35
|
+
...props
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** Article typography (MDX output goes inside). `dropcap` styles the first paragraph's letter. */
|
|
39
|
+
function Prose({ as: Tag = "article", dropcap = false, className, ...props }) {
|
|
40
|
+
return /* @__PURE__ */ jsx(Tag, {
|
|
41
|
+
className: cx("tx-prose", dropcap && "tx-prose--dropcap", className),
|
|
42
|
+
...props
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { Display, Eyebrow, Lead, Mark, Prose, SectionLabel };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Registry } from "../registry/index.js";
|
|
2
|
+
//#region src/react/use-registry.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The app registry. Starts from the build-time `snapshot` (so static HTML has a full nav), then
|
|
5
|
+
* uses the copy cached for this browser session, or fetches /registry.json once per session.
|
|
6
|
+
* In local dev it falls back to the production registry.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useRegistry(snapshot?: Registry | null): Registry | null;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { storage } from "../storage/index.js";
|
|
3
|
+
import { REGISTRY_PATH, REGISTRY_URL, fetchRegistry, isNewerRegistry, parseRegistry } from "../registry/index.js";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
//#region src/react/use-registry.ts
|
|
6
|
+
const CACHE_KEY = "registry";
|
|
7
|
+
function isLocalDev() {
|
|
8
|
+
const host = window.location.hostname;
|
|
9
|
+
return host === "localhost" || host === "127.0.0.1" || host === "[::1]";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The app registry. Starts from the build-time `snapshot` (so static HTML has a full nav), then
|
|
13
|
+
* uses the copy cached for this browser session, or fetches /registry.json once per session.
|
|
14
|
+
* In local dev it falls back to the production registry.
|
|
15
|
+
*/
|
|
16
|
+
function useRegistry(snapshot) {
|
|
17
|
+
const [registry, setRegistry] = useState(snapshot ?? null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const adopt = (candidate) => {
|
|
20
|
+
if (candidate) setRegistry((current) => isNewerRegistry(candidate, current) ? candidate : current);
|
|
21
|
+
};
|
|
22
|
+
const cached = parseRegistry(storage.session.get(CACHE_KEY));
|
|
23
|
+
if (cached) {
|
|
24
|
+
adopt(cached);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
(async () => {
|
|
29
|
+
let fresh = await fetchRegistry(REGISTRY_PATH, { signal: controller.signal });
|
|
30
|
+
if (!fresh && isLocalDev() && !controller.signal.aborted) fresh = await fetchRegistry(REGISTRY_URL, { signal: controller.signal });
|
|
31
|
+
if (fresh && !controller.signal.aborted) {
|
|
32
|
+
storage.session.set(CACHE_KEY, fresh);
|
|
33
|
+
adopt(fresh);
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
36
|
+
return () => controller.abort();
|
|
37
|
+
}, []);
|
|
38
|
+
return registry;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { useRegistry };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ResolvedTheme, ThemePreference } from "../theme.js";
|
|
2
|
+
//#region src/react/use-theme.d.ts
|
|
3
|
+
export interface ThemeState {
|
|
4
|
+
/** What the user picked. Shared by every toyonix app. */
|
|
5
|
+
preference: ThemePreference;
|
|
6
|
+
/** What's actually shown. */
|
|
7
|
+
resolved: ResolvedTheme;
|
|
8
|
+
setPreference: (preference: ThemePreference) => void;
|
|
9
|
+
/** Switches to the opposite of what's shown (an explicit light/dark choice). */
|
|
10
|
+
toggle: () => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The theme preference, synced across tabs and across toyonix apps, applied to html[data-theme].
|
|
14
|
+
* During static rendering and hydration it reports "system"/"light"; the real value follows
|
|
15
|
+
* immediately after (ThemeScript has already painted the right theme).
|
|
16
|
+
*/
|
|
17
|
+
export declare function useTheme(): ThemeState;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { applyResolvedTheme, resolveTheme } from "../theme.js";
|
|
3
|
+
import { storage } from "../storage/index.js";
|
|
4
|
+
import { useCallback, useEffect, useSyncExternalStore } from "react";
|
|
5
|
+
//#region src/react/use-theme.ts
|
|
6
|
+
const DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
7
|
+
function subscribePreference(listener) {
|
|
8
|
+
return storage.shared.subscribe("theme", listener);
|
|
9
|
+
}
|
|
10
|
+
function getPreference() {
|
|
11
|
+
return storage.shared.get("theme") ?? "system";
|
|
12
|
+
}
|
|
13
|
+
function subscribeSystem(listener) {
|
|
14
|
+
if (typeof window === "undefined" || !window.matchMedia) return () => {};
|
|
15
|
+
const query = window.matchMedia(DARK_QUERY);
|
|
16
|
+
query.addEventListener("change", listener);
|
|
17
|
+
return () => query.removeEventListener("change", listener);
|
|
18
|
+
}
|
|
19
|
+
function getSystemDark() {
|
|
20
|
+
return typeof window !== "undefined" && !!window.matchMedia?.(DARK_QUERY).matches;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The theme preference, synced across tabs and across toyonix apps, applied to html[data-theme].
|
|
24
|
+
* During static rendering and hydration it reports "system"/"light"; the real value follows
|
|
25
|
+
* immediately after (ThemeScript has already painted the right theme).
|
|
26
|
+
*/
|
|
27
|
+
function useTheme() {
|
|
28
|
+
const preference = useSyncExternalStore(subscribePreference, getPreference, () => "system");
|
|
29
|
+
const systemDark = useSyncExternalStore(subscribeSystem, getSystemDark, () => false);
|
|
30
|
+
const resolved = resolveTheme(preference, systemDark);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
applyResolvedTheme(resolved);
|
|
33
|
+
}, [resolved]);
|
|
34
|
+
return {
|
|
35
|
+
preference,
|
|
36
|
+
resolved,
|
|
37
|
+
setPreference: useCallback((next) => {
|
|
38
|
+
storage.shared.set("theme", next);
|
|
39
|
+
}, []),
|
|
40
|
+
toggle: useCallback(() => {
|
|
41
|
+
storage.shared.set("theme", resolveTheme(getPreference(), getSystemDark()) === "dark" ? "light" : "dark");
|
|
42
|
+
}, [])
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { useTheme };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AppStatus, Registry } from "./index.js";
|
|
2
|
+
//#region src/registry/build.d.ts
|
|
3
|
+
export declare const SITE_TOPIC = "toyonix-site";
|
|
4
|
+
export interface BuildRegistryOptions {
|
|
5
|
+
/** GitHub user or org that owns the sites, e.g. "ToYoNiX". */
|
|
6
|
+
owner: string;
|
|
7
|
+
/** Repo topic that marks a site. Defaults to "toyonix-site". */
|
|
8
|
+
topic?: string;
|
|
9
|
+
/** GitHub token (GITHUB_TOKEN in Actions). Optional, but unauthenticated calls are rate-limited. */
|
|
10
|
+
token?: string;
|
|
11
|
+
/** Injected for tests. */
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
/** Injected for tests. Defaults to the current time. */
|
|
14
|
+
now?: Date;
|
|
15
|
+
}
|
|
16
|
+
/** The optional "toyonix" field in a site's package.json. */
|
|
17
|
+
export interface SiteMetadata {
|
|
18
|
+
title?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
nav?: boolean;
|
|
21
|
+
order?: number;
|
|
22
|
+
status?: AppStatus;
|
|
23
|
+
}
|
|
24
|
+
export declare class RegistryBuildError extends Error {
|
|
25
|
+
name: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function buildRegistry(options: BuildRegistryOptions): Promise<Registry>;
|
|
28
|
+
//#endregion
|