@viglet/viglet-design-system 2026.3.2 → 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.
Files changed (177) hide show
  1. package/README.md +277 -7
  2. package/dist/assets.cjs +1 -0
  3. package/dist/assets.es.js +2 -0
  4. package/dist/badge-locale-BxI9TwkE.js +579 -0
  5. package/dist/badge-locale-sIsBdP_e.cjs +7 -0
  6. package/dist/bento/bento-actions-menu.d.ts +42 -0
  7. package/dist/bento/bento-actions-menu.d.ts.map +1 -0
  8. package/dist/bento/bento-back-to-top.d.ts +11 -0
  9. package/dist/bento/bento-back-to-top.d.ts.map +1 -0
  10. package/dist/bento/bento-command-palette.d.ts +28 -0
  11. package/dist/bento/bento-command-palette.d.ts.map +1 -0
  12. package/dist/bento/bento-count-tile.d.ts +18 -0
  13. package/dist/bento/bento-count-tile.d.ts.map +1 -0
  14. package/dist/bento/bento-empty-state.d.ts +35 -0
  15. package/dist/bento/bento-empty-state.d.ts.map +1 -0
  16. package/dist/bento/bento-entity-shell.d.ts +123 -0
  17. package/dist/bento/bento-entity-shell.d.ts.map +1 -0
  18. package/dist/bento/bento-entity-tile.d.ts +40 -0
  19. package/dist/bento/bento-entity-tile.d.ts.map +1 -0
  20. package/dist/bento/bento-form-hero.d.ts +91 -0
  21. package/dist/bento/bento-form-hero.d.ts.map +1 -0
  22. package/dist/bento/bento-form-section.d.ts +31 -0
  23. package/dist/bento/bento-form-section.d.ts.map +1 -0
  24. package/dist/bento/bento-hero-icon-picker.d.ts +35 -0
  25. package/dist/bento/bento-hero-icon-picker.d.ts.map +1 -0
  26. package/dist/bento/bento-hero.d.ts +62 -0
  27. package/dist/bento/bento-hero.d.ts.map +1 -0
  28. package/dist/bento/bento-inline-edit.d.ts +52 -0
  29. package/dist/bento/bento-inline-edit.d.ts.map +1 -0
  30. package/dist/bento/bento-layout.d.ts +52 -0
  31. package/dist/bento/bento-layout.d.ts.map +1 -0
  32. package/dist/bento/bento-list-page.d.ts +124 -0
  33. package/dist/bento/bento-list-page.d.ts.map +1 -0
  34. package/dist/bento/bento-nav-rail.d.ts +32 -0
  35. package/dist/bento/bento-nav-rail.d.ts.map +1 -0
  36. package/dist/bento/bento-nav.d.ts +69 -0
  37. package/dist/bento/bento-nav.d.ts.map +1 -0
  38. package/dist/bento/bento-save-bar.d.ts +36 -0
  39. package/dist/bento/bento-save-bar.d.ts.map +1 -0
  40. package/dist/bento/bento-scroll-fade.d.ts +20 -0
  41. package/dist/bento/bento-scroll-fade.d.ts.map +1 -0
  42. package/dist/bento/bento-scroll-save-bar.d.ts +22 -0
  43. package/dist/bento/bento-scroll-save-bar.d.ts.map +1 -0
  44. package/dist/bento/bento-section-chrome.d.ts +60 -0
  45. package/dist/bento/bento-section-chrome.d.ts.map +1 -0
  46. package/dist/bento/bento-section.d.ts +27 -0
  47. package/dist/bento/bento-section.d.ts.map +1 -0
  48. package/dist/bento/bento-shortcuts-dialog.d.ts +15 -0
  49. package/dist/bento/bento-shortcuts-dialog.d.ts.map +1 -0
  50. package/dist/bento/bento-status-marker.d.ts +26 -0
  51. package/dist/bento/bento-status-marker.d.ts.map +1 -0
  52. package/dist/bento/bento-tile.d.ts +42 -0
  53. package/dist/bento/bento-tile.d.ts.map +1 -0
  54. package/dist/bento/bento-tones.d.ts +33 -0
  55. package/dist/bento/bento-tones.d.ts.map +1 -0
  56. package/dist/bento/bento-user-menu.d.ts +31 -0
  57. package/dist/bento/bento-user-menu.d.ts.map +1 -0
  58. package/dist/bento/index.d.ts +59 -0
  59. package/dist/bento/index.d.ts.map +1 -0
  60. package/dist/bento.cjs +1 -0
  61. package/dist/bento.css +442 -0
  62. package/dist/bento.es.js +1501 -0
  63. package/dist/breadcrumb.context-CTnZ4rD0.cjs +1 -0
  64. package/dist/breadcrumb.context-h2A2IEJ_.js +928 -0
  65. package/dist/components/badge-locale.d.ts.map +1 -1
  66. package/dist/components/error-boundary.d.ts.map +1 -1
  67. package/dist/components/language-select.d.ts.map +1 -1
  68. package/dist/components/router/blank-slate.d.ts +10 -0
  69. package/dist/components/router/blank-slate.d.ts.map +1 -1
  70. package/dist/components/router/grid.list.d.ts +13 -0
  71. package/dist/components/router/grid.list.d.ts.map +1 -1
  72. package/dist/components/router/internal.sidebar.d.ts +27 -2
  73. package/dist/components/router/internal.sidebar.d.ts.map +1 -1
  74. package/dist/components/router/loading-provider.d.ts +6 -1
  75. package/dist/components/router/loading-provider.d.ts.map +1 -1
  76. package/dist/components/router/nav-main.d.ts +10 -0
  77. package/dist/components/router/nav-main.d.ts.map +1 -1
  78. package/dist/components/router/nav-user.d.ts +13 -0
  79. package/dist/components/router/nav-user.d.ts.map +1 -1
  80. package/dist/components/router/page-content.d.ts +10 -0
  81. package/dist/components/router/page-content.d.ts.map +1 -1
  82. package/dist/components/router/page-header.d.ts +13 -0
  83. package/dist/components/router/page-header.d.ts.map +1 -1
  84. package/dist/components/router/page.d.ts +13 -0
  85. package/dist/components/router/page.d.ts.map +1 -1
  86. package/dist/components/router/sticky.page.header.d.ts +14 -0
  87. package/dist/components/router/sticky.page.header.d.ts.map +1 -1
  88. package/dist/components/router/sub.page.d.ts +15 -11
  89. package/dist/components/router/sub.page.d.ts.map +1 -1
  90. package/dist/components/router/sub.page.header.d.ts +13 -0
  91. package/dist/components/router/sub.page.header.d.ts.map +1 -1
  92. package/dist/components/startup-first/startup-first.d.ts.map +1 -1
  93. package/dist/components/ui/floating-formulas-bg.d.ts +8 -1
  94. package/dist/components/ui/floating-formulas-bg.d.ts.map +1 -1
  95. package/dist/components/ui/form.d.ts +2 -2
  96. package/dist/components/ui/form.d.ts.map +1 -1
  97. package/dist/components/ui/gradient-button.d.ts.map +1 -1
  98. package/dist/components/ui/gradient-switch.d.ts.map +1 -1
  99. package/dist/components/ui/icon-picker-dialog.d.ts +35 -0
  100. package/dist/components/ui/icon-picker-dialog.d.ts.map +1 -0
  101. package/dist/components/ui/index.d.ts +1 -0
  102. package/dist/components/ui/index.d.ts.map +1 -1
  103. package/dist/components/ui/section-card.d.ts +3 -3
  104. package/dist/components/ui/section-card.d.ts.map +1 -1
  105. package/dist/components/ui/sidebar.d.ts.map +1 -1
  106. package/dist/components/ui/slider.d.ts +1 -1
  107. package/dist/components/ui/slider.d.ts.map +1 -1
  108. package/dist/contexts/user.context.d.ts +24 -0
  109. package/dist/contexts/user.context.d.ts.map +1 -1
  110. package/dist/exports.json +404 -0
  111. package/dist/floating-formulas-bg.cjs +1 -0
  112. package/dist/floating-formulas-bg.css +21 -0
  113. package/dist/floating-formulas-bg.es.js +83 -56
  114. package/dist/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  115. package/dist/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  116. package/dist/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  117. package/dist/fonts/inter-greek-wght-normal.woff2 +0 -0
  118. package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  119. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  120. package/dist/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  121. package/dist/fonts/plus-jakarta-sans-cyrillic-ext-wght-normal.woff2 +0 -0
  122. package/dist/fonts/plus-jakarta-sans-latin-ext-wght-normal.woff2 +0 -0
  123. package/dist/fonts/plus-jakarta-sans-latin-wght-normal.woff2 +0 -0
  124. package/dist/fonts/plus-jakarta-sans-vietnamese-wght-normal.woff2 +0 -0
  125. package/dist/fonts.css +126 -0
  126. package/dist/hooks/use-grid-adapter.d.ts.map +1 -1
  127. package/dist/hooks/use-mobile.d.ts +10 -0
  128. package/dist/hooks/use-mobile.d.ts.map +1 -1
  129. package/dist/hooks/use-sub-page-breadcrumb.d.ts.map +1 -1
  130. package/dist/i18n/index.d.ts +136 -0
  131. package/dist/i18n/index.d.ts.map +1 -1
  132. package/dist/i18n/locales/en/bento.json.d.ts +51 -0
  133. package/dist/i18n/locales/en/common.json.d.ts +7 -1
  134. package/dist/i18n/locales/en/forms.json.d.ts +15 -1
  135. package/dist/i18n/locales/en/nav.json.d.ts +3 -1
  136. package/dist/i18n/locales/pt/bento.json.d.ts +51 -0
  137. package/dist/i18n/locales/pt/common.json.d.ts +7 -1
  138. package/dist/i18n/locales/pt/forms.json.d.ts +15 -1
  139. package/dist/i18n/locales/pt/nav.json.d.ts +3 -1
  140. package/dist/i18n-DoNdMLEd.cjs +1 -0
  141. package/dist/{i18n-C94rDRaM.js → i18n-DuNITbWa.js} +155 -27
  142. package/dist/{i18n.cjs.js → i18n.cjs} +1 -1
  143. package/dist/i18n.es.js +1 -1
  144. package/dist/index.cjs +1 -0
  145. package/dist/index.d.ts +0 -1
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.es.js +492 -750
  148. package/dist/lib/axios.d.ts.map +1 -1
  149. package/dist/lib/export-xlsx.d.ts +7 -1
  150. package/dist/lib/export-xlsx.d.ts.map +1 -1
  151. package/dist/lib/react-markers.d.ts +17 -0
  152. package/dist/lib/react-markers.d.ts.map +1 -0
  153. package/dist/lib/utils.d.ts +22 -0
  154. package/dist/lib/utils.d.ts.map +1 -1
  155. package/dist/loading-provider-1mgM91iY.cjs +1 -0
  156. package/dist/loading-provider-CMnOuvdR.js +224 -0
  157. package/dist/preset.css +103 -3
  158. package/dist/products-DL_YYXkV.cjs +1 -0
  159. package/dist/products-Du9KB6Xl.js +9 -0
  160. package/dist/{rolldown-runtime-CMqjfN_6.cjs → rolldown-runtime-BocRIvOZ.cjs} +1 -1
  161. package/dist/router.cjs +1 -0
  162. package/dist/router.es.js +358 -555
  163. package/dist/user.context-kPAqKN4o.js +512 -0
  164. package/dist/user.context-r50nSWER.cjs +1 -0
  165. package/dist/viglet-design-system.css +1 -1
  166. package/dist/vite/boot-loader.d.ts +14 -4
  167. package/dist/vite/boot-loader.d.ts.map +1 -1
  168. package/dist/{vite.cjs.js → vite.cjs} +8 -8
  169. package/dist/vite.es.js +29 -16
  170. package/package.json +66 -22
  171. package/scripts/check-duplicates.mjs +198 -0
  172. package/dist/breadcrumb.context-C7VCfh49.js +0 -1501
  173. package/dist/breadcrumb.context-Td6Tjc_z.cjs +0 -7
  174. package/dist/floating-formulas-bg.cjs.js +0 -1
  175. package/dist/i18n-DN_2YzjB.cjs +0 -1
  176. package/dist/index.cjs.js +0 -1
  177. package/dist/router.cjs.js +0 -1
package/README.md CHANGED
@@ -2,12 +2,92 @@
2
2
 
3
3
  Shared component library, design tokens, hooks, utilities, and i18n for Viglet products (Turing, Dumont, Shio).
4
4
 
5
+ **[Browse the component catalogue](https://openviglet.github.io/viglet-design-system/)** — every
6
+ component, its variants and its props, rebuilt on each commit to `2026.3`. Look
7
+ there before writing a component: the catalogue is the answer to "does this
8
+ already exist".
9
+
10
+ Those three products are the consumers this package holds itself to, declared in
11
+ [`consumers.json`](consumers.json) rather than remembered: the render-parity
12
+ digest carries one accent per consumer, and CI refuses prose that names two of
13
+ them as though it were all three. A fourth console is one entry there, and the
14
+ checks widen with it.
15
+
5
16
  ## Installation
6
17
 
7
18
  ```bash
8
- npm install @viglet/viglet-design-system
19
+ pnpm add @viglet/viglet-design-system
20
+ ```
21
+
22
+ ## Trying a change in a product before publishing
23
+
24
+ A change here is a change to shared chrome, so the question is always what it
25
+ does to Shio, Turing and Dumont — and the answer should not require a
26
+ publish. From this checkout:
27
+
28
+ ```bash
29
+ pnpm use:local # build, then push dist into every 2026.3 product on disk
30
+ pnpm use:local --list # show what it would write to, and stop
31
+ ```
32
+
33
+ It finds the consumers by reading their `package.json`, and finds where each one
34
+ keeps the installed copy by following the link its own package manager made, so
35
+ neither a version bump nor a switch of package manager breaks the loop. Nothing
36
+ in the product's manifest or lockfile changes: `pnpm install` in the product puts
37
+ the published build back.
38
+
39
+ Pass directories to narrow it, and `--no-build` to reuse the `dist` already on
40
+ disk:
41
+
42
+ ```bash
43
+ pnpm use:local ../shio/2026.3/shio-react --no-build
44
+ ```
45
+
46
+ One thing it refuses to do: push over a tree whose dependencies are behind. It
47
+ writes files, and files cannot re-resolve a dependency — so if a range moved
48
+ here since the product last installed, the manifest it copies would ask for a
49
+ version the directory beside it does not have, and the product would fail to
50
+ build on symbols that version does not export. It names those packages and
51
+ stops. That is a real limit rather than a check to switch off: a range that
52
+ moved reaches a product through a release, not through this. `--skip-dep-check`
53
+ pushes anyway when you know why you want it.
54
+
55
+ ## Catching a duplicate before it drifts
56
+
57
+ The package ships `dist/exports.json` — every name it exports, per entry point —
58
+ and a CLI that reads it. Run it in the product's own CI:
59
+
60
+ ```bash
61
+ viglet-ds-check-duplicates src
62
+ ```
63
+
64
+ It fails, naming the import that replaces each local copy:
65
+
66
+ ```
67
+ src/components/page-header.tsx:18 declares PageHeader
68
+ replace it with: import { PageHeader } from "@viglet/viglet-design-system/router"
69
+ ```
70
+
71
+ One-line re-export shims are the sanctioned pattern and are skipped. When a
72
+ collision is deliberate — a product component that renders that product's own
73
+ data and merely shares a name — keep it by writing the reason in the file:
74
+
75
+ ```ts
76
+ // viglet-ds-allow-duplicate AppFooter -- renders Shio's build version
77
+ ```
78
+
79
+ In a product's workflow, it is one step beside the lint:
80
+
81
+ ```yaml
82
+ - name: No local copy of a shared component
83
+ run: pnpm exec viglet-ds-check-duplicates src
9
84
  ```
10
85
 
86
+ Add `--warn` to report without failing while the existing collisions are being
87
+ worked through, and drop it once the count is zero. `--json` prints the findings
88
+ for a bot to read; `--manifest <path>` checks against an export list other than
89
+ the installed one.
90
+
11
91
  ## Setup
12
92
 
13
93
  ### 1. Import styles
@@ -24,6 +104,37 @@ Or in your entry TypeScript/JavaScript:
24
104
  import "@viglet/viglet-design-system/styles";
25
105
  ```
26
106
 
107
+ The brand faces are a **separate import**, and one you probably want:
108
+
109
+ ```css
110
+ @import "@viglet/viglet-design-system/styles";
111
+ @import "@viglet/viglet-design-system/fonts";
112
+ ```
113
+
114
+ They used to be inside `./styles`, where they were 741 KB of its 964 KB —
115
+ Vite's library mode inlines every asset regardless of `assetsInlineLimit`, so
116
+ every subset of Inter and Plus Jakarta Sans was base64 in the CSS, twice over
117
+ because the preset imported them as well. Base64 of an already-compressed woff2
118
+ does not compress again, which is why 2,276 rules gzipped to 594 KB. Splitting
119
+ them takes `./styles` to 31 KB gzipped.
120
+
121
+ `./fonts` is 5 KB of rules pointing at 11 `.woff2` files shipped beside it in
122
+ `dist/fonts/`. Nothing in it resolves through your `node_modules`, and your CDN
123
+ and browser cache the faces apart from the rules — so a change to any rule no
124
+ longer re-downloads every font, and a product already serving Inter can drop
125
+ this copy.
126
+
127
+ **A page fetches about 77 KB of that, not 272 KB.** Each face carries a
128
+ `unicode-range`, so the browser asks only for the subsets your text needs; an
129
+ English or Portuguese page takes `latin` and nothing else, the accented
130
+ characters Portuguese uses being Latin-1 rather than `latin-ext`.
131
+ `size-budget.json` records both numbers, and CI fails if either moves — or if
132
+ the faces stop being subsetted at all.
133
+
134
+ **Upgrading:** add the second line, or the type falls back through `--font-sans`
135
+ to `system-ui`. That is a real look rather than a broken one, but it is not the
136
+ one the catalogue shows.
137
+
27
138
  ### 2. Initialize i18n
28
139
 
29
140
  ```ts
@@ -107,19 +218,40 @@ import {
107
218
 
108
219
  ```tsx
109
220
  import {
110
- PageHeader,
111
- SubPageHeader,
112
- GridList,
113
221
  DialogDelete,
114
- BlankSlate,
115
222
  LoadProvider,
116
- NavUser,
223
+ GradientButtonLink,
117
224
  AppFooter,
118
225
  LanguageSelect,
119
226
  ModeToggle,
120
227
  } from "@viglet/viglet-design-system";
121
228
  ```
122
229
 
230
+ A page's chrome — its header, its list, its sidebar — comes from the
231
+ [bento layer](#the-bento-layer) rather than from here. Read the next section
232
+ before reaching for `PageHeader`, `GridList` or `InternalSidebar`.
233
+
234
+ ### Two eras, and which one a new page should use
235
+
236
+ This package exports two complete page vocabularies. The **console era** is what all three products ship on today; the **[bento layer](#the-bento-layer)** is the current one. Every console-era export is marked `@deprecated` in its own types, so an editor strikes it through and offers the swap.
237
+
238
+ Nothing is being removed. No product has started cutting over, and a removal will get its own roadmap line rather than arriving as a side effect of this notice — so existing pages keep working and need no rush.
239
+
240
+ | Console era | Use instead | |
241
+ |---|---|---|
242
+ | `PageHeader` | `BentoHero` | Same title/subtitle/icon, plus a tone — the chip follows the product accent. |
243
+ | `SubPageHeader` | `BentoHero` | With `BentoBackLink` for the back target and `BentoActionsMenu` for the menu. |
244
+ | `StickyPageHeader` | `useBentoScrollFade` | The scroll state is separated from the chrome, so it also drives `BentoScrollSaveBar`. |
245
+ | `GridList` | `BentoListPage` | `BentoTileGrid` is the mosaic alone, for a page with its own chrome. |
246
+ | `BlankSlate` | `BentoEmptyState` | |
247
+ | `InternalSidebar` | `BentoNavRail` | The rail takes its nav array as a prop instead of importing routes. |
248
+ | `NavMain` | `BentoNavRail` | |
249
+ | `NavUser` | `BentoUserMenu` | Routes and feature flags arrive as props. |
250
+ | `SubPage` | `BentoEntityShell` | Renders through a render prop, so the shell never learns what an entity is. |
251
+ | `Page`, `PageContent` | — | No single replacement, deliberately: the shell is where a product is itself. Compose `BentoNavRail`, `BentoUserMenu` and `BentoCommandPalette`. |
252
+
253
+ `DialogDelete`, `LoadProvider` and `GradientButtonLink` are **not** console-era — the bento layer uses them itself, and they are not deprecated.
254
+
123
255
  ### Hooks
124
256
 
125
257
  ```tsx
@@ -146,6 +278,27 @@ import {
146
278
  } from "@viglet/viglet-design-system";
147
279
  ```
148
280
 
281
+ `exportToXlsx(data, headers, filename, sheetName?)` takes an optional sheet name; without one the sheet is named after `filename` (it used to be `Logging`, whatever you exported). The header row is written from `headers`, so an export with no rows still arrives with its column titles rather than as an empty file.
282
+
283
+ ### Product logos
284
+
285
+ ```tsx
286
+ import { productLogos, type ProductId } from "@viglet/viglet-design-system/assets";
287
+ ```
288
+
289
+ Their own subpath, not the root barrel. Vite's library mode inlines every asset
290
+ regardless of `assetsInlineLimit`, so anything the root barrel could reach was
291
+ base64 inside the root entry — `productLogos` names all four logos, and one of
292
+ them is 1.24 MB, which put 1.90 MB of PNG in front of every consumer. Nothing
293
+ renders that one: `VigletAppSwitcher` draws the Viglet Cloud entry with an icon.
294
+ Moving the map here left the root entry 56% lighter, and the size gate now
295
+ refuses any single inlined asset over 256 KB.
296
+
297
+ `VigletAppSwitcher` still imports the three logos it draws, so it needs no
298
+ change — and those three are now 256px rather than 1024–2375px, which is nine
299
+ times the 28 pixels the switcher renders them at. A test holds that ceiling,
300
+ because an asset this package can reach is an asset it ships.
301
+
149
302
  ### Models
150
303
 
151
304
  ```tsx
@@ -164,20 +317,47 @@ Accordion, Avatar, Badge, Breadcrumb, Button, Card, Checkbox, Dialog, Drawer, Dr
164
317
 
165
318
  ### App Components (23 components)
166
319
 
167
- AppFooter, BadgeColorful, BadgeLocale, BlankSlate, DialogDelete, GridList, InternalSidebar, LanguageSelect, LoadProvider, ModeToggle, NavMain, NavSecondary, NavUser, Page, PageContent, PageHeader, SubPage, SubPageHeader, ThemeProvider
320
+ AppFooter, BadgeColorful, BadgeLocale, DialogDelete, GradientButtonLink, LanguageSelect, LoadProvider, ModeToggle, NavSecondary, ThemeProvider
321
+
322
+ Console-era, `@deprecated`, still exported — see [the swap table](#two-eras-and-which-one-a-new-page-should-use): BlankSlate, GridList, InternalSidebar, NavMain, NavUser, Page, PageContent, PageHeader, StickyPageHeader, SubPage, SubPageHeader
168
323
 
169
324
  ### Hooks
170
325
 
171
326
  `useIsMobile`, `useDateLocale`, `useGridAdapter`, `useSubPageBreadcrumb`
172
327
 
328
+ `useGridAdapter(data, config)` tracks each extractor in `config`, not the object holding them, so a `url` builder that closes over a route param or a locale re-maps the rows when it changes. Pass the config inline if you like — keep the extractors themselves stable (a field name, a module-level function, a `useCallback`) and the memo holds.
329
+
173
330
  ### Contexts
174
331
 
175
332
  `BreadcrumbProvider` / `useBreadcrumb`, `UserProvider` / `useCurrentUser`, `ThemeProvider` / `useTheme`
176
333
 
334
+ `useCurrentUser()` returns `status` (`"loading" | "ready" | "failed"`) and `error` alongside `user` and `refreshUser`. Read `status` rather than inferring one from an empty `user` — the same empty object means a request that has not settled, a session that expired, and an account with no username. A rejecting `fetchUser` sets `status: "failed"` and is not rethrown.
335
+
177
336
  ### Design Tokens
178
337
 
179
338
  OKLCH-based color system with light/dark mode, CSS variables for theming, consistent radius scale, chart palette, sidebar theme, animations.
180
339
 
340
+ **The brand accent is one token, set once.** The tinted icon chip in a page header, the ring around it, an accented label and the solid primary fill all derive from two gradient stops, so a product picks its colour at the root rather than in every component:
341
+
342
+ ```css
343
+ :root {
344
+ --vg-accent-from: oklch(70.5% 0.213 47.604);
345
+ --vg-accent-to: oklch(64.6% 0.222 41.116);
346
+ --vg-accent-text: oklch(55.3% 0.195 38.402); /* readable on light */
347
+ --vg-accent-text-dark: oklch(75% 0.183 55.934); /* readable on dark */
348
+ }
349
+ ```
350
+
351
+ The tint, the strong tint and the hairline (`--vg-accent-surface`, `--vg-accent-surface-strong`, `--vg-accent-line`) are `color-mix` over `--vg-accent-from`, so they follow automatically; only the readable foreground is stated, because contrast is not a mix away. Use `--vg-accent-fg` in a component — it is already resolved for the current theme, so no `dark:` twin is needed.
352
+
353
+ **Declare them on `:root`, not on a wrapper.** A custom property substitutes its `var()` references where it is *declared*, so the derived tokens above are mixed against the `--vg-accent-from` declared in the preset's `:root`. Re-keying a subtree moves what a utility class mixes on the element — the chip, the solid fill — and leaves the tint, the hairline and the button fill at the root's value. The result looks like a component that half-ignores the theme.
354
+
355
+ Three utility classes cover the common shapes: `vg-accent-chip` (the tinted gradient chip — pair it with Tailwind's `ring-1`), `vg-accent-text` (an accented label or icon), and `vg-accent-solid` (a solid gradient fill).
356
+
357
+ `GradientButton` and `GradientSwitch` follow the accent in their primary variants (`default`, `outline`, `ghost`), so a re-key reaches the buttons too; their `secondary`, `destructive` and `success` variants keep fixed semantic hues, because "destructive" does not change colour with the brand.
358
+
359
+ This is separate from a component's **colour palette**. `SectionCard` (`blue | violet | emerald | amber | rose | cyan`) and `StickySaveBar` (`gray | blue | orange | green`) are keyed by hue — the caller picked that colour deliberately — so re-keying the accent leaves them alone, the same way it leaves the [bento tones](#the-bento-layer) alone.
360
+
181
361
  ### i18n
182
362
 
183
363
  Base translations (EN/PT) for common UI strings: buttons, form labels, dialog text, navigation, theme.
@@ -195,6 +375,96 @@ Base translations (EN/PT) for common UI strings: buttons, form labels, dialog te
195
375
  - Sonner for toast notifications
196
376
  - Lucide + Tabler icons
197
377
 
378
+ ## The bento layer
379
+
380
+ Turing grew a second era of chrome — the frosted tile, the airy hero, the
381
+ mosaic — inside one product while this package sat next to it exporting console
382
+ chrome. It is being moved here.
383
+
384
+ It is a separate entry point, so a console still on the first era carries none
385
+ of it:
386
+
387
+ ```ts
388
+ import "@viglet/viglet-design-system/bento.css";
389
+ import {
390
+ BentoEntityShell,
391
+ BentoListPage,
392
+ BentoFormHero,
393
+ BentoNavRail,
394
+ BentoCommandPalette,
395
+ } from "@viglet/viglet-design-system/bento";
396
+ ```
397
+
398
+ The stylesheet is a separate import from the components, so a consumer taking
399
+ only the layout maths does not pull CSS it never renders. It reads the preset's
400
+ tokens, so import the preset too.
401
+
402
+ "Carries none of it" is measured rather than claimed. `pnpm run build` ends by
403
+ bundling three fixtures through this package's own `exports` map, and fails if a
404
+ bento module, a bento class name or a run of `bento.css`'s selectors reaches a
405
+ consumer that imported only the root entry. `size-budget.json` records what each
406
+ entry costs: today the whole root entry is 87 KB gzipped and `./bento` 22 KB,
407
+ measured with everything the build externalises left out, so the numbers
408
+ describe this package rather than its dependencies. The preset's
409
+ `--vg-bento-tone-*` tokens are deliberately not counted as the layer: they ship
410
+ with every other token and are about a kilobyte of custom properties.
411
+
412
+ The test is whether a root consumer carries the subpath's **code**, not whether
413
+ the subpath exists. `./floating-formulas-bg` has its own entry *and*
414
+ `FloatingFormulasBg` is exported from the root barrel, where `Login` and
415
+ `StartupFirst` render it — so its rules are in `./styles` too, and that is
416
+ correct rather than a leak. The subpath is for a consumer who wants only that
417
+ background.
418
+
419
+ Every subpath in the table above is also **imported, required and type-checked
420
+ as you would use it** on each build: one fixture pulls all fifteen through the
421
+ real `exports` map, a CommonJS probe requires the seven that offer it, and a
422
+ generated TypeScript probe imports a value from each typed entry and uses it —
423
+ so a `types` field resolving to the wrong declarations fails here rather than
424
+ turning into `any` in your editor.
425
+
426
+ That last check found a real one. `"type": "module"` makes Node read any `.js`
427
+ as ESM, and the CommonJS entries were named `<entry>.cjs.js`, so every
428
+ `require()` of this package failed. They are `<entry>.cjs` now. No product met
429
+ it, because all three bundle with Vite and take the `import` condition.
430
+
431
+ **`./bento` requires `react-router-dom`.** The package declares that peer
432
+ optional because the root entry does not need it — only `./router` and `./bento`
433
+ do, and npm cannot mark a peer required for one entry point and optional for
434
+ another. `pnpm run build` fails if any other entry starts importing it, so the
435
+ split above stays true rather than becoming folklore.
436
+
437
+ [docs/BENTO-AUTHORING.md](docs/BENTO-AUTHORING.md) is the contract for writing a
438
+ bento page: the three page shapes, what the package will not hold for you, and
439
+ the colour, i18n, accessibility and layout rules that keep two consoles looking
440
+ like the same product. Read it before the first screen, not after the fifth.
441
+
442
+ [docs/BENTO-BOUNDARY.md](docs/BENTO-BOUNDARY.md) says which exports become part
443
+ of this package and which stay in the product, and why. Four of them are one
444
+ product's commercial offer rendered as cards, and shipping those as chrome would
445
+ put that offer in every console.
446
+
447
+ ## Contributing
448
+
449
+ The package manager is pnpm, matching the Shio, Turing and Dumont workspaces.
450
+
451
+ ```bash
452
+ pnpm install
453
+ pnpm lint # eslint
454
+ pnpm typecheck # tsc -b --force
455
+ pnpm test # vitest
456
+ pnpm build # tsc, vite, and the dist checks
457
+ pnpm storybook # the component catalogue, on :6006
458
+ ```
459
+
460
+ CI runs all of those on every push and pull request, and the publish workflow
461
+ re-runs them before it releases.
462
+
463
+ `pnpm build` ends in `scripts/check-dist.mjs`, which fails the build when dist
464
+ would be broken for consumers in a way nothing here can see — a declaration
465
+ importing through a `node_modules` path, a test artefact in the published tree,
466
+ or an `exports` entry the build did not produce.
467
+
198
468
  ## License
199
469
 
200
470
  Apache-2.0
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./products-DL_YYXkV.cjs");exports.dumontLogoUrl=e.n,exports.productLogos=e.t,exports.shioLogoUrl=e.r,exports.turingLogoUrl=e.i,exports.vigletLogoUrl=e.a;
@@ -0,0 +1,2 @@
1
+ import { a as e, i as t, n, r, t as i } from "./products-Du9KB6Xl.js";
2
+ export { n as dumontLogoUrl, i as productLogos, r as shioLogoUrl, t as turingLogoUrl, e as vigletLogoUrl };