@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.
- package/README.md +129 -0
- package/components/Accordion/Accordion.css +186 -0
- package/components/Accordion/accordion-variants.js +17 -0
- package/components/Accordion/accordion.marko +264 -0
- package/components/AccordionGroup/AccordionGroup.css +35 -0
- package/components/AccordionGroup/accordion-group.marko +17 -0
- package/components/Alert/Alert.css +104 -0
- package/components/Alert/alert-variants.js +35 -0
- package/components/Alert/alert.marko +94 -0
- package/components/AttachmentList/AttachmentList.css +92 -0
- package/components/AttachmentList/attachment-list.marko +51 -0
- package/components/AttachmentList/attachment-row.marko +167 -0
- package/components/Avatar/Avatar.css +110 -0
- package/components/Avatar/avatar-variants.js +12 -0
- package/components/Avatar/avatar.marko +71 -0
- package/components/Badge/Badge.css +381 -0
- package/components/Badge/badge-dismissible.marko +143 -0
- package/components/Badge/badge-variants.js +35 -0
- package/components/Badge/badge.marko +134 -0
- package/components/BottomSheet/BottomSheet.css +300 -0
- package/components/BottomSheet/bottom-sheet.marko +340 -0
- package/components/BulkActionBar/BulkActionBar.css +88 -0
- package/components/BulkActionBar/bulk-action-bar.marko +186 -0
- package/components/Button/Button.css +340 -0
- package/components/Button/button-variants.js +25 -0
- package/components/Button/button.marko +139 -0
- package/components/Card/Card.css +391 -0
- package/components/Card/card-body.marko +5 -0
- package/components/Card/card-collapsible.marko +94 -0
- package/components/Card/card-footer.marko +12 -0
- package/components/Card/card-header.marko +30 -0
- package/components/Card/card-info-pair.marko +17 -0
- package/components/Card/card-info-row.marko +12 -0
- package/components/Card/card-section.marko +14 -0
- package/components/Card/card-variants.js +24 -0
- package/components/Card/card.marko +124 -0
- package/components/Checkbox/Checkbox.css +249 -0
- package/components/Checkbox/checkbox-variants.js +21 -0
- package/components/Checkbox/checkbox.marko +128 -0
- package/components/ColorPicker/ColorPicker.css +253 -0
- package/components/ColorPicker/color-maths.js +104 -0
- package/components/ColorPicker/color-picker.marko +474 -0
- package/components/DatePicker/DatePicker.css +429 -0
- package/components/DatePicker/date-logic.js +225 -0
- package/components/DatePicker/date-picker.marko +492 -0
- package/components/Drawer/Drawer.css +174 -0
- package/components/Drawer/drawer.marko +262 -0
- package/components/Floating/Floating.css +28 -0
- package/components/Floating/floating-position.js +251 -0
- package/components/Floating/floating.marko +291 -0
- package/components/Form/Form.css +15 -0
- package/components/Form/form-context.js +69 -0
- package/components/Form/form.marko +73 -0
- package/components/GradientPicker/GradientPicker.css +179 -0
- package/components/GradientPicker/gradient-picker.marko +398 -0
- package/components/Grid/Grid.css +161 -0
- package/components/Grid/col.marko +36 -0
- package/components/Grid/grid-variants.js +43 -0
- package/components/Grid/grid.marko +25 -0
- package/components/Header/Header.css +457 -0
- package/components/Header/header.marko +523 -0
- package/components/Icon/Icon.css +44 -0
- package/components/Icon/icon-colors.js +31 -0
- package/components/Icon/icon.marko +56 -0
- package/components/IconButton/IconButton.css +85 -0
- package/components/IconButton/icon-button-variants.js +18 -0
- package/components/IconButton/icon-button.marko +103 -0
- package/components/Incrementer/Incrementer.css +94 -0
- package/components/Incrementer/incrementer.marko +70 -0
- package/components/Input/Input.css +547 -0
- package/components/Input/input-countries.js +109 -0
- package/components/Input/input-masks.js +218 -0
- package/components/Input/input-types.js +194 -0
- package/components/Input/input.marko +530 -0
- package/components/Menu/Menu.css +651 -0
- package/components/Menu/menu-variants.js +89 -0
- package/components/Menu/menu.marko +560 -0
- package/components/Modal/Modal.css +160 -0
- package/components/Modal/modal.marko +296 -0
- package/components/Nav/Nav.css +298 -0
- package/components/Nav/nav-variants.js +23 -0
- package/components/Nav/nav.marko +164 -0
- package/components/Notification/Notification.css +78 -0
- package/components/Notification/notification-variants.js +30 -0
- package/components/Notification/notification.marko +55 -0
- package/components/Pagination/Pagination.css +78 -0
- package/components/Pagination/pagination-pages.js +66 -0
- package/components/Pagination/pagination.marko +141 -0
- package/components/Pill/Pill.css +193 -0
- package/components/Pill/pill-variants.js +16 -0
- package/components/Pill/pill.marko +165 -0
- package/components/Popover/Popover.css +121 -0
- package/components/Popover/popover.marko +96 -0
- package/components/Radio/Radio.css +230 -0
- package/components/Radio/radio-variants.js +16 -0
- package/components/Radio/radio.marko +93 -0
- package/components/RadioGroup/RadioGroup.css +32 -0
- package/components/RadioGroup/radio-group.marko +93 -0
- package/components/SearchBar/SearchBar.css +181 -0
- package/components/SearchBar/search-bar-variants.js +24 -0
- package/components/SearchBar/search-bar.marko +157 -0
- package/components/Select/Select.css +427 -0
- package/components/Select/select-options.js +163 -0
- package/components/Select/select.marko +449 -0
- package/components/Separator/Separator.css +22 -0
- package/components/Separator/separator.marko +14 -0
- package/components/Skeleton/Skeleton.css +100 -0
- package/components/Skeleton/skeleton-avatar.marko +28 -0
- package/components/Skeleton/skeleton-button.marko +22 -0
- package/components/Skeleton/skeleton-image.marko +20 -0
- package/components/Skeleton/skeleton-input.marko +22 -0
- package/components/Skeleton/skeleton-variants.js +16 -0
- package/components/Skeleton/skeleton.marko +53 -0
- package/components/Spinner/Spinner.css +173 -0
- package/components/Spinner/spinner-geometry.js +39 -0
- package/components/Spinner/spinner-overlay.marko +97 -0
- package/components/Spinner/spinner.marko +88 -0
- package/components/StatCard/StatCard.css +90 -0
- package/components/StatCard/stat-card-group.marko +5 -0
- package/components/StatCard/stat-card.marko +57 -0
- package/components/Switch/Switch.css +209 -0
- package/components/Switch/switch.marko +99 -0
- package/components/Table/Table.css +270 -0
- package/components/Table/table-cell.marko +28 -0
- package/components/Table/table-header.marko +27 -0
- package/components/Table/table-logic.js +129 -0
- package/components/Table/table.marko +372 -0
- package/components/Text/Text.css +79 -0
- package/components/Text/text-variants.js +25 -0
- package/components/Text/text.marko +48 -0
- package/components/TextEditor/TextEditor.css +78 -0
- package/components/TextEditor/safe-url.js +50 -0
- package/components/TextEditor/text-editor-commands.js +22 -0
- package/components/TextEditor/text-editor.marko +253 -0
- package/components/Toast/Toast.css +88 -0
- package/components/Toast/toast-api.js +19 -0
- package/components/Toast/toast-store.js +118 -0
- package/components/Toast/toast-variants.js +16 -0
- package/components/Toast/toast.marko +93 -0
- package/components/Toast/toaster.marko +70 -0
- package/components/Toggle/Toggle.css +169 -0
- package/components/Toggle/toggle.marko +93 -0
- package/components/Tooltip/Tooltip.css +115 -0
- package/components/Tooltip/tooltip.marko +77 -0
- package/components/Uploader/Uploader.css +180 -0
- package/components/Uploader/crop-geometry.js +161 -0
- package/components/Uploader/uploader.marko +269 -0
- package/foundations/Scrollbar/Scrollbar.css +26 -0
- package/foundations/attrs.js +27 -0
- package/foundations/breakpoints.js +27 -0
- package/foundations/contrast.js +74 -0
- package/foundations/custom-scheme.js +222 -0
- package/foundations/overlay.js +108 -0
- package/foundations/styles.css +284 -0
- package/foundations/text.js +22 -0
- package/foundations/theme-server.js +81 -0
- package/foundations/theme.js +42 -0
- package/foundations/tokens.css +1656 -0
- package/icons/custom/custom-video-horizontal-filled.marko +6 -0
- package/icons/custom/custom-video-horizontal-regular.marko +6 -0
- package/icons/custom/custom-video-tour-3d-filled.marko +7 -0
- package/icons/custom/custom-video-tour-3d-regular.marko +9 -0
- package/icons/custom/custom-video-vertical-filled.marko +6 -0
- package/icons/custom/custom-video-vertical-regular.marko +6 -0
- package/icons/generated/fluent-add-regular.marko +3 -0
- package/icons/generated/fluent-alert-regular.marko +3 -0
- package/icons/generated/fluent-apps-regular.marko +3 -0
- package/icons/generated/fluent-arrow-download-regular.marko +3 -0
- package/icons/generated/fluent-arrow-left-regular.marko +3 -0
- package/icons/generated/fluent-arrow-right-regular.marko +3 -0
- package/icons/generated/fluent-arrow-rotate-clockwise-regular.marko +3 -0
- package/icons/generated/fluent-arrow-rotate-counterclockwise-regular.marko +3 -0
- package/icons/generated/fluent-border-all-regular.marko +3 -0
- package/icons/generated/fluent-calendar-regular.marko +3 -0
- package/icons/generated/fluent-checkmark-circle-filled.marko +3 -0
- package/icons/generated/fluent-checkmark-regular.marko +3 -0
- package/icons/generated/fluent-chevron-down-regular.marko +3 -0
- package/icons/generated/fluent-chevron-left-regular.marko +3 -0
- package/icons/generated/fluent-chevron-right-regular.marko +3 -0
- package/icons/generated/fluent-chevron-up-regular.marko +3 -0
- package/icons/generated/fluent-circle-half-fill-regular.marko +3 -0
- package/icons/generated/fluent-clock-regular.marko +3 -0
- package/icons/generated/fluent-color-regular.marko +3 -0
- package/icons/generated/fluent-crop-regular.marko +3 -0
- package/icons/generated/fluent-dark-theme-regular.marko +3 -0
- package/icons/generated/fluent-delete-regular.marko +3 -0
- package/icons/generated/fluent-desktop-regular.marko +3 -0
- package/icons/generated/fluent-dismiss-circle-filled.marko +3 -0
- package/icons/generated/fluent-dismiss-regular.marko +3 -0
- package/icons/generated/fluent-document-pdf-regular.marko +3 -0
- package/icons/generated/fluent-document-regular.marko +3 -0
- package/icons/generated/fluent-eye-off-regular.marko +3 -0
- package/icons/generated/fluent-eye-regular.marko +3 -0
- package/icons/generated/fluent-eyedropper-regular.marko +3 -0
- package/icons/generated/fluent-grid-regular.marko +3 -0
- package/icons/generated/fluent-history-regular.marko +3 -0
- package/icons/generated/fluent-home-regular.marko +3 -0
- package/icons/generated/fluent-image-regular.marko +3 -0
- package/icons/generated/fluent-info-regular.marko +3 -0
- package/icons/generated/fluent-link-regular.marko +3 -0
- package/icons/generated/fluent-more-horizontal-regular.marko +3 -0
- package/icons/generated/fluent-navigation-regular.marko +3 -0
- package/icons/generated/fluent-paint-brush-regular.marko +3 -0
- package/icons/generated/fluent-question-circle-regular.marko +3 -0
- package/icons/generated/fluent-search-regular.marko +3 -0
- package/icons/generated/fluent-settings-regular.marko +3 -0
- package/icons/generated/fluent-square-hint-regular.marko +3 -0
- package/icons/generated/fluent-subtract-regular.marko +3 -0
- package/icons/generated/fluent-text-align-center-regular.marko +3 -0
- package/icons/generated/fluent-text-align-left-regular.marko +3 -0
- package/icons/generated/fluent-text-align-right-regular.marko +3 -0
- package/icons/generated/fluent-text-bold-regular.marko +3 -0
- package/icons/generated/fluent-text-bullet-list-regular.marko +3 -0
- package/icons/generated/fluent-text-font-regular.marko +3 -0
- package/icons/generated/fluent-text-font-size-regular.marko +3 -0
- package/icons/generated/fluent-text-italic-regular.marko +3 -0
- package/icons/generated/fluent-text-number-list-ltr-regular.marko +3 -0
- package/icons/generated/fluent-video-regular.marko +3 -0
- package/icons/generated/fluent-warning-filled.marko +3 -0
- package/icons/generated/fluent-weather-moon-regular.marko +3 -0
- package/icons/generated/fluent-weather-sunny-regular.marko +3 -0
- package/icons/generated/fluent-zoom-in-regular.marko +3 -0
- package/icons/generated/fluent-zoom-out-regular.marko +3 -0
- package/icons/manifest.json +61 -0
- package/icons/social/social-facebook-color.marko +7 -0
- package/icons/social/social-facebook.marko +6 -0
- package/icons/social/social-google-color.marko +20 -0
- package/icons/social/social-google.marko +6 -0
- package/icons/social/social-instagram-color.marko +16 -0
- package/icons/social/social-instagram.marko +6 -0
- package/icons/social/social-linkedin-color.marko +8 -0
- package/icons/social/social-linkedin.marko +8 -0
- package/icons/social/social-messenger-color.marko +15 -0
- package/icons/social/social-messenger.marko +6 -0
- package/icons/social/social-pinterest-color.marko +6 -0
- package/icons/social/social-pinterest.marko +6 -0
- package/icons/social/social-telegram-color.marko +7 -0
- package/icons/social/social-telegram.marko +6 -0
- package/icons/social/social-whatsapp-color.marko +8 -0
- package/icons/social/social-whatsapp.marko +7 -0
- package/icons/social/social-x-color.marko +7 -0
- package/icons/social/social-x.marko +6 -0
- package/icons/social/social-youtube-color.marko +7 -0
- package/icons/social/social-youtube.marko +6 -0
- package/marko.json +203 -0
- package/package.json +55 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/* SDS Button.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Button/Button.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-button--primary
|
|
7
|
+
[data-color-scheme="lya"] .sds-button--primary:hover:not(:disabled):not(.sds-button--loading)
|
|
8
|
+
[data-color-scheme="lya"] .sds-button--primary:active:not(:disabled):not(.sds-button--loading)
|
|
9
|
+
[data-color-scheme="lya"] .sds-button--primary:focus-visible
|
|
10
|
+
[data-color-scheme="lya"] .sds-button--ghost
|
|
11
|
+
[data-color-scheme="lya"] .sds-button--ghost:hover:not(:disabled):not(.sds-button--loading)
|
|
12
|
+
[data-color-scheme="lya"] .sds-button--ghost:active:not(:disabled):not(.sds-button--loading)
|
|
13
|
+
[data-color-scheme="lya"] .sds-button--ghost:focus-visible
|
|
14
|
+
[data-color-scheme="lya"] .sds-button--pill:hover:not(:disabled):not(.sds-button--loading)
|
|
15
|
+
[data-color-scheme="lya"] .sds-button--pillFilled
|
|
16
|
+
[data-color-scheme="lya"] .sds-button--pillFilled:hover:not(:disabled):not(.sds-button--loading)
|
|
17
|
+
[data-color-scheme="lya"] .sds-button--pillFilled:active:not(:disabled):not(.sds-button--loading)
|
|
18
|
+
[data-color-scheme="lya"] .sds-button--pillFilled:focus-visible
|
|
19
|
+
[data-color-scheme="lya"] .sds-button--link
|
|
20
|
+
[data-color-scheme="lya"] .sds-button--link:hover:not(:disabled):not(.sds-button--loading)
|
|
21
|
+
[data-color-scheme="lya"] .sds-button--link:active:not(:disabled):not(.sds-button--loading)
|
|
22
|
+
*//* ============================================================
|
|
23
|
+
SDS Button
|
|
24
|
+
Variants: primary (filled) | ghost (outlined) | link
|
|
25
|
+
Sizes: small (48px) | medium (48px) | large (56px)
|
|
26
|
+
link: 24px fixed
|
|
27
|
+
Color: follows global data-color-scheme on root element
|
|
28
|
+
(blue by default, override via data-color-scheme)
|
|
29
|
+
States: enabled | hover | pressed | focused | disabled
|
|
30
|
+
============================================================ */
|
|
31
|
+
|
|
32
|
+
.sds-button {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
box-sizing: border-box;
|
|
37
|
+
border: 2px solid transparent;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
font-family: var(--font-family-base);
|
|
40
|
+
font-weight: var(--font-weight-bold);
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
white-space: nowrap;
|
|
43
|
+
transition:
|
|
44
|
+
background-color 120ms ease,
|
|
45
|
+
color 120ms ease,
|
|
46
|
+
border-color 120ms ease,
|
|
47
|
+
box-shadow 120ms ease,
|
|
48
|
+
opacity 120ms ease;
|
|
49
|
+
outline: none;
|
|
50
|
+
position: relative;
|
|
51
|
+
letter-spacing: -0.01em;
|
|
52
|
+
-webkit-font-smoothing: antialiased;
|
|
53
|
+
}
|
|
54
|
+
.sds-button--full {
|
|
55
|
+
width: 100%;
|
|
56
|
+
}
|
|
57
|
+
.sds-button__tooltip-wrapper--full {
|
|
58
|
+
display: flex;
|
|
59
|
+
width: 100%;
|
|
60
|
+
}
|
|
61
|
+
/* ──────────────────────────────────────────────
|
|
62
|
+
SIZES
|
|
63
|
+
────────────────────────────────────────────── */
|
|
64
|
+
.sds-button--md {
|
|
65
|
+
height: 48px;
|
|
66
|
+
padding: 0 var(--spacing-5);
|
|
67
|
+
gap: var(--spacing-2);
|
|
68
|
+
font-size: var(--font-size-title-sm);
|
|
69
|
+
line-height: var(--lh-title-sm);
|
|
70
|
+
/* soft, the install default — the four schemes are at the end of the file */
|
|
71
|
+
border-radius: 13px;
|
|
72
|
+
}
|
|
73
|
+
.sds-button--lg {
|
|
74
|
+
height: 56px;
|
|
75
|
+
padding: 0 var(--spacing-6);
|
|
76
|
+
gap: var(--spacing-2);
|
|
77
|
+
font-size: var(--font-size-title-sm);
|
|
78
|
+
line-height: var(--lh-title-sm);
|
|
79
|
+
/* soft, the install default — the four schemes are at the end of the file */
|
|
80
|
+
border-radius: 15px;
|
|
81
|
+
}
|
|
82
|
+
/* ──────────────────────────────────────────────
|
|
83
|
+
ICONS
|
|
84
|
+
────────────────────────────────────────────── */
|
|
85
|
+
.sds-button__icon {
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
flex-shrink: 0;
|
|
89
|
+
font-size: 24px;
|
|
90
|
+
width: 24px;
|
|
91
|
+
height: 24px;
|
|
92
|
+
}
|
|
93
|
+
/* ──────────────────────────────────────────────
|
|
94
|
+
VARIANT: primary (filled)
|
|
95
|
+
Uses --color-primary-* → follows data-color-scheme
|
|
96
|
+
────────────────────────────────────────────── */
|
|
97
|
+
.sds-button--primary {
|
|
98
|
+
background: var(--color-primary-50);
|
|
99
|
+
color: var(--color-on-primary);
|
|
100
|
+
}
|
|
101
|
+
.sds-button--primary:hover:not(:disabled):not(.sds-button--loading) {
|
|
102
|
+
background: var(--color-primary-60);
|
|
103
|
+
}
|
|
104
|
+
.sds-button--primary:active:not(:disabled):not(.sds-button--loading) {
|
|
105
|
+
background: var(--color-primary-70);
|
|
106
|
+
}
|
|
107
|
+
.sds-button--primary:focus-visible {
|
|
108
|
+
box-shadow: var(--focus-ring);
|
|
109
|
+
}
|
|
110
|
+
/* ──────────────────────────────────────────────
|
|
111
|
+
VARIANT: ghost (outlined / ghost)
|
|
112
|
+
────────────────────────────────────────────── */
|
|
113
|
+
.sds-button--ghost {
|
|
114
|
+
background-color: transparent;
|
|
115
|
+
border-color: var(--color-primary-50-solid);
|
|
116
|
+
color: var(--color-primary-50-solid);
|
|
117
|
+
}
|
|
118
|
+
.sds-button--ghost:hover:not(:disabled):not(.sds-button--loading) {
|
|
119
|
+
background: var(--color-primary-10);
|
|
120
|
+
border-color: var(--color-primary-60-solid);
|
|
121
|
+
color: var(--color-primary-60-solid);
|
|
122
|
+
}
|
|
123
|
+
.sds-button--ghost:active:not(:disabled):not(.sds-button--loading) {
|
|
124
|
+
background: var(--color-primary-20);
|
|
125
|
+
border-color: var(--color-primary-70-solid);
|
|
126
|
+
color: var(--color-primary-70-solid);
|
|
127
|
+
}
|
|
128
|
+
.sds-button--ghost:focus-visible {
|
|
129
|
+
box-shadow: var(--focus-ring);
|
|
130
|
+
}
|
|
131
|
+
.sds-button--link:focus-visible {
|
|
132
|
+
box-shadow: var(--focus-ring);
|
|
133
|
+
border-radius: var(--radius-sm);
|
|
134
|
+
}
|
|
135
|
+
/* ──────────────────────────────────────────────
|
|
136
|
+
VARIANT: link (text only)
|
|
137
|
+
────────────────────────────────────────────── */
|
|
138
|
+
.sds-button--link {
|
|
139
|
+
background-color: transparent;
|
|
140
|
+
border: none;
|
|
141
|
+
padding: 0;
|
|
142
|
+
height: 24px;
|
|
143
|
+
font-size: var(--font-size-title-sm);
|
|
144
|
+
line-height: var(--lh-title-sm);
|
|
145
|
+
color: var(--color-primary-50-solid);
|
|
146
|
+
}
|
|
147
|
+
.sds-button--link:hover:not(:disabled):not(.sds-button--loading) {
|
|
148
|
+
color: var(--color-primary-60-solid);
|
|
149
|
+
text-decoration: underline;
|
|
150
|
+
text-underline-offset: 3px;
|
|
151
|
+
}
|
|
152
|
+
.sds-button--link:active:not(:disabled):not(.sds-button--loading) {
|
|
153
|
+
color: var(--color-primary-70-solid);
|
|
154
|
+
}
|
|
155
|
+
/* ──────────────────────────────────────────────
|
|
156
|
+
VARIANT: pillFilled (pill, filled)
|
|
157
|
+
────────────────────────────────────────────── */
|
|
158
|
+
.sds-button--pillFilled {
|
|
159
|
+
height: 40px;
|
|
160
|
+
padding: 0 var(--spacing-4);
|
|
161
|
+
gap: var(--spacing-2);
|
|
162
|
+
border-radius: var(--radius-full);
|
|
163
|
+
font-size: var(--font-size-body-md);
|
|
164
|
+
font-weight: var(--font-weight-medium);
|
|
165
|
+
line-height: var(--lh-body-md);
|
|
166
|
+
background: var(--color-primary-50);
|
|
167
|
+
color: var(--color-on-primary);
|
|
168
|
+
border: 1px solid var(--color-primary-50-solid);
|
|
169
|
+
}
|
|
170
|
+
.sds-button--pillFilled:hover:not(:disabled):not(.sds-button--loading) {
|
|
171
|
+
background: var(--color-primary-60);
|
|
172
|
+
}
|
|
173
|
+
.sds-button--pillFilled:active:not(:disabled):not(.sds-button--loading) {
|
|
174
|
+
background: var(--color-primary-70);
|
|
175
|
+
}
|
|
176
|
+
.sds-button--pillFilled:focus-visible {
|
|
177
|
+
box-shadow: var(--focus-ring);
|
|
178
|
+
}
|
|
179
|
+
/* ──────────────────────────────────────────────
|
|
180
|
+
VARIANT: pill (pill, outlined)
|
|
181
|
+
────────────────────────────────────────────── */
|
|
182
|
+
.sds-button--pill {
|
|
183
|
+
height: 40px;
|
|
184
|
+
padding: 0 var(--spacing-4);
|
|
185
|
+
gap: var(--spacing-2);
|
|
186
|
+
border-radius: var(--radius-full);
|
|
187
|
+
font-size: var(--font-size-body-md);
|
|
188
|
+
font-weight: var(--font-weight-medium);
|
|
189
|
+
line-height: var(--lh-body-md);
|
|
190
|
+
background-color: var(--component-bg-color);
|
|
191
|
+
color: var(--color-neutral-80);
|
|
192
|
+
border: 1px solid var(--border-interactive-color);
|
|
193
|
+
}
|
|
194
|
+
.sds-button--pill:hover:not(:disabled):not(.sds-button--loading) {
|
|
195
|
+
border-color: var(--color-primary-50-solid);
|
|
196
|
+
}
|
|
197
|
+
.sds-button--pill:active:not(:disabled):not(.sds-button--loading) {
|
|
198
|
+
background-color: var(--color-neutral-20);
|
|
199
|
+
border-color: var(--color-neutral-60);
|
|
200
|
+
color: var(--color-neutral-90);
|
|
201
|
+
}
|
|
202
|
+
.sds-button--pill:focus-visible {
|
|
203
|
+
box-shadow: var(--focus-ring);
|
|
204
|
+
}
|
|
205
|
+
/* ──────────────────────────────────────────────
|
|
206
|
+
LOADING STATE
|
|
207
|
+
────────────────────────────────────────────── */
|
|
208
|
+
.sds-button--loading {
|
|
209
|
+
cursor: wait;
|
|
210
|
+
}
|
|
211
|
+
.sds-button--loading .sds-button__label,
|
|
212
|
+
.sds-button--loading .sds-button__icon {
|
|
213
|
+
opacity: 0;
|
|
214
|
+
}
|
|
215
|
+
.sds-button--loading .sds-spinner {
|
|
216
|
+
position: absolute;
|
|
217
|
+
top: 50%;
|
|
218
|
+
left: 50%;
|
|
219
|
+
transform: translate(-50%, -50%);
|
|
220
|
+
}
|
|
221
|
+
/* Primary/pillFilled have a dark background → white loader */
|
|
222
|
+
.sds-button--primary.sds-button--loading .sds-spinner--solid .sds-spinner__arc,
|
|
223
|
+
.sds-button--pillFilled.sds-button--loading .sds-spinner--solid .sds-spinner__arc {
|
|
224
|
+
stroke: var(--color-on-primary);
|
|
225
|
+
}
|
|
226
|
+
.sds-button--primary.sds-button--loading .sds-spinner__track,
|
|
227
|
+
.sds-button--pillFilled.sds-button--loading .sds-spinner__track {
|
|
228
|
+
/* The arc above already reads --color-on-primary, which is white or black by contrast
|
|
229
|
+
against the button's own fill. The track follows it at 30% rather than assuming
|
|
230
|
+
white: on a light primary --color-on-primary is black, and a white track there would
|
|
231
|
+
be invisible. KDLS hardcoded white and had that bug. */
|
|
232
|
+
stroke: color-mix(in srgb, var(--color-on-primary) 30%, transparent);
|
|
233
|
+
}
|
|
234
|
+
/* ──────────────────────────────────────────────
|
|
235
|
+
DISABLED
|
|
236
|
+
────────────────────────────────────────────── */
|
|
237
|
+
.sds-button:disabled,
|
|
238
|
+
.sds-button[aria-disabled="true"] {
|
|
239
|
+
cursor: not-allowed;
|
|
240
|
+
background-color: var(--color-neutral-20) !important;
|
|
241
|
+
border-color: var(--border-static-color) !important;
|
|
242
|
+
color: var(--color-neutral-40) !important;
|
|
243
|
+
box-shadow: none !important;
|
|
244
|
+
}
|
|
245
|
+
/* Tooltip wraps the button only when disabled: keeps pointer-events:none on the button
|
|
246
|
+
(lets hover reach the wrapper for the tooltip) and shows the cursor on the wrapper */
|
|
247
|
+
.sds-button__tooltip-wrapper {
|
|
248
|
+
cursor: help;
|
|
249
|
+
}
|
|
250
|
+
.sds-button__tooltip-wrapper > .sds-button:disabled,
|
|
251
|
+
.sds-button__tooltip-wrapper > .sds-button[aria-disabled="true"] {
|
|
252
|
+
pointer-events: none;
|
|
253
|
+
}
|
|
254
|
+
.sds-button--link:disabled,
|
|
255
|
+
.sds-button--link[aria-disabled="true"] {
|
|
256
|
+
background-color: transparent !important;
|
|
257
|
+
color: var(--color-neutral-40) !important;
|
|
258
|
+
border-color: transparent !important;
|
|
259
|
+
}
|
|
260
|
+
.sds-button--ghost:disabled,
|
|
261
|
+
.sds-button--ghost[aria-disabled="true"],
|
|
262
|
+
.sds-button--pill:disabled,
|
|
263
|
+
.sds-button--pill[aria-disabled="true"] {
|
|
264
|
+
background-color: transparent !important;
|
|
265
|
+
border-color: var(--border-static-color) !important;
|
|
266
|
+
color: var(--color-neutral-40) !important;
|
|
267
|
+
}
|
|
268
|
+
[data-theme="dark"] .sds-button:disabled,
|
|
269
|
+
[data-theme="dark"] .sds-button[aria-disabled="true"] {
|
|
270
|
+
background-color: var(--color-neutral-30) !important;
|
|
271
|
+
border-color: var(--border-interactive-color) !important;
|
|
272
|
+
color: var(--color-neutral-40) !important;
|
|
273
|
+
}
|
|
274
|
+
[data-theme="dark"] .sds-button--link:disabled,
|
|
275
|
+
[data-theme="dark"] .sds-button--link[aria-disabled="true"] {
|
|
276
|
+
background-color: transparent !important;
|
|
277
|
+
color: var(--color-neutral-40) !important;
|
|
278
|
+
border-color: transparent !important;
|
|
279
|
+
}
|
|
280
|
+
[data-theme="dark"] .sds-button--ghost:disabled,
|
|
281
|
+
[data-theme="dark"] .sds-button--ghost[aria-disabled="true"],
|
|
282
|
+
[data-theme="dark"] .sds-button--pill:disabled,
|
|
283
|
+
[data-theme="dark"] .sds-button--pill[aria-disabled="true"] {
|
|
284
|
+
background-color: transparent !important;
|
|
285
|
+
border-color: var(--border-interactive-color) !important;
|
|
286
|
+
color: var(--color-neutral-40) !important;
|
|
287
|
+
}
|
|
288
|
+
/* ──────────────────────────────────────────────
|
|
289
|
+
NEUTRAL SCHEME DARK MODE OVERRIDE
|
|
290
|
+
In dark mode, neutral-80 resolves to light gray —
|
|
291
|
+
ensure primary button stays legible.
|
|
292
|
+
────────────────────────────────────────────── */
|
|
293
|
+
[data-theme="dark"] .sds-button--pill:hover:not(:disabled):not(.sds-button--loading) {
|
|
294
|
+
background-color: transparent;
|
|
295
|
+
}
|
|
296
|
+
[data-theme="dark"] .sds-button--pill:active:not(:disabled):not(.sds-button--loading) {
|
|
297
|
+
background-color: var(--color-neutral-30);
|
|
298
|
+
}
|
|
299
|
+
/* Four more dead rules stood here, and they looked at first like a design intention worth
|
|
300
|
+
keeping: they set the primary button's own FILL in the dark theme, to `--color-neutral-80`
|
|
301
|
+
— which reads as "dark" to anyone writing CSS in the light theme.
|
|
302
|
+
|
|
303
|
+
It is not. In the dark theme `--color-neutral-80` resolves to #f2f2f2, exactly what
|
|
304
|
+
`--color-primary-50` resolves to there. Measured side by side in Chrome: both #f2f2f2
|
|
305
|
+
with #262626 text, indistinguishable. The rules asked for the button that already
|
|
306
|
+
exists, spelled with different token names, and they never ran anyway. Nothing to
|
|
307
|
+
preserve. */
|
|
308
|
+
|
|
309
|
+
/* ── Corner radius schemes ────────────────────────────────────────────────────
|
|
310
|
+
A fraction of the button's own height, not `--radius-md`, and for the reason the Pill
|
|
311
|
+
wrote down first: a radius past half the height draws a capsule, and the browser clamps
|
|
312
|
+
anything beyond it. `--radius-md` is 24px at `medium`, which on the 48px button is
|
|
313
|
+
EXACTLY half — so `medium` was already the capsule and `rounded` (32px, clamped back to
|
|
314
|
+
24) drew the identical shape. Rafael, looking at the two side by side: between medium
|
|
315
|
+
and rounded there is no visual difference, and there has to be.
|
|
316
|
+
|
|
317
|
+
fraction flat 0 soft 0.275 medium 0.375 rounded 0.5 (a capsule)
|
|
318
|
+
48px 0 13px 18px capsule
|
|
319
|
+
56px 0 15px 21px capsule
|
|
320
|
+
|
|
321
|
+
Same fractions as Pill (40px → 11 and 15) and as the 40px rows elsewhere, which is what
|
|
322
|
+
keeps every control in the system reading as one family at a given scheme.
|
|
323
|
+
|
|
324
|
+
`pillFilled` and `pill` are not here on purpose: they are capsules by definition —
|
|
325
|
+
being round is what those variants ARE, the way it is for a badge or an avatar — so
|
|
326
|
+
they keep `--radius-full` in every scheme.
|
|
327
|
+
|
|
328
|
+
The bare values above are `soft`'s, because an install that never picks a scheme has no
|
|
329
|
+
attribute at all and falls through to them. */
|
|
330
|
+
[data-radius="flat"] .sds-button--md { border-radius: 0; }
|
|
331
|
+
[data-radius="flat"] .sds-button--lg { border-radius: 0; }
|
|
332
|
+
|
|
333
|
+
[data-radius="soft"] .sds-button--md { border-radius: 13px; }
|
|
334
|
+
[data-radius="soft"] .sds-button--lg { border-radius: 15px; }
|
|
335
|
+
|
|
336
|
+
[data-radius="medium"] .sds-button--md { border-radius: 18px; }
|
|
337
|
+
[data-radius="medium"] .sds-button--lg { border-radius: 21px; }
|
|
338
|
+
|
|
339
|
+
[data-radius="rounded"] .sds-button--md { border-radius: var(--radius-full); }
|
|
340
|
+
[data-radius="rounded"] .sds-button--lg { border-radius: var(--radius-full); }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Button vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/Button/Button.tsx.
|
|
5
|
+
* Divergence: none. Every variant already read the primary slot rather than a Kenlo
|
|
6
|
+
* value — what KDLS added on top was a set of [data-color-scheme="lya"] overrides, and
|
|
7
|
+
* those are gone with the scheme. A gradient now reaches the button the same way it
|
|
8
|
+
* reaches everything else: through applyCustomGradient filling the slot.
|
|
9
|
+
*/
|
|
10
|
+
export const BUTTON_VARIANTS = ['primary', 'ghost', 'link', 'pill', 'pillFilled'];
|
|
11
|
+
export const BUTTON_SIZES = ['md', 'lg'];
|
|
12
|
+
export const BUTTON_WIDTHS = ['hug', 'fill'];
|
|
13
|
+
export const BUTTON_TYPES = ['button', 'submit', 'reset'];
|
|
14
|
+
|
|
15
|
+
function assertOneOf(label, value, allowed) {
|
|
16
|
+
if (!allowed.includes(value)) {
|
|
17
|
+
throw new Error(`Unknown button ${label}: "${value}". Allowed: ${allowed.join(', ')}`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const assertButtonVariant = (v) => assertOneOf('variant', v, BUTTON_VARIANTS);
|
|
23
|
+
export const assertButtonSize = (v) => assertOneOf('size', v, BUTTON_SIZES);
|
|
24
|
+
export const assertButtonWidth = (v) => assertOneOf('width', v, BUTTON_WIDTHS);
|
|
25
|
+
export const assertButtonType = (v) => assertOneOf('type', v, BUTTON_TYPES);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<!-- sds-button — ported from kdls-design-system v2.5.1 (0f3edf8) components/Button/Button.tsx.
|
|
2
|
+
|
|
3
|
+
Hydrates, for the same reason IconButton does: a button exists to be clicked, and Marko 5
|
|
4
|
+
drops a listener silently on a component that does not hydrate. Its input is a label and
|
|
5
|
+
a handful of flags, so the payload is small.
|
|
6
|
+
|
|
7
|
+
Divergences:
|
|
8
|
+
|
|
9
|
+
Sixteen [data-color-scheme="lya"] rules are gone with the scheme they served. They gave
|
|
10
|
+
the primary, ghost, pill and pillFilled variants a gradient treatment; a gradient reaches
|
|
11
|
+
the button through applyCustomGradient filling the primary slot now, and the base rules
|
|
12
|
+
already paint backgrounds from that slot.
|
|
13
|
+
|
|
14
|
+
`disabledTooltip` and `disabledTooltipPosition` are here, and they wrap rather than
|
|
15
|
+
decorate: a disabled <button> dispatches no mouse events and lets none bubble, so a
|
|
16
|
+
tooltip hung on the button itself would never open. KDLS solves it the same way — the
|
|
17
|
+
tooltip's handlers sit on a wrapper and the button inside it is given
|
|
18
|
+
`pointer-events: none`, which is what lets the pointer reach the wrapper at all.
|
|
19
|
+
|
|
20
|
+
Touch is still unanswered for tooltips in general (see sds-tooltip), so on a phone a
|
|
21
|
+
disabled button still explains itself only to a screen reader, through aria-describedby.
|
|
22
|
+
|
|
23
|
+
The spinner track follows --color-on-primary at 30% instead of a hardcoded white. KDLS
|
|
24
|
+
wrote rgba(255,255,255,.30), which is invisible on a light primary — where
|
|
25
|
+
--color-on-primary is black. -->
|
|
26
|
+
|
|
27
|
+
import { assertPlacement } from "../Floating/floating-position.js";
|
|
28
|
+
import { assertButtonVariant, assertButtonSize, assertButtonWidth, assertButtonType }
|
|
29
|
+
from "./button-variants.js";
|
|
30
|
+
|
|
31
|
+
class {
|
|
32
|
+
handleClick(event) {
|
|
33
|
+
const { disabled, isLoading, onClick } = this.input;
|
|
34
|
+
// `disabled` is already enforced by the browser; this guards the loading state,
|
|
35
|
+
// which stays focusable and keeps its shape.
|
|
36
|
+
if (disabled || isLoading) {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
onClick?.(event);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
$ {
|
|
45
|
+
const {
|
|
46
|
+
label,
|
|
47
|
+
variant = "primary",
|
|
48
|
+
size = "md",
|
|
49
|
+
width = "hug",
|
|
50
|
+
type = "button",
|
|
51
|
+
iconLeft,
|
|
52
|
+
iconRight,
|
|
53
|
+
isLoading = false,
|
|
54
|
+
disabled = false,
|
|
55
|
+
disabledTooltip,
|
|
56
|
+
disabledTooltipPosition = "top",
|
|
57
|
+
class: extraClass = "",
|
|
58
|
+
} = input;
|
|
59
|
+
|
|
60
|
+
assertPlacement(disabledTooltipPosition);
|
|
61
|
+
|
|
62
|
+
assertButtonVariant(variant);
|
|
63
|
+
assertButtonSize(size);
|
|
64
|
+
assertButtonWidth(width);
|
|
65
|
+
assertButtonType(type);
|
|
66
|
+
|
|
67
|
+
const ariaLabel = input["aria-label"] ?? input.ariaLabel;
|
|
68
|
+
if (!label && !ariaLabel) {
|
|
69
|
+
throw new Error('sds-button needs a `label`, or an `aria-label` when the button shows only an icon.');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const renderable = (value) => (value && value.renderBody) || value;
|
|
73
|
+
const loading = isLoading && !disabled;
|
|
74
|
+
|
|
75
|
+
// The explanation only appears when there is something to explain.
|
|
76
|
+
const explains = Boolean(disabledTooltip) && disabled;
|
|
77
|
+
const wrapperClass = [
|
|
78
|
+
"sds-button__tooltip-wrapper",
|
|
79
|
+
width === "fill" ? "sds-button__tooltip-wrapper--full" : "",
|
|
80
|
+
].filter(Boolean).join(" ");
|
|
81
|
+
|
|
82
|
+
const classes = [
|
|
83
|
+
"sds-button",
|
|
84
|
+
`sds-button--${variant}`,
|
|
85
|
+
`sds-button--${size}`,
|
|
86
|
+
width === "fill" ? "sds-button--full" : "",
|
|
87
|
+
loading ? "sds-button--loading" : "",
|
|
88
|
+
extraClass,
|
|
89
|
+
].filter(Boolean).join(" ");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
<macro|{ }| name="theButton">
|
|
93
|
+
<button
|
|
94
|
+
type=type
|
|
95
|
+
class=classes
|
|
96
|
+
disabled=(disabled || null)
|
|
97
|
+
aria-label=ariaLabel
|
|
98
|
+
aria-disabled=(disabled ? "true" : null)
|
|
99
|
+
aria-busy=(loading ? "true" : null)
|
|
100
|
+
on-click("handleClick")
|
|
101
|
+
>
|
|
102
|
+
<if(loading)>
|
|
103
|
+
<sds-spinner size="sm" decorative/>
|
|
104
|
+
</if>
|
|
105
|
+
|
|
106
|
+
<if(iconLeft)>
|
|
107
|
+
<span class="sds-button__icon sds-button__icon--left" aria-hidden="true">
|
|
108
|
+
<sds-icon>
|
|
109
|
+
<${renderable(iconLeft)}/>
|
|
110
|
+
</sds-icon>
|
|
111
|
+
</span>
|
|
112
|
+
</if>
|
|
113
|
+
|
|
114
|
+
<if(label)>
|
|
115
|
+
<span class="sds-button__label">${label}</span>
|
|
116
|
+
</if>
|
|
117
|
+
|
|
118
|
+
<if(iconRight)>
|
|
119
|
+
<span class="sds-button__icon sds-button__icon--right" aria-hidden="true">
|
|
120
|
+
<sds-icon>
|
|
121
|
+
<${renderable(iconRight)}/>
|
|
122
|
+
</sds-icon>
|
|
123
|
+
</span>
|
|
124
|
+
</if>
|
|
125
|
+
</button>
|
|
126
|
+
</macro>
|
|
127
|
+
|
|
128
|
+
<!-- The tooltip wraps, it does not decorate. A disabled <button> dispatches no mouse
|
|
129
|
+
events and lets none bubble, so handlers on the button itself would never fire; the
|
|
130
|
+
wrapper receives them instead, and Button.css gives the disabled button
|
|
131
|
+
`pointer-events: none` so the pointer reaches the wrapper at all. -->
|
|
132
|
+
<if(explains)>
|
|
133
|
+
<sds-tooltip content=disabledTooltip placement=disabledTooltipPosition class=wrapperClass>
|
|
134
|
+
<theButton/>
|
|
135
|
+
</sds-tooltip>
|
|
136
|
+
</if>
|
|
137
|
+
<else>
|
|
138
|
+
<theButton/>
|
|
139
|
+
</else>
|