@antadesign/anta 0.1.1-dev.0 → 0.1.1-dev.2

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.
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate-icons.mjs — read a folder of SVGs, emit a CSS file with one
4
+ * `a-icon[shape="…"]` rule per icon and a `.d.ts` file that augments
5
+ * Anta's `IconShapes` interface so the new shapes flow into `IconShape`.
6
+ *
7
+ * Run from CLI:
8
+ * node scripts/generate-icons.mjs --input <svg-folder> --output <out-folder> --name <basename>
9
+ *
10
+ * Or import programmatically:
11
+ * import { generate } from '@antadesign/anta/generate-icons.mjs'
12
+ * await generate({ input, output, name, builtInShapes })
13
+ *
14
+ * Defaults:
15
+ * --name = "a-icon.shapes"
16
+ * --output = "."
17
+ * --input is required
18
+ */
19
+
20
+ import fs from 'node:fs'
21
+ import path from 'node:path'
22
+ import { fileURLToPath } from 'node:url'
23
+
24
+ // SVGs whose names match these get a "collision" warning so consumers
25
+ // know they're shadowing a built-in. Anta passes its own list when
26
+ // generating its own shapes; for consumers, we include the canonical
27
+ // built-in names so generating a same-named shape is flagged.
28
+ const DEFAULT_BUILT_IN = [
29
+ 'chevron-down', 'chevron-up', 'chevron-left', 'chevron-right',
30
+ 'check', 'x', 'info', 'warning-triangle', 'plus', 'minus', 'menu', 'copy',
31
+ ]
32
+
33
+ function encodeSvg(svg) {
34
+ return svg
35
+ .replace(/"/g, "'")
36
+ .replace(/[\r\n%#()<>?[\\\]^`{|}]/g, encodeURIComponent)
37
+ }
38
+
39
+ // Removes `width=…` and `height=…` only from the root <svg> opening tag.
40
+ // Child elements (e.g. <rect width="14"…>) are intentionally untouched.
41
+ // Handles double-quoted, single-quoted, and unquoted attribute values.
42
+ function stripDimensions(svg) {
43
+ return svg.replace(/<svg\b[^>]*>/i, (m) =>
44
+ m.replace(/\s(?:width|height)\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/g, '')
45
+ )
46
+ }
47
+
48
+ export async function generate({ input, output = '.', name = 'a-icon.shapes', internal = false } = {}) {
49
+ if (!input) throw new Error('generate-icons: --input is required')
50
+ const inDir = path.resolve(input)
51
+ const outDir = path.resolve(output)
52
+ if (!fs.existsSync(inDir)) throw new Error(`generate-icons: input folder not found: ${inDir}`)
53
+ fs.mkdirSync(outDir, { recursive: true })
54
+
55
+ const files = fs.readdirSync(inDir).filter((f) => f.endsWith('.svg')).sort()
56
+ if (files.length === 0) {
57
+ console.warn(`generate-icons: no .svg files in ${inDir}`)
58
+ }
59
+
60
+ const shapes = []
61
+ const cssLines = ['/* Auto-generated by scripts/generate-icons.mjs. Do not edit by hand. */', '']
62
+ // Built-in collision detection is for consumer runs only. Anta's own
63
+ // build passes --internal so it doesn't warn about every one of its
64
+ // own shapes "colliding" with itself.
65
+ const builtInSet = internal ? new Set() : new Set(DEFAULT_BUILT_IN)
66
+ const collisions = []
67
+
68
+ for (const file of files) {
69
+ const shape = path.parse(file).name
70
+ if (shapes.includes(shape)) {
71
+ console.warn(`generate-icons: duplicate shape name "${shape}" — skipping`)
72
+ continue
73
+ }
74
+ if (builtInSet.has(shape)) collisions.push(shape)
75
+ const raw = fs.readFileSync(path.join(inDir, file), 'utf8')
76
+ const encoded = encodeSvg(stripDimensions(raw)).trim()
77
+ cssLines.push(`a-icon[shape="${shape}"] {`)
78
+ cssLines.push(` --icon: url("data:image/svg+xml,${encoded}");`)
79
+ cssLines.push('}')
80
+ cssLines.push('')
81
+ shapes.push(shape)
82
+ }
83
+
84
+ if (collisions.length > 0) {
85
+ console.warn(
86
+ `generate-icons: ${collisions.length} shape name(s) collide with Anta's built-in icons: ` +
87
+ `${collisions.join(', ')}. ` +
88
+ `The runtime CSS loaded last wins; import yours after \`@antadesign/anta/elements\` to override.`
89
+ )
90
+ }
91
+
92
+ // Optional synonyms — extra search keywords per shape. Read from
93
+ // `<input>/synonyms.json` if present; consumers/maintainers extend
94
+ // the list as their icon set grows. Format: { "shape-name": ["alt", "term"] }.
95
+ const synFile = path.join(inDir, 'synonyms.json')
96
+ /** @type {Record<string, string[]>} */
97
+ let synonyms = {}
98
+ if (fs.existsSync(synFile)) {
99
+ try {
100
+ const parsed = JSON.parse(fs.readFileSync(synFile, 'utf8'))
101
+ for (const [shape, list] of Object.entries(parsed)) {
102
+ if (!shapes.includes(shape)) {
103
+ console.warn(`generate-icons: synonyms.json references unknown shape "${shape}" — skipping`)
104
+ continue
105
+ }
106
+ if (!Array.isArray(list) || !list.every((v) => typeof v === 'string')) {
107
+ console.warn(`generate-icons: synonyms.json entry for "${shape}" is not a string array — skipping`)
108
+ continue
109
+ }
110
+ synonyms[shape] = list
111
+ }
112
+ } catch (e) {
113
+ console.warn(`generate-icons: failed to parse ${synFile}: ${e.message}`)
114
+ }
115
+ }
116
+
117
+ const cssPath = path.join(outDir, `${name}.css`)
118
+ const tsPath = path.join(outDir, `${name}.ts`)
119
+ fs.writeFileSync(cssPath, cssLines.join('\n'))
120
+
121
+ const synonymsEntries = Object.entries(synonyms)
122
+ const tsLines = [
123
+ '/* Auto-generated by scripts/generate-icons.mjs. Do not edit by hand. */',
124
+ '',
125
+ 'export const ICON_SHAPES = [',
126
+ ...shapes.map((s) => ` '${s}',`),
127
+ "] as const",
128
+ '',
129
+ 'export const ICON_SYNONYMS: Readonly<Record<string, readonly string[]>> = {',
130
+ ...synonymsEntries.map(([shape, list]) =>
131
+ ` '${shape}': [${list.map((v) => `'${v.replace(/'/g, "\\'")}'`).join(', ')}],`
132
+ ),
133
+ '}',
134
+ '',
135
+ "declare module '@antadesign/anta' {",
136
+ ' interface IconShapes {',
137
+ ...shapes.map((s) => ` '${s}': true`),
138
+ ' }',
139
+ '}',
140
+ '',
141
+ "export type IconShape = keyof import('@antadesign/anta').IconShapes",
142
+ '',
143
+ ]
144
+ fs.writeFileSync(tsPath, tsLines.join('\n'))
145
+
146
+ console.log(`generate-icons: wrote ${shapes.length} shape${shapes.length === 1 ? '' : 's'} to ${cssPath} and ${tsPath}`)
147
+ return { shapes, cssPath, tsPath }
148
+ }
149
+
150
+ function parseArgs(argv) {
151
+ const out = {}
152
+ for (let i = 0; i < argv.length; i++) {
153
+ const arg = argv[i]
154
+ if (arg.startsWith('--')) {
155
+ const key = arg.slice(2)
156
+ const next = argv[i + 1]
157
+ if (next && !next.startsWith('--')) {
158
+ out[key] = next
159
+ i++
160
+ } else {
161
+ out[key] = true
162
+ }
163
+ }
164
+ }
165
+ return out
166
+ }
167
+
168
+ const isMain = import.meta.url === `file://${process.argv[1]}` ||
169
+ import.meta.url === fileURLToPath(import.meta.url + '')
170
+ if (isMain || process.argv[1]?.endsWith('generate-icons.mjs')) {
171
+ const args = parseArgs(process.argv.slice(2))
172
+ generate({
173
+ input: args.input,
174
+ output: args.output,
175
+ name: args.name,
176
+ internal: args.internal === true,
177
+ }).catch((e) => {
178
+ console.error(e.message)
179
+ process.exit(1)
180
+ })
181
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,36 @@
1
+ /**
2
+ * @antadesign/anta — Antithesis Design System
3
+ *
4
+ * Portable UI components with web component internals and JSX wrappers.
5
+ * Works with React, Preact (via compat or `configure()`), or any custom JSX runtime.
6
+ *
7
+ * Import components from this entry point:
8
+ * ```ts
9
+ * import { Progress } from '@antadesign/anta'
10
+ * ```
11
+ *
12
+ * Register custom elements (client-side only):
13
+ * ```ts
14
+ * import '@antadesign/anta/elements'
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
1
19
  export { Progress } from './components/Progress';
20
+ export type { ProgressProps } from './components/Progress';
21
+ export { Text } from './components/Text';
22
+ export type { TextProps } from './components/Text';
23
+ export { Icon } from './components/Icon';
24
+ export type { IconProps } from './components/Icon';
25
+ export { ICON_SHAPES, ICON_SYNONYMS } from './elements/a-icon.shapes';
26
+ export type { BaseProps, BaseAttributes } from './general_types';
2
27
  export { configure } from './jsx-runtime';
28
+ /**
29
+ * Seed interface for the icon shape registry. The generated
30
+ * `a-icon.shapes.d.ts` augments this interface with one key per
31
+ * available shape; consumers can do the same with their own generated
32
+ * .d.ts files (TypeScript merges them by interface name).
33
+ */
34
+ export interface IconShapes {
35
+ }
36
+ export type IconShape = keyof IconShapes;
package/dist/index.js CHANGED
@@ -1,6 +1,13 @@
1
1
  import { Progress } from "./components/Progress";
2
+ import { Text } from "./components/Text";
3
+ import { Icon } from "./components/Icon";
4
+ import { ICON_SHAPES, ICON_SYNONYMS } from "./elements/a-icon.shapes";
2
5
  import { configure } from "./jsx-runtime";
3
6
  export {
7
+ ICON_SHAPES,
8
+ ICON_SYNONYMS,
9
+ Icon,
4
10
  Progress,
11
+ Text,
5
12
  configure
6
13
  };
@@ -4,11 +4,25 @@ type JsxFunction = {
4
4
  h(type: ComponentType, props: Record<string, unknown> | null, ...children: unknown[]): unknown;
5
5
  }['h'];
6
6
  declare let _Fragment: ComponentType;
7
+ /**
8
+ * Swap the underlying JSX factory used by all anta components.
9
+ *
10
+ * Not needed for React or Preact-with-compat — those work automatically.
11
+ * Call this before rendering any anta components when using Preact without
12
+ * compat aliasing, or a custom JSX runtime.
13
+ *
14
+ * @example Preact without compat
15
+ * ```ts
16
+ * import { configure } from '@antadesign/anta'
17
+ * import { h, Fragment } from 'preact'
18
+ * configure(h, Fragment)
19
+ * ```
20
+ */
7
21
  export declare function configure(jsx: JsxFunction, Fragment?: ComponentType): void;
8
22
  export declare function jsx(type: ComponentType, props: Record<string, unknown> | null, key?: string | number): unknown;
9
23
  export declare function jsxs(type: ComponentType, props: Record<string, unknown> | null, key?: string | number): unknown;
10
24
  export { _Fragment as Fragment };
11
- import type { AProgressAttributes, BaseAttributes } from './general_types';
25
+ import type { AProgressAttributes, ATextAttributes, AIconAttributes, BaseAttributes } from './general_types';
12
26
  export declare namespace JSX {
13
27
  type IntrinsicElements = React.JSX.IntrinsicElements & {
14
28
  'a-progress': AProgressAttributes;
@@ -16,5 +30,7 @@ export declare namespace JSX {
16
30
  'a-progress-number': BaseAttributes;
17
31
  'a-progress-text': BaseAttributes;
18
32
  'a-progress-hint': BaseAttributes;
33
+ 'a-text': ATextAttributes;
34
+ 'a-icon': AIconAttributes;
19
35
  };
20
36
  }
package/package.json CHANGED
@@ -1,29 +1,45 @@
1
1
  {
2
2
  "name": "@antadesign/anta",
3
- "version": "0.1.1-dev.0",
3
+ "version": "0.1.1-dev.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
- "files": ["dist"],
7
+ "files": [
8
+ "dist",
9
+ "NOTICES.md"
10
+ ],
11
+ "packageManager": "pnpm@8.13.1",
8
12
  "exports": {
9
13
  ".": {
10
14
  "types": "./dist/index.d.ts",
11
15
  "default": "./dist/index.js"
12
16
  },
17
+ "./jsx-runtime": {
18
+ "types": "./dist/jsx-runtime.d.ts",
19
+ "default": "./dist/jsx-runtime.js"
20
+ },
13
21
  "./elements": {
14
22
  "types": "./dist/elements/index.d.ts",
15
23
  "default": "./dist/elements/index.js"
16
24
  },
25
+ "./elements/*": {
26
+ "types": "./dist/elements/*.d.ts",
27
+ "default": "./dist/elements/*.js"
28
+ },
29
+ "./anta_global_tokens.css": "./dist/anta_global_tokens.css",
30
+ "./generate-icons.mjs": "./dist/generate-icons.mjs",
17
31
  "./*": {
18
32
  "types": "./dist/*.d.ts",
19
33
  "default": "./dist/*"
20
34
  }
21
35
  },
22
36
  "scripts": {
23
- "build": "pnpm run build:js && pnpm run build:types",
24
- "build:js": "esbuild src/components/Progress.tsx src/index.ts src/jsx-runtime.ts src/general_types.ts src/anta_helpers.ts src/elements/index.ts src/elements/a-progress.ts --outdir=dist --outbase=src --jsx=automatic --jsx-import-source=@antadesign/anta --format=esm --target=ES2022 --loader:.module.css=local-css --loader:.css=global-css",
37
+ "build": "pnpm run build:js && pnpm run build:css && pnpm run build:types",
38
+ "build:css": "cp src/elements/a-progress.css src/elements/a-text.css src/elements/a-icon.css src/elements/a-icon.shapes.css dist/elements/ && cp src/components/Progress.module.css src/components/Text.module.css dist/components/ && cp src/anta_global_tokens.css dist/ && cp scripts/generate-icons.mjs dist/",
39
+ "build:js": "esbuild src/components/Progress.tsx src/components/Text.tsx src/components/Icon.tsx src/index.ts src/jsx-runtime.ts src/general_types.ts src/anta_helpers.ts src/elements/index.ts src/elements/a-progress.ts src/elements/a-text.ts src/elements/a-icon.ts src/elements/a-icon.shapes.ts --outdir=dist --outbase=src --jsx=automatic --jsx-import-source=@antadesign/anta --format=esm --target=ES2022 --loader:.module.css=local-css --loader:.css=global-css",
25
40
  "build:types": "tsc -p src/tsconfig.json",
26
41
  "typecheck": "tsc --noEmit -p src/tsconfig.json",
42
+ "icons": "node scripts/generate-icons.mjs --input src/elements/icons --output src/elements --name a-icon.shapes --internal",
27
43
  "clean": "rm -rf dist"
28
44
  },
29
45
  "devDependencies": {