@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,85 @@
|
|
|
1
|
+
/* SDS IconButton.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/IconButton/IconButton.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-icon-button--primary:not(:disabled):not([aria-disabled="true"]) .sds-icon-button__icon svg rect
|
|
7
|
+
*//* ============================================================
|
|
8
|
+
SDS IconButton
|
|
9
|
+
Sizes: 32 | 40 | 48px
|
|
10
|
+
Variants: primary (colored, default) | neutral (gray)
|
|
11
|
+
============================================================ */
|
|
12
|
+
|
|
13
|
+
.sds-icon-button {
|
|
14
|
+
position: relative;
|
|
15
|
+
display: inline-flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
border: none;
|
|
19
|
+
background: transparent;
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
-webkit-font-smoothing: antialiased;
|
|
22
|
+
/* corner-radius-small = 8px, per Figma spec */
|
|
23
|
+
border-radius: var(--radius-sm);
|
|
24
|
+
transition: background-color 120ms ease;
|
|
25
|
+
padding: 0;
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
outline: none;
|
|
28
|
+
}
|
|
29
|
+
.sds-icon-button:disabled,
|
|
30
|
+
.sds-icon-button[aria-disabled="true"] {
|
|
31
|
+
cursor: not-allowed;
|
|
32
|
+
}
|
|
33
|
+
.sds-icon-button--loading {
|
|
34
|
+
cursor: wait;
|
|
35
|
+
}
|
|
36
|
+
/* ── Sizes ── */
|
|
37
|
+
.sds-icon-button--sm {
|
|
38
|
+
width: 32px;
|
|
39
|
+
height: 32px;
|
|
40
|
+
}
|
|
41
|
+
.sds-icon-button--md {
|
|
42
|
+
width: 40px;
|
|
43
|
+
height: 40px;
|
|
44
|
+
}
|
|
45
|
+
.sds-icon-button--lg {
|
|
46
|
+
width: 48px;
|
|
47
|
+
height: 48px;
|
|
48
|
+
}
|
|
49
|
+
/* ── Icon size ── */
|
|
50
|
+
.sds-icon-button__icon {
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
justify-content: center;
|
|
54
|
+
font-size: 24px;
|
|
55
|
+
line-height: 1;
|
|
56
|
+
position: relative;
|
|
57
|
+
}
|
|
58
|
+
/* Icon is always 24px regardless of button size (sm/md/lg) */
|
|
59
|
+
|
|
60
|
+
/* ── Hover & Pressed backgrounds ──
|
|
61
|
+
Figma uses opacity-05 / opacity-10 tokens (rgba 26,26,26)
|
|
62
|
+
Same for both primary (on) and neutral (off) variants. */
|
|
63
|
+
.sds-icon-button:hover:not(:disabled):not(.sds-icon-button--loading) {
|
|
64
|
+
background-color: var(--color-opacity-05);
|
|
65
|
+
}
|
|
66
|
+
.sds-icon-button:active:not(:disabled):not(.sds-icon-button--loading) {
|
|
67
|
+
background-color: var(--color-opacity-10);
|
|
68
|
+
}
|
|
69
|
+
/* ── Primary (default): colored icon ── */
|
|
70
|
+
.sds-icon-button--primary .sds-icon-button__icon {
|
|
71
|
+
color: var(--color-primary-50-solid);
|
|
72
|
+
}
|
|
73
|
+
/* ── Neutral (off): gray icon ── */
|
|
74
|
+
.sds-icon-button--neutral .sds-icon-button__icon {
|
|
75
|
+
color: var(--color-neutral-70);
|
|
76
|
+
}
|
|
77
|
+
/* ── Focus ring ── */
|
|
78
|
+
.sds-icon-button:focus-visible {
|
|
79
|
+
box-shadow: var(--focus-ring);
|
|
80
|
+
}
|
|
81
|
+
/* ── Disabled — always last, overrides primary/neutral icon color via cascade order ── */
|
|
82
|
+
.sds-icon-button:disabled .sds-icon-button__icon,
|
|
83
|
+
.sds-icon-button[aria-disabled="true"] .sds-icon-button__icon {
|
|
84
|
+
color: var(--color-neutral-40);
|
|
85
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The IconButton vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/IconButton/IconButton.tsx.
|
|
5
|
+
* Divergence: none. `primary` was already the slot, not a Kenlo value.
|
|
6
|
+
*/
|
|
7
|
+
export const ICON_BUTTON_VARIANTS = ['primary', 'neutral'];
|
|
8
|
+
export const ICON_BUTTON_SIZES = ['sm', 'md', 'lg'];
|
|
9
|
+
|
|
10
|
+
function assertOneOf(label, value, allowed) {
|
|
11
|
+
if (!allowed.includes(value)) {
|
|
12
|
+
throw new Error(`Unknown icon button ${label}: "${value}". Allowed: ${allowed.join(', ')}`);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const assertIconButtonVariant = (v) => assertOneOf('variant', v, ICON_BUTTON_VARIANTS);
|
|
18
|
+
export const assertIconButtonSize = (v) => assertOneOf('size', v, ICON_BUTTON_SIZES);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<!-- sds-icon-button — ported from kdls-design-system v2.5.1 (0f3edf8)
|
|
2
|
+
components/IconButton/IconButton.tsx.
|
|
3
|
+
|
|
4
|
+
This component hydrates, and unlike the Badge that is not a close call: a button whose
|
|
5
|
+
purpose is to be clicked has to carry its listener, and Marko 5 drops a listener silently
|
|
6
|
+
on a component that does not hydrate. Its input is an aria-label and three flags, so the
|
|
7
|
+
serialised payload is small — the cost scales with what you put in.
|
|
8
|
+
|
|
9
|
+
Divergences:
|
|
10
|
+
|
|
11
|
+
The inline <linearGradient> defs are gone. They existed so the lya scheme could fill the
|
|
12
|
+
glyph with a gradient through `fill: url(#...)`, and that scheme does not exist here. A
|
|
13
|
+
gradient reaches the icon through applyCustomGradient and the primary slot instead.
|
|
14
|
+
|
|
15
|
+
`aria-label` is required and validated. There is no way to derive a label from an
|
|
16
|
+
arbitrary glyph, and an unlabelled icon button is invisible to a screen reader — the one
|
|
17
|
+
failure this component can have that nobody sees. -->
|
|
18
|
+
|
|
19
|
+
import { assertIconButtonVariant, assertIconButtonSize } from "./icon-button-variants.js";
|
|
20
|
+
import { assertButtonType } from "../Button/button-variants.js";
|
|
21
|
+
|
|
22
|
+
class {
|
|
23
|
+
handleClick(event) {
|
|
24
|
+
const { disabled, isLoading, onClick } = this.input;
|
|
25
|
+
// The native `disabled` already blocks the click; this guards the loading state,
|
|
26
|
+
// which must stay focusable and keep its shape.
|
|
27
|
+
if (disabled || isLoading) {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
onClick?.(event);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
$ {
|
|
36
|
+
const {
|
|
37
|
+
icon,
|
|
38
|
+
variant = "primary",
|
|
39
|
+
size = "sm",
|
|
40
|
+
isLoading = false,
|
|
41
|
+
disabled = false,
|
|
42
|
+
type = "button",
|
|
43
|
+
class: extraClass = "",
|
|
44
|
+
} = input;
|
|
45
|
+
|
|
46
|
+
// Marko camelCases a hyphenated attribute written on a component tag, capitalising only
|
|
47
|
+
// the letter after the hyphen — see foundations/attrs.js. Applying the rule beats
|
|
48
|
+
// remembering the spelling: aria-haspopup arrives as `ariaHaspopup`.
|
|
49
|
+
assertButtonType(type);
|
|
50
|
+
|
|
51
|
+
const aria = (name) => input[`aria-${name}`]
|
|
52
|
+
?? input[`aria${name[0].toUpperCase()}${name.slice(1)}`]
|
|
53
|
+
?? null;
|
|
54
|
+
|
|
55
|
+
const label = aria("label");
|
|
56
|
+
// A disclosure — a button that opens a panel — has to say so, and say whether the panel
|
|
57
|
+
// is open. Without these the header's notification and product buttons announce nothing
|
|
58
|
+
// about what they control, which is KDLS's behaviour.
|
|
59
|
+
const ariaHasPopup = aria("haspopup");
|
|
60
|
+
const ariaExpanded = aria("expanded");
|
|
61
|
+
const ariaControls = aria("controls");
|
|
62
|
+
if (!label) {
|
|
63
|
+
throw new Error('sds-icon-button needs an `aria-label` — a glyph carries no name.');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
assertIconButtonVariant(variant);
|
|
67
|
+
assertIconButtonSize(size);
|
|
68
|
+
|
|
69
|
+
const renderable = (value) => (value && value.renderBody) || value;
|
|
70
|
+
const loading = isLoading && !disabled;
|
|
71
|
+
|
|
72
|
+
const classes = [
|
|
73
|
+
"sds-icon-button",
|
|
74
|
+
`sds-icon-button--${size}`,
|
|
75
|
+
`sds-icon-button--${variant}`,
|
|
76
|
+
loading ? "sds-icon-button--loading" : "",
|
|
77
|
+
extraClass,
|
|
78
|
+
].filter(Boolean).join(" ");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
<button
|
|
82
|
+
type=type
|
|
83
|
+
class=classes
|
|
84
|
+
disabled=(disabled || null)
|
|
85
|
+
aria-label=label
|
|
86
|
+
aria-haspopup=ariaHasPopup
|
|
87
|
+
aria-expanded=ariaExpanded
|
|
88
|
+
aria-controls=ariaControls
|
|
89
|
+
aria-disabled=(disabled ? "true" : null)
|
|
90
|
+
aria-busy=(loading ? "true" : null)
|
|
91
|
+
on-click("handleClick")
|
|
92
|
+
>
|
|
93
|
+
<if(loading)>
|
|
94
|
+
<sds-spinner size="sm" decorative/>
|
|
95
|
+
</if>
|
|
96
|
+
<span class="sds-icon-button__icon" aria-hidden="true">
|
|
97
|
+
<if(!loading)>
|
|
98
|
+
<sds-icon>
|
|
99
|
+
<${renderable(icon)}/>
|
|
100
|
+
</sds-icon>
|
|
101
|
+
</if>
|
|
102
|
+
</span>
|
|
103
|
+
</button>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* SDS Incrementer.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Incrementer/Incrementer.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-incrementer:hover:not(.sds-incrementer--disabled)
|
|
7
|
+
*//* ============================================================
|
|
8
|
+
SDS Incrementer
|
|
9
|
+
Height: 40px (equal to Pill and Toggle)
|
|
10
|
+
States: enabled | hover | disabled (per-button)
|
|
11
|
+
Theme: token-based via [data-theme="dark"]
|
|
12
|
+
============================================================ */
|
|
13
|
+
|
|
14
|
+
.sds-incrementer {
|
|
15
|
+
display: inline-flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
align-self: flex-start;
|
|
18
|
+
height: 40px;
|
|
19
|
+
gap: 0;
|
|
20
|
+
border-radius: var(--radius-full);
|
|
21
|
+
border: 1px solid var(--border-interactive-color);
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
font-family: var(--font-family-base);
|
|
24
|
+
background: var(--component-bg-color);
|
|
25
|
+
color: var(--body-color);
|
|
26
|
+
transition: border-color 120ms ease;
|
|
27
|
+
}
|
|
28
|
+
.sds-incrementer:hover:not(.sds-incrementer--disabled) {
|
|
29
|
+
border-color: var(--color-primary-50-solid);
|
|
30
|
+
}
|
|
31
|
+
.sds-incrementer--disabled {
|
|
32
|
+
background: var(--color-neutral-20);
|
|
33
|
+
border-color: var(--border-static-color);
|
|
34
|
+
color: var(--color-neutral-40);
|
|
35
|
+
cursor: not-allowed;
|
|
36
|
+
}
|
|
37
|
+
.sds-incrementer__btn:focus-visible {
|
|
38
|
+
outline: none;
|
|
39
|
+
box-shadow: var(--focus-ring);
|
|
40
|
+
border-radius: var(--radius-full);
|
|
41
|
+
}
|
|
42
|
+
/* ──────────────────────────────────────────────
|
|
43
|
+
BUTTONS
|
|
44
|
+
────────────────────────────────────────────── */
|
|
45
|
+
.sds-incrementer__btn {
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
width: 40px;
|
|
50
|
+
height: 40px;
|
|
51
|
+
border: none;
|
|
52
|
+
background: transparent;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
color: inherit;
|
|
55
|
+
flex-shrink: 0;
|
|
56
|
+
transition: background-color 120ms ease;
|
|
57
|
+
outline: none;
|
|
58
|
+
}
|
|
59
|
+
.sds-incrementer__btn:hover:not(:disabled) {
|
|
60
|
+
background: var(--color-neutral-20);
|
|
61
|
+
}
|
|
62
|
+
.sds-incrementer__btn:active:not(:disabled) {
|
|
63
|
+
background: var(--color-neutral-30);
|
|
64
|
+
}
|
|
65
|
+
.sds-incrementer__btn:disabled {
|
|
66
|
+
cursor: not-allowed;
|
|
67
|
+
}
|
|
68
|
+
/* ──────────────────────────────────────────────
|
|
69
|
+
VALUE DISPLAY
|
|
70
|
+
────────────────────────────────────────────── */
|
|
71
|
+
.sds-incrementer__value {
|
|
72
|
+
min-width: 36px;
|
|
73
|
+
text-align: center;
|
|
74
|
+
font-size: var(--font-size-body-md);
|
|
75
|
+
font-weight: var(--font-weight-medium);
|
|
76
|
+
line-height: var(--lh-body-md);
|
|
77
|
+
padding: 0 var(--spacing-1);
|
|
78
|
+
user-select: none;
|
|
79
|
+
}
|
|
80
|
+
/* ──────────────────────────────────────────────
|
|
81
|
+
DARK MODE
|
|
82
|
+
────────────────────────────────────────────── */
|
|
83
|
+
|
|
84
|
+
[data-theme="dark"] .sds-incrementer__btn:hover:not(:disabled) {
|
|
85
|
+
background: var(--color-neutral-30);
|
|
86
|
+
}
|
|
87
|
+
[data-theme="dark"] .sds-incrementer__btn:active:not(:disabled) {
|
|
88
|
+
background: var(--color-neutral-40);
|
|
89
|
+
}
|
|
90
|
+
[data-theme="dark"] .sds-incrementer--disabled {
|
|
91
|
+
background: var(--color-neutral-30);
|
|
92
|
+
border-color: var(--border-interactive-color);
|
|
93
|
+
color: var(--color-neutral-40);
|
|
94
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<!-- sds-incrementer — ported from kdls-design-system v2.5.1 (0f3edf8)
|
|
2
|
+
components/Incrementer/Incrementer.tsx.
|
|
3
|
+
|
|
4
|
+
Minus, a number, plus. It hydrates because the buttons have to do something, but it holds
|
|
5
|
+
no state: the value comes from the caller and goes back through onChange, which is what
|
|
6
|
+
lets it sit inside a form that already owns that number.
|
|
7
|
+
|
|
8
|
+
Divergence: the value is a <output> with aria-live, so a screen reader hears the new
|
|
9
|
+
number when a button is pressed. KDLS rendered a plain span, which changes silently —
|
|
10
|
+
someone using a screen reader presses plus and has no idea whether anything happened. -->
|
|
11
|
+
|
|
12
|
+
class {
|
|
13
|
+
step(direction) {
|
|
14
|
+
const { value, step = 1, min, max, disabled, onChange } = this.input;
|
|
15
|
+
if (disabled) return;
|
|
16
|
+
const next = value + direction * step;
|
|
17
|
+
if (min !== undefined && next < min) return;
|
|
18
|
+
if (max !== undefined && next > max) return;
|
|
19
|
+
onChange?.(next);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
subtract() { this.step(-1); }
|
|
23
|
+
add() { this.step(1); }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
$ {
|
|
27
|
+
const {
|
|
28
|
+
value,
|
|
29
|
+
min,
|
|
30
|
+
max,
|
|
31
|
+
step = 1,
|
|
32
|
+
disabled = false,
|
|
33
|
+
label,
|
|
34
|
+
class: extraClass = "",
|
|
35
|
+
} = input;
|
|
36
|
+
|
|
37
|
+
if (typeof value !== "number") {
|
|
38
|
+
throw new Error("sds-incrementer needs a numeric `value`.");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const canSubtract = !disabled && (min === undefined || value - step >= min);
|
|
42
|
+
const canAdd = !disabled && (max === undefined || value + step <= max);
|
|
43
|
+
|
|
44
|
+
const classes = ["sds-incrementer", disabled ? "sds-incrementer--disabled" : "", extraClass]
|
|
45
|
+
.filter(Boolean).join(" ");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
<div class=classes role="group" aria-label=label>
|
|
49
|
+
<button
|
|
50
|
+
type="button"
|
|
51
|
+
class="sds-incrementer__btn"
|
|
52
|
+
disabled=(!canSubtract || null)
|
|
53
|
+
aria-label="Diminuir"
|
|
54
|
+
on-click("subtract")
|
|
55
|
+
>
|
|
56
|
+
<sds-icon><fluent-subtract-regular/></sds-icon>
|
|
57
|
+
</button>
|
|
58
|
+
|
|
59
|
+
<output class="sds-incrementer__value" aria-live="polite">${value}</output>
|
|
60
|
+
|
|
61
|
+
<button
|
|
62
|
+
type="button"
|
|
63
|
+
class="sds-incrementer__btn"
|
|
64
|
+
disabled=(!canAdd || null)
|
|
65
|
+
aria-label="Aumentar"
|
|
66
|
+
on-click("add")
|
|
67
|
+
>
|
|
68
|
+
<sds-icon><fluent-add-regular/></sds-icon>
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|