@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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -2
  3. package/config/eslint.js +68 -0
  4. package/config/prettier.js +20 -0
  5. package/config/tsconfig.base.json +22 -0
  6. package/dist/css/base.css +58 -0
  7. package/dist/css/components.css +915 -0
  8. package/dist/css/fonts/LICENSE-Newsreader.txt +93 -0
  9. package/dist/css/fonts/LICENSE-Space-Grotesk.txt +93 -0
  10. package/dist/css/fonts/LICENSE-Space-Mono.txt +93 -0
  11. package/dist/css/fonts/newsreader-latin-ext-opsz-italic.woff2 +0 -0
  12. package/dist/css/fonts/newsreader-latin-ext-opsz-normal.woff2 +0 -0
  13. package/dist/css/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
  14. package/dist/css/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  15. package/dist/css/fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  16. package/dist/css/fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  17. package/dist/css/fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  18. package/dist/css/fonts/space-grotesk-latin-ext-400-normal.woff2 +0 -0
  19. package/dist/css/fonts/space-grotesk-latin-ext-500-normal.woff2 +0 -0
  20. package/dist/css/fonts/space-grotesk-latin-ext-700-normal.woff2 +0 -0
  21. package/dist/css/fonts/space-mono-latin-400-normal.woff2 +0 -0
  22. package/dist/css/fonts/space-mono-latin-700-normal.woff2 +0 -0
  23. package/dist/css/fonts/space-mono-latin-ext-400-normal.woff2 +0 -0
  24. package/dist/css/fonts/space-mono-latin-ext-700-normal.woff2 +0 -0
  25. package/dist/css/fonts.css +141 -0
  26. package/dist/css/index.css +10 -0
  27. package/dist/css/tailwind.css +46 -0
  28. package/dist/css/tokens.css +66 -0
  29. package/dist/env.d.ts +28 -0
  30. package/dist/env.js +62 -0
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.js +4 -0
  33. package/dist/next/index.d.ts +36 -0
  34. package/dist/next/index.js +103 -0
  35. package/dist/react/Alert.d.ts +8 -0
  36. package/dist/react/Alert.js +16 -0
  37. package/dist/react/AppLink.d.ts +11 -0
  38. package/dist/react/AppLink.js +12 -0
  39. package/dist/react/AppShell.d.ts +20 -0
  40. package/dist/react/AppShell.js +94 -0
  41. package/dist/react/Badge.d.ts +10 -0
  42. package/dist/react/Badge.js +29 -0
  43. package/dist/react/Button.d.ts +16 -0
  44. package/dist/react/Button.js +36 -0
  45. package/dist/react/Card.d.ts +21 -0
  46. package/dist/react/Card.js +61 -0
  47. package/dist/react/CodeBlock.d.ts +8 -0
  48. package/dist/react/CodeBlock.js +16 -0
  49. package/dist/react/Dialog.d.ts +16 -0
  50. package/dist/react/Dialog.js +33 -0
  51. package/dist/react/DropdownMenu.d.ts +12 -0
  52. package/dist/react/DropdownMenu.js +36 -0
  53. package/dist/react/Table.d.ts +5 -0
  54. package/dist/react/Table.js +15 -0
  55. package/dist/react/Tabs.d.ts +9 -0
  56. package/dist/react/Tabs.js +26 -0
  57. package/dist/react/ThemeScript.d.ts +9 -0
  58. package/dist/react/ThemeScript.js +15 -0
  59. package/dist/react/ThemeToggle.d.ts +5 -0
  60. package/dist/react/ThemeToggle.js +22 -0
  61. package/dist/react/Tooltip.d.ts +13 -0
  62. package/dist/react/Tooltip.js +21 -0
  63. package/dist/react/cx.d.ts +4 -0
  64. package/dist/react/cx.js +7 -0
  65. package/dist/react/form.d.ts +19 -0
  66. package/dist/react/form.js +76 -0
  67. package/dist/react/index.d.ts +21 -0
  68. package/dist/react/index.js +21 -0
  69. package/dist/react/layout.d.ts +7 -0
  70. package/dist/react/layout.js +29 -0
  71. package/dist/react/typography.d.ts +23 -0
  72. package/dist/react/typography.js +46 -0
  73. package/dist/react/use-registry.d.ts +9 -0
  74. package/dist/react/use-registry.js +41 -0
  75. package/dist/react/use-theme.d.ts +18 -0
  76. package/dist/react/use-theme.js +46 -0
  77. package/dist/registry/build.d.ts +28 -0
  78. package/dist/registry/build.js +91 -0
  79. package/dist/registry/index.d.ts +49 -0
  80. package/dist/registry/index.js +84 -0
  81. package/dist/slugs.d.ts +15 -0
  82. package/dist/slugs.js +37 -0
  83. package/dist/storage/index.d.ts +39 -0
  84. package/dist/storage/index.js +123 -0
  85. package/dist/theme.d.ts +19 -0
  86. package/dist/theme.js +26 -0
  87. package/package.json +111 -4
package/dist/env.js ADDED
@@ -0,0 +1,62 @@
1
+ //#region src/env.ts
2
+ /**
3
+ * Where this app lives. `withWebKit()` (next.config) bakes both values in at build time as
4
+ * NEXT_PUBLIC_BASE_PATH and NEXT_PUBLIC_APP_ID. The literal `process.env.X` expressions below
5
+ * are what Next replaces, so don't refactor them into a dynamic lookup.
6
+ */
7
+ /** The app id of the root site (`toyonix.github.io`). Every other app's id is its repo name. */
8
+ const ROOT_APP_ID = "root";
9
+ function readBasePath() {
10
+ try {
11
+ return process.env.NEXT_PUBLIC_BASE_PATH;
12
+ } catch {
13
+ return;
14
+ }
15
+ }
16
+ function readAppId() {
17
+ try {
18
+ return process.env.NEXT_PUBLIC_APP_ID;
19
+ } catch {
20
+ return;
21
+ }
22
+ }
23
+ /** Normalizes to "" (root) or "/slug" with no trailing slash. */
24
+ function normalizeBasePath(value) {
25
+ const trimmed = (value ?? "").trim().replace(/^\/+|\/+$/g, "");
26
+ return trimmed ? `/${trimmed}` : "";
27
+ }
28
+ /** "" for the root site, otherwise "/<slug>". */
29
+ function getBasePath() {
30
+ return normalizeBasePath(readBasePath());
31
+ }
32
+ /** "root" for the root site, otherwise the repo name. Used to namespace storage. */
33
+ function getAppId() {
34
+ const id = readAppId()?.trim();
35
+ if (id) return id;
36
+ const basePath = getBasePath();
37
+ return basePath ? basePath.slice(1) : ROOT_APP_ID;
38
+ }
39
+ const ABSOLUTE_URL = /^([a-z][a-z\d+.-]*:|\/\/)/i;
40
+ /**
41
+ * Prefixes an in-app path with this app's basePath. Use it for raw `<a href>`, `fetch`, and
42
+ * asset URLs; `next/link` and `next/image` already handle basePath.
43
+ * Absolute URLs, hash links, and query-only links are returned unchanged.
44
+ */
45
+ function withBasePath(path) {
46
+ if (ABSOLUTE_URL.test(path) || path.startsWith("#") || path.startsWith("?")) return path;
47
+ const normalized = path.startsWith("/") ? path : `/${path}`;
48
+ return `${getBasePath()}${normalized}`;
49
+ }
50
+ /**
51
+ * URL of a page in another toyonix app (or this one). Cross-app links are full page loads,
52
+ * so use a plain `<a>` (or `<AppLink>`), never `next/link`.
53
+ *
54
+ * appHref("gen") → "/gen/"; appHref("gen", "/layouts/") → "/gen/layouts/"; appHref("root") → "/"
55
+ */
56
+ function appHref(app, path = "/") {
57
+ const normalized = path.startsWith("/") ? path : `/${path}`;
58
+ if (app === "root" || app === "") return normalized;
59
+ return `/${app}${normalized}`;
60
+ }
61
+ //#endregion
62
+ export { ROOT_APP_ID, appHref, getAppId, getBasePath, normalizeBasePath, withBasePath };
@@ -0,0 +1,4 @@
1
+ import { ROOT_APP_ID, appHref, getAppId, getBasePath, normalizeBasePath, withBasePath } from "./env.js";
2
+ import { RESERVED_SLUGS, isReservedSlug, isRootRepo, isValidSlug, repoToAppId } from "./slugs.js";
3
+ import { ResolvedTheme, THEME_PREFERENCES, THEME_SCRIPT, ThemePreference, applyResolvedTheme, isThemePreference, resolveTheme } from "./theme.js";
4
+ export { RESERVED_SLUGS, ROOT_APP_ID, type ResolvedTheme, THEME_PREFERENCES, THEME_SCRIPT, type ThemePreference, appHref, applyResolvedTheme, getAppId, getBasePath, isReservedSlug, isRootRepo, isThemePreference, isValidSlug, normalizeBasePath, repoToAppId, resolveTheme, withBasePath };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { ROOT_APP_ID, appHref, getAppId, getBasePath, normalizeBasePath, withBasePath } from "./env.js";
2
+ import { RESERVED_SLUGS, isReservedSlug, isRootRepo, isValidSlug, repoToAppId } from "./slugs.js";
3
+ import { THEME_PREFERENCES, THEME_SCRIPT, applyResolvedTheme, isThemePreference, resolveTheme } from "./theme.js";
4
+ export { RESERVED_SLUGS, ROOT_APP_ID, THEME_PREFERENCES, THEME_SCRIPT, appHref, applyResolvedTheme, getAppId, getBasePath, isReservedSlug, isRootRepo, isThemePreference, isValidSlug, normalizeBasePath, repoToAppId, resolveTheme, withBasePath };
@@ -0,0 +1,36 @@
1
+ import { NextConfig } from "next";
2
+ //#region src/next/index.d.ts
3
+ export interface ResolvedSite {
4
+ /** "" for the root site, otherwise "/<repo>". */
5
+ basePath: string;
6
+ /** "root" for the root site, otherwise the repo name. */
7
+ appId: string;
8
+ /** Which input decided the basePath, for debugging. */
9
+ source: "PAGES_BASE_PATH" | "GITHUB_REPOSITORY" | "git remote" | "default";
10
+ }
11
+ export interface ResolveOptions {
12
+ /** Defaults to process.env. */
13
+ env?: Record<string, string | undefined>;
14
+ /** Returns the `origin` remote URL, or undefined. Injected for tests. */
15
+ gitRemote?: () => string | undefined;
16
+ }
17
+ /** "https://github.com/ToYoNiX/gen.git" or "git@github.com:ToYoNiX/gen.git" → "gen". */
18
+ export declare function repoNameFromRemote(remote: string): string | undefined;
19
+ /**
20
+ * Works out where this site is served from, with no per-repo config:
21
+ * 1. PAGES_BASE_PATH (set by the deploy workflow from actions/configure-pages)
22
+ * 2. GITHUB_REPOSITORY ("owner/repo", set in GitHub Actions)
23
+ * 3. the `origin` git remote (local dev)
24
+ * 4. "" (root)
25
+ */
26
+ export declare function resolveSite(options?: ResolveOptions): ResolvedSite;
27
+ /**
28
+ * Wraps a Next config for a toyonix site: static export for GitHub Pages, basePath resolved
29
+ * from the repo, and NEXT_PUBLIC_BASE_PATH / NEXT_PUBLIC_APP_ID baked in for the kit.
30
+ *
31
+ * // next.config.ts
32
+ * import { withWebKit } from "@toyonix/web-kit/next";
33
+ * export default withWebKit({});
34
+ */
35
+ export declare function withWebKit(config?: NextConfig, options?: ResolveOptions): NextConfig;
36
+ //#endregion
@@ -0,0 +1,103 @@
1
+ import { ROOT_APP_ID, normalizeBasePath } from "../env.js";
2
+ import { isRootRepo } from "../slugs.js";
3
+ import { execFileSync } from "node:child_process";
4
+ //#region src/next/index.ts
5
+ /**
6
+ * @toyonix/web-kit/next: Next.js config integration. Node-only; import it from next.config.ts.
7
+ */
8
+ function defaultGitRemote() {
9
+ try {
10
+ return execFileSync("git", [
11
+ "remote",
12
+ "get-url",
13
+ "origin"
14
+ ], {
15
+ encoding: "utf8",
16
+ stdio: [
17
+ "ignore",
18
+ "pipe",
19
+ "ignore"
20
+ ]
21
+ }).trim();
22
+ } catch {
23
+ return;
24
+ }
25
+ }
26
+ /** "https://github.com/ToYoNiX/gen.git" or "git@github.com:ToYoNiX/gen.git" → "gen". */
27
+ function repoNameFromRemote(remote) {
28
+ return remote.trim().match(/[/:]([^/:]+?)(?:\.git)?\/?$/)?.[1];
29
+ }
30
+ function fromRepoName(repo) {
31
+ return isRootRepo(repo) ? {
32
+ basePath: "",
33
+ appId: ROOT_APP_ID
34
+ } : {
35
+ basePath: `/${repo}`,
36
+ appId: repo
37
+ };
38
+ }
39
+ /**
40
+ * Works out where this site is served from, with no per-repo config:
41
+ * 1. PAGES_BASE_PATH (set by the deploy workflow from actions/configure-pages)
42
+ * 2. GITHUB_REPOSITORY ("owner/repo", set in GitHub Actions)
43
+ * 3. the `origin` git remote (local dev)
44
+ * 4. "" (root)
45
+ */
46
+ function resolveSite(options = {}) {
47
+ const env = options.env ?? process.env;
48
+ if (env.PAGES_BASE_PATH !== void 0) {
49
+ const basePath = normalizeBasePath(env.PAGES_BASE_PATH);
50
+ return {
51
+ basePath,
52
+ appId: basePath ? basePath.slice(1) : ROOT_APP_ID,
53
+ source: "PAGES_BASE_PATH"
54
+ };
55
+ }
56
+ const repo = env.GITHUB_REPOSITORY?.split("/")[1];
57
+ if (repo) return {
58
+ ...fromRepoName(repo),
59
+ source: "GITHUB_REPOSITORY"
60
+ };
61
+ const remote = (options.gitRemote ?? defaultGitRemote)();
62
+ const remoteRepo = remote ? repoNameFromRemote(remote) : void 0;
63
+ if (remoteRepo) return {
64
+ ...fromRepoName(remoteRepo),
65
+ source: "git remote"
66
+ };
67
+ return {
68
+ basePath: "",
69
+ appId: ROOT_APP_ID,
70
+ source: "default"
71
+ };
72
+ }
73
+ /**
74
+ * Wraps a Next config for a toyonix site: static export for GitHub Pages, basePath resolved
75
+ * from the repo, and NEXT_PUBLIC_BASE_PATH / NEXT_PUBLIC_APP_ID baked in for the kit.
76
+ *
77
+ * // next.config.ts
78
+ * import { withWebKit } from "@toyonix/web-kit/next";
79
+ * export default withWebKit({});
80
+ */
81
+ function withWebKit(config = {}, options = {}) {
82
+ if (config.output !== void 0 && config.output !== "export") throw new Error(`withWebKit: toyonix sites are statically exported; remove output: "${config.output}".`);
83
+ if (config.basePath !== void 0) throw new Error("withWebKit: basePath is derived from the repo name; remove it from next.config.");
84
+ if (config.trailingSlash === false) throw new Error("withWebKit: trailingSlash must stay true for GitHub Pages.");
85
+ const site = resolveSite(options);
86
+ return {
87
+ ...config,
88
+ output: "export",
89
+ trailingSlash: true,
90
+ basePath: site.basePath,
91
+ images: {
92
+ ...config.images,
93
+ unoptimized: true
94
+ },
95
+ env: {
96
+ ...config.env,
97
+ NEXT_PUBLIC_BASE_PATH: site.basePath,
98
+ NEXT_PUBLIC_APP_ID: site.appId
99
+ }
100
+ };
101
+ }
102
+ //#endregion
103
+ export { repoNameFromRemote, resolveSite, withWebKit };
@@ -0,0 +1,8 @@
1
+ import { ComponentProps, ReactNode } from "react";
2
+ //#region src/react/Alert.d.ts
3
+ export type AlertTone = "info" | "success" | "warning" | "danger";
4
+ export declare function Alert({ tone, title, className, children, role, ...props }: ComponentProps<"div"> & {
5
+ tone?: AlertTone;
6
+ title?: ReactNode;
7
+ }): import("react").JSX.Element;
8
+ //#endregion
@@ -0,0 +1,16 @@
1
+ import { cx } from "./cx.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/react/Alert.tsx
4
+ function Alert({ tone = "info", title, className, children, role, ...props }) {
5
+ return /* @__PURE__ */ jsxs("div", {
6
+ role: role ?? (tone === "danger" || tone === "warning" ? "alert" : "status"),
7
+ className: cx("tx-alert", tone !== "info" && `tx-alert--${tone}`, className),
8
+ ...props,
9
+ children: [title ? /* @__PURE__ */ jsx("strong", {
10
+ className: "tx-alert__title",
11
+ children: title
12
+ }) : null, children]
13
+ });
14
+ }
15
+ //#endregion
16
+ export { Alert };
@@ -0,0 +1,11 @@
1
+ import { ComponentProps } from "react";
2
+ //#region src/react/AppLink.d.ts
3
+ export interface AppLinkProps extends Omit<ComponentProps<"a">, "href"> {
4
+ /** Target app id: a repo name, or "root". */
5
+ app: string;
6
+ /** Path inside that app. Defaults to its home page. */
7
+ path?: string;
8
+ }
9
+ /** A link to another toyonix app. Always a full page load, never client-side navigation. */
10
+ export declare function AppLink({ app, path, ...props }: AppLinkProps): import("react").JSX.Element;
11
+ //#endregion
@@ -0,0 +1,12 @@
1
+ import { appHref } from "../env.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/react/AppLink.tsx
4
+ /** A link to another toyonix app. Always a full page load, never client-side navigation. */
5
+ function AppLink({ app, path, ...props }) {
6
+ return /* @__PURE__ */ jsx("a", {
7
+ href: appHref(app, path),
8
+ ...props
9
+ });
10
+ }
11
+ //#endregion
12
+ export { AppLink };
@@ -0,0 +1,20 @@
1
+ import { Registry } from "../registry/index.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/react/AppShell.d.ts
4
+ export interface AppShellProps {
5
+ children: ReactNode;
6
+ /** Build-time registry snapshot from `getRegistrySnapshot()`, so the nav is in the static HTML. */
7
+ registry?: Registry | null;
8
+ /** This app's nav title, used if the registry doesn't list it yet (e.g. a brand-new app). */
9
+ appTitle?: string;
10
+ /** App-local links, shown in a bar under the shared header. Set aria-current yourself. */
11
+ nav?: ReactNode;
12
+ /** Replaces the default footer content. */
13
+ footer?: ReactNode;
14
+ }
15
+ /**
16
+ * The shared toyonix chrome: header with the logo, cross-app nav, and theme toggle; optional
17
+ * app-local nav; main; footer. Every app renders its pages inside it.
18
+ */
19
+ export declare function AppShell({ children, registry, appTitle, nav, footer }: AppShellProps): import("react").JSX.Element;
20
+ //#endregion
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import { appHref, getAppId } from "../env.js";
3
+ import { navApps } from "../registry/index.js";
4
+ import { ThemeToggle } from "./ThemeToggle.js";
5
+ import { useRegistry } from "./use-registry.js";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/react/AppShell.tsx
8
+ /**
9
+ * The shared toyonix chrome: header with the logo, cross-app nav, and theme toggle; optional
10
+ * app-local nav; main; footer. Every app renders its pages inside it.
11
+ */
12
+ function AppShell({ children, registry, appTitle, nav, footer }) {
13
+ const appId = getAppId();
14
+ const apps = navApps(useRegistry(registry));
15
+ if (appId !== "root" && !apps.some((app) => app.id === appId)) apps.push({
16
+ id: appId,
17
+ title: appTitle ?? appId,
18
+ description: "",
19
+ path: appHref(appId),
20
+ status: "live",
21
+ nav: true,
22
+ order: Number.MAX_SAFE_INTEGER
23
+ });
24
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
25
+ /* @__PURE__ */ jsx("a", {
26
+ className: "tx-skip-link",
27
+ href: "#main",
28
+ children: "Skip to content"
29
+ }),
30
+ /* @__PURE__ */ jsx("header", {
31
+ className: "tx-header",
32
+ children: /* @__PURE__ */ jsxs("div", {
33
+ className: "tx-container tx-header__inner",
34
+ children: [
35
+ /* @__PURE__ */ jsxs("a", {
36
+ className: "tx-logo",
37
+ href: "/",
38
+ children: [/* @__PURE__ */ jsx("span", {
39
+ className: "tx-logo__mark",
40
+ "aria-hidden": "true",
41
+ children: "t"
42
+ }), /* @__PURE__ */ jsx("span", { children: "toyonix" })]
43
+ }),
44
+ /* @__PURE__ */ jsxs("nav", {
45
+ className: "tx-nav",
46
+ "aria-label": "toyonix apps",
47
+ children: [/* @__PURE__ */ jsx("a", {
48
+ href: "/",
49
+ "aria-current": appId === "root" ? "true" : void 0,
50
+ children: "Home"
51
+ }), apps.map((app) => /* @__PURE__ */ jsx("a", {
52
+ href: app.path,
53
+ "aria-current": app.id === appId ? "true" : void 0,
54
+ children: app.title
55
+ }, app.id))]
56
+ }),
57
+ /* @__PURE__ */ jsx(ThemeToggle, {})
58
+ ]
59
+ })
60
+ }),
61
+ nav ? /* @__PURE__ */ jsx("nav", {
62
+ className: "tx-subnav",
63
+ "aria-label": "Section",
64
+ children: /* @__PURE__ */ jsx("div", {
65
+ className: "tx-container tx-subnav__inner",
66
+ children: nav
67
+ })
68
+ }) : null,
69
+ /* @__PURE__ */ jsx("main", {
70
+ id: "main",
71
+ className: "tx-main",
72
+ children
73
+ }),
74
+ /* @__PURE__ */ jsx("footer", {
75
+ className: "tx-footer",
76
+ children: /* @__PURE__ */ jsx("div", {
77
+ className: "tx-container tx-footer__inner",
78
+ children: footer ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
79
+ suppressHydrationWarning: true,
80
+ children: [
81
+ "© ",
82
+ (/* @__PURE__ */ new Date()).getFullYear(),
83
+ " ToYoNiX"
84
+ ]
85
+ }), /* @__PURE__ */ jsxs("span", { children: ["built with ", /* @__PURE__ */ jsx("a", {
86
+ href: "https://github.com/ToYoNiX/web-kit",
87
+ children: "@toyonix/web-kit"
88
+ })] })] })
89
+ })
90
+ })
91
+ ] });
92
+ }
93
+ //#endregion
94
+ export { AppShell };
@@ -0,0 +1,10 @@
1
+ import { ComponentProps } from "react";
2
+ //#region src/react/Badge.d.ts
3
+ export type BadgeTone = "neutral" | "accent" | "success" | "warning" | "danger";
4
+ export declare function Badge({ tone, className, ...props }: ComponentProps<"span"> & {
5
+ tone?: BadgeTone;
6
+ }): import("react").JSX.Element;
7
+ export declare function Badges({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
8
+ export declare function Tag({ className, ...props }: ComponentProps<"span">): import("react").JSX.Element;
9
+ export declare function Tags({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
10
+ //#endregion
@@ -0,0 +1,29 @@
1
+ import { cx } from "./cx.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/react/Badge.tsx
4
+ function Badge({ tone = "neutral", className, ...props }) {
5
+ return /* @__PURE__ */ jsx("span", {
6
+ className: cx("tx-badge", `tx-badge--${tone}`, className),
7
+ ...props
8
+ });
9
+ }
10
+ function Badges({ className, ...props }) {
11
+ return /* @__PURE__ */ jsx("div", {
12
+ className: cx("tx-badges", className),
13
+ ...props
14
+ });
15
+ }
16
+ function Tag({ className, ...props }) {
17
+ return /* @__PURE__ */ jsx("span", {
18
+ className: cx("tx-tag", className),
19
+ ...props
20
+ });
21
+ }
22
+ function Tags({ className, ...props }) {
23
+ return /* @__PURE__ */ jsx("div", {
24
+ className: cx("tx-tags", className),
25
+ ...props
26
+ });
27
+ }
28
+ //#endregion
29
+ export { Badge, Badges, Tag, Tags };
@@ -0,0 +1,16 @@
1
+ import { ComponentProps } from "react";
2
+ //#region src/react/Button.d.ts
3
+ export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
4
+ interface ButtonOwnProps {
5
+ variant?: ButtonVariant;
6
+ /** Render the single child (e.g. next/link's <Link>) with button styling instead of a <button>. */
7
+ asChild?: boolean;
8
+ }
9
+ export type ButtonProps = ButtonOwnProps & ComponentProps<"button">;
10
+ export declare function Button({ variant, asChild, className, type, ...props }: ButtonProps): import("react").JSX.Element;
11
+ export type LinkButtonProps = ButtonOwnProps & ComponentProps<"a">;
12
+ /** A link styled as a button. For in-app links use <Button asChild><Link …/></Button>. */
13
+ export declare function LinkButton({ variant, asChild, className, ...props }: LinkButtonProps): import("react").JSX.Element;
14
+ export declare function ButtonRow({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
15
+ //#endregion
16
+ export {};
@@ -0,0 +1,36 @@
1
+ import { cx } from "./cx.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Slot } from "radix-ui";
4
+ //#region src/react/Button.tsx
5
+ function Button({ variant = "primary", asChild = false, className, type, ...props }) {
6
+ const classes = cx("tx-btn", `tx-btn--${variant}`, className);
7
+ if (asChild) return /* @__PURE__ */ jsx(Slot.Root, {
8
+ className: classes,
9
+ ...props
10
+ });
11
+ return /* @__PURE__ */ jsx("button", {
12
+ type: type ?? "button",
13
+ className: classes,
14
+ ...props
15
+ });
16
+ }
17
+ /** A link styled as a button. For in-app links use <Button asChild><Link …/></Button>. */
18
+ function LinkButton({ variant = "primary", asChild = false, className, ...props }) {
19
+ const classes = cx("tx-btn", `tx-btn--${variant}`, className);
20
+ if (asChild) return /* @__PURE__ */ jsx(Slot.Root, {
21
+ className: classes,
22
+ ...props
23
+ });
24
+ return /* @__PURE__ */ jsx("a", {
25
+ className: classes,
26
+ ...props
27
+ });
28
+ }
29
+ function ButtonRow({ className, ...props }) {
30
+ return /* @__PURE__ */ jsx("div", {
31
+ className: cx("tx-btn-row", className),
32
+ ...props
33
+ });
34
+ }
35
+ //#endregion
36
+ export { Button, ButtonRow, LinkButton };
@@ -0,0 +1,21 @@
1
+ import { ComponentProps } from "react";
2
+ //#region src/react/Card.d.ts
3
+ export type CardProps = ComponentProps<"div"> & {
4
+ /** Render the single child (e.g. <Link>) as the card. */
5
+ asChild?: boolean;
6
+ /** Hover lift + link styling. On by default when `asChild` is used. */
7
+ interactive?: boolean;
8
+ };
9
+ export declare function Card({ asChild, interactive, className, ...props }: CardProps): import("react").JSX.Element;
10
+ /** A card that is a plain link (e.g. to another app). Lifts on hover. */
11
+ export declare function LinkCard({ className, ...props }: ComponentProps<"a">): import("react").JSX.Element;
12
+ /** Grid of color-blocked, tilted cards (cycling card-1 → card-2 → card-3). */
13
+ export declare function CardGrid({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
14
+ export declare function CardTop({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
15
+ export declare function CardMeta({ className, ...props }: ComponentProps<"span">): import("react").JSX.Element;
16
+ export declare function CardTitle({ as: Tag, className, ...props }: ComponentProps<"h3"> & {
17
+ as?: "h2" | "h3" | "h4";
18
+ }): import("react").JSX.Element;
19
+ export declare function CardBody({ className, ...props }: ComponentProps<"p">): import("react").JSX.Element;
20
+ export declare function CardCta({ className, ...props }: ComponentProps<"span">): import("react").JSX.Element;
21
+ //#endregion
@@ -0,0 +1,61 @@
1
+ import { cx } from "./cx.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Slot } from "radix-ui";
4
+ //#region src/react/Card.tsx
5
+ function Card({ asChild = false, interactive, className, ...props }) {
6
+ const classes = cx("tx-card", (interactive ?? asChild) && "tx-card--link", className);
7
+ if (asChild) return /* @__PURE__ */ jsx(Slot.Root, {
8
+ className: classes,
9
+ ...props
10
+ });
11
+ return /* @__PURE__ */ jsx("div", {
12
+ className: classes,
13
+ ...props
14
+ });
15
+ }
16
+ /** A card that is a plain link (e.g. to another app). Lifts on hover. */
17
+ function LinkCard({ className, ...props }) {
18
+ return /* @__PURE__ */ jsx("a", {
19
+ className: cx("tx-card", "tx-card--link", className),
20
+ ...props
21
+ });
22
+ }
23
+ /** Grid of color-blocked, tilted cards (cycling card-1 → card-2 → card-3). */
24
+ function CardGrid({ className, ...props }) {
25
+ return /* @__PURE__ */ jsx("div", {
26
+ className: cx("tx-card-grid", className),
27
+ ...props
28
+ });
29
+ }
30
+ function CardTop({ className, ...props }) {
31
+ return /* @__PURE__ */ jsx("div", {
32
+ className: cx("tx-card__top", className),
33
+ ...props
34
+ });
35
+ }
36
+ function CardMeta({ className, ...props }) {
37
+ return /* @__PURE__ */ jsx("span", {
38
+ className: cx("tx-card__meta", className),
39
+ ...props
40
+ });
41
+ }
42
+ function CardTitle({ as: Tag = "h3", className, ...props }) {
43
+ return /* @__PURE__ */ jsx(Tag, {
44
+ className: cx("tx-card__title", className),
45
+ ...props
46
+ });
47
+ }
48
+ function CardBody({ className, ...props }) {
49
+ return /* @__PURE__ */ jsx("p", {
50
+ className: cx("tx-card__body", className),
51
+ ...props
52
+ });
53
+ }
54
+ function CardCta({ className, ...props }) {
55
+ return /* @__PURE__ */ jsx("span", {
56
+ className: cx("tx-card__cta", className),
57
+ ...props
58
+ });
59
+ }
60
+ //#endregion
61
+ export { Card, CardBody, CardCta, CardGrid, CardMeta, CardTitle, CardTop, LinkCard };
@@ -0,0 +1,8 @@
1
+ import { ComponentProps } from "react";
2
+ //#region src/react/CodeBlock.d.ts
3
+ /**
4
+ * A code block. Pass plain text, or pre-highlighted markup using the token classes
5
+ * tx-code__comment, tx-code__key, and tx-code__string.
6
+ */
7
+ export declare function CodeBlock({ className, children, ...props }: ComponentProps<"pre">): import("react").JSX.Element;
8
+ //#endregion
@@ -0,0 +1,16 @@
1
+ import { cx } from "./cx.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/react/CodeBlock.tsx
4
+ /**
5
+ * A code block. Pass plain text, or pre-highlighted markup using the token classes
6
+ * tx-code__comment, tx-code__key, and tx-code__string.
7
+ */
8
+ function CodeBlock({ className, children, ...props }) {
9
+ return /* @__PURE__ */ jsx("pre", {
10
+ className: cx("tx-code", className),
11
+ ...props,
12
+ children: /* @__PURE__ */ jsx("code", { children })
13
+ });
14
+ }
15
+ //#endregion
16
+ export { CodeBlock };
@@ -0,0 +1,16 @@
1
+ import { ComponentProps, ReactNode } from "react";
2
+ import { Dialog } from "radix-ui";
3
+ //#region src/react/Dialog.d.ts
4
+ declare const Dialog$1: import("react").FC<Dialog.DialogProps>;
5
+ export declare const DialogTrigger: import("react").ForwardRefExoticComponent<Dialog.DialogTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
6
+ export declare const DialogClose: import("react").ForwardRefExoticComponent<Dialog.DialogCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
7
+ export interface DialogContentProps extends Omit<ComponentProps<typeof Dialog.Content>, "title"> {
8
+ title: ReactNode;
9
+ description?: ReactNode;
10
+ /** Hide the × button (e.g. when the dialog has its own close action). */
11
+ hideClose?: boolean;
12
+ }
13
+ /** A modal dialog. The title is required for screen readers. */
14
+ export declare function DialogContent({ title, description, hideClose, className, children, ...props }: DialogContentProps): import("react").JSX.Element;
15
+ //#endregion
16
+ export { Dialog$1 as Dialog };
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { cx } from "./cx.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Dialog } from "radix-ui";
5
+ //#region src/react/Dialog.tsx
6
+ const Dialog$1 = Dialog.Root;
7
+ const DialogTrigger = Dialog.Trigger;
8
+ const DialogClose = Dialog.Close;
9
+ /** A modal dialog. The title is required for screen readers. */
10
+ function DialogContent({ title, description, hideClose, className, children, ...props }) {
11
+ return /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: "tx-overlay" }), /* @__PURE__ */ jsxs(Dialog.Content, {
12
+ className: cx("tx-dialog", className),
13
+ ...props,
14
+ children: [
15
+ /* @__PURE__ */ jsx(Dialog.Title, {
16
+ className: "tx-dialog__title",
17
+ children: title
18
+ }),
19
+ description ? /* @__PURE__ */ jsx(Dialog.Description, {
20
+ className: "tx-dialog__description",
21
+ children: description
22
+ }) : null,
23
+ children,
24
+ hideClose ? null : /* @__PURE__ */ jsx(Dialog.Close, {
25
+ className: "tx-btn tx-btn--ghost tx-dialog__close",
26
+ "aria-label": "Close",
27
+ children: "✕"
28
+ })
29
+ ]
30
+ })] });
31
+ }
32
+ //#endregion
33
+ export { Dialog$1 as Dialog, DialogClose, DialogContent, DialogTrigger };
@@ -0,0 +1,12 @@
1
+ import { ComponentProps } from "react";
2
+ import { DropdownMenu } from "radix-ui";
3
+ //#region src/react/DropdownMenu.d.ts
4
+ declare const DropdownMenu$1: import("react").FC<DropdownMenu.DropdownMenuProps>;
5
+ export declare const DropdownMenuTrigger: import("react").ForwardRefExoticComponent<DropdownMenu.DropdownMenuTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
6
+ export declare const DropdownMenuGroup: import("react").ForwardRefExoticComponent<DropdownMenu.DropdownMenuGroupProps & import("react").RefAttributes<HTMLDivElement>>;
7
+ export declare function DropdownMenuContent({ className, sideOffset, align, ...props }: ComponentProps<typeof DropdownMenu.Content>): import("react").JSX.Element;
8
+ export declare function DropdownMenuItem({ className, ...props }: ComponentProps<typeof DropdownMenu.Item>): import("react").JSX.Element;
9
+ export declare function DropdownMenuLabel({ className, ...props }: ComponentProps<typeof DropdownMenu.Label>): import("react").JSX.Element;
10
+ export declare function DropdownMenuSeparator({ className, ...props }: ComponentProps<typeof DropdownMenu.Separator>): import("react").JSX.Element;
11
+ //#endregion
12
+ export { DropdownMenu$1 as DropdownMenu };