@vegastack/design 0.7.58 → 0.7.60
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.60",
|
|
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
|
+
**136 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`), 12 starter blocks (`app-shell-01`, `board-01`, `issue-detail-01`, `command-search-01`, `list-page-01`, `library-01`, `login-01`, `notifications-01`, `review-split-01`, `settings-01`, `settings-02`, `status-pages-01`), 68 chart blocks across 7 families, and 9 data libs (`date-time`, `geo-data`, `emoji-data`, `drag-item`, `text-anchor`, `text-anchor-doc`, `file-kind`, `page-layout`, `tile-overlay`) — 705 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
|
|
@@ -72,7 +72,7 @@ starts with `icon-` is a component and never an icon.
|
|
|
72
72
|
- **`empty`** — A zero-data placeholder — always an icon (the icon prop, Inbox by default), title, description and a content slot, with a compact sm size for inline empties. The one empty-state markup: DataList's emptyState and noResults (SearchX, "No matches", Clear filters) are built on it.
|
|
73
73
|
- **`item`** — A composable row for list and feed content — media, title, description, actions — with a highlighted flash for a just-changed row.
|
|
74
74
|
- **`kbd`** — A keyboard-key chip, and a group that lays several of them out inline.
|
|
75
|
-
- **`markdown-view`** — Render a markdown string to safe, token-styled HTML — headings, lists, code, blockquotes, links, GFM tables — XSS-safe, no raw HTML.
|
|
75
|
+
- **`markdown-view`** — Render a markdown string to safe, token-styled HTML — headings (with optional ids), lists, code, blockquotes, links, GFM tables, mention and file chips, callouts and toggles — XSS-safe, no raw HTML.
|
|
76
76
|
- **`priority-icon`** — A flag marking priority — urgent, high, medium, low, none — each in a semantic color with filled, outline or dashed fill.
|
|
77
77
|
- **`relative-time`** — One Intl-based dates & times module — formatRelative, formatDuration, formatDate, formatDateTime, formatDateRange, formatTimeOfDay, formatDueLabel, groupByDay, time-zone cookie + provider — and the RelativeTime, DateTime, Duration and DueLabel components with absolute-time tooltips.
|
|
78
78
|
- **`status-icon`** — A small status indicator icon — todo, in progress, blocked, done, cancelled — each mapping to a lucide icon and semantic color.
|
|
@@ -118,6 +118,7 @@ starts with `icon-` is a component and never an icon.
|
|
|
118
118
|
|
|
119
119
|
- **`breadcrumb`** — A hierarchical navigation trail — links, separators, the current page, and ellipsis collapse for long paths.
|
|
120
120
|
- **`command`** — A searchable command palette — filtered, grouped items with keyboard navigation, optionally inside a ⌘K dialog.
|
|
121
|
+
- **`folder-tree`** — A Notion-style navigation tree for a file library — sections of folders, pages and files; folders that load their children on first open with loading, error, empty and Show all rows; one tab stop with tree arrow keys and typeahead; a ⋯ menu per row; pointer drag into a folder or section; and a folders-only picker mode for Move dialogs.
|
|
121
122
|
- **`menubar`** — A persistent horizontal bar of menus — application-style File / Edit / View navigation.
|
|
122
123
|
- **`multi-step-form`** — A guarded, branching flow around a Stepper — conditional steps, sync and async advance guards, locking, reachability-derived deep links and resume, and a phone layout chosen from the same predicate. Owns no fields and no validator.
|
|
123
124
|
- **`navigation-menu`** — A collection of links for navigating websites — triggers that open one shared panel, and plain links styled to match.
|
|
@@ -162,7 +163,8 @@ starts with `icon-` is a component and never an icon.
|
|
|
162
163
|
|
|
163
164
|
## Rich text
|
|
164
165
|
|
|
165
|
-
- **`
|
|
166
|
+
- **`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.
|
|
167
|
+
- **`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, callouts and toggles, @ mentions, image and file uploads, a heading outline, comment highlights, portaled menus, and one onCommit path.
|
|
166
168
|
|
|
167
169
|
## Chat
|
|
168
170
|
|