@tenphi/renderer 0.20.5 → 0.21.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.
@@ -8,6 +8,8 @@ function initializeSearch(element, options, development, base) {
8
8
  const dialog = element.querySelector("dialog");
9
9
  const frame = element.querySelector(".dialog-frame");
10
10
  const status = element.querySelector("[data-search-status]");
11
+ const input = element.querySelector("[data-search-input]");
12
+ const clear = element.querySelector("[data-clear-search]");
11
13
  const shortcut = open.querySelector("kbd");
12
14
  if (/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {
13
15
  shortcut.querySelector("kbd").textContent = "⌘";
@@ -15,7 +17,24 @@ function initializeSearch(element, options, development, base) {
15
17
  }
16
18
  delete shortcut.dataset.pending;
17
19
  let initialized;
20
+ let engineInput = null;
18
21
  let returnFocus = null;
22
+ let closing = false;
23
+ let generation = 0;
24
+ const updateSearch = () => {
25
+ if (clear) clear.hidden = !input?.value;
26
+ if (engineInput) {
27
+ engineInput.value = input?.value ?? "";
28
+ engineInput.dispatchEvent(new Event("input", { bubbles: true }));
29
+ }
30
+ };
31
+ input?.addEventListener("input", updateSearch);
32
+ clear?.addEventListener("click", () => {
33
+ if (!input) return;
34
+ input.value = "";
35
+ updateSearch();
36
+ input.focus();
37
+ });
19
38
  const initialize = () => {
20
39
  if (development) return Promise.resolve();
21
40
  return initialized ??= (async () => {
@@ -24,7 +43,7 @@ function initializeSearch(element, options, development, base) {
24
43
  const format = (url) => element.hasAttribute("data-strip-trailing-slash") ? url.replace(/(.)\/(#.*)?$/, "$1$2") : url;
25
44
  new PagefindUI({
26
45
  ...options,
27
- element: "#cookbook__search",
46
+ element: element.querySelector("[data-search-results]"),
28
47
  baseUrl: base,
29
48
  bundlePath: `${base.replace(/\/$/, "")}/pagefind/`,
30
49
  showImages: false,
@@ -39,6 +58,13 @@ function initializeSearch(element, options, development, base) {
39
58
  return result;
40
59
  }
41
60
  });
61
+ engineInput = element.querySelector(".pagefind-ui__search-input");
62
+ element.querySelector(".pagefind-ui__form")?.removeAttribute("role");
63
+ element.querySelectorAll(".pagefind-ui__search-input, .pagefind-ui__search-clear").forEach((control) => {
64
+ control.hidden = true;
65
+ control.tabIndex = -1;
66
+ });
67
+ updateSearch();
42
68
  })().catch((error) => {
43
69
  initialized = void 0;
44
70
  if (status) {
@@ -49,38 +75,53 @@ function initializeSearch(element, options, development, base) {
49
75
  throw error;
50
76
  });
51
77
  };
52
- const show = async () => {
53
- if (dialog.open) return;
54
- returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : open;
55
- dialog.removeAttribute("data-open");
56
- dialog.showModal();
78
+ const show = (trigger) => {
79
+ if (dialog.open && !closing) return;
80
+ generation += 1;
81
+ closing = false;
82
+ if (!dialog.open) {
83
+ returnFocus = trigger ?? (document.activeElement instanceof HTMLElement && document.activeElement !== document.body ? document.activeElement : open);
84
+ dialog.removeAttribute("data-open");
85
+ dialog.showModal();
86
+ }
87
+ input?.focus({ preventScroll: true });
57
88
  dialog.getBoundingClientRect();
58
89
  dialog.setAttribute("data-open", "");
59
90
  document.body.setAttribute("data-search-modal-open", "");
60
91
  if (!development && status) status.hidden = true;
61
- try {
62
- await initialize();
63
- if (dialog.open) element.querySelector("input")?.focus();
64
- } catch {}
92
+ initialize().catch(() => {});
93
+ };
94
+ const hide = async () => {
95
+ if (!dialog.open || closing) return;
96
+ closing = true;
97
+ const current = ++generation;
98
+ dialog.removeAttribute("data-open");
99
+ await Promise.allSettled(dialog.getAnimations().filter((animation) => Number.isFinite(animation.effect?.getComputedTiming().endTime)).map((animation) => animation.finished));
100
+ if (current === generation && dialog.open) dialog.close();
65
101
  };
66
102
  open.addEventListener("click", () => {
67
- show();
103
+ show(open);
68
104
  });
69
105
  open.disabled = false;
70
- close.addEventListener("click", () => dialog.close());
106
+ close.addEventListener("click", () => void hide());
107
+ dialog.addEventListener("cancel", (event) => {
108
+ event.preventDefault();
109
+ hide();
110
+ });
71
111
  dialog.addEventListener("click", (event) => {
72
112
  if (!(event.target instanceof Element)) return;
73
- if (event.target.closest("a[href]") || !frame.contains(event.target)) dialog.close();
113
+ if (event.target.closest("a[href]") || !frame.contains(event.target)) hide();
74
114
  });
75
115
  dialog.addEventListener("close", () => {
76
116
  dialog.removeAttribute("data-open");
117
+ closing = false;
77
118
  document.body.removeAttribute("data-search-modal-open");
78
119
  returnFocus?.focus();
79
120
  });
80
121
  window.addEventListener("keydown", (event) => {
81
122
  if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
82
123
  event.preventDefault();
83
- if (dialog.open) dialog.close();
124
+ if (dialog.open && !closing) hide();
84
125
  else show();
85
126
  }
86
127
  });
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","names":[],"sources":["../../src/client/search.ts"],"sourcesContent":["type SearchResult = { url: string; sub_results?: SearchResult[] };\ntype PagefindOptions = Record<string, unknown> & {\n processResult?: (result: SearchResult) => SearchResult | void;\n};\n\n/** Own the dialog lifecycle; Pagefind owns indexing, filtering and result rendering. */\nexport function initializeSearch(\n element: HTMLElement,\n options: PagefindOptions,\n development: boolean,\n base: string,\n): void {\n if (element.dataset.initialized) return;\n element.dataset.initialized = \"true\";\n const open = element.querySelector<HTMLButtonElement>(\"[data-open-modal]\")!;\n const close = element.querySelector<HTMLButtonElement>(\"[data-close-modal]\")!;\n const dialog = element.querySelector(\"dialog\")!;\n const frame = element.querySelector(\".dialog-frame\")!;\n const status = element.querySelector<HTMLElement>(\"[data-search-status]\");\n const shortcut = open.querySelector(\"kbd\")!;\n if (/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {\n shortcut.querySelector(\"kbd\")!.textContent = \"⌘\";\n open.setAttribute(\"aria-keyshortcuts\", \"Meta+K\");\n }\n delete shortcut.dataset.pending;\n let initialized: Promise<void> | undefined;\n let returnFocus: HTMLElement | null = null;\n const initialize = () => {\n if (development) return Promise.resolve();\n return (initialized ??= (async () => {\n // @ts-expect-error Pagefind publishes no declarations for its default UI.\n const { PagefindUI } = await import(\"@pagefind/default-ui\");\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n const format = (url: string) =>\n element.hasAttribute(\"data-strip-trailing-slash\")\n ? url.replace(/(.)\\/(#.*)?$/, \"$1$2\")\n : url;\n new PagefindUI({\n ...options,\n element: \"#cookbook__search\",\n baseUrl: base,\n bundlePath: `${base.replace(/\\/$/, \"\")}/pagefind/`,\n showImages: false,\n showSubResults: true,\n translations,\n processResult(result: SearchResult) {\n result = options.processResult?.(result) ?? result;\n result.url = format(result.url);\n result.sub_results?.forEach((child) => {\n child.url = format(child.url);\n });\n return result;\n },\n });\n })().catch((error: unknown) => {\n initialized = undefined;\n if (status) {\n status.hidden = false;\n // Reuse the localized Pagefind error, with a plain fallback.\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n status.textContent =\n translations.error ?? \"Search could not load. Close and try again.\";\n }\n throw error;\n }));\n };\n const show = async () => {\n if (dialog.open) return;\n returnFocus =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : open;\n dialog.removeAttribute(\"data-open\");\n dialog.showModal();\n // Establish the initial state after entering the top layer. The global\n // style renderer does not preserve @starting-style in server output.\n dialog.getBoundingClientRect();\n dialog.setAttribute(\"data-open\", \"\");\n document.body.setAttribute(\"data-search-modal-open\", \"\");\n if (!development && status) status.hidden = true;\n try {\n await initialize();\n // Pagefind mounts synchronously. Only focus if the user has not closed it.\n if (dialog.open) element.querySelector(\"input\")?.focus();\n } catch {\n /* Keep the close control usable when the search bundle fails. */\n }\n };\n open.addEventListener(\"click\", () => {\n void show();\n });\n open.disabled = false;\n close.addEventListener(\"click\", () => dialog.close());\n dialog.addEventListener(\"click\", (event) => {\n if (!(event.target instanceof Element)) return;\n if (event.target.closest(\"a[href]\") || !frame.contains(event.target))\n dialog.close();\n });\n dialog.addEventListener(\"close\", () => {\n dialog.removeAttribute(\"data-open\");\n document.body.removeAttribute(\"data-search-modal-open\");\n returnFocus?.focus();\n });\n window.addEventListener(\"keydown\", (event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n if (dialog.open) dialog.close();\n else void show();\n }\n });\n}\n"],"mappings":";;AAMA,SAAgB,iBACd,SACA,SACA,aACA,MACM;CACN,IAAI,QAAQ,QAAQ,aAAa;CACjC,QAAQ,QAAQ,cAAc;CAC9B,MAAM,OAAO,QAAQ,cAAiC,mBAAmB;CACzE,MAAM,QAAQ,QAAQ,cAAiC,oBAAoB;CAC3E,MAAM,SAAS,QAAQ,cAAc,QAAQ;CAC7C,MAAM,QAAQ,QAAQ,cAAc,eAAe;CACnD,MAAM,SAAS,QAAQ,cAA2B,sBAAsB;CACxE,MAAM,WAAW,KAAK,cAAc,KAAK;CACzC,IAAI,0BAA0B,KAAK,UAAU,QAAQ,GAAG;EACtD,SAAS,cAAc,KAAK,CAAC,CAAE,cAAc;EAC7C,KAAK,aAAa,qBAAqB,QAAQ;CACjD;CACA,OAAO,SAAS,QAAQ;CACxB,IAAI;CACJ,IAAI,cAAkC;CACtC,MAAM,mBAAmB;EACvB,IAAI,aAAa,OAAO,QAAQ,QAAQ;EACxC,OAAQ,iBAAiB,YAAY;GAEnC,MAAM,EAAE,eAAe,MAAM,OAAO;GACpC,MAAM,eAAe,KAAK,MAAM,QAAQ,QAAQ,gBAAgB,IAAI;GACpE,MAAM,UAAU,QACd,QAAQ,aAAa,2BAA2B,IAC5C,IAAI,QAAQ,gBAAgB,MAAM,IAClC;GACN,IAAI,WAAW;IACb,GAAG;IACH,SAAS;IACT,SAAS;IACT,YAAY,GAAG,KAAK,QAAQ,OAAO,EAAE,EAAE;IACvC,YAAY;IACZ,gBAAgB;IAChB;IACA,cAAc,QAAsB;KAClC,SAAS,QAAQ,gBAAgB,MAAM,KAAK;KAC5C,OAAO,MAAM,OAAO,OAAO,GAAG;KAC9B,OAAO,aAAa,SAAS,UAAU;MACrC,MAAM,MAAM,OAAO,MAAM,GAAG;KAC9B,CAAC;KACD,OAAO;IACT;GACF,CAAC;EACH,EAAA,CAAG,CAAC,CAAC,OAAO,UAAmB;GAC7B,cAAc,KAAA;GACd,IAAI,QAAQ;IACV,OAAO,SAAS;IAEhB,MAAM,eAAe,KAAK,MAAM,QAAQ,QAAQ,gBAAgB,IAAI;IACpE,OAAO,cACL,aAAa,SAAS;GAC1B;GACA,MAAM;EACR,CAAC;CACH;CACA,MAAM,OAAO,YAAY;EACvB,IAAI,OAAO,MAAM;EACjB,cACE,SAAS,yBAAyB,cAC9B,SAAS,gBACT;EACN,OAAO,gBAAgB,WAAW;EAClC,OAAO,UAAU;EAGjB,OAAO,sBAAsB;EAC7B,OAAO,aAAa,aAAa,EAAE;EACnC,SAAS,KAAK,aAAa,0BAA0B,EAAE;EACvD,IAAI,CAAC,eAAe,QAAQ,OAAO,SAAS;EAC5C,IAAI;GACF,MAAM,WAAW;GAEjB,IAAI,OAAO,MAAM,QAAQ,cAAc,OAAO,CAAC,EAAE,MAAM;EACzD,QAAQ,CAER;CACF;CACA,KAAK,iBAAiB,eAAe;EACnC,KAAU;CACZ,CAAC;CACD,KAAK,WAAW;CAChB,MAAM,iBAAiB,eAAe,OAAO,MAAM,CAAC;CACpD,OAAO,iBAAiB,UAAU,UAAU;EAC1C,IAAI,EAAE,MAAM,kBAAkB,UAAU;EACxC,IAAI,MAAM,OAAO,QAAQ,SAAS,KAAK,CAAC,MAAM,SAAS,MAAM,MAAM,GACjE,OAAO,MAAM;CACjB,CAAC;CACD,OAAO,iBAAiB,eAAe;EACrC,OAAO,gBAAgB,WAAW;EAClC,SAAS,KAAK,gBAAgB,wBAAwB;EACtD,aAAa,MAAM;CACrB,CAAC;CACD,OAAO,iBAAiB,YAAY,UAAU;EAC5C,KAAK,MAAM,WAAW,MAAM,YAAY,MAAM,IAAI,YAAY,MAAM,KAAK;GACvE,MAAM,eAAe;GACrB,IAAI,OAAO,MAAM,OAAO,MAAM;QACzB,KAAU;EACjB;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"search.js","names":[],"sources":["../../src/client/search.ts"],"sourcesContent":["type SearchResult = { url: string; sub_results?: SearchResult[] };\ntype PagefindOptions = Record<string, unknown> & {\n processResult?: (result: SearchResult) => SearchResult | void;\n};\n\n/** Own the dialog lifecycle; Pagefind owns indexing, filtering and result rendering. */\nexport function initializeSearch(\n element: HTMLElement,\n options: PagefindOptions,\n development: boolean,\n base: string,\n): void {\n if (element.dataset.initialized) return;\n element.dataset.initialized = \"true\";\n const open = element.querySelector<HTMLButtonElement>(\"[data-open-modal]\")!;\n const close = element.querySelector<HTMLButtonElement>(\"[data-close-modal]\")!;\n const dialog = element.querySelector(\"dialog\")!;\n const frame = element.querySelector(\".dialog-frame\")!;\n const status = element.querySelector<HTMLElement>(\"[data-search-status]\");\n const input = element.querySelector<HTMLInputElement>(\"[data-search-input]\");\n const clear = element.querySelector<HTMLButtonElement>(\"[data-clear-search]\");\n const shortcut = open.querySelector(\"kbd\")!;\n if (/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) {\n shortcut.querySelector(\"kbd\")!.textContent = \"⌘\";\n open.setAttribute(\"aria-keyshortcuts\", \"Meta+K\");\n }\n delete shortcut.dataset.pending;\n let initialized: Promise<void> | undefined;\n let engineInput: HTMLInputElement | null = null;\n let returnFocus: HTMLElement | null = null;\n let closing = false;\n let generation = 0;\n const updateSearch = () => {\n if (clear) clear.hidden = !input?.value;\n if (engineInput) {\n engineInput.value = input?.value ?? \"\";\n engineInput.dispatchEvent(new Event(\"input\", { bubbles: true }));\n }\n };\n input?.addEventListener(\"input\", updateSearch);\n clear?.addEventListener(\"click\", () => {\n if (!input) return;\n input.value = \"\";\n updateSearch();\n input.focus();\n });\n const initialize = () => {\n if (development) return Promise.resolve();\n return (initialized ??= (async () => {\n // @ts-expect-error Pagefind publishes no declarations for its default UI.\n const { PagefindUI } = await import(\"@pagefind/default-ui\");\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n const format = (url: string) =>\n element.hasAttribute(\"data-strip-trailing-slash\")\n ? url.replace(/(.)\\/(#.*)?$/, \"$1$2\")\n : url;\n new PagefindUI({\n ...options,\n element: element.querySelector(\"[data-search-results]\"),\n baseUrl: base,\n bundlePath: `${base.replace(/\\/$/, \"\")}/pagefind/`,\n showImages: false,\n showSubResults: true,\n translations,\n processResult(result: SearchResult) {\n result = options.processResult?.(result) ?? result;\n result.url = format(result.url);\n result.sub_results?.forEach((child) => {\n child.url = format(child.url);\n });\n return result;\n },\n });\n engineInput = element.querySelector(\".pagefind-ui__search-input\");\n element.querySelector(\".pagefind-ui__form\")?.removeAttribute(\"role\");\n // Cookbook owns the field so focus stays within the opening tap on mobile.\n // Pagefind still owns query processing and its lazily rendered results.\n element\n .querySelectorAll<HTMLElement>(\n \".pagefind-ui__search-input, .pagefind-ui__search-clear\",\n )\n .forEach((control) => {\n control.hidden = true;\n control.tabIndex = -1;\n });\n updateSearch();\n })().catch((error: unknown) => {\n initialized = undefined;\n if (status) {\n status.hidden = false;\n // Reuse the localized Pagefind error, with a plain fallback.\n const translations = JSON.parse(element.dataset.translations ?? \"{}\");\n status.textContent =\n translations.error ?? \"Search could not load. Close and try again.\";\n }\n throw error;\n }));\n };\n const show = (trigger?: HTMLElement) => {\n if (dialog.open && !closing) return;\n generation += 1;\n closing = false;\n if (!dialog.open) {\n returnFocus =\n trigger ??\n (document.activeElement instanceof HTMLElement &&\n document.activeElement !== document.body\n ? document.activeElement\n : open);\n dialog.removeAttribute(\"data-open\");\n dialog.showModal();\n }\n // Do this synchronously, before the lazy import releases user activation.\n input?.focus({ preventScroll: true });\n // Establish the initial state after entering the top layer. The global\n // style renderer does not preserve @starting-style in server output.\n dialog.getBoundingClientRect();\n dialog.setAttribute(\"data-open\", \"\");\n document.body.setAttribute(\"data-search-modal-open\", \"\");\n if (!development && status) status.hidden = true;\n void initialize().catch(() => {\n /* Keep the close control usable when the search bundle fails. */\n });\n };\n const hide = async () => {\n if (!dialog.open || closing) return;\n closing = true;\n const current = ++generation;\n dialog.removeAttribute(\"data-open\");\n // Keep the modal in the top layer until its exit transition has finished.\n // This also works in browsers without discrete display/overlay transitions.\n await Promise.allSettled(\n dialog\n .getAnimations()\n .filter((animation) =>\n Number.isFinite(animation.effect?.getComputedTiming().endTime),\n )\n .map((animation) => animation.finished),\n );\n if (current === generation && dialog.open) dialog.close();\n };\n open.addEventListener(\"click\", () => {\n show(open);\n });\n open.disabled = false;\n close.addEventListener(\"click\", () => void hide());\n dialog.addEventListener(\"cancel\", (event) => {\n event.preventDefault();\n void hide();\n });\n dialog.addEventListener(\"click\", (event) => {\n if (!(event.target instanceof Element)) return;\n if (event.target.closest(\"a[href]\") || !frame.contains(event.target))\n void hide();\n });\n dialog.addEventListener(\"close\", () => {\n dialog.removeAttribute(\"data-open\");\n closing = false;\n document.body.removeAttribute(\"data-search-modal-open\");\n returnFocus?.focus();\n });\n window.addEventListener(\"keydown\", (event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n if (dialog.open && !closing) void hide();\n else void show();\n }\n });\n}\n"],"mappings":"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"}
@@ -363,18 +363,18 @@ export default function GlobalStyles() {
363
363
  },
364
364
  Backdrop: {
365
365
  $: "dialog::backdrop",
366
- fill: "#overlay",
367
- backdropFilter: "blur(0.25rem)",
366
+ fill: { "": "#overlay", "@mobile": "#clear" },
367
+ backdropFilter: { "": "blur(0.25rem)", "@mobile": "none" },
368
368
  opacity: "0",
369
369
  transition: {
370
370
  "": "none",
371
- "!@reduced-motion":
371
+ "!@reduced-motion & !@mobile":
372
372
  "opacity $dialog-transition ease-out, display $dialog-transition allow-discrete, overlay $dialog-transition allow-discrete",
373
373
  },
374
374
  },
375
375
  EnteredBackdrop: {
376
376
  $: "dialog[open][data-open]::backdrop",
377
- opacity: "1",
377
+ opacity: { "": "1", "@mobile": "0" },
378
378
  },
379
379
  Frame: {
380
380
  $: ".dialog-frame",
@@ -1032,8 +1032,8 @@ export default function GlobalStyles() {
1032
1032
  ".cookbook-markdown-content code:not(:where(pre *, .not-content *))",
1033
1033
  resolveComponentStyles("MarkdownInlineCode", {
1034
1034
  padding: "0.125rem 0.375rem",
1035
- color: "#text",
1036
- fill: "#surface-2",
1035
+ color: "#text-soft",
1036
+ fill: "#surface-3",
1037
1037
  preset: "code",
1038
1038
  fontSize: "0.875em",
1039
1039
  radius: "($radius * 0.65)",
@@ -1530,7 +1530,7 @@ export default function GlobalStyles() {
1530
1530
  "$pagefind-ui-tag": "#surface-3",
1531
1531
  preset: "body",
1532
1532
  UI: {
1533
- $: ".pagefind-ui",
1533
+ $: ".pagefind-ui, [data-search-results]",
1534
1534
  display: "flex",
1535
1535
  flow: "column",
1536
1536
  flexGrow: "1",
@@ -1544,6 +1544,15 @@ export default function GlobalStyles() {
1544
1544
  flexGrow: "1",
1545
1545
  minBlockSize: "0",
1546
1546
  },
1547
+ Field: {
1548
+ $: ".cookbook-search-field",
1549
+ position: "relative",
1550
+ flexShrink: "0",
1551
+ },
1552
+ EngineControls: {
1553
+ $: ".pagefind-ui__search-input, .pagefind-ui__search-clear",
1554
+ display: "none",
1555
+ },
1547
1556
  Drawer: {
1548
1557
  $: ".pagefind-ui__drawer",
1549
1558
  display: "flex",
@@ -1552,7 +1561,7 @@ export default function GlobalStyles() {
1552
1561
  minBlockSize: "0",
1553
1562
  },
1554
1563
  Input: {
1555
- $: ".pagefind-ui__search-input",
1564
+ $: ".cookbook-search-input",
1556
1565
  flexShrink: "0",
1557
1566
  inlineSize: "100%",
1558
1567
  minBlockSize: "3rem",
@@ -1566,7 +1575,7 @@ export default function GlobalStyles() {
1566
1575
  boxShadow: "none",
1567
1576
  },
1568
1577
  Clear: {
1569
- $: ".pagefind-ui__search-clear",
1578
+ $: ".cookbook-search-clear",
1570
1579
  position: "absolute",
1571
1580
  insetBlockStart: "0",
1572
1581
  insetInlineEnd: "0",
@@ -1654,7 +1663,7 @@ export default function GlobalStyles() {
1654
1663
  },
1655
1664
  HoverMore: { $: ".pagefind-ui__button:hover", fill: "#surface-2-hover" },
1656
1665
  SearchIcon: {
1657
- $: ".pagefind-ui__form::before",
1666
+ $: ".cookbook-search-field::before",
1658
1667
  content: '""',
1659
1668
  position: "absolute",
1660
1669
  zIndex: "1",
@@ -1668,7 +1677,7 @@ export default function GlobalStyles() {
1668
1677
  pointerEvents: "none",
1669
1678
  },
1670
1679
  ClearIcon: {
1671
- $: ".pagefind-ui__search-clear::before",
1680
+ $: ".cookbook-search-clear::before",
1672
1681
  content: '""',
1673
1682
  display: "block",
1674
1683
  inlineSize: "1rem",
@@ -1677,7 +1686,7 @@ export default function GlobalStyles() {
1677
1686
  mask: `url("${svgIconUrl(closeIcon)}") center / 1rem no-repeat`,
1678
1687
  },
1679
1688
  SuppressedClear: {
1680
- $: ".pagefind-ui__search-clear.pagefind-ui__suppressed",
1689
+ $: ".cookbook-search-clear[hidden]",
1681
1690
  display: "none",
1682
1691
  },
1683
1692
  }),
@@ -1,7 +1,6 @@
1
1
  import { afterEach, describe, expect, it } from "vitest";
2
2
  import {
3
3
  configureComponentStyles,
4
- resolveLegacyAnatomyStyles,
5
4
  resolveComponentStyleOverride,
6
5
  resolveComponentStyles,
7
6
  unusedCustomStyleNames,
@@ -97,19 +96,7 @@ describe("component style configuration", () => {
97
96
  });
98
97
  });
99
98
 
100
- it("keeps custom anatomy styles on the compatibility bridge", () => {
101
- expect(
102
- resolveLegacyAnatomyStyles({
103
- Footer: { color: "#text-muted" },
104
- ThemeSelect: { padding: "1x" },
105
- ProductBadge: { color: "#accent-text" },
106
- }),
107
- ).toEqual({
108
- '[data-tasty-anatomy="ProductBadge"]': { color: "#accent-text" },
109
- });
110
- });
111
-
112
- it("reports only custom style names without a component or anatomy match", () => {
99
+ it("reports only custom style names without a component style resolver", () => {
113
100
  const styles = {
114
101
  ProjectBadge: { color: "#accent-text" },
115
102
  ProjectNote: { color: "#text" },
@@ -117,13 +104,10 @@ describe("component style configuration", () => {
117
104
  };
118
105
  configureComponentStyles(styles);
119
106
  resolveComponentStyles("ProjectBadge", { color: "#text" });
107
+ resolveComponentStyles("ProjectNote", { color: "#text" });
120
108
 
121
- expect(unusedCustomStyleNames(styles, new Set(["ProjectNote"]))).toEqual([
122
- "ProjectBadg",
123
- ]);
109
+ expect(unusedCustomStyleNames(styles)).toEqual(["ProjectBadg"]);
124
110
  configureComponentStyles(styles);
125
- expect(unusedCustomStyleNames(styles, new Set())).toEqual(
126
- Object.keys(styles),
127
- );
111
+ expect(unusedCustomStyleNames(styles)).toEqual(Object.keys(styles));
128
112
  });
129
113
  });
@@ -1,5 +1,4 @@
1
1
  import { mergeStyles, type Styles } from "@tenphi/tasty/core";
2
- import { COOKBOOK_COMPONENT_NAMES } from "@tenphi/docs";
3
2
 
4
3
  // Astro can load the integration and renderer through separate module graphs.
5
4
  // Keep their component configuration on the shared process global.
@@ -7,7 +6,6 @@ const sharedConfiguration = globalThis as typeof globalThis & {
7
6
  __tenphiCookbookComponentStyles?: Record<string, Styles | undefined>;
8
7
  __tenphiCookbookUsedComponentStyles?: Set<string>;
9
8
  };
10
- const cookbookComponentNames = new Set<string>(COOKBOOK_COMPONENT_NAMES);
11
9
 
12
10
  export function configureComponentStyles(
13
11
  styles: Record<string, Styles | undefined> | undefined,
@@ -29,15 +27,13 @@ export function resolveComponentStyles(
29
27
  : baseStyles;
30
28
  }
31
29
 
32
- /** Find custom names without a component style resolver or rendered anatomy. */
30
+ /** Find custom names without a component style resolver match. */
33
31
  export function unusedCustomStyleNames(
34
32
  styles: Record<string, Styles> | undefined,
35
- anatomyNames: ReadonlySet<string>,
36
33
  ): string[] {
37
34
  return Object.keys(styles ?? {}).filter(
38
35
  (name) =>
39
- !sharedConfiguration.__tenphiCookbookUsedComponentStyles?.has(name) &&
40
- !anatomyNames.has(name),
36
+ !sharedConfiguration.__tenphiCookbookUsedComponentStyles?.has(name),
41
37
  );
42
38
  }
43
39
 
@@ -47,19 +43,3 @@ export function resolveComponentStyleOverride(
47
43
  return sharedConfiguration.__tenphiCookbookComponentStyles?.[name] as
48
44
  Styles | undefined;
49
45
  }
50
-
51
- /** Preserve custom anatomy names from the pre-component style API. */
52
- export function resolveLegacyAnatomyStyles(
53
- styles: Record<string, Styles | undefined> | undefined,
54
- ): Record<string, Styles> | undefined {
55
- if (!styles) return undefined;
56
- const entries = Object.entries(styles)
57
- .filter(
58
- (entry): entry is [string, Styles] =>
59
- !cookbookComponentNames.has(entry[0]) && entry[1] !== undefined,
60
- )
61
- .map(([name, value]) => [`[data-tasty-anatomy="${name}"]`, value]);
62
- return entries.length
63
- ? (Object.fromEntries(entries) as Record<string, Styles>)
64
- : undefined;
65
- }
@@ -140,8 +140,8 @@ function createValidationConfig(theme = {}) {
140
140
  ...tasty_config_default,
141
141
  tokens: [
142
142
  ...tasty_config_default.tokens,
143
- ...Object.keys(theme.tokens ?? {}).map((name) => name.startsWith("--") ? `$${name.slice(2)}` : name),
144
- ...Object.keys(theme.palette ?? {}).map((name) => `#${name === "textSoft" ? "text-soft" : name}`)
143
+ ...Object.keys(theme.tokens ?? {}),
144
+ ...Object.keys(theme.palette ?? {}).map((name) => `#${name}`)
145
145
  ],
146
146
  units: [...tasty_config_default.units, ...Object.keys(theme.units ?? {})],
147
147
  states: [...tasty_config_default.states, ...Object.keys(theme.states ?? {})],
@@ -1 +1 @@
1
- {"version":3,"file":"eslint-plugin.js","names":["validationConfig"],"sources":["../src/tasty.config.ts","../src/eslint-plugin.ts"],"sourcesContent":["import type { TastyValidationConfig } from \"@tenphi/eslint-plugin-tasty\";\n\nexport default {\n importSources: [\"@tenphi/cookbook/styling\", \"@tenphi/renderer/styling\"],\n styleFunctions: {\n defineComponent: { argument: 1, kind: \"options\" },\n resolveComponentStyles: { argument: 1, kind: \"styles\" },\n mergeStyles: { argument: \"all\", kind: \"styles\", partial: true },\n },\n tokens: [\n \"$gap\",\n \"$radius\",\n \"$header-control-radius\",\n \"$card-radius\",\n \"$border-width\",\n \"$outline-width\",\n \"$outline-offset\",\n \"$layout-width\",\n \"$content-width\",\n \"$sidebar-width\",\n \"$control-height\",\n \"$transition\",\n \"$sharp-radius\",\n \"$bold-font-weight\",\n \"#white\",\n \"#black\",\n \"#clear\",\n \"#current\",\n \"#surface\",\n \"#header\",\n \"#heading\",\n \"#surface-2\",\n \"#surface-3\",\n \"#surface-2-hover\",\n \"#surface-2-pressed\",\n \"#surface-3-hover\",\n \"#surface-3-pressed\",\n \"#text\",\n \"#text-soft\",\n \"#text-muted\",\n \"#sidebar-text\",\n \"#border\",\n \"#border-strong\",\n \"#accent-text\",\n \"#accent-surface\",\n \"#accent-surface-text\",\n \"#logo-surface\",\n \"#logo-mark\",\n \"#accent-surface-subtle\",\n \"#accent-surface-2-subtle\",\n \"#focus\",\n \"#shadow\",\n \"#overlay\",\n \"#syntax-bg\",\n \"#syntax-text\",\n \"#syntax-comment\",\n \"#syntax-punctuation\",\n \"#syntax-keyword\",\n \"#syntax-string\",\n \"#syntax-token\",\n \"#syntax-property\",\n \"#syntax-number\",\n \"#syntax-function\",\n \"#syntax-value\",\n \"#syntax-operator\",\n \"#info\",\n \"#info-surface\",\n \"#info-text\",\n \"#success\",\n \"#success-surface\",\n \"#success-text\",\n \"#warning\",\n \"#warning-surface\",\n \"#warning-text\",\n \"#danger\",\n \"#danger-surface\",\n \"#danger-text\",\n \"#orange-surface\",\n \"#orange\",\n \"#orange-text\",\n \"#green-surface\",\n \"#green\",\n \"#green-text\",\n \"#blue-surface\",\n \"#blue\",\n \"#blue-text\",\n \"#purple-surface\",\n \"#purple\",\n \"#purple-text\",\n \"#red-surface\",\n \"#red\",\n \"#red-text\",\n ],\n units: [\"x\", \"r\", \"cr\", \"bw\"],\n states: [\n \"@mobile\",\n \"@desktop\",\n \"@small\",\n \"@compact\",\n \"@shell-mobile\",\n \"@shell-desktop\",\n \"@narrow-layout\",\n \"@medium-layout\",\n \"@reduced-motion\",\n ],\n presets: [\n \"body\",\n \"heading\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"navigation\",\n \"small\",\n \"code\",\n ],\n} satisfies TastyValidationConfig;\n","export { default, recommended, strict } from \"@tenphi/eslint-plugin-tasty\";\nexport type {\n ResolvedConfig,\n StyleFunctionConfig,\n TastyValidationConfig,\n} from \"@tenphi/eslint-plugin-tasty\";\nexport { default as validationConfig } from \"./tasty.config.js\";\n\nimport type { ThemeConfig } from \"@tenphi/docs\";\nimport type { TastyValidationConfig } from \"@tenphi/eslint-plugin-tasty\";\nimport validationConfig from \"./tasty.config.js\";\n\n/** Keep editor/linter names aligned with a Cookbook theme. */\nexport function createValidationConfig(\n theme: ThemeConfig = {},\n): TastyValidationConfig {\n return {\n ...validationConfig,\n tokens: [\n ...validationConfig.tokens,\n ...Object.keys(theme.tokens ?? {}).map((name) =>\n name.startsWith(\"--\") ? `$${name.slice(2)}` : name,\n ),\n ...Object.keys(theme.palette ?? {}).map(\n (name) => `#${name === \"textSoft\" ? \"text-soft\" : name}`,\n ),\n ],\n units: [...validationConfig.units, ...Object.keys(theme.units ?? {})],\n states: [...validationConfig.states, ...Object.keys(theme.states ?? {})],\n presets: [...validationConfig.presets, ...Object.keys(theme.presets ?? {})],\n recipes: Object.keys(theme.recipes ?? {}),\n };\n}\n"],"mappings":";;AAEA,IAAA,uBAAe;CACb,eAAe,CAAC,4BAA4B,0BAA0B;CACtE,gBAAgB;EACd,iBAAiB;GAAE,UAAU;GAAG,MAAM;EAAU;EAChD,wBAAwB;GAAE,UAAU;GAAG,MAAM;EAAS;EACtD,aAAa;GAAE,UAAU;GAAO,MAAM;GAAU,SAAS;EAAK;CAChE;CACA,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,OAAO;EAAC;EAAK;EAAK;EAAM;CAAI;CAC5B,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;ACzGA,SAAgB,uBACd,QAAqB,CAAC,GACC;CACvB,OAAO;EACL,GAAGA;EACH,QAAQ;GACN,GAAGA,qBAAiB;GACpB,GAAG,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,SACtC,KAAK,WAAW,IAAI,IAAI,IAAI,KAAK,MAAM,CAAC,MAAM,IAChD;GACA,GAAG,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC,KACjC,SAAS,IAAI,SAAS,aAAa,cAAc,MACpD;EACF;EACA,OAAO,CAAC,GAAGA,qBAAiB,OAAO,GAAG,OAAO,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC;EACpE,QAAQ,CAAC,GAAGA,qBAAiB,QAAQ,GAAG,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC,CAAC;EACvE,SAAS,CAAC,GAAGA,qBAAiB,SAAS,GAAG,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC,CAAC;EAC1E,SAAS,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC;CAC1C;AACF"}
1
+ {"version":3,"file":"eslint-plugin.js","names":["validationConfig"],"sources":["../src/tasty.config.ts","../src/eslint-plugin.ts"],"sourcesContent":["import type { TastyValidationConfig } from \"@tenphi/eslint-plugin-tasty\";\n\nexport default {\n importSources: [\"@tenphi/cookbook/styling\", \"@tenphi/renderer/styling\"],\n styleFunctions: {\n defineComponent: { argument: 1, kind: \"options\" },\n resolveComponentStyles: { argument: 1, kind: \"styles\" },\n mergeStyles: { argument: \"all\", kind: \"styles\", partial: true },\n },\n tokens: [\n \"$gap\",\n \"$radius\",\n \"$header-control-radius\",\n \"$card-radius\",\n \"$border-width\",\n \"$outline-width\",\n \"$outline-offset\",\n \"$layout-width\",\n \"$content-width\",\n \"$sidebar-width\",\n \"$control-height\",\n \"$transition\",\n \"$sharp-radius\",\n \"$bold-font-weight\",\n \"#white\",\n \"#black\",\n \"#clear\",\n \"#current\",\n \"#surface\",\n \"#header\",\n \"#heading\",\n \"#surface-2\",\n \"#surface-3\",\n \"#surface-2-hover\",\n \"#surface-2-pressed\",\n \"#surface-3-hover\",\n \"#surface-3-pressed\",\n \"#text\",\n \"#text-soft\",\n \"#text-muted\",\n \"#sidebar-text\",\n \"#border\",\n \"#border-strong\",\n \"#accent-text\",\n \"#accent-surface\",\n \"#accent-surface-text\",\n \"#logo-surface\",\n \"#logo-mark\",\n \"#accent-surface-subtle\",\n \"#accent-surface-2-subtle\",\n \"#focus\",\n \"#shadow\",\n \"#overlay\",\n \"#syntax-bg\",\n \"#syntax-text\",\n \"#syntax-comment\",\n \"#syntax-punctuation\",\n \"#syntax-keyword\",\n \"#syntax-string\",\n \"#syntax-token\",\n \"#syntax-property\",\n \"#syntax-number\",\n \"#syntax-function\",\n \"#syntax-value\",\n \"#syntax-operator\",\n \"#info\",\n \"#info-surface\",\n \"#info-text\",\n \"#success\",\n \"#success-surface\",\n \"#success-text\",\n \"#warning\",\n \"#warning-surface\",\n \"#warning-text\",\n \"#danger\",\n \"#danger-surface\",\n \"#danger-text\",\n \"#orange-surface\",\n \"#orange\",\n \"#orange-text\",\n \"#green-surface\",\n \"#green\",\n \"#green-text\",\n \"#blue-surface\",\n \"#blue\",\n \"#blue-text\",\n \"#purple-surface\",\n \"#purple\",\n \"#purple-text\",\n \"#red-surface\",\n \"#red\",\n \"#red-text\",\n ],\n units: [\"x\", \"r\", \"cr\", \"bw\"],\n states: [\n \"@mobile\",\n \"@desktop\",\n \"@small\",\n \"@compact\",\n \"@shell-mobile\",\n \"@shell-desktop\",\n \"@narrow-layout\",\n \"@medium-layout\",\n \"@reduced-motion\",\n ],\n presets: [\n \"body\",\n \"heading\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"navigation\",\n \"small\",\n \"code\",\n ],\n} satisfies TastyValidationConfig;\n","export { default, recommended, strict } from \"@tenphi/eslint-plugin-tasty\";\nexport type {\n ResolvedConfig,\n StyleFunctionConfig,\n TastyValidationConfig,\n} from \"@tenphi/eslint-plugin-tasty\";\nexport { default as validationConfig } from \"./tasty.config.js\";\n\nimport type { ThemeConfig } from \"@tenphi/docs\";\nimport type { TastyValidationConfig } from \"@tenphi/eslint-plugin-tasty\";\nimport validationConfig from \"./tasty.config.js\";\n\n/** Keep editor/linter names aligned with a Cookbook theme. */\nexport function createValidationConfig(\n theme: ThemeConfig = {},\n): TastyValidationConfig {\n return {\n ...validationConfig,\n tokens: [\n ...validationConfig.tokens,\n ...Object.keys(theme.tokens ?? {}),\n ...Object.keys(theme.palette ?? {}).map((name) => `#${name}`),\n ],\n units: [...validationConfig.units, ...Object.keys(theme.units ?? {})],\n states: [...validationConfig.states, ...Object.keys(theme.states ?? {})],\n presets: [...validationConfig.presets, ...Object.keys(theme.presets ?? {})],\n recipes: Object.keys(theme.recipes ?? {}),\n };\n}\n"],"mappings":";;AAEA,IAAA,uBAAe;CACb,eAAe,CAAC,4BAA4B,0BAA0B;CACtE,gBAAgB;EACd,iBAAiB;GAAE,UAAU;GAAG,MAAM;EAAU;EAChD,wBAAwB;GAAE,UAAU;GAAG,MAAM;EAAS;EACtD,aAAa;GAAE,UAAU;GAAO,MAAM;GAAU,SAAS;EAAK;CAChE;CACA,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,OAAO;EAAC;EAAK;EAAK;EAAM;CAAI;CAC5B,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;ACzGA,SAAgB,uBACd,QAAqB,CAAC,GACC;CACvB,OAAO;EACL,GAAGA;EACH,QAAQ;GACN,GAAGA,qBAAiB;GACpB,GAAG,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC;GACjC,GAAG,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM;EAC9D;EACA,OAAO,CAAC,GAAGA,qBAAiB,OAAO,GAAG,OAAO,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC;EACpE,QAAQ,CAAC,GAAGA,qBAAiB,QAAQ,GAAG,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC,CAAC;EACvE,SAAS,CAAC,GAAGA,qBAAiB,SAAS,GAAG,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC,CAAC;EAC1E,SAAS,OAAO,KAAK,MAAM,WAAW,CAAC,CAAC;CAC1C;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/plugin-contract.ts","../src/integration.ts"],"mappings":";;;;;KAEY;EAEN,WAAW,iBAAiB,QAAQ;;EAGpC,MAAM,iBAAiB;;;;UCiGZ;EACf,SAAS;EACT;EACA;;EAEA,oBAAoB;;iBAGE,SACtB,UAAS,kBACR"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/plugin-contract.ts","../src/integration.ts"],"mappings":";;;;;KAEY;EAEN,WAAW,iBAAiB,QAAQ;;EAGpC,MAAM,iBAAiB;;;;UC+FZ;EACf,SAAS;EACT;EACA;;EAEA,oBAAoB;;iBAGE,SACtB,UAAS,kBACR"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { localeAlternates } from "./localization.js";
3
3
  import { DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS, resolveThemeTokens, resolveTypographyPresets } from "./theme/defaults.js";
4
4
  import { configureCodeHighlighting, cookbookShikiConfig } from "./theme/shiki-theme.js";
5
5
  import { TASTY_UNITS, tastyTokens } from "./theme/tasty-config.js";
6
- import { a as resolveLegacyAnatomyStyles, n as cookbookStates, o as unusedCustomStyleNames, r as configureComponentStyles } from "./tasty-states-BDKIbfw2.js";
6
+ import { a as unusedCustomStyleNames, n as cookbookStates, r as configureComponentStyles } from "./tasty-states-rTLFy26t.js";
7
7
  import { agentPagePath } from "./page-metadata.js";
8
8
  import { createRequire } from "node:module";
9
9
  import { cp, mkdir, readFile, readdir, rename, stat, unlink, writeFile } from "node:fs/promises";
@@ -904,9 +904,9 @@ async function createDefaultSocialImage(site, base, colors) {
904
904
  const origin = site.url ? new URL(site.url).host : "";
905
905
  const surface = toHex(colors.surface.light);
906
906
  const heading = toHex(colors.heading.light);
907
- const soft = toHex(colors.textSoft.light);
908
- const accent = toHex(colors.accentText.light);
909
- const accentSurface = toHex(colors.accentSurface.light);
907
+ const soft = toHex(colors["text-soft"].light);
908
+ const accent = toHex(colors["accent-text"].light);
909
+ const accentSurface = toHex(colors["accent-surface"].light);
910
910
  const artwork = Buffer.from(`<svg xmlns="http://www.w3.org/2000/svg" width="${WIDTH}" height="${HEIGHT}" viewBox="0 0 ${WIDTH} ${HEIGHT}">
911
911
  <rect width="${WIDTH}" height="${HEIGHT}" fill="${surface}"/>
912
912
  <rect width="14" height="${HEIGHT}" fill="${accent}"/>
@@ -1530,17 +1530,15 @@ function configuredCookbook(options) {
1530
1530
  "astro:build:done": async (context) => {
1531
1531
  await callInner(inner, "astro:build:done", context);
1532
1532
  const output = fileURLToPath(context.dir);
1533
- const anatomyNames = /* @__PURE__ */ new Set();
1534
1533
  for (const relativePath of await readdir(output, { recursive: true })) {
1535
1534
  if (extname(relativePath) !== ".html") continue;
1536
1535
  const path = join(output, relativePath);
1537
1536
  const html = await readFile(path, "utf8");
1538
- for (const match of html.matchAll(/\bdata-tasty-anatomy="([^"]+)"/g)) anatomyNames.add(match[1]);
1539
1537
  const sanitized = html.replace(/\s*<link\b(?=[^>]*rel="stylesheet")(?=[^>]*href="data:text\/css,")[^>]*>/g, "").replace(/\s*<style>\s*<\/style>/g, "").replace(/<style>astro-island,astro-slot,astro-static-slot\{display:contents\}<\/style>/g, "");
1540
1538
  assertTastyOutput(sanitized, relativePath);
1541
1539
  if (sanitized !== html) await writeFile(path, sanitized);
1542
1540
  }
1543
- for (const name of unusedCustomStyleNames(options.config?.theme?.customStyles, anatomyNames)) context.logger.warn(`theme.customStyles.${name} did not match a component style resolver or rendered data-tasty-anatomy attribute. Check that its name matches defineComponent() or resolveComponentStyles().`);
1541
+ for (const name of unusedCustomStyleNames(options.config?.theme?.customStyles)) context.logger.warn(`theme.customStyles.${name} did not match a component style resolver. Check that its name matches defineComponent() or resolveComponentStyles().`);
1544
1542
  if (graph?.config.search.enabled !== false) try {
1545
1543
  const { index, errors } = await pagefind.createIndex();
1546
1544
  if (errors.length || !index) throw new Error(errors.join("\n") || "Pagefind did not create an index.");
@@ -1667,7 +1665,6 @@ function errorMessage(error) {
1667
1665
  }
1668
1666
  function configureTastyTheme(theme, resolved) {
1669
1667
  const tokens = tastyTokens(resolved);
1670
- const globalStyles = resolveLegacyAnatomyStyles(theme?.customStyles);
1671
1668
  globalThis.__tenphiCookbookTastyRuntime = {
1672
1669
  units: {
1673
1670
  ...TASTY_UNITS,
@@ -1689,8 +1686,7 @@ function configureTastyTheme(theme, resolved) {
1689
1686
  },
1690
1687
  recipes: theme?.recipes ?? {},
1691
1688
  tokens,
1692
- presets: resolved.presets,
1693
- ...globalStyles ? { globalStyles } : {}
1689
+ presets: resolved.presets
1694
1690
  });
1695
1691
  }
1696
1692
  async function callInner(integrations, hook, context) {