@texturehq/edges 0.0.18 → 0.0.20
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/dist/components.manifest.json +942 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +173 -16
- package/dist/index.d.ts +173 -16
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/styles.css +80 -18
- package/package.json +7 -3
- package/scripts/generate-components-manifest.js +151 -0
- package/scripts/setup-cursor-rules-manual.js +167 -0
- package/scripts/setup-cursor-rules.js +170 -0
- package/scripts/setup-cursor-rules.sh +95 -0
- package/templates/claude-rules/.claude +85 -0
- package/templates/claude-rules/claude.md +85 -0
- package/templates/cursor-rules/edges-usage.mdc +65 -0
package/dist/styles.css
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
--text-sm: 0.875rem;
|
|
8
8
|
--text-base: 1rem;
|
|
9
9
|
--text-lg: 1.125rem;
|
|
10
|
+
--radius-lg: 0.5rem;
|
|
10
11
|
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
11
12
|
--default-transition-duration: 150ms;
|
|
12
13
|
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
13
14
|
--default-font-family: "Inter", system-ui, sans-serif;
|
|
14
15
|
--default-mono-font-family: "Fira Code", monospace;
|
|
16
|
+
--color-brand-primary: #444ae1;
|
|
15
17
|
--color-neutral-black: #333333;
|
|
16
18
|
--color-neutral-white: #ffffff;
|
|
17
19
|
--color-text-body: #333333;
|
|
@@ -373,6 +375,9 @@
|
|
|
373
375
|
.mb-4 {
|
|
374
376
|
margin-bottom: calc(0.25rem * 4);
|
|
375
377
|
}
|
|
378
|
+
.ml-auto {
|
|
379
|
+
margin-left: auto;
|
|
380
|
+
}
|
|
376
381
|
.box-border {
|
|
377
382
|
box-sizing: border-box;
|
|
378
383
|
}
|
|
@@ -484,6 +489,9 @@
|
|
|
484
489
|
.min-h-\[100px\] {
|
|
485
490
|
min-height: 100px;
|
|
486
491
|
}
|
|
492
|
+
.w-2 {
|
|
493
|
+
width: calc(0.25rem * 2);
|
|
494
|
+
}
|
|
487
495
|
.w-3 {
|
|
488
496
|
width: calc(0.25rem * 3);
|
|
489
497
|
}
|
|
@@ -823,6 +831,9 @@
|
|
|
823
831
|
.rounded {
|
|
824
832
|
border-radius: 0.25rem;
|
|
825
833
|
}
|
|
834
|
+
.rounded-\[0\.5rem\] {
|
|
835
|
+
border-radius: 0.5rem;
|
|
836
|
+
}
|
|
826
837
|
.rounded-\[14px\] {
|
|
827
838
|
border-radius: 14px;
|
|
828
839
|
}
|
|
@@ -929,6 +940,9 @@
|
|
|
929
940
|
.border-border-muted\/50 {
|
|
930
941
|
border-color: color-mix(in oklab, #e5e7eb 50%, transparent);
|
|
931
942
|
}
|
|
943
|
+
.border-brand-primary {
|
|
944
|
+
border-color: #444ae1;
|
|
945
|
+
}
|
|
932
946
|
.border-current {
|
|
933
947
|
border-color: currentcolor;
|
|
934
948
|
}
|
|
@@ -956,6 +970,9 @@
|
|
|
956
970
|
.border-slate-800 {
|
|
957
971
|
border-color: var(--slate-800);
|
|
958
972
|
}
|
|
973
|
+
.border-text-body {
|
|
974
|
+
border-color: #333333;
|
|
975
|
+
}
|
|
959
976
|
.border-transparent {
|
|
960
977
|
border-color: transparent;
|
|
961
978
|
}
|
|
@@ -971,6 +988,9 @@
|
|
|
971
988
|
.\!bg-neutral-black {
|
|
972
989
|
background-color: #333333 !important;
|
|
973
990
|
}
|
|
991
|
+
.bg-\[\#444ae1\] {
|
|
992
|
+
background-color: #444ae1;
|
|
993
|
+
}
|
|
974
994
|
.bg-\[var\(--skeleton-base\)\] {
|
|
975
995
|
background-color: var(--skeleton-base);
|
|
976
996
|
}
|
|
@@ -1061,18 +1081,12 @@
|
|
|
1061
1081
|
.bg-orange-50 {
|
|
1062
1082
|
background-color: oklch(0.98 0.016 73.684);
|
|
1063
1083
|
}
|
|
1064
|
-
.bg-pink-400 {
|
|
1065
|
-
background-color: var(--pink-400);
|
|
1066
|
-
}
|
|
1067
1084
|
.bg-purple-50 {
|
|
1068
1085
|
background-color: oklch(0.977 0.014 308.299);
|
|
1069
1086
|
}
|
|
1070
1087
|
.bg-red-50 {
|
|
1071
1088
|
background-color: oklch(0.971 0.013 17.38);
|
|
1072
1089
|
}
|
|
1073
|
-
.bg-red-500 {
|
|
1074
|
-
background-color: oklch(0.637 0.237 25.331);
|
|
1075
|
-
}
|
|
1076
1090
|
.bg-red-600 {
|
|
1077
1091
|
background-color: oklch(0.577 0.245 27.325);
|
|
1078
1092
|
}
|
|
@@ -1097,9 +1111,6 @@
|
|
|
1097
1111
|
.bg-yellow-50 {
|
|
1098
1112
|
background-color: oklch(0.987 0.026 102.212);
|
|
1099
1113
|
}
|
|
1100
|
-
.bg-yellow-400 {
|
|
1101
|
-
background-color: oklch(0.852 0.199 91.936);
|
|
1102
|
-
}
|
|
1103
1114
|
.bg-gradient-to-r {
|
|
1104
1115
|
--tw-gradient-position: to right in oklab;
|
|
1105
1116
|
background-image: linear-gradient(var(--tw-gradient-stops));
|
|
@@ -1174,6 +1185,9 @@
|
|
|
1174
1185
|
.p-10 {
|
|
1175
1186
|
padding: calc(0.25rem * 10);
|
|
1176
1187
|
}
|
|
1188
|
+
.p-\[1rem\] {
|
|
1189
|
+
padding: 1rem;
|
|
1190
|
+
}
|
|
1177
1191
|
.\!px-2 {
|
|
1178
1192
|
padding-inline: calc(0.25rem * 2) !important;
|
|
1179
1193
|
}
|
|
@@ -1267,12 +1281,21 @@
|
|
|
1267
1281
|
.pl-3 {
|
|
1268
1282
|
padding-left: calc(0.25rem * 3);
|
|
1269
1283
|
}
|
|
1284
|
+
.pl-7 {
|
|
1285
|
+
padding-left: calc(0.25rem * 7);
|
|
1286
|
+
}
|
|
1270
1287
|
.pl-8 {
|
|
1271
1288
|
padding-left: calc(0.25rem * 8);
|
|
1272
1289
|
}
|
|
1290
|
+
.pl-9 {
|
|
1291
|
+
padding-left: calc(0.25rem * 9);
|
|
1292
|
+
}
|
|
1273
1293
|
.pl-10 {
|
|
1274
1294
|
padding-left: calc(0.25rem * 10);
|
|
1275
1295
|
}
|
|
1296
|
+
.pl-12 {
|
|
1297
|
+
padding-left: calc(0.25rem * 12);
|
|
1298
|
+
}
|
|
1276
1299
|
.text-center {
|
|
1277
1300
|
text-align: center;
|
|
1278
1301
|
}
|
|
@@ -1320,6 +1343,12 @@
|
|
|
1320
1343
|
font-size: 0.75rem;
|
|
1321
1344
|
line-height: var(--tw-leading, calc(1 / 0.75));
|
|
1322
1345
|
}
|
|
1346
|
+
.text-\[1\.125rem\] {
|
|
1347
|
+
font-size: 1.125rem;
|
|
1348
|
+
}
|
|
1349
|
+
.text-\[1rem\] {
|
|
1350
|
+
font-size: 1rem;
|
|
1351
|
+
}
|
|
1323
1352
|
.text-\[length\:var\(--control-text-lg\)\] {
|
|
1324
1353
|
font-size: var(--control-text-lg);
|
|
1325
1354
|
}
|
|
@@ -1344,6 +1373,10 @@
|
|
|
1344
1373
|
--tw-leading: 1.625;
|
|
1345
1374
|
line-height: 1.625;
|
|
1346
1375
|
}
|
|
1376
|
+
.font-\[500\] {
|
|
1377
|
+
--tw-font-weight: 500;
|
|
1378
|
+
font-weight: 500;
|
|
1379
|
+
}
|
|
1347
1380
|
.font-bold {
|
|
1348
1381
|
--tw-font-weight: 700;
|
|
1349
1382
|
font-weight: 700;
|
|
@@ -1381,6 +1414,15 @@
|
|
|
1381
1414
|
.\!text-text-caption {
|
|
1382
1415
|
color: #6b7280 !important;
|
|
1383
1416
|
}
|
|
1417
|
+
.text-\[\#111827\] {
|
|
1418
|
+
color: #111827;
|
|
1419
|
+
}
|
|
1420
|
+
.text-\[\#333333\] {
|
|
1421
|
+
color: #333333;
|
|
1422
|
+
}
|
|
1423
|
+
.text-\[\#ffffff\] {
|
|
1424
|
+
color: #ffffff;
|
|
1425
|
+
}
|
|
1384
1426
|
.text-action-destructive {
|
|
1385
1427
|
color: #b91c1c;
|
|
1386
1428
|
}
|
|
@@ -1420,9 +1462,6 @@
|
|
|
1420
1462
|
.text-gray-800 {
|
|
1421
1463
|
color: var(--gray-800);
|
|
1422
1464
|
}
|
|
1423
|
-
.text-green-500 {
|
|
1424
|
-
color: oklch(0.723 0.219 149.579);
|
|
1425
|
-
}
|
|
1426
1465
|
.text-green-600 {
|
|
1427
1466
|
color: oklch(0.627 0.194 149.214);
|
|
1428
1467
|
}
|
|
@@ -1509,6 +1548,9 @@
|
|
|
1509
1548
|
.caret-transparent {
|
|
1510
1549
|
caret-color: transparent;
|
|
1511
1550
|
}
|
|
1551
|
+
.opacity-0 {
|
|
1552
|
+
opacity: 0%;
|
|
1553
|
+
}
|
|
1512
1554
|
.opacity-50 {
|
|
1513
1555
|
opacity: 50%;
|
|
1514
1556
|
}
|
|
@@ -1534,6 +1576,14 @@
|
|
|
1534
1576
|
--tw-shadow: inset 0 2px 4px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
|
|
1535
1577
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1536
1578
|
}
|
|
1579
|
+
.shadow-lg {
|
|
1580
|
+
--tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1581
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1582
|
+
}
|
|
1583
|
+
.shadow-md {
|
|
1584
|
+
--tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1585
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1586
|
+
}
|
|
1537
1587
|
.shadow-none {
|
|
1538
1588
|
--tw-shadow: 0 0 #0000;
|
|
1539
1589
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -1578,9 +1628,6 @@
|
|
|
1578
1628
|
outline-style: var(--tw-outline-style);
|
|
1579
1629
|
outline-width: 1.5px;
|
|
1580
1630
|
}
|
|
1581
|
-
.-outline-offset-1 {
|
|
1582
|
-
outline-offset: calc(1px * -1);
|
|
1583
|
-
}
|
|
1584
1631
|
.-outline-offset-2 {
|
|
1585
1632
|
outline-offset: calc(2px * -1);
|
|
1586
1633
|
}
|
|
@@ -1605,9 +1652,6 @@
|
|
|
1605
1652
|
.outline-feedback-error-border {
|
|
1606
1653
|
outline-color: #ef4444;
|
|
1607
1654
|
}
|
|
1608
|
-
.outline-transparent {
|
|
1609
|
-
outline-color: transparent;
|
|
1610
|
-
}
|
|
1611
1655
|
.outline-white {
|
|
1612
1656
|
outline-color: var(--color-neutral-white);
|
|
1613
1657
|
}
|
|
@@ -1748,6 +1792,14 @@
|
|
|
1748
1792
|
color: #9ca3af;
|
|
1749
1793
|
}
|
|
1750
1794
|
}
|
|
1795
|
+
.placeholder\:text-text-placeholder {
|
|
1796
|
+
&::-moz-placeholder {
|
|
1797
|
+
color: #9ca3af;
|
|
1798
|
+
}
|
|
1799
|
+
&::placeholder {
|
|
1800
|
+
color: #9ca3af;
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1751
1803
|
.before\:absolute {
|
|
1752
1804
|
&::before {
|
|
1753
1805
|
content: var(--tw-content);
|
|
@@ -2118,6 +2170,11 @@
|
|
|
2118
2170
|
background-color: #f3f4f6;
|
|
2119
2171
|
}
|
|
2120
2172
|
}
|
|
2173
|
+
.data-\[focused\]\:opacity-100 {
|
|
2174
|
+
&[data-focused] {
|
|
2175
|
+
opacity: 100%;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2121
2178
|
.data-\[placeholder\]\:text-text-placeholder {
|
|
2122
2179
|
&[data-placeholder] {
|
|
2123
2180
|
color: #9ca3af;
|
|
@@ -2128,6 +2185,11 @@
|
|
|
2128
2185
|
background-color: #f3f4f6;
|
|
2129
2186
|
}
|
|
2130
2187
|
}
|
|
2188
|
+
.data-\[selected\]\:opacity-100 {
|
|
2189
|
+
&[data-selected] {
|
|
2190
|
+
opacity: 100%;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2131
2193
|
.supports-\[-moz-appearance\:none\]\:bg-gray-100 {
|
|
2132
2194
|
@supports (-moz-appearance:none) {
|
|
2133
2195
|
background-color: var(--gray-100);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@texturehq/edges",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"author": "Nicholas Brown <nick@texturehq.com>",
|
|
5
5
|
"description": "A shared component library for Texture",
|
|
6
6
|
"type": "module",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"sideEffects": false,
|
|
11
11
|
"files": [
|
|
12
|
-
"dist/**"
|
|
12
|
+
"dist/**",
|
|
13
|
+
"templates/**",
|
|
14
|
+
"scripts/**"
|
|
13
15
|
],
|
|
14
16
|
"exports": {
|
|
15
17
|
".": {
|
|
@@ -38,7 +40,8 @@
|
|
|
38
40
|
"test:coverage": "vitest run --coverage",
|
|
39
41
|
"test:ui": "vitest --ui",
|
|
40
42
|
"storybook": "storybook dev -p 6010 --no-open",
|
|
41
|
-
"build-storybook": "storybook build"
|
|
43
|
+
"build-storybook": "storybook build",
|
|
44
|
+
"postinstall": "node scripts/setup-cursor-rules.js || echo \"! setup-cursor-rules: non-fatal error\""
|
|
42
45
|
},
|
|
43
46
|
"peerDependencies": {
|
|
44
47
|
"react": "^18.2.0",
|
|
@@ -52,6 +55,7 @@
|
|
|
52
55
|
"next-intl": "^4.0.2",
|
|
53
56
|
"react-ace": "^14.0.1",
|
|
54
57
|
"react-aria-components": "^1.7.1",
|
|
58
|
+
"react-stately": "^3.35.0",
|
|
55
59
|
"tailwind-merge": "^3.2.0"
|
|
56
60
|
},
|
|
57
61
|
"devDependencies": {
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// generate-components-manifest.js
|
|
2
|
+
// Build-time script that scans exported components and creates dist/components.manifest.json
|
|
3
|
+
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
const ROOT = process.cwd();
|
|
8
|
+
const SRC_DIR = path.join(ROOT, "src");
|
|
9
|
+
const DIST_DIR = path.join(ROOT, "dist");
|
|
10
|
+
|
|
11
|
+
function read(file) {
|
|
12
|
+
return fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function ensureDir(dir) {
|
|
16
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function extractExportsFromIndex(indexContent) {
|
|
20
|
+
// Matches: export { Button } from "./components/Button";
|
|
21
|
+
const re = /export\s+\{\s*([A-Za-z0-9_,\s]+)\s*\}\s+from\s+"\.\/components\/([A-Za-z0-9_/.-]+)"/g;
|
|
22
|
+
const results = [];
|
|
23
|
+
let m;
|
|
24
|
+
while ((m = re.exec(indexContent))) {
|
|
25
|
+
const exported = m[1]
|
|
26
|
+
.split(",")
|
|
27
|
+
.map((s) => s.trim())
|
|
28
|
+
.filter(Boolean);
|
|
29
|
+
const rel = m[2];
|
|
30
|
+
exported.forEach((name) => {
|
|
31
|
+
// Only keep PascalCase (components); ignore sub-exports like Tab, TabList if not directory-named
|
|
32
|
+
results.push({ name, relPath: rel });
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return results;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function findComponentFile(relPath) {
|
|
39
|
+
// Components are in directories like Button/Button.tsx or Button/index.ts
|
|
40
|
+
const base = path.join(SRC_DIR, "components", relPath);
|
|
41
|
+
const candidates = [
|
|
42
|
+
path.join(base, `${relPath}.tsx`),
|
|
43
|
+
path.join(base, `${relPath}.ts`),
|
|
44
|
+
path.join(base, `index.tsx`),
|
|
45
|
+
path.join(base, `index.ts`),
|
|
46
|
+
];
|
|
47
|
+
for (const f of candidates) {
|
|
48
|
+
if (fs.existsSync(f)) return f;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getJsdocAbove(content, idx) {
|
|
54
|
+
// Find the last JSDoc block before idx
|
|
55
|
+
const upTo = content.slice(0, idx);
|
|
56
|
+
const start = upTo.lastIndexOf("/**");
|
|
57
|
+
const end = upTo.lastIndexOf("*/");
|
|
58
|
+
if (start !== -1 && end !== -1 && end > start) {
|
|
59
|
+
const block = upTo.slice(start + 3, end).trim();
|
|
60
|
+
return block
|
|
61
|
+
.split("\n")
|
|
62
|
+
.map((l) => l.replace(/^\s*\*\s?/, "").trim())
|
|
63
|
+
.join(" ")
|
|
64
|
+
.trim();
|
|
65
|
+
}
|
|
66
|
+
return "";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function extractProps(content, componentName) {
|
|
70
|
+
// Try `export interface <Name>Props` first
|
|
71
|
+
const ifaceRe = new RegExp(`export\\s+interface\\s+${componentName}Props\\s*(?:extends\\s+[^{]+)?\\{([\\s\\S]*?)\\}`, "m");
|
|
72
|
+
let m = ifaceRe.exec(content);
|
|
73
|
+
if (!m) {
|
|
74
|
+
// Try generic name: any exported *Props
|
|
75
|
+
const anyIfaceRe = /export\s+interface\s+([A-Za-z0-9_]+Props)\s*(?:extends\s+[^{]+)?\{([\s\S]*?)\}/m;
|
|
76
|
+
m = anyIfaceRe.exec(content);
|
|
77
|
+
}
|
|
78
|
+
if (!m) {
|
|
79
|
+
// Try type alias
|
|
80
|
+
const typeRe = new RegExp(`export\\s+type\\s+${componentName}Props\\s*=\\s*(?:[^{&]+&\s*)?([\\s\\S]*?)\\}`, "m");
|
|
81
|
+
m = typeRe.exec(content);
|
|
82
|
+
}
|
|
83
|
+
const props = [];
|
|
84
|
+
if (m) {
|
|
85
|
+
const body = m[2] || m[1] || "";
|
|
86
|
+
const lines = body
|
|
87
|
+
.split("\n")
|
|
88
|
+
.map((l) => l.trim())
|
|
89
|
+
.filter((l) => !!l && !l.startsWith("//"));
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
// Match: name?: Type; or name: Type;
|
|
92
|
+
const pm = /^(readonly\s+)?([A-Za-z0-9_]+)\??:\s*([^;]+);?/.exec(line);
|
|
93
|
+
if (pm) {
|
|
94
|
+
const name = pm[2];
|
|
95
|
+
const type = pm[3].trim();
|
|
96
|
+
props.push({ name, type });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return props;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function run() {
|
|
104
|
+
try {
|
|
105
|
+
const indexPath = path.join(SRC_DIR, "index.ts");
|
|
106
|
+
const indexContent = read(indexPath);
|
|
107
|
+
const exports = extractExportsFromIndex(indexContent);
|
|
108
|
+
|
|
109
|
+
const components = [];
|
|
110
|
+
for (const { name, relPath } of exports) {
|
|
111
|
+
// Only treat PascalCase names as components
|
|
112
|
+
if (!/^[A-Z]/.test(name)) continue;
|
|
113
|
+
|
|
114
|
+
const componentFile = findComponentFile(relPath);
|
|
115
|
+
if (!componentFile) continue;
|
|
116
|
+
const content = read(componentFile);
|
|
117
|
+
|
|
118
|
+
// Description: JSDoc above `export function Name` or above `export interface NameProps`
|
|
119
|
+
let idx = content.indexOf(`export function ${name}`);
|
|
120
|
+
if (idx === -1) idx = content.search(new RegExp(`export\\s+(const|class)\\s+${name}\b`));
|
|
121
|
+
if (idx === -1) idx = content.search(new RegExp(`export\\s+(interface|type)\\s+${name}Props\b`));
|
|
122
|
+
const description = idx !== -1 ? getJsdocAbove(content, idx) : "";
|
|
123
|
+
|
|
124
|
+
const props = extractProps(content, name);
|
|
125
|
+
|
|
126
|
+
components.push({
|
|
127
|
+
name,
|
|
128
|
+
importRoot: "@texturehq/edges",
|
|
129
|
+
importPath: `@texturehq/edges/components/${name}`,
|
|
130
|
+
description,
|
|
131
|
+
props,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
ensureDir(DIST_DIR);
|
|
136
|
+
const manifest = {
|
|
137
|
+
version: process.env.npm_package_version || "unknown",
|
|
138
|
+
generatedAt: new Date().toISOString(),
|
|
139
|
+
components: components.sort((a, b) => a.name.localeCompare(b.name)),
|
|
140
|
+
};
|
|
141
|
+
fs.writeFileSync(path.join(DIST_DIR, "components.manifest.json"), JSON.stringify(manifest, null, 2));
|
|
142
|
+
console.log(`Generated ${path.join("dist", "components.manifest.json")} with ${components.length} components.`);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.error("Failed to generate components manifest:", err);
|
|
145
|
+
process.exitCode = 1;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
run();
|
|
150
|
+
|
|
151
|
+
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// setup-cursor-rules-manual.js (manual installer for Cursor rules)
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const setupCursorRules = () => {
|
|
7
|
+
const cwd = process.cwd();
|
|
8
|
+
|
|
9
|
+
// Don't run inside the edges package itself
|
|
10
|
+
try {
|
|
11
|
+
const pkgJsonPath = path.join(cwd, "package.json");
|
|
12
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
13
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
14
|
+
if (pkg.name === "@texturehq/edges") return;
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
// ignore
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Try multiple possible locations for the templates directory
|
|
21
|
+
const possibleTemplatePaths = [
|
|
22
|
+
// Yalc path (the actual files)
|
|
23
|
+
path.join(cwd, 'node_modules/.yalc/@texturehq/edges/templates/cursor-rules'),
|
|
24
|
+
// Regular npm install path
|
|
25
|
+
path.join(__dirname, '../templates/cursor-rules'),
|
|
26
|
+
// Alternative paths
|
|
27
|
+
path.join(__dirname, '../../templates/cursor-rules'),
|
|
28
|
+
path.join(__dirname, '../../../templates/cursor-rules'),
|
|
29
|
+
// Direct path from node_modules
|
|
30
|
+
path.join(cwd, 'node_modules/@texturehq/edges/templates/cursor-rules'),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
let templatesDir = null;
|
|
34
|
+
for (const templatePath of possibleTemplatePaths) {
|
|
35
|
+
if (fs.existsSync(templatePath)) {
|
|
36
|
+
templatesDir = templatePath;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!templatesDir) {
|
|
42
|
+
console.log('⚠️ Could not find cursor rules templates. Tried paths:');
|
|
43
|
+
possibleTemplatePaths.forEach(path => console.log(` - ${path}`));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log(`✅ Found templates at: ${templatesDir}`);
|
|
48
|
+
|
|
49
|
+
// Try to read package version from multiple locations
|
|
50
|
+
const possiblePackageJsonPaths = [
|
|
51
|
+
// Yalc path (the actual files)
|
|
52
|
+
path.join(cwd, 'node_modules/.yalc/@texturehq/edges/package.json'),
|
|
53
|
+
// Regular npm install path
|
|
54
|
+
path.join(__dirname, '../package.json'),
|
|
55
|
+
path.join(__dirname, '../../package.json'),
|
|
56
|
+
path.join(__dirname, '../../../package.json'),
|
|
57
|
+
path.join(cwd, 'node_modules/@texturehq/edges/package.json'),
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
let packageVersion = 'unknown';
|
|
61
|
+
for (const packageJsonPath of possiblePackageJsonPaths) {
|
|
62
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
63
|
+
try {
|
|
64
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
65
|
+
packageVersion = packageJson.version;
|
|
66
|
+
console.log(`📦 Found package version: ${packageVersion}`);
|
|
67
|
+
break;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.log(`⚠️ Could not read package.json at: ${packageJsonPath}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const templateFiles = fs.readdirSync(templatesDir).filter(file => file.endsWith('.mdc'));
|
|
75
|
+
|
|
76
|
+
if (templateFiles.length === 0) {
|
|
77
|
+
console.log('⚠️ No .mdc files found in templates directory');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Always use package-level rules for version-specific behavior
|
|
82
|
+
const cursorDir = path.join(cwd, '.cursor');
|
|
83
|
+
const rulesDir = path.join(cursorDir, 'rules');
|
|
84
|
+
|
|
85
|
+
// Create directories recursively
|
|
86
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
87
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
88
|
+
|
|
89
|
+
let copiedCount = 0;
|
|
90
|
+
|
|
91
|
+
templateFiles.forEach(file => {
|
|
92
|
+
const templatePath = path.join(templatesDir, file);
|
|
93
|
+
|
|
94
|
+
// Read template content and inject version info
|
|
95
|
+
let templateContent = fs.readFileSync(templatePath, 'utf8');
|
|
96
|
+
|
|
97
|
+
// Add version information to the rule
|
|
98
|
+
const versionHeader = `\n\n<!-- @texturehq/edges version: ${packageVersion} -->\n`;
|
|
99
|
+
templateContent = templateContent + versionHeader;
|
|
100
|
+
|
|
101
|
+
const targetPath = path.join(rulesDir, file);
|
|
102
|
+
|
|
103
|
+
// Backup existing rule before overwriting
|
|
104
|
+
if (fs.existsSync(targetPath)) {
|
|
105
|
+
const backupsDir = path.join(rulesDir, "_backups");
|
|
106
|
+
fs.mkdirSync(backupsDir, { recursive: true });
|
|
107
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
108
|
+
fs.copyFileSync(targetPath, path.join(backupsDir, `${file}.${ts}.bak`));
|
|
109
|
+
}
|
|
110
|
+
// Always overwrite to ensure version-specific rules
|
|
111
|
+
fs.writeFileSync(targetPath, templateContent, "utf8");
|
|
112
|
+
copiedCount++;
|
|
113
|
+
console.log(`✅ Updated .cursor/rules/${file} for @texturehq/edges v${packageVersion}`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Additionally, try to render a components list rule from the manifest if available
|
|
117
|
+
const possibleManifestPaths = [
|
|
118
|
+
path.join(cwd, 'node_modules/.yalc/@texturehq/edges/dist/components.manifest.json'),
|
|
119
|
+
path.join(cwd, 'node_modules/@texturehq/edges/dist/components.manifest.json')
|
|
120
|
+
];
|
|
121
|
+
let manifestPath = null;
|
|
122
|
+
for (const p of possibleManifestPaths) {
|
|
123
|
+
if (fs.existsSync(p)) { manifestPath = p; break; }
|
|
124
|
+
}
|
|
125
|
+
if (manifestPath) {
|
|
126
|
+
try {
|
|
127
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
128
|
+
const lines = [
|
|
129
|
+
'---',
|
|
130
|
+
'alwaysApply: true',
|
|
131
|
+
'---',
|
|
132
|
+
'',
|
|
133
|
+
`## @texturehq/edges Components (v${manifest.version || 'unknown'})`,
|
|
134
|
+
''
|
|
135
|
+
];
|
|
136
|
+
for (const c of manifest.components || []) {
|
|
137
|
+
lines.push(`- ${c.name}`);
|
|
138
|
+
if (c.importRoot) lines.push(` - Import: \`import { ${c.name} } from "${c.importRoot}"\``);
|
|
139
|
+
if (c.importPath) lines.push(` - Subpath: \`import { ${c.name} } from "${c.importPath}"\``);
|
|
140
|
+
if (c.props && c.props.length) {
|
|
141
|
+
const propNames = c.props.slice(0, 8).map(p => p.name).join(', ');
|
|
142
|
+
lines.push(` - Props: ${propNames}${c.props.length > 8 ? ', …' : ''}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const outPath = path.join(rulesDir, 'edges-components.mdc');
|
|
146
|
+
// Backup existing components manifest before overwriting
|
|
147
|
+
if (fs.existsSync(outPath)) {
|
|
148
|
+
const backupsDir = path.join(rulesDir, "_backups");
|
|
149
|
+
fs.mkdirSync(backupsDir, { recursive: true });
|
|
150
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
151
|
+
fs.copyFileSync(outPath, path.join(backupsDir, `edges-components.mdc.${ts}.bak`));
|
|
152
|
+
}
|
|
153
|
+
fs.writeFileSync(outPath, lines.join('\n'), "utf8");
|
|
154
|
+
console.log(`✅ Wrote .cursor/rules/edges-components.mdc from manifest (${manifest.components?.length || 0} components)`);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.log('⚠️ Failed to read components.manifest.json:', err.message);
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
console.log('ℹ️ No components.manifest.json found; skipping edges-components.mdc generation');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (copiedCount > 0) {
|
|
163
|
+
console.log(`🎨 Updated ${copiedCount} cursor rule(s) for @texturehq/edges v${packageVersion}`);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
setupCursorRules();
|