@qds.dev/tools 0.9.1 → 0.10.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/README.md CHANGED
@@ -26,13 +26,11 @@ npm install @qds.dev/tools
26
26
 
27
27
  ```typescript
28
28
  // vite.config.ts
29
- import { icons } from '@qds.dev/tools/vite';
30
- import { defineConfig } from 'vite';
29
+ import { icons } from "@qds.dev/tools/vite";
30
+ import { defineConfig } from "vite";
31
31
 
32
32
  export default defineConfig({
33
- plugins: [
34
- icons()
35
- ]
33
+ plugins: [icons()]
36
34
  });
37
35
  ```
38
36
 
@@ -40,14 +38,11 @@ export default defineConfig({
40
38
 
41
39
  ```typescript
42
40
  // rolldown.config.ts
43
- import { icons, asChild } from '@qds.dev/tools/vite';
44
- import { defineConfig } from 'rolldown';
41
+ import { icons, asChild } from "@qds.dev/tools/vite";
42
+ import { defineConfig } from "rolldown";
45
43
 
46
44
  export default defineConfig({
47
- plugins: [
48
- icons(),
49
- asChild(),
50
- ]
45
+ plugins: [icons(), asChild()]
51
46
  });
52
47
  ```
53
48
 
@@ -59,11 +54,11 @@ When you edit a QDS component, several build plugins transform your code before
59
54
 
60
55
  ### Quick Reference
61
56
 
62
- | Pattern You See | Plugin | What Happens |
63
- |-----------------|--------|--------------|
64
- | `<Lucide.Check />`, `<Heroicons.Star />` | Icons | Becomes inline `<svg>` at build time |
65
- | `<Button asChild><a href="...">` | AsChild | Child props hoisted to parent |
66
- | `component$()` | Qwik Optimizer | Not in @qds.dev/tools (built into Qwik) |
57
+ | Pattern You See | Plugin | What Happens |
58
+ | ---------------------------------------- | -------------- | --------------------------------------- |
59
+ | `<Lucide.Check />`, `<Heroicons.Star />` | Icons | Becomes inline `<svg>` at build time |
60
+ | `<Button asChild><a href="...">` | AsChild | Child props hoisted to parent |
61
+ | `component$()` | Qwik Optimizer | Not in @qds.dev/tools (built into Qwik) |
67
62
 
68
63
  ### When to Read More
69
64
 
@@ -89,12 +84,17 @@ File changed: libs/components/checkbox/checkbox-indicator.tsx
89
84
  ```tsx
90
85
  // Your code:
91
86
  import { Lucide } from "@qds.dev/ui";
92
- <Lucide.Check width={20} class="text-green-500" />
87
+ <Lucide.Check width={20} class="text-green-500" />;
93
88
 
94
89
  // After icons plugin:
95
- import __qds_i_lucide_check from 'virtual:icons/lucide/check';
96
- <svg width={20} class="text-green-500" height="1em" viewBox="0 0 24 24"
97
- dangerouslySetInnerHTML={__qds_i_lucide_check} />
90
+ import __qds_i_lucide_check from "virtual:icons/lucide/check";
91
+ <svg
92
+ width={20}
93
+ class="text-green-500"
94
+ height="1em"
95
+ viewBox="0 0 24 24"
96
+ dangerouslySetInnerHTML={__qds_i_lucide_check}
97
+ />;
98
98
  ```
99
99
 
100
100
  **Why this matters:** The icon component you write doesn't exist at runtime. It's replaced with an actual `<svg>` element. If you're debugging icon issues, check the transformed output in browser devtools.
@@ -127,13 +127,13 @@ What you wrote is NOT what runs in the browser. The transformations above happen
127
127
 
128
128
  ### Common Debugging Scenarios
129
129
 
130
- | Issue | Likely Cause | Solution |
131
- |-------|--------------|----------|
132
- | Icon doesn't render | Icon name not in collection | Check [Iconify](https://icon-sets.iconify.design/) for valid names |
133
- | Icon has wrong viewBox | Icon collection uses different dimensions | Specify explicit `viewBox` prop |
134
- | asChild throws error | More than one child element | Ensure exactly one JSX child (whitespace is ignored) |
135
- | asChild props missing | Props not on direct child | Move props to the immediate child element |
136
- | Build error: "asChild elements must have exactly one child" | Multiple children or JSX expression | Use single element child, not `{condition && <el>}` patterns |
130
+ | Issue | Likely Cause | Solution |
131
+ | ----------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------ |
132
+ | Icon doesn't render | Icon name not in collection | Check [Iconify](https://icon-sets.iconify.design/) for valid names |
133
+ | Icon has wrong viewBox | Icon collection uses different dimensions | Specify explicit `viewBox` prop |
134
+ | asChild throws error | More than one child element | Ensure exactly one JSX child (whitespace is ignored) |
135
+ | asChild props missing | Props not on direct child | Move props to the immediate child element |
136
+ | Build error: "asChild elements must have exactly one child" | Multiple children or JSX expression | Use single element child, not `{condition && <el>}` patterns |
137
137
 
138
138
  ## How Plugins Transform Your Code
139
139
 
@@ -144,6 +144,7 @@ All transformations happen at build time. Your source code uses clean JSX patter
144
144
  Transforms icon JSX elements (`<Lucide.Check />`) into inline SVG at build time with virtual imports.
145
145
 
146
146
  **Before transformation (your code):**
147
+
147
148
  ```typescript
148
149
  import { Lucide } from "@qds.dev/ui";
149
150
 
@@ -153,6 +154,7 @@ export default component$(() => {
153
154
  ```
154
155
 
155
156
  **After transformation (build output):**
157
+
156
158
  ```typescript
157
159
  import __qds_i_lucide_check from 'virtual:icons/lucide/check';
158
160
 
@@ -162,6 +164,7 @@ export default component$(() => {
162
164
  ```
163
165
 
164
166
  **What this does:**
167
+
165
168
  - Transforms icon JSX into inline SVG elements
166
169
  - Generates virtual imports for icon data
167
170
  - Adds default dimensions (1em) if not specified
@@ -173,9 +176,10 @@ export default component$(() => {
173
176
  Hoists child element props to parent component when using asChild pattern for polymorphic rendering.
174
177
 
175
178
  **Before transformation (your code):**
179
+
176
180
  ```typescript
177
181
  export const Link = component$(() => {
178
- // Gives styles of button, but renders as the link child.
182
+ // Gives styles of button, but renders as the link child.
179
183
  // Useful when sharing styles OR existing logic inside of button that needs to be shared.
180
184
  return (
181
185
  <Button asChild>
@@ -186,6 +190,7 @@ export const Link = component$(() => {
186
190
  ```
187
191
 
188
192
  **After transformation (build output):**
193
+
189
194
  ```typescript
190
195
  export const Link = component$(() => {
191
196
  return (
@@ -197,6 +202,7 @@ export const Link = component$(() => {
197
202
  ```
198
203
 
199
204
  **What this does:**
205
+
200
206
  - Removes child element wrapper
201
207
  - Hoists child props to `movedProps` object
202
208
  - Adds `jsxType` to identify element type
@@ -205,20 +211,22 @@ export const Link = component$(() => {
205
211
 
206
212
  ## API
207
213
 
208
- | Export | Description |
209
- |--------|-------------|
210
- | Main export (`@qds.dev/tools`) | Core type utilities (AsChildTypes) |
211
- | `/vite` | Mostly re-exported from rolldown to stay modular: `icons`, `asChild`, `inlineAsset`, `minifyContentPlugin` |
212
- | `/rolldown` | Rolldown plugins: `icons`, `asChild`, `inlineAsset`, `inlineCssPlugin`, `qwikRolldown` |
213
- | `/playground` | Prop extraction and scenario injection plugins for component playgrounds |
214
- | `/utils` | General utility functions for code transformation |
214
+ | Export | Description |
215
+ | ------------------------------ | ---------------------------------------------------------------------------------------------------------- |
216
+ | Main export (`@qds.dev/tools`) | Core type utilities (AsChildTypes) |
217
+ | `/vite` | Mostly re-exported from rolldown to stay modular: `icons`, `asChild`, `inlineAsset`, `minifyContentPlugin` |
218
+ | `/rolldown` | Rolldown plugins: `icons`, `asChild`, `inlineAsset`, `inlineCssPlugin`, `qwikRolldown` |
219
+ | `/playground` | Prop extraction and scenario injection plugins for component playgrounds |
220
+ | `/utils` | General utility functions for code transformation |
215
221
 
216
222
  **Key plugins:**
217
223
 
218
224
  ### `icons(options?)`
225
+
219
226
  Transforms icon JSX elements into inline SVG with virtual imports.
220
227
 
221
228
  **Options:**
229
+
222
230
  - `packs?: Record<string, { iconifyPrefix: string }>` - Custom icon pack configuration
223
231
  - `importSources?: string[]` - Additional import sources to scan (default: `["@qds.dev/ui"]`)
224
232
  - `debug?: boolean` - Enable debug logging
@@ -226,24 +234,29 @@ Transforms icon JSX elements into inline SVG with virtual imports.
226
234
  **Default icon packs:** Lucide, Heroicons, Tabler, Hugeicons, MaterialSymbols, AkarIcons
227
235
 
228
236
  ### `asChild(options?)`
237
+
229
238
  Hoists child element props to parent component for polymorphic rendering.
230
239
 
231
240
  **Options:**
241
+
232
242
  - `debug?: boolean` - Enable debug logging
233
243
 
234
244
  **Use case:** Implement polymorphic "as" pattern where components can render as different elements while preserving parent component logic.
235
245
 
236
246
  ### `playground(options)`
247
+
237
248
  Factory function returning two plugins for interactive component playgrounds.
238
249
 
239
250
  **Returns:** `[propExtraction(options), scenarioInjection()]`
240
251
 
241
252
  **Options:**
253
+
242
254
  - `componentsDir: string` - Directory containing component files
243
255
  - `outputDir: string` - Directory for generated metadata JSON
244
256
  - `debug?: boolean` - Enable debug logging
245
257
 
246
258
  **What it does:**
259
+
247
260
  - Extracts TypeScript prop types from component files → JSON metadata
248
261
  - Injects scenario imports into MDX playground files
249
262
  - Enables interactive component demos with prop controls
@@ -256,14 +269,14 @@ The `/playground` export provides specialized plugins for building interactive c
256
269
 
257
270
  ```typescript
258
271
  // vite.config.ts
259
- import { playground } from '@qds.dev/tools/playground';
260
- import { defineConfig } from 'vite';
272
+ import { playground } from "@qds.dev/tools/playground";
273
+ import { defineConfig } from "vite";
261
274
 
262
275
  export default defineConfig({
263
276
  plugins: [
264
277
  playground({
265
- componentsDir: 'libs/components/src',
266
- outputDir: '.playground-metadata'
278
+ componentsDir: "libs/components/src",
279
+ outputDir: ".playground-metadata"
267
280
  })
268
281
  ]
269
282
  });
@@ -274,12 +287,14 @@ export default defineConfig({
274
287
  Extracts TypeScript prop types from component files and generates JSON metadata.
275
288
 
276
289
  **Process:**
290
+
277
291
  1. Reads component `.tsx` files from `componentsDir`
278
292
  2. Parses TypeScript prop interfaces and types
279
293
  3. Extracts JSDoc comments for prop descriptions
280
294
  4. Generates JSON files in `outputDir`
281
295
 
282
296
  **Output type:**
297
+
283
298
  ```typescript
284
299
  interface ComponentMetadata {
285
300
  componentName: string;
@@ -305,6 +320,7 @@ interface PropType {
305
320
  Transforms MDX files containing `<Playground />` components by auto-injecting scenario imports.
306
321
 
307
322
  **Process:**
323
+
308
324
  1. Scans for `<Playground />` in MDX files
309
325
  2. Looks for adjacent `scenarios/` directory
310
326
  3. Auto-imports scenario components and source code
@@ -313,6 +329,7 @@ Transforms MDX files containing `<Playground />` components by auto-injecting sc
313
329
  **Example MDX transformation:**
314
330
 
315
331
  Before:
332
+
316
333
  ```mdx
317
334
  # Button Component
318
335
 
@@ -320,15 +337,14 @@ Before:
320
337
  ```
321
338
 
322
339
  After (build time):
340
+
323
341
  ```mdx
324
- import * as Scenario1 from './scenarios/basic.tsx';
325
- import Scenario1Code from './scenarios/basic.tsx?raw';
342
+ import * as Scenario1 from "./scenarios/basic.tsx";
343
+ import Scenario1Code from "./scenarios/basic.tsx?raw";
326
344
 
327
345
  <Playground
328
346
  component={Button}
329
- scenarios={[
330
- { component: Scenario1, code: Scenario1Code }
331
- ]}
347
+ scenarios={[{ component: Scenario1, code: Scenario1Code }]}
332
348
  />
333
349
  ```
334
350
 
@@ -347,14 +363,17 @@ For package internals, dependency relationships, and design decisions, see [ARCH
347
363
  ## Related Packages
348
364
 
349
365
  **Used by:**
366
+
350
367
  - [`create-qds`](https://www.npmjs.com/package/create-qds) - CLI that scaffolds projects with these tools preconfigured
351
368
  - All QDS packages - Internal build tooling for @qds.dev/ui, @qds.dev/motion, @qds.dev/code
352
369
 
353
370
  **Complements:**
371
+
354
372
  - [@qds.dev/ui](https://www.npmjs.com/package/@qds.dev/ui) - Uses these build tools for icon transformations
355
373
  - [@qds.dev/base](https://www.npmjs.com/package/@qds.dev/base) - Uses these build tools for component patterns
356
374
 
357
375
  **Build dependencies:**
376
+
358
377
  - `vite` - Vite plugin compatibility
359
378
  - `rolldown` - Rolldown plugin compatibility
360
379
  - `oxc-*` - Fast JavaScript/TypeScript parsing and transformation
@@ -36,9 +36,9 @@ const scenarioInjection = () => {
36
36
  if ((mdxNode.type === "mdxJsxFlowElement" || mdxNode.type === "mdxJsxTextElement") && mdxNode.name === "Playground") {
37
37
  if (mdxNode.position?.start?.offset !== void 0 && mdxNode.position?.end?.offset !== void 0) {
38
38
  if (!mdxNode.attributes.some((attr) => attr.name === "scenarios")) {
39
- const scenariosArrayString = `[${scenarioFiles.map((s$1) => `{name: "${s$1.name}", component: ${s$1.componentVar}, source: ${s$1.sourceVar}}`).join(", ")}]`;
40
- const insertPos$1 = mdxNode.position.start.offset + 11;
41
- s.appendLeft(insertPos$1, ` scenarios={${scenariosArrayString}}`);
39
+ const scenariosArrayString = `[${scenarioFiles.map((s) => `{name: "${s.name}", component: ${s.componentVar}, source: ${s.sourceVar}}`).join(", ")}]`;
40
+ const insertPos = mdxNode.position.start.offset + 11;
41
+ s.appendLeft(insertPos, ` scenarios={${scenariosArrayString}}`);
42
42
  hasPlayground = true;
43
43
  }
44
44
  }
@@ -56,7 +56,7 @@ import { walk } from "oxc-walker";
56
56
  * @param s - MagicString instance for code transformation
57
57
  * @param source - Original source code
58
58
  */ function processAsChild(elem, s, source) {
59
- const children = elem.children.filter((child$1) => !isJSXText(child$1) || child$1.value.trim() !== "");
59
+ const children = elem.children.filter((child) => !isJSXText(child) || child.value.trim() !== "");
60
60
  if (children.length === 0) return;
61
61
  if (children.length > 1) throw new Error(`asChild elements must have exactly one child at ${elem.start}`);
62
62
  const child = children[0];
@@ -42,7 +42,7 @@ const nodeRequire = createRequire(import.meta.url);
42
42
  resolveId: {
43
43
  order: "pre",
44
44
  filter: { id: combinedQuery },
45
- async handler(id, importer, options$1) {
45
+ async handler(id, importer, options) {
46
46
  const isInlineAsset = inlineAssetQuery.test(id);
47
47
  const isNoTransform = noTransformQuery.test(id);
48
48
  if (!isInlineAsset && !isNoTransform) return;
@@ -57,7 +57,7 @@ const nodeRequire = createRequire(import.meta.url);
57
57
  let resolvedPath = null;
58
58
  try {
59
59
  const resolved = await this.resolve(basePath, importer, {
60
- ...options$1,
60
+ ...options,
61
61
  skipSelf: true
62
62
  });
63
63
  if (resolved) resolvedPath = resolved.id.split("?")[0];
@@ -75,8 +75,8 @@ const nodeRequire = createRequire(import.meta.url);
75
75
  }
76
76
  const subpath = parts.slice(subpathStartIndex).join("/");
77
77
  try {
78
- const basePath$1 = importer ? dirname(importer) : process.cwd();
79
- resolvedPath = join(dirname(nodeRequire.resolve(`${packageName}/package.json`, { paths: [basePath$1] })), subpath);
78
+ const basePath = importer ? dirname(importer) : process.cwd();
79
+ resolvedPath = join(dirname(nodeRequire.resolve(`${packageName}/package.json`, { paths: [basePath] })), subpath);
80
80
  debugInlineAsset("Manually resolved package import:", resolvedPath);
81
81
  } catch (err) {
82
82
  debugInlineAsset("Failed to manually resolve:", err);
@@ -15,9 +15,9 @@ import { transform } from "oxc-transform";
15
15
  const partString = `.${options?.part || "script"}.`;
16
16
  const scriptExtension = createRegExp(exactly(partString).and(oneOrMore(char)).at.lineEnd());
17
17
  const processMap = async (id, code) => {
18
- const basename$1 = id.split(sep).join("/").split("/").pop() || "";
19
- if (!scriptExtension.test(basename$1)) return false;
20
- const [name] = basename$1.split(partString);
18
+ const basename = id.split(sep).join("/").split("/").pop() || "";
19
+ if (!scriptExtension.test(basename)) return false;
20
+ const [name] = basename.split(partString);
21
21
  if (!name) return false;
22
22
  try {
23
23
  scriptsMap[name] = minifySync(id, (await transform(id, code, { typescript: { onlyRemoveTypeImports: false } })).code, {
package/package.json CHANGED
@@ -1,63 +1,67 @@
1
1
  {
2
2
  "name": "@qds.dev/tools",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "private": false,
5
5
  "description": "Tools and utilities for Qwik Design System",
6
- "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/kunai-consulting/qwik-design-system"
9
+ },
7
10
  "files": [
8
11
  "lib",
9
12
  "lib-types"
10
13
  ],
14
+ "type": "module",
15
+ "sideEffects": false,
11
16
  "main": "./lib/src/index.qwik.mjs",
12
- "qwik": "./lib/src/index.qwik.mjs",
13
17
  "types": "./lib-types/tools/src/index.d.ts",
14
18
  "exports": {
15
19
  ".": {
16
- "import": "./lib/src/index.qwik.mjs",
17
- "types": "./lib-types/tools/src/index.d.ts"
20
+ "types": "./lib-types/tools/src/index.d.ts",
21
+ "import": "./lib/src/index.qwik.mjs"
18
22
  },
19
23
  "./package.json": "./package.json",
20
24
  "./vite": {
21
- "import": "./lib/vite/index.qwik.mjs",
22
- "types": "./lib-types/tools/vite/index.d.ts"
25
+ "types": "./lib-types/tools/vite/index.d.ts",
26
+ "import": "./lib/vite/index.qwik.mjs"
23
27
  },
24
28
  "./utils": {
25
- "import": "./lib/utils/index.qwik.mjs",
26
- "types": "./lib-types/tools/utils/index.d.ts"
29
+ "types": "./lib-types/tools/utils/index.d.ts",
30
+ "import": "./lib/utils/index.qwik.mjs"
27
31
  },
28
32
  "./rolldown": {
29
- "import": "./lib/rolldown/index.qwik.mjs",
30
- "types": "./lib-types/tools/rolldown/index.d.ts"
33
+ "types": "./lib-types/tools/rolldown/index.d.ts",
34
+ "import": "./lib/rolldown/index.qwik.mjs"
31
35
  },
32
36
  "./playground": {
33
- "import": "./lib/playground/index.qwik.mjs",
34
- "types": "./lib-types/tools/playground/index.d.ts"
37
+ "types": "./lib-types/tools/playground/index.d.ts",
38
+ "import": "./lib/playground/index.qwik.mjs"
35
39
  }
36
40
  },
37
- "devDependencies": {
38
- "@iconify/types": "^2",
39
- "magic-string": "^0.30.17",
40
- "rolldown": "1.0.0-beta.45",
41
- "typescript": "5.4.5",
42
- "vite": "^7.3.1"
41
+ "scripts": {
42
+ "build": "pnpm run build.lib & pnpm run build.types && pnpm generate.icon.types",
43
+ "build.lib": "rolldown -c rolldown.config.ts",
44
+ "build.types": "tsc --emitDeclarationOnly --outDir ./lib-types",
45
+ "generate.icon.types": "node src/generate/icon-types.ts"
43
46
  },
44
47
  "dependencies": {
45
48
  "@iconify/json": "^2.2.382",
46
49
  "@iconify/utils": "^3.0.1",
47
- "@oxc-project/types": "^0.102.0",
50
+ "@oxc-project/types": "^0.111.0",
48
51
  "magic-regexp": "^0.10.0",
49
- "oxc-minify": "^0.102.0",
50
- "oxc-parser": "^0.102.0",
51
- "oxc-transform": "^0.102.0",
52
+ "oxc-minify": "^0.111.0",
53
+ "oxc-parser": "^0.111.0",
54
+ "oxc-transform": "^0.111.0",
52
55
  "oxc-walker": "^0.5.2",
53
56
  "remark": "^15.0.1",
54
57
  "remark-mdx": "^3.1.1"
55
58
  },
56
- "sideEffects": false,
57
- "scripts": {
58
- "build": "pnpm run build.lib & pnpm run build.types && pnpm generate.icon.types",
59
- "build.lib": "rolldown -c rolldown.config.ts",
60
- "build.types": "tsc --emitDeclarationOnly --outDir ./lib-types",
61
- "generate.icon.types": "node src/generate/icon-types.ts"
62
- }
63
- }
59
+ "devDependencies": {
60
+ "@iconify/types": "^2",
61
+ "magic-string": "^0.30.17",
62
+ "rolldown": "1.0.0-rc.4",
63
+ "typescript": "5.4.5",
64
+ "vite": "^7.3.1"
65
+ },
66
+ "qwik": "./lib/src/index.qwik.mjs"
67
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Kunai Consulting
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.