@tenphi/starlight 0.5.0 → 0.6.1

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 (38) hide show
  1. package/dist/components/Card.astro +5 -3
  2. package/dist/components/GlobalStyles.js +761 -0
  3. package/dist/components/LayoutComponents.js +404 -0
  4. package/dist/components/Logo.astro +39 -0
  5. package/dist/components/MobileNavigationTabs.astro +7 -2
  6. package/dist/components/PackageVersion.astro +22 -0
  7. package/dist/components/Preview.astro +21 -10
  8. package/dist/components/Steps.astro +5 -1
  9. package/dist/components/Tabs.astro +9 -2
  10. package/dist/components/TastyComponents.js +156 -0
  11. package/dist/components/component-styles.test.ts +75 -0
  12. package/dist/components/component-styles.ts +79 -0
  13. package/dist/components/customize-component.js +10 -0
  14. package/dist/components/svg-icon.test.ts +11 -0
  15. package/dist/components/svg-icon.ts +11 -0
  16. package/dist/components/tasty-states.d.ts +2 -0
  17. package/dist/components/tasty-states.js +21 -0
  18. package/dist/components-public.d.ts +1 -0
  19. package/dist/components.d.ts +2 -1
  20. package/dist/components.js +2 -1
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +297 -163
  24. package/dist/index.js.map +1 -1
  25. package/dist/{navigation-CC0dlAL8.js → navigation-CkQXI2Zb.js} +41 -2
  26. package/dist/navigation-CkQXI2Zb.js.map +1 -0
  27. package/dist/navigation.d.ts +11 -2
  28. package/dist/navigation.d.ts.map +1 -1
  29. package/dist/navigation.js +2 -2
  30. package/dist/overrides/Header.astro +28 -5
  31. package/dist/overrides/MobileMenuFooter.astro +15 -0
  32. package/dist/overrides/ThemeSelect.astro +69 -0
  33. package/dist/routes/DocsPage.astro +43 -145
  34. package/package.json +5 -9
  35. package/dist/components/NavigationTree.astro +0 -98
  36. package/dist/navigation-CC0dlAL8.js.map +0 -1
  37. package/dist/styles.css +0 -1346
  38. package/dist/styles.d.ts +0 -1
@@ -0,0 +1,156 @@
1
+ import { tasty } from "@tenphi/tasty";
2
+ import { customizeComponent } from "./customize-component.js";
3
+ import { configureCookbookStates } from "./tasty-states.js";
4
+
5
+ configureCookbookStates();
6
+
7
+ export const CardRoot = customizeComponent(
8
+ "Card",
9
+ { as: "article" },
10
+ tasty({
11
+ as: "article",
12
+ styles: {
13
+ display: "grid",
14
+ gap: "1.5x",
15
+ padding: "2.5x",
16
+ color: "#text",
17
+ textDecoration: "none",
18
+ border: true,
19
+ radius: "1cr",
20
+ fill: "#surface-2",
21
+ shadow: "0 1px 2px #shadow",
22
+ transition: "fill 120ms ease, shadow 120ms ease, translate 120ms ease",
23
+
24
+ Heading2: {
25
+ $: "h2",
26
+ margin: "0",
27
+ },
28
+ Heading3: {
29
+ $: "h3",
30
+ margin: "0",
31
+ },
32
+ Paragraph: {
33
+ $: "p",
34
+ margin: "0",
35
+ },
36
+ },
37
+ }),
38
+ );
39
+
40
+ export const CardLink = tasty(CardRoot, {
41
+ as: "a",
42
+ styles: {
43
+ fill: {
44
+ "": "#surface-2",
45
+ ":hover": "#surface-2-hover",
46
+ ":active": "#surface-2-pressed",
47
+ },
48
+ shadow: {
49
+ "": "0 1px 2px #shadow",
50
+ ":hover": "0 .75x 2x #shadow",
51
+ },
52
+ translate: {
53
+ "": "0",
54
+ ":hover": "0 -1px",
55
+ ":active": "0",
56
+ },
57
+ },
58
+ });
59
+
60
+ const previewElements = {
61
+ Caption: "figcaption",
62
+ Stage: "div",
63
+ Frame: "iframe",
64
+ Code: "details",
65
+ Summary: "summary",
66
+ Pre: "pre",
67
+ };
68
+
69
+ export const PreviewRoot = customizeComponent(
70
+ "Preview",
71
+ { as: "figure", elements: previewElements },
72
+ tasty({
73
+ as: "figure",
74
+ styles: {
75
+ margin: "0",
76
+ overflow: "clip",
77
+ color: "#text",
78
+ border: true,
79
+ radius: "1cr",
80
+ fill: "#surface",
81
+ shadow: "0 1px 2px #shadow",
82
+
83
+ Caption: {
84
+ padding: "1.5x 2x",
85
+ preset: "small",
86
+ fill: "#surface-2",
87
+ },
88
+ Stage: {
89
+ padding: "3x",
90
+ fill: "#surface",
91
+ },
92
+ Frame: {
93
+ display: "block",
94
+ width: "100%",
95
+ height: "min 18rem",
96
+ border: "0",
97
+ fill: "#surface",
98
+ },
99
+ Code: {
100
+ border: "1bw top #border",
101
+ },
102
+ Summary: {
103
+ padding: "1.5x 2x",
104
+ preset: "small",
105
+ fill: "#surface-2",
106
+ cursor: "pointer",
107
+ },
108
+ Pre: {
109
+ margin: "0",
110
+ radius: "0",
111
+ },
112
+ },
113
+ elements: previewElements,
114
+ }),
115
+ );
116
+
117
+ export const StepsRoot = customizeComponent(
118
+ "Steps",
119
+ { as: "ol" },
120
+ tasty({
121
+ as: "ol",
122
+ styles: {
123
+ display: "grid",
124
+ gap: "2x",
125
+ padding: "4x left",
126
+ border: "1bw left #border",
127
+
128
+ Item: {
129
+ $: "> li",
130
+ padding: "1x left",
131
+ },
132
+ Marker: {
133
+ $: "> li::marker",
134
+ color: "#accent-text",
135
+ preset: "bold",
136
+ },
137
+ },
138
+ }),
139
+ );
140
+
141
+ export const TabsRoot = customizeComponent(
142
+ "Tabs",
143
+ { as: "div" },
144
+ tasty({
145
+ as: "div",
146
+ styles: {
147
+ display: "flex",
148
+ flow: "row wrap",
149
+ gap: "1x",
150
+ padding: "1x",
151
+ border: true,
152
+ radius: "1cr",
153
+ fill: "#surface-2",
154
+ },
155
+ }),
156
+ );
@@ -0,0 +1,75 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import {
3
+ configureComponentStyles,
4
+ resolveLegacyAnatomyStyles,
5
+ resolveComponentStyleOverride,
6
+ resolveComponentStyles,
7
+ } from "./component-styles.js";
8
+
9
+ const defaults = {
10
+ color: "#text",
11
+ padding: "2x",
12
+ Label: { color: "#text-soft", fontWeight: 500 },
13
+ };
14
+
15
+ afterEach(() => configureComponentStyles(undefined));
16
+
17
+ describe("component style configuration", () => {
18
+ it("extends defaults with a plain Tasty style object", () => {
19
+ configureComponentStyles({
20
+ Card: { padding: "3x", Label: { color: "#accent-text" } },
21
+ });
22
+
23
+ expect(resolveComponentStyles("Card", defaults)).toEqual({
24
+ color: "#text",
25
+ padding: "3x",
26
+ Label: { color: "#accent-text", fontWeight: 500 },
27
+ });
28
+ });
29
+
30
+ it("supports explicit extension and complete replacement", () => {
31
+ configureComponentStyles({
32
+ Card: { mode: "extend", styles: { radius: "1cr" } },
33
+ });
34
+ expect(resolveComponentStyles("Card", defaults)).toMatchObject({
35
+ color: "#text",
36
+ radius: "1cr",
37
+ });
38
+
39
+ configureComponentStyles({
40
+ Card: { mode: "replace", styles: { display: "grid" } },
41
+ });
42
+ expect(resolveComponentStyles("Card", defaults)).toEqual({
43
+ display: "grid",
44
+ });
45
+ });
46
+
47
+ it("normalizes configured component overrides for Tasty composition", () => {
48
+ expect(resolveComponentStyleOverride("Card")).toBeUndefined();
49
+
50
+ configureComponentStyles({ Card: { padding: "3x" } });
51
+ expect(resolveComponentStyleOverride("Card")).toEqual({
52
+ mode: "extend",
53
+ styles: { padding: "3x" },
54
+ });
55
+
56
+ configureComponentStyles({
57
+ Card: { mode: "replace", styles: { display: "grid" } },
58
+ });
59
+ expect(resolveComponentStyleOverride("Card")).toEqual({
60
+ mode: "replace",
61
+ styles: { display: "grid" },
62
+ });
63
+ });
64
+
65
+ it("keeps custom anatomy styles on the compatibility bridge", () => {
66
+ expect(
67
+ resolveLegacyAnatomyStyles({
68
+ ThemeSelect: { padding: "1x" },
69
+ ProductBadge: { color: "#accent-text" },
70
+ }),
71
+ ).toEqual({
72
+ '[data-tasty-anatomy="ProductBadge"]': { color: "#accent-text" },
73
+ });
74
+ });
75
+ });
@@ -0,0 +1,79 @@
1
+ import { mergeStyles, type Styles } from "@tenphi/tasty/core";
2
+ import {
3
+ COOKBOOK_COMPONENT_NAMES,
4
+ type ComponentStyleConfig,
5
+ type ComponentStylesConfig,
6
+ type CookbookComponentName,
7
+ } from "@tenphi/docs";
8
+
9
+ // Astro can load the integration and renderer through separate module graphs.
10
+ // Keep their component configuration on the shared process global.
11
+ const sharedConfiguration = globalThis as typeof globalThis & {
12
+ __tenphiCookbookComponentStyles?: ComponentStylesConfig;
13
+ };
14
+ const cookbookComponentNames = new Set<string>(COOKBOOK_COMPONENT_NAMES);
15
+
16
+ export function configureComponentStyles(
17
+ styles: ComponentStylesConfig | undefined,
18
+ ): void {
19
+ sharedConfiguration.__tenphiCookbookComponentStyles = styles ?? {};
20
+ }
21
+
22
+ export function resolveComponentStyles(
23
+ name: CookbookComponentName,
24
+ defaults: Styles,
25
+ ): Styles {
26
+ const configured = sharedConfiguration.__tenphiCookbookComponentStyles?.[
27
+ name
28
+ ] as ComponentStyleConfig | undefined;
29
+ if (!configured) return defaults;
30
+ if (isModeConfig(configured)) {
31
+ const styles = configured.styles as Styles;
32
+ return configured.mode === "replace"
33
+ ? styles
34
+ : mergeStyles(defaults, styles);
35
+ }
36
+ return mergeStyles(defaults, configured as Styles);
37
+ }
38
+
39
+ export function resolveComponentStyleOverride(
40
+ name: CookbookComponentName,
41
+ ): { mode: "extend" | "replace"; styles: Styles } | undefined {
42
+ const configured = sharedConfiguration.__tenphiCookbookComponentStyles?.[
43
+ name
44
+ ] as ComponentStyleConfig | undefined;
45
+ if (!configured) return undefined;
46
+ if (isModeConfig(configured)) {
47
+ return { mode: configured.mode, styles: configured.styles as Styles };
48
+ }
49
+ return { mode: "extend", styles: configured as Styles };
50
+ }
51
+
52
+ /** Preserve custom anatomy names from the pre-component style API. */
53
+ export function resolveLegacyAnatomyStyles(
54
+ styles: ComponentStylesConfig | undefined,
55
+ ): Record<string, Styles> | undefined {
56
+ if (!styles) return undefined;
57
+ const entries = Object.entries(styles)
58
+ .filter(
59
+ (entry): entry is [string, ComponentStyleConfig] =>
60
+ !cookbookComponentNames.has(entry[0]) && entry[1] !== undefined,
61
+ )
62
+ .map(([name, value]) => [
63
+ `[data-tasty-anatomy="${name}"]`,
64
+ isModeConfig(value) ? value.styles : value,
65
+ ]);
66
+ return entries.length
67
+ ? (Object.fromEntries(entries) as Record<string, Styles>)
68
+ : undefined;
69
+ }
70
+
71
+ function isModeConfig(
72
+ value: ComponentStyleConfig,
73
+ ): value is Extract<ComponentStyleConfig, { mode: string }> {
74
+ return (
75
+ "mode" in value &&
76
+ (value.mode === "extend" || value.mode === "replace") &&
77
+ "styles" in value
78
+ );
79
+ }
@@ -0,0 +1,10 @@
1
+ import { tasty } from "@tenphi/tasty";
2
+ import { resolveComponentStyleOverride } from "./component-styles.js";
3
+
4
+ export function customizeComponent(name, options, base) {
5
+ const override = resolveComponentStyleOverride(name);
6
+ if (!override) return base;
7
+ return override.mode === "replace"
8
+ ? tasty({ ...options, styles: override.styles })
9
+ : tasty(base, { styles: override.styles });
10
+ }
@@ -0,0 +1,11 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { svgIconUrl } from "./svg-icon.js";
3
+
4
+ describe("svgIconUrl", () => {
5
+ it("preserves case-sensitive SVG data when Tasty lowercases the style", () => {
6
+ const svg = '<svg viewBox="0 0 24 24"><path d="M1 2H3Z"/></svg>';
7
+ const [, payload] = svgIconUrl(svg).toLowerCase().split(",", 2);
8
+
9
+ expect(decodeURIComponent(payload ?? "")).toBe(svg);
10
+ });
11
+ });
@@ -0,0 +1,11 @@
1
+ /** Encode an SVG data URL that remains valid after Tasty lowercases styles. */
2
+ export function svgIconUrl(svg: string): string {
3
+ const encoded = encodeURIComponent(svg).replace(
4
+ /%[0-9A-F]{2}|[A-Z]/g,
5
+ (token) =>
6
+ token.startsWith("%")
7
+ ? token.toLowerCase()
8
+ : `%${token.charCodeAt(0).toString(16)}`,
9
+ );
10
+ return `data:image/svg+xml,${encoded}`;
11
+ }
@@ -0,0 +1,2 @@
1
+ export const cookbookStates: Record<`@${string}`, string>;
2
+ export function configureCookbookStates(): void;
@@ -0,0 +1,21 @@
1
+ import { configure } from "@tenphi/tasty";
2
+
3
+ export const cookbookStates = {
4
+ "@mobile": "@media(w < 50rem)",
5
+ "@desktop": "@media(w >= 50rem)",
6
+ "@small": "@media(w <= 40rem)",
7
+ "@shell-mobile": "@media(w <= 48rem)",
8
+ "@shell-desktop": "@media(w > 48rem)",
9
+ "@narrow-layout": "@media(w < 72rem)",
10
+ "@medium-layout": "@media(w >= 50rem) & @media(w < 72rem)",
11
+ "@reduced-motion": "@media(prefers-reduced-motion: reduce)",
12
+ };
13
+
14
+ let configured = false;
15
+
16
+ /** Configure aliases in the renderer's Tasty module before styles are parsed. */
17
+ export function configureCookbookStates() {
18
+ if (configured) return;
19
+ configure({ states: cookbookStates });
20
+ configured = true;
21
+ }
@@ -1,6 +1,7 @@
1
1
  import type { AstroComponentFactory } from "astro/runtime/server/index.js";
2
2
 
3
3
  export const Card: AstroComponentFactory;
4
+ export const Logo: AstroComponentFactory;
4
5
  export const Preview: AstroComponentFactory;
5
6
  export const Steps: AstroComponentFactory;
6
7
  export const Tabs: AstroComponentFactory;
@@ -1,5 +1,6 @@
1
1
  import Card from "./components/Card.astro";
2
+ import Logo from "./components/Logo.astro";
2
3
  import Preview from "./components/Preview.astro";
3
4
  import Steps from "./components/Steps.astro";
4
5
  import Tabs from "./components/Tabs.astro";
5
- export { Card, Preview, Steps, Tabs };
6
+ export { Card, Logo, Preview, Steps, Tabs };
@@ -1,5 +1,6 @@
1
1
  import Card from "./components/Card.astro";
2
+ import Logo from "./components/Logo.astro";
2
3
  import Preview from "./components/Preview.astro";
3
4
  import Steps from "./components/Steps.astro";
4
5
  import Tabs from "./components/Tabs.astro";
5
- export { Card, Preview, Steps, Tabs };
6
+ export { Card, Logo, Preview, Steps, Tabs };
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ interface StarlightOptions {
6
6
  title: string;
7
7
  description?: string;
8
8
  customCss?: string[];
9
+ disable404Route?: boolean;
9
10
  pagefind?: false | Record<string, unknown>;
10
11
  sidebar?: unknown[];
11
12
  [key: string]: unknown;
@@ -22,7 +23,6 @@ declare function tastyStarlight(config: Parameters<typeof starlight>[0]): AstroI
22
23
  //#endregion
23
24
  //#region src/theme/index.d.ts
24
25
  interface ResolvedDocsTheme {
25
- css: string;
26
26
  colors: {
27
27
  surface: Record<string, string>;
28
28
  surface2: Record<string, string>;
@@ -33,6 +33,7 @@ interface ResolvedDocsTheme {
33
33
  accentSurface: Record<string, string>;
34
34
  accentSurfaceText: Record<string, string>;
35
35
  focus: Record<string, string>;
36
+ shadow: Record<string, string>;
36
37
  };
37
38
  tokens: ThemeTokens;
38
39
  presets: Record<string, TypographyPreset>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/starlight-runtime.d.ts","../src/integration.ts","../src/theme/index.ts","../src/theme/defaults.ts"],"mappings":";;;;UAEiB;EACf;EACA;EACA;EACA,mBAAmB;EACnB;GACC;;iBAGqB,UAAU,SAAS,mBAAmB;;;UCqB7C;EACf,SAAS;EACT;;iBAGsB,SACtB,UAAS,kBACR;iBAsZa,eACd,QAAQ,kBAAkB,gBACzB;;;UC7ac;EACf;EACA;IACE,SAAS;IACT,UAAU;IACV,UAAU;IACV,MAAM;IACN,UAAU;IACV,YAAY;IACZ,eAAe;IACf,mBAAmB;IACnB,OAAO;;EAET,QAAQ;EACR,SAAS,eAAe;EACxB;IACE;IACA;IACA;IACA;;EAEF,aAAa;;iBAGC,iBAAiB,QAAO,cAAmB;;;cCpC9C;;;;;;;;;;;;cAkBA,4BAA4B,eAAe"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/starlight-runtime.d.ts","../src/integration.ts","../src/theme/index.ts","../src/theme/defaults.ts"],"mappings":";;;;UAEiB;EACf;EACA;EACA;EACA;EACA,mBAAmB;EACnB;GACC;;iBAGqB,UAAU,SAAS,mBAAmB;;;UCmC7C;EACf,SAAS;EACT;;iBAGsB,SACtB,UAAS,kBACR;iBA4aa,eACd,QAAQ,kBAAkB,gBACzB;;;UCldc;EACf;IACE,SAAS;IACT,UAAU;IACV,UAAU;IACV,MAAM;IACN,UAAU;IACV,YAAY;IACZ,eAAe;IACf,mBAAmB;IACnB,OAAO;IACP,QAAQ;;EAEV,QAAQ;EACR,SAAS,eAAe;EACxB;IACE;IACA;IACA;IACA;;EAEF,aAAa;;iBAGC,iBAAiB,QAAO,cAAmB;;;cCpC9C;;;;;;;;;;;;cAkBA,4BAA4B,eAAe"}