@vegastack/design 0.7.58 → 0.7.59
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/bin/check-updates.mjs
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
//
|
|
6
6
|
// HOW IT WORKS (one index request + bounded item requests for installed copies):
|
|
7
7
|
// 1. Resolve the @vegastack registry url + auth headers from components.json (or env).
|
|
8
|
-
// 2. Scan the components dir
|
|
8
|
+
// 2. Scan the components dir — plus `aliases.lib` / `aliases.hooks` for `@lib/…` and `@hooks/…`
|
|
9
|
+
// targets such as `date-time` — for files carrying the provenance header the registry stamps:
|
|
9
10
|
// // @vegastack <name>@<version> sha256-<integrity>
|
|
10
11
|
// That header IS the version pin recorded at copy-in time.
|
|
11
12
|
// 3. Fetch the registry INDEX once (…/registry.json) — every item carries meta.version + meta.integrity.
|
|
@@ -357,10 +358,8 @@ function indexUrl(urlTemplate) {
|
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
// ── components dir + scan ──────────────────────────────────────────────────────────────────────
|
|
360
|
-
function
|
|
361
|
-
|
|
362
|
-
const ui = componentsJson?.aliases?.ui;
|
|
363
|
-
const rel = ui ? ui.replace(/^@\//, "").replace(/^~\//, "") : "components/ui";
|
|
361
|
+
function resolveAliasDir(cwd, alias, fallback) {
|
|
362
|
+
const rel = alias ? alias.replace(/^@\//, "").replace(/^~\//, "") : fallback;
|
|
364
363
|
const direct = resolve(cwd, rel); // assumes @/ = project root
|
|
365
364
|
if (existsSync(direct)) return direct;
|
|
366
365
|
const srcVariant = resolve(cwd, "src", rel); // common alias: @/* -> src/*
|
|
@@ -368,6 +367,35 @@ function resolveComponentsDir(cwd, dirFlag, componentsJson) {
|
|
|
368
367
|
return direct; // documented default; "none found" message hints --dir
|
|
369
368
|
}
|
|
370
369
|
|
|
370
|
+
function resolveComponentsDir(cwd, dirFlag, componentsJson) {
|
|
371
|
+
if (dirFlag) return resolve(cwd, dirFlag);
|
|
372
|
+
return resolveAliasDir(cwd, componentsJson?.aliases?.ui, "components/ui");
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Where registry files land besides the components dir: `@lib/…` targets (e.g. `date-time`,
|
|
377
|
+
* `page-layout`) under `aliases.lib`, `@hooks/…` under `aliases.hooks`. Scanned only when
|
|
378
|
+
* components.json names the alias and the directory exists — so a locally edited lib file is
|
|
379
|
+
* drift exactly like an edited component.
|
|
380
|
+
*/
|
|
381
|
+
function resolveExtraRoots(cwd, componentsJson, uiDir) {
|
|
382
|
+
const roots = [];
|
|
383
|
+
for (const kind of ["lib", "hooks"]) {
|
|
384
|
+
const alias = componentsJson?.aliases?.[kind];
|
|
385
|
+
if (!alias) continue;
|
|
386
|
+
const dir = resolveAliasDir(cwd, alias, kind);
|
|
387
|
+
if (!existsSync(dir)) continue;
|
|
388
|
+
const overlaps = [uiDir, ...roots.map((r) => r.dir)].some(
|
|
389
|
+
(other) =>
|
|
390
|
+
dir === other ||
|
|
391
|
+
dir.startsWith(other + sep) ||
|
|
392
|
+
other.startsWith(dir + sep),
|
|
393
|
+
);
|
|
394
|
+
if (!overlaps) roots.push({ kind, dir });
|
|
395
|
+
}
|
|
396
|
+
return roots;
|
|
397
|
+
}
|
|
398
|
+
|
|
371
399
|
function walk(dir, out = [], isRoot = true) {
|
|
372
400
|
let rootStat;
|
|
373
401
|
try {
|
|
@@ -410,7 +438,7 @@ function walk(dir, out = [], isRoot = true) {
|
|
|
410
438
|
// pipeline strips leading comments during its transform, so most consumer copies have NO
|
|
411
439
|
// header. Headerless files are identified by filename against the registry index and compared
|
|
412
440
|
// by alias-normalized CONTENT instead (see `normalizeForCompare`).
|
|
413
|
-
function readInstalled(file, root) {
|
|
441
|
+
function readInstalled(file, root, kind = "ui") {
|
|
414
442
|
let content;
|
|
415
443
|
try {
|
|
416
444
|
content = readFileSync(file, "utf8");
|
|
@@ -423,7 +451,7 @@ function readInstalled(file, root) {
|
|
|
423
451
|
);
|
|
424
452
|
const m = PROVENANCE_RE.exec(firstLine);
|
|
425
453
|
const name = basename(file).replace(/\.tsx?$/, "");
|
|
426
|
-
const relativePath = relative(root, file).split(sep).join("/")
|
|
454
|
+
const relativePath = `${kind}/${relative(root, file).split(sep).join("/")}`;
|
|
427
455
|
return m
|
|
428
456
|
? {
|
|
429
457
|
file,
|
|
@@ -464,10 +492,19 @@ function expectedVariantsForCompare(content, label, aliases, fileType) {
|
|
|
464
492
|
return new Set([exact, stripped]);
|
|
465
493
|
}
|
|
466
494
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
495
|
+
const TARGET_ROOTS = [
|
|
496
|
+
["@ui/", "ui"],
|
|
497
|
+
["@lib/", "lib"],
|
|
498
|
+
["@hooks/", "hooks"],
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
/** A registry file's install location as `<root kind>/<path>`, or undefined for other targets. */
|
|
502
|
+
function targetPath(file) {
|
|
503
|
+
if (typeof file?.target !== "string") return undefined;
|
|
504
|
+
for (const [prefix, kind] of TARGET_ROOTS)
|
|
505
|
+
if (file.target.startsWith(prefix))
|
|
506
|
+
return `${kind}/${file.target.slice(prefix.length)}`;
|
|
507
|
+
return undefined;
|
|
471
508
|
}
|
|
472
509
|
|
|
473
510
|
async function mapLimit(values, limit, fn) {
|
|
@@ -611,7 +648,7 @@ export async function main(argv) {
|
|
|
611
648
|
}
|
|
612
649
|
remote.set(item.name, item);
|
|
613
650
|
for (const file of item.files) {
|
|
614
|
-
const target =
|
|
651
|
+
const target = targetPath(file);
|
|
615
652
|
if (!target) continue;
|
|
616
653
|
if (targetOwners.has(target)) {
|
|
617
654
|
console.error(
|
|
@@ -630,15 +667,19 @@ export async function main(argv) {
|
|
|
630
667
|
// - headerless files NOT in the index are skipped (they're the consumer's own components)
|
|
631
668
|
let installedFiles;
|
|
632
669
|
try {
|
|
633
|
-
installedFiles =
|
|
670
|
+
installedFiles = [
|
|
671
|
+
...walk(dir).map((file) => readInstalled(file, dir, "ui")),
|
|
672
|
+
...(opts.dir ? [] : resolveExtraRoots(cwd, componentsJson, dir)).flatMap(
|
|
673
|
+
({ kind, dir: extra }) =>
|
|
674
|
+
walk(extra).map((file) => readInstalled(file, extra, kind)),
|
|
675
|
+
),
|
|
676
|
+
];
|
|
634
677
|
} catch (err) {
|
|
635
678
|
console.error(`✗ ${terminalText(err.message)}`);
|
|
636
679
|
return 2;
|
|
637
680
|
}
|
|
638
681
|
const grouped = new Map();
|
|
639
|
-
for (const installedFile of installedFiles
|
|
640
|
-
.map((file) => readInstalled(file, dir))
|
|
641
|
-
.filter(Boolean)) {
|
|
682
|
+
for (const installedFile of installedFiles.filter(Boolean)) {
|
|
642
683
|
const itemName = installedFile.header
|
|
643
684
|
? installedFile.name
|
|
644
685
|
: targetOwners.get(installedFile.relativePath);
|
|
@@ -708,7 +749,7 @@ export async function main(argv) {
|
|
|
708
749
|
status: "missing",
|
|
709
750
|
};
|
|
710
751
|
|
|
711
|
-
const expectedTargets = (r.files ?? []).map(
|
|
752
|
+
const expectedTargets = (r.files ?? []).map(targetPath).filter(Boolean);
|
|
712
753
|
const installedByTarget = new Map(
|
|
713
754
|
group.files.map((file) => [file.relativePath, file]),
|
|
714
755
|
);
|
|
@@ -735,7 +776,7 @@ export async function main(argv) {
|
|
|
735
776
|
if (item.name !== group.name || !Array.isArray(item.files)) {
|
|
736
777
|
throw new Error("registry item identity/files contract mismatch");
|
|
737
778
|
}
|
|
738
|
-
const fetchedTargets = item.files.map(
|
|
779
|
+
const fetchedTargets = item.files.map(targetPath).filter(Boolean);
|
|
739
780
|
const sortedFetchedTargets = [...fetchedTargets].sort();
|
|
740
781
|
const sortedExpectedTargets = [...expectedTargets].sort();
|
|
741
782
|
if (
|
|
@@ -751,7 +792,7 @@ export async function main(argv) {
|
|
|
751
792
|
}
|
|
752
793
|
if (
|
|
753
794
|
item.files.some(
|
|
754
|
-
(entry) =>
|
|
795
|
+
(entry) => targetPath(entry) && typeof entry.content !== "string",
|
|
755
796
|
)
|
|
756
797
|
) {
|
|
757
798
|
throw new Error("registry item contains a non-string component file");
|
|
@@ -765,7 +806,7 @@ export async function main(argv) {
|
|
|
765
806
|
}
|
|
766
807
|
let same = true;
|
|
767
808
|
for (const entry of item.files ?? []) {
|
|
768
|
-
const target =
|
|
809
|
+
const target = targetPath(entry);
|
|
769
810
|
if (!target) continue;
|
|
770
811
|
const local = installedByTarget.get(target);
|
|
771
812
|
const expectedVariants = expectedVariantsForCompare(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vegastack/design",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.59",
|
|
4
4
|
"description": "VegaStack design system — cn utility, icon runtime, Tailwind v4 preset, and the vegastack-design CLI (tokens ship separately as @vegastack/design-tokens)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<!-- GENERATED — do not hand-edit. Regenerated from the design system's component contract,
|
|
4
4
|
which is the authority for membership and counts. -->
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**135 components**, plus 467 animated-icon items, 13 hooks (`use-animation-replay`, `use-announcer`, `use-async-search`, `use-drag-reorder`, `use-file-drop`, `use-inline-edit`, `use-list-nav`, `use-media-query`, `use-mobile`, `use-modal-inert`, `use-overflow`, `use-platform`, `use-tabs-swipe`), 11 starter blocks (`app-shell-01`, `board-01`, `issue-detail-01`, `command-search-01`, `list-page-01`, `login-01`, `notifications-01`, `review-split-01`, `settings-01`, `settings-02`, `status-pages-01`), 68 chart blocks across 7 families, and 6 data libs (`date-time`, `geo-data`, `emoji-data`, `drag-item`, `page-layout`, `tile-overlay`) — 700 registry items in total.
|
|
7
7
|
|
|
8
8
|
Install any of them with `shadcn add @vegastack/<name>`. Animated icons install as
|
|
9
9
|
`@vegastack/icon-<name>`; the bare name is reserved for components, so a component whose name
|
|
@@ -162,6 +162,7 @@ starts with `icon-` is a component and never an icon.
|
|
|
162
162
|
|
|
163
163
|
## Rich text
|
|
164
164
|
|
|
165
|
+
- **`template-editor`** — A plain-paragraph editor for text with placeholders: typing @ or {{ opens a searchable list of tokens, the one picked becomes an atomic inline chip, and the value is plain text with {{id}} tokens.
|
|
165
166
|
- **`text-edit`** — A Tiptap-based, markdown-first rich-text editor with no toolbar and no fill — caret-only as a document, or boxed with a subtle focus border: a slash menu for blocks, a bubble menu for marks and block types, GFM tables with a menu and drag grips, block drag handles, portaled menus, and one onCommit path.
|
|
166
167
|
|
|
167
168
|
## Chat
|