@inglorious/ui 0.1.0 → 1.0.0

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 (283) hide show
  1. package/README.md +45 -0
  2. package/package.json +191 -16
  3. package/src/all.css +7 -0
  4. package/src/controls/button/button.stories.js +35 -15
  5. package/src/controls/button/index.js +1 -3
  6. package/src/controls/button/style.css +80 -37
  7. package/src/controls/button/template.js +23 -26
  8. package/src/controls/button-group/button-group.stories.js +19 -15
  9. package/src/controls/button-group/index.js +1 -2
  10. package/src/controls/button-group/style.css +0 -7
  11. package/src/controls/button-group/template.js +46 -56
  12. package/src/controls/checkbox/checkbox.stories.js +16 -13
  13. package/src/controls/checkbox/index.js +1 -2
  14. package/src/controls/checkbox/style.css +23 -2
  15. package/src/controls/checkbox/template.js +20 -18
  16. package/src/controls/combobox/combobox.stories.js +92 -0
  17. package/src/controls/{select → combobox}/handlers.js +8 -5
  18. package/src/controls/combobox/helpers.js +91 -0
  19. package/src/controls/combobox/index.js +43 -0
  20. package/src/controls/combobox/style.css +203 -0
  21. package/src/controls/combobox/template.js +340 -0
  22. package/src/controls/controls.css +12 -0
  23. package/src/controls/fab/fab.stories.js +11 -11
  24. package/src/controls/fab/index.js +1 -2
  25. package/src/controls/fab/template.js +21 -19
  26. package/src/controls/icon-button/icon-button.stories.js +8 -10
  27. package/src/controls/icon-button/index.js +1 -2
  28. package/src/controls/icon-button/template.js +13 -19
  29. package/src/controls/input/index.js +1 -2
  30. package/src/controls/input/input.stories.js +24 -23
  31. package/src/controls/input/style.css +9 -7
  32. package/src/controls/input/template.js +28 -31
  33. package/src/controls/radio-group/index.js +1 -2
  34. package/src/controls/radio-group/radio-group.stories.js +11 -8
  35. package/src/controls/radio-group/style.css +22 -1
  36. package/src/controls/radio-group/template.js +20 -15
  37. package/src/controls/rating/index.js +1 -2
  38. package/src/controls/rating/rating.stories.js +7 -10
  39. package/src/controls/rating/style.css +1 -2
  40. package/src/controls/rating/template.js +20 -17
  41. package/src/controls/select/helpers.js +2 -21
  42. package/src/controls/select/index.js +1 -13
  43. package/src/controls/select/select.stories.js +68 -64
  44. package/src/controls/select/style.css +66 -189
  45. package/src/controls/select/template.js +77 -406
  46. package/src/controls/slider/index.js +1 -2
  47. package/src/controls/slider/slider.stories.js +15 -12
  48. package/src/controls/slider/style.css +24 -3
  49. package/src/controls/slider/template.js +30 -23
  50. package/src/controls/switch/index.js +1 -2
  51. package/src/controls/switch/style.css +23 -2
  52. package/src/controls/switch/switch.stories.js +14 -11
  53. package/src/controls/switch/template.js +18 -16
  54. package/src/data-display/avatar/avatar.stories.js +106 -0
  55. package/src/data-display/avatar/index.js +3 -0
  56. package/src/data-display/avatar/style.css +64 -0
  57. package/src/data-display/avatar/template.js +81 -0
  58. package/src/data-display/badge/badge.stories.js +64 -0
  59. package/src/data-display/badge/index.js +3 -0
  60. package/src/data-display/badge/style.css +84 -0
  61. package/src/data-display/badge/template.js +46 -0
  62. package/src/data-display/chip/chip.stories.js +57 -0
  63. package/src/data-display/chip/index.js +3 -0
  64. package/src/data-display/chip/style.css +84 -0
  65. package/src/data-display/chip/template.js +32 -0
  66. package/src/data-display/data-display.css +11 -0
  67. package/src/data-display/data-grid/base.css +58 -0
  68. package/src/data-display/data-grid/data-grid.stories.js +158 -0
  69. package/src/data-display/data-grid/filters/helpers.js +8 -0
  70. package/src/data-display/data-grid/filters/index.js +21 -0
  71. package/src/data-display/data-grid/filters/input.js +24 -0
  72. package/src/data-display/data-grid/filters/range.js +48 -0
  73. package/src/data-display/data-grid/filters/select.js +17 -0
  74. package/src/data-display/data-grid/handlers.js +523 -0
  75. package/src/data-display/data-grid/helpers.js +248 -0
  76. package/src/data-display/data-grid/index.js +64 -0
  77. package/src/data-display/data-grid/style.css +14 -0
  78. package/src/data-display/data-grid/template.js +458 -0
  79. package/src/data-display/data-grid/theme.css +148 -0
  80. package/src/data-display/divider/divider.stories.js +48 -0
  81. package/src/data-display/divider/index.js +3 -0
  82. package/src/data-display/divider/style.css +18 -0
  83. package/src/data-display/divider/template.js +17 -0
  84. package/src/data-display/icon/icon-implementations.mdx +160 -0
  85. package/src/data-display/icon/icon-utf8.stories.js +156 -0
  86. package/src/data-display/icon/icon.stories.js +38 -0
  87. package/src/data-display/icon/index.js +3 -0
  88. package/src/data-display/icon/style.css +17 -0
  89. package/src/data-display/icon/template.js +19 -0
  90. package/src/data-display/list/handlers.js +25 -0
  91. package/src/data-display/list/index.js +4 -0
  92. package/src/data-display/list/list.stories.js +187 -0
  93. package/src/data-display/list/style.css +119 -0
  94. package/src/data-display/list/template.js +302 -0
  95. package/src/data-display/material-icon/index.js +3 -0
  96. package/src/data-display/material-icon/material-icon.stories.js +99 -0
  97. package/src/data-display/material-icon/style.css +27 -0
  98. package/src/data-display/material-icon/template.js +21 -0
  99. package/src/data-display/table/index.js +1 -0
  100. package/src/data-display/table/style.css +42 -0
  101. package/src/data-display/table/table.stories.js +40 -0
  102. package/src/data-display/table/template.js +114 -0
  103. package/src/data-display/tooltip/index.js +3 -0
  104. package/src/data-display/tooltip/style.css +57 -0
  105. package/src/data-display/tooltip/template.js +58 -0
  106. package/src/data-display/tooltip/tooltip.stories.js +44 -0
  107. package/src/data-display/typography/index.js +3 -0
  108. package/src/data-display/typography/style.css +49 -0
  109. package/src/data-display/typography/template.js +110 -0
  110. package/src/data-display/typography/typography.stories.js +48 -0
  111. package/src/data-display/virtual-list/handlers.js +68 -0
  112. package/src/data-display/virtual-list/index.js +4 -0
  113. package/src/data-display/virtual-list/template.js +101 -0
  114. package/src/examples/dashboard/app-drawer.js +255 -0
  115. package/src/examples/dashboard/app-header.js +149 -0
  116. package/src/examples/dashboard/dashboard.js +85 -0
  117. package/src/examples/dashboard/dashboard.stories.js +47 -0
  118. package/src/examples/dashboard/data.js +205 -0
  119. package/src/examples/dashboard/mode.js +27 -0
  120. package/src/examples/dashboard/primitive-content.js +1325 -0
  121. package/src/examples/dashboard/primitive-section.js +158 -0
  122. package/src/examples/dashboard/router.js +13 -0
  123. package/src/examples/dashboard/social-card.js +73 -0
  124. package/src/examples/dashboard/stat-card.js +84 -0
  125. package/src/examples/dashboard/style.css +339 -0
  126. package/src/examples/dashboard/theme-utils.js +95 -0
  127. package/src/examples/dashboard/theme.js +27 -0
  128. package/src/examples/dashboard/traffic-card.js +108 -0
  129. package/src/examples/dashboard/traffic-sales-card.js +267 -0
  130. package/src/feedback/alert/alert.stories.js +70 -0
  131. package/src/feedback/alert/index.js +3 -0
  132. package/src/feedback/alert/style.css +98 -0
  133. package/src/feedback/alert/template.js +74 -0
  134. package/src/feedback/backdrop/backdrop.stories.js +21 -0
  135. package/src/feedback/backdrop/index.js +3 -0
  136. package/src/feedback/backdrop/style.css +25 -0
  137. package/src/feedback/backdrop/template.js +31 -0
  138. package/src/feedback/dialog/dialog.stories.js +27 -0
  139. package/src/feedback/dialog/index.js +3 -0
  140. package/src/feedback/dialog/style.css +68 -0
  141. package/src/feedback/dialog/template.js +64 -0
  142. package/src/feedback/feedback.css +6 -0
  143. package/src/feedback/progress/index.js +3 -0
  144. package/src/feedback/progress/progress.stories.js +54 -0
  145. package/src/feedback/progress/style.css +95 -0
  146. package/src/feedback/progress/template.js +88 -0
  147. package/src/feedback/skeleton/index.js +3 -0
  148. package/src/feedback/skeleton/skeleton.stories.js +44 -0
  149. package/src/feedback/skeleton/style.css +41 -0
  150. package/src/feedback/skeleton/template.js +48 -0
  151. package/src/feedback/snackbar/index.js +3 -0
  152. package/src/feedback/snackbar/snackbar.stories.js +25 -0
  153. package/src/feedback/snackbar/style.css +64 -0
  154. package/src/feedback/snackbar/template.js +55 -0
  155. package/src/index.js +32 -1
  156. package/src/layout/container/container.stories.js +105 -0
  157. package/src/layout/container/index.js +3 -0
  158. package/src/layout/container/style.css +34 -0
  159. package/src/layout/container/template.js +119 -0
  160. package/src/layout/flex/flex.stories.js +28 -10
  161. package/src/layout/flex/index.js +1 -2
  162. package/src/layout/flex/style.css +20 -0
  163. package/src/layout/flex/template.js +40 -13
  164. package/src/layout/grid/grid.stories.js +46 -30
  165. package/src/layout/grid/index.js +1 -2
  166. package/src/layout/grid/style.css +20 -0
  167. package/src/layout/grid/template.js +100 -20
  168. package/src/layout/layout.css +3 -0
  169. package/src/navigation/bottom-navigation/bottom-navigation.stories.js +33 -0
  170. package/src/navigation/bottom-navigation/index.js +1 -0
  171. package/src/navigation/bottom-navigation/style.css +32 -0
  172. package/src/navigation/bottom-navigation/template.js +74 -0
  173. package/src/navigation/breadcrumbs/breadcrumbs.stories.js +33 -0
  174. package/src/navigation/breadcrumbs/index.js +1 -0
  175. package/src/navigation/breadcrumbs/style.css +27 -0
  176. package/src/navigation/breadcrumbs/template.js +79 -0
  177. package/src/navigation/drawer/drawer.stories.js +60 -0
  178. package/src/navigation/drawer/index.js +3 -0
  179. package/src/navigation/drawer/style.css +125 -0
  180. package/src/navigation/drawer/template.js +131 -0
  181. package/src/navigation/link/index.js +3 -0
  182. package/src/navigation/link/link.stories.js +53 -0
  183. package/src/navigation/link/style.css +40 -0
  184. package/src/navigation/link/template.js +53 -0
  185. package/src/navigation/menu/index.js +1 -0
  186. package/src/navigation/menu/menu.stories.js +36 -0
  187. package/src/navigation/menu/style.css +44 -0
  188. package/src/navigation/menu/template.js +81 -0
  189. package/src/navigation/navigation.css +9 -0
  190. package/src/navigation/pagination/index.js +1 -0
  191. package/src/navigation/pagination/pagination.stories.js +61 -0
  192. package/src/navigation/pagination/style.css +29 -0
  193. package/src/navigation/pagination/template.js +140 -0
  194. package/src/navigation/speed-dial/index.js +1 -0
  195. package/src/navigation/speed-dial/speed-dial.stories.js +40 -0
  196. package/src/navigation/speed-dial/style.css +38 -0
  197. package/src/navigation/speed-dial/template.js +68 -0
  198. package/src/navigation/stepper/index.js +1 -0
  199. package/src/navigation/stepper/stepper.stories.js +35 -0
  200. package/src/navigation/stepper/style.css +49 -0
  201. package/src/navigation/stepper/template.js +61 -0
  202. package/src/navigation/tabs/index.js +1 -0
  203. package/src/navigation/tabs/style.css +35 -0
  204. package/src/navigation/tabs/tabs.stories.js +40 -0
  205. package/src/navigation/tabs/template.js +79 -0
  206. package/src/overview.mdx +39 -0
  207. package/src/stories/notifyStory.js +22 -25
  208. package/src/styles/base.css +2 -0
  209. package/src/styles/reset.css +15 -0
  210. package/src/{themes → styles/themes}/bootstrap.css +2 -0
  211. package/src/{themes → styles/themes}/inglorious.css +9 -1
  212. package/src/{themes → styles/themes}/material.css +2 -0
  213. package/src/{tokens/index.css → styles/tokens.css} +9 -0
  214. package/src/surfaces/accordion/accordion.stories.js +60 -0
  215. package/src/surfaces/accordion/index.js +1 -0
  216. package/src/surfaces/accordion/style.css +64 -0
  217. package/src/surfaces/accordion/template.js +85 -0
  218. package/src/surfaces/app-bar/app-bar.stories.js +109 -0
  219. package/src/surfaces/app-bar/index.js +3 -0
  220. package/src/surfaces/app-bar/style.css +109 -0
  221. package/src/surfaces/app-bar/template.js +78 -0
  222. package/src/surfaces/card/card.stories.js +108 -0
  223. package/src/surfaces/card/index.js +1 -0
  224. package/src/surfaces/card/style.css +107 -0
  225. package/src/surfaces/card/template.js +163 -0
  226. package/src/surfaces/paper/index.js +3 -0
  227. package/src/surfaces/paper/paper.stories.js +97 -0
  228. package/src/surfaces/paper/style.css +73 -0
  229. package/src/surfaces/paper/template.js +76 -0
  230. package/src/surfaces/surfaces.css +4 -0
  231. package/types/controls/button-group.d.ts +8 -7
  232. package/types/controls/button.d.ts +10 -7
  233. package/types/controls/checkbox.d.ts +8 -6
  234. package/types/controls/combobox.d.ts +66 -0
  235. package/types/controls/fab.d.ts +6 -5
  236. package/types/controls/icon-button.d.ts +8 -7
  237. package/types/controls/input.d.ts +18 -11
  238. package/types/controls/radio-group.d.ts +7 -5
  239. package/types/controls/rating.d.ts +6 -5
  240. package/types/controls/select.d.ts +11 -34
  241. package/types/controls/slider.d.ts +8 -6
  242. package/types/controls/switch.d.ts +7 -5
  243. package/types/data-display/avatar.d.ts +30 -0
  244. package/types/data-display/badge.d.ts +20 -0
  245. package/types/data-display/chip.d.ts +25 -0
  246. package/types/data-display/data-grid.d.ts +151 -0
  247. package/types/data-display/divider.d.ts +14 -0
  248. package/types/data-display/icon.d.ts +16 -0
  249. package/types/data-display/list.d.ts +66 -0
  250. package/types/data-display/material-icon.d.ts +15 -0
  251. package/types/data-display/table.d.ts +45 -0
  252. package/types/data-display/tooltip.d.ts +20 -0
  253. package/types/data-display/typography.d.ts +28 -0
  254. package/types/data-display/virtual-list.d.ts +94 -0
  255. package/types/feedback/alert.d.ts +22 -0
  256. package/types/feedback/backdrop.d.ts +17 -0
  257. package/types/feedback/dialog.d.ts +21 -0
  258. package/types/feedback/progress.d.ts +18 -0
  259. package/types/feedback/skeleton.d.ts +18 -0
  260. package/types/feedback/snackbar.d.ts +19 -0
  261. package/types/index.d.ts +92 -14
  262. package/types/layout/container.d.ts +28 -0
  263. package/types/layout/flex.d.ts +16 -5
  264. package/types/layout/grid.d.ts +15 -4
  265. package/types/navigation/bottom-navigation.d.ts +33 -0
  266. package/types/navigation/breadcrumbs.d.ts +29 -0
  267. package/types/navigation/drawer.d.ts +23 -0
  268. package/types/navigation/link.d.ts +22 -0
  269. package/types/navigation/menu.d.ts +32 -0
  270. package/types/navigation/pagination.d.ts +50 -0
  271. package/types/navigation/speed-dial.d.ts +35 -0
  272. package/types/navigation/stepper.d.ts +26 -0
  273. package/types/navigation/tabs.d.ts +31 -0
  274. package/types/surfaces/accordion.d.ts +32 -0
  275. package/types/surfaces/app-bar.d.ts +25 -0
  276. package/types/surfaces/card.d.ts +39 -0
  277. package/types/surfaces/paper.d.ts +28 -0
  278. package/src/shared/withRenderValidation.js +0 -19
  279. package/src/widgets/card/card.stories.js +0 -135
  280. package/src/widgets/card/index.js +0 -4
  281. package/src/widgets/card/style.css +0 -53
  282. package/src/widgets/card/template.js +0 -97
  283. package/types/widgets/card.d.ts +0 -21
@@ -0,0 +1,1325 @@
1
+ import { html } from "@inglorious/web"
2
+
3
+ import { button } from "../../controls/button/index.js"
4
+ import { buttonGroup } from "../../controls/button-group/index.js"
5
+ import { checkbox } from "../../controls/checkbox/index.js"
6
+ import { combobox } from "../../controls/combobox/index.js"
7
+ import { fab } from "../../controls/fab/index.js"
8
+ import { iconButton } from "../../controls/icon-button/index.js"
9
+ import { input } from "../../controls/input/index.js"
10
+ import { radioGroup } from "../../controls/radio-group/index.js"
11
+ import { rating } from "../../controls/rating/index.js"
12
+ import { select } from "../../controls/select/index.js"
13
+ import { slider } from "../../controls/slider/index.js"
14
+ import { switchControl } from "../../controls/switch/index.js"
15
+ import { avatar } from "../../data-display/avatar/index.js"
16
+ import { badge } from "../../data-display/badge/index.js"
17
+ import { chip } from "../../data-display/chip/index.js"
18
+ import { dataGrid } from "../../data-display/data-grid/index.js"
19
+ import { divider } from "../../data-display/divider/index.js"
20
+ import { icon } from "../../data-display/icon/index.js"
21
+ import { list } from "../../data-display/list/index.js"
22
+ import { materialIcon } from "../../data-display/material-icon/index.js"
23
+ import { table } from "../../data-display/table/index.js"
24
+ import { tooltip } from "../../data-display/tooltip/index.js"
25
+ import { typography } from "../../data-display/typography/index.js"
26
+ import { alert } from "../../feedback/alert/index.js"
27
+ import { backdrop } from "../../feedback/backdrop/index.js"
28
+ import { dialog } from "../../feedback/dialog/index.js"
29
+ import { progress } from "../../feedback/progress/index.js"
30
+ import { skeleton } from "../../feedback/skeleton/index.js"
31
+ import { snackbar } from "../../feedback/snackbar/index.js"
32
+ import { container } from "../../layout/container/index.js"
33
+ import { flex } from "../../layout/flex/index.js"
34
+ import { grid } from "../../layout/grid/index.js"
35
+ import { bottomNavigation } from "../../navigation/bottom-navigation/index.js"
36
+ import { breadcrumbs } from "../../navigation/breadcrumbs/index.js"
37
+ import { drawer } from "../../navigation/drawer/index.js"
38
+ import { link } from "../../navigation/link/index.js"
39
+ import { menu } from "../../navigation/menu/index.js"
40
+ import { pagination } from "../../navigation/pagination/index.js"
41
+ import { speedDial } from "../../navigation/speed-dial/index.js"
42
+ import { stepper } from "../../navigation/stepper/index.js"
43
+ import { tabs } from "../../navigation/tabs/index.js"
44
+ import { accordion } from "../../surfaces/accordion/index.js"
45
+ import { appBar } from "../../surfaces/app-bar/index.js"
46
+ import { card } from "../../surfaces/card/index.js"
47
+ import { paper } from "../../surfaces/paper/index.js"
48
+
49
+ const categoryMeta = {
50
+ layout: {
51
+ label: "Layout",
52
+ summary:
53
+ "Layout primitives define structure, spacing, and responsive flow.",
54
+ verb: "structuring pages and layouts",
55
+ useCases: [
56
+ "Scaffold page sections",
57
+ "Control spacing and alignment",
58
+ "Build responsive grids",
59
+ ],
60
+ },
61
+ controls: {
62
+ label: "Controls",
63
+ summary: "Controls capture user input and trigger actions.",
64
+ verb: "capturing user input and actions",
65
+ useCases: ["Primary actions", "Form inputs", "State toggles"],
66
+ },
67
+ "data-display": {
68
+ label: "Data Display",
69
+ summary:
70
+ "Data display primitives present information, status, and metrics.",
71
+ verb: "presenting data and status",
72
+ useCases: ["Show metrics", "Summarize status", "Structure dense data"],
73
+ },
74
+ feedback: {
75
+ label: "Feedback",
76
+ summary: "Feedback primitives communicate system state and validation.",
77
+ verb: "communicating system state and validation",
78
+ useCases: ["Surface errors", "Indicate progress", "Confirm system actions"],
79
+ },
80
+ navigation: {
81
+ label: "Navigation",
82
+ summary:
83
+ "Navigation primitives help users move between views and sections.",
84
+ verb: "moving between views and sections",
85
+ useCases: ["App-level navigation", "In-page navigation", "Wayfinding"],
86
+ },
87
+ surfaces: {
88
+ label: "Surfaces",
89
+ summary: "Surfaces group content and provide visual hierarchy.",
90
+ verb: "grouping and layering content",
91
+ useCases: [
92
+ "Content containment",
93
+ "Elevation and hierarchy",
94
+ "Section organization",
95
+ ],
96
+ },
97
+ }
98
+
99
+ const previewRow = (children) =>
100
+ html`<div class="iw-primitive-preview-row">${children}</div>`
101
+
102
+ const previewColumn = (children) =>
103
+ html`<div class="iw-primitive-preview-column">${children}</div>`
104
+
105
+ const primitiveDetailsByPath = {
106
+ "/layout/container": {
107
+ summary: "Constrains content width and applies consistent gutters.",
108
+ description:
109
+ "Container is the primary boundary component for predictable line length and horizontal rhythm.",
110
+ useCases: [
111
+ "Page shell sections",
112
+ "Readable content columns",
113
+ "Consistent guttering",
114
+ ],
115
+ example: {
116
+ code: `import { container } from "@inglorious/ui/container"
117
+ import { typography } from "@inglorious/ui/typography"
118
+
119
+ container.render({
120
+ maxWidth: "md",
121
+ padding: "lg",
122
+ children: typography.render({
123
+ variant: "h6",
124
+ children: "Content width locked to md"
125
+ })
126
+ })`,
127
+ preview: () =>
128
+ container.render({
129
+ maxWidth: "md",
130
+ padding: "lg",
131
+ children: typography.render({
132
+ variant: "h6",
133
+ children: "Content width locked to md",
134
+ }),
135
+ }),
136
+ },
137
+ },
138
+ "/layout/flex": {
139
+ summary: "Row/column layout with alignment, gap, and wrapping control.",
140
+ description:
141
+ "Flex composes horizontal and vertical stacks without custom CSS rules for spacing and alignment.",
142
+ useCases: ["Toolbar rows", "Form stacks", "Inline actions"],
143
+ example: {
144
+ code: `import { flex } from "@inglorious/ui/flex"
145
+ import { paper } from "@inglorious/ui/paper"
146
+
147
+ flex.render({
148
+ align: "center",
149
+ gap: "sm",
150
+ children: [
151
+ paper.render({ padding: "sm", children: "Left" }),
152
+ paper.render({ padding: "sm", children: "Right" })
153
+ ]
154
+ })`,
155
+ preview: () =>
156
+ flex.render({
157
+ align: "center",
158
+ gap: "sm",
159
+ children: [
160
+ paper.render({ padding: "sm", children: "Left" }),
161
+ paper.render({ padding: "sm", children: "Right" }),
162
+ ],
163
+ }),
164
+ },
165
+ },
166
+ "/layout/grid": {
167
+ summary: "Responsive grid with consistent spacing and auto-wrapping.",
168
+ description:
169
+ "Grid is ideal for dashboards and card layouts where column count varies by viewport.",
170
+ useCases: ["Card galleries", "Metric grids", "Dashboard panels"],
171
+ example: {
172
+ code: `import { grid } from "@inglorious/ui/grid"
173
+ import { paper } from "@inglorious/ui/paper"
174
+
175
+ grid.render({
176
+ minColumnWidth: "10rem",
177
+ gap: "sm",
178
+ children: [
179
+ paper.render({ padding: "sm", children: "A" }),
180
+ paper.render({ padding: "sm", children: "B" }),
181
+ paper.render({ padding: "sm", children: "C" }),
182
+ paper.render({ padding: "sm", children: "D" })
183
+ ]
184
+ })`,
185
+ preview: () =>
186
+ grid.render({
187
+ minColumnWidth: "10rem",
188
+ gap: "sm",
189
+ children: [
190
+ paper.render({ padding: "sm", children: "A" }),
191
+ paper.render({ padding: "sm", children: "B" }),
192
+ paper.render({ padding: "sm", children: "C" }),
193
+ paper.render({ padding: "sm", children: "D" }),
194
+ ],
195
+ }),
196
+ },
197
+ },
198
+ "/controls/button": {
199
+ summary: "Action trigger with variants, colors, and shapes.",
200
+ description:
201
+ "Button exposes stateful styles for primary, secondary, and destructive actions.",
202
+ useCases: ["Primary CTAs", "Dialog actions", "Toolbar commands"],
203
+ example: {
204
+ code: `import { button } from "@inglorious/ui/button"
205
+
206
+ button.render({
207
+ variant: "default",
208
+ color: "primary",
209
+ children: "Save changes"
210
+ })`,
211
+ preview: () =>
212
+ previewRow([
213
+ button.render({
214
+ variant: "default",
215
+ color: "primary",
216
+ children: "Primary",
217
+ }),
218
+ button.render({
219
+ variant: "outline",
220
+ color: "primary",
221
+ children: "Outline",
222
+ }),
223
+ button.render({
224
+ variant: "ghost",
225
+ color: "secondary",
226
+ children: "Ghost",
227
+ }),
228
+ ]),
229
+ },
230
+ },
231
+ "/controls/button-group": {
232
+ summary: "Grouped buttons for segmented or multi-select actions.",
233
+ description:
234
+ "Button Group handles selection state while keeping controls visually attached.",
235
+ useCases: ["Segmented filters", "Mode switches", "Batch actions"],
236
+ example: {
237
+ code: `import { buttonGroup } from "@inglorious/ui/button-group"
238
+
239
+ buttonGroup.render({
240
+ value: "week",
241
+ buttons: [
242
+ { id: "day", label: "Day" },
243
+ { id: "week", label: "Week" },
244
+ { id: "month", label: "Month" }
245
+ ]
246
+ })`,
247
+ preview: () =>
248
+ buttonGroup.render({
249
+ value: "week",
250
+ buttons: [
251
+ { id: "day", label: "Day" },
252
+ { id: "week", label: "Week" },
253
+ { id: "month", label: "Month" },
254
+ ],
255
+ }),
256
+ },
257
+ },
258
+ "/controls/checkbox": {
259
+ summary: "Binary choice with optional indeterminate state.",
260
+ description:
261
+ "Checkboxes allow multi-select within lists and forms while staying compact.",
262
+ useCases: ["Bulk selection", "Settings toggles", "Agreement fields"],
263
+ example: {
264
+ code: `import { checkbox } from "@inglorious/ui/checkbox"
265
+
266
+ checkbox.render({
267
+ label: "Send weekly report",
268
+ isChecked: true
269
+ })`,
270
+ preview: () =>
271
+ previewColumn([
272
+ checkbox.render({
273
+ label: "Send weekly report",
274
+ isChecked: true,
275
+ }),
276
+ checkbox.render({
277
+ label: "Email notifications",
278
+ isChecked: false,
279
+ }),
280
+ ]),
281
+ },
282
+ },
283
+ "/controls/combobox": {
284
+ summary: "Searchable dropdown with multi-select and tag support.",
285
+ description:
286
+ "Combobox facilitates selection from large option sets with autocomplete, tag-based multi-select, and custom filtering.",
287
+ useCases: ["Tag selection", "Data filtering", "Complex forms"],
288
+ example: {
289
+ code: `import { combobox } from "@inglorious/ui/combobox"
290
+
291
+ combobox.render({
292
+ label: "Frameworks",
293
+ placeholder: "Select frameworks...",
294
+ isMulti: true,
295
+ isSearchable: true,
296
+ isClearable: true,
297
+ options: [
298
+ { label: "React", value: "react" },
299
+ { label: "Angular", value: "angular" },
300
+ { label: "Vue", value: "vue" },
301
+ { label: "Svelte", value: "svelte" },
302
+ { label: "Inglorious", value: "inglorious" }
303
+ ],
304
+ selectedValue: ["inglorious"]
305
+ })`,
306
+ preview: () =>
307
+ combobox.render({
308
+ label: "Frameworks",
309
+ placeholder: "Select frameworks...",
310
+ isMulti: true,
311
+ isSearchable: true,
312
+ isClearable: true,
313
+ options: [
314
+ { label: "React", value: "react" },
315
+ { label: "Angular", value: "angular" },
316
+ { label: "Vue", value: "vue" },
317
+ { label: "Svelte", value: "svelte" },
318
+ { label: "Inglorious", value: "inglorious" },
319
+ ],
320
+ selectedValue: ["inglorious"],
321
+ }),
322
+ },
323
+ },
324
+ "/controls/fab": {
325
+ summary: "Floating action button for dominant, contextual actions.",
326
+ description:
327
+ "FABs emphasize the most important action in a view, especially on mobile.",
328
+ useCases: ["Create actions", "Quick add", "Contextual primary"],
329
+ example: {
330
+ code: `import { fab } from "@inglorious/ui/fab"
331
+
332
+ fab.render({
333
+ isExtended: true,
334
+ children: "Create"
335
+ })`,
336
+ preview: () =>
337
+ previewRow([
338
+ fab.render({ children: "+" }),
339
+ fab.render({ isExtended: true, children: "Create" }),
340
+ ]),
341
+ },
342
+ },
343
+ "/controls/icon-button": {
344
+ summary: "Compact icon-only button with optional label.",
345
+ description:
346
+ "Icon Button is optimized for toolbars and dense control clusters.",
347
+ useCases: ["Toolbar controls", "Inline actions", "Overflow triggers"],
348
+ example: {
349
+ code: `import { iconButton } from "@inglorious/ui/icon-button"
350
+ import { materialIcon } from "@inglorious/ui/material-icon"
351
+
352
+ iconButton.render({
353
+ icon: materialIcon.render({ name: "settings" }),
354
+ label: "Settings",
355
+ variant: "ghost"
356
+ })`,
357
+ preview: () =>
358
+ previewRow([
359
+ iconButton.render({
360
+ icon: materialIcon.render({ name: "settings" }),
361
+ label: "Settings",
362
+ variant: "ghost",
363
+ }),
364
+ iconButton.render({
365
+ icon: materialIcon.render({ name: "favorite" }),
366
+ label: "Favorite",
367
+ variant: "ghost",
368
+ }),
369
+ ]),
370
+ },
371
+ },
372
+ "/controls/input": {
373
+ summary: "Text input with labeling, validation, and helper text.",
374
+ description:
375
+ "Input exposes states for errors and hints while keeping layout consistent.",
376
+ useCases: ["Forms", "Search fields", "Inline editing"],
377
+ example: {
378
+ code: `import { input } from "@inglorious/ui/input"
379
+
380
+ input.render({
381
+ label: "Email",
382
+ inputType: "email",
383
+ placeholder: "name@company.com",
384
+ hint: "We will not share your email"
385
+ })`,
386
+ preview: () =>
387
+ previewColumn([
388
+ input.render({
389
+ label: "Email",
390
+ inputType: "email",
391
+ placeholder: "name@company.com",
392
+ hint: "We will not share your email",
393
+ value: "",
394
+ }),
395
+ input.render({
396
+ label: "Password",
397
+ inputType: "password",
398
+ placeholder: "••••••••",
399
+ value: "",
400
+ }),
401
+ ]),
402
+ },
403
+ },
404
+ "/controls/radio-group": {
405
+ summary: "Single-choice selection among visible options.",
406
+ description:
407
+ "Radio Group ensures mutual exclusivity with explicit option labels.",
408
+ useCases: ["Plan selection", "Single-choice forms", "Mode switching"],
409
+ example: {
410
+ code: `import { radioGroup } from "@inglorious/ui/radio-group"
411
+
412
+ radioGroup.render({
413
+ label: "Billing",
414
+ value: "annual",
415
+ options: [
416
+ { label: "Monthly", value: "monthly" },
417
+ { label: "Annual", value: "annual" }
418
+ ]
419
+ })`,
420
+ preview: () =>
421
+ radioGroup.render({
422
+ label: "Billing",
423
+ value: "annual",
424
+ options: [
425
+ { label: "Monthly", value: "monthly" },
426
+ { label: "Annual", value: "annual" },
427
+ ],
428
+ }),
429
+ },
430
+ },
431
+ "/controls/rating": {
432
+ summary: "Discrete rating control with custom symbols.",
433
+ description:
434
+ "Rating captures qualitative feedback with a numeric value backing it.",
435
+ useCases: ["Reviews", "Quality scoring", "Satisfaction"],
436
+ example: {
437
+ code: `import { rating } from "@inglorious/ui/rating"
438
+
439
+ rating.render({
440
+ value: 4,
441
+ max: 5
442
+ })`,
443
+ preview: () => rating.render({ value: 4, max: 5 }),
444
+ },
445
+ },
446
+ "/controls/select": {
447
+ summary: "Dropdown selection for compact option lists.",
448
+ description:
449
+ "Select keeps forms tight while preserving clear option labels.",
450
+ useCases: ["Filters", "Country selectors", "Form fields"],
451
+ example: {
452
+ code: `import { select } from "@inglorious/ui/select"
453
+
454
+ select.render({
455
+ value: "active",
456
+ options: [
457
+ { value: "active", label: "Active" },
458
+ { value: "paused", label: "Paused" },
459
+ { value: "archived", label: "Archived" }
460
+ ]
461
+ })`,
462
+ preview: () =>
463
+ select.render({
464
+ value: "active",
465
+ options: [
466
+ { value: "active", label: "Active" },
467
+ { value: "paused", label: "Paused" },
468
+ { value: "archived", label: "Archived" },
469
+ ],
470
+ }),
471
+ },
472
+ },
473
+ "/controls/slider": {
474
+ summary: "Continuous range input with numeric feedback.",
475
+ description:
476
+ "Slider is ideal for approximate values like volume or thresholds.",
477
+ useCases: ["Range filters", "Preference tuning", "Threshold settings"],
478
+ example: {
479
+ code: `import { slider } from "@inglorious/ui/slider"
480
+
481
+ slider.render({
482
+ label: "Volume",
483
+ value: 32,
484
+ min: 0,
485
+ max: 100
486
+ })`,
487
+ preview: () =>
488
+ slider.render({ label: "Volume", value: 32, min: 0, max: 100 }),
489
+ },
490
+ },
491
+ "/controls/switch": {
492
+ summary: "Binary toggle with immediate state feedback.",
493
+ description:
494
+ "Switches represent live state and can be flipped without confirmation.",
495
+ useCases: ["Feature flags", "Settings", "Live states"],
496
+ example: {
497
+ code: `import { switchControl } from "@inglorious/ui/switch"
498
+
499
+ switchControl.render({
500
+ label: "Auto-sync",
501
+ isChecked: true
502
+ })`,
503
+ preview: () =>
504
+ previewColumn([
505
+ switchControl.render({ label: "Auto-sync", isChecked: true }),
506
+ switchControl.render({ label: "Offline mode", isChecked: false }),
507
+ ]),
508
+ },
509
+ },
510
+ "/data-display/avatar": {
511
+ summary: "Identity marker with image, initials, or fallback content.",
512
+ description:
513
+ "Avatar supports automatic color hashing and multiple shapes/sizes.",
514
+ useCases: ["User lists", "Assignees", "Account menus"],
515
+ example: {
516
+ code: `import { avatar } from "@inglorious/ui/avatar"
517
+
518
+ avatar.render({
519
+ initials: "JD",
520
+ color: "auto"
521
+ })`,
522
+ preview: () =>
523
+ previewRow([
524
+ avatar.render({ initials: "JD", color: "auto" }),
525
+ avatar.render({ src: "/transparent.png", shape: "square" }),
526
+ ]),
527
+ },
528
+ },
529
+ "/data-display/badge": {
530
+ summary: "Compact label for status, counts, or metadata.",
531
+ description: "Badges are lightweight chips for quick semantic emphasis.",
532
+ useCases: ["Status tags", "Counts", "Category labels"],
533
+ example: {
534
+ code: `import { badge } from "@inglorious/ui/badge"
535
+
536
+ badge.render({
537
+ color: "success",
538
+ children: "LIVE"
539
+ })`,
540
+ preview: () =>
541
+ previewRow([
542
+ badge.render({ color: "success", children: "LIVE" }),
543
+ badge.render({ color: "warning", children: "BETA" }),
544
+ badge.render({ color: "info", children: "NEW" }),
545
+ ]),
546
+ },
547
+ },
548
+ "/data-display/chip": {
549
+ summary: "Compact token for filters, tags, or selections.",
550
+ description: "Chips are best for quick filters or removable selections.",
551
+ useCases: ["Tag lists", "Filter pills", "Multi-select"],
552
+ example: {
553
+ code: `import { chip } from "@inglorious/ui/chip"
554
+
555
+ chip.render({
556
+ children: "Priority: High",
557
+ color: "warning"
558
+ })`,
559
+ preview: () =>
560
+ previewRow([
561
+ chip.render({ children: "Priority: High", color: "warning" }),
562
+ chip.render({ children: "Assigned", color: "success" }),
563
+ chip.render({ children: "Blocked", color: "error" }),
564
+ ]),
565
+ },
566
+ },
567
+ "/data-display/data-grid": {
568
+ summary: "Feature-rich data grid with sorting, filtering, and paging.",
569
+ description:
570
+ "Data Grid supports structured datasets with built-in pagination and search hooks.",
571
+ useCases: ["Admin tables", "Operational dashboards", "Data exports"],
572
+ example: {
573
+ code: `import { dataGrid } from "@inglorious/ui/data-grid"
574
+
575
+ dataGrid.render({
576
+ rowId: "id",
577
+ columns: [
578
+ { id: "id", title: "ID", type: "number", isSortable: true },
579
+ { id: "name", title: "Name" },
580
+ { id: "status", title: "Status" }
581
+ ],
582
+ rows: [
583
+ { id: 1, name: "Alpha", status: "Active" },
584
+ { id: 2, name: "Beta", status: "Paused" },
585
+ { id: 3, name: "Gamma", status: "Active" }
586
+ ],
587
+ filters: {},
588
+ sorts: [],
589
+ selection: [],
590
+ pagination: { page: 0, pageSize: 3, pageSizes: [3, 6] }
591
+ })`,
592
+ preview: () =>
593
+ dataGrid.render({
594
+ rowId: "id",
595
+ columns: [
596
+ { id: "id", title: "ID", type: "number", isSortable: true },
597
+ { id: "name", title: "Name" },
598
+ { id: "status", title: "Status" },
599
+ ],
600
+ rows: [
601
+ { id: 1, name: "Alpha", status: "Active" },
602
+ { id: 2, name: "Beta", status: "Paused" },
603
+ { id: 3, name: "Gamma", status: "Active" },
604
+ ],
605
+ filters: {},
606
+ sorts: [],
607
+ selection: [],
608
+ pagination: { page: 0, pageSize: 3, pageSizes: [3, 6] },
609
+ }),
610
+ },
611
+ },
612
+ "/data-display/divider": {
613
+ summary: "Lightweight separator between content groups.",
614
+ description:
615
+ "Divider adds visual rhythm without introducing heavy borders.",
616
+ useCases: ["Section boundaries", "List grouping", "Sidebars"],
617
+ example: {
618
+ code: `import { divider } from "@inglorious/ui/divider"
619
+
620
+ divider.render({ orientation: "horizontal" })`,
621
+ preview: () =>
622
+ previewColumn([
623
+ typography.render({ variant: "body2", children: "Section A" }),
624
+ divider.render({ orientation: "horizontal" }),
625
+ typography.render({ variant: "body2", children: "Section B" }),
626
+ ]),
627
+ },
628
+ },
629
+ "/data-display/icon": {
630
+ summary: "Generic icon wrapper with size and color control.",
631
+ description:
632
+ "Icon is a neutral wrapper for SVGs or glyphs within UI layouts.",
633
+ useCases: ["Inline cues", "Status indicators", "UI affordances"],
634
+ example: {
635
+ code: `import { icon } from "@inglorious/ui/icon"
636
+
637
+ icon.render({
638
+ size: "lg",
639
+ children: "★"
640
+ })`,
641
+ preview: () =>
642
+ previewRow([
643
+ icon.render({ size: "lg", children: "★" }),
644
+ icon.render({ size: "lg", children: "⚡" }),
645
+ ]),
646
+ },
647
+ },
648
+ "/data-display/list": {
649
+ summary: "Structured lists with optional icons and secondary text.",
650
+ description:
651
+ "List supports nested items, selection state, and action affordances.",
652
+ useCases: ["Navigation menus", "Activity feeds", "Result lists"],
653
+ example: {
654
+ code: `import { list } from "@inglorious/ui/list"
655
+
656
+ list.render({
657
+ items: [
658
+ { id: "alpha", primary: "Alpha", secondary: "Ready" },
659
+ { id: "beta", primary: "Beta", secondary: "Paused" }
660
+ ]
661
+ })`,
662
+ preview: () =>
663
+ list.render({
664
+ isInset: true,
665
+ items: [
666
+ {
667
+ id: "alpha",
668
+ primary: "Alpha",
669
+ secondary: "Ready",
670
+ icon: materialIcon.render({ name: "bolt", size: "sm" }),
671
+ },
672
+ {
673
+ id: "beta",
674
+ primary: "Beta",
675
+ secondary: "Paused",
676
+ icon: materialIcon.render({ name: "pause", size: "sm" }),
677
+ },
678
+ ],
679
+ }),
680
+ },
681
+ },
682
+ "/data-display/material-icon": {
683
+ summary: "Material Symbols integration with consistent sizing.",
684
+ description:
685
+ "Material Icon renders Material Symbols with predefined size tokens.",
686
+ useCases: ["Standard iconography", "Toolbar actions", "Menus"],
687
+ example: {
688
+ code: `import { materialIcon } from "@inglorious/ui/material-icon"
689
+
690
+ materialIcon.render({ name: "bolt", size: "lg" })`,
691
+ preview: () =>
692
+ previewRow([
693
+ materialIcon.render({ name: "bolt", size: "lg" }),
694
+ materialIcon.render({ name: "settings", size: "lg" }),
695
+ materialIcon.render({ name: "layers", size: "lg" }),
696
+ ]),
697
+ },
698
+ },
699
+ "/data-display/table": {
700
+ summary: "Lightweight table for structured data.",
701
+ description:
702
+ "Table is a minimal data layout when you do not need full grid features.",
703
+ useCases: ["Reports", "Billing summaries", "Audit tables"],
704
+ example: {
705
+ code: `import { table } from "@inglorious/ui/table"
706
+
707
+ table.render({
708
+ isStriped: true,
709
+ columns: [
710
+ { id: "name", label: "Name" },
711
+ { id: "role", label: "Role" }
712
+ ],
713
+ rows: [
714
+ { id: 1, name: "Alex", role: "Owner" },
715
+ { id: 2, name: "Sam", role: "Editor" }
716
+ ]
717
+ })`,
718
+ preview: () =>
719
+ table.render({
720
+ isStriped: true,
721
+ columns: [
722
+ { id: "name", label: "Name" },
723
+ { id: "role", label: "Role" },
724
+ ],
725
+ rows: [
726
+ { id: 1, name: "Alex", role: "Owner" },
727
+ { id: 2, name: "Sam", role: "Editor" },
728
+ ],
729
+ }),
730
+ },
731
+ },
732
+ "/data-display/tooltip": {
733
+ summary: "On-hover or focus help text for dense UIs.",
734
+ description:
735
+ "Tooltip keeps interfaces clean while still exposing contextual help.",
736
+ useCases: ["Icon explanations", "Truncated labels", "Inline hints"],
737
+ example: {
738
+ code: `import { tooltip } from "@inglorious/ui/tooltip"
739
+
740
+ tooltip.render({
741
+ isOpen: true,
742
+ content: "Copy to clipboard",
743
+ children: "Hover me"
744
+ })`,
745
+ preview: () =>
746
+ tooltip.render({
747
+ isOpen: true,
748
+ content: "Copy to clipboard",
749
+ children: iconButton.render({
750
+ icon: materialIcon.render({ name: "content_copy" }),
751
+ label: "Copy",
752
+ variant: "ghost",
753
+ }),
754
+ }),
755
+ },
756
+ },
757
+ "/data-display/typography": {
758
+ summary: "Text styles for hierarchy and consistent rhythm.",
759
+ description:
760
+ "Typography tokens enforce consistent sizing, weight, and color across surfaces.",
761
+ useCases: ["Headings", "Body text", "Meta labels"],
762
+ example: {
763
+ code: `import { typography } from "@inglorious/ui/typography"
764
+
765
+ typography.render({
766
+ variant: "h5",
767
+ children: "Section title"
768
+ })`,
769
+ preview: () =>
770
+ previewColumn([
771
+ typography.render({ variant: "h5", children: "Section title" }),
772
+ typography.render({
773
+ variant: "body1",
774
+ children: "Body text uses a readable line height.",
775
+ }),
776
+ typography.render({
777
+ variant: "body2",
778
+ color: "secondary",
779
+ children: "Secondary metadata label",
780
+ }),
781
+ ]),
782
+ },
783
+ },
784
+ "/feedback/alert": {
785
+ summary: "Inline status messaging with severity and variants.",
786
+ description:
787
+ "Alert surfaces contextual feedback without interrupting the flow.",
788
+ useCases: ["Validation errors", "Success banners", "System warnings"],
789
+ example: {
790
+ code: `import { alert } from "@inglorious/ui/alert"
791
+
792
+ alert.render({
793
+ title: "Payment failed",
794
+ description: "Card expired on 04/24",
795
+ severity: "error"
796
+ })`,
797
+ preview: () =>
798
+ alert.render({
799
+ title: "Payment failed",
800
+ description: "Card expired on 04/24",
801
+ severity: "error",
802
+ }),
803
+ },
804
+ },
805
+ "/feedback/backdrop": {
806
+ summary: "Blocking overlay to focus attention or indicate loading.",
807
+ description:
808
+ "Backdrop dims the app surface and optionally displays a loading cue.",
809
+ useCases: ["Blocking operations", "Modal focus", "Loading states"],
810
+ example: {
811
+ code: `import { backdrop } from "@inglorious/ui/backdrop"
812
+
813
+ backdrop.render({
814
+ isOpen: true,
815
+ children: "Processing..."
816
+ })`,
817
+ preview: () =>
818
+ backdrop.render({
819
+ isOpen: true,
820
+ children: "Processing...",
821
+ }),
822
+ },
823
+ },
824
+ "/feedback/dialog": {
825
+ summary: "Modal dialog for confirmations and focused tasks.",
826
+ description:
827
+ "Dialog interrupts flow for explicit confirmation or data entry.",
828
+ useCases: ["Destructive actions", "Confirmations", "Focused forms"],
829
+ example: {
830
+ code: `import { dialog } from "@inglorious/ui/dialog"
831
+ import { button } from "@inglorious/ui/button"
832
+
833
+ dialog.render({
834
+ isOpen: true,
835
+ title: "Delete record",
836
+ description: "This action cannot be undone.",
837
+ actions: button.render({ children: "Confirm" })
838
+ })`,
839
+ preview: () =>
840
+ dialog.render({
841
+ isOpen: true,
842
+ title: "Delete record",
843
+ description: "This action cannot be undone.",
844
+ actions: previewRow([
845
+ button.render({
846
+ variant: "ghost",
847
+ color: "secondary",
848
+ children: "Cancel",
849
+ }),
850
+ button.render({
851
+ variant: "default",
852
+ color: "error",
853
+ children: "Delete",
854
+ }),
855
+ ]),
856
+ }),
857
+ },
858
+ },
859
+ "/feedback/progress": {
860
+ summary: "Linear or circular progress indicators.",
861
+ description:
862
+ "Progress communicates activity for async or long-running operations.",
863
+ useCases: ["Uploads", "Background tasks", "Step completion"],
864
+ example: {
865
+ code: `import { progress } from "@inglorious/ui/progress"
866
+
867
+ progress.render({
868
+ variant: "linear",
869
+ value: 45
870
+ })`,
871
+ preview: () =>
872
+ previewColumn([
873
+ progress.render({ variant: "linear", value: 45 }),
874
+ progress.render({ variant: "circular", value: 72, size: 48 }),
875
+ ]),
876
+ },
877
+ },
878
+ "/feedback/skeleton": {
879
+ summary: "Placeholder surfaces to reduce perceived loading time.",
880
+ description: "Skeleton preserves layout while content is still loading.",
881
+ useCases: ["Card placeholders", "List loading", "Async fetches"],
882
+ example: {
883
+ code: `import { skeleton } from "@inglorious/ui/skeleton"
884
+
885
+ skeleton.render({
886
+ variant: "text",
887
+ lines: 3
888
+ })`,
889
+ preview: () =>
890
+ previewColumn([
891
+ skeleton.render({ variant: "text", lines: 3 }),
892
+ skeleton.render({ variant: "rect", height: 80 }),
893
+ ]),
894
+ },
895
+ },
896
+ "/feedback/snackbar": {
897
+ summary: "Transient notification with optional action.",
898
+ description: "Snackbar provides quick feedback without blocking the user.",
899
+ useCases: ["Save confirmations", "Undo prompts", "Background updates"],
900
+ example: {
901
+ code: `import { snackbar } from "@inglorious/ui/snackbar"
902
+
903
+ snackbar.render({
904
+ isOpen: true,
905
+ message: "Saved",
906
+ action: "Undo"
907
+ })`,
908
+ preview: () =>
909
+ snackbar.render({
910
+ isOpen: true,
911
+ message: "Saved",
912
+ action: link.render({ href: "#", children: "Undo" }),
913
+ }),
914
+ },
915
+ },
916
+ "/navigation/bottom-navigation": {
917
+ summary: "Compact mobile navigation with icon labels.",
918
+ description:
919
+ "Bottom Navigation keeps primary destinations reachable on small screens.",
920
+ useCases: ["Mobile apps", "Primary sections", "Quick switching"],
921
+ example: {
922
+ code: `import { bottomNavigation } from "@inglorious/ui/bottom-navigation"
923
+
924
+ bottomNavigation.render({
925
+ value: 1,
926
+ actions: [
927
+ { label: "Home", icon: "home" },
928
+ { label: "Search", icon: "search" },
929
+ { label: "Profile", icon: "person" }
930
+ ]
931
+ })`,
932
+ preview: () =>
933
+ bottomNavigation.render({
934
+ value: 1,
935
+ actions: [
936
+ { label: "Home", icon: materialIcon.render({ name: "home" }) },
937
+ { label: "Search", icon: materialIcon.render({ name: "search" }) },
938
+ { label: "Profile", icon: materialIcon.render({ name: "person" }) },
939
+ ],
940
+ }),
941
+ },
942
+ },
943
+ "/navigation/breadcrumbs": {
944
+ summary: "Hierarchy trail for deep navigation.",
945
+ description:
946
+ "Breadcrumbs communicate location and allow quick jumps to parent levels.",
947
+ useCases: ["Nested pages", "Content hierarchies", "Admin paths"],
948
+ example: {
949
+ code: `import { breadcrumbs } from "@inglorious/ui/breadcrumbs"
950
+
951
+ breadcrumbs.render({
952
+ items: [
953
+ { label: "Projects", href: "/projects" },
954
+ { label: "Atlas" },
955
+ { label: "Settings" }
956
+ ]
957
+ })`,
958
+ preview: () =>
959
+ breadcrumbs.render({
960
+ items: [
961
+ { label: "Projects", href: "/projects" },
962
+ { label: "Atlas" },
963
+ { label: "Settings" },
964
+ ],
965
+ }),
966
+ },
967
+ },
968
+ "/navigation/drawer": {
969
+ summary: "Sidebar navigation with collapsible sections.",
970
+ description:
971
+ "Drawer anchors large navigation trees and can collapse for density.",
972
+ useCases: ["Admin navigation", "Settings menus", "Content trees"],
973
+ example: {
974
+ code: `import { drawer } from "@inglorious/ui/drawer"
975
+ import { list } from "@inglorious/ui/list"
976
+
977
+ drawer.render({
978
+ isOpen: true,
979
+ title: "Navigation",
980
+ children: list.render({ items: [
981
+ { id: "home", primary: "Dashboard" },
982
+ { id: "reports", primary: "Reports" }
983
+ ] })
984
+ })`,
985
+ preview: () =>
986
+ drawer.render({
987
+ isOpen: true,
988
+ hasBackdrop: false,
989
+ title: "Navigation",
990
+ children: list.render({
991
+ items: [
992
+ {
993
+ id: "home",
994
+ primary: "Dashboard",
995
+ icon: materialIcon.render({ name: "speed" }),
996
+ },
997
+ {
998
+ id: "reports",
999
+ primary: "Reports",
1000
+ icon: materialIcon.render({ name: "bar_chart" }),
1001
+ },
1002
+ ],
1003
+ }),
1004
+ }),
1005
+ },
1006
+ },
1007
+ "/navigation/link": {
1008
+ summary: "Inline navigation with consistent theme styling.",
1009
+ description:
1010
+ "Link standardizes color and underline behavior across surfaces.",
1011
+ useCases: ["Inline navigation", "Help links", "Secondary actions"],
1012
+ example: {
1013
+ code: `import { link } from "@inglorious/ui/link"
1014
+
1015
+ link.render({
1016
+ href: "/docs",
1017
+ children: "Read documentation"
1018
+ })`,
1019
+ preview: () =>
1020
+ previewRow([
1021
+ link.render({ href: "#", children: "Read documentation" }),
1022
+ link.render({
1023
+ href: "#",
1024
+ children: "Release notes",
1025
+ underline: "always",
1026
+ }),
1027
+ ]),
1028
+ },
1029
+ },
1030
+ "/navigation/menu": {
1031
+ summary: "Context menu for grouped actions.",
1032
+ description:
1033
+ "Menu surfaces grouped actions without cluttering the main UI.",
1034
+ useCases: ["Overflow menus", "Context actions", "Quick picks"],
1035
+ example: {
1036
+ code: `import { menu } from "@inglorious/ui/menu"
1037
+
1038
+ menu.render({
1039
+ isOpen: true,
1040
+ items: [
1041
+ { label: "Edit" },
1042
+ { label: "Duplicate" },
1043
+ { hasDivider: true },
1044
+ { label: "Archive" }
1045
+ ]
1046
+ })`,
1047
+ preview: () =>
1048
+ menu.render({
1049
+ isOpen: true,
1050
+ items: [
1051
+ { label: "Edit" },
1052
+ { label: "Duplicate" },
1053
+ { hasDivider: true },
1054
+ { label: "Archive" },
1055
+ ],
1056
+ }),
1057
+ },
1058
+ },
1059
+ "/navigation/pagination": {
1060
+ summary: "Page controls for long lists or tables.",
1061
+ description: "Pagination keeps dataset navigation fast and accessible.",
1062
+ useCases: ["Search results", "Data tables", "Archives"],
1063
+ example: {
1064
+ code: `import { pagination } from "@inglorious/ui/pagination"
1065
+
1066
+ pagination.render({
1067
+ page: 2,
1068
+ count: 6
1069
+ })`,
1070
+ preview: () => pagination.render({ page: 2, count: 6 }),
1071
+ },
1072
+ },
1073
+ "/navigation/speed-dial": {
1074
+ summary: "Expandable action cluster for quick commands.",
1075
+ description:
1076
+ "Speed Dial groups floating actions and reveals them on interaction.",
1077
+ useCases: ["Mobile shortcuts", "Create actions", "Context tools"],
1078
+ example: {
1079
+ code: `import { speedDial } from "@inglorious/ui/speed-dial"
1080
+
1081
+ speedDial.render({
1082
+ isOpen: true,
1083
+ actions: [
1084
+ { label: "Add", icon: "+" },
1085
+ { label: "Share", icon: "↗" }
1086
+ ]
1087
+ })`,
1088
+ preview: () =>
1089
+ speedDial.render({
1090
+ isOpen: true,
1091
+ actions: [
1092
+ { label: "Add", icon: "+" },
1093
+ { label: "Share", icon: "↗" },
1094
+ ],
1095
+ }),
1096
+ },
1097
+ },
1098
+ "/navigation/stepper": {
1099
+ summary: "Step-based navigation for multi-stage flows.",
1100
+ description:
1101
+ "Stepper communicates progress and ordering in multi-step tasks.",
1102
+ useCases: ["Checkout", "Onboarding", "Wizard flows"],
1103
+ example: {
1104
+ code: `import { stepper } from "@inglorious/ui/stepper"
1105
+
1106
+ stepper.render({
1107
+ activeStep: 1,
1108
+ steps: [
1109
+ { label: "Details" },
1110
+ { label: "Billing" },
1111
+ { label: "Confirm" }
1112
+ ]
1113
+ })`,
1114
+ preview: () =>
1115
+ stepper.render({
1116
+ activeStep: 1,
1117
+ steps: [
1118
+ { label: "Details" },
1119
+ { label: "Billing" },
1120
+ { label: "Confirm" },
1121
+ ],
1122
+ }),
1123
+ },
1124
+ },
1125
+ "/navigation/tabs": {
1126
+ summary: "Horizontal content switching with panels.",
1127
+ description:
1128
+ "Tabs keep related content in one location with explicit selection state.",
1129
+ useCases: ["Detail views", "Settings", "Section switches"],
1130
+ example: {
1131
+ code: `import { tabs } from "@inglorious/ui/tabs"
1132
+
1133
+ tabs.render({
1134
+ value: 0,
1135
+ items: [
1136
+ { label: "Overview", panel: "Overview content" },
1137
+ { label: "Details", panel: "Details content" }
1138
+ ]
1139
+ })`,
1140
+ preview: () =>
1141
+ tabs.render({
1142
+ value: 0,
1143
+ items: [
1144
+ {
1145
+ label: "Overview",
1146
+ panel: typography.render({
1147
+ variant: "body2",
1148
+ children: "Overview content",
1149
+ }),
1150
+ },
1151
+ {
1152
+ label: "Details",
1153
+ panel: typography.render({
1154
+ variant: "body2",
1155
+ children: "Details content",
1156
+ }),
1157
+ },
1158
+ ],
1159
+ }),
1160
+ },
1161
+ },
1162
+ "/surfaces/accordion": {
1163
+ summary: "Collapsible sections for dense content.",
1164
+ description:
1165
+ "Accordion reveals details on demand while keeping layouts compact.",
1166
+ useCases: ["FAQs", "Settings groups", "Detail panels"],
1167
+ example: {
1168
+ code: `import { accordion } from "@inglorious/ui/accordion"
1169
+
1170
+ accordion.render({
1171
+ items: [
1172
+ { title: "Usage", content: "How to use it", isExpanded: true },
1173
+ { title: "API", content: "Props and handlers" }
1174
+ ]
1175
+ })`,
1176
+ preview: () =>
1177
+ accordion.render({
1178
+ items: [
1179
+ {
1180
+ title: "Usage",
1181
+ content: "How to use it",
1182
+ isExpanded: true,
1183
+ },
1184
+ { title: "API", content: "Props and handlers" },
1185
+ ],
1186
+ }),
1187
+ },
1188
+ },
1189
+ "/surfaces/app-bar": {
1190
+ summary: "Top app bar with title, actions, and optional metadata.",
1191
+ description:
1192
+ "App Bar anchors navigation and global actions in a consistent header.",
1193
+ useCases: ["App headers", "Section titles", "Global actions"],
1194
+ example: {
1195
+ code: `import { appBar } from "@inglorious/ui/app-bar"
1196
+ import { button } from "@inglorious/ui/button"
1197
+
1198
+ appBar.render({
1199
+ title: "Project Ops",
1200
+ subtitle: "SLA dashboard",
1201
+ trailing: button.render({ children: "Share" })
1202
+ })`,
1203
+ preview: () =>
1204
+ appBar.render({
1205
+ title: "Project Ops",
1206
+ subtitle: "SLA dashboard",
1207
+ leading: materialIcon.render({ name: "menu" }),
1208
+ trailing: button.render({
1209
+ variant: "ghost",
1210
+ color: "secondary",
1211
+ children: "Share",
1212
+ }),
1213
+ }),
1214
+ },
1215
+ },
1216
+ "/surfaces/card": {
1217
+ summary: "Elevated container for grouped content and actions.",
1218
+ description:
1219
+ "Card provides a flexible surface with optional header and footer sections.",
1220
+ useCases: ["Dashboard panels", "Content previews", "Summary blocks"],
1221
+ example: {
1222
+ code: `import { card } from "@inglorious/ui/card"
1223
+
1224
+ card.render({
1225
+ title: "Weekly report",
1226
+ subtitle: "Updated 2h ago",
1227
+ children: "View metrics and KPIs"
1228
+ })`,
1229
+ preview: () =>
1230
+ card.render({
1231
+ title: "Weekly report",
1232
+ subtitle: "Updated 2h ago",
1233
+ children: typography.render({
1234
+ variant: "body2",
1235
+ children: "View metrics and KPIs",
1236
+ }),
1237
+ }),
1238
+ },
1239
+ },
1240
+ "/surfaces/paper": {
1241
+ summary: "Low-elevation surface with configurable padding.",
1242
+ description:
1243
+ "Paper is the base surface primitive for sections and layout regions.",
1244
+ useCases: ["Section backgrounds", "Inset panels", "Content blocks"],
1245
+ example: {
1246
+ code: `import { paper } from "@inglorious/ui/paper"
1247
+
1248
+ paper.render({
1249
+ padding: "md",
1250
+ children: "Surface content"
1251
+ })`,
1252
+ preview: () =>
1253
+ paper.render({
1254
+ padding: "md",
1255
+ children: typography.render({
1256
+ variant: "body2",
1257
+ children: "Surface content",
1258
+ }),
1259
+ }),
1260
+ },
1261
+ },
1262
+ }
1263
+
1264
+ const primitivePaths = Object.keys(primitiveDetailsByPath)
1265
+
1266
+ export const primitiveContentByPath = primitivePaths.reduce((acc, path) => {
1267
+ acc[path] = buildContentForPath(path)
1268
+ return acc
1269
+ }, {})
1270
+
1271
+ export function getPrimitiveContent(path, entity) {
1272
+ if (path && primitiveContentByPath[path]) {
1273
+ return primitiveContentByPath[path]
1274
+ }
1275
+
1276
+ if (path) {
1277
+ const inferred = buildContentForPath(path)
1278
+ if (inferred) return inferred
1279
+ }
1280
+
1281
+ if (entity?.name || entity?.category) {
1282
+ return {
1283
+ name: entity?.name ?? "Primitive",
1284
+ category: entity?.category ?? "",
1285
+ summary: entity?.summary ?? "",
1286
+ description: entity?.description ?? "",
1287
+ useCases: entity?.useCases ?? [],
1288
+ example: entity?.example ?? null,
1289
+ }
1290
+ }
1291
+
1292
+ return null
1293
+ }
1294
+
1295
+ function buildContentForPath(path) {
1296
+ const parts = path?.split("/").filter(Boolean)
1297
+ if (!parts || parts.length < 2) return null
1298
+
1299
+ const [categoryKey, nameKey] = parts
1300
+ const meta = categoryMeta[categoryKey]
1301
+ if (!meta) return null
1302
+
1303
+ const details = primitiveDetailsByPath[path] ?? {}
1304
+ const name = details.name ?? toTitleCase(nameKey)
1305
+ const category = meta.label
1306
+
1307
+ return {
1308
+ name,
1309
+ category,
1310
+ summary: details.summary ?? meta.summary,
1311
+ description:
1312
+ details.description ??
1313
+ `${name} is a ${category} primitive for ${meta.verb}.`,
1314
+ useCases: details.useCases ?? meta.useCases,
1315
+ example: details.example ?? null,
1316
+ }
1317
+ }
1318
+
1319
+ function toTitleCase(slug) {
1320
+ if (!slug) return ""
1321
+ return slug
1322
+ .split("-")
1323
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
1324
+ .join(" ")
1325
+ }