@getvitops/astro 0.8.0 → 0.9.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/CHANGELOG.md +68 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +9 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -8
- package/src/components/Cards.astro +16 -14
- package/src/components/Drawer.astro +19 -2
- package/src/components/Popover.astro +17 -2
- package/src/components/Subgrid.astro +18 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# @getvitops/astro
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **Fixed: `Subgrid` and `Cards` rendered as unstyled lists, in every format.**
|
|
8
|
+
|
|
9
|
+
`Subgrid.astro` drew its geometry with Tailwind utilities — `grid-rows-subgrid` and
|
|
10
|
+
`row-span-(--row-span)`, the latter Tailwind v4's arbitrary-CSS-variable syntax. No framework CSS
|
|
11
|
+
layer defines those, so under `css.format: 'css'` or `'bricks'` the component had no layout at all.
|
|
12
|
+
|
|
13
|
+
It failed under `'tailwind'` too, which is the part worth internalising: **Tailwind v4 is JIT and
|
|
14
|
+
does not scan `node_modules`**, so a class that only a shipped component references is never
|
|
15
|
+
generated. A consumer had to add the package to Tailwind's `@source` by hand to get a subgrid;
|
|
16
|
+
without that, cards silently laid out at `grid-row: auto` — visually plausible, quietly wrong. The
|
|
17
|
+
same trap applied to `grid` in `Subgrid` and `sr-only` / `not-sr-only` in `Popover` / `Drawer`:
|
|
18
|
+
those are in the generator's `TW_CLASH` list, so the framework strips its own rules for them from
|
|
19
|
+
the tailwind bundle and defers to Tailwind — meaning they resolved only when the consumer's own
|
|
20
|
+
templates happened to use the same class.
|
|
21
|
+
|
|
22
|
+
The components now emit framework classes only, and the `subgrid` pattern owns the layout:
|
|
23
|
+
- `Subgrid` renders `<ul class="subgrid"><li>…` and ships no `<style>` block of its own.
|
|
24
|
+
- `Popover` / `Drawer` use a component-scoped `visually-hidden` instead of `sr-only`. The
|
|
25
|
+
`not-sr-only` on their icons was a no-op and is gone.
|
|
26
|
+
- The `subgrid` pattern absorbed the wrapped-row margin the component used to carry, so
|
|
27
|
+
hand-written `.subgrid` markup gets it too, and resets list markers on `ul`/`ol`.
|
|
28
|
+
|
|
29
|
+
**Also fixed: `Cards` discarded the `card` class and every class you put on a child.** It wrote
|
|
30
|
+
`card` onto the slotted element and then serialised that element's _inner_ HTML, dropping the
|
|
31
|
+
attribute it had just set. Child `class` and `style` now reach the rendered `<li>`.
|
|
32
|
+
|
|
33
|
+
**Breaking — the subgrid custom properties are renamed.** One `--subgrid-*` vocabulary now covers
|
|
34
|
+
both the pattern and the component; the old names are removed, not aliased:
|
|
35
|
+
|
|
36
|
+
| removed | use |
|
|
37
|
+
| ------------------------------- | -------------------- |
|
|
38
|
+
| `--items-per-row`, `--cols` | `--subgrid-cols` |
|
|
39
|
+
| `--rows-per-item`, `--row-span` | `--subgrid-row-span` |
|
|
40
|
+
| `--row-margin` | `--subgrid-row-gap` |
|
|
41
|
+
|
|
42
|
+
`--subgrid-gap` (the grid gap) is unchanged, as are the `.subgrid-cols-*` / `.subgrid-rows-*` /
|
|
43
|
+
`.subgrid-responsive` modifiers. Anything still setting an old name falls back to the pattern
|
|
44
|
+
defaults — 3 columns, span 2 — so grep for them when you upgrade.
|
|
45
|
+
|
|
46
|
+
- **`tailwindcss` and `@tailwindcss/vite` are now optional peer dependencies, not dependencies.**
|
|
47
|
+
|
|
48
|
+
Only `css.format: 'tailwind'` ever used them, but every consumer installed them — including
|
|
49
|
+
`'css'` and `'bricks'` projects that never touch Tailwind. The integration now loads
|
|
50
|
+
`@tailwindcss/vite` lazily inside that branch and throws a directive error if it is missing.
|
|
51
|
+
|
|
52
|
+
**Migration:** if you use `css.format: 'tailwind'` (the default), add both to your
|
|
53
|
+
`devDependencies` — `pnpm add -D tailwindcss @tailwindcss/vite`. Most Tailwind projects already
|
|
54
|
+
have them. Everyone else can drop them.
|
|
55
|
+
|
|
56
|
+
### Patch Changes
|
|
57
|
+
|
|
58
|
+
- Updated dependencies
|
|
59
|
+
- Updated dependencies
|
|
60
|
+
- Updated dependencies
|
|
61
|
+
- Updated dependencies [c949cae]
|
|
62
|
+
- Updated dependencies
|
|
63
|
+
- Updated dependencies
|
|
64
|
+
- Updated dependencies
|
|
65
|
+
- Updated dependencies
|
|
66
|
+
- @getvitops/generator@0.9.0
|
|
67
|
+
- @getvitops/core@0.9.0
|
|
68
|
+
- @getvitops/vite@0.9.0
|
|
69
|
+
- @getvitops/utils@0.9.0
|
|
70
|
+
|
|
3
71
|
## 0.8.0
|
|
4
72
|
|
|
5
73
|
### Minor Changes
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/integration.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/integration.ts"],"mappings":";;;;;UAsBiB,uBAAA;;EAEf,MAAA;EACA,YAAA;EAHe;EAKf,IAAA;;EAEA,UAAA;EACA,eAAA;AAAA;AAAA,UAGe,mBAAA;EAJf;EAMA,KAAA;EALe;EAOf,MAAA,GAAS,MAAM;EAJA;EAMf,GAAA;;;;;;;;EAQA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,OAAA,GAAU,uBAAA;;EAEV,aAAA;EAFA;EAIA,GAAA,GAAM,mBAAmB;EAFzB;;;;;AAcM;AACP;;;;;EADC,MAAA;AAAA;AAAA,iBA2BsB,SAAA,CAAU,IAAA,GAAM,gBAAA,GAAwB,gBAAgB"}
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { dirname, join, resolve } from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { faviconLinks, generateFavicons, writeFaviconManifest } from "@getvitops/utils";
|
|
5
5
|
import vitops from "@getvitops/vite";
|
|
6
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
7
6
|
|
|
8
7
|
export * from "@getvitops/utils"
|
|
9
8
|
|
|
@@ -94,7 +93,15 @@ function getvitops(opts = {}) {
|
|
|
94
93
|
out,
|
|
95
94
|
...editor ? { editorManifestDir: publicDir } : {}
|
|
96
95
|
})];
|
|
97
|
-
if (format === "tailwind")
|
|
96
|
+
if (format === "tailwind") {
|
|
97
|
+
let tailwindcss;
|
|
98
|
+
try {
|
|
99
|
+
({default: tailwindcss} = await import("@tailwindcss/vite"));
|
|
100
|
+
} catch {
|
|
101
|
+
throw new Error("[getvitops] css.format: 'tailwind' requires `tailwindcss` and `@tailwindcss/vite` in your devDependencies — install them, or switch to css.format: 'css' for the standalone bundle.");
|
|
102
|
+
}
|
|
103
|
+
plugins.push(...tailwindcss());
|
|
104
|
+
}
|
|
98
105
|
updateConfig({ vite: { plugins } });
|
|
99
106
|
const cssFile = format === "tailwind" ? "tailwind.css" : "styles.css";
|
|
100
107
|
if (opts.css.inject !== false) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/integration.ts"],"sourcesContent":["/**\n * @getvitops/astro — the Astro integration. One entry wires the design system's\n * `<head>` contributions into a consumer site:\n * - favicons + PWA manifest (generated into public/),\n * - the web-component runtime bundles (copied into public/vitops/),\n * - (opt-in) the design-system CSS, generated + auto-injected (no manual import).\n * The `<Head />` component (shipped alongside) renders the tags, reading resolved\n * config from the `virtual:getvitops/head` module this integration provides.\n */\nimport { cpSync, existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Format } from '@getvitops/generator';\nimport {\n type FaviconLink,\n faviconLinks,\n generateFavicons,\n writeFaviconManifest,\n} from '@getvitops/utils';\nimport vitops from '@getvitops/vite';\nimport tailwindcss from '@tailwindcss/vite';\nimport type { AstroIntegration } from 'astro';\n\nexport interface GetvitopsFaviconOptions {\n /** Source SVG or PNG. */\n source: string;\n lowResSource?: string;\n /** App name → enables `site.webmanifest`. */\n name?: string;\n /** PWA theme color (also `<meta name=\"theme-color\">`). */\n themeColor?: string;\n backgroundColor?: string;\n}\n\nexport interface GetvitopsCssOptions {\n /** Path to design-system.json (default 'design-system.json'). */\n input?: string;\n /** Output format (default 'tailwind'). */\n format?: Format;\n /** Directory the generated CSS is written to (default 'src/styles'). */\n out?: string;\n /**\n * Auto-inject the generated stylesheet into every SSR page (default true).\n * Set false when other integrations add routes that must not inherit the\n * design system (e.g. EmDash's `/_emdash/admin`) — then import the generated\n * file (`<out>/tailwind.css` or `<out>/styles.css`) from your site layout so\n * only your own pages (and previews rendered through them) are styled.\n */\n inject?: boolean;\n}\n\nexport interface GetvitopsOptions {\n favicon?: GetvitopsFaviconOptions;\n /** Copy + link the web-component bundles (default true). */\n webComponents?: boolean;\n /** Generate + auto-inject the design-system CSS. Off unless provided. */\n css?: GetvitopsCssOptions;\n /**\n * Ship the live theme editor (default false).\n *\n * Copies `editor.js` into `public/vitops/`, loads it from `<Head />`, and mirrors\n * the generated `design-manifest.json` next to it so `<wc-theme-editor>` resolves\n * its default `/vitops/design-manifest.json`. Requires `css` (the manifest is a\n * `css`-format output) — place the `<wc-theme-editor>` tag in your layout yourself.\n *\n * Editing is live on any deploy; **saving back** to `design-system.json` needs the\n * dev server, so on a static build that button simply isn't rendered.\n */\n editor?: boolean;\n}\n\ninterface HeadData {\n favicons: boolean;\n faviconLinks: FaviconLink[];\n themeColor: string | null;\n webComponents: boolean;\n wcBase: string;\n editor: boolean;\n}\n\nconst VIRTUAL_ID = 'virtual:getvitops/head';\nconst RESOLVED_ID = `\\0${VIRTUAL_ID}`;\n\nfunction virtualHeadPlugin(data: HeadData) {\n return {\n name: '@getvitops/astro:virtual-head',\n resolveId(id: string) {\n return id === VIRTUAL_ID ? RESOLVED_ID : null;\n },\n load(id: string) {\n return id === RESOLVED_ID ? `export default ${JSON.stringify(data)};` : null;\n },\n };\n}\n\nexport default function getvitops(opts: GetvitopsOptions = {}): AstroIntegration {\n return {\n name: '@getvitops/astro',\n hooks: {\n 'astro:config:setup': async ({ config, updateConfig, injectScript, logger }) => {\n const root = fileURLToPath(config.root);\n const publicDir = fileURLToPath(config.publicDir);\n const webComponents = opts.webComponents !== false;\n const editor = opts.editor === true;\n if (editor && !opts.css)\n logger.warn('editor: true needs a `css` config — it reads design-manifest.json.');\n const hasManifest = !!(opts.favicon?.name && opts.favicon?.themeColor);\n let hasSvg = false;\n\n // 1. Favicons + manifest → public/\n if (opts.favicon) {\n const source = resolve(root, opts.favicon.source);\n hasSvg = source.endsWith('.svg');\n await generateFavicons({\n source,\n outputDir: publicDir,\n ...(opts.favicon.lowResSource\n ? { lowResSource: resolve(root, opts.favicon.lowResSource) }\n : {}),\n });\n if (opts.favicon.name && opts.favicon.themeColor) {\n await writeFaviconManifest(publicDir, {\n name: opts.favicon.name,\n themeColor: opts.favicon.themeColor,\n ...(opts.favicon.backgroundColor\n ? { backgroundColor: opts.favicon.backgroundColor }\n : {}),\n });\n }\n logger.info('generated favicons + manifest → public/');\n }\n\n // 2. Web-component bundles → public/vitops/\n if (webComponents) {\n const corePkg = fileURLToPath(import.meta.resolve('@getvitops/core/package.json'));\n const coreDist = join(dirname(corePkg), 'dist');\n const dest = join(publicDir, 'vitops');\n if (existsSync(coreDist)) {\n const bundles = ['polyfills.js', 'deferred.js', 'elements.js', 'polyfills'];\n if (editor) bundles.push('editor.js');\n for (const f of bundles) {\n const src = join(coreDist, f);\n if (existsSync(src)) cpSync(src, join(dest, f), { recursive: true });\n }\n logger.info('copied web-component bundles → public/vitops/');\n } else {\n logger.warn(\n `@getvitops/core dist not found (${coreDist}); run build:core. Skipping WC copy.`,\n );\n }\n }\n\n // 3. Virtual head module for <Head/>\n updateConfig({\n vite: {\n plugins: [\n virtualHeadPlugin({\n favicons: !!opts.favicon,\n faviconLinks: opts.favicon ? faviconLinks({ hasSvg, manifest: hasManifest }) : [],\n themeColor: opts.favicon?.themeColor ?? null,\n webComponents,\n wcBase: '/vitops',\n editor,\n }),\n ],\n },\n });\n\n // 4. CSS — generate + compile + auto-inject (consumer imports nothing).\n if (opts.css) {\n const format: Format = opts.css.format ?? 'tailwind';\n const out = opts.css.out ?? 'src/styles';\n const plugins = [\n vitops({\n input: opts.css.input ?? 'design-system.json',\n format,\n out,\n // Mirrored inside the generate pass so the served copy can never be\n // missing on a cold start or stale after a config edit.\n ...(editor ? { editorManifestDir: publicDir } : {}),\n }),\n ];\n // tailwindcss() is typed against a newer vite than @getvitops/vite's\n // peer; the Plugin shapes are structurally compatible at runtime\n // (Astro forwards them verbatim), so bridge the two type identities.\n if (format === 'tailwind') plugins.push(...(tailwindcss() as unknown as typeof plugins));\n updateConfig({ vite: { plugins } });\n const cssFile = format === 'tailwind' ? 'tailwind.css' : 'styles.css';\n if (opts.css.inject !== false) {\n const cssPath = resolve(root, out, cssFile);\n injectScript('page-ssr', `import ${JSON.stringify(cssPath)};`);\n logger.info(`design-system CSS (${format}) auto-injected from ${out}/${cssFile}`);\n } else {\n logger.info(\n `design-system CSS (${format}) generated at ${out}/${cssFile} (inject: false — import it from your layout)`,\n );\n }\n }\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgFA,MAAM,aAAa;AACnB,MAAM,cAAc,KAAK;AAEzB,SAAS,kBAAkB,MAAgB;CACzC,OAAO;EACL,MAAM;EACN,UAAU,IAAY;GACpB,OAAO,OAAO,aAAa,cAAc;EAC3C;EACA,KAAK,IAAY;GACf,OAAO,OAAO,cAAc,kBAAkB,KAAK,UAAU,IAAI,EAAE,KAAK;EAC1E;CACF;AACF;AAEA,SAAwB,UAAU,OAAyB,CAAC,GAAqB;CAC/E,OAAO;EACL,MAAM;EACN,OAAO,EACL,sBAAsB,OAAO,EAAE,QAAQ,cAAc,cAAc,aAAa;GAC9E,MAAM,OAAO,cAAc,OAAO,IAAI;GACtC,MAAM,YAAY,cAAc,OAAO,SAAS;GAChD,MAAM,gBAAgB,KAAK,kBAAkB;GAC7C,MAAM,SAAS,KAAK,WAAW;GAC/B,IAAI,UAAU,CAAC,KAAK,KAClB,OAAO,KAAK,oEAAoE;GAClF,MAAM,cAAc,CAAC,EAAE,KAAK,SAAS,QAAQ,KAAK,SAAS;GAC3D,IAAI,SAAS;GAGb,IAAI,KAAK,SAAS;IAChB,MAAM,SAAS,QAAQ,MAAM,KAAK,QAAQ,MAAM;IAChD,SAAS,OAAO,SAAS,MAAM;IAC/B,MAAM,iBAAiB;KACrB;KACA,WAAW;KACX,GAAI,KAAK,QAAQ,eACb,EAAE,cAAc,QAAQ,MAAM,KAAK,QAAQ,YAAY,EAAE,IACzD,CAAC;IACP,CAAC;IACD,IAAI,KAAK,QAAQ,QAAQ,KAAK,QAAQ,YACpC,MAAM,qBAAqB,WAAW;KACpC,MAAM,KAAK,QAAQ;KACnB,YAAY,KAAK,QAAQ;KACzB,GAAI,KAAK,QAAQ,kBACb,EAAE,iBAAiB,KAAK,QAAQ,gBAAgB,IAChD,CAAC;IACP,CAAC;IAEH,OAAO,KAAK,yCAAyC;GACvD;GAGA,IAAI,eAAe;IAEjB,MAAM,WAAW,KAAK,QADN,cAAc,OAAO,KAAK,QAAQ,8BAA8B,CAC5C,CAAC,GAAG,MAAM;IAC9C,MAAM,OAAO,KAAK,WAAW,QAAQ;IACrC,IAAI,WAAW,QAAQ,GAAG;KACxB,MAAM,UAAU;MAAC;MAAgB;MAAe;MAAe;KAAW;KAC1E,IAAI,QAAQ,QAAQ,KAAK,WAAW;KACpC,KAAK,MAAM,KAAK,SAAS;MACvB,MAAM,MAAM,KAAK,UAAU,CAAC;MAC5B,IAAI,WAAW,GAAG,GAAG,OAAO,KAAK,KAAK,MAAM,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;KACrE;KACA,OAAO,KAAK,+CAA+C;IAC7D,OACE,OAAO,KACL,mCAAmC,SAAS,qCAC9C;GAEJ;GAGA,aAAa,EACX,MAAM,EACJ,SAAS,CACP,kBAAkB;IAChB,UAAU,CAAC,CAAC,KAAK;IACjB,cAAc,KAAK,UAAU,aAAa;KAAE;KAAQ,UAAU;IAAY,CAAC,IAAI,CAAC;IAChF,YAAY,KAAK,SAAS,cAAc;IACxC;IACA,QAAQ;IACR;GACF,CAAC,CACH,EACF,EACF,CAAC;GAGD,IAAI,KAAK,KAAK;IACZ,MAAM,SAAiB,KAAK,IAAI,UAAU;IAC1C,MAAM,MAAM,KAAK,IAAI,OAAO;IAC5B,MAAM,UAAU,CACd,OAAO;KACL,OAAO,KAAK,IAAI,SAAS;KACzB;KACA;KAGA,GAAI,SAAS,EAAE,mBAAmB,UAAU,IAAI,CAAC;IACnD,CAAC,CACH;IAIA,IAAI,WAAW,YAAY,QAAQ,KAAK,GAAI,YAAY,CAA+B;IACvF,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAClC,MAAM,UAAU,WAAW,aAAa,iBAAiB;IACzD,IAAI,KAAK,IAAI,WAAW,OAAO;KAC7B,MAAM,UAAU,QAAQ,MAAM,KAAK,OAAO;KAC1C,aAAa,YAAY,UAAU,KAAK,UAAU,OAAO,EAAE,EAAE;KAC7D,OAAO,KAAK,sBAAsB,OAAO,uBAAuB,IAAI,GAAG,SAAS;IAClF,OACE,OAAO,KACL,sBAAsB,OAAO,iBAAiB,IAAI,GAAG,QAAQ,8CAC/D;GAEJ;EACF,EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/integration.ts"],"sourcesContent":["/**\n * @getvitops/astro — the Astro integration. One entry wires the design system's\n * `<head>` contributions into a consumer site:\n * - favicons + PWA manifest (generated into public/),\n * - the web-component runtime bundles (copied into public/vitops/),\n * - (opt-in) the design-system CSS, generated + auto-injected (no manual import).\n * The `<Head />` component (shipped alongside) renders the tags, reading resolved\n * config from the `virtual:getvitops/head` module this integration provides.\n */\nimport { cpSync, existsSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Format } from '@getvitops/generator';\nimport {\n type FaviconLink,\n faviconLinks,\n generateFavicons,\n writeFaviconManifest,\n} from '@getvitops/utils';\nimport vitops from '@getvitops/vite';\nimport type { AstroIntegration } from 'astro';\n\nexport interface GetvitopsFaviconOptions {\n /** Source SVG or PNG. */\n source: string;\n lowResSource?: string;\n /** App name → enables `site.webmanifest`. */\n name?: string;\n /** PWA theme color (also `<meta name=\"theme-color\">`). */\n themeColor?: string;\n backgroundColor?: string;\n}\n\nexport interface GetvitopsCssOptions {\n /** Path to design-system.json (default 'design-system.json'). */\n input?: string;\n /** Output format (default 'tailwind'). */\n format?: Format;\n /** Directory the generated CSS is written to (default 'src/styles'). */\n out?: string;\n /**\n * Auto-inject the generated stylesheet into every SSR page (default true).\n * Set false when other integrations add routes that must not inherit the\n * design system (e.g. EmDash's `/_emdash/admin`) — then import the generated\n * file (`<out>/tailwind.css` or `<out>/styles.css`) from your site layout so\n * only your own pages (and previews rendered through them) are styled.\n */\n inject?: boolean;\n}\n\nexport interface GetvitopsOptions {\n favicon?: GetvitopsFaviconOptions;\n /** Copy + link the web-component bundles (default true). */\n webComponents?: boolean;\n /** Generate + auto-inject the design-system CSS. Off unless provided. */\n css?: GetvitopsCssOptions;\n /**\n * Ship the live theme editor (default false).\n *\n * Copies `editor.js` into `public/vitops/`, loads it from `<Head />`, and mirrors\n * the generated `design-manifest.json` next to it so `<wc-theme-editor>` resolves\n * its default `/vitops/design-manifest.json`. Requires `css` (the manifest is a\n * `css`-format output) — place the `<wc-theme-editor>` tag in your layout yourself.\n *\n * Editing is live on any deploy; **saving back** to `design-system.json` needs the\n * dev server, so on a static build that button simply isn't rendered.\n */\n editor?: boolean;\n}\n\ninterface HeadData {\n favicons: boolean;\n faviconLinks: FaviconLink[];\n themeColor: string | null;\n webComponents: boolean;\n wcBase: string;\n editor: boolean;\n}\n\nconst VIRTUAL_ID = 'virtual:getvitops/head';\nconst RESOLVED_ID = `\\0${VIRTUAL_ID}`;\n\nfunction virtualHeadPlugin(data: HeadData) {\n return {\n name: '@getvitops/astro:virtual-head',\n resolveId(id: string) {\n return id === VIRTUAL_ID ? RESOLVED_ID : null;\n },\n load(id: string) {\n return id === RESOLVED_ID ? `export default ${JSON.stringify(data)};` : null;\n },\n };\n}\n\nexport default function getvitops(opts: GetvitopsOptions = {}): AstroIntegration {\n return {\n name: '@getvitops/astro',\n hooks: {\n 'astro:config:setup': async ({ config, updateConfig, injectScript, logger }) => {\n const root = fileURLToPath(config.root);\n const publicDir = fileURLToPath(config.publicDir);\n const webComponents = opts.webComponents !== false;\n const editor = opts.editor === true;\n if (editor && !opts.css)\n logger.warn('editor: true needs a `css` config — it reads design-manifest.json.');\n const hasManifest = !!(opts.favicon?.name && opts.favicon?.themeColor);\n let hasSvg = false;\n\n // 1. Favicons + manifest → public/\n if (opts.favicon) {\n const source = resolve(root, opts.favicon.source);\n hasSvg = source.endsWith('.svg');\n await generateFavicons({\n source,\n outputDir: publicDir,\n ...(opts.favicon.lowResSource\n ? { lowResSource: resolve(root, opts.favicon.lowResSource) }\n : {}),\n });\n if (opts.favicon.name && opts.favicon.themeColor) {\n await writeFaviconManifest(publicDir, {\n name: opts.favicon.name,\n themeColor: opts.favicon.themeColor,\n ...(opts.favicon.backgroundColor\n ? { backgroundColor: opts.favicon.backgroundColor }\n : {}),\n });\n }\n logger.info('generated favicons + manifest → public/');\n }\n\n // 2. Web-component bundles → public/vitops/\n if (webComponents) {\n const corePkg = fileURLToPath(import.meta.resolve('@getvitops/core/package.json'));\n const coreDist = join(dirname(corePkg), 'dist');\n const dest = join(publicDir, 'vitops');\n if (existsSync(coreDist)) {\n const bundles = ['polyfills.js', 'deferred.js', 'elements.js', 'polyfills'];\n if (editor) bundles.push('editor.js');\n for (const f of bundles) {\n const src = join(coreDist, f);\n if (existsSync(src)) cpSync(src, join(dest, f), { recursive: true });\n }\n logger.info('copied web-component bundles → public/vitops/');\n } else {\n logger.warn(\n `@getvitops/core dist not found (${coreDist}); run build:core. Skipping WC copy.`,\n );\n }\n }\n\n // 3. Virtual head module for <Head/>\n updateConfig({\n vite: {\n plugins: [\n virtualHeadPlugin({\n favicons: !!opts.favicon,\n faviconLinks: opts.favicon ? faviconLinks({ hasSvg, manifest: hasManifest }) : [],\n themeColor: opts.favicon?.themeColor ?? null,\n webComponents,\n wcBase: '/vitops',\n editor,\n }),\n ],\n },\n });\n\n // 4. CSS — generate + compile + auto-inject (consumer imports nothing).\n if (opts.css) {\n const format: Format = opts.css.format ?? 'tailwind';\n const out = opts.css.out ?? 'src/styles';\n const plugins = [\n vitops({\n input: opts.css.input ?? 'design-system.json',\n format,\n out,\n // Mirrored inside the generate pass so the served copy can never be\n // missing on a cold start or stale after a config edit.\n ...(editor ? { editorManifestDir: publicDir } : {}),\n }),\n ];\n // Tailwind is an optional peer — only the `tailwind` format needs it,\n // so it's loaded here rather than imported at module scope. (The\n // plugin is typed against a newer vite than @getvitops/vite's peer;\n // the Plugin shapes are structurally compatible at runtime — Astro\n // forwards them verbatim — so bridge the two type identities.)\n if (format === 'tailwind') {\n let tailwindcss: () => unknown[];\n try {\n ({ default: tailwindcss } = await import('@tailwindcss/vite'));\n } catch {\n throw new Error(\n \"[getvitops] css.format: 'tailwind' requires `tailwindcss` and `@tailwindcss/vite` \" +\n 'in your devDependencies — install them, or switch to css.format: ' +\n \"'css' for the standalone bundle.\",\n );\n }\n plugins.push(...(tailwindcss() as unknown as typeof plugins));\n }\n updateConfig({ vite: { plugins } });\n const cssFile = format === 'tailwind' ? 'tailwind.css' : 'styles.css';\n if (opts.css.inject !== false) {\n const cssPath = resolve(root, out, cssFile);\n injectScript('page-ssr', `import ${JSON.stringify(cssPath)};`);\n logger.info(`design-system CSS (${format}) auto-injected from ${out}/${cssFile}`);\n } else {\n logger.info(\n `design-system CSS (${format}) generated at ${out}/${cssFile} (inject: false — import it from your layout)`,\n );\n }\n }\n },\n },\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getvitops/astro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Astro integration for the Vitops design system — favicons/PWA, web-component scripts, and CSS, via a getvitops() integration + <Head /> component.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -39,24 +39,32 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"@getvitops/
|
|
45
|
-
"@getvitops/
|
|
46
|
-
"@getvitops/generator": "0.8.0",
|
|
47
|
-
"@getvitops/utils": "0.8.0"
|
|
42
|
+
"@getvitops/core": "0.9.0",
|
|
43
|
+
"@getvitops/vite": "0.9.0",
|
|
44
|
+
"@getvitops/generator": "0.9.0",
|
|
45
|
+
"@getvitops/utils": "0.9.0"
|
|
48
46
|
},
|
|
49
47
|
"devDependencies": {
|
|
48
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
50
49
|
"astro": "^7.1.2",
|
|
50
|
+
"tailwindcss": "^4.3.3",
|
|
51
51
|
"vitest": "^4.1.9"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
+
"@tailwindcss/vite": ">=4",
|
|
54
55
|
"astro": ">=7",
|
|
55
|
-
"astro-icon": ">=1"
|
|
56
|
+
"astro-icon": ">=1",
|
|
57
|
+
"tailwindcss": ">=4"
|
|
56
58
|
},
|
|
57
59
|
"peerDependenciesMeta": {
|
|
60
|
+
"@tailwindcss/vite": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
58
63
|
"astro-icon": {
|
|
59
64
|
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"tailwindcss": {
|
|
67
|
+
"optional": true
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
}
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* Cards — a `Subgrid` whose items are `card`s. The child's own class and style
|
|
4
|
+
* ride along, so `<article class="bg-surface">` becomes `<li class="card bg-surface">`.
|
|
5
|
+
*
|
|
6
|
+
* The class has to be put on the `<li>` we hand to Subgrid rather than written
|
|
7
|
+
* into the slotted element: `serialize()` returns a node's *inner* HTML, so the
|
|
8
|
+
* element carrying the attribute is discarded on the way through.
|
|
9
|
+
*/
|
|
2
10
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
11
|
import Subgrid from './Subgrid.astro';
|
|
4
|
-
import { parseRenderedSlots, serialize } from '@getvitops/utils';
|
|
12
|
+
import { parseRenderedSlots, getAttribute, serialize } from '@getvitops/utils';
|
|
5
13
|
|
|
6
14
|
export interface Props extends HTMLAttributes<'ul'> {}
|
|
7
15
|
|
|
8
16
|
const { class: className, ...rest } = Astro.props;
|
|
9
17
|
|
|
10
18
|
const nodes = parseRenderedSlots(await Astro.slots.render('default'));
|
|
11
|
-
const slots = nodes.filter(node => 'tagName' in node).map(node => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} else {
|
|
17
|
-
node.attrs.push({ name: 'class', value });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return { html: serialize(node), attrs: node.attrs };
|
|
21
|
-
});
|
|
19
|
+
const slots = nodes.filter(node => 'tagName' in node).map(node => ({
|
|
20
|
+
html: serialize(node),
|
|
21
|
+
class: getAttribute(node, 'class'),
|
|
22
|
+
style: getAttribute(node, 'style'),
|
|
23
|
+
}));
|
|
22
24
|
---
|
|
23
25
|
|
|
24
26
|
<Subgrid
|
|
25
27
|
role="list"
|
|
26
|
-
class
|
|
28
|
+
class={className}
|
|
27
29
|
{...rest}
|
|
28
30
|
>
|
|
29
31
|
{slots.map((slot) => (
|
|
30
|
-
<li class="card
|
|
32
|
+
<li class:list={["card", slot.class]} style={slot.style} set:html={slot.html}></li>
|
|
31
33
|
))}
|
|
32
34
|
</Subgrid>
|
|
@@ -49,8 +49,8 @@ const { class: dialogAttrClass, style: dialogAttrStyle, ...dialogRestAttrs } = a
|
|
|
49
49
|
aria-label={trigger?.label || 'Open drawer'}
|
|
50
50
|
{...triggerRestAttrs}
|
|
51
51
|
>
|
|
52
|
-
<span class={trigger?.icon
|
|
53
|
-
{trigger?.icon && <Icon name={iconResolver(trigger.icon)}
|
|
52
|
+
<span class:list={[trigger?.icon && 'visually-hidden']}>{trigger?.label || 'Open'}</span>
|
|
53
|
+
{trigger?.icon && <Icon name={iconResolver(trigger.icon)} />}
|
|
54
54
|
</button>
|
|
55
55
|
</slot>
|
|
56
56
|
|
|
@@ -63,3 +63,20 @@ const { class: dialogAttrClass, style: dialogAttrStyle, ...dialogRestAttrs } = a
|
|
|
63
63
|
>
|
|
64
64
|
<slot />
|
|
65
65
|
</dialog>
|
|
66
|
+
|
|
67
|
+
<style>
|
|
68
|
+
/* Icon-only triggers keep their label for screen readers. Component-scoped
|
|
69
|
+
rather than the framework's `sr-only`: that one is in the generator's
|
|
70
|
+
TW_CLASH list, so the tailwind format ships no rule for it. */
|
|
71
|
+
.visually-hidden {
|
|
72
|
+
position: absolute;
|
|
73
|
+
inline-size: 1px;
|
|
74
|
+
block-size: 1px;
|
|
75
|
+
padding: 0;
|
|
76
|
+
margin: -1px;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
clip-path: inset(50%);
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
border: 0;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
@@ -48,8 +48,8 @@ const { class: triggerAttrClass, ...triggerRestAttrs } = trigger?.attrs ?? {};
|
|
|
48
48
|
aria-label={trigger?.label || 'Open'}
|
|
49
49
|
{...triggerRestAttrs}
|
|
50
50
|
>
|
|
51
|
-
<span class={trigger?.icon
|
|
52
|
-
{trigger?.icon && <Icon name={iconResolver(trigger.icon)}
|
|
51
|
+
<span class:list={[trigger?.icon && 'visually-hidden']}>{trigger?.label || 'Open'}</span>
|
|
52
|
+
{trigger?.icon && <Icon name={iconResolver(trigger.icon)} />}
|
|
53
53
|
</button>
|
|
54
54
|
</slot>
|
|
55
55
|
|
|
@@ -87,4 +87,19 @@ const { class: triggerAttrClass, ...triggerRestAttrs } = trigger?.attrs ?? {};
|
|
|
87
87
|
font-family: inherit;
|
|
88
88
|
color: inherit;
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
/* Icon-only triggers keep their label for screen readers. Component-scoped
|
|
92
|
+
rather than the framework's `sr-only`: that one is in the generator's
|
|
93
|
+
TW_CLASH list, so the tailwind format ships no rule for it. */
|
|
94
|
+
.visually-hidden {
|
|
95
|
+
position: absolute;
|
|
96
|
+
inline-size: 1px;
|
|
97
|
+
block-size: 1px;
|
|
98
|
+
padding: 0;
|
|
99
|
+
margin: -1px;
|
|
100
|
+
overflow: hidden;
|
|
101
|
+
clip-path: inset(50%);
|
|
102
|
+
white-space: nowrap;
|
|
103
|
+
border: 0;
|
|
104
|
+
}
|
|
90
105
|
</style>
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* Subgrid — re-emits slotted children as `<li>` items of a `.subgrid` grid, so
|
|
4
|
+
* the tranches inside each one align on shared row lines. Every declaration
|
|
5
|
+
* lives in the framework's `subgrid` pattern (patterns/subgrid.css), which is
|
|
6
|
+
* emitted in all three output formats; this file is markup only.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here may reach for a Tailwind utility: Tailwind doesn't scan
|
|
9
|
+
* node_modules, so a class only it can emit is silently never generated — and
|
|
10
|
+
* classes in the generator's TW_CLASH list are stripped from the framework's
|
|
11
|
+
* own tailwind bundle by design.
|
|
12
|
+
*
|
|
13
|
+
* Size it from the consumer's own CSS, which keeps media-query overrides
|
|
14
|
+
* working: `--subgrid-cols`, `--subgrid-row-span`, `--subgrid-gap`,
|
|
15
|
+
* `--subgrid-row-gap`. `--num-items` is set here for nth-child-style maths.
|
|
16
|
+
*/
|
|
2
17
|
import type { HTMLAttributes } from 'astro/types';
|
|
3
18
|
import { parseRenderedSlots, getAttribute, serialize, styleList } from '@getvitops/utils';
|
|
4
19
|
|
|
@@ -10,23 +25,8 @@ const nodes = parseRenderedSlots(await Astro.slots.render('default'));
|
|
|
10
25
|
const slots = nodes.filter(node => 'tagName' in node).map(node => ({ html: serialize(node), attrs: node.attrs }));
|
|
11
26
|
---
|
|
12
27
|
|
|
13
|
-
<style>
|
|
14
|
-
ul {
|
|
15
|
-
grid-template-columns: repeat(var(--cols, var(--_cols, 1)), minmax(0, 1fr));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
li {
|
|
19
|
-
--current-row: round(down, calc((sibling-index() - 1) / var(--cols)), 1);
|
|
20
|
-
|
|
21
|
-
/* Apply the extra gap ONLY if the row index is > 0.
|
|
22
|
-
We use clamp to ensure the multiplier is either 0 or 1.
|
|
23
|
-
*/
|
|
24
|
-
--row-gap-multiplier: clamp(0, var(--current-row), 1);
|
|
25
|
-
margin-block-start: calc(var(--row-gap-multiplier) * var(--row-margin));
|
|
26
|
-
}
|
|
27
|
-
</style>
|
|
28
|
-
<ul class:list={["grid", className]} style={styleList({'--num-items': slots.length}, style)}>
|
|
28
|
+
<ul class:list={["subgrid", className]} style={styleList({'--num-items': slots.length}, style)}>
|
|
29
29
|
{slots.map((slot) => (
|
|
30
|
-
<li class:list={[
|
|
30
|
+
<li class:list={[getAttribute(slot, 'class')]} style={styleList(getAttribute(slot, 'style'))} set:html={slot.html}></li>
|
|
31
31
|
))}
|
|
32
|
-
</ul>
|
|
32
|
+
</ul>
|