@viglet/viglet-design-system 2026.2.57 → 2026.3.3
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/README.md +277 -7
- package/dist/assets.cjs +1 -0
- package/dist/assets.es.js +2 -0
- package/dist/badge-locale-BxI9TwkE.js +579 -0
- package/dist/badge-locale-sIsBdP_e.cjs +7 -0
- package/dist/bento/bento-actions-menu.d.ts +42 -0
- package/dist/bento/bento-actions-menu.d.ts.map +1 -0
- package/dist/bento/bento-back-to-top.d.ts +11 -0
- package/dist/bento/bento-back-to-top.d.ts.map +1 -0
- package/dist/bento/bento-command-palette.d.ts +28 -0
- package/dist/bento/bento-command-palette.d.ts.map +1 -0
- package/dist/bento/bento-count-tile.d.ts +18 -0
- package/dist/bento/bento-count-tile.d.ts.map +1 -0
- package/dist/bento/bento-empty-state.d.ts +35 -0
- package/dist/bento/bento-empty-state.d.ts.map +1 -0
- package/dist/bento/bento-entity-shell.d.ts +123 -0
- package/dist/bento/bento-entity-shell.d.ts.map +1 -0
- package/dist/bento/bento-entity-tile.d.ts +40 -0
- package/dist/bento/bento-entity-tile.d.ts.map +1 -0
- package/dist/bento/bento-form-hero.d.ts +91 -0
- package/dist/bento/bento-form-hero.d.ts.map +1 -0
- package/dist/bento/bento-form-section.d.ts +31 -0
- package/dist/bento/bento-form-section.d.ts.map +1 -0
- package/dist/bento/bento-hero-icon-picker.d.ts +35 -0
- package/dist/bento/bento-hero-icon-picker.d.ts.map +1 -0
- package/dist/bento/bento-hero.d.ts +62 -0
- package/dist/bento/bento-hero.d.ts.map +1 -0
- package/dist/bento/bento-inline-edit.d.ts +52 -0
- package/dist/bento/bento-inline-edit.d.ts.map +1 -0
- package/dist/bento/bento-layout.d.ts +52 -0
- package/dist/bento/bento-layout.d.ts.map +1 -0
- package/dist/bento/bento-list-page.d.ts +124 -0
- package/dist/bento/bento-list-page.d.ts.map +1 -0
- package/dist/bento/bento-nav-rail.d.ts +32 -0
- package/dist/bento/bento-nav-rail.d.ts.map +1 -0
- package/dist/bento/bento-nav.d.ts +69 -0
- package/dist/bento/bento-nav.d.ts.map +1 -0
- package/dist/bento/bento-save-bar.d.ts +36 -0
- package/dist/bento/bento-save-bar.d.ts.map +1 -0
- package/dist/bento/bento-scroll-fade.d.ts +20 -0
- package/dist/bento/bento-scroll-fade.d.ts.map +1 -0
- package/dist/bento/bento-scroll-save-bar.d.ts +22 -0
- package/dist/bento/bento-scroll-save-bar.d.ts.map +1 -0
- package/dist/bento/bento-section-chrome.d.ts +60 -0
- package/dist/bento/bento-section-chrome.d.ts.map +1 -0
- package/dist/bento/bento-section.d.ts +27 -0
- package/dist/bento/bento-section.d.ts.map +1 -0
- package/dist/bento/bento-shortcuts-dialog.d.ts +15 -0
- package/dist/bento/bento-shortcuts-dialog.d.ts.map +1 -0
- package/dist/bento/bento-status-marker.d.ts +26 -0
- package/dist/bento/bento-status-marker.d.ts.map +1 -0
- package/dist/bento/bento-tile.d.ts +42 -0
- package/dist/bento/bento-tile.d.ts.map +1 -0
- package/dist/bento/bento-tones.d.ts +33 -0
- package/dist/bento/bento-tones.d.ts.map +1 -0
- package/dist/bento/bento-user-menu.d.ts +31 -0
- package/dist/bento/bento-user-menu.d.ts.map +1 -0
- package/dist/bento/index.d.ts +59 -0
- package/dist/bento/index.d.ts.map +1 -0
- package/dist/bento.cjs +1 -0
- package/dist/bento.css +442 -0
- package/dist/bento.es.js +1501 -0
- package/dist/breadcrumb.context-CTnZ4rD0.cjs +1 -0
- package/dist/breadcrumb.context-h2A2IEJ_.js +928 -0
- package/dist/components/app-footer.d.ts +1 -1
- package/dist/components/app-footer.d.ts.map +1 -1
- package/dist/components/app-switcher.d.ts +1 -1
- package/dist/components/app-switcher.d.ts.map +1 -1
- package/dist/components/backend-status.d.ts +2 -2
- package/dist/components/backend-status.d.ts.map +1 -1
- package/dist/components/badge-locale.d.ts.map +1 -1
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/language-select.d.ts +1 -1
- package/dist/components/language-select.d.ts.map +1 -1
- package/dist/components/language-switcher.d.ts +1 -1
- package/dist/components/language-switcher.d.ts.map +1 -1
- package/dist/components/login/login.d.ts +11 -11
- package/dist/components/login/login.d.ts.map +1 -1
- package/dist/components/mode-toggle.d.ts +2 -2
- package/dist/components/mode-toggle.d.ts.map +1 -1
- package/dist/components/nav-secondary.d.ts +1 -1
- package/dist/components/nav-secondary.d.ts.map +1 -1
- package/dist/components/router/blank-slate.d.ts +10 -0
- package/dist/components/router/blank-slate.d.ts.map +1 -1
- package/dist/components/router/gradient-button-link.d.ts +1 -1
- package/dist/components/router/gradient-button-link.d.ts.map +1 -1
- package/dist/components/router/grid.list.d.ts +13 -0
- package/dist/components/router/grid.list.d.ts.map +1 -1
- package/dist/components/router/internal.sidebar.d.ts +27 -2
- package/dist/components/router/internal.sidebar.d.ts.map +1 -1
- package/dist/components/router/loading-provider.d.ts +7 -2
- package/dist/components/router/loading-provider.d.ts.map +1 -1
- package/dist/components/router/nav-main.d.ts +11 -1
- package/dist/components/router/nav-main.d.ts.map +1 -1
- package/dist/components/router/nav-user.d.ts +15 -1
- package/dist/components/router/nav-user.d.ts.map +1 -1
- package/dist/components/router/page-content.d.ts +10 -0
- package/dist/components/router/page-content.d.ts.map +1 -1
- package/dist/components/router/page-header.d.ts +13 -0
- package/dist/components/router/page-header.d.ts.map +1 -1
- package/dist/components/router/page.d.ts +13 -0
- package/dist/components/router/page.d.ts.map +1 -1
- package/dist/components/router/sticky.page.header.d.ts +14 -0
- package/dist/components/router/sticky.page.header.d.ts.map +1 -1
- package/dist/components/router/sub.page.d.ts +15 -11
- package/dist/components/router/sub.page.d.ts.map +1 -1
- package/dist/components/router/sub.page.header.d.ts +13 -0
- package/dist/components/router/sub.page.header.d.ts.map +1 -1
- package/dist/components/startup-first/startup-first.d.ts +11 -11
- package/dist/components/startup-first/startup-first.d.ts.map +1 -1
- package/dist/components/theme-provider.d.ts +1 -1
- package/dist/components/theme-provider.d.ts.map +1 -1
- package/dist/components/ui/avatar.d.ts +3 -3
- package/dist/components/ui/avatar.d.ts.map +1 -1
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/badge.d.ts.map +1 -1
- package/dist/components/ui/breadcrumb.d.ts +7 -7
- package/dist/components/ui/breadcrumb.d.ts.map +1 -1
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/card.d.ts +7 -7
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/checkbox.d.ts +1 -1
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/dialog.d.ts +10 -10
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/drawer.d.ts +10 -10
- package/dist/components/ui/drawer.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.d.ts +15 -15
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/floating-formulas-bg.d.ts +8 -1
- package/dist/components/ui/floating-formulas-bg.d.ts.map +1 -1
- package/dist/components/ui/form-actions.d.ts +4 -4
- package/dist/components/ui/form-actions.d.ts.map +1 -1
- package/dist/components/ui/form.d.ts +8 -8
- package/dist/components/ui/form.d.ts.map +1 -1
- package/dist/components/ui/glass-card.d.ts +1 -1
- package/dist/components/ui/glass-card.d.ts.map +1 -1
- package/dist/components/ui/gradient-button.d.ts +1 -1
- package/dist/components/ui/gradient-button.d.ts.map +1 -1
- package/dist/components/ui/gradient-switch.d.ts +1 -1
- package/dist/components/ui/gradient-switch.d.ts.map +1 -1
- package/dist/components/ui/icon-picker-dialog.d.ts +35 -0
- package/dist/components/ui/icon-picker-dialog.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/input.d.ts +1 -1
- package/dist/components/ui/input.d.ts.map +1 -1
- package/dist/components/ui/label.d.ts +1 -1
- package/dist/components/ui/label.d.ts.map +1 -1
- package/dist/components/ui/navigation-menu.d.ts +8 -8
- package/dist/components/ui/navigation-menu.d.ts.map +1 -1
- package/dist/components/ui/pagination.d.ts +5 -5
- package/dist/components/ui/pagination.d.ts.map +1 -1
- package/dist/components/ui/popover.d.ts +7 -7
- package/dist/components/ui/popover.d.ts.map +1 -1
- package/dist/components/ui/progress.d.ts +1 -1
- package/dist/components/ui/progress.d.ts.map +1 -1
- package/dist/components/ui/pulse-ring.d.ts +1 -1
- package/dist/components/ui/pulse-ring.d.ts.map +1 -1
- package/dist/components/ui/resizable.d.ts +3 -3
- package/dist/components/ui/resizable.d.ts.map +1 -1
- package/dist/components/ui/section-card.d.ts +7 -7
- package/dist/components/ui/section-card.d.ts.map +1 -1
- package/dist/components/ui/select.d.ts +10 -10
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/separator.d.ts +1 -1
- package/dist/components/ui/separator.d.ts.map +1 -1
- package/dist/components/ui/sheet.d.ts +8 -8
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sidebar.d.ts +23 -23
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/skeleton.d.ts +1 -1
- package/dist/components/ui/skeleton.d.ts.map +1 -1
- package/dist/components/ui/slider.d.ts +1 -1
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/sonner.d.ts +1 -1
- package/dist/components/ui/sonner.d.ts.map +1 -1
- package/dist/components/ui/stepper.d.ts +3 -3
- package/dist/components/ui/stepper.d.ts.map +1 -1
- package/dist/components/ui/sticky-save-bar.d.ts +2 -2
- package/dist/components/ui/sticky-save-bar.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +1 -1
- package/dist/components/ui/switch.d.ts.map +1 -1
- package/dist/components/ui/table.d.ts +8 -8
- package/dist/components/ui/table.d.ts.map +1 -1
- package/dist/components/ui/tabs.d.ts +4 -4
- package/dist/components/ui/tabs.d.ts.map +1 -1
- package/dist/components/ui/textarea.d.ts +1 -1
- package/dist/components/ui/textarea.d.ts.map +1 -1
- package/dist/components/ui/toggle-group.d.ts +2 -2
- package/dist/components/ui/toggle-group.d.ts.map +1 -1
- package/dist/components/ui/toggle.d.ts +1 -1
- package/dist/components/ui/toggle.d.ts.map +1 -1
- package/dist/components/ui/tooltip.d.ts +4 -4
- package/dist/components/ui/tooltip.d.ts.map +1 -1
- package/dist/components/ui/user-avatar.d.ts +1 -1
- package/dist/components/ui/user-avatar.d.ts.map +1 -1
- package/dist/components/ui/user-menu.d.ts +1 -1
- package/dist/components/ui/user-menu.d.ts.map +1 -1
- package/dist/components/viglet-app-switcher.d.ts +1 -1
- package/dist/components/viglet-app-switcher.d.ts.map +1 -1
- package/dist/contexts/breadcrumb.context.d.ts +1 -1
- package/dist/contexts/breadcrumb.context.d.ts.map +1 -1
- package/dist/contexts/user.context.d.ts +25 -1
- package/dist/contexts/user.context.d.ts.map +1 -1
- package/dist/exports.json +404 -0
- package/dist/floating-formulas-bg.cjs +1 -0
- package/dist/floating-formulas-bg.css +21 -0
- package/dist/floating-formulas-bg.es.js +83 -56
- package/dist/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-greek-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
- package/dist/fonts/plus-jakarta-sans-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/plus-jakarta-sans-latin-ext-wght-normal.woff2 +0 -0
- package/dist/fonts/plus-jakarta-sans-latin-wght-normal.woff2 +0 -0
- package/dist/fonts/plus-jakarta-sans-vietnamese-wght-normal.woff2 +0 -0
- package/dist/fonts.css +126 -0
- package/dist/hooks/use-grid-adapter.d.ts.map +1 -1
- package/dist/hooks/use-mobile.d.ts +10 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -1
- package/dist/hooks/use-sub-page-breadcrumb.d.ts.map +1 -1
- package/dist/i18n/index.d.ts +136 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/locales/en/bento.json.d.ts +51 -0
- package/dist/i18n/locales/en/common.json.d.ts +7 -1
- package/dist/i18n/locales/en/forms.json.d.ts +15 -1
- package/dist/i18n/locales/en/nav.json.d.ts +3 -1
- package/dist/i18n/locales/pt/bento.json.d.ts +51 -0
- package/dist/i18n/locales/pt/common.json.d.ts +7 -1
- package/dist/i18n/locales/pt/forms.json.d.ts +15 -1
- package/dist/i18n/locales/pt/nav.json.d.ts +3 -1
- package/dist/i18n-DoNdMLEd.cjs +1 -0
- package/dist/{i18n-C94rDRaM.js → i18n-DuNITbWa.js} +155 -27
- package/dist/{i18n.cjs.js → i18n.cjs} +1 -1
- package/dist/i18n.es.js +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +512 -770
- package/dist/lib/axios.d.ts.map +1 -1
- package/dist/lib/export-xlsx.d.ts +7 -1
- package/dist/lib/export-xlsx.d.ts.map +1 -1
- package/dist/lib/react-markers.d.ts +17 -0
- package/dist/lib/react-markers.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +22 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/loading-provider-1mgM91iY.cjs +1 -0
- package/dist/loading-provider-CMnOuvdR.js +224 -0
- package/dist/preset.css +103 -3
- package/dist/products-DL_YYXkV.cjs +1 -0
- package/dist/products-Du9KB6Xl.js +9 -0
- package/dist/{chunk-CMqjfN_6.cjs → rolldown-runtime-BocRIvOZ.cjs} +1 -1
- package/dist/router.cjs +1 -0
- package/dist/router.es.js +361 -558
- package/dist/user.context-kPAqKN4o.js +512 -0
- package/dist/user.context-r50nSWER.cjs +1 -0
- package/dist/viglet-design-system.css +1 -1
- package/dist/vite/boot-loader.d.ts +14 -4
- package/dist/vite/boot-loader.d.ts.map +1 -1
- package/dist/{vite.cjs.js → vite.cjs} +8 -8
- package/dist/vite.es.js +29 -16
- package/package.json +67 -23
- package/scripts/check-duplicates.mjs +198 -0
- package/dist/breadcrumb.context-BF0x4--Z.cjs +0 -7
- package/dist/breadcrumb.context-CCiYXxir.js +0 -1501
- package/dist/floating-formulas-bg.cjs.js +0 -1
- package/dist/i18n-CmYeG6uh.cjs +0 -1
- package/dist/index.cjs.js +0 -1
- package/dist/router.cjs.js +0 -1
|
@@ -20,15 +20,24 @@ export interface VigletBootLoaderOptions {
|
|
|
20
20
|
title: string;
|
|
21
21
|
/** Uppercase subtitle under the title, e.g. `"Enterprise Search Intelligence"`. */
|
|
22
22
|
subtitle: string;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Accent hex color (light mode), e.g. `"#4169E1"` or `"#41E"`.
|
|
25
|
+
*
|
|
26
|
+
* Hex only, and enforced: the value is used raw in the gradients and parsed
|
|
27
|
+
* into an `r, g, b` triplet for the rgba tints, so anything the parser cannot
|
|
28
|
+
* read would render the loader in two different accents. A named colour or an
|
|
29
|
+
* `rgb()`/`hsl()` string throws rather than half-applying.
|
|
30
|
+
*/
|
|
24
31
|
color: string;
|
|
25
|
-
/** Accent hex color in dark mode
|
|
32
|
+
/** Accent hex color in dark mode, under the same rule as `color`. Defaults to `color`. */
|
|
26
33
|
colorDark?: string;
|
|
27
34
|
/**
|
|
28
35
|
* CSS class prefix applied to every rule and keyframe to avoid collisions
|
|
29
36
|
* (rings, mark, molecules, gas, progress, etc). Default: `"viglet"`.
|
|
30
37
|
*
|
|
31
|
-
* Must be a
|
|
38
|
+
* Must be a CSS identifier — a letter, then letters, digits, `-` or `_`. It is
|
|
39
|
+
* interpolated into every selector and keyframe name, so a value outside that
|
|
40
|
+
* throws instead of emitting rules of its own.
|
|
32
41
|
*/
|
|
33
42
|
prefix?: string;
|
|
34
43
|
/** `localStorage` key used to detect the stored theme. Default: `"vite-ui-theme"`. */
|
|
@@ -46,7 +55,8 @@ export interface VigletBootLoaderOptions {
|
|
|
46
55
|
* it inside `<div id="root">` in your `index.html` (or `marketing.html`).
|
|
47
56
|
*
|
|
48
57
|
* Default: `"<!--viglet-boot-loader-->"`. If not found, the plugin falls
|
|
49
|
-
* back to injecting right after the opening `<div id="root">` tag
|
|
58
|
+
* back to injecting right after the opening `<div id="root">` tag, and warns
|
|
59
|
+
* on the console when the page offers neither.
|
|
50
60
|
*/
|
|
51
61
|
placeholder?: string;
|
|
52
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boot-loader.d.ts","sourceRoot":"","sources":["../../src/vite/boot-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,MAAM,EAAE,MAAM,MAAM,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB
|
|
1
|
+
{"version":3,"file":"boot-loader.d.ts","sourceRoot":"","sources":["../../src/vite/boot-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,MAAM,EAAE,MAAM,MAAM,CAAC;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAsEzE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){let{title:
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){let{title:n,subtitle:o,color:s,colorDark:c=s,prefix:l=`viglet`,storageKey:u=`vite-ui-theme`,testFlag:d=`__VIGLET_LOADING_TEST__`,placeholder:f=`<!--viglet-boot-loader-->`}=e,p=t(s,`color`),m=t(c,`colorDark`);if(!/^[a-zA-Z][\w-]*$/.test(l))throw Error(`vigletBootLoader: prefix must start with a letter and hold only letters, digits, "-" or "_" — received ${JSON.stringify(l)}.`);let h={pfx:l,title:n,subtitle:o,color:s,colorDark:c,rgb:p,rgbDark:m,storageKey:u,testFlag:d},g=r(h),_=i(h),v=a(h);return{name:`viglet-boot-loader`,transformIndexHtml(e){let t;if(e.includes(f))t=e.replace(f,()=>v);else{let n=/(<div\b[^>]*\bid=["']root["'][^>]*>)/;n.test(e)?t=e.replace(n,e=>`${e}\n${v}\n`):(console.warn(`[viglet-boot-loader] no injection point found: the HTML holds neither the ${f} placeholder nor a <div id="root">, so no boot loader was injected.`),t=e)}return{html:t,tags:[{tag:`style`,attrs:{"data-viglet-boot-loader":``},children:g,injectTo:`head`},{tag:`script`,children:_,injectTo:`head`}]}}}}function t(e,t){let r=n(e);if(r)return r;throw Error(`vigletBootLoader: ${t} must be a hex colour like "#4169E1" or "#41E" — received ${JSON.stringify(e)}. Named CSS colours and rgb()/hsl() cannot be read for the loader's rgba tints.`)}function n(e){if(!e)return null;let t=/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(e.trim());if(t){let[,e,n,r]=t;return`${Number.parseInt(e+e,16)}, ${Number.parseInt(n+n,16)}, ${Number.parseInt(r+r,16)}`}let n=/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(e.trim());if(n){let[,e,t,r]=n;return`${Number.parseInt(e,16)}, ${Number.parseInt(t,16)}, ${Number.parseInt(r,16)}`}return null}function r({pfx:e,color:t,colorDark:n,rgb:r}){return`
|
|
2
2
|
html, body { margin: 0; padding: 0; height: 100%; }
|
|
3
3
|
/* Boot-loader paints body only for the pre-React loading screen. It must
|
|
4
4
|
NOT own "body { color }": that rule is unlayered, so it beats the app's
|
|
@@ -140,7 +140,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e)
|
|
|
140
140
|
border-radius: 999px; box-shadow: 0 4px 12px rgba(220, 38, 38, 0.35);
|
|
141
141
|
z-index: 10000;
|
|
142
142
|
}
|
|
143
|
-
`.trim()}function
|
|
143
|
+
`.trim()}function i({pfx:e,storageKey:t,testFlag:n}){return`
|
|
144
144
|
(function () {
|
|
145
145
|
try {
|
|
146
146
|
var stored = localStorage.getItem(${JSON.stringify(t)});
|
|
@@ -166,14 +166,14 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e)
|
|
|
166
166
|
}
|
|
167
167
|
} catch (e) { /* ignore */ }
|
|
168
168
|
})();
|
|
169
|
-
`.trim()}function
|
|
170
|
-
<div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="Loading ${
|
|
169
|
+
`.trim()}function a({pfx:e,title:t,subtitle:n}){return`
|
|
170
|
+
<div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="Loading ${o(t)}">
|
|
171
171
|
<div class="${e}-boot-stage">
|
|
172
172
|
<div class="${e}-boot-ring"></div>
|
|
173
173
|
<div class="${e}-boot-ring delay-1"></div>
|
|
174
174
|
<div class="${e}-boot-ring delay-2"></div>
|
|
175
175
|
<div class="${e}-boot-ring delay-3"></div>
|
|
176
|
-
<div class="${e}-boot-logo-mark" aria-label="${
|
|
176
|
+
<div class="${e}-boot-logo-mark" aria-label="${o(t)}">
|
|
177
177
|
<svg class="${e}-boot-molecules" viewBox="0 0 100 100" aria-hidden="true">
|
|
178
178
|
<g class="${e}-boot-molecule m-1">
|
|
179
179
|
<line x1="28" y1="50" x2="72" y2="50" />
|
|
@@ -223,9 +223,9 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e)
|
|
|
223
223
|
</div>
|
|
224
224
|
</div>
|
|
225
225
|
<div class="${e}-boot-text">
|
|
226
|
-
<div class="${e}-boot-title">${
|
|
227
|
-
<div class="${e}-boot-subtitle">${
|
|
226
|
+
<div class="${e}-boot-title">${o(t)}</div>
|
|
227
|
+
<div class="${e}-boot-subtitle">${o(n)}</div>
|
|
228
228
|
</div>
|
|
229
229
|
<div class="${e}-boot-progress" aria-hidden="true"></div>
|
|
230
230
|
</div>
|
|
231
|
-
`.trim()}function
|
|
231
|
+
`.trim()}function o(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}exports.vigletBootLoader=e;
|
package/dist/vite.es.js
CHANGED
|
@@ -1,36 +1,49 @@
|
|
|
1
1
|
//#region src/vite/boot-loader.ts
|
|
2
2
|
function e(e) {
|
|
3
|
-
let { title:
|
|
3
|
+
let { title: n, subtitle: o, color: s, colorDark: c = s, prefix: l = "viglet", storageKey: u = "vite-ui-theme", testFlag: d = "__VIGLET_LOADING_TEST__", placeholder: f = "<!--viglet-boot-loader-->" } = e, p = t(s, "color"), m = t(c, "colorDark");
|
|
4
|
+
if (!/^[a-zA-Z][\w-]*$/.test(l)) throw Error(`vigletBootLoader: prefix must start with a letter and hold only letters, digits, "-" or "_" — received ${JSON.stringify(l)}.`);
|
|
5
|
+
let h = {
|
|
4
6
|
pfx: l,
|
|
5
|
-
title:
|
|
7
|
+
title: n,
|
|
6
8
|
subtitle: o,
|
|
7
9
|
color: s,
|
|
8
10
|
colorDark: c,
|
|
9
11
|
rgb: p,
|
|
10
|
-
rgbDark:
|
|
12
|
+
rgbDark: m,
|
|
11
13
|
storageKey: u,
|
|
12
14
|
testFlag: d
|
|
13
|
-
},
|
|
15
|
+
}, g = r(h), _ = i(h), v = a(h);
|
|
14
16
|
return {
|
|
15
17
|
name: "viglet-boot-loader",
|
|
16
18
|
transformIndexHtml(e) {
|
|
19
|
+
let t;
|
|
20
|
+
if (e.includes(f)) t = e.replace(f, () => v);
|
|
21
|
+
else {
|
|
22
|
+
let n = /(<div\b[^>]*\bid=["']root["'][^>]*>)/;
|
|
23
|
+
n.test(e) ? t = e.replace(n, (e) => `${e}\n${v}\n`) : (console.warn(`[viglet-boot-loader] no injection point found: the HTML holds neither the ${f} placeholder nor a <div id="root">, so no boot loader was injected.`), t = e);
|
|
24
|
+
}
|
|
17
25
|
return {
|
|
18
|
-
html:
|
|
26
|
+
html: t,
|
|
19
27
|
tags: [{
|
|
20
28
|
tag: "style",
|
|
21
29
|
attrs: { "data-viglet-boot-loader": "" },
|
|
22
|
-
children:
|
|
30
|
+
children: g,
|
|
23
31
|
injectTo: "head"
|
|
24
32
|
}, {
|
|
25
33
|
tag: "script",
|
|
26
|
-
children:
|
|
34
|
+
children: _,
|
|
27
35
|
injectTo: "head"
|
|
28
36
|
}]
|
|
29
37
|
};
|
|
30
38
|
}
|
|
31
39
|
};
|
|
32
40
|
}
|
|
33
|
-
function t(e) {
|
|
41
|
+
function t(e, t) {
|
|
42
|
+
let r = n(e);
|
|
43
|
+
if (r) return r;
|
|
44
|
+
throw Error(`vigletBootLoader: ${t} must be a hex colour like "#4169E1" or "#41E" — received ${JSON.stringify(e)}. Named CSS colours and rgb()/hsl() cannot be read for the loader's rgba tints.`);
|
|
45
|
+
}
|
|
46
|
+
function n(e) {
|
|
34
47
|
if (!e) return null;
|
|
35
48
|
let t = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(e.trim());
|
|
36
49
|
if (t) {
|
|
@@ -44,7 +57,7 @@ function t(e) {
|
|
|
44
57
|
}
|
|
45
58
|
return null;
|
|
46
59
|
}
|
|
47
|
-
function
|
|
60
|
+
function r({ pfx: e, color: t, colorDark: n, rgb: r }) {
|
|
48
61
|
return `
|
|
49
62
|
html, body { margin: 0; padding: 0; height: 100%; }
|
|
50
63
|
/* Boot-loader paints body only for the pre-React loading screen. It must
|
|
@@ -189,7 +202,7 @@ function n({ pfx: e, color: t, colorDark: n, rgb: r }) {
|
|
|
189
202
|
}
|
|
190
203
|
`.trim();
|
|
191
204
|
}
|
|
192
|
-
function
|
|
205
|
+
function i({ pfx: e, storageKey: t, testFlag: n }) {
|
|
193
206
|
return `
|
|
194
207
|
(function () {
|
|
195
208
|
try {
|
|
@@ -218,15 +231,15 @@ function r({ pfx: e, storageKey: t, testFlag: n }) {
|
|
|
218
231
|
})();
|
|
219
232
|
`.trim();
|
|
220
233
|
}
|
|
221
|
-
function
|
|
234
|
+
function a({ pfx: e, title: t, subtitle: n }) {
|
|
222
235
|
return `
|
|
223
|
-
<div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="Loading ${
|
|
236
|
+
<div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="Loading ${o(t)}">
|
|
224
237
|
<div class="${e}-boot-stage">
|
|
225
238
|
<div class="${e}-boot-ring"></div>
|
|
226
239
|
<div class="${e}-boot-ring delay-1"></div>
|
|
227
240
|
<div class="${e}-boot-ring delay-2"></div>
|
|
228
241
|
<div class="${e}-boot-ring delay-3"></div>
|
|
229
|
-
<div class="${e}-boot-logo-mark" aria-label="${
|
|
242
|
+
<div class="${e}-boot-logo-mark" aria-label="${o(t)}">
|
|
230
243
|
<svg class="${e}-boot-molecules" viewBox="0 0 100 100" aria-hidden="true">
|
|
231
244
|
<g class="${e}-boot-molecule m-1">
|
|
232
245
|
<line x1="28" y1="50" x2="72" y2="50" />
|
|
@@ -276,14 +289,14 @@ function i({ pfx: e, title: t, subtitle: n }) {
|
|
|
276
289
|
</div>
|
|
277
290
|
</div>
|
|
278
291
|
<div class="${e}-boot-text">
|
|
279
|
-
<div class="${e}-boot-title">${
|
|
280
|
-
<div class="${e}-boot-subtitle">${
|
|
292
|
+
<div class="${e}-boot-title">${o(t)}</div>
|
|
293
|
+
<div class="${e}-boot-subtitle">${o(n)}</div>
|
|
281
294
|
</div>
|
|
282
295
|
<div class="${e}-boot-progress" aria-hidden="true"></div>
|
|
283
296
|
</div>
|
|
284
297
|
`.trim();
|
|
285
298
|
}
|
|
286
|
-
function
|
|
299
|
+
function o(e) {
|
|
287
300
|
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
288
301
|
}
|
|
289
302
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viglet/viglet-design-system",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Viglet Design System - Shared components, hooks, utilities and design tokens for Viglet products",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -12,54 +12,64 @@
|
|
|
12
12
|
"access": "public",
|
|
13
13
|
"registry": "https://registry.npmjs.org"
|
|
14
14
|
},
|
|
15
|
-
"main": "./dist/index.cjs
|
|
15
|
+
"main": "./dist/index.cjs",
|
|
16
16
|
"module": "./dist/index.es.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
21
21
|
"import": "./dist/index.es.js",
|
|
22
|
-
"require": "./dist/index.cjs
|
|
22
|
+
"require": "./dist/index.cjs"
|
|
23
23
|
},
|
|
24
|
+
"./bento": {
|
|
25
|
+
"types": "./dist/bento/index.d.ts",
|
|
26
|
+
"import": "./dist/bento.es.js",
|
|
27
|
+
"require": "./dist/bento.cjs"
|
|
28
|
+
},
|
|
29
|
+
"./bento.css": "./dist/bento.css",
|
|
30
|
+
"./assets": {
|
|
31
|
+
"types": "./dist/assets/products/index.d.ts",
|
|
32
|
+
"import": "./dist/assets.es.js",
|
|
33
|
+
"require": "./dist/assets.cjs"
|
|
34
|
+
},
|
|
35
|
+
"./exports.json": "./dist/exports.json",
|
|
24
36
|
"./styles": "./dist/viglet-design-system.css",
|
|
37
|
+
"./fonts": "./dist/fonts.css",
|
|
38
|
+
"./fonts.css": "./dist/fonts.css",
|
|
25
39
|
"./preset": "./dist/preset.css",
|
|
26
40
|
"./preset.css": "./dist/preset.css",
|
|
27
41
|
"./i18n": {
|
|
28
42
|
"types": "./dist/i18n/index.d.ts",
|
|
29
43
|
"import": "./dist/i18n.es.js",
|
|
30
|
-
"require": "./dist/i18n.cjs
|
|
44
|
+
"require": "./dist/i18n.cjs"
|
|
31
45
|
},
|
|
32
46
|
"./router": {
|
|
33
47
|
"types": "./dist/router.d.ts",
|
|
34
48
|
"import": "./dist/router.es.js",
|
|
35
|
-
"require": "./dist/router.cjs
|
|
49
|
+
"require": "./dist/router.cjs"
|
|
36
50
|
},
|
|
37
51
|
"./floating-formulas-bg": {
|
|
38
52
|
"types": "./dist/components/ui/floating-formulas-bg.d.ts",
|
|
39
53
|
"import": "./dist/floating-formulas-bg.es.js",
|
|
40
|
-
"require": "./dist/floating-formulas-bg.cjs
|
|
54
|
+
"require": "./dist/floating-formulas-bg.cjs"
|
|
41
55
|
},
|
|
42
56
|
"./floating-formulas-bg.css": "./dist/floating-formulas-bg.css",
|
|
43
57
|
"./vite": {
|
|
44
58
|
"types": "./dist/vite/index.d.ts",
|
|
45
59
|
"import": "./dist/vite.es.js",
|
|
46
|
-
"require": "./dist/vite.cjs
|
|
60
|
+
"require": "./dist/vite.cjs"
|
|
47
61
|
}
|
|
48
62
|
},
|
|
63
|
+
"bin": {
|
|
64
|
+
"viglet-ds-check-duplicates": "./scripts/check-duplicates.mjs"
|
|
65
|
+
},
|
|
49
66
|
"files": [
|
|
50
|
-
"dist"
|
|
67
|
+
"dist",
|
|
68
|
+
"scripts/check-duplicates.mjs"
|
|
51
69
|
],
|
|
52
70
|
"sideEffects": [
|
|
53
71
|
"**/*.css"
|
|
54
72
|
],
|
|
55
|
-
"scripts": {
|
|
56
|
-
"dev": "vite build --watch",
|
|
57
|
-
"build": "tsc -b && node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && vite build && node -e \"require('fs').cpSync('src/styles/preset.css','dist/preset.css')\"",
|
|
58
|
-
"lint": "eslint .",
|
|
59
|
-
"storybook": "storybook dev -p 6006",
|
|
60
|
-
"build-storybook": "storybook build",
|
|
61
|
-
"prepublishOnly": "npm run build"
|
|
62
|
-
},
|
|
63
73
|
"peerDependencies": {
|
|
64
74
|
"i18next": ">=25.0.0",
|
|
65
75
|
"i18next-browser-languagedetector": ">=8.0.0",
|
|
@@ -76,6 +86,9 @@
|
|
|
76
86
|
}
|
|
77
87
|
},
|
|
78
88
|
"dependencies": {
|
|
89
|
+
"@dnd-kit/core": "^6.3.1",
|
|
90
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
91
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
79
92
|
"@fontsource-variable/inter": "^5.2.8",
|
|
80
93
|
"@fontsource-variable/plus-jakarta-sans": "^5.2.8",
|
|
81
94
|
"@iconify/react": "^6.0.2",
|
|
@@ -98,7 +111,7 @@
|
|
|
98
111
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
|
99
112
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
100
113
|
"@tabler/icons-react": "^3.40.0",
|
|
101
|
-
"@tanstack/react-table": "^
|
|
114
|
+
"@tanstack/react-table": "^9.1.2",
|
|
102
115
|
"axios": "^1.13.6",
|
|
103
116
|
"class-variance-authority": "^0.7.1",
|
|
104
117
|
"clsx": "^2.1.1",
|
|
@@ -116,28 +129,59 @@
|
|
|
116
129
|
"@storybook/addon-a11y": "^10.3.5",
|
|
117
130
|
"@storybook/addon-docs": "^10.3.5",
|
|
118
131
|
"@storybook/addon-themes": "^10.3.5",
|
|
132
|
+
"@storybook/addon-vitest": "10.5.10",
|
|
119
133
|
"@storybook/react-vite": "^10.3.5",
|
|
120
134
|
"@tailwindcss/typography": "^0.5.19",
|
|
121
135
|
"@tailwindcss/vite": "^4.2.2",
|
|
122
|
-
"@
|
|
136
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
137
|
+
"@testing-library/react": "^16.3.2",
|
|
138
|
+
"@testing-library/user-event": "^14.6.6",
|
|
139
|
+
"@types/node": "^26.0.1",
|
|
123
140
|
"@types/react": "^19.2.14",
|
|
124
141
|
"@types/react-dom": "^19.2.3",
|
|
142
|
+
"@types/semver": "^7.8.0",
|
|
125
143
|
"@vitejs/plugin-react": "^6.0.1",
|
|
144
|
+
"@vitest/browser": "^4.1.11",
|
|
145
|
+
"@vitest/browser-playwright": "^4.1.11",
|
|
126
146
|
"eslint": "^9.39.0",
|
|
127
147
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
128
148
|
"eslint-plugin-react-refresh": "^0.5.2",
|
|
129
149
|
"globals": "^17.4.0",
|
|
150
|
+
"i18next": "^26.4.0",
|
|
151
|
+
"i18next-browser-languagedetector": "^8.2.1",
|
|
152
|
+
"jsdom": "^30.0.1",
|
|
153
|
+
"next-themes": "^0.4.6",
|
|
154
|
+
"playwright": "^1.62.1",
|
|
155
|
+
"react-i18next": "^17.0.12",
|
|
130
156
|
"react-router-dom": "^7.0.0",
|
|
157
|
+
"semver": "^7.8.5",
|
|
158
|
+
"sonner": "^2.0.8",
|
|
131
159
|
"storybook": "^10.3.5",
|
|
132
160
|
"tailwindcss": "^4.1.11",
|
|
133
161
|
"tw-animate-css": "^1.4.0",
|
|
134
|
-
"typescript": "~6.0.
|
|
162
|
+
"typescript": "~6.0.3",
|
|
135
163
|
"typescript-eslint": "^8.58.0",
|
|
136
164
|
"vite": "^8.0.8",
|
|
137
|
-
"vite-plugin-dts": "^5.0.0"
|
|
165
|
+
"vite-plugin-dts": "^5.0.0",
|
|
166
|
+
"vitest": "^4.1.11"
|
|
138
167
|
},
|
|
139
168
|
"engines": {
|
|
140
|
-
"node": "
|
|
141
|
-
"
|
|
169
|
+
"node": ">=26",
|
|
170
|
+
"pnpm": ">=11"
|
|
171
|
+
},
|
|
172
|
+
"scripts": {
|
|
173
|
+
"dev": "vite build --watch",
|
|
174
|
+
"build": "tsc -b && node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && vite build && node -e \"require('fs').cpSync('src/styles/preset.css','dist/preset.css')\" && node scripts/build-fonts.mjs && node scripts/emit-exports.mjs && node scripts/check-dist.mjs && node scripts/check-exports.mjs && node scripts/check-size.mjs",
|
|
175
|
+
"check:dist": "node scripts/check-dist.mjs",
|
|
176
|
+
"check:size": "node scripts/check-size.mjs",
|
|
177
|
+
"typecheck": "tsc -b --force",
|
|
178
|
+
"lint": "eslint . --max-warnings 0",
|
|
179
|
+
"test": "vitest run",
|
|
180
|
+
"test:watch": "vitest",
|
|
181
|
+
"use:local": "node scripts/use-local.mjs",
|
|
182
|
+
"storybook": "storybook dev -p 6006",
|
|
183
|
+
"build-storybook": "storybook build",
|
|
184
|
+
"build:fonts": "node scripts/build-fonts.mjs",
|
|
185
|
+
"check:exports": "node scripts/check-exports.mjs"
|
|
142
186
|
}
|
|
143
|
-
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// VDS5 — fail a consumer's build when it declares a component this package
|
|
3
|
+
// already exports, and name the import that replaces it.
|
|
4
|
+
//
|
|
5
|
+
// Run it from a product checkout, in that product's CI:
|
|
6
|
+
//
|
|
7
|
+
// viglet-ds-check-duplicates # scan ./src
|
|
8
|
+
// viglet-ds-check-duplicates src app # scan these directories
|
|
9
|
+
// viglet-ds-check-duplicates --json # machine-readable findings
|
|
10
|
+
// viglet-ds-check-duplicates --warn # report, but exit 0
|
|
11
|
+
// viglet-ds-check-duplicates --manifest p # read the export list from p
|
|
12
|
+
//
|
|
13
|
+
// Reporting that a duplicate exists is not the useful half. A local copy is
|
|
14
|
+
// written because the author did not know the shared one existed, so the finding
|
|
15
|
+
// has to end in the line they would have written instead — which is why the
|
|
16
|
+
// manifest records the specifier per entry point rather than just a list of
|
|
17
|
+
// names.
|
|
18
|
+
//
|
|
19
|
+
// A one-line re-export shim is the sanctioned pattern and is not a duplicate:
|
|
20
|
+
// files that re-export from this package are skipped.
|
|
21
|
+
//
|
|
22
|
+
// Some collisions are deliberate — Shio's AppFooter renders Shio's own build
|
|
23
|
+
// version and merely shares a name. Keep those by writing, anywhere in the file:
|
|
24
|
+
//
|
|
25
|
+
// // viglet-ds-allow-duplicate AppFooter -- renders Shio's build version
|
|
26
|
+
//
|
|
27
|
+
// The reason is the point. A gate with no way to say "this one is mine" is a
|
|
28
|
+
// gate somebody deletes.
|
|
29
|
+
|
|
30
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"
|
|
31
|
+
import { createRequire } from "node:module"
|
|
32
|
+
import { dirname, join, relative, resolve } from "node:path"
|
|
33
|
+
import { fileURLToPath } from "node:url"
|
|
34
|
+
|
|
35
|
+
const PACKAGE_NAME = "@viglet/viglet-design-system"
|
|
36
|
+
const EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs"])
|
|
37
|
+
const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build", "out", "coverage", ".next"])
|
|
38
|
+
|
|
39
|
+
const args = process.argv.slice(2)
|
|
40
|
+
const asJson = args.includes("--json")
|
|
41
|
+
const warnOnly = args.includes("--warn")
|
|
42
|
+
const manifestFlag = args.indexOf("--manifest")
|
|
43
|
+
const manifestPath = manifestFlag === -1 ? null : args[manifestFlag + 1]
|
|
44
|
+
const roots = args.filter(
|
|
45
|
+
(a, i) => !a.startsWith("--") && i !== manifestFlag + 1,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
function loadManifest() {
|
|
49
|
+
// An explicit path wins: it is how this repository's own tests pin a fixture,
|
|
50
|
+
// and how a monorepo checks against a version other than the hoisted one.
|
|
51
|
+
if (manifestPath) {
|
|
52
|
+
if (!existsSync(manifestPath)) {
|
|
53
|
+
console.error(`check-duplicates: no manifest at ${manifestPath}`)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
return JSON.parse(readFileSync(manifestPath, "utf8"))
|
|
57
|
+
}
|
|
58
|
+
// Installed in the consumer.
|
|
59
|
+
const require = createRequire(join(process.cwd(), "package.json"))
|
|
60
|
+
try {
|
|
61
|
+
return require(`${PACKAGE_NAME}/exports.json`)
|
|
62
|
+
} catch {
|
|
63
|
+
/* fall through */
|
|
64
|
+
}
|
|
65
|
+
// Running from this repository against its own dist.
|
|
66
|
+
const local = resolve(dirname(fileURLToPath(import.meta.url)), "..", "dist", "exports.json")
|
|
67
|
+
if (existsSync(local)) return JSON.parse(readFileSync(local, "utf8"))
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const manifest = loadManifest()
|
|
72
|
+
if (!manifest) {
|
|
73
|
+
console.error(
|
|
74
|
+
`check-duplicates: could not read ${PACKAGE_NAME}/exports.json.\n` +
|
|
75
|
+
`Install ${PACKAGE_NAME} (>= the version that ships the manifest) and re-run.`,
|
|
76
|
+
)
|
|
77
|
+
process.exit(1)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// name -> the specifier that exports it. The root entry wins when a name appears
|
|
81
|
+
// in more than one, since that is the import a product would write.
|
|
82
|
+
const exported = new Map()
|
|
83
|
+
for (const [subpath, entry] of Object.entries(manifest.entries)) {
|
|
84
|
+
for (const name of [...entry.values, ...entry.types]) {
|
|
85
|
+
const isType = entry.types.includes(name)
|
|
86
|
+
if (!exported.has(name) || subpath === ".") {
|
|
87
|
+
exported.set(name, { specifier: entry.specifier, isType })
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function collect(dir, files = []) {
|
|
93
|
+
let dirents
|
|
94
|
+
try {
|
|
95
|
+
dirents = readdirSync(dir, { withFileTypes: true })
|
|
96
|
+
} catch {
|
|
97
|
+
return files
|
|
98
|
+
}
|
|
99
|
+
for (const entry of dirents) {
|
|
100
|
+
const full = join(dir, entry.name)
|
|
101
|
+
if (entry.isDirectory()) {
|
|
102
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) collect(full, files)
|
|
103
|
+
} else if (EXTENSIONS.has(entry.name.slice(entry.name.lastIndexOf(".")))) {
|
|
104
|
+
files.push(full)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return files
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// `export const X`, `export function X`, `export class X`, `export type X`,
|
|
111
|
+
// `export interface X`, and the names inside a local `export { A, B as C }`.
|
|
112
|
+
const DECLARED =
|
|
113
|
+
/^\s*export\s+(?:declare\s+)?(?:default\s+)?(?:abstract\s+)?(?:const|let|var|function\*?|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/gm
|
|
114
|
+
const EXPORT_LIST = /^\s*export\s+(?:type\s+)?\{([^}]*)\}\s*(?!from)[;\n]/gm
|
|
115
|
+
|
|
116
|
+
function declaredNames(source) {
|
|
117
|
+
const names = new Map()
|
|
118
|
+
for (const match of source.matchAll(DECLARED)) {
|
|
119
|
+
names.set(match[1], lineOf(source, match.index))
|
|
120
|
+
}
|
|
121
|
+
for (const match of source.matchAll(EXPORT_LIST)) {
|
|
122
|
+
for (const clause of match[1].split(",")) {
|
|
123
|
+
// `A as B` exports B; a bare `A` exports A.
|
|
124
|
+
const name = clause.includes(" as ")
|
|
125
|
+
? clause.split(" as ").pop().trim()
|
|
126
|
+
: clause.trim()
|
|
127
|
+
if (/^[A-Za-z_$][\w$]*$/.test(name) && name !== "default") {
|
|
128
|
+
names.set(name, lineOf(source, match.index))
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return names
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function lineOf(source, index) {
|
|
136
|
+
return source.slice(0, index).split("\n").length
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const scanRoots = (roots.length ? roots : ["src"]).map((r) => resolve(r))
|
|
140
|
+
const missing = scanRoots.filter((r) => !existsSync(r) || !statSync(r).isDirectory())
|
|
141
|
+
if (missing.length === scanRoots.length) {
|
|
142
|
+
console.error(
|
|
143
|
+
`check-duplicates: nothing to scan (${scanRoots.map((r) => relative(process.cwd(), r)).join(", ")}).\n` +
|
|
144
|
+
"Pass the source directories explicitly: viglet-ds-check-duplicates <dir> [dir]",
|
|
145
|
+
)
|
|
146
|
+
process.exit(1)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const findings = []
|
|
150
|
+
let scanned = 0
|
|
151
|
+
for (const root of scanRoots) {
|
|
152
|
+
for (const file of collect(root)) {
|
|
153
|
+
const source = readFileSync(file, "utf8")
|
|
154
|
+
scanned++
|
|
155
|
+
// A re-export shim is the sanctioned pattern, not a duplicate.
|
|
156
|
+
if (source.includes(`from "${PACKAGE_NAME}`) || source.includes(`from '${PACKAGE_NAME}`)) {
|
|
157
|
+
if (/^\s*export\s+(?:\*|\{)/m.test(source)) continue
|
|
158
|
+
}
|
|
159
|
+
const allowed = new Set(
|
|
160
|
+
[...source.matchAll(/viglet-ds-allow-duplicate\s+([A-Za-z_$][\w$]*)/g)].map((m) => m[1]),
|
|
161
|
+
)
|
|
162
|
+
for (const [name, line] of declaredNames(source)) {
|
|
163
|
+
const match = exported.get(name)
|
|
164
|
+
if (!match || allowed.has(name)) continue
|
|
165
|
+
findings.push({
|
|
166
|
+
file: relative(process.cwd(), file).replace(/\\/g, "/"),
|
|
167
|
+
line,
|
|
168
|
+
name,
|
|
169
|
+
replacement: match.isType
|
|
170
|
+
? `import type { ${name} } from "${match.specifier}"`
|
|
171
|
+
: `import { ${name} } from "${match.specifier}"`,
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (asJson) {
|
|
178
|
+
console.log(JSON.stringify({ scanned, findings }, null, 2))
|
|
179
|
+
} else if (findings.length === 0) {
|
|
180
|
+
console.log(
|
|
181
|
+
`check-duplicates: ${scanned} file(s) scanned, no local copy of a ${PACKAGE_NAME} export.`,
|
|
182
|
+
)
|
|
183
|
+
} else {
|
|
184
|
+
console.error(
|
|
185
|
+
`\ncheck-duplicates: ${findings.length} declaration(s) already exported by ${PACKAGE_NAME}@${manifest.version}\n`,
|
|
186
|
+
)
|
|
187
|
+
for (const finding of findings) {
|
|
188
|
+
console.error(` ${finding.file}:${finding.line} declares ${finding.name}`)
|
|
189
|
+
console.error(` replace it with: ${finding.replacement}\n`)
|
|
190
|
+
}
|
|
191
|
+
console.error(
|
|
192
|
+
"A local copy that drifts is the failure the design system exists to prevent.\n" +
|
|
193
|
+
"If the product genuinely needs a variation, wrap the shared component rather\n" +
|
|
194
|
+
"than re-declaring its name.\n",
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
process.exit(findings.length > 0 && !warnOnly ? 1 : 0)
|