@brightspot/ui 6.8.0 → 6.8.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 (191) hide show
  1. package/CHANGELOG.md +661 -0
  2. package/README.md +18 -2
  3. package/dist/storybook/CHANGELOG.md +661 -0
  4. package/dist/storybook/README.md +195 -0
  5. package/dist/storybook/assets/{ActionBar.stories-CJBn-mku.js → ActionBar.stories-TlhuCumU.js} +31 -28
  6. package/dist/storybook/assets/ActionItem-CjtyGLd5.js +16 -0
  7. package/dist/storybook/assets/{ActionItem.stories-DXzC9C1u.js → ActionItem.stories-BVlNQvfP.js} +2 -2
  8. package/dist/storybook/assets/AiSparkle.stories-DMzc8JUe.js +73 -0
  9. package/dist/storybook/assets/Avatar-C6Li1sPI.js +4 -0
  10. package/dist/storybook/assets/Avatar.stories-COj6XrPn.js +213 -0
  11. package/dist/storybook/assets/AvatarGroup-DgxRTZBe.js +1 -0
  12. package/dist/storybook/assets/AvatarGroup.stories-Dh3e7iN2.js +225 -0
  13. package/dist/storybook/assets/Badge-bWrvpEgX.js +1 -0
  14. package/dist/storybook/assets/{Badge.stories-DEpoJpUZ.js → Badge.stories-KXpmEXpt.js} +4 -4
  15. package/dist/storybook/assets/Banner-FSFX1AIb.css +1 -0
  16. package/dist/storybook/assets/{Banner.stories--jeU6fKq.js → Banner.stories-Cnhm3dXK.js} +14 -14
  17. package/dist/storybook/assets/Button-DE0s-gat.js +10 -0
  18. package/dist/storybook/assets/Button.stories-Cwg1YZEb.js +54 -0
  19. package/dist/storybook/assets/ButtonGroup-CoLI5nGO.js +1 -0
  20. package/dist/storybook/assets/{ButtonGroup.stories-CerE_0AC.js → ButtonGroup.stories-VhnKPP1n.js} +7 -7
  21. package/dist/storybook/assets/Card-DyntwdY-.css +1 -0
  22. package/dist/storybook/assets/{Card.stories-5SxHtU3Y.js → Card.stories-BgpL90zB.js} +60 -29
  23. package/dist/storybook/assets/{Celebrate.stories-COS789GX.js → Celebrate.stories-D3NJgYcX.js} +5 -5
  24. package/dist/storybook/assets/Checkbox-BC1T_KxW.js +30 -0
  25. package/dist/storybook/assets/{Checkbox.stories-DuQu38Gv.js → Checkbox.stories-AFQNz7dQ.js} +10 -10
  26. package/dist/storybook/assets/CircularProgress-eqVb2jUD.js +42 -0
  27. package/dist/storybook/assets/{CircularProgress.stories-Lf2Ws46Y.js → CircularProgress.stories-B6t8VhmJ.js} +2 -2
  28. package/dist/storybook/assets/ClipboardMixin-DcxrOy5B.js +1 -0
  29. package/dist/storybook/assets/{ClipboardMixin.stories-BT5KfLZ_.js → ClipboardMixin.stories-BqtQMjmS.js} +6 -6
  30. package/dist/storybook/assets/{Color-6BZIO3FS-BNBxjqrS.js → Color-6BZIO3FS-CDluohEc.js} +1 -1
  31. package/dist/storybook/assets/{Colors.stories-Ck6bXbd0.js → Colors.stories-CqTniDIa.js} +1 -1
  32. package/dist/storybook/assets/{CombinedEffects.stories-DLELdAMr.js → CombinedEffects.stories-FwW0chy5.js} +2 -2
  33. package/dist/storybook/assets/{ComponentStatesMixin-B6uJL_2c.js → ComponentStatesMixin-hUqOL2aW.js} +1 -1
  34. package/dist/storybook/assets/{ComponentStatesMixin.stories-fiyrALkY.js → ComponentStatesMixin.stories-CwGoq685.js} +1 -1
  35. package/dist/storybook/assets/{CopyToClipboard.stories-2OfBH19_.js → CopyToClipboard.stories-DUGjgtQx.js} +18 -10
  36. package/dist/storybook/assets/{Debounce.stories-C9qo3lIN.js → Debounce.stories-CrWfXhKS.js} +1 -1
  37. package/dist/storybook/assets/{DocsRenderer-LL677BLK-CBVYZYjR.js → DocsRenderer-LL677BLK-9e51z9Xc.js} +3 -3
  38. package/dist/storybook/assets/{Dropdown.stories-15ZDMkRz.js → Dropdown.stories-BsBxV0wp.js} +2 -2
  39. package/dist/storybook/assets/DropdownMenu-B-LvOIGj.js +42 -0
  40. package/dist/storybook/assets/EmptyState-h0A4Qpiu.css +1 -0
  41. package/dist/storybook/assets/{EmptyState.stories-Bjb8hzYj.js → EmptyState.stories-CJ1w8Tp2.js} +33 -21
  42. package/dist/storybook/assets/EscaAvatar.stories-BoLLSj9q.js +140 -0
  43. package/dist/storybook/assets/{Events.stories-BV0vMF2I.js → Events.stories-C3sTBwPJ.js} +2 -2
  44. package/dist/storybook/assets/{Heading.stories-CEUJqUbQ.js → Heading.stories-jmXDRBmM.js} +1 -1
  45. package/dist/storybook/assets/{HueRipple.stories-CwvtcOM_.js → HueRipple.stories-BPx5aSYd.js} +2 -2
  46. package/dist/storybook/assets/Icon-CWyJRQf7.js +34409 -0
  47. package/dist/storybook/assets/{Icon.stories-AB_v-61c.js → Icon.stories-iYBxmv2x.js} +10 -10
  48. package/dist/storybook/assets/IconButton-Di5Rgs7F.js +12 -0
  49. package/dist/storybook/assets/{IconButton.stories-BHuHsM3k.js → IconButton.stories-DENLoxVk.js} +2 -2
  50. package/dist/storybook/assets/LinearProgress-D9ngIVlv.js +25 -0
  51. package/dist/storybook/assets/{LinearProgress.stories-BNN5SXe3.js → LinearProgress.stories-u90B_VJR.js} +2 -2
  52. package/dist/storybook/assets/Message-CM3eexdu.css +1 -0
  53. package/dist/storybook/assets/Message-nFAa55c_.js +28 -0
  54. package/dist/storybook/assets/{Message.stories-DdLhMXnb.js → Message.stories-B4rpz5rI.js} +2 -2
  55. package/dist/storybook/assets/OnFindMixin-oL1bvTFj.js +1 -0
  56. package/dist/storybook/assets/{OnFindMixin.stories-B-5TeBOF.js → OnFindMixin.stories-CdeS5sFA.js} +9 -9
  57. package/dist/storybook/assets/Pagination-CSWcjuDU.js +88 -0
  58. package/dist/storybook/assets/{Pagination.stories-C9zsOdb2.js → Pagination.stories-Da2WzJkv.js} +33 -33
  59. package/dist/storybook/assets/{Popover.stories-BiqIwebU.js → Popover.stories-CVljlVHc.js} +16 -16
  60. package/dist/storybook/assets/ProgressMixin-CeSrn0_P.js +1 -0
  61. package/dist/storybook/assets/Radio-rvfGhZwK.js +25 -0
  62. package/dist/storybook/assets/{Radio.stories-BmrEdPkm.js → Radio.stories-B0wHdJuc.js} +6 -6
  63. package/dist/storybook/assets/{RadioGroup.stories-ChARVXs3.js → RadioGroup.stories-D8krOSlP.js} +22 -22
  64. package/dist/storybook/assets/{ReadyMixin-BbuzH3uO.js → ReadyMixin-CvX_eidU.js} +1 -1
  65. package/dist/storybook/assets/RovingTabindexMixin-9z8lwaM9.js +1 -0
  66. package/dist/storybook/assets/{RovingTabindexMixin.stories-xm4b394_.js → RovingTabindexMixin.stories-Y8vBWjJp.js} +5 -5
  67. package/dist/storybook/assets/{Rtc.stories-DdcMaELA.js → Rtc.stories-D3Y-z8y_.js} +1 -1
  68. package/dist/storybook/assets/{ScrollShadow.stories-CI67Ougx.js → ScrollShadow.stories-1KD0lWHX.js} +1 -1
  69. package/dist/storybook/assets/{Switch.stories-DOqrRkxc.js → Switch.stories-Bsqvm_HE.js} +60 -27
  70. package/dist/storybook/assets/{Tab.stories-DN8o4cf_.js → Tab.stories-CzcTisNs.js} +7 -7
  71. package/dist/storybook/assets/Tabs-DdpYNZSW.js +17 -0
  72. package/dist/storybook/assets/{Tabs.stories-BEowfCcl.js → Tabs.stories-UOS3V0J4.js} +6 -6
  73. package/dist/storybook/assets/{Throttle.stories-BZ_nsuw1.js → Throttle.stories-C8jgzh6e.js} +1 -1
  74. package/dist/storybook/assets/Tooltip.stories-B5BoI0cH.js +143 -0
  75. package/dist/storybook/assets/TooltipMixin-CVKslCDt.js +1 -0
  76. package/dist/storybook/assets/{Upload.stories-sAEiabwq.js → Upload.stories-BsQDCDqo.js} +102 -52
  77. package/dist/storybook/assets/UploadItem-CYQqNwUF.js +54 -0
  78. package/dist/storybook/assets/{UploadItem.stories-C19JMfmB.js → UploadItem.stories-_le7XBTV.js} +4 -4
  79. package/dist/storybook/assets/{Welcome.stories-C30jg0r1.js → Welcome.stories-rramKkhd.js} +38 -8
  80. package/dist/storybook/assets/Widget-elBzGg8w.css +1 -0
  81. package/dist/storybook/assets/Widget.stories-DtbAaklk.js +279 -0
  82. package/dist/storybook/assets/{WithTooltip-65CFNBJE-PFRy5maL.js → WithTooltip-65CFNBJE-DK6GcBuR.js} +1 -1
  83. package/dist/storybook/assets/ai-sparkle-BZMJJAxY.js +1 -0
  84. package/dist/storybook/assets/aria-D5THOgos.js +1 -0
  85. package/dist/storybook/assets/{blocks-DLjjvsFT.js → blocks-DHnzPh43.js} +5 -5
  86. package/dist/storybook/assets/esca-glow-BwdhBvIX.js +2 -0
  87. package/dist/storybook/assets/esca-idle-B-fumiIb.js +1 -0
  88. package/dist/storybook/assets/esca-search-rwNfo19I.js +1 -0
  89. package/dist/storybook/assets/esca-task-complete-BAJP2dY2.js +1 -0
  90. package/dist/storybook/assets/esca-wave-Bjs4CUR7.js +1 -0
  91. package/dist/storybook/assets/{formatter-EIJCOSYU-D39uscG_.js → formatter-EIJCOSYU-qig-qWlG.js} +1 -1
  92. package/dist/storybook/assets/i18n-BQ-Uj-0B.js +1 -0
  93. package/dist/storybook/assets/if-defined-DerKRcyC.js +1 -0
  94. package/dist/storybook/assets/{iframe-B9buZjP7.js → iframe-DlBK9Drk.js} +24 -24
  95. package/dist/storybook/assets/{index-BdEHup-4.js → index-CItQyB37.js} +1 -1
  96. package/dist/storybook/assets/lottie_svg-C3v6xdng.js +2 -0
  97. package/dist/storybook/assets/{onFind-CGzSFqNN.js → onFind-Ci35eu2y.js} +1 -1
  98. package/dist/storybook/assets/{onFind.stories-Dq71qO14.js → onFind.stories-BmbwWWo1.js} +1 -1
  99. package/dist/storybook/assets/{onRemove.stories-B1GqLH_U.js → onRemove.stories-DFWCIgE4.js} +1 -1
  100. package/dist/storybook/assets/{onVisible.stories-BNKxOfLw.js → onVisible.stories-B-onpgE-.js} +1 -1
  101. package/dist/storybook/assets/property-Bmq4RTSP.js +1 -0
  102. package/dist/storybook/assets/ref-BhKk4SDh.js +1 -0
  103. package/dist/storybook/assets/state-DVIUS0Gf.js +1 -0
  104. package/dist/storybook/assets/{style-map-qCiIYcp5.js → style-map-DE4G47KD.js} +1 -1
  105. package/dist/storybook/assets/{syntaxhighlighter-ED5Y7EFY-CUM-CaRF.js → syntaxhighlighter-ED5Y7EFY-Dfgnal1d.js} +1 -1
  106. package/dist/storybook/custom-elements.json +11835 -0
  107. package/dist/storybook/docs/components/ActionBar.md +55 -0
  108. package/dist/storybook/docs/components/ActionItem.md +50 -0
  109. package/dist/storybook/docs/components/AiSparkle.md +33 -0
  110. package/dist/storybook/docs/components/Avatar.md +45 -0
  111. package/dist/storybook/docs/components/AvatarGroup.md +34 -0
  112. package/dist/storybook/docs/components/Badge.md +47 -0
  113. package/dist/storybook/docs/components/Banner.md +35 -0
  114. package/dist/storybook/docs/components/ButtonGroup.md +65 -0
  115. package/dist/storybook/docs/components/Card.md +67 -0
  116. package/dist/storybook/docs/components/Checkbox.md +49 -0
  117. package/dist/storybook/docs/components/CircularProgress.md +40 -0
  118. package/dist/storybook/docs/components/CopyToClipboard.md +51 -0
  119. package/dist/storybook/docs/components/Dropdown.md +74 -0
  120. package/dist/storybook/docs/components/DropdownItem.md +45 -0
  121. package/dist/storybook/docs/components/DropdownMenu.md +41 -0
  122. package/dist/storybook/docs/components/EmptyState.md +62 -0
  123. package/dist/storybook/docs/components/EscaAvatar.md +40 -0
  124. package/dist/storybook/docs/components/Icon.md +40 -0
  125. package/dist/storybook/docs/components/IconButton.md +36 -0
  126. package/dist/storybook/docs/components/LinearProgress.md +37 -0
  127. package/dist/storybook/docs/components/Message.md +50 -0
  128. package/dist/storybook/docs/components/Pagination.md +70 -0
  129. package/dist/storybook/docs/components/Popover.md +59 -0
  130. package/dist/storybook/docs/components/README.md +48 -0
  131. package/dist/storybook/docs/components/Radio.md +55 -0
  132. package/dist/storybook/docs/components/RadioGroup.md +34 -0
  133. package/dist/storybook/docs/components/Switch.md +48 -0
  134. package/dist/storybook/docs/components/Tab.md +40 -0
  135. package/dist/storybook/docs/components/Tabs.md +49 -0
  136. package/dist/storybook/docs/components/Upload.md +63 -0
  137. package/dist/storybook/docs/components/UploadItem.md +30 -0
  138. package/dist/storybook/docs/components/Widget.md +88 -0
  139. package/dist/storybook/docs/dari-elements.md +55 -0
  140. package/dist/storybook/iframe.html +1 -1
  141. package/dist/storybook/index.html +29 -2
  142. package/dist/storybook/llms-full.txt +1721 -0
  143. package/dist/storybook/llms.txt +65 -0
  144. package/dist/storybook/project.json +1 -1
  145. package/dist/storybook/robots.txt +7 -0
  146. package/dist/storybook/sb-addons/storybook-3/manager-bundle.js +1 -1
  147. package/dist/storybook/sitemap.xml +90 -0
  148. package/docs/components/ActionBar.md +41 -64
  149. package/docs/components/ActionItem.md +50 -96
  150. package/docs/components/AiSparkle.md +23 -60
  151. package/docs/components/Avatar.md +45 -88
  152. package/docs/components/AvatarGroup.md +24 -44
  153. package/docs/components/Badge.md +34 -62
  154. package/docs/components/Banner.md +25 -39
  155. package/docs/components/ButtonGroup.md +65 -99
  156. package/docs/components/Card.md +67 -83
  157. package/docs/components/Checkbox.md +49 -91
  158. package/docs/components/CircularProgress.md +40 -84
  159. package/docs/components/CopyToClipboard.md +35 -40
  160. package/docs/components/Dropdown.md +74 -120
  161. package/docs/components/DropdownItem.md +45 -81
  162. package/docs/components/DropdownMenu.md +30 -70
  163. package/docs/components/EmptyState.md +45 -62
  164. package/docs/components/EscaAvatar.md +30 -61
  165. package/docs/components/Icon.md +29 -62
  166. package/docs/components/IconButton.md +36 -83
  167. package/docs/components/LinearProgress.md +28 -70
  168. package/docs/components/Message.md +38 -63
  169. package/docs/components/Pagination.md +70 -100
  170. package/docs/components/Popover.md +46 -79
  171. package/docs/components/README.md +34 -40
  172. package/docs/components/Radio.md +55 -105
  173. package/docs/components/RadioGroup.md +26 -55
  174. package/docs/components/Switch.md +48 -84
  175. package/docs/components/Tab.md +30 -70
  176. package/docs/components/Tabs.md +49 -86
  177. package/docs/components/Upload.md +63 -112
  178. package/docs/components/UploadItem.md +22 -53
  179. package/docs/components/Widget.md +66 -67
  180. package/llms.txt +63 -0
  181. package/package.json +9 -6
  182. package/dist/storybook/assets/AiSparkle.stories-BfjT5jrJ.js +0 -72
  183. package/dist/storybook/assets/Avatar.stories-D8lnIZaY.js +0 -213
  184. package/dist/storybook/assets/AvatarGroup.stories-Cz9oVah0.js +0 -225
  185. package/dist/storybook/assets/Button-2ucj5lUP.js +0 -10
  186. package/dist/storybook/assets/Button.stories-ndl1RJd7.js +0 -54
  187. package/dist/storybook/assets/EscaAvatar.stories-Rc2MSzCX.js +0 -139
  188. package/dist/storybook/assets/LucideDynamicLoader-BuoNL33C.js +0 -1
  189. package/dist/storybook/assets/Tooltip.stories-3bar43ZN.js +0 -143
  190. package/dist/storybook/assets/Widget.stories-9-1XpZNl.js +0 -233
  191. package/dist/storybook/assets/if-defined-BwWBCoAU.js +0 -1
@@ -0,0 +1,55 @@
1
+ # `<btu-radio>`
2
+
3
+ A single radio option, selectable from a set of mutually exclusive choices.
4
+
5
+ Uses a hidden native radio input internally for accessibility and form
6
+ participation. Styled via the `btu-radio` Tailwind plugin classes. Typically
7
+ placed inside a `btu-radio-group`, which owns the shared `name`, selection
8
+ state, and arrow-key navigation; a standalone radio also works but manages
9
+ only its own checked state. The component manages its own `className` — do not
10
+ modify it externally after initialization (classes present at connection time
11
+ are preserved).
12
+
13
+ ```js
14
+ import '@brightspot/ui/components/radio/Radio.js'
15
+ ```
16
+
17
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-radio--docs
18
+
19
+ ## Attributes
20
+
21
+ | Attribute | Property | Type | Default | Description |
22
+ | --- | --- | --- | --- | --- |
23
+ | `label` | `label` | `string \| undefined` | | The text label displayed next to the radio. |
24
+ | `description` | `description` | `string \| undefined` | | Optional helper text displayed below the label. |
25
+ | `size` | `size` | `'sm' \| 'md'` | `'sm'` | Controls the scale of the radio and associated typography. |
26
+ | `checked` | `checked` | `boolean` | `false` | Whether this option is currently selected. |
27
+ | `disabled` | `disabled` | `boolean` | `false` | If true, the radio is non-interactive and visually muted. |
28
+ | `invalid` | `invalid` | `boolean` | `false` | If true, displays error styling on the radio. |
29
+ | `error` | `error` | `string \| undefined` | | Error message text displayed below the radio when validation fails. Setting this also activates error styling without needing to set invalid. |
30
+ | `value` | `value` | `string \| undefined` | | Value submitted with the form when this option is selected. |
31
+ | `name` | `name` | `string \| undefined` | | Name of the form control. Usually set by the parent `btu-radio-group` so every option in the group shares one name. |
32
+ | `tooltip` | `tooltip` | `string` | `''` | Tooltip text content. Set to empty string to remove the tooltip. |
33
+ | `tooltip-position` | `tooltipPosition` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | Position relative to the host element. Auto-flips when constrained by the viewport. |
34
+ | `tooltip-delay` | `tooltipDelay` | `number` | `300` | Show delay in milliseconds (hover trigger only). |
35
+ | `tooltip-offset` | `tooltipOffset` | `'sm' \| 'md' \| 'lg' \| 'xl' \| null` | `null` | Gap between host and tooltip (sm=4px, md=8px, lg=12px, xl=16px). |
36
+ | `tooltip-no-arrow` | `tooltipNoArrow` | `boolean` | `false` | Hide the arrow pseudo-element. |
37
+ | `tooltip-trigger` | `tooltipTrigger` | `string` | `'hover focus'` | Space-separated trigger types: 'hover', 'focus', 'click'. |
38
+
39
+ ## Events
40
+
41
+ | Event | Detail | Description |
42
+ | --- | --- | --- |
43
+ | `btu-radio-ready` | | Fired after the radio is first rendered and initialized |
44
+ | `btu-radio-change` | `{ checked: boolean; value: string }` | Fired when the user selects this option |
45
+
46
+ ## CSS custom properties
47
+
48
+ | Property | Description |
49
+ | --- | --- |
50
+ | `--radio-color-primary` | Fill and border color when selected (default: oklch(var(--btu-theme-primary-700))) |
51
+ | `--radio-color-border` | Border color in the unselected state (default: oklch(var(--btu-theme-gray-300))) |
52
+ | `--radio-color-error` | Border and text color in the error state (default: oklch(var(--btu-theme-error-600))) |
53
+ | `--radio-label-spacing` | Distance between the radio and the label (default: 0.75rem) |
54
+ | `--radio-box-size` | [Internal] Diameter of the radio control, set by the size variant (sm: 1rem, md: 1.25rem). Use the `size` attribute instead of overriding directly — the dot must scale in tandem. |
55
+ | `--radio-dot-size` | [Internal] Diameter of the selected dot, set by the size variant (sm: 0.375rem, md: 0.5rem). Use the `size` attribute instead of overriding directly. |
@@ -0,0 +1,34 @@
1
+ # `<btu-radio-group>`
2
+
3
+ A container that groups `btu-radio` options into a single-select control.
4
+
5
+ Owns the shared form `name`, the selected `value`, and keyboard navigation
6
+ following the WAI-ARIA radio group pattern: a single roving tabstop, and
7
+ arrow keys that move focus and select in one step. Selection state and the
8
+ `disabled` / `size` properties are propagated down to child radios.
9
+
10
+ ```js
11
+ import '@brightspot/ui/components/radio/RadioGroup.js'
12
+ ```
13
+
14
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-radio-group--docs
15
+
16
+ ## Attributes
17
+
18
+ | Attribute | Property | Type | Default | Description |
19
+ | --- | --- | --- | --- | --- |
20
+ | `name` | `name` | `string \| undefined` | | Form field name shared by every radio in the group. |
21
+ | `value` | `value` | `string \| undefined` | | Value of the currently selected option. |
22
+ | `orientation` | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Layout direction of the options. |
23
+ | `size` | `size` | `'sm' \| 'md'` | `'sm'` | Controls the scale of every radio in the group. |
24
+ | `required` | `required` | `boolean` | `false` | Marks a selection as mandatory for form submission. |
25
+ | `disabled` | `disabled` | `boolean` | `false` | Disables every option in the group. |
26
+
27
+ ## Events
28
+
29
+ | Event | Detail | Description |
30
+ | --- | --- | --- |
31
+ | `btu-radio-group-ready` | | Fired after first render and initialization |
32
+ | `btu-radio-group-change` | `{ value: string }` | Fired when the selected value changes |
33
+ | `btu-radio-ready` | | Fired when a child radio finishes initialization (bubbles from btu-radio) |
34
+ | `btu-radio-change` | `{ checked: boolean; value: string }` | Fired when a child radio is selected (bubbles from btu-radio) |
@@ -0,0 +1,48 @@
1
+ # `<btu-switch>`
2
+
3
+ A toggle switch component for binary on/off states.
4
+
5
+ Uses a hidden checkbox internally for accessibility, styled via the
6
+ `btu-switch` Tailwind plugin classes.
7
+
8
+ ```js
9
+ import '@brightspot/ui/components/switch/Switch.js'
10
+ ```
11
+
12
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-switch--docs
13
+
14
+ ## Attributes
15
+
16
+ | Attribute | Property | Type | Default | Description |
17
+ | --- | --- | --- | --- | --- |
18
+ | `size` | `size` | `'sm' \| 'md' \| 'lg'` | `'sm'` | Controls the physical dimensions of the switch and the associated label typography. |
19
+ | `label` | `label` | `string \| undefined` | | The primary text displayed next to the toggle. |
20
+ | `description` | `description` | `string \| undefined` | | Optional helper text or secondary information displayed below the label. |
21
+ | `checked` | `checked` | `boolean` | `false` | The current state of the switch (on/off). |
22
+ | `disabled` | `disabled` | `boolean` | `false` | If true, the toggle is non-interactive and visually muted. |
23
+ | `name` | `name` | `string \| undefined` | | Name of the control for form participation. |
24
+ | `label-position` | `labelPosition` | `'start' \| 'end'` | `'end'` | Determines if the label appears to the left or right of the switch. |
25
+ | `on-icon` | `onIcon` | `string \| undefined` | | Lucide icon name shown on the track when the switch is checked (on). |
26
+ | `off-icon` | `offIcon` | `string \| undefined` | | Lucide icon name shown on the track when the switch is unchecked (off). |
27
+
28
+ ## Events
29
+
30
+ | Event | Detail | Description |
31
+ | --- | --- | --- |
32
+ | `btu-switch-ready` | | Fired after the toggle is first rendered and initialized |
33
+ | `btu-switch-change` | `{ checked: boolean }` | Fired when the user toggles the switch |
34
+ | `btu-switch-focus` | | Fired when the component gains focus |
35
+
36
+ ## CSS custom properties
37
+
38
+ | Property | Description |
39
+ | --- | --- |
40
+ | `--switch-color-track-on` | Background color when the toggle is checked (default: var(--btu-theme-primary-700)) |
41
+ | `--switch-color-track-off` | Background color when the toggle is unchecked (default: var(--btu-theme-gray-300)) |
42
+ | `--switch-color-knob` | Color of the sliding circular handle (default: var(--btu-theme-white)) |
43
+ | `--switch-label-spacing` | Distance between the switch and the text label (default: 0.75rem) |
44
+ | `--switch-track-width` | Track width (default: sm 1.75rem, md 2.25rem, lg 2.75rem) |
45
+ | `--switch-track-height` | Track height (default: sm 1rem, md 1.25rem, lg 1.5rem) |
46
+ | `--switch-knob-size` | Knob diameter (default: sm 0.75rem, md 1rem, lg 1.25rem) |
47
+ | `--switch-knob-padding` | Space between knob and track edges (default: 0.125rem) |
48
+ | `--switch-track-icon-size` | Size of the track icons (default: sm 0.5rem, md 0.625rem, lg 0.75rem) |
@@ -0,0 +1,40 @@
1
+ # `<btu-tab>`
2
+
3
+ An individual tab within a tab group.
4
+
5
+ Renders a button with role="tab" that participates in keyboard navigation
6
+ and selection state managed by the parent `btu-tabs` container.
7
+
8
+ ```js
9
+ import '@brightspot/ui/components/tabs/Tab.js'
10
+ ```
11
+
12
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-tabs-tab--docs
13
+
14
+ ## Attributes
15
+
16
+ | Attribute | Property | Type | Default | Description |
17
+ | --- | --- | --- | --- | --- |
18
+ | `name` | `name` | `string \| undefined` | | Value that identifies this tab and links it to panel elements that share the same `name` attribute. |
19
+ | `label` | `label` | `string \| undefined` | | Text displayed in the tab. |
20
+ | `description` | `description` | `string \| undefined` | | Accessibility description for screen readers. |
21
+ | `disabled` | `disabled` | `boolean` | `false` | Whether the tab is disabled and non-interactive. |
22
+ | `symbol` | `symbol` | `string \| undefined` | | Lucide icon symbol to display. |
23
+ | `icon-position` | `iconPosition` | `'leading' \| 'trailing'` | `'leading'` | Placement of the icon relative to the label. |
24
+ | `icon-only` | `iconOnly` | `boolean` | `false` | When true, hides the label visually while maintaining accessibility. |
25
+ | `error` | `error` | `boolean` | `false` | When true, displays an error badge on the tab. |
26
+ | `badge` | `badge` | `string \| undefined` | | Displays a badge with the given value alongside the label. |
27
+
28
+ ## Events
29
+
30
+ | Event | Detail | Description |
31
+ | --- | --- | --- |
32
+ | `btu-tab-ready` | | Fired after first render |
33
+ | `btu-tab-change` | `{name: string}` | Fired when a non-disabled tab with a name is clicked |
34
+
35
+ ## CSS custom properties
36
+
37
+ | Property | Description |
38
+ | --- | --- |
39
+ | `--badge-color-background` | Background color of the count indicator badge (default: gray-50) |
40
+ | `--badge-color-foreground` | Text color of the count indicator badge (default: gray-800) |
@@ -0,0 +1,49 @@
1
+ # `<btu-tabs>`
2
+
3
+ A container component for managing a group of tabs.
4
+
5
+ Provides selection state management, size propagation to child tabs,
6
+ and keyboard navigation following the WAI-ARIA Tabs pattern.
7
+
8
+ When a tab becomes active, direct sibling elements that share the same
9
+ `name` value are shown; other siblings with a `name` attribute are
10
+ hidden. Only direct siblings are managed — nested tab groups control their
11
+ own panels independently.
12
+
13
+ ```js
14
+ import '@brightspot/ui/components/tabs/Tabs.js'
15
+ ```
16
+
17
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-tabs--docs
18
+
19
+ ## Attributes
20
+
21
+ | Attribute | Property | Type | Default | Description |
22
+ | --- | --- | --- | --- | --- |
23
+ | `size` | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Size variant applied to all child tabs. |
24
+ | `active-tab` | `activeTab` | `string \| undefined` | | The `name` value of the currently active tab. |
25
+ | `variant` | `variant` | `'full' \| 'menu'` | `'full'` | Layout variant. - 'full': tabs scroll horizontally when they overflow (default) - 'menu': all tabs are hidden; the active tab label and a chevron dropdown are shown instead |
26
+
27
+ ## Events
28
+
29
+ | Event | Detail | Description |
30
+ | --- | --- | --- |
31
+ | `btu-tabs-ready` | | Fired after first render and initialization |
32
+ | `btu-tabs-show` | `{name: string}` | Fired when a tab becomes active |
33
+ | `btu-tabs-hide` | `{name: string}` | Fired when a tab is deactivated |
34
+ | `btu-tab-change` | `{name: string}` | Fired when a tab is selected (bubbles from btu-tab) |
35
+ | `btu-tab-ready` | | Fired when a child tab finishes initialization (bubbles from btu-tab) |
36
+
37
+ ## CSS custom properties
38
+
39
+ | Property | Description |
40
+ | --- | --- |
41
+ | `--tabs-active-color` | Text and icon color of the active tab (default: gray-700) |
42
+ | `--tabs-active-indicator-color` | Color of the active tab underline indicator (default: primary-500 → primary-700 → primary-900 gradient) |
43
+ | `--tabs-border-color` | Color of the bottom border divider (default: gray-200) |
44
+ | `--tabs-color` | Text and icon color for all tabs (default: gray-500; active/hover tabs use gray-700) |
45
+ | `--tabs-background` | Background color for all tab buttons (default: transparent) |
46
+ | `--tabs-container-background` | Background color of the tabs container (default: theme white) |
47
+ | `--tabs-hover-background` | Background color of a tab on hover (default: gray-100) |
48
+ | `--tabs-hover-color` | Text and icon color of a tab on hover (default: gray-700) |
49
+ | `--tabs-gap` | Spacing between tabs (default: 1rem) |
@@ -0,0 +1,63 @@
1
+ # `<btu-upload>`
2
+
3
+ A file upload component with drop zone and file list.
4
+
5
+ The component is presentation + file-selection only. It handles file browsing,
6
+ drag-and-drop reception, client-side validation, and rendering the file list
7
+ with progress bars. It does not perform network requests — the consumer listens
8
+ for events, performs their own upload, and drives state back via imperative methods.
9
+
10
+ ```js
11
+ import '@brightspot/ui/components/upload/Upload.js'
12
+ ```
13
+
14
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-upload--docs
15
+
16
+ ## Attributes
17
+
18
+ | Attribute | Property | Type | Default | Description |
19
+ | --- | --- | --- | --- | --- |
20
+ | `accept` | `accept` | `string` | `''` | Accepted file types, matching the HTML `<input accept>` attribute format. Client-side filter only — the browser's file picker uses this as a hint, and drag-drop is enforced by this component. Server-side validation is still required. Supported forms (comma-separated, any combination): - `image/*` — MIME wildcard (any image) - `application/pdf` — exact MIME type - `.pdf`, `.docx` — file extension (case-insensitive) Examples: - `accept="image/*"` — any image - `accept="image/*,application/pdf"` — images and PDFs - `accept=".jpg,.jpeg,.png,.heic"` — specific extensions - `accept=""` (or omitted) — allow all Note: users can bypass the file picker's filter (most browsers offer an "All Files" option), so this attribute is a UX filter, not a security boundary. |
21
+ | `max-file-size` | `maxFileSize` | `number` | `0` | Maximum file size in bytes. Files exceeding this are rejected. 0 means unlimited. |
22
+ | `max-files` | `maxFiles` | `number` | `Infinity` | Maximum number of files allowed. When omitted, uploads are unlimited. `max-files="1"` enters single-file mode (selecting a new file replaces the existing one). `max-files="0"` allows zero files. Values above 1 cap the queue at that many files. |
23
+ | `disabled` | `disabled` | `boolean` | `false` | Disables all interaction — file selection, drag-and-drop, and action buttons. |
24
+ | `no-drag` | `noDrag` | `boolean` | `false` | Disables drag-and-drop. File selection via click still works. |
25
+
26
+ ## Methods
27
+
28
+ | Method | Description |
29
+ | --- | --- |
30
+ | `setFileProgress(id: string, percent: number): void` | Update the progress of a file upload. Clamps value to 0-100 and coerces non-finite inputs to 0. Announces milestones (25%, 50%, 75%) to screen readers; 100% completion is announced by setFileStatus('complete'). Status transitions: - `pending` → `uploading` (auto — first progress report starts the upload) - `uploading` → `uploading` (progress updates) - `error` → `error` (progress updates only; status is preserved so a stale late callback can't wipe the error UI. To recover from error, call `setFileStatus(id, 'uploading')` first, then report progress.) - `complete` → ignored (terminal state) |
31
+ | `setFileStatus(id: string, status: FileStatusSettable, message?: string): void` | Set the status of a file. Valid statuses: 'uploading', 'complete', 'error'. For 'error' status, an optional message can be provided. Transitions from 'complete' are rejected (terminal state) — a late-resolving XHR cannot overwrite a prior success. Rejected calls emit `btu-upload-api-error` with reason: 'invalid-transition'. |
32
+ | `setFileSymbol(id: string, symbol: string): void` | Override the icon symbol for a file. |
33
+ | `removeFile(id: string): void` | Remove a file programmatically. Fires `btu-upload-file-removed`. |
34
+ | `getFiles(): readonly FileState[]` | Get a snapshot of all current files and their states. States are readonly; mutations on the returned array's elements are ineffective. |
35
+
36
+ ## Events
37
+
38
+ | Event | Detail | Description |
39
+ | --- | --- | --- |
40
+ | `btu-upload-ready` | `unknown` | Fired when the component has completed first render |
41
+ | `btu-upload-file-added` | `{id: string, file: File}` | Fired when a file passes validation and is added |
42
+ | `btu-upload-file-removed` | `{id: string, file: File}` | Fired when a file is removed (user action, programmatic, or on disconnect for in-flight uploads) |
43
+ | `btu-upload-file-retry` | `{id: string, file: File}` | Fired when user clicks "Try again" on a failed upload |
44
+ | `btu-upload-file-rejected` | `{file: File, reason: 'type' \| 'size' \| 'count'}` | Fired when a file fails client-side validation or the queue is full |
45
+ | `btu-upload-file-completed` | `{id: string, file: File}` | Fired when a file's status transitions into 'complete' |
46
+ | `btu-upload-api-error` | `{method: string, id: string, reason: 'unknown-id' \| 'invalid-transition', message: string}` | Fired when an imperative API call references an unknown id or an illegal status transition |
47
+
48
+ ## CSS custom properties
49
+
50
+ | Property | Description |
51
+ | --- | --- |
52
+ | `--upload-dropzone-bg` | Drop zone background color (default: gray-25) |
53
+ | `--upload-dropzone-border-color` | Drop zone border color (default: gray-300; gray-200 when disabled, gray-400 in high-contrast) |
54
+ | `--upload-dropzone-border-radius` | Drop zone border radius (default: borderRadius.lg) |
55
+ | `--upload-dropzone-hover-bg` | Drop zone hover background (hover default: gray-50; drag-over default: primary-25) |
56
+ | `--upload-dropzone-hover-border-color` | Drop zone hover/focus border color (default: primary-300; drag-over uses primary-400) |
57
+ | `--upload-dropzone-focus-ring-color` | Drop zone focus ring color (default: primary-100) |
58
+ | `--upload-item-bg` | Item background color (default: white) |
59
+ | `--upload-item-border-color` | Item border color (default: gray-200) |
60
+ | `--upload-item-active-border-color` | Item active/in-progress border (default: gray-300) |
61
+ | `--upload-item-complete-border-color` | Item completed border color (default: primary-500) |
62
+ | `--upload-item-error-bg` | Item error background (default: error-25) |
63
+ | `--upload-item-error-border-color` | Item error border color (default: error-300) |
@@ -0,0 +1,30 @@
1
+ # `<btu-upload-item>`
2
+
3
+ Internal upload item sub-component for displaying individual file upload state.
4
+
5
+ This component is not part of the public API — consumers should not create,
6
+ query, or modify items directly. All interaction goes through `btu-upload` methods.
7
+
8
+ ```js
9
+ import '@brightspot/ui/components/upload/UploadItem.js'
10
+ ```
11
+
12
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-upload-upload-item--docs
13
+
14
+ ## Events
15
+
16
+ | Event | Detail | Description |
17
+ | --- | --- | --- |
18
+ | `btu-upload-item-remove` | `{id: string}` | Fired when remove button is clicked |
19
+ | `btu-upload-item-retry` | `{id: string}` | Fired when retry link is clicked |
20
+
21
+ ## CSS custom properties
22
+
23
+ | Property | Description |
24
+ | --- | --- |
25
+ | `--upload-item-bg` | Item background color (default: white) |
26
+ | `--upload-item-border-color` | Item border color (default: gray-200) |
27
+ | `--upload-item-active-border-color` | Item active/in-progress border (default: gray-300) |
28
+ | `--upload-item-complete-border-color` | Item completed border color (default: primary-500) |
29
+ | `--upload-item-error-bg` | Item error background (default: error-25) |
30
+ | `--upload-item-error-border-color` | Item error border color (default: error-300) |
@@ -0,0 +1,88 @@
1
+ # `<btu-widget>`
2
+
3
+ A widget component for displaying content with header, body, and footer sections.
4
+
5
+ ## Architecture: Light DOM + Manager Pattern
6
+
7
+ This component uses **Light DOM** (no Shadow Root) with the **Manager Pattern**:
8
+ - User-provided children are physically moved into internal containers
9
+ - Movement is based on `slot` attributes (pseudo-slots)
10
+ - The `onFind` utility automatically redistributes dynamically-added content
11
+
12
+ ### Node Redistribution Rules
13
+ - `slot="controls"` → Moved to header actions area (before system buttons)
14
+ - `slot="footer"` → Moved to footer container
15
+ - *(no slot)* → Moved to body container (default)
16
+
17
+ ## Features
18
+
19
+ - **Collapsible**: Optional chevron toggle to hide/show body and footer
20
+ - **Fullscreen**: Optional maximize button for fullscreen mode via `:state(fullscreen)` custom state
21
+ - **Dynamic Content**: `onFind` handles content added after initialization
22
+ - **Accessible**: Full ARIA support and keyboard navigation
23
+ - **Themeable**: CSS custom properties for colors and spacing
24
+
25
+ ## Accessibility
26
+
27
+ - **Collapse toggle**: `aria-expanded`, `aria-controls`, `aria-label`
28
+ - **Fullscreen toggle**: `aria-pressed`, `aria-label`
29
+ - **Body region**: `role="region"`, `aria-labelledby` linking to heading
30
+ - **Tab order**: Natural flow via physical DOM placement
31
+ - **Collapsed content**: Hidden via `inert` attribute and CSS grid collapse
32
+
33
+ ```js
34
+ import '@brightspot/ui/components/widget/Widget.js'
35
+ ```
36
+
37
+ The CMS page defines this element itself, so a plugin can use it there without the import.
38
+
39
+ Interactive examples: https://ui.brightspot.com/?path=/docs/components-widget--docs
40
+
41
+ ## Attributes
42
+
43
+ | Attribute | Property | Type | Default | Description |
44
+ | --- | --- | --- | --- | --- |
45
+ | `heading` | `heading` | `string` | `''` | Heading text displayed in the header. |
46
+ | `collapsible` | `collapsible` | `boolean` | `false` | Whether the widget can be collapsed/expanded. When true, a chevron toggle button appears in the header. |
47
+ | `collapsed` | `collapsed` | `boolean` | `false` | Whether the widget is currently collapsed. When true, body and footer are hidden. Implies collapsible. |
48
+ | `fullscreenable` | `fullscreenable` | `boolean` | `false` | Whether the widget can enter fullscreen mode. When true, a fullscreen toggle button appears in the header. |
49
+
50
+ ## Properties
51
+
52
+ These have no attribute; set them from JavaScript.
53
+
54
+ | Property | Type | Default | Description |
55
+ | --- | --- | --- | --- |
56
+ | `isFullscreen` (read-only) | `boolean` | | Whether the widget is currently in fullscreen mode (read-only). Use `btu-widget-fullscreen-changed` event to react to changes. |
57
+
58
+ ## Events
59
+
60
+ | Event | Detail | Description |
61
+ | --- | --- | --- |
62
+ | `btu-widget-ready` | | Fired after first render and redistribution |
63
+ | `btu-widget-collapse-changed` | `{collapsed: boolean}` | Fired when collapsed state changes |
64
+ | `btu-widget-fullscreen-changed` | `{fullscreen: boolean}` | Fired when fullscreen state changes |
65
+
66
+ ## Slots
67
+
68
+ | Slot | Description |
69
+ | --- | --- |
70
+ | (default) | Default pseudo-slot: elements without slot attribute are moved to body |
71
+ | `controls` | Pseudo-slot: buttons/actions moved to header actions area |
72
+ | `footer` | Pseudo-slot: content moved to footer container |
73
+
74
+ ## CSS custom properties
75
+
76
+ | Property | Description |
77
+ | --- | --- |
78
+ | `--widget-background` | Body and footer background color (default: --btu-theme-white) |
79
+ | `--widget-border` | Widget border and dividers (default: 1px solid gray-200) |
80
+ | `--widget-border-color` | Color of header bottom divider (default: gray-200) |
81
+ | `--header-background` | Header background color (default: transparent) |
82
+
83
+ ## CSS states
84
+
85
+ | State | Description |
86
+ | --- | --- |
87
+ | `:state(collapsed)` | Applied when the widget is collapsed, targetable via :state(collapsed) |
88
+ | `:state(fullscreen)` | Applied when the widget is in fullscreen mode, targetable via :state(fullscreen) |
@@ -0,0 +1,55 @@
1
+ # Dari HTML elements
2
+
3
+ `com.brightspot.ui.dari` contains generated Java classes for the `btu-*` web components, one class per element,
4
+ so Java code in Brightspot and in plugins can render them with typed attribute setters instead of raw HTML strings.
5
+ The classes are generated from the same [Custom Elements Manifest](components/README.md) used for the component API
6
+ reference, and compile into the `com.brightspot.ui:ui` jar.
7
+
8
+ The `BrightspotUi` interface holds one constant per element, named from its tag—for example `BrightspotUi#BADGE`
9
+ for `<btu-badge>`. Each constant is an instance of the generated class, so chaining an element's own setters with
10
+ inherited ones (`classList`, `attr`, `with`, and the rest of `com.psddev.dari.html`) compiles in any order:
11
+
12
+ ```java
13
+ import static com.brightspot.ui.dari.BrightspotUi.BADGE;
14
+
15
+ BADGE.classList("Page-env").variant("success").dot(true).with("QA")
16
+ // <btu-badge class="Page-env" variant="success" dot>QA</btu-badge>
17
+ ```
18
+
19
+ Rendering a constant emits only the tag—the page must also load the component, or the element stays inert. On a
20
+ CMS page, import it in the plugin's front-end entry, the same as for any other element not defined by the CMS. See
21
+ [Using these in a plugin](components/README.md#using-these-in-a-plugin) for which elements the CMS already defines.
22
+
23
+ Nest content, including other elements, with `with`:
24
+
25
+ ```java
26
+ import static com.brightspot.ui.dari.BrightspotUi.CARD;
27
+ import static com.brightspot.ui.dari.BrightspotUi.BADGE;
28
+
29
+ CARD.heading("Release notes").headingLevel(3).with(BADGE.with("New"))
30
+ // <btu-card heading="Release notes" heading-level="3"><btu-badge>New</btu-badge></btu-card>
31
+ ```
32
+
33
+ ## Setter types
34
+
35
+ Each generated setter's parameter type follows the element's CEM attribute type:
36
+
37
+ | CEM type | Java parameter | Behavior |
38
+ |---|---|---|
39
+ | `boolean` | `boolean` | Emits a bare attribute (for example `dot`) when `true`, omits it when `false`. |
40
+ | `number` | `Number` | Emits the attribute set to the number's string form. |
41
+ | anything else, including unions like `boolean \| 'pulse'` | `String` | Emits the attribute set to the string value. |
42
+
43
+ A handful of boolean attributes default to `true` in the component itself, such as `indeterminate` on
44
+ `<btu-circular-progress>`. Because an HTML boolean attribute can only be present or absent, calling the setter with
45
+ `false` has no effect—there is no way to represent "explicitly false" in the markup, so the component falls back to
46
+ its own default.
47
+
48
+ ## Icon, widget, and copy-to-clipboard
49
+
50
+ `ICON`, `WIDGET`, and `COPY_TO_CLIPBOARD` render the library elements, which the CMS defines. For a gradient icon, use
51
+ `ICON.gradient("primary")`—the library icon has no `fill` attribute.
52
+
53
+ `com.psddev.cms.ui.Components` also has `ICON` and `WIDGET` constants. A class that statically imports both
54
+ `Components.*` and `BrightspotUi.*` gets an ambiguous-name compile error, so import `BrightspotUi` constants by name,
55
+ as in the examples above.
@@ -613,7 +613,7 @@
613
613
  }
614
614
  </style>
615
615
 
616
- <script type="module" crossorigin src="./assets/iframe-B9buZjP7.js"></script>
616
+ <script type="module" crossorigin src="./assets/iframe-DlBK9Drk.js"></script>
617
617
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-PPVm8Dsz.js">
618
618
  <link rel="stylesheet" crossorigin href="./assets/iframe-BzrT7trF.css">
619
619
  </head>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
 
6
- <title>storybook - Storybook</title>
6
+ <title>Brightspot UI components - Storybook</title>
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1" />
8
8
 
9
9
 
@@ -53,7 +53,22 @@
53
53
  <link href="./sb-addons/vitest-2/manager-bundle.js" rel="modulepreload" />
54
54
 
55
55
  <link href="./sb-addons/storybook-3/manager-bundle.js" rel="modulepreload" />
56
- <link rel="icon" type="image/svg+xml" href="./BSPLogoMark.svg" />
56
+ <!--
57
+ Keep these above the no-JS paragraph: anything after it lands in <body>.
58
+ No og:url or canonical, because every page shares this one HTML file.
59
+ -->
60
+ <meta
61
+ name="description"
62
+ content="Web components, a Tailwind CSS preset and design tokens for Brightspot CMS screens and plugins, with live examples."
63
+ />
64
+ <meta property="og:type" content="website" />
65
+ <meta property="og:site_name" content="Brightspot UI" />
66
+ <meta property="og:title" content="Brightspot UI components" />
67
+ <meta
68
+ property="og:description"
69
+ content="Web components, a Tailwind CSS preset and design tokens for Brightspot CMS screens and plugins, with live examples."
70
+ />
71
+ <link rel="icon" type="image/svg+xml" href="./BSPLogoMark.svg" />
57
72
  <style>
58
73
  /* Must match brandImage in theme.ts. */
59
74
  img[src='./brightspot-logo.svg'] {
@@ -91,6 +106,18 @@
91
106
  }
92
107
  }
93
108
  </style>
109
+ <link rel="describedby" href="./llms.txt" type="text/markdown" />
110
+ <!--
111
+ Shown only without JavaScript, which is also how agents fetch the page. A paragraph survives their HTML-to-markdown
112
+ conversion (the parser moves it into <body>), where meta tags and <noscript> don't.
113
+ -->
114
+ <p id="no-js">
115
+ This site needs JavaScript. The component docs are also available as markdown:
116
+ <a href="./llms.txt">https://ui.brightspot.com/llms.txt</a>
117
+ </p>
118
+ <script>
119
+ document.getElementById('no-js').remove()
120
+ </script>
94
121
 
95
122
 
96
123
  <style>