@inglorious/ui 0.1.0 → 1.0.1

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 +190 -15
  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,160 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks"
2
+
3
+ <Meta title="Data Display/Icon/Implementations" />
4
+
5
+ <div className="iw-theme-content">
6
+
7
+ # Icon Implementations
8
+
9
+ Use this page as a quick reference for supported icon strategies in `@inglorious/ui`.
10
+
11
+ <style>{`
12
+ .iw-icon-tabs { display: grid; gap: 0.75rem; }
13
+ .iw-icon-tabs > input { position: absolute; opacity: 0; pointer-events: none; }
14
+ .iw-icon-tab-labels { display: flex; flex-wrap: wrap; gap: 0.5rem; }
15
+ .iw-icon-tab-labels label {
16
+ border: 1px solid var(--iw-color-border);
17
+ border-radius: var(--iw-radius-md);
18
+ background: var(--iw-color-bg-secondary);
19
+ color: var(--iw-color-text);
20
+ padding: 0.35rem 0.65rem;
21
+ cursor: pointer;
22
+ font-size: 0.875rem;
23
+ }
24
+ .iw-icon-tab-panels {
25
+ border: 1px solid var(--iw-color-border);
26
+ border-radius: var(--iw-radius-md);
27
+ background: var(--iw-color-surface);
28
+ padding: 0.85rem;
29
+ }
30
+ .iw-icon-tab-panel { display: none; line-height: 1.45; }
31
+ #iw-icon-tab-generic:checked ~ .iw-icon-tab-panels .iw-icon-tab-panel-generic,
32
+ #iw-icon-tab-svg:checked ~ .iw-icon-tab-panels .iw-icon-tab-panel-svg,
33
+ #iw-icon-tab-material:checked ~ .iw-icon-tab-panels .iw-icon-tab-panel-material,
34
+ #iw-icon-tab-fa:checked ~ .iw-icon-tab-panels .iw-icon-tab-panel-fa,
35
+ #iw-icon-tab-lucide:checked ~ .iw-icon-tab-panels .iw-icon-tab-panel-lucide,
36
+ #iw-icon-tab-a11y:checked ~ .iw-icon-tab-panels .iw-icon-tab-panel-a11y { display: block; }
37
+ #iw-icon-tab-generic:checked ~ .iw-icon-tab-labels label[for="iw-icon-tab-generic"],
38
+ #iw-icon-tab-svg:checked ~ .iw-icon-tab-labels label[for="iw-icon-tab-svg"],
39
+ #iw-icon-tab-material:checked ~ .iw-icon-tab-labels label[for="iw-icon-tab-material"],
40
+ #iw-icon-tab-fa:checked ~ .iw-icon-tab-labels label[for="iw-icon-tab-fa"],
41
+ #iw-icon-tab-lucide:checked ~ .iw-icon-tab-labels label[for="iw-icon-tab-lucide"],
42
+ #iw-icon-tab-a11y:checked ~ .iw-icon-tab-labels label[for="iw-icon-tab-a11y"] {
43
+ border-color: var(--iw-color-primary);
44
+ box-shadow: inset 0 0 0 1px var(--iw-color-primary);
45
+ }
46
+ .iw-icon-example { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 1.5rem; margin-top: 0.35rem; }
47
+ .iw-material-symbol {
48
+ font-family: "Material Symbols Outlined";
49
+ font-weight: 400;
50
+ font-style: normal;
51
+ font-size: 1.5rem;
52
+ line-height: 1;
53
+ letter-spacing: normal;
54
+ text-transform: none;
55
+ display: inline-block;
56
+ white-space: nowrap;
57
+ word-wrap: normal;
58
+ direction: ltr;
59
+ font-feature-settings: "liga";
60
+ -webkit-font-smoothing: antialiased;
61
+ }
62
+ .iw-theme-content { background: var(--iw-color-bg, #ffffff); color: var(--iw-color-text, #000000); padding: 1rem; border-radius: var(--iw-radius-md); }
63
+ .iw-theme-content h1, .iw-theme-content p, .iw-theme-content li, .iw-theme-content pre, .iw-theme-content code { background: var(--iw-color-surface, #ffffff); color: var(--iw-color-text, #000000); }
64
+ `}</style>
65
+
66
+ <div className="iw-icon-tabs">
67
+ <input id="iw-icon-tab-generic" type="radio" name="iw-icon-tab" defaultChecked />
68
+ <input id="iw-icon-tab-svg" type="radio" name="iw-icon-tab" />
69
+ <input id="iw-icon-tab-material" type="radio" name="iw-icon-tab" />
70
+ <input id="iw-icon-tab-fa" type="radio" name="iw-icon-tab" />
71
+ <input id="iw-icon-tab-lucide" type="radio" name="iw-icon-tab" />
72
+ <input id="iw-icon-tab-a11y" type="radio" name="iw-icon-tab" />
73
+
74
+ <div className="iw-icon-tab-labels">
75
+ <label htmlFor="iw-icon-tab-generic">Generic</label>
76
+ <label htmlFor="iw-icon-tab-svg">Inline SVG</label>
77
+ <label htmlFor="iw-icon-tab-material">Material</label>
78
+ <label htmlFor="iw-icon-tab-fa">Font Awesome</label>
79
+ <label htmlFor="iw-icon-tab-lucide">Lucide</label>
80
+ <label htmlFor="iw-icon-tab-a11y">Accessibility</label>
81
+ </div>
82
+
83
+ <div className="iw-icon-tab-panels">
84
+ <section className="iw-icon-tab-panel iw-icon-tab-panel-generic">
85
+ <p>Use <code>@inglorious/ui/icon</code> for glyphs, emoji, and simple symbols. Reference: <a href="/?path=/story/data-display-icon--unicode">UTF-8 Icons</a></p>
86
+ <pre><code>{`icon.render({ children: "★", size: "md", color: "primary" })`}</code></pre>
87
+ <div className="iw-icon-example">★ ⚑ ♫</div>
88
+ </section>
89
+
90
+ <section className="iw-icon-tab-panel iw-icon-tab-panel-svg">
91
+ <p>Use inline SVG when you want a custom icon pack without font dependencies.</p>
92
+ <pre><code>{`icon.render({
93
+ children: html\`<svg viewBox="0 0 24 24" ...>...</svg>\`,
94
+ size: "md",
95
+ })`}</code></pre>
96
+
97
+ <div className="iw-icon-example">
98
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
99
+ <path d="M12 2v20M2 12h20" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
100
+ </svg>
101
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
102
+ <path d="M3 12l6 6 12-12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
103
+ </svg>
104
+ <svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
105
+ <path d="M12 21s-7-4.35-9-8.5C1.25 8.6 3.8 5 7.6 5c2.1 0 3.4 1.1 4.4 2.5C13 6.1 14.3 5 16.4 5 20.2 5 22.75 8.6 21 12.5 19 16.65 12 21 12 21Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
106
+ </svg>
107
+ </div>
108
+ </section>
109
+
110
+ <section className="iw-icon-tab-panel iw-icon-tab-panel-material">
111
+ <p>Use <code>@inglorious/ui/material-icon</code> when Material Symbols fonts are loaded. Reference: <a href="https://fonts.google.com/icons?icon.set=Material+Icons" target="_blank">Material Icons</a></p>
112
+ <pre><code>{`materialIcon.render({ name: "home", filled: true, size: "md" })`}</code></pre>
113
+ <div className="iw-icon-example">
114
+ <span className="iw-material-symbol" aria-hidden="true">home</span>
115
+ <span className="iw-material-symbol" aria-hidden="true">settings</span>
116
+ <span className="iw-material-symbol" aria-hidden="true">favorite</span>
117
+ </div>
118
+ </section>
119
+
120
+ <section className="iw-icon-tab-panel iw-icon-tab-panel-fa">
121
+ <p>Load Font Awesome CSS globally, then pass an icon element as <code>children</code>. Reference: <a href="https://fontawesome.com/search" target="_blank">Font Awesome Icons</a></p>
122
+ <pre><code>{`icon.render({
123
+ children: html\`<i class="fa-solid fa-user" aria-hidden="true"></i>\`,
124
+ })`}</code></pre>
125
+
126
+ <div className="iw-icon-example">
127
+ <i className="fa-solid fa-user" aria-hidden="true"></i>
128
+ <i className="fa-solid fa-gear" aria-hidden="true"></i>
129
+ <i className="fa-solid fa-heart" aria-hidden="true"></i>
130
+ </div>
131
+ </section>
132
+
133
+ <section className="iw-icon-tab-panel iw-icon-tab-panel-lucide">
134
+ <p>Lucide requires runtime bootstrapping before icons render. Reference: <a href="https://lucide.dev/icons/?focus" target="_blank">Lucide Icons</a></p>
135
+ <pre><code>{`import { createIcons, icons } from "lucide"
136
+ createIcons({
137
+ icons,
138
+ attrs: { "stroke-width": 1.75 },
139
+ })`}</code></pre>
140
+ <p>Then render nodes such as <code>{`<i data-lucide="user"></i>`}</code>.</p>
141
+
142
+ <div className="iw-icon-example">
143
+ <i data-lucide="user" aria-hidden="true"></i>
144
+ <i data-lucide="settings" aria-hidden="true"></i>
145
+ <i data-lucide="heart" aria-hidden="true"></i>
146
+ </div>
147
+ </section>
148
+
149
+ <section className="iw-icon-tab-panel iw-icon-tab-panel-a11y">
150
+ <ul>
151
+ <li>Decorative icons: use <code>aria-hidden="true"</code>.</li>
152
+ <li>Meaningful icons: include an <code>aria-label</code> or visible text.</li>
153
+ <li>Do not rely on icon shape alone for state; pair with text/color contrast.</li>
154
+ </ul>
155
+ <p>Unicode glyph explorer lives in the <strong>Data Display/Icon/Unicode</strong> story.</p>
156
+ </section>
157
+
158
+ </div>
159
+ </div>
160
+ </div>
@@ -0,0 +1,156 @@
1
+ import { virtualList } from "@inglorious/ui/virtual-list"
2
+ import { html, repeat } from "@inglorious/web"
3
+
4
+ import { button } from "../../controls/button"
5
+ import {
6
+ createEntityRender,
7
+ notifyActionArgType,
8
+ } from "../../stories/notifyStory.js"
9
+ import { icon } from "."
10
+
11
+ const unicodeList = {
12
+ ...virtualList,
13
+
14
+ create(entity) {
15
+ virtualList.create(entity)
16
+
17
+ const items = []
18
+ let rowIndex = 0
19
+ let row = []
20
+
21
+ for (let code = entity.start; code <= entity.end; code += 1) {
22
+ row.push(code)
23
+ if (row.length >= entity.columns) {
24
+ items.push({ id: `row-${rowIndex}`, codes: row })
25
+ row = []
26
+ rowIndex += 1
27
+ }
28
+ }
29
+
30
+ if (row.length) {
31
+ items.push({ id: `row-${rowIndex}`, codes: row })
32
+ }
33
+
34
+ entity.items = items
35
+ },
36
+
37
+ render(entity, api) {
38
+ return virtualList.render(entity, {
39
+ ...api,
40
+ getType: () => unicodeList,
41
+ })
42
+ },
43
+
44
+ renderItem(entity, { item }) {
45
+ const { columns = 16, size = "md" } = entity
46
+ const codes = item.codes ?? []
47
+
48
+ return html`
49
+ <div
50
+ style=${[
51
+ "display: grid",
52
+ `grid-template-columns: repeat(${columns}, minmax(0, 1fr))`,
53
+ "gap: 0.5rem",
54
+ "align-items: center",
55
+ ].join("; ")}
56
+ >
57
+ ${repeat(
58
+ codes,
59
+ (code) => code,
60
+ (code) => {
61
+ const glyph = String.fromCodePoint(code)
62
+ const label = `Copy U+${code
63
+ .toString(16)
64
+ .toUpperCase()
65
+ .padStart(4, "0")}`
66
+
67
+ return button.render({
68
+ id: code,
69
+ variant: "ghost",
70
+ color: "default",
71
+ size: "sm",
72
+ shape: "square",
73
+ ariaLabel: label,
74
+ onClick: () => copyGlyph(glyph),
75
+ children: icon.render({
76
+ children: glyph,
77
+ size,
78
+ color: "current",
79
+ }),
80
+ })
81
+ },
82
+ )}
83
+ </div>
84
+ `
85
+ },
86
+ }
87
+
88
+ export default {
89
+ title: "Data Display/Icon",
90
+ render: createEntityRender({ unicodeList }),
91
+ argTypes: {
92
+ ...notifyActionArgType,
93
+ start: {
94
+ control: "number",
95
+ description: "Start code point (decimal).",
96
+ },
97
+ end: {
98
+ control: "number",
99
+ description: "End code point (decimal).",
100
+ },
101
+ columns: {
102
+ control: "number",
103
+ description: "Grid columns for the glyphs.",
104
+ },
105
+ viewportHeight: {
106
+ control: "number",
107
+ description: "Viewport height for the virtualized list (px).",
108
+ },
109
+ estimatedHeight: {
110
+ control: "number",
111
+ description: "Estimated row height for virtualization (px).",
112
+ },
113
+ size: {
114
+ control: "select",
115
+ options: ["sm", "md", "lg"],
116
+ },
117
+ },
118
+ parameters: {
119
+ docs: {
120
+ description: {
121
+ component:
122
+ "Unicode glyph explorer for the icon primitive. Click a glyph to copy it.",
123
+ },
124
+ },
125
+ },
126
+ }
127
+
128
+ export const Unicode = {
129
+ args: {
130
+ id: "unicodeList",
131
+ type: "unicodeList",
132
+ start: 0,
133
+ end: 129799,
134
+ columns: 20,
135
+ viewportHeight: 600,
136
+ estimatedHeight: 56,
137
+ size: "lg",
138
+ },
139
+ }
140
+
141
+ async function copyGlyph(glyph) {
142
+ if (navigator?.clipboard?.writeText) {
143
+ await navigator.clipboard.writeText(glyph)
144
+ return
145
+ }
146
+
147
+ const textarea = document.createElement("textarea")
148
+ textarea.value = glyph
149
+ textarea.setAttribute("readonly", "")
150
+ textarea.style.position = "absolute"
151
+ textarea.style.left = "-9999px"
152
+ document.body.appendChild(textarea)
153
+ textarea.select()
154
+ document.execCommand("copy")
155
+ document.body.removeChild(textarea)
156
+ }
@@ -0,0 +1,38 @@
1
+ import { createRender } from "../../stories/notifyStory.js"
2
+ import { icon } from "."
3
+
4
+ export default {
5
+ title: "Data Display/Icon",
6
+ tags: ["autodocs"],
7
+ render: createRender(icon),
8
+ argTypes: {
9
+ children: { control: "text", description: "Icon glyph or inline content." },
10
+ size: {
11
+ control: "select",
12
+ options: ["sm", "md", "lg"],
13
+ description: "Icon size scale.",
14
+ },
15
+ color: {
16
+ control: "text",
17
+ description:
18
+ "Any valid CSS color value (`current` keeps inherited color).",
19
+ },
20
+ onClick: { action: "onClick" },
21
+ },
22
+ parameters: {
23
+ docs: {
24
+ description: {
25
+ component:
26
+ "Generic inline icon primitive for glyphs, emoji, or custom symbol text. See `Data Display/Icon/Implementations` for Font Awesome and Lucide setup patterns.",
27
+ },
28
+ },
29
+ },
30
+ }
31
+
32
+ export const Default = {
33
+ args: {
34
+ children: "★",
35
+ size: "md",
36
+ color: "current",
37
+ },
38
+ }
@@ -0,0 +1,3 @@
1
+ import * as renderers from "./template.js"
2
+
3
+ export const icon = { ...renderers }
@@ -0,0 +1,17 @@
1
+ .iw-icon {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ width: 1em;
6
+ height: 1em;
7
+ line-height: 1;
8
+ cursor: pointer;
9
+
10
+ &.iw-icon-sm {
11
+ font-size: 0.875rem;
12
+ }
13
+
14
+ &.iw-icon-lg {
15
+ font-size: 1.5rem;
16
+ }
17
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @typedef {import('../../../types/data-display/icon').IconProps} IconProps
3
+ */
4
+
5
+ import { classMap, html } from "@inglorious/web"
6
+
7
+ export function render({ children, size = "md", color = "current", onClick }) {
8
+ return html`<span
9
+ class=${classMap({
10
+ "iw-icon": true,
11
+ [`iw-icon-${size}`]: size !== "md",
12
+ "iw-icon-current": color === "current",
13
+ })}
14
+ style=${color !== "current" ? `color: ${color};` : ""}
15
+ aria-hidden="true"
16
+ @click=${onClick}
17
+ >${children}</span
18
+ >`
19
+ }
@@ -0,0 +1,25 @@
1
+ export function itemToggle(entity, payload) {
2
+ if (!payload?.path?.length) return
3
+
4
+ entity.items = toggleItemByPath(entity.items, payload.path)
5
+ }
6
+
7
+ function toggleItemByPath(items, path) {
8
+ if (!Array.isArray(items) || path.length === 0) return items
9
+
10
+ const [index, ...rest] = path
11
+ return items.map((item, itemIndex) => {
12
+ if (itemIndex !== index || !item || typeof item !== "object") return item
13
+
14
+ if (rest.length === 0) {
15
+ const isExpanded = !!item.isExpanded
16
+ return { ...item, isExpanded: !isExpanded }
17
+ }
18
+
19
+ const children = Array.isArray(item.children)
20
+ ? toggleItemByPath(item.children, rest)
21
+ : item.children
22
+
23
+ return { ...item, children }
24
+ })
25
+ }
@@ -0,0 +1,4 @@
1
+ import * as handlers from "./handlers.js"
2
+ import { list as renderers } from "./template.js"
3
+
4
+ export const list = { ...renderers, ...handlers }
@@ -0,0 +1,187 @@
1
+ import { createRender } from "../../stories/notifyStory.js"
2
+ import { list } from "."
3
+
4
+ export default {
5
+ title: "Data Display/List",
6
+ tags: ["autodocs"],
7
+ render: createRender(list),
8
+ argTypes: {
9
+ items: {
10
+ control: "object",
11
+ description: "Items rendered by default renderer.",
12
+ },
13
+ isOrdered: {
14
+ control: "boolean",
15
+ description: "Use ordered list semantics.",
16
+ },
17
+ isDense: {
18
+ control: "boolean",
19
+ description: "Reduce item vertical spacing.",
20
+ },
21
+ isDivided: {
22
+ control: "boolean",
23
+ description: "Add separators between items.",
24
+ },
25
+ isInset: {
26
+ control: "boolean",
27
+ description: "Align items without icons to those with icons.",
28
+ },
29
+ padding: {
30
+ control: "select",
31
+ options: ["none", "sm", "md", "lg", "xl"],
32
+ description: "Outer padding for the list.",
33
+ },
34
+ onItemClick: { action: "onItemClick" },
35
+ onItemToggle: { action: "onItemToggle" },
36
+ },
37
+ parameters: {
38
+ docs: {
39
+ description: {
40
+ component:
41
+ "List primitive with optional ordered mode and overridable `renderItem(props, payload)` sub-render. Click events use `onItemClick(item, path)` and toggle events use `onItemToggle(item, path)`.",
42
+ },
43
+ },
44
+ },
45
+ }
46
+
47
+ export const Default = {
48
+ args: {
49
+ items: [
50
+ { id: "a", primary: "First item", secondary: "Secondary text" },
51
+ { id: "b", primary: "Second item", secondary: "More details" },
52
+ { id: "c", primary: "Third item", secondary: "Optional caption" },
53
+ ],
54
+ isOrdered: false,
55
+ isDense: false,
56
+ isDivided: false,
57
+ padding: "none",
58
+ },
59
+ }
60
+
61
+ export const Ordered = {
62
+ args: {
63
+ ...Default.args,
64
+ isOrdered: true,
65
+ },
66
+ }
67
+
68
+ export const Dense = {
69
+ args: {
70
+ ...Default.args,
71
+ isDense: true,
72
+ },
73
+ }
74
+
75
+ export const Divided = {
76
+ args: {
77
+ ...Default.args,
78
+ isDivided: true,
79
+ },
80
+ }
81
+
82
+ export const WithIcons = {
83
+ args: {
84
+ items: [
85
+ { id: "a", icon: "★", primary: "Starred", secondary: "Pinned item" },
86
+ { id: "b", primary: "Settings", secondary: "Manage options" },
87
+ { id: "c", icon: "✓", primary: "Done", secondary: "Completed task" },
88
+ ],
89
+ isOrdered: false,
90
+ isDense: false,
91
+ isDivided: true,
92
+ isInset: true,
93
+ },
94
+ }
95
+
96
+ export const Selected = {
97
+ args: {
98
+ items: [
99
+ { id: "a", primary: "Inbox", isSelected: true },
100
+ { id: "b", primary: "Drafts" },
101
+ { id: "c", primary: "Archive" },
102
+ ],
103
+ },
104
+ }
105
+
106
+ export const Disabled = {
107
+ args: {
108
+ items: [
109
+ { id: "a", primary: "Active item" },
110
+ { id: "b", primary: "Disabled item", isDisabled: true },
111
+ ],
112
+ },
113
+ }
114
+
115
+ export const Nested = {
116
+ args: {
117
+ items: [
118
+ {
119
+ id: "a",
120
+ primary: "Parent item",
121
+ isExpanded: true,
122
+ children: [
123
+ { id: "a-1", primary: "Child item 1" },
124
+ { id: "a-2", primary: "Child item 2", isSelected: true },
125
+ ],
126
+ },
127
+ { id: "b", primary: "Sibling item" },
128
+ ],
129
+ isDivided: true,
130
+ },
131
+ }
132
+
133
+ export const NestedWithIcons = {
134
+ args: {
135
+ items: [
136
+ {
137
+ id: "a",
138
+ icon: "📁",
139
+ primary: "Projects",
140
+ isExpanded: true,
141
+ children: [
142
+ { id: "a-1", icon: "📄", primary: "Spec.md" },
143
+ { id: "a-2", primary: "Notes", isSelected: true },
144
+ ],
145
+ },
146
+ { id: "b", icon: "🗂️", primary: "Archive" },
147
+ ],
148
+ isDivided: true,
149
+ isInset: true,
150
+ },
151
+ }
152
+
153
+ export const WithActions = {
154
+ args: {
155
+ items: [
156
+ {
157
+ id: "a",
158
+ primary: "Notifications",
159
+ secondary: "Enable alerts",
160
+ action: "On",
161
+ },
162
+ {
163
+ id: "b",
164
+ primary: "Wi-Fi",
165
+ secondary: "Office network",
166
+ action: "⋯",
167
+ },
168
+ ],
169
+ },
170
+ }
171
+
172
+ export const Expandable = {
173
+ args: {
174
+ items: [
175
+ {
176
+ id: "a",
177
+ primary: "Inbox",
178
+ isExpanded: false,
179
+ children: [
180
+ { id: "a-1", primary: "Starred" },
181
+ { id: "a-2", primary: "Drafts" },
182
+ ],
183
+ },
184
+ { id: "b", primary: "Archive" },
185
+ ],
186
+ },
187
+ }