@viglet/viglet-design-system 2026.3.9 → 2026.3.11

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 (259) hide show
  1. package/README.md +528 -44
  2. package/consumers.json +186 -0
  3. package/dist/badge-locale-CJkHDlPg.cjs +1 -0
  4. package/dist/badge-locale-DxDp8Q3S.js +397 -0
  5. package/dist/bento/bento-actions-menu.d.ts +8 -0
  6. package/dist/bento/bento-actions-menu.d.ts.map +1 -1
  7. package/dist/bento/bento-back-to-top.d.ts +9 -1
  8. package/dist/bento/bento-back-to-top.d.ts.map +1 -1
  9. package/dist/bento/bento-command-palette.d.ts +56 -9
  10. package/dist/bento/bento-command-palette.d.ts.map +1 -1
  11. package/dist/bento/bento-data-table.d.ts +81 -0
  12. package/dist/bento/bento-data-table.d.ts.map +1 -0
  13. package/dist/bento/bento-diff.d.ts +41 -0
  14. package/dist/bento/bento-diff.d.ts.map +1 -0
  15. package/dist/bento/bento-empty-state.d.ts +8 -1
  16. package/dist/bento/bento-empty-state.d.ts.map +1 -1
  17. package/dist/bento/bento-entity-shell.d.ts.map +1 -1
  18. package/dist/bento/bento-filter-bar.d.ts +60 -0
  19. package/dist/bento/bento-filter-bar.d.ts.map +1 -0
  20. package/dist/bento/bento-form-section.d.ts +14 -1
  21. package/dist/bento/bento-form-section.d.ts.map +1 -1
  22. package/dist/bento/bento-inline-edit.d.ts.map +1 -1
  23. package/dist/bento/bento-nav-rail.d.ts +13 -13
  24. package/dist/bento/bento-nav-rail.d.ts.map +1 -1
  25. package/dist/bento/bento-nav.d.ts +10 -2
  26. package/dist/bento/bento-nav.d.ts.map +1 -1
  27. package/dist/bento/bento-palette-trigger.d.ts +18 -0
  28. package/dist/bento/bento-palette-trigger.d.ts.map +1 -0
  29. package/dist/bento/bento-section-chrome.d.ts +19 -39
  30. package/dist/bento/bento-section-chrome.d.ts.map +1 -1
  31. package/dist/bento/bento-shell-shortcuts.d.ts +67 -0
  32. package/dist/bento/bento-shell-shortcuts.d.ts.map +1 -0
  33. package/dist/bento/bento-shell.d.ts +53 -0
  34. package/dist/bento/bento-shell.d.ts.map +1 -0
  35. package/dist/bento/bento-shortcuts-dialog.d.ts +9 -7
  36. package/dist/bento/bento-shortcuts-dialog.d.ts.map +1 -1
  37. package/dist/bento/bento-status-marker.d.ts +5 -2
  38. package/dist/bento/bento-status-marker.d.ts.map +1 -1
  39. package/dist/bento/bento-tile.d.ts.map +1 -1
  40. package/dist/bento/bento-user-menu.d.ts +9 -8
  41. package/dist/bento/bento-user-menu.d.ts.map +1 -1
  42. package/dist/bento/bento-version-rail.d.ts +31 -0
  43. package/dist/bento/bento-version-rail.d.ts.map +1 -0
  44. package/dist/bento/index.d.ts +15 -6
  45. package/dist/bento/index.d.ts.map +1 -1
  46. package/dist/bento.cjs +5 -1
  47. package/dist/bento.css +70 -4
  48. package/dist/bento.es.js +1778 -701
  49. package/dist/catalogue.json +5283 -0
  50. package/dist/components/app-footer.d.ts +7 -0
  51. package/dist/components/app-footer.d.ts.map +1 -1
  52. package/dist/components/app-switcher.d.ts.map +1 -1
  53. package/dist/components/backend-status.d.ts +19 -11
  54. package/dist/components/backend-status.d.ts.map +1 -1
  55. package/dist/components/badge-colorful.d.ts +13 -0
  56. package/dist/components/badge-colorful.d.ts.map +1 -1
  57. package/dist/components/badge-locale.d.ts +7 -0
  58. package/dist/components/badge-locale.d.ts.map +1 -1
  59. package/dist/components/error-boundary.d.ts +15 -13
  60. package/dist/components/error-boundary.d.ts.map +1 -1
  61. package/dist/components/language-select.d.ts +8 -0
  62. package/dist/components/language-select.d.ts.map +1 -1
  63. package/dist/components/login/login.d.ts +27 -0
  64. package/dist/components/login/login.d.ts.map +1 -1
  65. package/dist/components/mode-toggle.d.ts +9 -0
  66. package/dist/components/mode-toggle.d.ts.map +1 -1
  67. package/dist/components/nav-secondary.d.ts +7 -0
  68. package/dist/components/nav-secondary.d.ts.map +1 -1
  69. package/dist/components/router/dialog.delete.d.ts +8 -0
  70. package/dist/components/router/dialog.delete.d.ts.map +1 -1
  71. package/dist/components/router/gradient-button-link.d.ts +6 -0
  72. package/dist/components/router/gradient-button-link.d.ts.map +1 -1
  73. package/dist/components/router/index.d.ts +0 -11
  74. package/dist/components/router/index.d.ts.map +1 -1
  75. package/dist/components/router/loading-provider.d.ts +4 -0
  76. package/dist/components/router/loading-provider.d.ts.map +1 -1
  77. package/dist/components/startup-first/startup-first.d.ts +29 -0
  78. package/dist/components/startup-first/startup-first.d.ts.map +1 -1
  79. package/dist/components/ui/accordion.d.ts +17 -0
  80. package/dist/components/ui/accordion.d.ts.map +1 -1
  81. package/dist/components/ui/avatar.d.ts +14 -0
  82. package/dist/components/ui/avatar.d.ts.map +1 -1
  83. package/dist/components/ui/badge.d.ts +6 -0
  84. package/dist/components/ui/badge.d.ts.map +1 -1
  85. package/dist/components/ui/breadcrumb.d.ts +25 -0
  86. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  87. package/dist/components/ui/button.d.ts +15 -1
  88. package/dist/components/ui/button.d.ts.map +1 -1
  89. package/dist/components/ui/card.d.ts +27 -0
  90. package/dist/components/ui/card.d.ts.map +1 -1
  91. package/dist/components/ui/checkbox.d.ts +4 -0
  92. package/dist/components/ui/checkbox.d.ts.map +1 -1
  93. package/dist/components/ui/dialog.d.ts +36 -0
  94. package/dist/components/ui/dialog.d.ts.map +1 -1
  95. package/dist/components/ui/drawer.d.ts +35 -0
  96. package/dist/components/ui/drawer.d.ts.map +1 -1
  97. package/dist/components/ui/dropdown-menu.d.ts +53 -0
  98. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  99. package/dist/components/ui/floating-formulas-bg.d.ts +8 -0
  100. package/dist/components/ui/floating-formulas-bg.d.ts.map +1 -1
  101. package/dist/components/ui/form-actions.d.ts +7 -0
  102. package/dist/components/ui/form-actions.d.ts.map +1 -1
  103. package/dist/components/ui/form-item-two-columns.d.ts +7 -0
  104. package/dist/components/ui/form-item-two-columns.d.ts.map +1 -1
  105. package/dist/components/ui/form.d.ts +25 -0
  106. package/dist/components/ui/form.d.ts.map +1 -1
  107. package/dist/components/ui/glass-card.d.ts +18 -14
  108. package/dist/components/ui/glass-card.d.ts.map +1 -1
  109. package/dist/components/ui/gradient-button.d.ts +15 -1
  110. package/dist/components/ui/gradient-button.d.ts.map +1 -1
  111. package/dist/components/ui/gradient-switch.d.ts +6 -0
  112. package/dist/components/ui/gradient-switch.d.ts.map +1 -1
  113. package/dist/components/ui/hover-card.d.ts +14 -0
  114. package/dist/components/ui/hover-card.d.ts.map +1 -1
  115. package/dist/components/ui/icon-picker-dialog.d.ts.map +1 -1
  116. package/dist/components/ui/index.d.ts +6 -4
  117. package/dist/components/ui/index.d.ts.map +1 -1
  118. package/dist/components/ui/input.d.ts +6 -0
  119. package/dist/components/ui/input.d.ts.map +1 -1
  120. package/dist/components/ui/label.d.ts +4 -0
  121. package/dist/components/ui/label.d.ts.map +1 -1
  122. package/dist/components/ui/navigation-menu.d.ts +41 -0
  123. package/dist/components/ui/navigation-menu.d.ts.map +1 -1
  124. package/dist/components/ui/pagination.d.ts +25 -0
  125. package/dist/components/ui/pagination.d.ts.map +1 -1
  126. package/dist/components/ui/popover.d.ts +24 -0
  127. package/dist/components/ui/popover.d.ts.map +1 -1
  128. package/dist/components/ui/progress.d.ts +4 -0
  129. package/dist/components/ui/progress.d.ts.map +1 -1
  130. package/dist/components/ui/pulse-ring.d.ts +9 -11
  131. package/dist/components/ui/pulse-ring.d.ts.map +1 -1
  132. package/dist/components/ui/resizable.d.ts +11 -0
  133. package/dist/components/ui/resizable.d.ts.map +1 -1
  134. package/dist/components/ui/section-card.d.ts +9 -0
  135. package/dist/components/ui/section-card.d.ts.map +1 -1
  136. package/dist/components/ui/select.d.ts +36 -0
  137. package/dist/components/ui/select.d.ts.map +1 -1
  138. package/dist/components/ui/separator.d.ts +4 -0
  139. package/dist/components/ui/separator.d.ts.map +1 -1
  140. package/dist/components/ui/sheet.d.ts +29 -0
  141. package/dist/components/ui/sheet.d.ts.map +1 -1
  142. package/dist/components/ui/sidebar.d.ts +83 -0
  143. package/dist/components/ui/sidebar.d.ts.map +1 -1
  144. package/dist/components/ui/skeleton.d.ts +4 -0
  145. package/dist/components/ui/skeleton.d.ts.map +1 -1
  146. package/dist/components/ui/slider.d.ts +4 -0
  147. package/dist/components/ui/slider.d.ts.map +1 -1
  148. package/dist/components/ui/sonner.d.ts +16 -0
  149. package/dist/components/ui/sonner.d.ts.map +1 -1
  150. package/dist/components/ui/stepper.d.ts +8 -0
  151. package/dist/components/ui/stepper.d.ts.map +1 -1
  152. package/dist/components/ui/sticky-save-bar.d.ts +7 -0
  153. package/dist/components/ui/sticky-save-bar.d.ts.map +1 -1
  154. package/dist/components/ui/switch.d.ts +4 -0
  155. package/dist/components/ui/switch.d.ts.map +1 -1
  156. package/dist/components/ui/table.d.ts +31 -0
  157. package/dist/components/ui/table.d.ts.map +1 -1
  158. package/dist/components/ui/tabs.d.ts +16 -0
  159. package/dist/components/ui/tabs.d.ts.map +1 -1
  160. package/dist/components/ui/textarea.d.ts +4 -0
  161. package/dist/components/ui/textarea.d.ts.map +1 -1
  162. package/dist/components/ui/toggle-group.d.ts +7 -0
  163. package/dist/components/ui/toggle-group.d.ts.map +1 -1
  164. package/dist/components/ui/toggle.d.ts +4 -0
  165. package/dist/components/ui/toggle.d.ts.map +1 -1
  166. package/dist/components/ui/tooltip.d.ts +18 -0
  167. package/dist/components/ui/tooltip.d.ts.map +1 -1
  168. package/dist/components/ui/user-avatar.d.ts +2 -1
  169. package/dist/components/ui/user-avatar.d.ts.map +1 -1
  170. package/dist/components/ui/viglet-assistant.d.ts +103 -0
  171. package/dist/components/ui/viglet-assistant.d.ts.map +1 -0
  172. package/dist/components/ui/viglet-avatar.d.ts +44 -0
  173. package/dist/components/ui/viglet-avatar.d.ts.map +1 -0
  174. package/dist/contexts/breadcrumb.context.d.ts +7 -0
  175. package/dist/contexts/breadcrumb.context.d.ts.map +1 -1
  176. package/dist/contexts/user.context.d.ts +8 -0
  177. package/dist/contexts/user.context.d.ts.map +1 -1
  178. package/dist/exports.json +359 -30
  179. package/dist/floating-formulas-bg.cjs +1 -1
  180. package/dist/floating-formulas-bg.es.js +56 -55
  181. package/dist/hooks/index.d.ts +1 -0
  182. package/dist/hooks/index.d.ts.map +1 -1
  183. package/dist/hooks/use-assistant-notifications.d.ts +15 -0
  184. package/dist/hooks/use-assistant-notifications.d.ts.map +1 -0
  185. package/dist/i18n/index.d.ts +168 -0
  186. package/dist/i18n/index.d.ts.map +1 -1
  187. package/dist/i18n/locales/en/assistant.json.d.ts +25 -0
  188. package/dist/i18n/locales/en/bento.json.d.ts +48 -2
  189. package/dist/i18n/locales/en/common.json.d.ts +6 -1
  190. package/dist/i18n/locales/en/language.json.d.ts +8 -0
  191. package/dist/i18n/locales/pt/assistant.json.d.ts +25 -0
  192. package/dist/i18n/locales/pt/bento.json.d.ts +48 -2
  193. package/dist/i18n/locales/pt/common.json.d.ts +6 -1
  194. package/dist/i18n/locales/pt/language.json.d.ts +8 -0
  195. package/dist/i18n.cjs +1 -1
  196. package/dist/i18n.es.js +572 -2
  197. package/dist/index.cjs +1 -1
  198. package/dist/index.d.ts +0 -1
  199. package/dist/index.d.ts.map +1 -1
  200. package/dist/index.es.js +2280 -733
  201. package/dist/lib/busy.d.ts +26 -0
  202. package/dist/lib/busy.d.ts.map +1 -0
  203. package/dist/lib/corner-slot.d.ts +15 -0
  204. package/dist/lib/corner-slot.d.ts.map +1 -0
  205. package/dist/{loading-provider-BWWhhfEn.js → loading-provider-ClDkFPuv.js} +84 -81
  206. package/dist/loading-provider-DGuCfsl9.cjs +1 -0
  207. package/dist/preset.css +7 -10
  208. package/dist/router.cjs +1 -1
  209. package/dist/router.es.js +2 -776
  210. package/dist/user.context-Cr3GAQ_r.js +762 -0
  211. package/dist/user.context-hbdvmXOn.cjs +1 -0
  212. package/dist/utils-Fk5jmzzb.js +41 -0
  213. package/dist/utils-Oagwe_oa.cjs +1 -0
  214. package/dist/viglet-design-system.css +1 -1
  215. package/dist/vite/boot-loader.d.ts +33 -2
  216. package/dist/vite/boot-loader.d.ts.map +1 -1
  217. package/dist/vite.cjs +16 -5
  218. package/dist/vite.es.js +27 -14
  219. package/docs/BENTO-AUTHORING.md +81 -11
  220. package/docs/reference/grounds.dc.html +9 -9
  221. package/package.json +16 -4
  222. package/scripts/consumer-entries.mjs +209 -0
  223. package/scripts/lib/contrast.mjs +301 -0
  224. package/scripts/mcp.mjs +300 -0
  225. package/scripts/page-lint.mjs +428 -0
  226. package/scripts/page-reference.mjs +54 -10
  227. package/dist/badge-locale-CoEEv7s5.js +0 -581
  228. package/dist/badge-locale-hQyWhAKe.cjs +0 -7
  229. package/dist/breadcrumb.context-KQut7j8U.js +0 -917
  230. package/dist/breadcrumb.context-Vwc3lAlf.cjs +0 -1
  231. package/dist/components/router/blank-slate.d.ts +0 -21
  232. package/dist/components/router/blank-slate.d.ts.map +0 -1
  233. package/dist/components/router/grid.list.d.ts +0 -39
  234. package/dist/components/router/grid.list.d.ts.map +0 -1
  235. package/dist/components/router/internal.sidebar.d.ts +0 -61
  236. package/dist/components/router/internal.sidebar.d.ts.map +0 -1
  237. package/dist/components/router/nav-main.d.ts +0 -25
  238. package/dist/components/router/nav-main.d.ts.map +0 -1
  239. package/dist/components/router/nav-user.d.ts +0 -24
  240. package/dist/components/router/nav-user.d.ts.map +0 -1
  241. package/dist/components/router/page-content.d.ts +0 -12
  242. package/dist/components/router/page-content.d.ts.map +0 -1
  243. package/dist/components/router/page-header.d.ts +0 -23
  244. package/dist/components/router/page-header.d.ts.map +0 -1
  245. package/dist/components/router/page.d.ts +0 -22
  246. package/dist/components/router/page.d.ts.map +0 -1
  247. package/dist/components/router/sticky.page.header.d.ts +0 -85
  248. package/dist/components/router/sticky.page.header.d.ts.map +0 -1
  249. package/dist/components/router/sub.page.d.ts +0 -50
  250. package/dist/components/router/sub.page.d.ts.map +0 -1
  251. package/dist/components/router/sub.page.header.d.ts +0 -37
  252. package/dist/components/router/sub.page.header.d.ts.map +0 -1
  253. package/dist/i18n-DD3rQOWi.js +0 -426
  254. package/dist/i18n-DrBq-qJJ.cjs +0 -1
  255. package/dist/lib/react-markers.d.ts +0 -17
  256. package/dist/lib/react-markers.d.ts.map +0 -1
  257. package/dist/loading-provider-CmeMqLGk.cjs +0 -1
  258. package/dist/user.context-B9vIBzY5.cjs +0 -1
  259. package/dist/user.context-D1PxP4D4.js +0 -512
@@ -50,6 +50,35 @@ export interface VigletBootLoaderOptions {
50
50
  * Default: `"__VIGLET_LOADING_TEST__"`.
51
51
  */
52
52
  testFlag?: string;
53
+ /**
54
+ * Accessible name for the loader's status region — the whole phrase, not a
55
+ * word slotted into one. Default: `"Loading <title>"`.
56
+ *
57
+ * The loader is HTML written at build time and runs before any bundle, so it
58
+ * cannot ask i18next for anything; without this the first thing a screen
59
+ * reader hears in a Portuguese product is English. It is the complete label
60
+ * rather than a `loading` word plus the title, because where the product's
61
+ * name falls in the sentence is not the same in every language.
62
+ *
63
+ * ```ts
64
+ * vigletBootLoader({ …, loadingLabel: "Carregando o Viglet Turing ES" });
65
+ * ```
66
+ */
67
+ loadingLabel?: string;
68
+ /**
69
+ * Accessible names per language, for a product that ships more than one.
70
+ *
71
+ * The inline script already runs before paint, so it can read
72
+ * `navigator.language` and set the label from this map. Keys are language
73
+ * tags: an exact match wins (`"pt-BR"`), then the primary subtag (`"pt"`).
74
+ * Nothing matching leaves {@link loadingLabel} — or the English default —
75
+ * standing, which is also what a reader gets with scripting off.
76
+ *
77
+ * ```ts
78
+ * vigletBootLoader({ …, loadingLabels: { en: "Loading Turing", pt: "Carregando o Turing" } });
79
+ * ```
80
+ */
81
+ loadingLabels?: Record<string, string>;
53
82
  /**
54
83
  * HTML comment that the plugin replaces with the boot-loader markup. Put
55
84
  * it inside `<div id="root">` in your `index.html` (or `marketing.html`).
@@ -65,12 +94,14 @@ export interface VigletBootLoaderOptions {
65
94
  * build/dev time, so the loader visuals stay identical across the ecosystem and
66
95
  * there is a single place to evolve the design.
67
96
  *
68
- * Four of the seven consumers take it: Turing, Shio, Dumont and the Cloud Home.
97
+ * Four of the nine consumers take it: Turing, Shio, Dumont and the Cloud Home.
69
98
  * The Cloud Console and Schools are Next applications and have no Vite build to
70
99
  * plug into — they render their own first paint, which is what a server-rendered
71
100
  * page does instead of a boot loader. The Roadkeep GUI has a Vite build and
72
101
  * still does not take it: it ships as a desktop application, so its bundle is on
73
- * disk and nothing is waiting on a fetch to paint.
102
+ * disk and nothing is waiting on a fetch to paint. The Openviglet Website has
103
+ * one too and is a marketing site, where a boot loader is a spinner in front of
104
+ * copy; Viglet Docs is Docusaurus and has no Vite build at all.
74
105
  *
75
106
  * What the plugin injects:
76
107
  *
@@ -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;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAsEzE"}
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;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAuFzE"}
package/dist/vite.cjs CHANGED
@@ -1,4 +1,4 @@
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`
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-->`,loadingLabel:p,loadingLabels:m}=e,h=t(s,`color`),g=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 _={pfx:l,title:n,subtitle:o,color:s,colorDark:c,rgb:h,rgbDark:g,storageKey:u,testFlag:d,loadingLabel:p??`Loading ${n}`,loadingLabels:m},v=r(_),y=i(_),b=a(_);return{name:`viglet-boot-loader`,transformIndexHtml(e){let t;if(e.includes(f))t=e.replace(f,()=>b);else{let n=/(<div\b[^>]*\bid=["']root["'][^>]*>)/;n.test(e)?t=e.replace(n,e=>`${e}\n${b}\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:v,injectTo:`head`},{tag:`script`,children:y,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,8 +140,19 @@ 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 i({pfx:e,storageKey:t,testFlag:n}){return`
144
- (function () {
143
+ `.trim()}function i({pfx:e,storageKey:t,testFlag:n,loadingLabels:r}){return`
144
+ (function () {${r?`
145
+ try {
146
+ var labels = ${JSON.stringify(r)};
147
+ var tag = String(navigator.language || "");
148
+ var label = labels[tag] || labels[tag.split("-")[0]];
149
+ if (label) {
150
+ document.addEventListener("DOMContentLoaded", function () {
151
+ var region = document.getElementById(${JSON.stringify(e+`-boot-loader`)});
152
+ if (region) region.setAttribute("aria-label", label);
153
+ });
154
+ }
155
+ } catch (e) { /* ignore */ }`:``}
145
156
  try {
146
157
  var stored = localStorage.getItem(${JSON.stringify(t)});
147
158
  var prefersLight = stored === "light"
@@ -166,8 +177,8 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e)
166
177
  }
167
178
  } catch (e) { /* ignore */ }
168
179
  })();
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)}">
180
+ `.trim()}function a({pfx:e,title:t,subtitle:n,loadingLabel:r}){return`
181
+ <div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="${o(r)}">
171
182
  <div class="${e}-boot-stage">
172
183
  <div class="${e}-boot-ring"></div>
173
184
  <div class="${e}-boot-ring delay-1"></div>
package/dist/vite.es.js CHANGED
@@ -1,37 +1,39 @@
1
1
  //#region src/vite/boot-loader.ts
2
2
  function e(e) {
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");
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-->", loadingLabel: p, loadingLabels: m } = e, h = t(s, "color"), g = t(c, "colorDark");
4
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 = {
5
+ let _ = {
6
6
  pfx: l,
7
7
  title: n,
8
8
  subtitle: o,
9
9
  color: s,
10
10
  colorDark: c,
11
- rgb: p,
12
- rgbDark: m,
11
+ rgb: h,
12
+ rgbDark: g,
13
13
  storageKey: u,
14
- testFlag: d
15
- }, g = r(h), _ = i(h), v = a(h);
14
+ testFlag: d,
15
+ loadingLabel: p ?? `Loading ${n}`,
16
+ loadingLabels: m
17
+ }, v = r(_), y = i(_), b = a(_);
16
18
  return {
17
19
  name: "viglet-boot-loader",
18
20
  transformIndexHtml(e) {
19
21
  let t;
20
- if (e.includes(f)) t = e.replace(f, () => v);
22
+ if (e.includes(f)) t = e.replace(f, () => b);
21
23
  else {
22
24
  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);
25
+ n.test(e) ? t = e.replace(n, (e) => `${e}\n${b}\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
26
  }
25
27
  return {
26
28
  html: t,
27
29
  tags: [{
28
30
  tag: "style",
29
31
  attrs: { "data-viglet-boot-loader": "" },
30
- children: g,
32
+ children: v,
31
33
  injectTo: "head"
32
34
  }, {
33
35
  tag: "script",
34
- children: _,
36
+ children: y,
35
37
  injectTo: "head"
36
38
  }]
37
39
  };
@@ -202,9 +204,20 @@ function r({ pfx: e, color: t, colorDark: n, rgb: r }) {
202
204
  }
203
205
  `.trim();
204
206
  }
205
- function i({ pfx: e, storageKey: t, testFlag: n }) {
207
+ function i({ pfx: e, storageKey: t, testFlag: n, loadingLabels: r }) {
206
208
  return `
207
- (function () {
209
+ (function () {${r ? `
210
+ try {
211
+ var labels = ${JSON.stringify(r)};
212
+ var tag = String(navigator.language || "");
213
+ var label = labels[tag] || labels[tag.split("-")[0]];
214
+ if (label) {
215
+ document.addEventListener("DOMContentLoaded", function () {
216
+ var region = document.getElementById(${JSON.stringify(e + "-boot-loader")});
217
+ if (region) region.setAttribute("aria-label", label);
218
+ });
219
+ }
220
+ } catch (e) { /* ignore */ }` : ""}
208
221
  try {
209
222
  var stored = localStorage.getItem(${JSON.stringify(t)});
210
223
  var prefersLight = stored === "light"
@@ -231,9 +244,9 @@ function i({ pfx: e, storageKey: t, testFlag: n }) {
231
244
  })();
232
245
  `.trim();
233
246
  }
234
- function a({ pfx: e, title: t, subtitle: n }) {
247
+ function a({ pfx: e, title: t, subtitle: n, loadingLabel: r }) {
235
248
  return `
236
- <div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="Loading ${o(t)}">
249
+ <div id="${e}-boot-loader" role="status" aria-live="polite" aria-label="${o(r)}">
237
250
  <div class="${e}-boot-stage">
238
251
  <div class="${e}-boot-ring"></div>
239
252
  <div class="${e}-boot-ring delay-1"></div>
@@ -15,25 +15,51 @@ or by the product passing a prop. Almost all of the divergence between two produ
15
15
  from this layer is an argument about that ownership rather than about a component.
16
16
  [docs/reference/page-anatomy.dc.html](reference/page-anatomy.dc.html) draws it.
17
17
 
18
- **The nav is the rail** — fixed, one width, desktop only, with its gutter reserved by
19
- `bento-rail-gutter` on whatever wraps the routed page (§7).
18
+ **`BentoShell` is the shell.** Pass it the rail, the header's two edges and the routed
19
+ page; it owns the rest of this section.
20
+
21
+ ```tsx
22
+ <BentoShell
23
+ rail={<BentoNavRail groups={groups} homeRoute={ROUTES.HOME} />}
24
+ headerStart={<ProductMark />}
25
+ headerEnd={<BentoUserMenu accountRoute={ROUTES.ACCOUNT} logoutUrl={ROUTES.LOGOUT} />}
26
+ >
27
+ <Outlet />
28
+ </BentoShell>
29
+ ```
30
+
31
+ **The nav is the rail** — fixed, one width, desktop only. The shell reserves its gutter
32
+ when it is given one (§7).
20
33
 
21
34
  **The header carries a set, in this order:** the mark and wordmark; a back control where
22
35
  the route has a parent; the palette trigger, with the platform's own keyboard hint. On the
23
36
  trailing edge: the locale where a second one ships, the ground, and the signed-in user.
24
- `BentoBackToTop` sits at the corner.
37
+ The trigger is `BentoPaletteTrigger`, and `useBentoShellShortcuts` binds the keys it and
38
+ `BentoShortcutsDialog` show, so no product writes a keydown listener for them.
25
39
 
26
40
  Two things the header is not. It is not a second always-visible nav — the rail is the nav
27
41
  and the palette is the mobile one, and a second eats the width the content needs. And it is
28
42
  not a home for one surface's controls: a switcher or a pending count belongs to the surface
29
43
  that owns it, not to every page that renders beneath it.
30
44
 
45
+ **The corner is the shell's.** The assistant dock, passed as `dock`, takes it, and
46
+ `BentoBackToTop` stacks above the dock. Neither is fixed to the viewport inside the shell:
47
+ two components each pinning themselves to one corner is how the dock came to cover the
48
+ button.
49
+
31
50
  **The shell owns the reading column.** `main` sets the max width, the gutters and the
32
51
  vertical rhythm once, so every page begins and ends on the same line; a page sets none of
33
52
  the three. A narrower column for a single-question form is a variant the shell offers by
34
53
  name, not a class each page repeats. The moment pages set their own they disagree, and the
35
54
  defect exists only *between* screens — which is why nobody reviewing one of them sees it.
36
55
 
56
+ `column` names the variant: `default` for every page, `narrow` for a single-question
57
+ form, `wide` for a table or a board, and `full` for a tool that owns the viewport, such as
58
+ a chat, which fills the width and height and scrolls inside itself. The route decides the
59
+ variant and passes it to the shell; the page never does. Each width is a custom property
60
+ (`--bento-column-default`, `-narrow`, `-wide`), so a product re-keys one once.
61
+ `viglet-ds-page-lint` reports a page whose outermost element sets any of the three.
62
+
37
63
  **A page may own an aside**, inside that column and scrolling with it: filters, a contents
38
64
  list, a conversation. That is not the console era's sidebar, which collapses, remembers its
39
65
  width and pushes content — the reason that era needs a provider and this one does not.
@@ -61,6 +87,18 @@ there.
61
87
  `BentoEntityTile` for the common icon-chip + status-pill + title + meta shape;
62
88
  hand-roll a tile only when the entity genuinely needs a different layout.
63
89
 
90
+ A list a reader sorts, selects a range of and acts on in bulk, or one that runs
91
+ to thousands of rows, is `BentoDataTable` instead. It mounts only the visible rows,
92
+ its headers sort and say how, a row is reachable and selectable from the keyboard,
93
+ and row actions are a menu of named items. Pass the rows, the columns and the
94
+ actions, and store the column layout it reports. Never build a table from `Table`
95
+ and a scroll container: that is the list every console rebuilt before this one.
96
+
97
+ Filters over a list are `BentoFilterBar`: a search field, the facets you declare,
98
+ and the active filters as removable chips. It holds no state. Keep its value where
99
+ the URL can hold it, filter your rows with it, and pass the same value to the
100
+ table as `selectionScope`, so a selection never outlives the rows it was made on.
101
+
64
102
  **A form screen with its own hero** is `BentoFormHero` as the first child inside
65
103
  the `<form>` it submits. It renders both halves of the morph itself.
66
104
 
@@ -74,8 +112,26 @@ and no padding of its own — a table wants `p-0` and a toolbar wants `py-2`.
74
112
  Never hand-roll `bento-glass rounded-2xl border`: the moment two call sites pick
75
113
  different radii the product is inconsistent for a reason no diff shows.
76
114
 
77
- Two rules that outrank convenience:
78
-
115
+ Three rules that outrank convenience:
116
+
117
+ - **A back-link eyebrow leads with the arrow, and only a back-link does.** The
118
+ eyebrow above a hero's title is small, upper-case and set in muted text, which
119
+ is the same treatment whether it names the parent list or merely says what kind
120
+ of thing this is. The arrow is what separates them: with it the line reads as
121
+ the way back, without it as a label. So it is not decoration, and it is not
122
+ optional on one page because the layout looked tidier — it is the only
123
+ difference a reader has.
124
+ - `BentoEntityShell` gives you this for free: it links the eyebrow to
125
+ `listRoute` and puts the arrow in, so you pass the label alone.
126
+ - Every other hero takes `backTo` + `backLabel`. `BentoHero` and
127
+ `BentoFormHero` both render `BentoBackLink` from them.
128
+ - An eyebrow that needs something after the link — a status marker, a count —
129
+ is the one case for passing `eyebrow` yourself, and it composes
130
+ `BentoBackLink` rather than re-typing an arrow. `eyebrow` wins over `backTo`,
131
+ so a page that sets both silently loses the arrow.
132
+ - **Never put one on an eyebrow that navigates nowhere.** An arrow promises a
133
+ destination, and a promise the click does not keep is worse than the plain
134
+ label would have been.
79
135
  - **Identity lives in the hero, never in the form.** Title, description, icon
80
136
  and enabled state are the shell's; a form field for any of them is a second
81
137
  place to edit the same thing.
@@ -147,10 +203,13 @@ stylesheet imports this package and then declares its own `:root`, so it lands
147
203
  after the preset's dark block at the same specificity and in no layer. One value
148
204
  set there wins on *both* grounds, and the dark ground silently gets the light
149
205
  value. The inputs are read per ground, so you never write a dark block.
206
+ `viglet-ds-page-lint` reports a stylesheet or a style object that sets it.
150
207
 
151
208
  The solid fill carries text, so that pair holds 4.5:1 on both grounds (§6). An
152
209
  accent stop at full chroma usually does not, so this value is often a deeper step
153
- than the one the chip is drawn with.
210
+ than the one the chip is drawn with. `viglet-ds-page-lint --contrast <your
211
+ stylesheet>` measures every pair your re-key touches, on both grounds, before a
212
+ screenshot does.
154
213
 
155
214
  If you need a one-off tint, set `--bento-tone-from` / `--bento-tone-to` on a
156
215
  subtree instead of touching the tokens.
@@ -181,7 +240,18 @@ push, and a violation fails the build.
181
240
  `{boolean}` expression is a lint failure.
182
241
  - **Headings increase by one.** The hero is `h1`, so a section under it is `h2`
183
242
  — which is what `BentoFormSection` renders by default. A repeated label, like
184
- the sticky bar's title, is not a heading at all.
243
+ the sticky bar's title, is not a heading at all. `BentoEmptyState`'s title is an
244
+ `h2` too; pass `titleLevel={3}` when it sits inside a section.
245
+ - **Busy is not disabled.** A control whose action is running takes `loading`:
246
+ it says so with `aria-busy`, ignores a second press and keeps focus, where
247
+ `disabled` would drop the focus of the button just pressed as the result is
248
+ announced. A Save with nothing to save is `aria-disabled`, focusable and inert,
249
+ for the same reason. `disabled` is for a control that is genuinely unavailable.
250
+ - **Landmarks and focus are the shell's.** `BentoShell` renders the one `main`,
251
+ labelled, and a skip link as the first thing a keyboard reaches. On a route
252
+ change it moves focus to the new page's `h1` and announces it, so give every
253
+ page exactly one `h1` (the hero is one) and never manage focus on navigation
254
+ yourself.
185
255
  - **Contrast holds at 4.5:1**, including text on a tinted surface. Tinted pills
186
256
  need the darker text token in light mode.
187
257
  - **Reduced motion**: every animation in `bento.css` is turned off under
@@ -195,10 +265,10 @@ push, and a violation fails the build.
195
265
  tiles and `row-span-2` for a featured one. **Keep spans in multiples of two**
196
266
  so tiles reflow cleanly at every breakpoint — this is what keeps two consoles'
197
267
  grids aligned.
198
- - The nav rail is desktop-only. Reserve its gutter with `bento-rail-gutter` on
199
- whatever wraps the routed page. On mobile, navigation is the header's command
200
- trigger and the global shortcut; do not add a second always-visible nav that
201
- eats mobile width.
268
+ - The nav rail is desktop-only. `BentoShell` reserves its gutter; a shell that is
269
+ still a product's own puts `bento-rail-gutter` on whatever wraps the routed page.
270
+ On mobile, navigation is the header's command trigger and the global shortcut;
271
+ do not add a second always-visible nav that eats mobile width.
202
272
  - There is **no sidebar provider**, and no context between the shell's pieces.
203
273
  The console era needs one because its sidebar collapses, remembers and pushes
204
274
  content; the rail is fixed, one width, and hidden below `md`. That is about the
@@ -33,7 +33,7 @@
33
33
  <div class="eyebrow" style="color:#1447e6">REFERENCE</div>
34
34
  <div style="display:flex;align-items:baseline;gap:12px;margin-top:4px">
35
35
  <div style="font-size:21px;font-weight:600;letter-spacing:-0.015em">Both grounds, and nothing told by colour alone</div>
36
- <div style="font-size:12.5px;color:#737373">The same components twice. Every state carries a dot or a word as well as a hue.</div>
36
+ <div style="font-size:12.5px;color:#696969">The same components twice. Every state carries a dot or a word as well as a hue.</div>
37
37
  </div>
38
38
  </div>
39
39
 
@@ -42,7 +42,7 @@
42
42
  <!-- LIGHT -->
43
43
  <div style="border:1px solid #e5e5e5;border-radius:14px;background:#ffffff;padding:15px;display:flex;flex-direction:column;gap:12px;overflow:hidden">
44
44
  <div style="display:flex;align-items:center;gap:9px">
45
- <span class="eyebrow" style="color:#737373">LIGHT</span>
45
+ <span class="eyebrow" style="color:#696969">LIGHT</span>
46
46
  <span class="mono" style="font-size:10px;color:#a1a1a1">--vg-background oklch(1 0 0)</span>
47
47
  </div>
48
48
 
@@ -53,22 +53,22 @@
53
53
  <div style="flex:1"></div>
54
54
  <span class="ratio pass">19.8:1</span>
55
55
  </div>
56
- <div style="font-size:11.5px;color:#737373;line-height:1.45">A line of muted description, which is the pair a panel is most likely to reach for.</div>
57
- <div style="display:flex;align-items:center;gap:7px;margin-top:7px"><span class="ratio pass">4.73:1</span><span style="font-size:10px;color:#737373">muted on the ground</span></div>
56
+ <div style="font-size:11.5px;color:#696969;line-height:1.45">A line of muted description, which is the pair a panel is most likely to reach for.</div>
57
+ <div style="display:flex;align-items:center;gap:7px;margin-top:7px"><span class="ratio pass">5.51:1</span><span style="font-size:10px;color:#696969">muted on the ground</span></div>
58
58
  </div>
59
59
 
60
60
  <div>
61
- <div class="eyebrow" style="color:#737373;margin-bottom:7px">STATUS -- A DOT AND A WORD</div>
61
+ <div class="eyebrow" style="color:#696969;margin-bottom:7px">STATUS -- A DOT AND A WORD</div>
62
62
  <div style="display:flex;flex-wrap:wrap;gap:6px">
63
63
  <span style="display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 9px;border-radius:999px;border:1px solid rgba(0,188,125,0.4);background:rgba(0,188,125,0.1);color:#007a55;font-size:11px;font-weight:600"><span style="width:6px;height:6px;border-radius:999px;background:#00bc7d"></span>On</span>
64
64
  <span style="display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 9px;border-radius:999px;border:1px solid rgba(254,154,0,0.4);background:rgba(254,154,0,0.1);color:#973c00;font-size:11px;font-weight:600"><span style="width:6px;height:6px;border-radius:999px;background:#fe9a00"></span>Warn</span>
65
65
  <span style="display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 9px;border-radius:999px;border:1px solid rgba(251,44,54,0.4);background:rgba(251,44,54,0.1);color:#c10007;font-size:11px;font-weight:600"><span style="width:6px;height:6px;border-radius:999px;background:#fb2c36"></span>Error</span>
66
66
  </div>
67
- <div style="font-size:10px;color:#737373;margin-top:6px">Tinted surfaces take the darker text token here, which is the whole reason there are two.</div>
67
+ <div style="font-size:10px;color:#696969;margin-top:6px">Tinted surfaces take the darker text token here, which is the whole reason there are two.</div>
68
68
  </div>
69
69
 
70
70
  <div>
71
- <div class="eyebrow" style="color:#737373;margin-bottom:7px">THE ACCENT, AND THE FOCUS RING</div>
71
+ <div class="eyebrow" style="color:#696969;margin-bottom:7px">THE ACCENT, AND THE FOCUS RING</div>
72
72
  <div style="display:flex;align-items:center;gap:9px">
73
73
  <div style="display:inline-flex;align-items:center;height:32px;padding:0 13px;border-radius:10px;background:#1447e6;color:#ffffff;font-size:12.5px;font-weight:500">Primary</div>
74
74
  <div style="display:inline-flex;align-items:center;height:32px;padding:0 13px;border-radius:10px;border:1px solid #e5e5e5;color:#0a0a0a;font-size:12.5px;font-weight:500;box-shadow:0 0 0 3px rgba(20,71,230,0.35)">Focused</div>
@@ -124,12 +124,12 @@
124
124
 
125
125
  <div style="margin:14px 24px 18px;border:1px solid #e5e5e5;background:#ffffff;border-radius:12px;padding:11px 14px;display:flex;gap:18px;align-items:flex-start">
126
126
  <div style="flex:1">
127
- <div class="eyebrow" style="color:#737373;margin-bottom:4px">THE ACCENT IS THE SAME RATIO ON BOTH GROUNDS</div>
127
+ <div class="eyebrow" style="color:#696969;margin-bottom:4px">THE ACCENT IS THE SAME RATIO ON BOTH GROUNDS</div>
128
128
  <div style="font-size:12px;color:#404040;line-height:1.5">6.83 and 6.79. That is not luck -- it is what the two readable inputs are for. A product that states one accent value and lets the other ground inherit gets one of these numbers and not the other.</div>
129
129
  </div>
130
130
  <div style="width:1px;align-self:stretch;background:#ededed"></div>
131
131
  <div style="width:340px">
132
- <div class="eyebrow" style="color:#737373;margin-bottom:4px">A STATE IS NEVER ONLY A HUE</div>
132
+ <div class="eyebrow" style="color:#696969;margin-bottom:4px">A STATE IS NEVER ONLY A HUE</div>
133
133
  <div style="font-size:12px;color:#404040;line-height:1.5">Every pill above carries a dot and a word. A reader who cannot separate the three hues still reads three states.</div>
134
134
  </div>
135
135
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viglet/viglet-design-system",
3
- "version": "2026.3.9",
3
+ "version": "2026.3.11",
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",
@@ -33,6 +33,8 @@
33
33
  "require": "./dist/assets.cjs"
34
34
  },
35
35
  "./exports.json": "./dist/exports.json",
36
+ "./catalogue.json": "./dist/catalogue.json",
37
+ "./consumers.json": "./consumers.json",
36
38
  "./styles": "./dist/viglet-design-system.css",
37
39
  "./fonts": "./dist/fonts.css",
38
40
  "./fonts.css": "./dist/fonts.css",
@@ -62,11 +64,19 @@
62
64
  },
63
65
  "bin": {
64
66
  "viglet-ds-check-duplicates": "./scripts/check-duplicates.mjs",
67
+ "viglet-ds-consumer-entries": "./scripts/consumer-entries.mjs",
68
+ "viglet-ds-mcp": "./scripts/mcp.mjs",
69
+ "viglet-ds-page-lint": "./scripts/page-lint.mjs",
65
70
  "viglet-ds-page-reference": "./scripts/page-reference.mjs"
66
71
  },
67
72
  "files": [
68
73
  "dist",
74
+ "consumers.json",
69
75
  "scripts/check-duplicates.mjs",
76
+ "scripts/consumer-entries.mjs",
77
+ "scripts/mcp.mjs",
78
+ "scripts/page-lint.mjs",
79
+ "scripts/lib/contrast.mjs",
70
80
  "scripts/page-reference.mjs",
71
81
  "docs/BENTO-AUTHORING.md",
72
82
  "docs/BENTO-BOUNDARY.md",
@@ -81,6 +91,7 @@
81
91
  "next-themes": ">=0.4.0",
82
92
  "react": "^18.0.0 || ^19.0.0",
83
93
  "react-dom": "^18.0.0 || ^19.0.0",
94
+ "react-hook-form": "^7.71.2",
84
95
  "react-i18next": ">=15.0.0",
85
96
  "react-router-dom": "^7.0.0",
86
97
  "sonner": ">=2.0.0"
@@ -123,7 +134,6 @@
123
134
  "date-fns": "^4.1.0",
124
135
  "lucide-react": "^1.0.1",
125
136
  "radix-ui": "^1.4.3",
126
- "react-hook-form": "^7.71.2",
127
137
  "react-resizable-panels": "^4.7.3",
128
138
  "tailwind-merge": "^3.5.0",
129
139
  "vaul": "^1.1.2",
@@ -157,6 +167,7 @@
157
167
  "jsdom": "^30.0.1",
158
168
  "next-themes": "^0.4.6",
159
169
  "playwright": "^1.62.1",
170
+ "react-hook-form": "^7.71.2",
160
171
  "react-i18next": "^17.0.12",
161
172
  "react-router-dom": "^7.0.0",
162
173
  "semver": "^7.8.5",
@@ -176,14 +187,15 @@
176
187
  },
177
188
  "scripts": {
178
189
  "dev": "vite build --watch",
179
- "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",
190
+ "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/emit-catalogue.mjs && node scripts/check-dist.mjs && node scripts/check-exports.mjs && node scripts/check-catalogue.mjs && node scripts/check-readme.mjs && node scripts/check-size.mjs",
180
191
  "check:dist": "node scripts/check-dist.mjs",
181
192
  "check:size": "node scripts/check-size.mjs",
182
- "typecheck": "tsc -b --force",
193
+ "typecheck": "tsc -b --force && tsc -p .storybook/tsconfig.json --noEmit",
183
194
  "lint": "eslint . --max-warnings 0",
184
195
  "test": "vitest run",
185
196
  "test:watch": "vitest",
186
197
  "use:local": "node scripts/use-local.mjs",
198
+ "chrome:census": "node scripts/chrome-census.mjs",
187
199
  "storybook": "storybook dev -p 6006",
188
200
  "build-storybook": "storybook build",
189
201
  "build:fonts": "node scripts/build-fonts.mjs",