@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,253 @@
|
|
|
1
|
+
/* SDS ColorPicker.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/ColorPicker/ColorPicker.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-colorpicker__trigger--open
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* Five values snapped to the system.
|
|
10
|
+
|
|
11
|
+
The opacity slider's fallback colour was #298EE6 — Kenlo blue, written into a stylesheet
|
|
12
|
+
that is meant to carry no brand at all, and the only reason it is visible is that it
|
|
13
|
+
shows for the one frame before --cp-hex is set. It reads --color-neutral-50 now: a colour
|
|
14
|
+
with no opinion, which is what a slider with no colour yet should show.
|
|
15
|
+
|
|
16
|
+
The chequerboard behind the opacity slider was #ccc on white. It is the universal way of
|
|
17
|
+
drawing "there is nothing here", so it stays a chequerboard, but out of the neutral ramp.
|
|
18
|
+
|
|
19
|
+
The three shadows were rgba literals; two are opacity steps and the panel's is
|
|
20
|
+
--shadow-drop-md, which is the same shadow the other floating panels use. *//* ============================================================
|
|
21
|
+
SDS ColorPicker
|
|
22
|
+
============================================================ */
|
|
23
|
+
|
|
24
|
+
/* ── Wrapper ── */
|
|
25
|
+
.sds-colorpicker {
|
|
26
|
+
display: inline-block;
|
|
27
|
+
}
|
|
28
|
+
.sds-colorpicker--fill {
|
|
29
|
+
display: block;
|
|
30
|
+
width: 100%;
|
|
31
|
+
}
|
|
32
|
+
.sds-colorpicker--fill .sds-floating,
|
|
33
|
+
.sds-colorpicker--fill .sds-colorpicker__trigger {
|
|
34
|
+
width: 100%;
|
|
35
|
+
}
|
|
36
|
+
/* ── Trigger (Input-like) ── */
|
|
37
|
+
.sds-colorpicker__trigger {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: var(--spacing-3);
|
|
41
|
+
height: 56px;
|
|
42
|
+
padding: 0 var(--spacing-3);
|
|
43
|
+
background: var(--component-bg-color);
|
|
44
|
+
border: 1px solid var(--border-interactive-color);
|
|
45
|
+
border-radius: var(--radius-md);
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
font-family: var(--font-family-base);
|
|
48
|
+
transition: border-color 120ms ease;
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
outline: none;
|
|
51
|
+
}
|
|
52
|
+
/* ── Disabled ── */
|
|
53
|
+
.sds-colorpicker__trigger--disabled {
|
|
54
|
+
opacity: 0.5;
|
|
55
|
+
cursor: not-allowed;
|
|
56
|
+
}
|
|
57
|
+
.sds-colorpicker__trigger:hover:not(.sds-colorpicker__trigger--disabled),
|
|
58
|
+
.sds-colorpicker__trigger--open,
|
|
59
|
+
.sds-colorpicker__trigger:focus-visible {
|
|
60
|
+
border-color: var(--color-primary-50-solid);
|
|
61
|
+
}
|
|
62
|
+
.sds-colorpicker__trigger--open,
|
|
63
|
+
.sds-colorpicker__trigger:focus-visible {
|
|
64
|
+
box-shadow: var(--focus-ring);
|
|
65
|
+
}
|
|
66
|
+
.sds-colorpicker__swatch {
|
|
67
|
+
width: 24px;
|
|
68
|
+
height: 24px;
|
|
69
|
+
border-radius: var(--radius-sm);
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
border: 1px solid var(--border-interactive-color);
|
|
72
|
+
}
|
|
73
|
+
.sds-colorpicker__field {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: var(--spacing-0-5);
|
|
77
|
+
min-width: 0;
|
|
78
|
+
}
|
|
79
|
+
.sds-colorpicker__hex {
|
|
80
|
+
font-size: var(--font-size-body-md);
|
|
81
|
+
line-height: var(--lh-body-md);
|
|
82
|
+
color: var(--body-color);
|
|
83
|
+
font-weight: var(--font-weight-medium);
|
|
84
|
+
}
|
|
85
|
+
/* ── Panel ── */
|
|
86
|
+
.sds-colorpicker__panel {
|
|
87
|
+
width: 280px;
|
|
88
|
+
background: var(--component-bg-color);
|
|
89
|
+
border: 1px solid var(--border-interactive-color);
|
|
90
|
+
border-radius: var(--radius-md);
|
|
91
|
+
box-shadow: var(--shadow-drop-md);
|
|
92
|
+
padding: var(--spacing-3);
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
gap: var(--spacing-3);
|
|
96
|
+
box-sizing: border-box;
|
|
97
|
+
}
|
|
98
|
+
/* ── Color canvas ── */
|
|
99
|
+
.sds-colorpicker__canvas {
|
|
100
|
+
position: relative;
|
|
101
|
+
width: 100%;
|
|
102
|
+
height: 160px;
|
|
103
|
+
border-radius: var(--radius-sm);
|
|
104
|
+
cursor: crosshair;
|
|
105
|
+
background:
|
|
106
|
+
linear-gradient(to right, var(--color-white), transparent),
|
|
107
|
+
linear-gradient(to bottom, transparent, var(--color-black)),
|
|
108
|
+
hsl(var(--cp-hue, 0), 100%, 50%);
|
|
109
|
+
user-select: none;
|
|
110
|
+
}
|
|
111
|
+
.sds-colorpicker__handle {
|
|
112
|
+
position: absolute;
|
|
113
|
+
width: 14px;
|
|
114
|
+
height: 14px;
|
|
115
|
+
border-radius: 50%;
|
|
116
|
+
border: 2px solid var(--color-white);
|
|
117
|
+
box-shadow: 0 1px 4px var(--color-opacity-40);
|
|
118
|
+
transform: translate(-50%, -50%);
|
|
119
|
+
pointer-events: none;
|
|
120
|
+
}
|
|
121
|
+
/* ── Slider row: IconButton + stacked sliders ── */
|
|
122
|
+
.sds-colorpicker__slider-row {
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
gap: var(--spacing-4); /* 16px between eyedropper and sliders */
|
|
126
|
+
}
|
|
127
|
+
/* ── Stacked sliders column ── */
|
|
128
|
+
.sds-colorpicker__sliders {
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: column;
|
|
131
|
+
gap: var(--spacing-2);
|
|
132
|
+
flex: 1;
|
|
133
|
+
}
|
|
134
|
+
/* ── Individual slider ── */
|
|
135
|
+
.sds-colorpicker__slider {
|
|
136
|
+
position: relative;
|
|
137
|
+
width: 100%;
|
|
138
|
+
height: 12px;
|
|
139
|
+
border-radius: var(--radius-full);
|
|
140
|
+
cursor: pointer;
|
|
141
|
+
user-select: none;
|
|
142
|
+
}
|
|
143
|
+
.sds-colorpicker__slider--hue {
|
|
144
|
+
background: linear-gradient(to right,
|
|
145
|
+
hsl(0, 100%, 50%), hsl(30, 100%, 50%), hsl(60, 100%, 50%),
|
|
146
|
+
hsl(120, 100%, 50%), hsl(180, 100%, 50%), hsl(240, 100%, 50%),
|
|
147
|
+
hsl(300, 100%, 50%), hsl(360, 100%, 50%)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
.sds-colorpicker__slider--opacity {
|
|
151
|
+
background:
|
|
152
|
+
linear-gradient(to right, transparent, var(--cp-hex, var(--color-neutral-50))),
|
|
153
|
+
repeating-conic-gradient(var(--color-neutral-30) 0% 25%, var(--component-bg-color) 0% 50%) 0 0 / 8px 8px;
|
|
154
|
+
}
|
|
155
|
+
.sds-colorpicker__slider-thumb {
|
|
156
|
+
position: absolute;
|
|
157
|
+
top: 50%;
|
|
158
|
+
width: 16px;
|
|
159
|
+
height: 16px;
|
|
160
|
+
border-radius: 50%;
|
|
161
|
+
background: var(--color-white);
|
|
162
|
+
border: 2px solid var(--color-white);
|
|
163
|
+
box-shadow: 0 1px 4px var(--color-opacity-30);
|
|
164
|
+
transform: translate(-50%, -50%);
|
|
165
|
+
pointer-events: none;
|
|
166
|
+
}
|
|
167
|
+
/* ── R G B [A] inputs ── */
|
|
168
|
+
.sds-colorpicker__input-group {
|
|
169
|
+
display: grid;
|
|
170
|
+
grid-template-columns: repeat(3, 1fr);
|
|
171
|
+
gap: var(--spacing-1);
|
|
172
|
+
}
|
|
173
|
+
.sds-colorpicker__input-group--rgba {
|
|
174
|
+
grid-template-columns: repeat(4, 1fr);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Divergence: the fields inside these groups carry a tighter horizontal padding than a
|
|
178
|
+
field anywhere else.
|
|
179
|
+
|
|
180
|
+
A field is 16px in from each edge, which is right when it is the width of a form and
|
|
181
|
+
wrong here: four of them share a 254px panel, so each is 61px wide and 32 of those are
|
|
182
|
+
padding. "128" did not fit — measured, it rendered as "12" and a clipped glyph. KDLS
|
|
183
|
+
has the same four columns at the same width and the same clipping.
|
|
184
|
+
|
|
185
|
+
The value is what this control exists to show, so the padding gives way to it. */
|
|
186
|
+
.sds-colorpicker__input-group .sds-input,
|
|
187
|
+
.sds-colorpicker__panel > .sds-input-box .sds-input {
|
|
188
|
+
padding-left: var(--spacing-2);
|
|
189
|
+
padding-right: var(--spacing-2);
|
|
190
|
+
}
|
|
191
|
+
/* ── Apply button ── */
|
|
192
|
+
.sds-colorpicker__apply {
|
|
193
|
+
width: 100%;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* The trigger is a <button>, which brings the browser's own control chrome. KDLS uses a
|
|
197
|
+
div with role="button" and does not need this — and cannot be opened by keyboard.
|
|
198
|
+
|
|
199
|
+
It resets only what the browser supplies and the design does not: the system font, the
|
|
200
|
+
centred text, the inherited colour. It must NOT reset border or background, which the
|
|
201
|
+
rule above sets on purpose — `button.sds-…` outranks `.sds-…`, so `border: 0` here beat
|
|
202
|
+
the 1px stroke that makes this read as a field, and the trigger rendered with no outline
|
|
203
|
+
at all. The same mistake was made once before, in the Select's options, and the rule
|
|
204
|
+
that came out of it is this: a chrome reset names the properties the design is silent
|
|
205
|
+
about, and nothing else. */
|
|
206
|
+
button.sds-colorpicker__trigger {
|
|
207
|
+
appearance: none;
|
|
208
|
+
font: inherit;
|
|
209
|
+
color: inherit;
|
|
210
|
+
text-align: left;
|
|
211
|
+
cursor: pointer;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
button.sds-colorpicker__trigger:disabled {
|
|
215
|
+
cursor: not-allowed;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* The canvas and the sliders take focus now, so they have to show it. */
|
|
219
|
+
.sds-colorpicker__canvas:focus-visible,
|
|
220
|
+
.sds-colorpicker__slider:focus-visible {
|
|
221
|
+
outline: var(--focus-ring-width) solid var(--focus-stroke-color);
|
|
222
|
+
outline-offset: 2px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* ── Overlay ──
|
|
226
|
+
The panel centred over the page rather than anchored to its trigger. Used where
|
|
227
|
+
anchoring cannot work: inside another panel, where it would land on top of the panel it
|
|
228
|
+
came from, and on a phone, where there is no room beside a trigger. */
|
|
229
|
+
.sds-colorpicker__backdrop {
|
|
230
|
+
position: fixed;
|
|
231
|
+
inset: 0;
|
|
232
|
+
z-index: var(--z-overlay);
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
justify-content: center;
|
|
236
|
+
padding: var(--spacing-4);
|
|
237
|
+
/* The scrim the Modal uses, and its dark-theme twin: --color-opacity-* inverts, so a
|
|
238
|
+
backdrop written with it goes white on a dark page. */
|
|
239
|
+
background: var(--color-opacity-50);
|
|
240
|
+
overflow-y: auto;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
[data-theme="dark"] .sds-colorpicker__backdrop {
|
|
244
|
+
background: var(--color-scrim);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Driven entirely from outside, with no trigger of its own: the root still has to be in
|
|
248
|
+
the tree — it is what holds the overlay — but it must not take up a line while the
|
|
249
|
+
overlay is closed. `display: contents` leaves the element addressable and gives its box
|
|
250
|
+
away. */
|
|
251
|
+
.sds-colorpicker--headless {
|
|
252
|
+
display: contents;
|
|
253
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colour conversions.
|
|
3
|
+
*
|
|
4
|
+
* Ported verbatim in behaviour from kdls-design-system v2.5.1 (0f3edf8)
|
|
5
|
+
* components/ColorPicker/ColorPicker.tsx, where the six functions sit at module scope.
|
|
6
|
+
* Pulled into their own file because they are pure, because a round trip through HSV and
|
|
7
|
+
* back is exactly the kind of arithmetic that drifts by one, and because the picker's
|
|
8
|
+
* default colour was Kenlo blue written as three numbers — a brand value in a file that is
|
|
9
|
+
* supposed to carry none.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** KDLS falls back to [41, 142, 230] — #298EE6, Kenlo blue. SDS has no brand to fall back
|
|
13
|
+
* to, so an unreadable value starts the picker at the middle of the neutral ramp: a
|
|
14
|
+
* colour with no opinion, which is what a picker with no value should show. */
|
|
15
|
+
export const FALLBACK_RGB = [128, 128, 128];
|
|
16
|
+
|
|
17
|
+
export function hsvToRgb(h, s, v) {
|
|
18
|
+
h /= 360; s /= 100; v /= 100;
|
|
19
|
+
let r = 0;
|
|
20
|
+
let g = 0;
|
|
21
|
+
let b = 0;
|
|
22
|
+
const i = Math.floor(h * 6);
|
|
23
|
+
const f = h * 6 - i;
|
|
24
|
+
const p = v * (1 - s);
|
|
25
|
+
const q = v * (1 - f * s);
|
|
26
|
+
const t = v * (1 - (1 - f) * s);
|
|
27
|
+
switch (i % 6) {
|
|
28
|
+
case 0: r = v; g = t; b = p; break;
|
|
29
|
+
case 1: r = q; g = v; b = p; break;
|
|
30
|
+
case 2: r = p; g = v; b = t; break;
|
|
31
|
+
case 3: r = p; g = q; b = v; break;
|
|
32
|
+
case 4: r = t; g = p; b = v; break;
|
|
33
|
+
case 5: r = v; g = p; b = q; break;
|
|
34
|
+
default: break;
|
|
35
|
+
}
|
|
36
|
+
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function rgbToHex(r, g, b) {
|
|
40
|
+
return `#${[r, g, b].map((x) => x.toString(16).padStart(2, '0').toUpperCase()).join('')}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function hexToRgb(hex) {
|
|
44
|
+
if (typeof hex !== 'string') return null;
|
|
45
|
+
const clean = hex.replace('#', '');
|
|
46
|
+
if (clean.length !== 6 && clean.length !== 8) return null;
|
|
47
|
+
// parseInt stops at the first bad character and returns what it read, so "gggggg" would
|
|
48
|
+
// pass a NaN check on a prefix. The shape is checked before the value.
|
|
49
|
+
if (!/^[0-9a-f]+$/i.test(clean)) return null;
|
|
50
|
+
const n = parseInt(clean.slice(0, 6), 16);
|
|
51
|
+
if (Number.isNaN(n)) return null;
|
|
52
|
+
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The alpha of an 8-digit hex, as a percentage. Null when there is none to read. */
|
|
56
|
+
export function hexToAlpha(hex) {
|
|
57
|
+
if (typeof hex !== 'string') return null;
|
|
58
|
+
const clean = hex.replace('#', '');
|
|
59
|
+
if (clean.length !== 8) return null;
|
|
60
|
+
if (!/^[0-9a-f]+$/i.test(clean)) return null;
|
|
61
|
+
const a = parseInt(clean.slice(6, 8), 16);
|
|
62
|
+
return Number.isNaN(a) ? null : Math.round((a / 255) * 100);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function alphaToHex(opacity) {
|
|
66
|
+
return Math.round((opacity / 100) * 255).toString(16).padStart(2, '0').toUpperCase();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function rgbToHsv(r, g, b) {
|
|
70
|
+
r /= 255; g /= 255; b /= 255;
|
|
71
|
+
const max = Math.max(r, g, b);
|
|
72
|
+
const min = Math.min(r, g, b);
|
|
73
|
+
const d = max - min;
|
|
74
|
+
let h = 0;
|
|
75
|
+
const s = max === 0 ? 0 : d / max;
|
|
76
|
+
const v = max;
|
|
77
|
+
if (max !== min) {
|
|
78
|
+
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
79
|
+
else if (max === g) h = ((b - r) / d + 2) / 6;
|
|
80
|
+
else h = ((r - g) / d + 4) / 6;
|
|
81
|
+
}
|
|
82
|
+
// Unrounded, on purpose.
|
|
83
|
+
//
|
|
84
|
+
// Saturation and value used to be rounded to whole percents here, and the picker keeps
|
|
85
|
+
// its colour as HSV — so every RGB value made a round trip through a 0–100 integer that
|
|
86
|
+
// has nowhere near the resolution of 0–255. Measured: 118 of the 256 possible values of
|
|
87
|
+
// one channel came back different, each off by one. Typing 200 into the R field gave
|
|
88
|
+
// 199, and the field appeared to fight whoever was typing in it.
|
|
89
|
+
//
|
|
90
|
+
// Nobody had seen it because the R, G, B and HEX fields were inert until this commit:
|
|
91
|
+
// they were wired to an `onInput` prop that `sds-input` does not accept.
|
|
92
|
+
//
|
|
93
|
+
// Rounding belongs where a number is shown, not where it is stored.
|
|
94
|
+
return [h * 360, s * 100, v * 100];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The hex a picker should open on, given whatever it was handed. */
|
|
98
|
+
export function startingRgb(value) {
|
|
99
|
+
return hexToRgb(value ?? '') ?? [...FALLBACK_RGB];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function startingAlpha(value) {
|
|
103
|
+
return hexToAlpha(value ?? '') ?? 100;
|
|
104
|
+
}
|