@kenlo/sds-design-system 0.9.9

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 (246) hide show
  1. package/README.md +129 -0
  2. package/components/Accordion/Accordion.css +186 -0
  3. package/components/Accordion/accordion-variants.js +17 -0
  4. package/components/Accordion/accordion.marko +264 -0
  5. package/components/AccordionGroup/AccordionGroup.css +35 -0
  6. package/components/AccordionGroup/accordion-group.marko +17 -0
  7. package/components/Alert/Alert.css +104 -0
  8. package/components/Alert/alert-variants.js +35 -0
  9. package/components/Alert/alert.marko +94 -0
  10. package/components/AttachmentList/AttachmentList.css +92 -0
  11. package/components/AttachmentList/attachment-list.marko +51 -0
  12. package/components/AttachmentList/attachment-row.marko +167 -0
  13. package/components/Avatar/Avatar.css +110 -0
  14. package/components/Avatar/avatar-variants.js +12 -0
  15. package/components/Avatar/avatar.marko +71 -0
  16. package/components/Badge/Badge.css +381 -0
  17. package/components/Badge/badge-dismissible.marko +143 -0
  18. package/components/Badge/badge-variants.js +35 -0
  19. package/components/Badge/badge.marko +134 -0
  20. package/components/BottomSheet/BottomSheet.css +300 -0
  21. package/components/BottomSheet/bottom-sheet.marko +340 -0
  22. package/components/BulkActionBar/BulkActionBar.css +88 -0
  23. package/components/BulkActionBar/bulk-action-bar.marko +186 -0
  24. package/components/Button/Button.css +340 -0
  25. package/components/Button/button-variants.js +25 -0
  26. package/components/Button/button.marko +139 -0
  27. package/components/Card/Card.css +391 -0
  28. package/components/Card/card-body.marko +5 -0
  29. package/components/Card/card-collapsible.marko +94 -0
  30. package/components/Card/card-footer.marko +12 -0
  31. package/components/Card/card-header.marko +30 -0
  32. package/components/Card/card-info-pair.marko +17 -0
  33. package/components/Card/card-info-row.marko +12 -0
  34. package/components/Card/card-section.marko +14 -0
  35. package/components/Card/card-variants.js +24 -0
  36. package/components/Card/card.marko +124 -0
  37. package/components/Checkbox/Checkbox.css +249 -0
  38. package/components/Checkbox/checkbox-variants.js +21 -0
  39. package/components/Checkbox/checkbox.marko +128 -0
  40. package/components/ColorPicker/ColorPicker.css +253 -0
  41. package/components/ColorPicker/color-maths.js +104 -0
  42. package/components/ColorPicker/color-picker.marko +474 -0
  43. package/components/DatePicker/DatePicker.css +429 -0
  44. package/components/DatePicker/date-logic.js +225 -0
  45. package/components/DatePicker/date-picker.marko +492 -0
  46. package/components/Drawer/Drawer.css +174 -0
  47. package/components/Drawer/drawer.marko +262 -0
  48. package/components/Floating/Floating.css +28 -0
  49. package/components/Floating/floating-position.js +251 -0
  50. package/components/Floating/floating.marko +291 -0
  51. package/components/Form/Form.css +15 -0
  52. package/components/Form/form-context.js +69 -0
  53. package/components/Form/form.marko +73 -0
  54. package/components/GradientPicker/GradientPicker.css +179 -0
  55. package/components/GradientPicker/gradient-picker.marko +398 -0
  56. package/components/Grid/Grid.css +161 -0
  57. package/components/Grid/col.marko +36 -0
  58. package/components/Grid/grid-variants.js +43 -0
  59. package/components/Grid/grid.marko +25 -0
  60. package/components/Header/Header.css +457 -0
  61. package/components/Header/header.marko +523 -0
  62. package/components/Icon/Icon.css +44 -0
  63. package/components/Icon/icon-colors.js +31 -0
  64. package/components/Icon/icon.marko +56 -0
  65. package/components/IconButton/IconButton.css +85 -0
  66. package/components/IconButton/icon-button-variants.js +18 -0
  67. package/components/IconButton/icon-button.marko +103 -0
  68. package/components/Incrementer/Incrementer.css +94 -0
  69. package/components/Incrementer/incrementer.marko +70 -0
  70. package/components/Input/Input.css +547 -0
  71. package/components/Input/input-countries.js +109 -0
  72. package/components/Input/input-masks.js +218 -0
  73. package/components/Input/input-types.js +194 -0
  74. package/components/Input/input.marko +530 -0
  75. package/components/Menu/Menu.css +651 -0
  76. package/components/Menu/menu-variants.js +89 -0
  77. package/components/Menu/menu.marko +560 -0
  78. package/components/Modal/Modal.css +160 -0
  79. package/components/Modal/modal.marko +296 -0
  80. package/components/Nav/Nav.css +298 -0
  81. package/components/Nav/nav-variants.js +23 -0
  82. package/components/Nav/nav.marko +164 -0
  83. package/components/Notification/Notification.css +78 -0
  84. package/components/Notification/notification-variants.js +30 -0
  85. package/components/Notification/notification.marko +55 -0
  86. package/components/Pagination/Pagination.css +78 -0
  87. package/components/Pagination/pagination-pages.js +66 -0
  88. package/components/Pagination/pagination.marko +141 -0
  89. package/components/Pill/Pill.css +193 -0
  90. package/components/Pill/pill-variants.js +16 -0
  91. package/components/Pill/pill.marko +165 -0
  92. package/components/Popover/Popover.css +121 -0
  93. package/components/Popover/popover.marko +96 -0
  94. package/components/Radio/Radio.css +230 -0
  95. package/components/Radio/radio-variants.js +16 -0
  96. package/components/Radio/radio.marko +93 -0
  97. package/components/RadioGroup/RadioGroup.css +32 -0
  98. package/components/RadioGroup/radio-group.marko +93 -0
  99. package/components/SearchBar/SearchBar.css +181 -0
  100. package/components/SearchBar/search-bar-variants.js +24 -0
  101. package/components/SearchBar/search-bar.marko +157 -0
  102. package/components/Select/Select.css +427 -0
  103. package/components/Select/select-options.js +163 -0
  104. package/components/Select/select.marko +449 -0
  105. package/components/Separator/Separator.css +22 -0
  106. package/components/Separator/separator.marko +14 -0
  107. package/components/Skeleton/Skeleton.css +100 -0
  108. package/components/Skeleton/skeleton-avatar.marko +28 -0
  109. package/components/Skeleton/skeleton-button.marko +22 -0
  110. package/components/Skeleton/skeleton-image.marko +20 -0
  111. package/components/Skeleton/skeleton-input.marko +22 -0
  112. package/components/Skeleton/skeleton-variants.js +16 -0
  113. package/components/Skeleton/skeleton.marko +53 -0
  114. package/components/Spinner/Spinner.css +173 -0
  115. package/components/Spinner/spinner-geometry.js +39 -0
  116. package/components/Spinner/spinner-overlay.marko +97 -0
  117. package/components/Spinner/spinner.marko +88 -0
  118. package/components/StatCard/StatCard.css +90 -0
  119. package/components/StatCard/stat-card-group.marko +5 -0
  120. package/components/StatCard/stat-card.marko +57 -0
  121. package/components/Switch/Switch.css +209 -0
  122. package/components/Switch/switch.marko +99 -0
  123. package/components/Table/Table.css +270 -0
  124. package/components/Table/table-cell.marko +28 -0
  125. package/components/Table/table-header.marko +27 -0
  126. package/components/Table/table-logic.js +129 -0
  127. package/components/Table/table.marko +372 -0
  128. package/components/Text/Text.css +79 -0
  129. package/components/Text/text-variants.js +25 -0
  130. package/components/Text/text.marko +48 -0
  131. package/components/TextEditor/TextEditor.css +78 -0
  132. package/components/TextEditor/safe-url.js +50 -0
  133. package/components/TextEditor/text-editor-commands.js +22 -0
  134. package/components/TextEditor/text-editor.marko +253 -0
  135. package/components/Toast/Toast.css +88 -0
  136. package/components/Toast/toast-api.js +19 -0
  137. package/components/Toast/toast-store.js +118 -0
  138. package/components/Toast/toast-variants.js +16 -0
  139. package/components/Toast/toast.marko +93 -0
  140. package/components/Toast/toaster.marko +70 -0
  141. package/components/Toggle/Toggle.css +169 -0
  142. package/components/Toggle/toggle.marko +93 -0
  143. package/components/Tooltip/Tooltip.css +115 -0
  144. package/components/Tooltip/tooltip.marko +77 -0
  145. package/components/Uploader/Uploader.css +180 -0
  146. package/components/Uploader/crop-geometry.js +161 -0
  147. package/components/Uploader/uploader.marko +269 -0
  148. package/foundations/Scrollbar/Scrollbar.css +26 -0
  149. package/foundations/attrs.js +27 -0
  150. package/foundations/breakpoints.js +27 -0
  151. package/foundations/contrast.js +74 -0
  152. package/foundations/custom-scheme.js +222 -0
  153. package/foundations/overlay.js +108 -0
  154. package/foundations/styles.css +284 -0
  155. package/foundations/text.js +22 -0
  156. package/foundations/theme-server.js +81 -0
  157. package/foundations/theme.js +42 -0
  158. package/foundations/tokens.css +1656 -0
  159. package/icons/custom/custom-video-horizontal-filled.marko +6 -0
  160. package/icons/custom/custom-video-horizontal-regular.marko +6 -0
  161. package/icons/custom/custom-video-tour-3d-filled.marko +7 -0
  162. package/icons/custom/custom-video-tour-3d-regular.marko +9 -0
  163. package/icons/custom/custom-video-vertical-filled.marko +6 -0
  164. package/icons/custom/custom-video-vertical-regular.marko +6 -0
  165. package/icons/generated/fluent-add-regular.marko +3 -0
  166. package/icons/generated/fluent-alert-regular.marko +3 -0
  167. package/icons/generated/fluent-apps-regular.marko +3 -0
  168. package/icons/generated/fluent-arrow-download-regular.marko +3 -0
  169. package/icons/generated/fluent-arrow-left-regular.marko +3 -0
  170. package/icons/generated/fluent-arrow-right-regular.marko +3 -0
  171. package/icons/generated/fluent-arrow-rotate-clockwise-regular.marko +3 -0
  172. package/icons/generated/fluent-arrow-rotate-counterclockwise-regular.marko +3 -0
  173. package/icons/generated/fluent-border-all-regular.marko +3 -0
  174. package/icons/generated/fluent-calendar-regular.marko +3 -0
  175. package/icons/generated/fluent-checkmark-circle-filled.marko +3 -0
  176. package/icons/generated/fluent-checkmark-regular.marko +3 -0
  177. package/icons/generated/fluent-chevron-down-regular.marko +3 -0
  178. package/icons/generated/fluent-chevron-left-regular.marko +3 -0
  179. package/icons/generated/fluent-chevron-right-regular.marko +3 -0
  180. package/icons/generated/fluent-chevron-up-regular.marko +3 -0
  181. package/icons/generated/fluent-circle-half-fill-regular.marko +3 -0
  182. package/icons/generated/fluent-clock-regular.marko +3 -0
  183. package/icons/generated/fluent-color-regular.marko +3 -0
  184. package/icons/generated/fluent-crop-regular.marko +3 -0
  185. package/icons/generated/fluent-dark-theme-regular.marko +3 -0
  186. package/icons/generated/fluent-delete-regular.marko +3 -0
  187. package/icons/generated/fluent-desktop-regular.marko +3 -0
  188. package/icons/generated/fluent-dismiss-circle-filled.marko +3 -0
  189. package/icons/generated/fluent-dismiss-regular.marko +3 -0
  190. package/icons/generated/fluent-document-pdf-regular.marko +3 -0
  191. package/icons/generated/fluent-document-regular.marko +3 -0
  192. package/icons/generated/fluent-eye-off-regular.marko +3 -0
  193. package/icons/generated/fluent-eye-regular.marko +3 -0
  194. package/icons/generated/fluent-eyedropper-regular.marko +3 -0
  195. package/icons/generated/fluent-grid-regular.marko +3 -0
  196. package/icons/generated/fluent-history-regular.marko +3 -0
  197. package/icons/generated/fluent-home-regular.marko +3 -0
  198. package/icons/generated/fluent-image-regular.marko +3 -0
  199. package/icons/generated/fluent-info-regular.marko +3 -0
  200. package/icons/generated/fluent-link-regular.marko +3 -0
  201. package/icons/generated/fluent-more-horizontal-regular.marko +3 -0
  202. package/icons/generated/fluent-navigation-regular.marko +3 -0
  203. package/icons/generated/fluent-paint-brush-regular.marko +3 -0
  204. package/icons/generated/fluent-question-circle-regular.marko +3 -0
  205. package/icons/generated/fluent-search-regular.marko +3 -0
  206. package/icons/generated/fluent-settings-regular.marko +3 -0
  207. package/icons/generated/fluent-square-hint-regular.marko +3 -0
  208. package/icons/generated/fluent-subtract-regular.marko +3 -0
  209. package/icons/generated/fluent-text-align-center-regular.marko +3 -0
  210. package/icons/generated/fluent-text-align-left-regular.marko +3 -0
  211. package/icons/generated/fluent-text-align-right-regular.marko +3 -0
  212. package/icons/generated/fluent-text-bold-regular.marko +3 -0
  213. package/icons/generated/fluent-text-bullet-list-regular.marko +3 -0
  214. package/icons/generated/fluent-text-font-regular.marko +3 -0
  215. package/icons/generated/fluent-text-font-size-regular.marko +3 -0
  216. package/icons/generated/fluent-text-italic-regular.marko +3 -0
  217. package/icons/generated/fluent-text-number-list-ltr-regular.marko +3 -0
  218. package/icons/generated/fluent-video-regular.marko +3 -0
  219. package/icons/generated/fluent-warning-filled.marko +3 -0
  220. package/icons/generated/fluent-weather-moon-regular.marko +3 -0
  221. package/icons/generated/fluent-weather-sunny-regular.marko +3 -0
  222. package/icons/generated/fluent-zoom-in-regular.marko +3 -0
  223. package/icons/generated/fluent-zoom-out-regular.marko +3 -0
  224. package/icons/manifest.json +61 -0
  225. package/icons/social/social-facebook-color.marko +7 -0
  226. package/icons/social/social-facebook.marko +6 -0
  227. package/icons/social/social-google-color.marko +20 -0
  228. package/icons/social/social-google.marko +6 -0
  229. package/icons/social/social-instagram-color.marko +16 -0
  230. package/icons/social/social-instagram.marko +6 -0
  231. package/icons/social/social-linkedin-color.marko +8 -0
  232. package/icons/social/social-linkedin.marko +8 -0
  233. package/icons/social/social-messenger-color.marko +15 -0
  234. package/icons/social/social-messenger.marko +6 -0
  235. package/icons/social/social-pinterest-color.marko +6 -0
  236. package/icons/social/social-pinterest.marko +6 -0
  237. package/icons/social/social-telegram-color.marko +7 -0
  238. package/icons/social/social-telegram.marko +6 -0
  239. package/icons/social/social-whatsapp-color.marko +8 -0
  240. package/icons/social/social-whatsapp.marko +7 -0
  241. package/icons/social/social-x-color.marko +7 -0
  242. package/icons/social/social-x.marko +6 -0
  243. package/icons/social/social-youtube-color.marko +7 -0
  244. package/icons/social/social-youtube.marko +6 -0
  245. package/marko.json +203 -0
  246. package/package.json +55 -0
@@ -0,0 +1,209 @@
1
+ /* SDS Switch.
2
+ Ported from kdls-design-system v2.5.1 (0f3edf8) components/Switch/Switch.css
3
+ by scripts/port-css.mjs. Divergences beyond the mechanical rename are noted inline.
4
+
5
+ Rules removed with the brand families they targeted:
6
+ [data-color-scheme="lya"] .sds-switch--on .sds-switch__track
7
+ [data-color-scheme="lya"] .sds-switch--on:not(.sds-switch--disabled):hover .sds-switch__track
8
+ */.sds-switch {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: var(--spacing-2);
12
+ cursor: pointer;
13
+ user-select: none;
14
+ font-family: var(--font-family-base);
15
+ outline: none;
16
+ }
17
+ .sds-switch--disabled {
18
+ cursor: not-allowed;
19
+ }
20
+ /* Track */
21
+ .sds-switch__track {
22
+ position: relative;
23
+ display: flex;
24
+ align-items: center;
25
+ /* soft, the install default — see the note by the scheme overrides below */
26
+ border-radius: 5px;
27
+ transition: background-color 200ms ease, box-shadow 200ms ease;
28
+ flex-shrink: 0;
29
+ background: var(--color-neutral-50);
30
+ }
31
+ .sds-switch--sm .sds-switch__track {
32
+ width: 44px;
33
+ height: 24px;
34
+ }
35
+ .sds-switch--md .sds-switch__track {
36
+ width: 56px;
37
+ height: 32px;
38
+ }
39
+ /* Track states */
40
+ .sds-switch--off .sds-switch__track {
41
+ background-color: var(--color-neutral-50);
42
+ }
43
+ .sds-switch--off:not(.sds-switch--disabled):hover .sds-switch__track {
44
+ background-color: var(--color-neutral-60);
45
+ }
46
+ .sds-switch--on .sds-switch__track {
47
+ background: var(--color-primary-50);
48
+ }
49
+ .sds-switch--on .sds-switch__thumb {
50
+ background: var(--color-on-primary);
51
+ }
52
+ .sds-switch--on:not(.sds-switch--disabled):hover .sds-switch__track {
53
+ background: var(--color-primary-60);
54
+ }
55
+ /* ── Disabled ── */
56
+ .sds-switch--disabled .sds-switch__track {
57
+ background-color: var(--color-neutral-20) !important;
58
+ }
59
+ .sds-switch--disabled .sds-switch__thumb {
60
+ background-color: var(--color-neutral-40);
61
+ }
62
+ [data-theme="dark"] .sds-switch--disabled .sds-switch__track {
63
+ background-color: var(--color-neutral-40) !important;
64
+ }
65
+ [data-theme="dark"] .sds-switch--disabled .sds-switch__thumb {
66
+ background-color: var(--color-neutral-20);
67
+ }
68
+ .sds-switch--disabled .sds-switch__label {
69
+ color: var(--color-neutral-40);
70
+ }
71
+ /* Thumb */
72
+ .sds-switch__thumb {
73
+ position: absolute;
74
+ /* soft, the install default — see the note by the scheme overrides below */
75
+ border-radius: 4px;
76
+ /* Off, the track is a mid grey and white reads against it. On, see the `:checked` rule
77
+ further down — the thumb then sits on the primary colour and cannot stay white. */
78
+ background: var(--color-white);
79
+ box-shadow: var(--shadow-drop-sm);
80
+ transition: transform 200ms ease, background-color 120ms ease;
81
+ }
82
+ .sds-switch--sm .sds-switch__thumb {
83
+ width: 20px;
84
+ height: 20px;
85
+ left: var(--spacing-0-5);
86
+ }
87
+ .sds-switch--sm.sds-switch--on .sds-switch__thumb {
88
+ transform: translateX(20px);
89
+ }
90
+ .sds-switch--md .sds-switch__thumb {
91
+ width: 28px;
92
+ height: 28px;
93
+ left: var(--spacing-0-5);
94
+ }
95
+ .sds-switch--md.sds-switch--on .sds-switch__thumb {
96
+ transform: translateX(24px);
97
+ }
98
+ /* Label */
99
+
100
+ /* Focus ring */
101
+ .sds-switch--on:focus-visible .sds-switch__track,
102
+ .sds-switch--off:focus-visible .sds-switch__track {
103
+ box-shadow: var(--focus-ring);
104
+ outline: none;
105
+ }
106
+ /* Container */
107
+ .sds-switch-container {
108
+ display: flex;
109
+ align-items: center;
110
+ height: 56px;
111
+ padding: 0 var(--spacing-4);
112
+ border: 1px solid var(--color-neutral-40);
113
+ border-radius: var(--radius-md);
114
+ background: var(--component-bg-color);
115
+ }
116
+ .sds-switch-container--disabled {
117
+ border-color: var(--border-static-color);
118
+ }
119
+ [data-theme="dark"] .sds-switch-container {
120
+ border-color: var(--color-neutral-60);
121
+ }
122
+ /* Wrapper — vertical stack with tight gap */
123
+ .sds-switch-wrapper {
124
+ display: flex;
125
+ flex-direction: column;
126
+ align-items: flex-start;
127
+ gap: var(--spacing-1);
128
+ }
129
+ /* Width modifier */
130
+ .sds-switch-wrapper--fill { width: 100%; }
131
+ .sds-switch-wrapper--fill > .sds-switch-container { width: 100%; }
132
+ /* Content column (label + hint stacked, no-container case) */
133
+ .sds-switch__content {
134
+ display: flex;
135
+ flex-direction: column;
136
+ gap: var(--spacing-0-5);
137
+ }
138
+ /* Hint */
139
+ .sds-switch__hint.sds-switch__hint--disabled { color: var(--color-neutral-40); }
140
+ .sds-switch-container + .sds-switch__hint { padding-left: var(--spacing-4); }
141
+ /* Dark mode */
142
+ [data-theme="dark"] .sds-switch--off .sds-switch__track {
143
+ background-color: var(--color-neutral-40);
144
+ }
145
+ [data-theme="dark"] .sds-switch--off:not(.sds-switch--disabled):hover .sds-switch__track {
146
+ background-color: var(--color-neutral-50);
147
+ }
148
+ [data-theme="dark"] .sds-switch-container--disabled {
149
+ border-color: var(--border-interactive-color);
150
+ }
151
+ /* ── Corner Radius Scheme overrides ── */
152
+ /* The base values above are soft's, not a capsule's: an install with no data-radius
153
+ attribute gets the default scheme, and SDS's default is soft — KDLS's was `default`,
154
+ Kenlo's own, which it kept unnamed in :root. `rounded` is explicit for the same reason,
155
+ because it can no longer fall through to the base. See Pill.css for the long version. */
156
+ /* Valores próprios, e não a escada, porque o trilho pequeno tem 24px de altura: metade
157
+ é 12px, e QUALQUER raio a partir daí desenha a mesma cápsula. `medium` valia exatamente
158
+ 12px, então ele já era o formato final e ficava idêntico ao `rounded` — foi isso que o
159
+ Rafael viu. A crescente aqui é 0 → 5 → 9 → cápsula, e o 9 é o maior número que ainda
160
+ deixa um canto visível no trilho de 24px. */
161
+ [data-radius="flat"] .sds-switch__track { border-radius: 0; }
162
+ [data-radius="flat"] .sds-switch__thumb { border-radius: 0; }
163
+ [data-radius="soft"] .sds-switch__track { border-radius: 5px; }
164
+ [data-radius="soft"] .sds-switch__thumb { border-radius: 4px; }
165
+ [data-radius="medium"] .sds-switch__track { border-radius: 9px; }
166
+ [data-radius="medium"] .sds-switch__thumb { border-radius: 7px; }
167
+ [data-radius="rounded"] .sds-switch__track { border-radius: var(--radius-full); }
168
+ /* The thumb is a circle at rounded, which is what 50% draws on a square box. */
169
+ [data-radius="rounded"] .sds-switch__thumb { border-radius: 50%; }
170
+
171
+ /* ── The native input ──────────────────────────────────────────────────────────
172
+ A real checkbox with role="switch". KDLS drew a div with useState and a click handler:
173
+ unreachable by keyboard, unsubmittable in a form, and announced as nothing in
174
+ particular. role="switch" is what makes a screen reader say "on" and "off" rather than
175
+ "checked" and "unchecked".
176
+
177
+ Hidden with opacity, not display:none — a hidden input cannot be focused. */
178
+ .sds-switch__input {
179
+ position: absolute;
180
+ width: 1px;
181
+ height: 1px;
182
+ margin: 0;
183
+ opacity: 0;
184
+ pointer-events: none;
185
+ }
186
+
187
+ .sds-switch__input:checked ~ .sds-switch__track {
188
+ background: var(--color-primary-50);
189
+ }
190
+
191
+ /* On, the thumb sits on the primary colour and has to be read against THAT.
192
+
193
+ It was a fixed `--color-white`, and `--color-primary-50` inverts: in the dark theme the
194
+ track is #f2f2f2 and the thumb was #ffffff — measured at 1.12:1, which is not low
195
+ contrast, it is an invisible thumb. A switch whose knob you cannot see is a switch whose
196
+ state you cannot read. Rafael found it on the portal.
197
+
198
+ `--color-on-primary` is the palette's own answer for what goes on that surface, and this
199
+ is the same fix the Button, the Notification and the Avatar took. A patch for it used to
200
+ sit here too, guarded on `[data-color-scheme="neutral"][data-theme="dark"]`, which could
201
+ never match — see the note in tokens.css. */
202
+ .sds-switch__input:checked ~ .sds-switch__track .sds-switch__thumb {
203
+ transform: translateX(100%);
204
+ background: var(--color-on-primary);
205
+ }
206
+
207
+ .sds-switch__input:focus-visible ~ .sds-switch__track {
208
+ box-shadow: var(--focus-ring);
209
+ }
@@ -0,0 +1,99 @@
1
+ <!-- sds-switch — ported from kdls-design-system v2.5.1 (0f3edf8) components/Switch/Switch.tsx.
2
+
3
+ A real <input type="checkbox" role="switch">. KDLS drew a div with useState and a click
4
+ handler, so a switch could not be reached by keyboard, could not be submitted with a form,
5
+ and announced itself as nothing in particular.
6
+
7
+ role="switch" is what makes a screen reader say "on"/"off" rather than "checked"/
8
+ "unchecked" — the same control, named the way a person would name it.
9
+
10
+ `checked` is the controlled value and `defaultChecked` the uncontrolled starting one, as
11
+ in KDLS. In the DOM they are the same attribute — it sets the *initial* state and the
12
+ browser owns it afterwards — so a caller passing `checked` and never updating it will see
13
+ the switch move anyway. A caller who needs it pinned has to re-render with the value it
14
+ wants, which is what controlled means.
15
+
16
+ No state: the browser owns checked, and the native change event bubbles for anyone who
17
+ needs to react. -->
18
+
19
+ $ {
20
+ const {
21
+ label,
22
+ hint,
23
+ name,
24
+ value,
25
+ size = "sm",
26
+ width = "hug",
27
+ checked,
28
+ defaultChecked = false,
29
+ disabled = false,
30
+ container = false,
31
+ // `component.id`, not a random string. Marko gives every component an id that is the
32
+ // same on the server and in the browser; a random one drawn inside the render block is
33
+ // a different value on each side, so every `for` and `aria-*` pointing at it resolved
34
+ // to nothing after hydration — and changed again on every re-render.
35
+ id = `sds-switch-${component.id}`,
36
+ class: extraClass = "",
37
+ } = input;
38
+
39
+ const isOn = checked !== undefined ? checked : defaultChecked;
40
+
41
+ if (size !== "sm" && size !== "md") {
42
+ throw new Error(`Unknown switch size: "${size}". Allowed: sm, md`);
43
+ }
44
+ if (width !== "hug" && width !== "fill") {
45
+ throw new Error(`Unknown switch width: "${width}". Allowed: hug, fill`);
46
+ }
47
+
48
+ const hintId = hint ? `${id}-hint` : null;
49
+
50
+ const classes = [
51
+ "sds-switch",
52
+ `sds-switch--${size}`,
53
+ isOn ? "sds-switch--on" : "sds-switch--off",
54
+ disabled ? "sds-switch--disabled" : "",
55
+ extraClass,
56
+ ].filter(Boolean).join(" ");
57
+
58
+ const wrapperClass = [
59
+ "sds-switch-wrapper",
60
+ `sds-switch-wrapper--${width}`,
61
+ container ? "sds-switch-container" : "",
62
+ container && disabled ? "sds-switch-container--disabled" : "",
63
+ ].filter(Boolean).join(" ");
64
+ }
65
+
66
+ <div class=wrapperClass>
67
+ <label class=classes for=id>
68
+ <input
69
+ class="sds-switch__input"
70
+ type="checkbox"
71
+ role="switch"
72
+ id=id
73
+ name=name
74
+ value=value
75
+ checked=(isOn || null)
76
+ disabled=(disabled || null)
77
+ aria-describedby=hintId
78
+ />
79
+
80
+ <span class="sds-switch__track" aria-hidden="true">
81
+ <span class="sds-switch__thumb"/>
82
+ </span>
83
+
84
+ <if(label)>
85
+ <span class="sds-switch__content">
86
+ <sds-text as="span" variant="bodyMd" color="inherit" class="sds-switch__label">
87
+ ${label}
88
+ </sds-text>
89
+ </span>
90
+ </if>
91
+ </label>
92
+
93
+ <if(hint)>
94
+ <sds-text as="span" id=hintId variant="labelRegular" color="inherit"
95
+ class=`sds-switch__hint ${disabled ? "sds-switch__hint--disabled" : ""}`.trim()>
96
+ ${hint}
97
+ </sds-text>
98
+ </if>
99
+ </div>
@@ -0,0 +1,270 @@
1
+ /* SDS Table.
2
+ Ported from kdls-design-system v2.5.1 (0f3edf8) components/Table/Table.css
3
+ by scripts/port-css.mjs. Divergences beyond the mechanical rename are noted inline.
4
+ *//* ── Table ──────────────────────────────────────────────────────────────
5
+ Surface canvas + sortable list with header, rows and column system.
6
+ BEM root: .sds-table
7
+ ─────────────────────────────────────────────────────────────────── */
8
+
9
+ /* ── Canvas wrapper ── */
10
+ .sds-table {
11
+ width: 100%;
12
+ background: var(--component-bg-color);
13
+ border: 1px solid transparent;
14
+ border-radius: var(--radius-md);
15
+ overflow: hidden;
16
+ display: flex;
17
+ flex-direction: column;
18
+ }
19
+ /* ── bordered=true — visible neutral-20 stroke ── */
20
+ .sds-table--bordered {
21
+ border-color: var(--border-static-color);
22
+ }
23
+ .sds-table .sds-pagination {
24
+ padding: var(--spacing-4) var(--spacing-6);
25
+ }
26
+ /* ── variant="cardLines" — restores the container's own padding/gap and turns each row
27
+ back into an individual card (own border, radius, gap) ── */
28
+ .sds-table--cardLines {
29
+ padding: var(--spacing-6);
30
+ gap: var(--spacing-6);
31
+ }
32
+ .sds-table--cardLines .sds-table__list {
33
+ gap: var(--spacing-4);
34
+ }
35
+ .sds-table--cardLines .sds-table__header {
36
+ padding: 0;
37
+ }
38
+ .sds-table--cardLines .sds-table__row--header {
39
+ padding: 0 var(--spacing-4);
40
+ }
41
+ .sds-table--cardLines .sds-table__row:not(.sds-table__row--header) {
42
+ border: 1px solid var(--border-static-color);
43
+ border-radius: var(--radius-md);
44
+ padding: var(--spacing-2) var(--spacing-4);
45
+ }
46
+ .sds-table--cardLines .sds-pagination {
47
+ padding: 0;
48
+ }
49
+ /* ── Header: title on the left, filters always on the right (margin-left: auto
50
+ guarantees right alignment even without a title) — wraps to a line
51
+ below the title when they don't fit side by side (flex-wrap) ── */
52
+ .sds-table__header {
53
+ display: flex;
54
+ align-items: center;
55
+ flex-wrap: wrap;
56
+ gap: var(--spacing-4);
57
+ padding: var(--spacing-4) var(--spacing-6);
58
+ }
59
+ .sds-table__header-title {
60
+ flex: 1;
61
+ min-width: 0;
62
+ }
63
+ /* ── Mobile sort picker — replaces the label row below the 800px breakpoint,
64
+ only rendered when at least one column is sortable ── */
65
+ .sds-table__sort-picker {
66
+ display: flex;
67
+ flex-wrap: wrap;
68
+ align-items: center;
69
+ gap: var(--spacing-4);
70
+ padding: var(--spacing-2) var(--spacing-6);
71
+ }
72
+ .sds-table__header-filters {
73
+ display: flex;
74
+ align-items: center;
75
+ flex-wrap: wrap;
76
+ gap: var(--spacing-4);
77
+ margin-left: auto;
78
+ }
79
+ /* ── List (scrollable table body) ── */
80
+ .sds-table__list {
81
+ width: 100%;
82
+ overflow-x: auto;
83
+ display: flex;
84
+ flex-direction: column;
85
+ }
86
+ /* ── Row ── */
87
+ .sds-table__row {
88
+ position: relative; /* anchors sds-table__mobile-icon-actions */
89
+ display: grid;
90
+ /* grid-template-columns driven entirely by inline style on each row */
91
+ align-items: center;
92
+ gap: var(--spacing-4);
93
+ padding: var(--spacing-4) var(--spacing-6);
94
+ min-height: 56px;
95
+ border-radius: 0;
96
+ border: none;
97
+ border-top: 1px solid var(--border-static-color);
98
+ background: var(--component-bg-color);
99
+ transition: background-color 120ms ease;
100
+ }
101
+ /* ── Mobile-only action slots (TableColumn.mobileAction) ──
102
+ 'icon' (chevron, •••) pins to the row's top-right corner, independent of the
103
+ stack's flow — rowSelection's checkbox pushes the stack down but never this.
104
+ 'link' collects into a final row: one button stays left-aligned, more than
105
+ one split the width evenly. ── */
106
+ .sds-table__mobile-icon-actions {
107
+ position: absolute;
108
+ top: var(--spacing-2);
109
+ right: var(--spacing-2);
110
+ display: flex;
111
+ align-items: center;
112
+ gap: var(--spacing-2);
113
+ }
114
+ .sds-table__mobile-link-actions {
115
+ display: flex;
116
+ gap: var(--spacing-4);
117
+ }
118
+ .sds-table__mobile-link-actions--split .sds-table__mobile-link-action {
119
+ flex: 1;
120
+ }
121
+ /* Header row */
122
+ .sds-table__row--header {
123
+ min-height: auto;
124
+ background: transparent;
125
+ border: 1px solid transparent;
126
+ border-radius: 0;
127
+ padding: var(--spacing-2) var(--spacing-6);
128
+ }
129
+ .sds-table__row--header .sds-table__col {
130
+ font-size: var(--font-size-body-md);
131
+ font-weight: var(--font-weight-medium);
132
+ color: var(--color-neutral-80);
133
+ flex-direction: column;
134
+ align-items: flex-start;
135
+ justify-content: center;
136
+ text-align: left;
137
+ }
138
+ /* Title follows the column's align — same direction as the content below it */
139
+ .sds-table__row--header .sds-table__col--center {
140
+ align-items: center;
141
+ text-align: center;
142
+ }
143
+ .sds-table__row--header .sds-table__col--end {
144
+ align-items: flex-end;
145
+ text-align: right;
146
+ }
147
+ .sds-table__row:hover:not(.sds-table__row--header) {
148
+ background: var(--color-neutral-10);
149
+ }
150
+ .sds-table__row--selected {
151
+ background: transparent;
152
+ outline: 1px solid var(--color-primary-30-solid);
153
+ outline-offset: -1px;
154
+ }
155
+ .sds-table__row--selected:hover {
156
+ background: var(--color-neutral-10);
157
+ }
158
+ /* ── Clickable row (hoverable + onRowClick) — same recipe as Card's hoverable,
159
+ but with background instead of box-shadow, to match the row's already-existing
160
+ hover (more subtle than Card's elevation) ── */
161
+ .sds-table__row--clickable {
162
+ cursor: pointer;
163
+ outline: none;
164
+ border-color: var(--border-interactive-color);
165
+ }
166
+ .sds-table__row.sds-table__row--clickable:active {
167
+ background: var(--color-neutral-20);
168
+ }
169
+ .sds-table__row--clickable:focus-visible {
170
+ box-shadow: var(--focus-ring);
171
+ }
172
+ /* ── Column ── */
173
+ .sds-table__col {
174
+ display: flex;
175
+ flex-direction: column;
176
+ justify-content: center;
177
+ min-width: 0; /* grid items don't shrink below content by default — required below */
178
+ overflow-wrap: anywhere; /* long unbreakable text (email, url) wraps inside the column instead of overflowing into the next one */
179
+ font-family: var(--font-family-base);
180
+ font-size: var(--font-size-body-md);
181
+ font-weight: var(--font-weight-regular);
182
+ color: var(--body-color);
183
+ }
184
+ .sds-table__col--center {
185
+ align-items: center;
186
+ text-align: center;
187
+ }
188
+ .sds-table__col--end {
189
+ align-items: flex-end;
190
+ text-align: right;
191
+ }
192
+ .sds-table__col--check { padding: 0; }
193
+ /* ── Sortable header ── */
194
+ .sds-table__row--header .sds-table__col--sortable {
195
+ flex-direction: row;
196
+ align-items: center;
197
+ justify-content: flex-start;
198
+ gap: var(--spacing-1);
199
+ cursor: pointer;
200
+ user-select: none;
201
+ }
202
+ .sds-table__row--header .sds-table__col--sortable.sds-table__col--center {
203
+ justify-content: center;
204
+ }
205
+ .sds-table__row--header .sds-table__col--sortable.sds-table__col--end {
206
+ justify-content: flex-end;
207
+ }
208
+ .sds-table__col-title {
209
+ overflow: hidden;
210
+ text-overflow: ellipsis;
211
+ white-space: nowrap;
212
+ }
213
+ .sds-table__sort {
214
+ display: inline-flex;
215
+ flex-direction: column;
216
+ margin: -3px 0;
217
+ }
218
+ /* ── Ellipsis (single-line truncation + Tooltip on hover) ── */
219
+ .sds-table__col--ellipsis .sds-tooltip-wrapper {
220
+ display: flex;
221
+ min-width: 0;
222
+ max-width: 100%;
223
+ }
224
+ .sds-table__ellipsis {
225
+ display: block;
226
+ overflow: hidden;
227
+ text-overflow: ellipsis;
228
+ white-space: nowrap;
229
+ min-width: 0;
230
+ max-width: 100%;
231
+ }
232
+ /* ── Cell text styles ── */
233
+ .sds-table__cell-secondary.sds-table__cell-secondary--alert {
234
+ color: var(--color-error-50);
235
+ }
236
+
237
+
238
+ /* A sortable header is a <button>, not a div with a click handler — so the header can be
239
+ reached and pressed from the keyboard, which KDLS's cannot. These take the browser's own
240
+ control styling off and let it fill the cell it sits in. */
241
+ .sds-table__sort-button {
242
+ appearance: none;
243
+ border: 0;
244
+ background: none;
245
+ font: inherit;
246
+ color: inherit;
247
+ cursor: pointer;
248
+ display: inline-flex;
249
+ align-items: center;
250
+ gap: var(--spacing-1);
251
+ padding: 0;
252
+ min-width: 0;
253
+ max-width: 100%;
254
+ }
255
+
256
+ .sds-table__sort-button:focus-visible {
257
+ outline: var(--focus-ring-width) solid var(--focus-stroke-color);
258
+ outline-offset: 2px;
259
+ border-radius: var(--radius-xs);
260
+ }
261
+
262
+ /* A table with no rows. KDLS renders the header row and then nothing at all, which reads
263
+ as a table still loading rather than one with no results. */
264
+ .sds-table__empty {
265
+ padding: var(--spacing-6);
266
+ text-align: center;
267
+ color: var(--color-neutral-60);
268
+ font-family: var(--font-family-base);
269
+ font-size: var(--font-size-body-md);
270
+ }
@@ -0,0 +1,28 @@
1
+ <!-- sds-table-cell — ported from kdls-design-system v2.5.1 (0f3edf8)
2
+ components/Table/Table.tsx (TableCell).
3
+
4
+ Two lines in one cell: the value, and a smaller line under it that can be marked as a
5
+ problem. Exported so a `render` function can build a cell without knowing the classes. -->
6
+
7
+ $ {
8
+ const { primary, secondary, alert = false } = input;
9
+ const renderable = (value) => (value && value.renderBody) || value;
10
+
11
+ const secondaryClass = [
12
+ "sds-table__cell-secondary",
13
+ alert ? "sds-table__cell-secondary--alert" : "",
14
+ ].filter(Boolean).join(" ");
15
+ }
16
+
17
+ <if(primary)>
18
+ <sds-text as="span" variant="bodyMd">
19
+ <if(typeof primary === "string")>${primary}</if>
20
+ <else><${renderable(primary)}/></else>
21
+ </sds-text>
22
+ </if>
23
+ <if(secondary)>
24
+ <sds-text as="span" variant="labelRegular" class=secondaryClass>
25
+ <if(typeof secondary === "string")>${secondary}</if>
26
+ <else><${renderable(secondary)}/></else>
27
+ </sds-text>
28
+ </if>
@@ -0,0 +1,27 @@
1
+ <!-- sds-table-header — ported from kdls-design-system v2.5.1 (0f3edf8)
2
+ components/Table/Table.tsx (TableHeader).
3
+
4
+ The bar above a table: a title on the left, filters on the right, and anything else
5
+ after them. Passed to sds-table as its `header` slot. -->
6
+
7
+ $ {
8
+ const { title, filters, class: extraClass = "" } = input;
9
+ const renderable = (value) => (value && value.renderBody) || value;
10
+ }
11
+
12
+ <div class=`sds-table__header ${extraClass}`.trim()>
13
+ <if(title)>
14
+ <sds-text as="span" variant="titleMd" class="sds-table__header-title">
15
+ <if(typeof title === "string")>${title}</if>
16
+ <else><${renderable(title)}/></else>
17
+ </sds-text>
18
+ </if>
19
+ <if(filters)>
20
+ <div class="sds-table__header-filters">
21
+ <${renderable(filters)}/>
22
+ </div>
23
+ </if>
24
+ <if(input.renderBody)>
25
+ <${input.renderBody}/>
26
+ </if>
27
+ </div>