@tamagui/cli 2.7.7 → 3.0.0-0.canary.1791057742817

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/add.cjs +76 -87
  2. package/dist/build.cjs +421 -278
  3. package/dist/cli.cjs +410 -340
  4. package/dist/generate-prompt.cjs +37 -386
  5. package/dist/generate.cjs +45 -54
  6. package/dist/icons.cjs +263 -0
  7. package/dist/index.cjs +1 -1
  8. package/dist/migrate.cjs +443 -0
  9. package/dist/preview-theme.cjs +70 -0
  10. package/dist/setup-prompt.cjs +216 -0
  11. package/dist/to-tailwind-default-config.cjs +874 -0
  12. package/dist/to-tailwind.cjs +213 -0
  13. package/dist/update-template.cjs +43 -52
  14. package/dist/update.cjs +14 -18
  15. package/dist/upgrade.cjs +417 -401
  16. package/dist/utils.cjs +84 -101
  17. package/metro.cjs +1 -0
  18. package/metro.d.ts +1 -0
  19. package/metro.mjs +1 -0
  20. package/package.json +45 -14
  21. package/src/build.ts +579 -361
  22. package/src/cli.ts +171 -24
  23. package/src/generate-prompt.ts +18 -526
  24. package/src/icons.ts +308 -0
  25. package/src/migrate.ts +428 -0
  26. package/src/preview-theme.ts +54 -0
  27. package/src/setup-prompt.ts +192 -0
  28. package/src/to-tailwind-default-config.ts +852 -0
  29. package/src/to-tailwind.ts +313 -0
  30. package/src/upgrade.ts +30 -33
  31. package/src/utils.ts +11 -9
  32. package/types/add.d.ts +1 -1
  33. package/types/add.d.ts.map +1 -1
  34. package/types/build.d.ts +2 -1
  35. package/types/build.d.ts.map +1 -1
  36. package/types/generate-prompt.d.ts +2 -2
  37. package/types/generate-prompt.d.ts.map +1 -1
  38. package/types/icons.d.ts +14 -0
  39. package/types/icons.d.ts.map +1 -0
  40. package/types/migrate.d.ts +7 -0
  41. package/types/migrate.d.ts.map +1 -0
  42. package/types/preview-theme.d.ts +8 -0
  43. package/types/preview-theme.d.ts.map +1 -0
  44. package/types/setup-prompt.d.ts +5 -0
  45. package/types/setup-prompt.d.ts.map +1 -0
  46. package/types/to-tailwind-default-config.d.ts +53 -0
  47. package/types/to-tailwind-default-config.d.ts.map +1 -0
  48. package/types/to-tailwind.d.ts +16 -0
  49. package/types/to-tailwind.d.ts.map +1 -0
  50. package/types/upgrade.d.ts.map +1 -1
  51. package/types/utils.d.ts.map +1 -1
  52. package/vite.cjs +1 -0
  53. package/vite.d.ts +1 -0
  54. package/vite.mjs +1 -0
package/dist/icons.cjs ADDED
@@ -0,0 +1,263 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: () => from[key],
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var icons_exports = {};
28
+ __export(icons_exports, {
29
+ HEROICONS_VERSION: () => HEROICONS_VERSION,
30
+ LUCIDE_VERSION: () => LUCIDE_VERSION,
31
+ PHOSPHOR_VERSION: () => PHOSPHOR_VERSION,
32
+ addIcons: () => addIcons,
33
+ svgToComponent: () => svgToComponent
34
+ });
35
+ module.exports = __toCommonJS(icons_exports);
36
+ var import_node_fs = require("node:fs");
37
+ var import_promises = require("node:fs/promises");
38
+ var import_node_path = __toESM(require("node:path"));
39
+ var import_chalk = __toESM(require("chalk"));
40
+ const LUCIDE_VERSION = "1.49.0";
41
+ const HEROICONS_VERSION = "2.2.0";
42
+ const PHOSPHOR_VERSION = "2.1.1";
43
+ const libraries = [
44
+ "lucide",
45
+ "heroicons",
46
+ "phosphor"
47
+ ];
48
+ const phosphorWeights = [
49
+ "regular",
50
+ "bold",
51
+ "duotone",
52
+ "fill",
53
+ "light",
54
+ "thin"
55
+ ];
56
+ const heroiconsDirs = {
57
+ outline: "24/outline",
58
+ solid: "24/solid",
59
+ mini: "20/solid",
60
+ micro: "16/solid"
61
+ };
62
+ async function addIcons(options) {
63
+ const cwd = options.cwd ?? process.cwd();
64
+ const from = options.from ?? "lucide";
65
+ const outDir = import_node_path.default.resolve(cwd, options.out ?? "components/icons");
66
+ const localDir = libraries.includes(from) ? null : import_node_path.default.resolve(cwd, from);
67
+ if (localDir && !((0, import_node_fs.existsSync)(localDir) && (0, import_node_fs.statSync)(localDir).isDirectory())) {
68
+ throw new Error(`--from must be ${libraries.join(", ")}, or a directory of svg files (got "${from}")`);
69
+ }
70
+ if (!options.names.length) {
71
+ throw new Error("give the icons to add, e.g. `tamagui icons add Search ChevronDown`");
72
+ }
73
+ if (options.weight && from !== "phosphor") {
74
+ throw new Error("--weight applies to phosphor only");
75
+ }
76
+ if (options.weight && !phosphorWeights.includes(options.weight)) {
77
+ throw new Error(`--weight is one of ${phosphorWeights.join(", ")}`);
78
+ }
79
+ if (options.variant && from !== "heroicons") {
80
+ throw new Error("--variant applies to heroicons only");
81
+ }
82
+ if (options.variant && !heroiconsDirs[options.variant]) {
83
+ throw new Error(`--variant is one of ${Object.keys(heroiconsDirs).join(", ")}`);
84
+ }
85
+ const icons = [...new Set(options.names)].map((arg) => {
86
+ const [name, source = name] = arg.split("=");
87
+ const isKebab = (x) => /^[a-z0-9-]+$/.test(x);
88
+ const isPascal = (x) => /^[A-Z][A-Za-z0-9]*$/.test(x);
89
+ if (!(isKebab(name) || isPascal(name)) || !(isKebab(source) || isPascal(source)) || source !== name && !isPascal(name)) {
90
+ throw new Error(`icon names are PascalCase, kebab-case, or Name=source-name, got "${arg}"`);
91
+ }
92
+ return {
93
+ componentName: isKebab(name) ? kebabToPascal(name) : name,
94
+ file: isKebab(source) ? source : pascalToKebab(stripIconSuffix(source))
95
+ };
96
+ });
97
+ const loaded = await Promise.all(icons.map(async (icon) => {
98
+ if (localDir) {
99
+ const file = import_node_path.default.join(localDir, `${icon.file}.svg`);
100
+ return {
101
+ ...icon,
102
+ svg: (0, import_node_fs.existsSync)(file) ? await (0, import_promises.readFile)(file, "utf-8") : null
103
+ };
104
+ }
105
+ const url = sourceUrl(from, icon.file, options);
106
+ const response = await fetch(url);
107
+ if (response.status === 404) return {
108
+ ...icon,
109
+ svg: null
110
+ };
111
+ if (!response.ok) {
112
+ throw new Error(`fetching ${url} failed (${response.status})`);
113
+ }
114
+ return {
115
+ ...icon,
116
+ svg: await response.text()
117
+ };
118
+ }));
119
+ const unknown = loaded.filter((icon) => icon.svg === null);
120
+ if (unknown.length) {
121
+ throw new Error(`unknown ${from} icon${unknown.length === 1 ? "" : "s"}: ${unknown.map((icon) => `${icon.componentName} (${icon.file}.svg)`).join(", ")}`);
122
+ }
123
+ await (0, import_promises.mkdir)(outDir, { recursive: true });
124
+ for (const icon of loaded) {
125
+ const file = import_node_path.default.join(outDir, `${icon.componentName}.tsx`);
126
+ await (0, import_promises.writeFile)(file, svgToComponent(icon.componentName, icon.svg));
127
+ console.info(`${import_chalk.default.green("wrote")} ${import_node_path.default.relative(cwd, file)}`);
128
+ }
129
+ const components = (await (0, import_promises.readdir)(outDir)).filter((file) => file.endsWith(".tsx")).map((file) => file.slice(0, -".tsx".length)).sort();
130
+ await (0, import_promises.writeFile)(import_node_path.default.join(outDir, "index.ts"), components.map((name) => `export { ${name} } from './${name}'`).join("\n") + "\n");
131
+ console.info(`${import_chalk.default.green("wrote")} ${import_node_path.default.relative(cwd, import_node_path.default.join(outDir, "index.ts"))} (${components.length} icons)`);
132
+ }
133
+ function sourceUrl(library, file, options) {
134
+ switch (library) {
135
+ case "lucide": return `https://unpkg.com/lucide-static@${LUCIDE_VERSION}/icons/${file}.svg`;
136
+ case "heroicons": return `https://unpkg.com/heroicons@${HEROICONS_VERSION}/${heroiconsDirs[options.variant ?? "outline"]}/${file}.svg`;
137
+ case "phosphor": {
138
+ const weight = options.weight ?? "regular";
139
+ const name = weight === "regular" ? file : `${file}-${weight}`;
140
+ return `https://unpkg.com/@phosphor-icons/core@${PHOSPHOR_VERSION}/assets/${weight}/${name}.svg`;
141
+ }
142
+ }
143
+ }
144
+ function pascalToKebab(name) {
145
+ return name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Za-z])(\d)/g, "$1-$2").toLowerCase();
146
+ }
147
+ function kebabToPascal(name) {
148
+ return name.split("-").map((part) => part ? part[0].toUpperCase() + part.slice(1) : part).join("");
149
+ }
150
+ function stripIconSuffix(name) {
151
+ return name.endsWith("Icon") && name.length > 4 ? name.slice(0, -4) : name;
152
+ }
153
+ function parseSvg(svg) {
154
+ const root = {
155
+ tag: "",
156
+ attrs: [],
157
+ children: []
158
+ };
159
+ const stack = [root];
160
+ const tagPattern = /<(\/?)([A-Za-z][A-Za-z0-9]*)((?:"[^"]*"|'[^']*'|[^>"'])*?)(\/?)>/g;
161
+ for (const [, closing, tag, attrText, selfClose] of svg.replace(/<!--[\s\S]*?-->/g, "").matchAll(tagPattern)) {
162
+ if (closing) {
163
+ if (stack.pop()?.tag !== tag) throw new Error(`mismatched </${tag}> in svg`);
164
+ continue;
165
+ }
166
+ const node = {
167
+ tag,
168
+ attrs: [],
169
+ children: []
170
+ };
171
+ for (const [, name, double, single] of attrText.matchAll(/([A-Za-z_:][A-Za-z0-9_.:-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g)) {
172
+ node.attrs.push([name, double ?? single]);
173
+ }
174
+ stack[stack.length - 1].children.push(node);
175
+ if (!selfClose) stack.push(node);
176
+ }
177
+ const svgNode = root.children.find((node) => node.tag === "svg");
178
+ if (stack.length !== 1 || !svgNode) throw new Error("svg source has no complete <svg> root");
179
+ return svgNode;
180
+ }
181
+ const elements = {
182
+ path: "Path",
183
+ circle: "Circle",
184
+ ellipse: "Ellipse",
185
+ line: "Line",
186
+ polyline: "Polyline",
187
+ polygon: "Polygon",
188
+ rect: "Rect",
189
+ g: "G",
190
+ defs: "Defs",
191
+ clipPath: "ClipPath",
192
+ linearGradient: "LinearGradient",
193
+ radialGradient: "RadialGradient",
194
+ stop: "Stop",
195
+ use: "Use"
196
+ };
197
+ const restrictedNames = [
198
+ "Infinity",
199
+ "NaN",
200
+ "undefined"
201
+ ];
202
+ function svgToComponent(name, svg) {
203
+ const root = parseSvg(svg);
204
+ const used = /* @__PURE__ */ new Set();
205
+ const ref = (element) => element === name ? `_${element}` : element;
206
+ const jsxAttr = (attrName, value) => {
207
+ if (attrName === "style") {
208
+ throw new Error(`${name}: style attributes have no react-native-svg equivalent`);
209
+ }
210
+ const prop = attrName === "xlink:href" ? "href" : attrName.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
211
+ return value === "currentColor" ? `${prop}={color}` : `${prop}="${value}"`;
212
+ };
213
+ const keepAttr = ([attrName]) => !(attrName === "xmlns" || attrName.startsWith("xmlns:") || attrName === "class" || attrName === "version" || attrName.startsWith("data-") || attrName.startsWith("aria-"));
214
+ const rootAttrs = root.attrs.filter(keepAttr);
215
+ const viewBox = rootAttrs.find(([attrName]) => attrName === "viewBox")?.[1];
216
+ if (!viewBox) throw new Error(`${name}: svg source has no viewBox`);
217
+ const rootStroke = rootAttrs.some(([attrName, value]) => attrName === "stroke" && value === "currentColor");
218
+ const strokeWidth = rootAttrs.find(([attrName]) => attrName === "stroke-width")?.[1];
219
+ const emit = (node, indent) => {
220
+ const element = elements[node.tag];
221
+ if (!element) throw new Error(`${name}: unsupported svg element <${node.tag}>`);
222
+ used.add(element);
223
+ const attrs = node.attrs.filter(keepAttr).map(([n, v]) => jsxAttr(n, v));
224
+ if (rootStroke && !node.attrs.some(([n]) => n === "stroke") && node.tag !== "g") {
225
+ attrs.push("stroke={color}");
226
+ }
227
+ const open = `${indent}<${ref(element)}${attrs.map((attr) => ` ${attr}`).join("")}`;
228
+ if (!node.children.length) return `${open} />`;
229
+ return `${open}>
230
+ ${node.children.map((child) => emit(child, `${indent} `)).join("\n")}
231
+ ${indent}</${ref(element)}>`;
232
+ };
233
+ const children = root.children.map((child) => emit(child, " "));
234
+ if (!children.length) throw new Error(`${name}: svg source draws nothing`);
235
+ const svgAttrs = [
236
+ "width={size}",
237
+ "height={size}",
238
+ ...rootAttrs.filter(([attrName]) => attrName !== "width" && attrName !== "height").map(([attrName, value]) => jsxAttr(attrName, value)),
239
+ "{...otherProps}"
240
+ ];
241
+ const imports = [...used].sort().map((element) => element === name ? `${element} as _${element}` : element);
242
+ const themedOptions = strokeWidth && strokeWidth !== "2" ? `, { defaultStrokeWidth: ${strokeWidth} }` : "";
243
+ return `${restrictedNames.includes(name) ? "/* eslint-disable no-shadow-restricted-names */\n" : ""}import { memo, type JSX } from 'react'
244
+ import { Svg, ${imports.join(", ")}, type SvgProps } from 'react-native-svg'
245
+ import { themed, type IconProps } from '@tamagui/helpers-icon'
246
+
247
+ export const ${name}: (props: IconProps) => JSX.Element = themed(
248
+ memo(function ${name}(props: IconProps) {
249
+ const { color = 'black', size = 24, ...otherProps } = props as SvgProps & {
250
+ color?: string
251
+ size?: number
252
+ }
253
+ return (
254
+ <Svg
255
+ ${svgAttrs.map((attr) => ` ${attr}`).join("\n")}
256
+ >
257
+ ${children.join("\n")}
258
+ </Svg>
259
+ )
260
+ })${themedOptions}
261
+ )
262
+ `;
263
+ }
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- require("./cli.cjs");
2
+ require("./cli.cjs");