@boostdev/design-system-components 1.1.0 → 1.1.2

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 (269) hide show
  1. package/AGENTS.md +46 -5
  2. package/dist/client.cjs +206 -113
  3. package/dist/client.css +664 -624
  4. package/dist/client.d.cts +9 -3
  5. package/dist/client.d.ts +9 -3
  6. package/dist/client.js +241 -149
  7. package/dist/index.cjs +206 -113
  8. package/dist/index.css +664 -624
  9. package/dist/index.d.cts +9 -3
  10. package/dist/index.d.ts +9 -3
  11. package/dist/index.js +241 -149
  12. package/dist/web-components/chunk-2QA62WCQ.js +48 -0
  13. package/dist/web-components/chunk-4BX6AWXX.js +146 -0
  14. package/dist/web-components/chunk-57TRNCWQ.js +93 -0
  15. package/dist/web-components/chunk-5IPHEONG.js +139 -0
  16. package/dist/web-components/chunk-5R6IFELV.js +63 -0
  17. package/dist/web-components/chunk-5TFWOPLH.js +49 -0
  18. package/dist/web-components/chunk-6I3CFC26.js +89 -0
  19. package/dist/web-components/chunk-6T3RKUKG.js +65 -0
  20. package/dist/web-components/chunk-7FMR53BW.js +127 -0
  21. package/dist/web-components/chunk-A67LCT7C.js +134 -0
  22. package/dist/web-components/chunk-AGKJTMJI.js +56 -0
  23. package/dist/web-components/chunk-BQLZ7I4G.js +56 -0
  24. package/dist/web-components/chunk-CAPI25CU.js +53 -0
  25. package/dist/web-components/chunk-CJ5ZOO42.js +229 -0
  26. package/dist/web-components/chunk-CR5PGUHV.js +109 -0
  27. package/dist/web-components/chunk-ECW3HHWA.js +185 -0
  28. package/dist/web-components/chunk-HGBNDR22.js +98 -0
  29. package/dist/web-components/chunk-IK3PTFZ4.js +133 -0
  30. package/dist/web-components/chunk-IQGLIQSO.js +188 -0
  31. package/dist/web-components/chunk-ITHLKR7Q.js +105 -0
  32. package/dist/web-components/chunk-K5CE6HSB.js +169 -0
  33. package/dist/web-components/chunk-L3XHOMN6.js +111 -0
  34. package/dist/{web-components.js → web-components/chunk-LGEZYFUU.js} +62 -834
  35. package/dist/web-components/chunk-LSC4N56Q.js +168 -0
  36. package/dist/web-components/chunk-LY62SAVN.js +64 -0
  37. package/dist/web-components/chunk-O4UFI2RX.js +244 -0
  38. package/dist/web-components/chunk-O7I63SQX.js +124 -0
  39. package/dist/web-components/chunk-OHUTLSIQ.js +69 -0
  40. package/dist/web-components/chunk-OQTRTMAB.js +27 -0
  41. package/dist/web-components/chunk-OTX4COSV.js +187 -0
  42. package/dist/web-components/chunk-PY62FTRW.js +179 -0
  43. package/dist/web-components/chunk-Q4T5BJT6.js +94 -0
  44. package/dist/web-components/chunk-QDRH46TF.js +281 -0
  45. package/dist/web-components/chunk-QDST57JC.js +119 -0
  46. package/dist/web-components/chunk-QPOKHLMQ.js +45 -0
  47. package/dist/web-components/chunk-SOQQ7RVJ.js +88 -0
  48. package/dist/web-components/chunk-UFFCKVZE.js +149 -0
  49. package/dist/web-components/chunk-VM3YHGQ2.js +152 -0
  50. package/dist/web-components/chunk-VMMVWLXL.js +53 -0
  51. package/dist/web-components/chunk-VSS5ITNE.js +109 -0
  52. package/dist/web-components/chunk-XIENXR7H.js +118 -0
  53. package/dist/web-components/chunk-Y4MAXTMA.js +80 -0
  54. package/dist/web-components/chunk-YLVTEY23.js +165 -0
  55. package/dist/web-components/globals.d.ts +2 -0
  56. package/dist/web-components/globals.js +1 -0
  57. package/dist/web-components/index.d.ts +41 -0
  58. package/dist/web-components/index.js +165 -0
  59. package/dist/web-components/interaction/bds-accordion-item.d.ts +54 -0
  60. package/dist/web-components/interaction/bds-accordion-item.js +7 -0
  61. package/dist/web-components/interaction/bds-accordion.d.ts +50 -0
  62. package/dist/web-components/interaction/bds-accordion.js +7 -0
  63. package/dist/web-components/interaction/bds-button.d.ts +100 -0
  64. package/dist/web-components/interaction/bds-button.js +7 -0
  65. package/dist/web-components/interaction/bds-collapsible.d.ts +52 -0
  66. package/dist/web-components/interaction/bds-collapsible.js +7 -0
  67. package/dist/web-components/interaction/bds-dialog.d.ts +56 -0
  68. package/dist/web-components/interaction/bds-dialog.js +7 -0
  69. package/dist/web-components/interaction/bds-drawer.d.ts +64 -0
  70. package/dist/web-components/interaction/bds-drawer.js +7 -0
  71. package/dist/web-components/interaction/bds-popover.d.ts +62 -0
  72. package/dist/web-components/interaction/bds-popover.js +7 -0
  73. package/dist/web-components/interaction/bds-skip-link.d.ts +36 -0
  74. package/dist/web-components/interaction/bds-skip-link.js +7 -0
  75. package/dist/web-components/interaction/bds-tab-panel.d.ts +26 -0
  76. package/dist/web-components/interaction/bds-tab-panel.js +7 -0
  77. package/dist/web-components/interaction/bds-tab.d.ts +45 -0
  78. package/dist/web-components/interaction/bds-tab.js +7 -0
  79. package/dist/web-components/interaction/bds-tabs.d.ts +46 -0
  80. package/dist/web-components/interaction/bds-tabs.js +7 -0
  81. package/dist/web-components/interaction/bds-toast-provider.d.ts +57 -0
  82. package/dist/web-components/interaction/bds-toast-provider.js +7 -0
  83. package/dist/web-components/interaction/bds-tooltip.d.ts +50 -0
  84. package/dist/web-components/interaction/bds-tooltip.js +7 -0
  85. package/dist/web-components/interaction/form/bds-checkbox.d.ts +70 -0
  86. package/dist/web-components/interaction/form/bds-checkbox.js +7 -0
  87. package/dist/web-components/interaction/form/bds-combobox.d.ts +84 -0
  88. package/dist/web-components/interaction/form/bds-combobox.js +7 -0
  89. package/dist/web-components/interaction/form/bds-file-input.d.ts +62 -0
  90. package/dist/web-components/interaction/form/bds-file-input.js +7 -0
  91. package/dist/web-components/interaction/form/bds-number-input.d.ts +68 -0
  92. package/dist/web-components/interaction/form/bds-number-input.js +7 -0
  93. package/dist/web-components/interaction/form/bds-radio.d.ts +68 -0
  94. package/dist/web-components/interaction/form/bds-radio.js +7 -0
  95. package/dist/web-components/interaction/form/bds-segmented-control.d.ts +71 -0
  96. package/dist/web-components/interaction/form/bds-segmented-control.js +7 -0
  97. package/dist/web-components/interaction/form/bds-select.d.ts +79 -0
  98. package/dist/web-components/interaction/form/bds-select.js +7 -0
  99. package/dist/web-components/interaction/form/bds-slider.d.ts +70 -0
  100. package/dist/web-components/interaction/form/bds-slider.js +7 -0
  101. package/dist/web-components/interaction/form/bds-switch.d.ts +67 -0
  102. package/dist/web-components/interaction/form/bds-switch.js +7 -0
  103. package/dist/web-components/interaction/form/bds-textarea.d.ts +70 -0
  104. package/dist/web-components/interaction/form/bds-textarea.js +7 -0
  105. package/dist/web-components/ui/bds-alert.d.ts +66 -0
  106. package/dist/web-components/ui/bds-alert.js +7 -0
  107. package/dist/web-components/ui/bds-avatar.d.ts +50 -0
  108. package/dist/web-components/ui/bds-avatar.js +7 -0
  109. package/dist/web-components/ui/bds-badge.d.ts +35 -0
  110. package/dist/web-components/ui/bds-badge.js +7 -0
  111. package/dist/web-components/ui/bds-breadcrumb.d.ts +35 -0
  112. package/dist/web-components/ui/bds-breadcrumb.js +7 -0
  113. package/dist/web-components/ui/bds-card.d.ts +72 -0
  114. package/dist/web-components/ui/bds-card.js +7 -0
  115. package/dist/web-components/ui/bds-description-list.d.ts +42 -0
  116. package/dist/web-components/ui/bds-description-list.js +7 -0
  117. package/dist/web-components/ui/bds-icon-wrapper.d.ts +39 -0
  118. package/dist/web-components/ui/bds-icon-wrapper.js +7 -0
  119. package/dist/web-components/ui/bds-link.d.ts +59 -0
  120. package/dist/web-components/ui/bds-link.js +7 -0
  121. package/dist/web-components/ui/bds-loading.d.ts +32 -0
  122. package/dist/web-components/ui/bds-loading.js +7 -0
  123. package/dist/web-components/ui/bds-notification-banner.d.ts +61 -0
  124. package/dist/web-components/ui/bds-notification-banner.js +7 -0
  125. package/dist/web-components/ui/bds-progress-circle.d.ts +53 -0
  126. package/dist/web-components/ui/bds-progress-circle.js +7 -0
  127. package/dist/web-components/ui/bds-progress.d.ts +54 -0
  128. package/dist/web-components/ui/bds-progress.js +7 -0
  129. package/dist/web-components/ui/bds-rating.d.ts +36 -0
  130. package/dist/web-components/ui/bds-rating.js +7 -0
  131. package/dist/web-components/ui/bds-section-header.d.ts +53 -0
  132. package/dist/web-components/ui/bds-section-header.js +8 -0
  133. package/dist/web-components/ui/bds-separator.d.ts +32 -0
  134. package/dist/web-components/ui/bds-separator.js +7 -0
  135. package/dist/web-components/ui/bds-skeleton.d.ts +22 -0
  136. package/dist/web-components/ui/bds-skeleton.js +7 -0
  137. package/dist/web-components/ui/bds-typography.d.ts +44 -0
  138. package/dist/web-components/ui/bds-typography.js +8 -0
  139. package/package.json +169 -4
  140. package/src/components/interaction/Button/Button.module.css +1 -1
  141. package/src/components/interaction/Button/Button.native.mdx +72 -0
  142. package/src/components/interaction/Command/Command.module.css +7 -7
  143. package/src/components/interaction/Command/Command.spec.tsx +37 -0
  144. package/src/components/interaction/Command/Command.tsx +37 -2
  145. package/src/components/interaction/Dialog/Dialog.module.css +10 -13
  146. package/src/components/interaction/Dialog/Dialog.spec.tsx +53 -1
  147. package/src/components/interaction/Dialog/Dialog.stories.tsx +17 -0
  148. package/src/components/interaction/Dialog/Dialog.tsx +50 -16
  149. package/src/components/interaction/Drawer/Drawer.module.css +11 -11
  150. package/src/components/interaction/Drawer/Drawer.spec.tsx +48 -1
  151. package/src/components/interaction/Drawer/Drawer.tsx +38 -4
  152. package/src/components/interaction/DropdownMenu/DropdownMenu.module.css +6 -6
  153. package/src/components/interaction/Popover/Popover.module.css +74 -15
  154. package/src/components/interaction/Popover/Popover.spec.tsx +94 -59
  155. package/src/components/interaction/Popover/Popover.tsx +44 -60
  156. package/src/components/interaction/Toast/Toast.module.css +7 -7
  157. package/src/components/interaction/form/Checkbox/Checkbox.module.css +6 -6
  158. package/src/components/interaction/form/Checkbox/Checkbox.native.mdx +74 -0
  159. package/src/components/interaction/form/Combobox/Combobox.module.css +7 -8
  160. package/src/components/interaction/form/FileInput/FileInput.module.css +4 -4
  161. package/src/components/interaction/form/NumberInput/NumberInput.module.css +1 -1
  162. package/src/components/interaction/form/Radio/Radio.module.css +6 -6
  163. package/src/components/interaction/form/SegmentedControl/SegmentedControl.module.css +5 -6
  164. package/src/components/interaction/form/Select/Select.module.css +3 -3
  165. package/src/components/interaction/form/Slider/Slider.module.css +6 -6
  166. package/src/components/interaction/form/Switch/Switch.module.css +8 -8
  167. package/src/components/interaction/form/Textarea/Textarea.module.css +1 -1
  168. package/src/components/layout/IconWrapper/IconWrapper.module.css +2 -2
  169. package/src/components/ui/Accordion/Accordion.module.css +5 -5
  170. package/src/components/ui/Alert/Alert.native.mdx +62 -0
  171. package/src/components/ui/Avatar/Avatar.native.mdx +50 -0
  172. package/src/components/ui/Badge/Badge.native.mdx +54 -0
  173. package/src/components/ui/Calendar/Calendar.module.css +7 -7
  174. package/src/components/ui/Carousel/Carousel.module.css +5 -5
  175. package/src/components/ui/Collapsible/Collapsible.module.css +4 -4
  176. package/src/components/ui/Link/Link.module.css +2 -2
  177. package/src/components/ui/Loading/Loading.module.css +7 -7
  178. package/src/components/ui/NotificationBanner/NotificationBanner.module.css +3 -3
  179. package/src/components/ui/Pagination/Pagination.module.css +6 -6
  180. package/src/components/ui/Progress/Progress.module.css +5 -5
  181. package/src/components/ui/Separator/Separator.module.css +3 -3
  182. package/src/components/ui/Skeleton/Skeleton.module.css +1 -1
  183. package/src/components/ui/Table/Table.module.css +9 -9
  184. package/src/components/ui/Tabs/Tabs.module.css +3 -3
  185. package/src/components/ui/Tooltip/Tooltip.module.css +8 -8
  186. package/src/components/ui/Typography/Typography.native.mdx +56 -0
  187. package/src/polyfill-invoker-commands.ts +68 -0
  188. package/src/react-augment.d.ts +19 -0
  189. package/src/stories/ReactNative.mdx +121 -0
  190. package/src/web-components/index.ts +47 -0
  191. package/src/web-components/interaction/BdsButton.mdx +106 -0
  192. package/src/web-components/interaction/BdsPopover.mdx +120 -0
  193. package/src/web-components/interaction/BdsToastProvider.mdx +94 -0
  194. package/src/web-components/interaction/bds-accordion-item.spec.ts +75 -0
  195. package/src/web-components/interaction/bds-accordion-item.ts +181 -0
  196. package/src/web-components/interaction/bds-accordion.spec.ts +73 -0
  197. package/src/web-components/interaction/bds-accordion.ts +99 -0
  198. package/src/web-components/interaction/bds-collapsible.spec.ts +56 -0
  199. package/src/web-components/interaction/bds-collapsible.ts +170 -0
  200. package/src/web-components/interaction/bds-dialog.spec.ts +119 -0
  201. package/src/web-components/interaction/bds-dialog.ts +224 -0
  202. package/src/web-components/interaction/bds-drawer.spec.ts +113 -0
  203. package/src/web-components/interaction/bds-drawer.ts +266 -0
  204. package/src/web-components/interaction/bds-popover.spec.ts +49 -1
  205. package/src/web-components/interaction/bds-popover.ts +12 -0
  206. package/src/web-components/interaction/bds-skip-link.spec.ts +42 -0
  207. package/src/web-components/interaction/bds-skip-link.ts +74 -0
  208. package/src/web-components/interaction/bds-tab-panel.spec.ts +32 -0
  209. package/src/web-components/interaction/bds-tab-panel.ts +38 -0
  210. package/src/web-components/interaction/bds-tab.spec.ts +71 -0
  211. package/src/web-components/interaction/bds-tab.ts +110 -0
  212. package/src/web-components/interaction/bds-tabs.spec.ts +120 -0
  213. package/src/web-components/interaction/bds-tabs.ts +152 -0
  214. package/src/web-components/interaction/bds-tooltip.spec.ts +49 -0
  215. package/src/web-components/interaction/bds-tooltip.ts +127 -0
  216. package/src/web-components/interaction/form/bds-checkbox.spec.ts +63 -0
  217. package/src/web-components/interaction/form/bds-checkbox.ts +168 -0
  218. package/src/web-components/interaction/form/bds-combobox.spec.ts +117 -0
  219. package/src/web-components/interaction/form/bds-combobox.ts +336 -0
  220. package/src/web-components/interaction/form/bds-file-input.spec.ts +58 -0
  221. package/src/web-components/interaction/form/bds-file-input.ts +209 -0
  222. package/src/web-components/interaction/form/bds-number-input.spec.ts +87 -0
  223. package/src/web-components/interaction/form/bds-number-input.ts +221 -0
  224. package/src/web-components/interaction/form/bds-radio.spec.ts +70 -0
  225. package/src/web-components/interaction/form/bds-radio.ts +157 -0
  226. package/src/web-components/interaction/form/bds-segmented-control.spec.ts +74 -0
  227. package/src/web-components/interaction/form/bds-segmented-control.ts +211 -0
  228. package/src/web-components/interaction/form/bds-select.spec.ts +74 -0
  229. package/src/web-components/interaction/form/bds-select.ts +190 -0
  230. package/src/web-components/interaction/form/bds-slider.spec.ts +41 -0
  231. package/src/web-components/interaction/form/bds-slider.ts +162 -0
  232. package/src/web-components/interaction/form/bds-switch.spec.ts +62 -0
  233. package/src/web-components/interaction/form/bds-switch.ts +166 -0
  234. package/src/web-components/interaction/form/bds-textarea.spec.ts +55 -0
  235. package/src/web-components/interaction/form/bds-textarea.ts +143 -0
  236. package/src/web-components/test/helpers.ts +8 -0
  237. package/src/web-components/ui/BdsAlert.mdx +90 -0
  238. package/src/web-components/ui/BdsBadge.mdx +74 -0
  239. package/src/web-components/ui/bds-avatar.spec.ts +75 -0
  240. package/src/web-components/ui/bds-avatar.ts +122 -0
  241. package/src/web-components/ui/bds-breadcrumb.spec.ts +55 -0
  242. package/src/web-components/ui/bds-breadcrumb.ts +114 -0
  243. package/src/web-components/ui/bds-card.spec.ts +70 -0
  244. package/src/web-components/ui/bds-card.ts +156 -0
  245. package/src/web-components/ui/bds-description-list.spec.ts +36 -0
  246. package/src/web-components/ui/bds-description-list.ts +79 -0
  247. package/src/web-components/ui/bds-icon-wrapper.spec.ts +21 -0
  248. package/src/web-components/ui/bds-icon-wrapper.ts +68 -0
  249. package/src/web-components/ui/bds-link.spec.ts +72 -0
  250. package/src/web-components/ui/bds-link.ts +138 -0
  251. package/src/web-components/ui/bds-loading.spec.ts +38 -0
  252. package/src/web-components/ui/bds-loading.ts +76 -0
  253. package/src/web-components/ui/bds-notification-banner.spec.ts +82 -0
  254. package/src/web-components/ui/bds-notification-banner.ts +185 -0
  255. package/src/web-components/ui/bds-progress-circle.spec.ts +58 -0
  256. package/src/web-components/ui/bds-progress-circle.ts +142 -0
  257. package/src/web-components/ui/bds-progress.spec.ts +66 -0
  258. package/src/web-components/ui/bds-progress.ts +127 -0
  259. package/src/web-components/ui/bds-rating.spec.ts +70 -0
  260. package/src/web-components/ui/bds-rating.ts +80 -0
  261. package/src/web-components/ui/bds-section-header.spec.ts +57 -0
  262. package/src/web-components/ui/bds-section-header.ts +96 -0
  263. package/src/web-components/ui/bds-separator.spec.ts +50 -0
  264. package/src/web-components/ui/bds-separator.ts +66 -0
  265. package/src/web-components/ui/bds-skeleton.spec.ts +22 -0
  266. package/src/web-components/ui/bds-skeleton.ts +55 -0
  267. package/src/web-components/ui/bds-typography.spec.ts +76 -0
  268. package/src/web-components/ui/bds-typography.ts +112 -0
  269. package/dist/web-components.d.ts +0 -303
@@ -0,0 +1,156 @@
1
+ import { LitElement, css, html, nothing } from 'lit';
2
+
3
+ export type CardVariant = 'default' | 'elevated' | 'outlined';
4
+ export type CardPadding = 'none' | 'small' | 'medium' | 'large';
5
+ export type CardTextAlign = 'start' | 'center' | 'end';
6
+
7
+ /**
8
+ * `<bds-card>` — framework-agnostic Card layout custom element.
9
+ *
10
+ * Attributes:
11
+ * variant — "default" (default) | "elevated" | "outlined"
12
+ * padding — "none" | "small" | "medium" (default) | "large"
13
+ * text-align — "start" (default) | "center" | "end"
14
+ * clickable — boolean; renders as a <button> with hover/active effects
15
+ * aria-label — accessible label (useful when clickable)
16
+ *
17
+ * Slots:
18
+ * (default) — card content
19
+ *
20
+ * Events:
21
+ * bds-click — fired (bubbles, composed) when the card button is clicked
22
+ *
23
+ * @example
24
+ * <bds-card variant="elevated" padding="large">
25
+ * <p>Card content</p>
26
+ * </bds-card>
27
+ *
28
+ * <bds-card clickable aria-label="Open details">
29
+ * <p>Clickable card</p>
30
+ * </bds-card>
31
+ */
32
+ export class BdsCard extends LitElement {
33
+ static styles = css`
34
+ :host {
35
+ display: block;
36
+ }
37
+
38
+ .card {
39
+ background-color: var(--card_color, var(--bds-color_bg));
40
+ color: var(--card_on-color, var(--bds-color_on-bg));
41
+ border-radius: var(--bds-border_radius--m);
42
+ transition: all 0.3s ease;
43
+ position: relative;
44
+ box-sizing: border-box;
45
+ inline-size: 100%;
46
+ text-align: inherit;
47
+ font: inherit;
48
+ border: none;
49
+ }
50
+
51
+ .card.--default { box-shadow: var(--bds-shadow_s); }
52
+ .card.--elevated { box-shadow: var(--bds-shadow_m); }
53
+
54
+ .card.--outlined {
55
+ --bdc_color: currentcolor;
56
+ outline: var(--bdc-outline_width) solid var(--bdc_color);
57
+ outline-offset: var(--bdc-outline_offset);
58
+ box-shadow: var(--bds-shadow_s);
59
+ }
60
+
61
+ .card.--padding-none { padding: 0; }
62
+ .card.--padding-small { padding: var(--bds-space_s); }
63
+ .card.--padding-medium { padding: var(--bds-space_m); }
64
+ .card.--padding-large { padding: var(--bds-space_l); }
65
+
66
+ .card.--text-start { text-align: start; }
67
+ .card.--text-center { text-align: center; }
68
+ .card.--text-end { text-align: end; }
69
+
70
+ .card.--clickable {
71
+ cursor: pointer;
72
+ display: block;
73
+ }
74
+
75
+ .card.--clickable:focus-visible {
76
+ outline: 2px solid var(--color_focus, currentcolor);
77
+ outline-offset: 2px;
78
+ }
79
+
80
+ .card.--clickable:active {
81
+ transform: translateY(0);
82
+ box-shadow: var(--bds-shadow_s);
83
+ }
84
+
85
+ @media (hover: hover) and (pointer: fine) {
86
+ .card.--clickable:hover {
87
+ transform: translateY(-2px);
88
+ box-shadow: var(--bds-shadow_xl);
89
+ }
90
+
91
+ .card.--default:hover { box-shadow: var(--bds-shadow_m); }
92
+ .card.--elevated:hover { box-shadow: var(--bds-shadow_2xl); }
93
+ .card.--outlined:hover { box-shadow: var(--bds-shadow_s); }
94
+ }
95
+ `;
96
+
97
+ static properties = {
98
+ variant: { type: String, reflect: true },
99
+ padding: { type: String, reflect: true },
100
+ textAlign: { type: String, attribute: 'text-align', reflect: true },
101
+ clickable: { type: Boolean, reflect: true },
102
+ ariaLabel: { type: String, attribute: 'aria-label' },
103
+ };
104
+
105
+ declare variant: CardVariant;
106
+ declare padding: CardPadding;
107
+ declare textAlign: CardTextAlign;
108
+ declare clickable: boolean;
109
+ declare ariaLabel: string;
110
+
111
+ constructor() {
112
+ super();
113
+ this.variant = 'default';
114
+ this.padding = 'medium';
115
+ this.textAlign = 'start';
116
+ this.clickable = false;
117
+ this.ariaLabel = '';
118
+ }
119
+
120
+ private _handleClick() {
121
+ this.dispatchEvent(new CustomEvent('bds-click', { bubbles: true, composed: true }));
122
+ }
123
+
124
+ render() {
125
+ const classes = [
126
+ 'card',
127
+ `--${this.variant}`,
128
+ `--padding-${this.padding}`,
129
+ `--text-${this.textAlign}`,
130
+ this.clickable ? '--clickable' : '',
131
+ ].filter(Boolean).join(' ');
132
+
133
+ if (this.clickable) {
134
+ return html`
135
+ <button
136
+ type="button"
137
+ class=${classes}
138
+ @click=${this._handleClick}
139
+ aria-label=${this.ariaLabel || nothing}
140
+ >
141
+ <slot></slot>
142
+ </button>
143
+ `;
144
+ }
145
+
146
+ return html`<div class=${classes}><slot></slot></div>`;
147
+ }
148
+ }
149
+
150
+ customElements.define('bds-card', BdsCard);
151
+
152
+ declare global {
153
+ interface HTMLElementTagNameMap {
154
+ 'bds-card': BdsCard;
155
+ }
156
+ }
@@ -0,0 +1,36 @@
1
+ import { fixture, cleanup } from '../test/helpers';
2
+ import { BdsDescriptionList } from './bds-description-list';
3
+
4
+ describe('bds-description-list', () => {
5
+ it('is registered as a custom element', () => {
6
+ expect(customElements.get('bds-description-list')).toBe(BdsDescriptionList);
7
+ });
8
+
9
+ it('defaults to layout="stacked"', async () => {
10
+ const el = await fixture('<bds-description-list></bds-description-list>');
11
+ expect(el.getAttribute('layout')).toBe('stacked');
12
+ cleanup(el);
13
+ });
14
+
15
+ it('renders a <dl> in shadow DOM', async () => {
16
+ const el = await fixture('<bds-description-list></bds-description-list>');
17
+ expect(el.shadowRoot!.querySelector('dl')).not.toBeNull();
18
+ cleanup(el);
19
+ });
20
+
21
+ it('accepts slotted <dt> and <dd> elements', async () => {
22
+ const el = await fixture('<bds-description-list><dt>Name</dt><dd>Jane</dd></bds-description-list>');
23
+ expect(el.querySelector('dt')!.textContent).toBe('Name');
24
+ expect(el.querySelector('dd')!.textContent).toBe('Jane');
25
+ cleanup(el);
26
+ });
27
+
28
+ it('reflects layout attribute', async () => {
29
+ const el = await fixture('<bds-description-list layout="inline"></bds-description-list>') as BdsDescriptionList;
30
+ expect(el.getAttribute('layout')).toBe('inline');
31
+ el.layout = 'stacked';
32
+ await el.updateComplete;
33
+ expect(el.getAttribute('layout')).toBe('stacked');
34
+ cleanup(el);
35
+ });
36
+ });
@@ -0,0 +1,79 @@
1
+ import { LitElement, css, html } from 'lit';
2
+
3
+ /**
4
+ * `<bds-description-list>` — framework-agnostic Description List custom element.
5
+ *
6
+ * Renders a `<dl>` styled list. Consumers provide `<dt>` and `<dd>` elements
7
+ * as slotted children; this component handles layout and styling.
8
+ *
9
+ * Attributes:
10
+ * layout — "stacked" (default) | "inline"
11
+ *
12
+ * Slots:
13
+ * (default) — `<dt>` and `<dd>` pairs
14
+ *
15
+ * @example
16
+ * <bds-description-list layout="inline">
17
+ * <dt>Name</dt>
18
+ * <dd>Jane Doe</dd>
19
+ * <dt>Email</dt>
20
+ * <dd>jane@example.com</dd>
21
+ * </bds-description-list>
22
+ */
23
+ export class BdsDescriptionList extends LitElement {
24
+ static styles = css`
25
+ :host {
26
+ display: block;
27
+ }
28
+
29
+ .list {
30
+ display: flex;
31
+ flex-direction: column;
32
+ gap: var(--bds-space_s);
33
+ margin: 0;
34
+ padding: 0;
35
+ font-size: var(--bds-font_size--body);
36
+ color: var(--bds-color_on-bg);
37
+ }
38
+
39
+ /* Style slotted dt/dd elements */
40
+ ::slotted(dt) {
41
+ font-weight: var(--bds-font_weight--semibold);
42
+ color: var(--bds-color_on-bg);
43
+ margin: 0;
44
+ }
45
+
46
+ ::slotted(dd) {
47
+ margin: 0;
48
+ color: var(--bds-color_on-bg);
49
+ }
50
+
51
+ /* Inline layout: pair each dt/dd side by side */
52
+ :host([layout='inline']) .list {
53
+ gap: var(--bds-space_xs);
54
+ }
55
+ `;
56
+
57
+ static properties = {
58
+ layout: { type: String, reflect: true },
59
+ };
60
+
61
+ declare layout: 'stacked' | 'inline';
62
+
63
+ constructor() {
64
+ super();
65
+ this.layout = 'stacked';
66
+ }
67
+
68
+ render() {
69
+ return html`<dl class="list"><slot></slot></dl>`;
70
+ }
71
+ }
72
+
73
+ customElements.define('bds-description-list', BdsDescriptionList);
74
+
75
+ declare global {
76
+ interface HTMLElementTagNameMap {
77
+ 'bds-description-list': BdsDescriptionList;
78
+ }
79
+ }
@@ -0,0 +1,21 @@
1
+ import { fixture, cleanup } from '../test/helpers';
2
+ import { BdsIconWrapper } from './bds-icon-wrapper';
3
+
4
+ describe('bds-icon-wrapper', () => {
5
+ it('is registered as a custom element', () => {
6
+ expect(customElements.get('bds-icon-wrapper')).toBe(BdsIconWrapper);
7
+ });
8
+
9
+ it('renders a wrapper div in shadow DOM', async () => {
10
+ const el = await fixture('<bds-icon-wrapper></bds-icon-wrapper>');
11
+ expect(el.shadowRoot!.querySelector('.wrapper')).not.toBeNull();
12
+ cleanup(el);
13
+ });
14
+
15
+ it('renders slotted content', async () => {
16
+ const el = await fixture('<bds-icon-wrapper><svg aria-hidden="true"></svg></bds-icon-wrapper>');
17
+ const svg = el.querySelector('svg');
18
+ expect(svg).not.toBeNull();
19
+ cleanup(el);
20
+ });
21
+ });
@@ -0,0 +1,68 @@
1
+ import { LitElement, css, html } from 'lit';
2
+
3
+ /**
4
+ * `<bds-icon-wrapper>` — framework-agnostic Icon Wrapper custom element.
5
+ *
6
+ * Displays an icon inside a circular container with background and foreground theming.
7
+ *
8
+ * Attributes:
9
+ * aria-hidden — boolean attribute; set to "true" for decorative icons
10
+ *
11
+ * Slots:
12
+ * (default) — icon content (SVG or img)
13
+ *
14
+ * @example
15
+ * <bds-icon-wrapper aria-hidden="true">
16
+ * <svg>…</svg>
17
+ * </bds-icon-wrapper>
18
+ */
19
+ export class BdsIconWrapper extends LitElement {
20
+ static styles = css`
21
+ :host {
22
+ display: inline-flex;
23
+ }
24
+
25
+ .wrapper {
26
+ inline-size: 2em;
27
+ block-size: 2em;
28
+ font-size: 3em;
29
+ border-radius: 50%;
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ margin: var(--bds-space_l) auto var(--bds-space_m);
34
+ background: var(--icon-wrapper-color, var(--bds-color_bg));
35
+ color: var(--bds-on-icon-wrapper-color, var(--bds-color_on-bg));
36
+ fill: var(--bds-on-icon-wrapper-color, var(--bds-color_on-bg));
37
+ position: relative;
38
+ transition: var(--bds-animation_transition);
39
+ }
40
+
41
+ .wrapper svg {
42
+ fill: currentcolor;
43
+ }
44
+ `;
45
+
46
+ static properties = {
47
+ ariaHidden: { type: String, attribute: 'aria-hidden', reflect: true },
48
+ };
49
+
50
+ declare ariaHidden: string;
51
+
52
+ constructor() {
53
+ super();
54
+ this.ariaHidden = '';
55
+ }
56
+
57
+ render() {
58
+ return html`<div class="wrapper"><slot></slot></div>`;
59
+ }
60
+ }
61
+
62
+ customElements.define('bds-icon-wrapper', BdsIconWrapper);
63
+
64
+ declare global {
65
+ interface HTMLElementTagNameMap {
66
+ 'bds-icon-wrapper': BdsIconWrapper;
67
+ }
68
+ }
@@ -0,0 +1,72 @@
1
+ import { fixture, cleanup } from '../test/helpers';
2
+ import { BdsLink } from './bds-link';
3
+
4
+ describe('bds-link', () => {
5
+ it('is registered as a custom element', () => {
6
+ expect(customElements.get('bds-link')).toBe(BdsLink);
7
+ });
8
+
9
+ it('defaults to variant="default"', async () => {
10
+ const el = await fixture('<bds-link href="/test">Link</bds-link>');
11
+ expect(el.getAttribute('variant')).toBe('default');
12
+ cleanup(el);
13
+ });
14
+
15
+ it('renders an <a> with the given href', async () => {
16
+ const el = await fixture('<bds-link href="/about">About</bds-link>');
17
+ const a = el.shadowRoot!.querySelector('a');
18
+ expect(a).not.toBeNull();
19
+ expect(a!.getAttribute('href')).toBe('/about');
20
+ cleanup(el);
21
+ });
22
+
23
+ it('renders slotted content', async () => {
24
+ const el = await fixture('<bds-link href="/">Home</bds-link>');
25
+ expect(el.textContent?.trim()).toBe('Home');
26
+ cleanup(el);
27
+ });
28
+
29
+ it('adds target="_blank" and rel="noreferrer noopener" when external is set', async () => {
30
+ const el = await fixture('<bds-link href="https://example.com" external>Visit</bds-link>');
31
+ const a = el.shadowRoot!.querySelector('a');
32
+ expect(a!.getAttribute('target')).toBe('_blank');
33
+ expect(a!.getAttribute('rel')).toBe('noreferrer noopener');
34
+ cleanup(el);
35
+ });
36
+
37
+ it('renders visually hidden external label when external is set', async () => {
38
+ const el = await fixture('<bds-link href="https://example.com" external>Visit</bds-link>');
39
+ const label = el.shadowRoot!.querySelector('.external-label');
40
+ expect(label).not.toBeNull();
41
+ expect(label!.textContent).toBe('(opens in new tab)');
42
+ cleanup(el);
43
+ });
44
+
45
+ it('uses custom external-label when provided', async () => {
46
+ const el = await fixture('<bds-link href="https://example.com" external external-label="(new window)">Visit</bds-link>');
47
+ const label = el.shadowRoot!.querySelector('.external-label');
48
+ expect(label!.textContent).toBe('(new window)');
49
+ cleanup(el);
50
+ });
51
+
52
+ it('does not render external label when external is not set', async () => {
53
+ const el = await fixture('<bds-link href="/about">About</bds-link>');
54
+ expect(el.shadowRoot!.querySelector('.external-label')).toBeNull();
55
+ cleanup(el);
56
+ });
57
+
58
+ it('applies variant class to the anchor', async () => {
59
+ const el = await fixture('<bds-link href="/test" variant="subtle">Link</bds-link>');
60
+ const a = el.shadowRoot!.querySelector('a');
61
+ expect(a!.classList.contains('--variant_subtle')).toBe(true);
62
+ cleanup(el);
63
+ });
64
+
65
+ it('reflects variant property updates', async () => {
66
+ const el = await fixture('<bds-link href="/test">Link</bds-link>') as BdsLink;
67
+ el.variant = 'standalone';
68
+ await el.updateComplete;
69
+ expect(el.getAttribute('variant')).toBe('standalone');
70
+ cleanup(el);
71
+ });
72
+ });
@@ -0,0 +1,138 @@
1
+ import { LitElement, css, html, nothing } from 'lit';
2
+
3
+ export type LinkVariant = 'default' | 'subtle' | 'standalone';
4
+
5
+ /**
6
+ * `<bds-link>` — framework-agnostic Link custom element.
7
+ *
8
+ * Attributes:
9
+ * href — URL for the anchor
10
+ * target — link target (e.g. "_blank")
11
+ * variant — "default" (default) | "subtle" | "standalone"
12
+ * external — boolean; when set, adds rel="noreferrer noopener" and a
13
+ * visually-hidden label for screen readers
14
+ * external-label — the screen reader text appended for external links
15
+ * (default: "(opens in new tab)")
16
+ *
17
+ * Slots:
18
+ * (default) — link text / content
19
+ *
20
+ * @example
21
+ * <bds-link href="https://example.com" external>Visit site</bds-link>
22
+ */
23
+ export class BdsLink extends LitElement {
24
+ static styles = css`
25
+ :host {
26
+ display: inline;
27
+ }
28
+
29
+ .link {
30
+ color: var(--link_color, var(--bds-color_interactive_on-bg));
31
+ text-decoration: underline;
32
+ text-underline-offset: 0.2em;
33
+ transition: var(--bds-animation_transition);
34
+ cursor: pointer;
35
+ }
36
+
37
+ .link:focus-visible {
38
+ outline: var(--bds-outline_default);
39
+ outline-offset: var(--bds-outline_offset);
40
+ border-radius: var(--bds-border_radius--xs);
41
+ }
42
+
43
+ @media (hover: hover) and (pointer: fine) {
44
+ .link:hover {
45
+ --link_color: var(--link_color-hover, var(--bds-color_blue--strong));
46
+ }
47
+ }
48
+
49
+ .link.--variant_default {
50
+ --link_color: var(--bds-color_interactive_on-bg);
51
+ --link_color-hover: var(--bds-color_blue--strong);
52
+ }
53
+
54
+ .link.--variant_subtle {
55
+ --link_color: var(--bds-color_on-bg);
56
+ --link_color-hover: var(--bds-color_interactive_on-bg);
57
+ }
58
+
59
+ .link.--variant_standalone {
60
+ --link_color: var(--bds-color_interactive_on-bg);
61
+ --link_color-hover: var(--bds-color_blue--strong);
62
+ display: inline-flex;
63
+ align-items: center;
64
+ gap: var(--bds-space_xxs);
65
+ font-weight: var(--bds-font_weight--semibold);
66
+ text-decoration: none;
67
+ }
68
+
69
+ @media (hover: hover) and (pointer: fine) {
70
+ .link.--variant_standalone:hover {
71
+ text-decoration: underline;
72
+ text-underline-offset: 0.2em;
73
+ }
74
+ }
75
+
76
+ .external-label {
77
+ position: absolute;
78
+ inline-size: 1px;
79
+ block-size: 1px;
80
+ padding: 0;
81
+ margin: -1px;
82
+ overflow: hidden;
83
+ clip: rect(0, 0, 0, 0);
84
+ white-space: nowrap;
85
+ border-width: 0;
86
+ }
87
+ `;
88
+
89
+ static properties = {
90
+ href: { type: String },
91
+ target: { type: String },
92
+ variant: { type: String, reflect: true },
93
+ external: { type: Boolean, reflect: true },
94
+ externalLabel: { type: String, attribute: 'external-label' },
95
+ };
96
+
97
+ declare href: string;
98
+ declare target: string;
99
+ declare variant: LinkVariant;
100
+ declare external: boolean;
101
+ declare externalLabel: string;
102
+
103
+ constructor() {
104
+ super();
105
+ this.href = '';
106
+ this.target = '';
107
+ this.variant = 'default';
108
+ this.external = false;
109
+ this.externalLabel = '(opens in new tab)';
110
+ }
111
+
112
+ render() {
113
+ const rel = this.external ? 'noreferrer noopener' : nothing;
114
+ const target = this.external ? '_blank' : (this.target || nothing);
115
+
116
+ return html`
117
+ <a
118
+ class="link --variant_${this.variant}"
119
+ href=${this.href || nothing}
120
+ target=${target}
121
+ rel=${rel}
122
+ >
123
+ <slot></slot>
124
+ ${this.external
125
+ ? html`<span class="external-label">${this.externalLabel}</span>`
126
+ : nothing}
127
+ </a>
128
+ `;
129
+ }
130
+ }
131
+
132
+ customElements.define('bds-link', BdsLink);
133
+
134
+ declare global {
135
+ interface HTMLElementTagNameMap {
136
+ 'bds-link': BdsLink;
137
+ }
138
+ }
@@ -0,0 +1,38 @@
1
+ import { fixture, cleanup } from '../test/helpers';
2
+ import { BdsLoading } from './bds-loading';
3
+
4
+ describe('bds-loading', () => {
5
+ it('is registered as a custom element', () => {
6
+ expect(customElements.get('bds-loading')).toBe(BdsLoading);
7
+ });
8
+
9
+ it('defaults to size="medium"', async () => {
10
+ const el = await fixture('<bds-loading></bds-loading>');
11
+ expect(el.getAttribute('size')).toBe('medium');
12
+ cleanup(el);
13
+ });
14
+
15
+ it('renders a spinner in shadow DOM', async () => {
16
+ const el = await fixture('<bds-loading></bds-loading>');
17
+ const spinner = el.shadowRoot!.querySelector('.spinner');
18
+ expect(spinner).not.toBeNull();
19
+ cleanup(el);
20
+ });
21
+
22
+ it('spinner has role="status" and aria-label="Loading"', async () => {
23
+ const el = await fixture('<bds-loading></bds-loading>');
24
+ const spinner = el.shadowRoot!.querySelector('.spinner');
25
+ expect(spinner!.getAttribute('role')).toBe('status');
26
+ expect(spinner!.getAttribute('aria-label')).toBe('Loading');
27
+ cleanup(el);
28
+ });
29
+
30
+ it('reflects size attribute', async () => {
31
+ const el = await fixture('<bds-loading size="large"></bds-loading>') as BdsLoading;
32
+ expect(el.size).toBe('large');
33
+ el.size = 'small';
34
+ await el.updateComplete;
35
+ expect(el.getAttribute('size')).toBe('small');
36
+ cleanup(el);
37
+ });
38
+ });
@@ -0,0 +1,76 @@
1
+ import { LitElement, css, html } from 'lit';
2
+
3
+ /**
4
+ * `<bds-loading>` — framework-agnostic Loading spinner custom element.
5
+ *
6
+ * Attributes:
7
+ * size — "small" | "medium" (default) | "large"
8
+ *
9
+ * @example
10
+ * <bds-loading></bds-loading>
11
+ * <bds-loading size="large"></bds-loading>
12
+ */
13
+ export class BdsLoading extends LitElement {
14
+ static styles = css`
15
+ :host {
16
+ display: flex;
17
+ justify-content: center;
18
+ align-items: center;
19
+ }
20
+
21
+ .spinner {
22
+ inline-size: 2.5em;
23
+ block-size: 2.5em;
24
+ border: 4px solid var(--bds-color_bg);
25
+ border-block-start: 4px solid var(--bds-color_interactive);
26
+ border-radius: 50%;
27
+ animation: spin 1s linear infinite;
28
+ }
29
+
30
+ :host([size='small']) .spinner {
31
+ inline-size: 1.5em;
32
+ block-size: 1.5em;
33
+ border-width: 2px;
34
+ }
35
+
36
+ :host([size='large']) .spinner {
37
+ inline-size: 4em;
38
+ block-size: 4em;
39
+ border-width: 6px;
40
+ }
41
+
42
+ @keyframes spin {
43
+ 0% { transform: rotate(0deg); }
44
+ 100% { transform: rotate(360deg); }
45
+ }
46
+
47
+ @media (prefers-reduced-motion: reduce) {
48
+ .spinner {
49
+ animation: none;
50
+ }
51
+ }
52
+ `;
53
+
54
+ static properties = {
55
+ size: { type: String, reflect: true },
56
+ };
57
+
58
+ declare size: 'small' | 'medium' | 'large';
59
+
60
+ constructor() {
61
+ super();
62
+ this.size = 'medium';
63
+ }
64
+
65
+ render() {
66
+ return html`<div class="spinner" role="status" aria-label="Loading"></div>`;
67
+ }
68
+ }
69
+
70
+ customElements.define('bds-loading', BdsLoading);
71
+
72
+ declare global {
73
+ interface HTMLElementTagNameMap {
74
+ 'bds-loading': BdsLoading;
75
+ }
76
+ }