@pithyjs/ui-kit 0.1.0-beta.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 (417) hide show
  1. package/LICENSE +21 -0
  2. package/dist/animation/animate-in.d.ts +35 -0
  3. package/dist/animation/animate-in.d.ts.map +1 -0
  4. package/dist/animation/animate-in.js +71 -0
  5. package/dist/animation/animate-in.js.map +1 -0
  6. package/dist/atoms/actions/_icon-control.scss +53 -0
  7. package/dist/atoms/actions/button/Button.d.ts +93 -0
  8. package/dist/atoms/actions/button/Button.d.ts.map +1 -0
  9. package/dist/atoms/actions/button/Button.js +332 -0
  10. package/dist/atoms/actions/button/Button.js.map +1 -0
  11. package/dist/atoms/actions/button/button.scss +342 -0
  12. package/dist/atoms/actions/icon-button/IconButton.d.ts +47 -0
  13. package/dist/atoms/actions/icon-button/IconButton.d.ts.map +1 -0
  14. package/dist/atoms/actions/icon-button/IconButton.js +81 -0
  15. package/dist/atoms/actions/icon-button/IconButton.js.map +1 -0
  16. package/dist/atoms/actions/icon-button/icon-button.scss +20 -0
  17. package/dist/atoms/actions/icon-group/IconGroup.d.ts +60 -0
  18. package/dist/atoms/actions/icon-group/IconGroup.d.ts.map +1 -0
  19. package/dist/atoms/actions/icon-group/IconGroup.js +191 -0
  20. package/dist/atoms/actions/icon-group/IconGroup.js.map +1 -0
  21. package/dist/atoms/actions/icon-group/icon-group.scss +36 -0
  22. package/dist/atoms/actions/segmented-control/SegmentedControl.d.ts +49 -0
  23. package/dist/atoms/actions/segmented-control/SegmentedControl.d.ts.map +1 -0
  24. package/dist/atoms/actions/segmented-control/SegmentedControl.js +107 -0
  25. package/dist/atoms/actions/segmented-control/SegmentedControl.js.map +1 -0
  26. package/dist/atoms/actions/segmented-control/segmented-control.scss +90 -0
  27. package/dist/atoms/content/_mixins.scss +79 -0
  28. package/dist/atoms/content/action-tile/ActionTile.d.ts +27 -0
  29. package/dist/atoms/content/action-tile/ActionTile.d.ts.map +1 -0
  30. package/dist/atoms/content/action-tile/ActionTile.js +98 -0
  31. package/dist/atoms/content/action-tile/ActionTile.js.map +1 -0
  32. package/dist/atoms/content/action-tile/action-tile.scss +150 -0
  33. package/dist/atoms/content/badge/Badge.d.ts +57 -0
  34. package/dist/atoms/content/badge/Badge.d.ts.map +1 -0
  35. package/dist/atoms/content/badge/Badge.js +177 -0
  36. package/dist/atoms/content/badge/Badge.js.map +1 -0
  37. package/dist/atoms/content/badge/badge.scss +198 -0
  38. package/dist/atoms/content/heading/Heading.d.ts +53 -0
  39. package/dist/atoms/content/heading/Heading.d.ts.map +1 -0
  40. package/dist/atoms/content/heading/Heading.js +142 -0
  41. package/dist/atoms/content/heading/Heading.js.map +1 -0
  42. package/dist/atoms/content/heading/heading.scss +43 -0
  43. package/dist/atoms/content/icon/Icon.d.ts +68 -0
  44. package/dist/atoms/content/icon/Icon.d.ts.map +1 -0
  45. package/dist/atoms/content/icon/Icon.js +137 -0
  46. package/dist/atoms/content/icon/Icon.js.map +1 -0
  47. package/dist/atoms/content/icon/icon.scss +66 -0
  48. package/dist/atoms/content/icon/resolveIconSvg.d.ts +21 -0
  49. package/dist/atoms/content/icon/resolveIconSvg.d.ts.map +1 -0
  50. package/dist/atoms/content/icon/resolveIconSvg.js +73 -0
  51. package/dist/atoms/content/icon/resolveIconSvg.js.map +1 -0
  52. package/dist/atoms/content/image/Image.d.ts +81 -0
  53. package/dist/atoms/content/image/Image.d.ts.map +1 -0
  54. package/dist/atoms/content/image/Image.js +293 -0
  55. package/dist/atoms/content/image/Image.js.map +1 -0
  56. package/dist/atoms/content/image/image.scss +77 -0
  57. package/dist/atoms/content/text/Text.d.ts +58 -0
  58. package/dist/atoms/content/text/Text.d.ts.map +1 -0
  59. package/dist/atoms/content/text/Text.js +158 -0
  60. package/dist/atoms/content/text/Text.js.map +1 -0
  61. package/dist/atoms/content/text/text.scss +98 -0
  62. package/dist/atoms/content/tile/Tile.d.ts +66 -0
  63. package/dist/atoms/content/tile/Tile.d.ts.map +1 -0
  64. package/dist/atoms/content/tile/Tile.js +125 -0
  65. package/dist/atoms/content/tile/Tile.js.map +1 -0
  66. package/dist/atoms/content/tile/tile.scss +122 -0
  67. package/dist/atoms/feedback/tooltip/Tooltip.d.ts +44 -0
  68. package/dist/atoms/feedback/tooltip/Tooltip.d.ts.map +1 -0
  69. package/dist/atoms/feedback/tooltip/Tooltip.js +121 -0
  70. package/dist/atoms/feedback/tooltip/Tooltip.js.map +1 -0
  71. package/dist/atoms/feedback/tooltip/tooltip.scss +96 -0
  72. package/dist/atoms/forms/checkbox/Checkbox.d.ts +49 -0
  73. package/dist/atoms/forms/checkbox/Checkbox.d.ts.map +1 -0
  74. package/dist/atoms/forms/checkbox/Checkbox.js +269 -0
  75. package/dist/atoms/forms/checkbox/Checkbox.js.map +1 -0
  76. package/dist/atoms/forms/checkbox/CheckboxGroup.d.ts +50 -0
  77. package/dist/atoms/forms/checkbox/CheckboxGroup.d.ts.map +1 -0
  78. package/dist/atoms/forms/checkbox/CheckboxGroup.js +132 -0
  79. package/dist/atoms/forms/checkbox/CheckboxGroup.js.map +1 -0
  80. package/dist/atoms/forms/checkbox/checkbox.scss +506 -0
  81. package/dist/atoms/forms/file-picker/FilePicker.d.ts +23 -0
  82. package/dist/atoms/forms/file-picker/FilePicker.d.ts.map +1 -0
  83. package/dist/atoms/forms/file-picker/FilePicker.js +103 -0
  84. package/dist/atoms/forms/file-picker/FilePicker.js.map +1 -0
  85. package/dist/atoms/forms/file-picker/file-picker.scss +84 -0
  86. package/dist/atoms/forms/form-field/FormField.d.ts +39 -0
  87. package/dist/atoms/forms/form-field/FormField.d.ts.map +1 -0
  88. package/dist/atoms/forms/form-field/FormField.js +139 -0
  89. package/dist/atoms/forms/form-field/FormField.js.map +1 -0
  90. package/dist/atoms/forms/form-field/form-field.scss +46 -0
  91. package/dist/atoms/forms/input/Input.d.ts +81 -0
  92. package/dist/atoms/forms/input/Input.d.ts.map +1 -0
  93. package/dist/atoms/forms/input/Input.js +417 -0
  94. package/dist/atoms/forms/input/Input.js.map +1 -0
  95. package/dist/atoms/forms/input/input.scss +547 -0
  96. package/dist/atoms/forms/radio/Radio.d.ts +54 -0
  97. package/dist/atoms/forms/radio/Radio.d.ts.map +1 -0
  98. package/dist/atoms/forms/radio/Radio.js +278 -0
  99. package/dist/atoms/forms/radio/Radio.js.map +1 -0
  100. package/dist/atoms/forms/radio/RadioGroup.d.ts +54 -0
  101. package/dist/atoms/forms/radio/RadioGroup.d.ts.map +1 -0
  102. package/dist/atoms/forms/radio/RadioGroup.js +137 -0
  103. package/dist/atoms/forms/radio/RadioGroup.js.map +1 -0
  104. package/dist/atoms/forms/radio/radio.scss +459 -0
  105. package/dist/atoms/forms/select/Select.d.ts +57 -0
  106. package/dist/atoms/forms/select/Select.d.ts.map +1 -0
  107. package/dist/atoms/forms/select/Select.js +457 -0
  108. package/dist/atoms/forms/select/Select.js.map +1 -0
  109. package/dist/atoms/forms/select/select-dropdown.d.ts +49 -0
  110. package/dist/atoms/forms/select/select-dropdown.d.ts.map +1 -0
  111. package/dist/atoms/forms/select/select-dropdown.js +305 -0
  112. package/dist/atoms/forms/select/select-dropdown.js.map +1 -0
  113. package/dist/atoms/forms/select/select-keyboard.d.ts +14 -0
  114. package/dist/atoms/forms/select/select-keyboard.d.ts.map +1 -0
  115. package/dist/atoms/forms/select/select-keyboard.js +182 -0
  116. package/dist/atoms/forms/select/select-keyboard.js.map +1 -0
  117. package/dist/atoms/forms/select/select.scss +630 -0
  118. package/dist/atoms/forms/textarea/Textarea.d.ts +69 -0
  119. package/dist/atoms/forms/textarea/Textarea.d.ts.map +1 -0
  120. package/dist/atoms/forms/textarea/Textarea.js +394 -0
  121. package/dist/atoms/forms/textarea/Textarea.js.map +1 -0
  122. package/dist/atoms/forms/textarea/textarea.scss +486 -0
  123. package/dist/atoms/forms/toggle/Toggle.d.ts +47 -0
  124. package/dist/atoms/forms/toggle/Toggle.d.ts.map +1 -0
  125. package/dist/atoms/forms/toggle/Toggle.js +243 -0
  126. package/dist/atoms/forms/toggle/Toggle.js.map +1 -0
  127. package/dist/atoms/forms/toggle/toggle.scss +561 -0
  128. package/dist/compiler.d.ts +7 -0
  129. package/dist/compiler.d.ts.map +1 -0
  130. package/dist/compiler.js +18 -0
  131. package/dist/compiler.js.map +1 -0
  132. package/dist/icons/index.d.ts +14 -0
  133. package/dist/icons/index.d.ts.map +1 -0
  134. package/dist/icons/index.js +14 -0
  135. package/dist/icons/index.js.map +1 -0
  136. package/dist/icons/registry.d.ts +65 -0
  137. package/dist/icons/registry.d.ts.map +1 -0
  138. package/dist/icons/registry.js +126 -0
  139. package/dist/icons/registry.js.map +1 -0
  140. package/dist/index.d.ts +55 -0
  141. package/dist/index.d.ts.map +1 -0
  142. package/dist/index.js +64 -0
  143. package/dist/index.js.map +1 -0
  144. package/dist/layout/Grid.d.ts +78 -0
  145. package/dist/layout/Grid.d.ts.map +1 -0
  146. package/dist/layout/Grid.js +272 -0
  147. package/dist/layout/Grid.js.map +1 -0
  148. package/dist/layout/GridItem.d.ts +52 -0
  149. package/dist/layout/GridItem.d.ts.map +1 -0
  150. package/dist/layout/GridItem.js +99 -0
  151. package/dist/layout/GridItem.js.map +1 -0
  152. package/dist/layout/PageSection.d.ts +43 -0
  153. package/dist/layout/PageSection.d.ts.map +1 -0
  154. package/dist/layout/PageSection.js +75 -0
  155. package/dist/layout/PageSection.js.map +1 -0
  156. package/dist/layout/SmartContainer.d.ts +66 -0
  157. package/dist/layout/SmartContainer.d.ts.map +1 -0
  158. package/dist/layout/SmartContainer.js +194 -0
  159. package/dist/layout/SmartContainer.js.map +1 -0
  160. package/dist/layout/Stack.d.ts +65 -0
  161. package/dist/layout/Stack.d.ts.map +1 -0
  162. package/dist/layout/Stack.js +114 -0
  163. package/dist/layout/Stack.js.map +1 -0
  164. package/dist/organisms/content/Card.d.ts +93 -0
  165. package/dist/organisms/content/Card.d.ts.map +1 -0
  166. package/dist/organisms/content/Card.js +353 -0
  167. package/dist/organisms/content/Card.js.map +1 -0
  168. package/dist/organisms/content/_card-horizontal.scss +88 -0
  169. package/dist/organisms/content/_card-link.scss +49 -0
  170. package/dist/organisms/content/_card-overlay.scss +91 -0
  171. package/dist/organisms/content/_card-root.scss +99 -0
  172. package/dist/organisms/content/_card-slots.scss +143 -0
  173. package/dist/organisms/content/_card-states.scss +166 -0
  174. package/dist/organisms/content/_card-tokens.scss +22 -0
  175. package/dist/organisms/content/_card-variants.scss +31 -0
  176. package/dist/organisms/content/card.scss +15 -0
  177. package/dist/organisms/feedback/Modal.d.ts +39 -0
  178. package/dist/organisms/feedback/Modal.d.ts.map +1 -0
  179. package/dist/organisms/feedback/Modal.js +120 -0
  180. package/dist/organisms/feedback/Modal.js.map +1 -0
  181. package/dist/organisms/feedback/Popover.d.ts +30 -0
  182. package/dist/organisms/feedback/Popover.d.ts.map +1 -0
  183. package/dist/organisms/feedback/Popover.js +151 -0
  184. package/dist/organisms/feedback/Popover.js.map +1 -0
  185. package/dist/organisms/feedback/modal.scss +66 -0
  186. package/dist/organisms/feedback/popover.scss +27 -0
  187. package/dist/organisms/forms/DynamicForm.d.ts +118 -0
  188. package/dist/organisms/forms/DynamicForm.d.ts.map +1 -0
  189. package/dist/organisms/forms/DynamicForm.js +546 -0
  190. package/dist/organisms/forms/DynamicForm.js.map +1 -0
  191. package/dist/organisms/forms/Form.d.ts +62 -0
  192. package/dist/organisms/forms/Form.d.ts.map +1 -0
  193. package/dist/organisms/forms/Form.js +131 -0
  194. package/dist/organisms/forms/Form.js.map +1 -0
  195. package/dist/organisms/forms/dynamic-form.scss +91 -0
  196. package/dist/organisms/forms/form-helpers.d.ts +21 -0
  197. package/dist/organisms/forms/form-helpers.d.ts.map +1 -0
  198. package/dist/organisms/forms/form-helpers.js +57 -0
  199. package/dist/organisms/forms/form-helpers.js.map +1 -0
  200. package/dist/organisms/forms/form-state.d.ts +66 -0
  201. package/dist/organisms/forms/form-state.d.ts.map +1 -0
  202. package/dist/organisms/forms/form-state.js +156 -0
  203. package/dist/organisms/forms/form-state.js.map +1 -0
  204. package/dist/organisms/forms/form.scss +23 -0
  205. package/dist/organisms/forms/validation.d.ts +32 -0
  206. package/dist/organisms/forms/validation.d.ts.map +1 -0
  207. package/dist/organisms/forms/validation.js +118 -0
  208. package/dist/organisms/forms/validation.js.map +1 -0
  209. package/dist/organisms/navigation/Navbar.d.ts +66 -0
  210. package/dist/organisms/navigation/Navbar.d.ts.map +1 -0
  211. package/dist/organisms/navigation/Navbar.js +881 -0
  212. package/dist/organisms/navigation/Navbar.js.map +1 -0
  213. package/dist/organisms/navigation/_navbar-announcement.scss +62 -0
  214. package/dist/organisms/navigation/_navbar-brand.scss +69 -0
  215. package/dist/organisms/navigation/_navbar-container.scss +37 -0
  216. package/dist/organisms/navigation/_navbar-desktop.scss +116 -0
  217. package/dist/organisms/navigation/_navbar-drawer.scss +97 -0
  218. package/dist/organisms/navigation/_navbar-links.scss +143 -0
  219. package/dist/organisms/navigation/_navbar-menu.scss +193 -0
  220. package/dist/organisms/navigation/_navbar-root.scss +107 -0
  221. package/dist/organisms/navigation/_navbar-search.scss +83 -0
  222. package/dist/organisms/navigation/_navbar-toggle.scss +91 -0
  223. package/dist/organisms/navigation/_navbar-tokens.scss +15 -0
  224. package/dist/organisms/navigation/navbar.scss +17 -0
  225. package/dist/registry/categories.d.ts +6 -0
  226. package/dist/registry/categories.d.ts.map +1 -0
  227. package/dist/registry/categories.js +13 -0
  228. package/dist/registry/categories.js.map +1 -0
  229. package/dist/registry/components.d.ts +5 -0
  230. package/dist/registry/components.d.ts.map +1 -0
  231. package/dist/registry/components.js +95 -0
  232. package/dist/registry/components.js.map +1 -0
  233. package/dist/registry/index.d.ts +59 -0
  234. package/dist/registry/index.d.ts.map +1 -0
  235. package/dist/registry/index.js +79 -0
  236. package/dist/registry/index.js.map +1 -0
  237. package/dist/registry/levels.d.ts +6 -0
  238. package/dist/registry/levels.d.ts.map +1 -0
  239. package/dist/registry/levels.js +9 -0
  240. package/dist/registry/levels.js.map +1 -0
  241. package/dist/registry/registry-meta-types.d.ts +67 -0
  242. package/dist/registry/registry-meta-types.d.ts.map +1 -0
  243. package/dist/registry/registry-meta-types.js +6 -0
  244. package/dist/registry/registry-meta-types.js.map +1 -0
  245. package/dist/registry/registry-meta.d.ts +5 -0
  246. package/dist/registry/registry-meta.d.ts.map +1 -0
  247. package/dist/registry/registry-meta.js +731 -0
  248. package/dist/registry/registry-meta.js.map +1 -0
  249. package/dist/registry/renderer.d.ts +69 -0
  250. package/dist/registry/renderer.d.ts.map +1 -0
  251. package/dist/registry/renderer.js +311 -0
  252. package/dist/registry/renderer.js.map +1 -0
  253. package/dist/sections/_section-base.scss +204 -0
  254. package/dist/sections/contact/ContactSection.d.ts +55 -0
  255. package/dist/sections/contact/ContactSection.d.ts.map +1 -0
  256. package/dist/sections/contact/ContactSection.js +142 -0
  257. package/dist/sections/contact/ContactSection.js.map +1 -0
  258. package/dist/sections/contact/contact-section.scss +142 -0
  259. package/dist/sections/cta/CTASection.d.ts +52 -0
  260. package/dist/sections/cta/CTASection.d.ts.map +1 -0
  261. package/dist/sections/cta/CTASection.js +130 -0
  262. package/dist/sections/cta/CTASection.js.map +1 -0
  263. package/dist/sections/cta/cta-section.scss +131 -0
  264. package/dist/sections/entrance.d.ts +29 -0
  265. package/dist/sections/entrance.d.ts.map +1 -0
  266. package/dist/sections/entrance.js +69 -0
  267. package/dist/sections/entrance.js.map +1 -0
  268. package/dist/sections/features/FeaturesSection.d.ts +54 -0
  269. package/dist/sections/features/FeaturesSection.d.ts.map +1 -0
  270. package/dist/sections/features/FeaturesSection.js +139 -0
  271. package/dist/sections/features/FeaturesSection.js.map +1 -0
  272. package/dist/sections/features/features-section.scss +140 -0
  273. package/dist/sections/footer/FooterSection.d.ts +53 -0
  274. package/dist/sections/footer/FooterSection.d.ts.map +1 -0
  275. package/dist/sections/footer/FooterSection.js +147 -0
  276. package/dist/sections/footer/FooterSection.js.map +1 -0
  277. package/dist/sections/footer/footer-section.scss +131 -0
  278. package/dist/sections/hero/HeroSection.d.ts +66 -0
  279. package/dist/sections/hero/HeroSection.d.ts.map +1 -0
  280. package/dist/sections/hero/HeroSection.js +156 -0
  281. package/dist/sections/hero/HeroSection.js.map +1 -0
  282. package/dist/sections/hero/hero-section.scss +211 -0
  283. package/dist/shared/_form-animations.scss +283 -0
  284. package/dist/shared/_media-fit.scss +63 -0
  285. package/dist/shared/_mixins.scss +69 -0
  286. package/dist/shared/_tokens.scss +116 -0
  287. package/dist/shared/badge.d.ts +15 -0
  288. package/dist/shared/badge.d.ts.map +1 -0
  289. package/dist/shared/badge.js +15 -0
  290. package/dist/shared/badge.js.map +1 -0
  291. package/dist/shared/button.d.ts +22 -0
  292. package/dist/shared/button.d.ts.map +1 -0
  293. package/dist/shared/button.js +22 -0
  294. package/dist/shared/button.js.map +1 -0
  295. package/dist/shared/card.d.ts +21 -0
  296. package/dist/shared/card.d.ts.map +1 -0
  297. package/dist/shared/card.js +38 -0
  298. package/dist/shared/card.js.map +1 -0
  299. package/dist/shared/checkbox.d.ts +10 -0
  300. package/dist/shared/checkbox.d.ts.map +1 -0
  301. package/dist/shared/checkbox.js +28 -0
  302. package/dist/shared/checkbox.js.map +1 -0
  303. package/dist/shared/clickable.d.ts +34 -0
  304. package/dist/shared/clickable.d.ts.map +1 -0
  305. package/dist/shared/clickable.js +54 -0
  306. package/dist/shared/clickable.js.map +1 -0
  307. package/dist/shared/common.d.ts +31 -0
  308. package/dist/shared/common.d.ts.map +1 -0
  309. package/dist/shared/common.js +92 -0
  310. package/dist/shared/common.js.map +1 -0
  311. package/dist/shared/entrance-config.d.ts +46 -0
  312. package/dist/shared/entrance-config.d.ts.map +1 -0
  313. package/dist/shared/entrance-config.js +54 -0
  314. package/dist/shared/entrance-config.js.map +1 -0
  315. package/dist/shared/focusable.d.ts +8 -0
  316. package/dist/shared/focusable.d.ts.map +1 -0
  317. package/dist/shared/focusable.js +17 -0
  318. package/dist/shared/focusable.js.map +1 -0
  319. package/dist/shared/form-elements.d.ts +57 -0
  320. package/dist/shared/form-elements.d.ts.map +1 -0
  321. package/dist/shared/form-elements.js +95 -0
  322. package/dist/shared/form-elements.js.map +1 -0
  323. package/dist/shared/form-state.d.ts +52 -0
  324. package/dist/shared/form-state.d.ts.map +1 -0
  325. package/dist/shared/form-state.js +151 -0
  326. package/dist/shared/form-state.js.map +1 -0
  327. package/dist/shared/grid.d.ts +21 -0
  328. package/dist/shared/grid.d.ts.map +1 -0
  329. package/dist/shared/grid.js +187 -0
  330. package/dist/shared/grid.js.map +1 -0
  331. package/dist/shared/icon-slot.d.ts +22 -0
  332. package/dist/shared/icon-slot.d.ts.map +1 -0
  333. package/dist/shared/icon-slot.js +38 -0
  334. package/dist/shared/icon-slot.js.map +1 -0
  335. package/dist/shared/icon.d.ts +17 -0
  336. package/dist/shared/icon.d.ts.map +1 -0
  337. package/dist/shared/icon.js +18 -0
  338. package/dist/shared/icon.js.map +1 -0
  339. package/dist/shared/icons.d.ts +19 -0
  340. package/dist/shared/icons.d.ts.map +1 -0
  341. package/dist/shared/icons.js +22 -0
  342. package/dist/shared/icons.js.map +1 -0
  343. package/dist/shared/image.d.ts +35 -0
  344. package/dist/shared/image.d.ts.map +1 -0
  345. package/dist/shared/image.js +46 -0
  346. package/dist/shared/image.js.map +1 -0
  347. package/dist/shared/input.d.ts +12 -0
  348. package/dist/shared/input.d.ts.map +1 -0
  349. package/dist/shared/input.js +29 -0
  350. package/dist/shared/input.js.map +1 -0
  351. package/dist/shared/radio.d.ts +10 -0
  352. package/dist/shared/radio.d.ts.map +1 -0
  353. package/dist/shared/radio.js +29 -0
  354. package/dist/shared/radio.js.map +1 -0
  355. package/dist/shared/reconcile-list.d.ts +37 -0
  356. package/dist/shared/reconcile-list.d.ts.map +1 -0
  357. package/dist/shared/reconcile-list.js +95 -0
  358. package/dist/shared/reconcile-list.js.map +1 -0
  359. package/dist/shared/section.d.ts +23 -0
  360. package/dist/shared/section.d.ts.map +1 -0
  361. package/dist/shared/section.js +65 -0
  362. package/dist/shared/section.js.map +1 -0
  363. package/dist/shared/segmented.d.ts +17 -0
  364. package/dist/shared/segmented.d.ts.map +1 -0
  365. package/dist/shared/segmented.js +53 -0
  366. package/dist/shared/segmented.js.map +1 -0
  367. package/dist/shared/select.d.ts +18 -0
  368. package/dist/shared/select.d.ts.map +1 -0
  369. package/dist/shared/select.js +14 -0
  370. package/dist/shared/select.js.map +1 -0
  371. package/dist/shared/slots.d.ts +11 -0
  372. package/dist/shared/slots.d.ts.map +1 -0
  373. package/dist/shared/slots.js +33 -0
  374. package/dist/shared/slots.js.map +1 -0
  375. package/dist/shared/smart-container.d.ts +19 -0
  376. package/dist/shared/smart-container.d.ts.map +1 -0
  377. package/dist/shared/smart-container.js +29 -0
  378. package/dist/shared/smart-container.js.map +1 -0
  379. package/dist/shared/text.d.ts +29 -0
  380. package/dist/shared/text.d.ts.map +1 -0
  381. package/dist/shared/text.js +72 -0
  382. package/dist/shared/text.js.map +1 -0
  383. package/dist/shared/textarea.d.ts +6 -0
  384. package/dist/shared/textarea.d.ts.map +1 -0
  385. package/dist/shared/textarea.js +18 -0
  386. package/dist/shared/textarea.js.map +1 -0
  387. package/dist/shared/toggle.d.ts +6 -0
  388. package/dist/shared/toggle.d.ts.map +1 -0
  389. package/dist/shared/toggle.js +19 -0
  390. package/dist/shared/toggle.js.map +1 -0
  391. package/dist/shared/types.d.ts +41 -0
  392. package/dist/shared/types.d.ts.map +1 -0
  393. package/dist/shared/types.js +20 -0
  394. package/dist/shared/types.js.map +1 -0
  395. package/dist/structural/ErrorBoundary.d.ts +18 -0
  396. package/dist/structural/ErrorBoundary.d.ts.map +1 -0
  397. package/dist/structural/ErrorBoundary.js +119 -0
  398. package/dist/structural/ErrorBoundary.js.map +1 -0
  399. package/dist/structural/For.d.ts +37 -0
  400. package/dist/structural/For.d.ts.map +1 -0
  401. package/dist/structural/For.js +129 -0
  402. package/dist/structural/For.js.map +1 -0
  403. package/dist/structural/Lazy.d.ts +43 -0
  404. package/dist/structural/Lazy.d.ts.map +1 -0
  405. package/dist/structural/Lazy.js +47 -0
  406. package/dist/structural/Lazy.js.map +1 -0
  407. package/dist/structural/NavLink.d.ts +45 -0
  408. package/dist/structural/NavLink.d.ts.map +1 -0
  409. package/dist/structural/NavLink.js +37 -0
  410. package/dist/structural/NavLink.js.map +1 -0
  411. package/dist/structural/Show.d.ts +35 -0
  412. package/dist/structural/Show.d.ts.map +1 -0
  413. package/dist/structural/Show.js +34 -0
  414. package/dist/structural/Show.js.map +1 -0
  415. package/dist/structural/nav-link.scss +54 -0
  416. package/dist/styles/index.scss +58 -0
  417. package/package.json +64 -0
@@ -0,0 +1,353 @@
1
+ /** @codex
2
+ {
3
+ "id": "pithy.ui-kit.card",
4
+ "title": "<Card> Organism",
5
+ "category": "feature",
6
+ "risk": "medium"
7
+ }
8
+ */
9
+ import { captureChildren } from '@pithyjs/core';
10
+ import { effect } from '@pithyjs/signals';
11
+ import { isSafeHref, sanitizeHref } from '@pithyjs/shared';
12
+ import { cleanupRouterDirectives } from '@pithyjs/router';
13
+ import { captureSlot, extractSlot } from '../../shared/slots';
14
+ import { generateSectionHeadingId, validateEnum } from '../../shared/section';
15
+ import { ORIENTATIONS } from '../../shared/types';
16
+ import { CARD_VARIANTS, CARD_PADDINGS, CARD_RADII, CARD_MEDIA_ASPECTS, } from '../../shared/card';
17
+ // -- Helpers ------------------------------------------------------------------
18
+ function firstHeadingIn(root) {
19
+ if (!root)
20
+ return null;
21
+ return root.querySelector('h1, h2, h3, h4, h5, h6');
22
+ }
23
+ function wrapSlot(name, className, tag, fragment) {
24
+ if (!fragment)
25
+ return null;
26
+ // If the user projected a single element whose tag already matches our
27
+ // target (e.g. `<footer data-slot="footer">`), reuse it instead of
28
+ // wrapping — otherwise the flex container would wrap a block child and
29
+ // lose all layout. `<template data-slot="...">` always falls through to
30
+ // the wrapper since extractSlot unpacks its content, and a mismatched
31
+ // tag (e.g. `<div data-slot="footer">`) is wrapped so the semantic tag
32
+ // we advertise is preserved.
33
+ const only = fragment.children.length === 1 && fragment.childNodes.length === 1
34
+ ? fragment.firstElementChild
35
+ : null;
36
+ if (only && only.tagName.toLowerCase() === tag) {
37
+ only.classList.add(className);
38
+ captureSlot(only, name);
39
+ return only;
40
+ }
41
+ const wrapper = document.createElement(tag);
42
+ wrapper.classList.add(className);
43
+ captureSlot(wrapper, name);
44
+ wrapper.appendChild(fragment);
45
+ return wrapper;
46
+ }
47
+ // -- Component ----------------------------------------------------------------
48
+ /**
49
+ * Content container with named slots (`media`, `header`, default = body,
50
+ * `footer`), five variants, orientation, and a pseudo-link pattern that
51
+ * lets the whole card act as a navigation target without sacrificing
52
+ * interactive children.
53
+ *
54
+ * @example
55
+ * ```html
56
+ * <Card variant="'elevated'" clickable="true" href="'/post/hello'">
57
+ * <img data-slot="media" src="/hero.jpg" alt="">
58
+ * <header data-slot="header">
59
+ * <Heading level="3">Hello world</Heading>
60
+ * </header>
61
+ * <Text>A short excerpt…</Text>
62
+ * <footer data-slot="footer">
63
+ * <Text color="'text-muted'" size="'sm'">3 min read</Text>
64
+ * </footer>
65
+ * </Card>
66
+ * ```
67
+ */
68
+ /** @codexApi {"parent":"pithy.ui-kit.card","name":"Card","stability":"stable","signature":"(props?: CardProps) => { el: HTMLElement; destroy: () => void }"} */
69
+ export function Card(props = {}) {
70
+ const { variant: rawVariant = 'default', padding: rawPadding = 'md', radius: rawRadius = 'md', orientation: rawOrientation = 'vertical', mediaOverlay = false, clickable = false, href, linkLabel: rawLinkLabel, disabled = false, selected = false, eyebrow, ariaLabel: rawAriaLabel, ariaLabelledBy: rawAriaLabelledBy, id, } = props;
71
+ // Whitespace-only labels would set an effectively empty accessible name
72
+ // and silently bypass the heading fallback. Trim once and treat empty
73
+ // strings as absent — same pattern as <Button>.
74
+ const ariaLabel = rawAriaLabel?.trim() || undefined;
75
+ const linkLabel = rawLinkLabel?.trim() || undefined;
76
+ const ariaLabelledBy = rawAriaLabelledBy?.trim() || undefined;
77
+ if (import.meta.env?.DEV) {
78
+ if (rawAriaLabel != null && !ariaLabel) {
79
+ console.warn('[<Card>] `ariaLabel` was empty or whitespace-only; falling back to heading / ariaLabelledBy / linkLabel.');
80
+ }
81
+ if (rawLinkLabel != null && !linkLabel) {
82
+ console.warn('[<Card>] `linkLabel` was empty or whitespace-only; falling back to heading / ariaLabelledBy / ariaLabel.');
83
+ }
84
+ if (rawAriaLabelledBy != null && !ariaLabelledBy) {
85
+ console.warn('[<Card>] `ariaLabelledBy` was whitespace-only; falling back to heading / ariaLabel / linkLabel.');
86
+ }
87
+ }
88
+ // Destructure defaults first so undefined props skip validateEnum's warning path.
89
+ const variant = validateEnum('Card', 'variant', rawVariant, CARD_VARIANTS, 'default');
90
+ const padding = validateEnum('Card', 'padding', rawPadding, CARD_PADDINGS, 'md');
91
+ const radius = validateEnum('Card', 'radius', rawRadius, CARD_RADII, 'md');
92
+ const orientation = validateEnum('Card', 'orientation', rawOrientation, ORIENTATIONS, 'vertical');
93
+ // Horizontal thumbnails need a predictable aspect ratio or lists get janky.
94
+ const resolvedMediaAspect = props.mediaAspect &&
95
+ CARD_MEDIA_ASPECTS.includes(props.mediaAspect)
96
+ ? props.mediaAspect
97
+ : orientation === 'horizontal'
98
+ ? '16/9'
99
+ : undefined;
100
+ if (import.meta.env?.DEV) {
101
+ if (clickable && !href) {
102
+ console.warn('[<Card>] `clickable` requires `href`. The card will render without the stretched link overlay.');
103
+ }
104
+ if (!clickable && href) {
105
+ console.warn("[<Card>] `href` is ignored when `clickable` is false. Set `clickable='true'` to activate the link overlay.");
106
+ }
107
+ if (props.mediaAspect &&
108
+ !CARD_MEDIA_ASPECTS.includes(props.mediaAspect)) {
109
+ console.warn(`[<Card>] Invalid mediaAspect: "${props.mediaAspect}". Expected one of: ${CARD_MEDIA_ASPECTS.join(', ')}.`);
110
+ }
111
+ // Runtime guard for the site builder's untyped prop bag — TS consumers
112
+ // can't reach this, but JSON-driven rendering can.
113
+ if (typeof props.onClick === 'function') {
114
+ console.warn("[<Card>] `onClick` is not supported in V0.1. Use `clickable='true'` + `href` for navigation, or nest a <Button onClick=...> inside the footer slot. A first-class onClick card lands in V0.2.");
115
+ }
116
+ }
117
+ // Sanitize before both validating and assigning so the rendered URL is
118
+ // exactly what isSafeHref() checked — control-char / whitespace bypass
119
+ // surfaces disappear.
120
+ const normalizedHref = typeof href === 'string' ? sanitizeHref(href) : '';
121
+ const safeHref = clickable && normalizedHref && isSafeHref(normalizedHref)
122
+ ? normalizedHref
123
+ : null;
124
+ if (import.meta.env?.DEV && clickable && href && !safeHref) {
125
+ if (!normalizedHref) {
126
+ console.warn(`[<Card>] \`href\` was empty or whitespace-only after sanitization; the card will not be clickable.`);
127
+ }
128
+ else {
129
+ console.warn(`[<Card>] Unsafe href rejected: "${normalizedHref}". Only http(s), mailto, tel, fragment-only (#...), query-only (?...), and relative URLs (/..., ./..., ../...) are allowed.`);
130
+ }
131
+ }
132
+ const disposers = [];
133
+ // Capture projected children before any inner components render — mirrors
134
+ // the Navbar/section-template pattern. Named nodes are re-homed into slot
135
+ // wrappers below; anything left in the fragment becomes the default body.
136
+ const { el: childFragment, destroy: destroyChildren } = captureChildren();
137
+ disposers.push(destroyChildren);
138
+ const article = document.createElement('article');
139
+ article.classList.add('ui-card');
140
+ article.dataset.variant = variant;
141
+ article.dataset.padding = padding;
142
+ article.dataset.radius = radius;
143
+ article.dataset.orientation = orientation;
144
+ if (clickable && safeHref)
145
+ article.dataset.clickable = 'true';
146
+ if (mediaOverlay)
147
+ article.dataset.mediaOverlay = 'true';
148
+ if (id)
149
+ article.id = id;
150
+ // Reactive `selected` + `disabled`: follow Button's pattern — accept a
151
+ // boolean or a `() => boolean` getter. A function triggers an effect;
152
+ // a literal bakes in once.
153
+ const readDisabled = () => typeof disabled === 'function' ? disabled() : disabled;
154
+ const readSelected = () => typeof selected === 'function' ? selected() : selected;
155
+ const isReactive = typeof disabled === 'function' || typeof selected === 'function';
156
+ const applyState = () => {
157
+ const isDisabled = readDisabled();
158
+ const isSelected = readSelected();
159
+ if (isDisabled) {
160
+ article.dataset.disabled = 'true';
161
+ article.setAttribute('aria-disabled', 'true');
162
+ // `inert` blocks focus, clicks, and AT on every descendant.
163
+ article.setAttribute('inert', '');
164
+ }
165
+ else {
166
+ delete article.dataset.disabled;
167
+ article.removeAttribute('aria-disabled');
168
+ article.removeAttribute('inert');
169
+ }
170
+ if (isSelected) {
171
+ article.dataset.selected = 'true';
172
+ }
173
+ else {
174
+ delete article.dataset.selected;
175
+ }
176
+ // aria-current only has meaning in a navigation context, which disabled
177
+ // removes — keep the existing (non-reactive) gate on clickable && safeHref.
178
+ if (isSelected && clickable && safeHref && !isDisabled) {
179
+ article.setAttribute('aria-current', 'true');
180
+ }
181
+ else {
182
+ article.removeAttribute('aria-current');
183
+ }
184
+ };
185
+ if (isReactive) {
186
+ disposers.push(effect(applyState));
187
+ }
188
+ else {
189
+ applyState();
190
+ }
191
+ // An element can't @container-query itself, so layout lives on a child.
192
+ // See card.scss for the chrome/query-container split.
193
+ const layout = document.createElement('div');
194
+ layout.classList.add('ui-card-layout');
195
+ captureSlot(layout, 'default');
196
+ article.appendChild(layout);
197
+ // Slots — order is significant: media comes first so it can bleed when
198
+ // padding=none, then header/body/footer.
199
+ const mediaFragment = extractSlot(childFragment, 'media');
200
+ const mediaWrapper = wrapSlot('media', 'ui-card-media', 'div', mediaFragment);
201
+ if (mediaWrapper && resolvedMediaAspect) {
202
+ mediaWrapper.dataset.aspect = resolvedMediaAspect;
203
+ }
204
+ if (mediaWrapper)
205
+ layout.appendChild(mediaWrapper);
206
+ const headerFragment = extractSlot(childFragment, 'header');
207
+ let headerWrapper = wrapSlot('header', 'ui-card-header', 'header', headerFragment);
208
+ // If no header slot was projected, create one so the eyebrow has a home.
209
+ // Mirrors the Hero / CTA section eyebrow pattern.
210
+ if (typeof eyebrow === 'string' && eyebrow.trim().length > 0) {
211
+ const eyebrowEl = document.createElement('span');
212
+ eyebrowEl.classList.add('ui-card-eyebrow');
213
+ eyebrowEl.textContent = eyebrow.trim();
214
+ if (!headerWrapper) {
215
+ headerWrapper = document.createElement('header');
216
+ headerWrapper.classList.add('ui-card-header');
217
+ captureSlot(headerWrapper, 'header');
218
+ }
219
+ headerWrapper.prepend(eyebrowEl);
220
+ }
221
+ if (headerWrapper)
222
+ layout.appendChild(headerWrapper);
223
+ // Extract footer BEFORE the body collapse — otherwise the body scoop below
224
+ // would swallow footer nodes along with the default content.
225
+ const footerFragment = extractSlot(childFragment, 'footer');
226
+ const footerWrapper = wrapSlot('footer', 'ui-card-footer', 'footer', footerFragment);
227
+ // Skip the wrapper when empty so media+footer-only cards don't carry a
228
+ // vestigial element.
229
+ const remainingHasContent = childFragment.childNodes.length > 0 &&
230
+ Array.from(childFragment.childNodes).some(n => n.nodeType !== Node.TEXT_NODE || (n.textContent ?? '').trim().length > 0);
231
+ if (remainingHasContent) {
232
+ const body = document.createElement('div');
233
+ body.classList.add('ui-card-body');
234
+ body.appendChild(childFragment);
235
+ layout.appendChild(body);
236
+ }
237
+ if (footerWrapper)
238
+ layout.appendChild(footerWrapper);
239
+ // Overlay mode collapses header/body/footer into one caption group so
240
+ // the scrim, inverse text, and block-end anchoring share a positioning
241
+ // context. Media stays at z-index 0.
242
+ if (mediaOverlay) {
243
+ const caption = document.createElement('div');
244
+ caption.classList.add('ui-card-caption');
245
+ const nodesToMove = Array.from(layout.children).filter(c => c.classList.contains('ui-card-header') ||
246
+ c.classList.contains('ui-card-body') ||
247
+ c.classList.contains('ui-card-footer'));
248
+ for (const node of nodesToMove)
249
+ caption.appendChild(node);
250
+ // Only add the caption if it actually has content — an image-only card
251
+ // with `mediaOverlay` is still a valid configuration.
252
+ if (caption.children.length > 0)
253
+ layout.appendChild(caption);
254
+ }
255
+ // Accessible name fallback chain:
256
+ // ariaLabelledBy > clickable heading (auto-id) > heading (auto-id)
257
+ // > ariaLabel > linkLabel > DEV warning
258
+ // Non-clickable cards with headings also get aria-labelledby so screen
259
+ // readers announce "article, <heading text>" instead of bare "article".
260
+ const heading = firstHeadingIn(headerWrapper);
261
+ if (ariaLabelledBy) {
262
+ article.setAttribute('aria-labelledby', ariaLabelledBy);
263
+ }
264
+ else if (clickable && safeHref) {
265
+ if (heading) {
266
+ if (!heading.id)
267
+ heading.id = generateSectionHeadingId('card', id);
268
+ article.setAttribute('aria-labelledby', heading.id);
269
+ }
270
+ else if (ariaLabel) {
271
+ article.setAttribute('aria-label', ariaLabel);
272
+ }
273
+ else if (linkLabel) {
274
+ article.setAttribute('aria-label', linkLabel);
275
+ }
276
+ else if (import.meta.env?.DEV) {
277
+ console.warn('[<Card>] Clickable card has no accessible name. Add a heading in the header slot, or pass `ariaLabel` / `ariaLabelledBy`.');
278
+ }
279
+ }
280
+ else if (heading) {
281
+ if (!heading.id)
282
+ heading.id = generateSectionHeadingId('card', id);
283
+ article.setAttribute('aria-labelledby', heading.id);
284
+ }
285
+ else if (ariaLabel) {
286
+ article.setAttribute('aria-label', ariaLabel);
287
+ }
288
+ // Pseudo-link overlay — absolute anchor at z-index 1 covers the card for
289
+ // hit-testing. Interactive descendants (buttons/inner links) are raised
290
+ // above it via a :is() rule in card.scss so they stay clickable.
291
+ if (clickable && safeHref) {
292
+ const overlay = document.createElement('a');
293
+ overlay.classList.add('ui-card-link');
294
+ overlay.href = safeHref;
295
+ overlay.setAttribute('data-router-link', '');
296
+ overlay.setAttribute('data-prefetch', 'none');
297
+ disposers.push(() => cleanupRouterDirectives(overlay));
298
+ if (linkLabel) {
299
+ overlay.setAttribute('aria-label', linkLabel);
300
+ }
301
+ else if (ariaLabelledBy) {
302
+ // Honour the explicit override — keeps article + overlay names in sync.
303
+ overlay.setAttribute('aria-labelledby', ariaLabelledBy);
304
+ }
305
+ else if (heading) {
306
+ // Reference the heading id so the link name stays in sync with reactive
307
+ // heading text — snapshotting textContent would freeze a stale name.
308
+ if (!heading.id)
309
+ heading.id = generateSectionHeadingId('card', id);
310
+ overlay.setAttribute('aria-labelledby', heading.id);
311
+ }
312
+ else if (ariaLabel) {
313
+ overlay.setAttribute('aria-label', ariaLabel);
314
+ }
315
+ else {
316
+ // Last-resort visually-hidden label so the link always has an
317
+ // accessible name even when heading and labels are absent.
318
+ const sr = document.createElement('span');
319
+ sr.classList.add('ui-card-link-label');
320
+ sr.textContent = 'Open';
321
+ overlay.appendChild(sr);
322
+ }
323
+ article.appendChild(overlay);
324
+ }
325
+ // Interactive-by-content: a non-clickable card that contains a focusable
326
+ // descendant (button, inner link, form control) still participates in the
327
+ // hover/focus-within lift. Tagged at mount so the SCSS can rely on a plain
328
+ // attribute selector rather than `:has()` inside `:where()` (which has
329
+ // uneven browser behaviour today).
330
+ if (!article.dataset.clickable) {
331
+ const focusable = article.querySelector('a, button, input, select, textarea, [role="button"], [tabindex]:not([tabindex="-1"])');
332
+ if (focusable)
333
+ article.dataset.interactive = 'true';
334
+ }
335
+ return {
336
+ el: article,
337
+ destroy: () => {
338
+ for (const dispose of disposers) {
339
+ try {
340
+ dispose();
341
+ }
342
+ catch (err) {
343
+ if (import.meta.env?.DEV) {
344
+ console.error('[<Card>] disposer threw:', err);
345
+ }
346
+ }
347
+ }
348
+ disposers.length = 0;
349
+ article.replaceChildren();
350
+ },
351
+ };
352
+ }
353
+ //# sourceMappingURL=Card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../../src/organisms/content/Card.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /// Card horizontal orientation — @container upgrade
2
+ /// @group organisms/content
3
+
4
+ @use 'card-tokens' as tokens;
5
+
6
+ // ============================================
7
+ // Horizontal orientation — mobile-first @container upgrade
8
+ // ============================================
9
+ //
10
+ // Below $card-horizontal-min the layout stays vertical (base rules win).
11
+ // At or above the threshold, horizontal cards switch the layout element
12
+ // to a 2-column grid: media spans the full block-size on the inline-start,
13
+ // header/body/footer stack on the inline-end.
14
+
15
+ @container (min-inline-size: #{tokens.$card-horizontal-min}) {
16
+ .ui-card[data-orientation='horizontal'] > .ui-card-layout {
17
+ display: grid;
18
+ grid-template-columns:
19
+ clamp(
20
+ #{tokens.$card-media-min},
21
+ #{tokens.$card-media-preferred},
22
+ #{tokens.$card-media-max}
23
+ )
24
+ 1fr;
25
+ // Explicit 3-row track: header (auto) | body (1fr fills extra space) |
26
+ // footer (auto, pinned at the bottom by the track order alone). This
27
+ // produces the editorial layout: header+body hug the block-start while
28
+ // footer always sits flush to the card's block-end, no matter how tall
29
+ // the media side is.
30
+ grid-template-rows: auto 1fr auto;
31
+ column-gap: var(--space-md); // media ↔ body: Friends
32
+ row-gap: 0;
33
+ align-items: stretch;
34
+ }
35
+
36
+ .ui-card[data-orientation='horizontal'] > .ui-card-layout > .ui-card-media {
37
+ grid-column: 1;
38
+ grid-row: 1 / -1;
39
+ // Media fills the grid cell edge-to-edge. Any aspect-ratio set on the
40
+ // media slot loses meaning here because the cell's block-size is driven
41
+ // by the layout; the inner img/video relies on object-fit: cover (from
42
+ // base .ui-card-media rules) to crop gracefully.
43
+ aspect-ratio: auto;
44
+ inline-size: auto;
45
+ block-size: auto;
46
+ }
47
+
48
+ .ui-card[data-orientation='horizontal'] > .ui-card-layout > .ui-card-header {
49
+ grid-column: 2;
50
+ grid-row: 1;
51
+ }
52
+
53
+ .ui-card[data-orientation='horizontal'] > .ui-card-layout > .ui-card-body {
54
+ grid-column: 2;
55
+ grid-row: 2;
56
+ // Content hugs the block-start of the 1fr track instead of centre-
57
+ // stretching across the extra space.
58
+ align-self: start;
59
+ }
60
+
61
+ .ui-card[data-orientation='horizontal'] > .ui-card-layout > .ui-card-footer {
62
+ grid-column: 2;
63
+ grid-row: 3;
64
+ // Row 3 is auto-sized and placed after the 1fr row → footer naturally
65
+ // pins to the block-end. The base `margin-block-start: auto` rule is a
66
+ // no-op in grid context and doesn't interfere here.
67
+ }
68
+
69
+ // Padded horizontal: media kisses the leading + block edges.
70
+ .ui-card[data-orientation='horizontal']:not([data-padding='none'])
71
+ > .ui-card-layout
72
+ > .ui-card-media {
73
+ margin-block: calc(-1 * var(--_card-padding));
74
+ margin-inline-start: calc(-1 * var(--_card-padding));
75
+ border-start-start-radius: inherit;
76
+ border-end-start-radius: inherit;
77
+ border-start-end-radius: 0;
78
+ border-end-end-radius: 0;
79
+ }
80
+
81
+ // Zero-padding horizontal: only the trailing corners need squaring.
82
+ .ui-card[data-orientation='horizontal'][data-padding='none']
83
+ > .ui-card-layout
84
+ > .ui-card-media {
85
+ border-start-end-radius: 0;
86
+ border-end-end-radius: 0;
87
+ }
88
+ }
@@ -0,0 +1,49 @@
1
+ /// Card pseudo-link overlay + focus ring
2
+ /// @group organisms/content
3
+
4
+ @use '@pithyjs/design-system/a11y/styles/mixins' as a11y;
5
+
6
+ // ============================================
7
+ // Pseudo-link overlay (clickable cards)
8
+ // ============================================
9
+
10
+ .ui-card-link {
11
+ position: absolute;
12
+ inset: 0;
13
+ z-index: 1;
14
+ border-radius: inherit;
15
+ color: inherit;
16
+ text-decoration: none;
17
+ // The link itself carries no visible chrome — the card is the affordance.
18
+ -webkit-tap-highlight-color: transparent;
19
+ }
20
+
21
+ // Interactive descendants inside a clickable card rise above the overlay
22
+ // anchor so they still receive their own clicks (buttons, tag chips,
23
+ // inline links inside the body slot).
24
+ .ui-card[data-clickable='true']
25
+ .ui-card-layout
26
+ :is(
27
+ a:not(.ui-card-link),
28
+ button,
29
+ [role='button'],
30
+ input,
31
+ select,
32
+ textarea,
33
+ [tabindex]:not([tabindex='-1'])
34
+ ) {
35
+ position: relative;
36
+ z-index: 2;
37
+ }
38
+
39
+ .ui-card-link-label {
40
+ // Visually-hidden but kept in the a11y tree.
41
+ @include a11y.visually-hidden;
42
+ }
43
+
44
+ // Card-wide focus ring: when the stretched link takes keyboard focus, the
45
+ // whole article paints the focus ring — the card *is* the focus indicator.
46
+ // Disabled cards are inert (no focus possible), but guard defensively.
47
+ .ui-card:not([data-disabled='true']):has(.ui-card-link:focus-visible) {
48
+ @include a11y.focus-ring;
49
+ }
@@ -0,0 +1,91 @@
1
+ /// Card full-bleed media overlay mode
2
+ /// @group organisms/content
3
+
4
+ // ============================================
5
+ // Full-bleed media overlay mode
6
+ // ============================================
7
+ //
8
+ // Flipped topology: media fills the card (ignoring `padding`) and the
9
+ // header/body/footer collapse into a single `.ui-card-caption` group that
10
+ // rides a gradient scrim at the block-end. Uses CSS Grid with a single
11
+ // named area so media + caption stack in the same cell — caption pins to
12
+ // block-end, media fills. Text color flips to `--color-text-inverse`
13
+ // (always readable on the dark scrim regardless of theme).
14
+
15
+ .ui-card[data-media-overlay='true'] > .ui-card-layout {
16
+ display: grid;
17
+ grid-template-areas: 'stack';
18
+ padding: 0;
19
+ gap: 0;
20
+ // Overlay cards are media-first — block-size is dictated by the media's
21
+ // aspect ratio. The caption lives on top.
22
+ min-block-size: 100%;
23
+ }
24
+
25
+ .ui-card[data-media-overlay='true'] > .ui-card-layout > .ui-card-media {
26
+ grid-area: stack;
27
+ z-index: 0;
28
+ inline-size: 100%;
29
+ block-size: 100%;
30
+ // Cancel the vertical-mode negative-inset margins — they're irrelevant
31
+ // now that media spans the whole card via grid-area.
32
+ margin: 0;
33
+ // Inherit the card's radius so corners stay rounded.
34
+ border-radius: inherit;
35
+ }
36
+
37
+ .ui-card[data-media-overlay='true'] > .ui-card-layout > .ui-card-caption {
38
+ grid-area: stack;
39
+ align-self: end;
40
+ z-index: 1;
41
+
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--space-xs);
45
+ padding: var(--_card-padding);
46
+ color: var(--color-text-inverse);
47
+
48
+ // Scrim — fades from transparent at the top to a dark `--color-overlay`
49
+ // tint at the block-end so the caption stays readable over any image.
50
+ // `--color-overlay` is a design-system token that's always dark, by design.
51
+ background: linear-gradient(
52
+ to top,
53
+ color-mix(in oklch, var(--color-overlay) 82%, transparent) 0%,
54
+ color-mix(in oklch, var(--color-overlay) 50%, transparent) 45%,
55
+ transparent 100%
56
+ );
57
+
58
+ // Inherit the card's radius on the block-end corners only.
59
+ border-end-start-radius: inherit;
60
+ border-end-end-radius: inherit;
61
+ }
62
+
63
+ // Inside a caption, the heading, body, and eyebrow all inherit the inverse
64
+ // color. Eyebrow keeps a slight tint drop so it reads as secondary.
65
+ .ui-card[data-media-overlay='true']
66
+ .ui-card-caption
67
+ :is(h1, h2, h3, h4, h5, h6),
68
+ .ui-card[data-media-overlay='true'] .ui-card-caption .ui-card-body,
69
+ .ui-card[data-media-overlay='true'] .ui-card-caption .ui-card-body .ui-text,
70
+ .ui-card[data-media-overlay='true'] .ui-card-caption .ui-text {
71
+ color: var(--color-text-inverse);
72
+ }
73
+
74
+ .ui-card[data-media-overlay='true'] .ui-card-caption .ui-card-eyebrow {
75
+ color: var(--color-text-inverse);
76
+ opacity: 0.9;
77
+ }
78
+
79
+ // Muted text becomes less translucent against the scrim — fully opaque
80
+ // inverse color reads better than a muted variant would.
81
+ .ui-card[data-media-overlay='true'] .ui-card-caption [data-color='text-muted'] {
82
+ color: var(--color-text-inverse);
83
+ opacity: 0.8;
84
+ }
85
+
86
+ // Footer's auto margin-block-start makes sense inside a flex column card,
87
+ // but inside the compact caption stack we want tight rhythm.
88
+ .ui-card[data-media-overlay='true'] .ui-card-caption > .ui-card-footer {
89
+ margin-block-start: 0;
90
+ padding-block-start: 0;
91
+ }