@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,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Skeleton vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/Skeleton/Skeleton.tsx, where
|
|
5
|
+
* Button, Input and Image were sub-components of Skeleton. They are sibling tags here:
|
|
6
|
+
* they share nothing but a stylesheet, so nesting them under one parent would be a
|
|
7
|
+
* namespace rather than a relationship.
|
|
8
|
+
*/
|
|
9
|
+
export const SKELETON_SIZES = ['sm', 'md', 'lg'];
|
|
10
|
+
|
|
11
|
+
export function assertSkeletonSize(size) {
|
|
12
|
+
if (!SKELETON_SIZES.includes(size)) {
|
|
13
|
+
throw new Error(`Unknown skeleton size: "${size}". Allowed: ${SKELETON_SIZES.join(', ')}`);
|
|
14
|
+
}
|
|
15
|
+
return size;
|
|
16
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<!-- sds-skeleton — ported from kdls-design-system v2.5.1 (0f3edf8)
|
|
2
|
+
components/Skeleton/Skeleton.tsx.
|
|
3
|
+
|
|
4
|
+
A placeholder for content that has not arrived. `loading=false` renders the real content
|
|
5
|
+
instead, so a caller writes the swap once rather than branching around it.
|
|
6
|
+
|
|
7
|
+
It is aria-hidden and carries aria-busy on the region: a screen reader should hear
|
|
8
|
+
"loading", not a description of grey rectangles. KDLS left it unannounced entirely, which
|
|
9
|
+
means a screen reader user hears nothing at all while waiting.
|
|
10
|
+
|
|
11
|
+
No state: it is told whether it is loading. -->
|
|
12
|
+
|
|
13
|
+
import { assertSkeletonSize } from "./skeleton-variants.js";
|
|
14
|
+
|
|
15
|
+
$ {
|
|
16
|
+
const {
|
|
17
|
+
loading = true,
|
|
18
|
+
rows = 3,
|
|
19
|
+
title = true,
|
|
20
|
+
avatar = false,
|
|
21
|
+
active = true,
|
|
22
|
+
size = "md",
|
|
23
|
+
label = "Carregando",
|
|
24
|
+
class: extraClass = "",
|
|
25
|
+
} = input;
|
|
26
|
+
|
|
27
|
+
assertSkeletonSize(size);
|
|
28
|
+
|
|
29
|
+
const classes = [
|
|
30
|
+
"sds-skeleton",
|
|
31
|
+
active ? "sds-skeleton--active" : "",
|
|
32
|
+
extraClass,
|
|
33
|
+
].filter(Boolean).join(" ");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
<if(!loading)>
|
|
37
|
+
<${input.renderBody}/>
|
|
38
|
+
</if>
|
|
39
|
+
<else>
|
|
40
|
+
<div class=classes role="status" aria-busy="true" aria-label=label>
|
|
41
|
+
<if(avatar)>
|
|
42
|
+
<span class=`sds-skeleton__avatar sds-skeleton__avatar--${size}` aria-hidden="true"/>
|
|
43
|
+
</if>
|
|
44
|
+
<div class="sds-skeleton__content" aria-hidden="true">
|
|
45
|
+
<if(title)>
|
|
46
|
+
<span class="sds-skeleton__line sds-skeleton__line--title"/>
|
|
47
|
+
</if>
|
|
48
|
+
<for|_, index| of=Array.from({ length: rows })>
|
|
49
|
+
<span class=`sds-skeleton__line ${index === rows - 1 ? "sds-skeleton__line--last" : ""}`.trim()/>
|
|
50
|
+
</for>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</else>
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/* SDS Spinner.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Spinner/Spinner.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-spinner--solid .sds-spinner__arc
|
|
7
|
+
*//* ────────────────────────────────────────────────────────────
|
|
8
|
+
Spinner — SVG stroke-dasharray spinner
|
|
9
|
+
Spinning: arc grows then shrinks via stroke-dasharray + SVG rotation
|
|
10
|
+
Done: full circle (primary-50) + check draws via stroke-dashoffset
|
|
11
|
+
No dark block needed — all tokens auto-invert or are pivot (50)
|
|
12
|
+
──────────────────────────────────────────────────────────── */
|
|
13
|
+
|
|
14
|
+
/* ── Size tokens ── */
|
|
15
|
+
.sds-spinner--sm { --sds-spinner-size: 24px; }
|
|
16
|
+
.sds-spinner--md { --sds-spinner-size: 40px; }
|
|
17
|
+
.sds-spinner--lg { --sds-spinner-size: 56px; }
|
|
18
|
+
/* ── Fullscreen overlay ── */
|
|
19
|
+
/* Fixed backdrop covering the viewport, spinner centered — same overlay treatment as Modal */
|
|
20
|
+
.sds-spinner-fullscreen {
|
|
21
|
+
position: fixed;
|
|
22
|
+
inset: 0;
|
|
23
|
+
z-index: var(--z-notice);
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
background: var(--color-opacity-50);
|
|
28
|
+
animation: sds-spinner-overlay-in 120ms ease;
|
|
29
|
+
}
|
|
30
|
+
[data-theme="dark"] .sds-spinner-fullscreen {
|
|
31
|
+
background: var(--color-scrim);
|
|
32
|
+
}
|
|
33
|
+
@keyframes sds-spinner-overlay-in {
|
|
34
|
+
from { opacity: 0; }
|
|
35
|
+
to { opacity: 1; }
|
|
36
|
+
}
|
|
37
|
+
/* ── Base wrapper ── */
|
|
38
|
+
.sds-spinner {
|
|
39
|
+
position: relative;
|
|
40
|
+
display: inline-flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: center;
|
|
43
|
+
width: var(--sds-spinner-size);
|
|
44
|
+
height: var(--sds-spinner-size);
|
|
45
|
+
flex-shrink: 0;
|
|
46
|
+
}
|
|
47
|
+
/* ── SVG container ── */
|
|
48
|
+
.sds-spinner__svg {
|
|
49
|
+
display: block;
|
|
50
|
+
overflow: visible;
|
|
51
|
+
transform-origin: center center;
|
|
52
|
+
}
|
|
53
|
+
/* ── Track ring ── */
|
|
54
|
+
.sds-spinner__track {
|
|
55
|
+
fill: none;
|
|
56
|
+
stroke: var(--color-neutral-20);
|
|
57
|
+
}
|
|
58
|
+
/* ── Arc — base ── */
|
|
59
|
+
.sds-spinner__arc {
|
|
60
|
+
fill: none;
|
|
61
|
+
}
|
|
62
|
+
/* Solid variant color */
|
|
63
|
+
.sds-spinner--solid .sds-spinner__arc {
|
|
64
|
+
stroke: var(--color-primary-50-solid);
|
|
65
|
+
}
|
|
66
|
+
/* ── SPINNING STATE ── */
|
|
67
|
+
|
|
68
|
+
/* SVG rotates continuously — moves the arc around the circle */
|
|
69
|
+
.sds-spinner__svg {
|
|
70
|
+
animation: sds-spinner-rotate 1.4s linear infinite;
|
|
71
|
+
}
|
|
72
|
+
/* Arc grows from sliver → 75% → shrinks back to sliver ("worm") */
|
|
73
|
+
.sds-spinner__arc {
|
|
74
|
+
stroke-dasharray: 1px, var(--c);
|
|
75
|
+
stroke-dashoffset: 0;
|
|
76
|
+
animation: sds-spinner-dash 1.4s ease-in-out infinite;
|
|
77
|
+
}
|
|
78
|
+
/* Gradient variant: wave color cycles continuously scheme→secondary→tertiary */
|
|
79
|
+
/* ── DONE STATE ── */
|
|
80
|
+
|
|
81
|
+
/* Pause (not cancel) spinning when done — prevents snap-to-0 rotation glitch */
|
|
82
|
+
.sds-spinner--done .sds-spinner__svg {
|
|
83
|
+
animation-play-state: paused;
|
|
84
|
+
}
|
|
85
|
+
.sds-spinner--done .sds-spinner__arc {
|
|
86
|
+
animation-play-state: paused;
|
|
87
|
+
}
|
|
88
|
+
/* Done SVG overlay — absolutely positioned on top of the spinning SVG */
|
|
89
|
+
.sds-spinner__done-svg {
|
|
90
|
+
position: absolute;
|
|
91
|
+
top: 0;
|
|
92
|
+
left: 0;
|
|
93
|
+
display: block;
|
|
94
|
+
overflow: visible;
|
|
95
|
+
}
|
|
96
|
+
/* Fill circle — covers full stroke area (r + sw/2 radius set in TSX) */
|
|
97
|
+
.sds-spinner__done-fill {
|
|
98
|
+
fill: var(--color-primary-50-solid);
|
|
99
|
+
}
|
|
100
|
+
/* Mask hole — shrinks interior to zero; ease-out = starts fast, no noticeable pause */
|
|
101
|
+
.sds-spinner__fill-hole {
|
|
102
|
+
transform-box: fill-box;
|
|
103
|
+
transform-origin: 50% 50%;
|
|
104
|
+
animation: sds-fill-hole-shrink 420ms ease-out forwards;
|
|
105
|
+
}
|
|
106
|
+
/* ── Checkmark — draws itself after fill completes ── */
|
|
107
|
+
.sds-spinner__check {
|
|
108
|
+
fill: none;
|
|
109
|
+
stroke: var(--color-white);
|
|
110
|
+
stroke-dasharray: var(--check-len);
|
|
111
|
+
stroke-dashoffset: var(--check-len);
|
|
112
|
+
animation: sds-check-draw 300ms ease-out 420ms forwards;
|
|
113
|
+
}
|
|
114
|
+
/* ── Animations ── */
|
|
115
|
+
|
|
116
|
+
@keyframes sds-spinner-rotate {
|
|
117
|
+
to { transform: rotate(360deg); }
|
|
118
|
+
}
|
|
119
|
+
@keyframes sds-fill-hole-shrink {
|
|
120
|
+
from { transform: scale(1); }
|
|
121
|
+
to { transform: scale(0); }
|
|
122
|
+
}
|
|
123
|
+
/* Phase 1: arc grows from 1px to 75% of circumference
|
|
124
|
+
Phase 2: arc shrinks back to 1% while dashoffset advances full circle
|
|
125
|
+
Combined with SVG rotation → "traveling worm" effect */
|
|
126
|
+
@keyframes sds-spinner-dash {
|
|
127
|
+
0% {
|
|
128
|
+
stroke-dasharray: 1px, var(--c);
|
|
129
|
+
stroke-dashoffset: 0;
|
|
130
|
+
}
|
|
131
|
+
50% {
|
|
132
|
+
stroke-dasharray: calc(var(--c) * 0.75), var(--c);
|
|
133
|
+
stroke-dashoffset: calc(var(--c) * -0.25);
|
|
134
|
+
}
|
|
135
|
+
100% {
|
|
136
|
+
stroke-dasharray: 1px, var(--c);
|
|
137
|
+
stroke-dashoffset: calc(var(--c) * -1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
@keyframes sds-check-draw {
|
|
141
|
+
to { stroke-dashoffset: 0; }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* ── Variants ──────────────────────────────────────────────────────────────────
|
|
145
|
+
KDLS shipped two: `solid`, which paints the arc with the scheme colour, and
|
|
146
|
+
`gradient`, whose whole definition was to cycle scheme -> secondary -> tertiary. Those
|
|
147
|
+
two families do not exist in SDS, and there is nothing left of that variant once they
|
|
148
|
+
go — so the variant is gone and the `variant` attribute with it. The arc reads the
|
|
149
|
+
primary slot, which is what `solid` always did.
|
|
150
|
+
|
|
151
|
+
The Lya keyframe (an arc cycling between two hardcoded hexes, #77A6E0 and #BF71E5,
|
|
152
|
+
neither of which was ever a token) is removed for the same reason. */
|
|
153
|
+
|
|
154
|
+
/* The way out, in plain sight. It was visually hidden until focused — the skip-link
|
|
155
|
+
shape — and that means a control whose metrics change when it takes focus, which is the
|
|
156
|
+
one thing tests/no-reflow-on-interaction.test.js exists to forbid. It is also the wrong
|
|
157
|
+
answer here: a blocking overlay with a hidden exit is a blocking overlay. */
|
|
158
|
+
.sds-spinner-fullscreen__dismiss {
|
|
159
|
+
margin-top: var(--spacing-4);
|
|
160
|
+
padding: var(--spacing-2) var(--spacing-4);
|
|
161
|
+
border: 0;
|
|
162
|
+
border-radius: var(--radius-sm);
|
|
163
|
+
background: var(--component-bg-color);
|
|
164
|
+
color: var(--body-color);
|
|
165
|
+
font-family: var(--font-family-base);
|
|
166
|
+
font-size: var(--font-size-body-md);
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* The overlay stacks its spinner over the way out. */
|
|
171
|
+
.sds-spinner-fullscreen {
|
|
172
|
+
flex-direction: column;
|
|
173
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Spinner's SVG geometry, per size.
|
|
3
|
+
*
|
|
4
|
+
* Ported verbatim from kdls-design-system v2.5.1 (0f3edf8) components/Spinner/Spinner.tsx.
|
|
5
|
+
* These are drawing constants, not design tokens: they describe one shape at three sizes,
|
|
6
|
+
* and changing them changes the drawing rather than the theme.
|
|
7
|
+
*
|
|
8
|
+
* px the box, in CSS pixels
|
|
9
|
+
* r the circle radius
|
|
10
|
+
* sw the arc stroke width
|
|
11
|
+
* checkSw the checkmark stroke width
|
|
12
|
+
* checkLen the approximate path length, which drives the draw-on animation
|
|
13
|
+
* check the checkmark path, scaled 0.75 from centre so it sits inside the circle
|
|
14
|
+
*/
|
|
15
|
+
export const SPINNER_SIZES = ['sm', 'md', 'lg'];
|
|
16
|
+
|
|
17
|
+
export const SPINNER_GEOMETRY = {
|
|
18
|
+
sm: { px: 24, r: 9, sw: 2, checkSw: 2, checkLen: 14, check: 'M7.5 12L10.5 15.5L16.5 9' },
|
|
19
|
+
md: { px: 40, r: 16, sw: 3, checkSw: 3, checkLen: 22, check: 'M12.5 20L17.75 25.5L27.5 15' },
|
|
20
|
+
lg: { px: 56, r: 23, sw: 4, checkSw: 4, checkLen: 31, check: 'M17.5 28L24.5 35.5L38.5 20.5' },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function assertSpinnerSize(size) {
|
|
24
|
+
if (!SPINNER_SIZES.includes(size)) {
|
|
25
|
+
throw new Error(`Unknown spinner size: "${size}". Allowed: ${SPINNER_SIZES.join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
return size;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function geometryFor(size) {
|
|
31
|
+
const g = SPINNER_GEOMETRY[assertSpinnerSize(size)];
|
|
32
|
+
return {
|
|
33
|
+
...g,
|
|
34
|
+
cx: g.px / 2,
|
|
35
|
+
circumference: +(2 * Math.PI * g.r).toFixed(2),
|
|
36
|
+
holeR: g.r - g.sw / 2,
|
|
37
|
+
fillR: g.r + g.sw / 2,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!-- sds-spinner-overlay — the fullscreen half of the Spinner, and the only half that has
|
|
2
|
+
state.
|
|
3
|
+
|
|
4
|
+
The Spinner is markup and must stay markup: a listing skeleton puts fifty of them on a
|
|
5
|
+
page, and Marko decides serialisation per template at compile time, so a single
|
|
6
|
+
`on-click` anywhere in spinner.marko would be paid by every one of those fifty.
|
|
7
|
+
|
|
8
|
+
An overlay is the opposite kind of thing. There is one, it covers the viewport, and it
|
|
9
|
+
needs a way out — a spinner that finishes behind a backdrop nobody can dismiss locks
|
|
10
|
+
the page. So the state lives here, in the template that is rendered once.
|
|
11
|
+
|
|
12
|
+
It closes on a click and, once `done`, on its own after `dismissAfter` milliseconds.
|
|
13
|
+
Both are reported through `onDismiss`; a caller that controls `isOpen` decides whether
|
|
14
|
+
the close actually happens, and one that does not gets it for free. -->
|
|
15
|
+
|
|
16
|
+
import { assertSpinnerSize } from "./spinner-geometry.js";
|
|
17
|
+
|
|
18
|
+
class {
|
|
19
|
+
onCreate() {
|
|
20
|
+
this.state = { closed: false };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
onInput(input) {
|
|
24
|
+
// Re-opening after a dismissal has to clear the flag, or the overlay stays gone.
|
|
25
|
+
if (input.isOpen && this.state.closed) this.state.closed = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onMount() {
|
|
29
|
+
this.arm();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
onUpdate() {
|
|
33
|
+
this.arm();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
onDestroy() {
|
|
37
|
+
clearTimeout(this.timer);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The automatic close, armed only once the spinner has something to say it is done. */
|
|
41
|
+
arm() {
|
|
42
|
+
clearTimeout(this.timer);
|
|
43
|
+
if (!this.input.done || !this.isOpen) return;
|
|
44
|
+
this.timer = setTimeout(() => this.dismiss(), this.input.dismissAfter ?? 3000);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get isOpen() {
|
|
48
|
+
return this.input.isOpen !== undefined ? this.input.isOpen : !this.state.closed;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
dismiss() {
|
|
52
|
+
clearTimeout(this.timer);
|
|
53
|
+
this.input.onDismiss?.();
|
|
54
|
+
if (this.input.isOpen === undefined) this.state.closed = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A click on the backdrop, not on the spinner sitting in the middle of it. */
|
|
58
|
+
closeFromBackdrop(event, element) {
|
|
59
|
+
if (event.target !== element) return;
|
|
60
|
+
this.dismiss();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
closeOnEscape(event) {
|
|
64
|
+
if (event.key !== "Escape") return;
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
this.dismiss();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
$ {
|
|
71
|
+
const { size = "md", done = false, label, dismissLabel = "Fechar" } = input;
|
|
72
|
+
|
|
73
|
+
assertSpinnerSize(size);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
<if(component.isOpen)>
|
|
77
|
+
<div
|
|
78
|
+
class="sds-spinner-fullscreen"
|
|
79
|
+
role="alertdialog"
|
|
80
|
+
aria-label=(label ?? (done ? "Concluído" : "Carregando"))
|
|
81
|
+
on-click("closeFromBackdrop")
|
|
82
|
+
on-keydown("closeOnEscape")
|
|
83
|
+
>
|
|
84
|
+
<sds-spinner size=size done=done label=label/>
|
|
85
|
+
|
|
86
|
+
<!-- The way out, in plain sight. Hiding it until focused would mean a control whose
|
|
87
|
+
metrics change when it takes focus, and a blocking overlay whose exit is
|
|
88
|
+
invisible is a blocking overlay. -->
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
class="sds-spinner-fullscreen__dismiss"
|
|
92
|
+
on-click("dismiss")
|
|
93
|
+
>
|
|
94
|
+
${dismissLabel}
|
|
95
|
+
</button>
|
|
96
|
+
</div>
|
|
97
|
+
</if>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!-- sds-spinner — ported from kdls-design-system v2.5.1 (0f3edf8) components/Spinner/Spinner.tsx.
|
|
2
|
+
|
|
3
|
+
Divergences:
|
|
4
|
+
|
|
5
|
+
No `variant`. KDLS had two — `solid`, which paints the arc with the scheme colour, and
|
|
6
|
+
`gradient`, whose entire definition was to cycle scheme to secondary to tertiary. Those
|
|
7
|
+
families do not exist in SDS and nothing is left of that variant once they go, so the
|
|
8
|
+
variant went with them and the attribute with it. The arc reads the primary slot, which
|
|
9
|
+
is what `solid` always did.
|
|
10
|
+
|
|
11
|
+
No `onComplete` callback, and therefore no state. KDLS attached a native `animationend`
|
|
12
|
+
listener to the checkmark path to report completion. The event is already the API: a
|
|
13
|
+
caller that needs to know listens for `animationend` on `.sds-spinner__check` itself,
|
|
14
|
+
and the component stays markup.
|
|
15
|
+
|
|
16
|
+
`fullscreen` moved out, to sds-spinner-overlay. It renders in place rather than through a
|
|
17
|
+
portal — the overlay is position:fixed, so it covers the viewport from wherever it sits in
|
|
18
|
+
the tree, and the portal was solving a React-specific problem that does not exist here.
|
|
19
|
+
What it also needs is a way out, and a way out is a click handler: Marko decides
|
|
20
|
+
serialisation per template at compile time, so one handler here would be paid by every
|
|
21
|
+
spinner on the page, and a listing skeleton renders fifty. The overlay is rendered once,
|
|
22
|
+
so that is where the state belongs. -->
|
|
23
|
+
|
|
24
|
+
import { assertSpinnerSize } from "./spinner-geometry.js";
|
|
25
|
+
import { geometryFor } from "./spinner-geometry.js";
|
|
26
|
+
|
|
27
|
+
$ {
|
|
28
|
+
const {
|
|
29
|
+
size = "md",
|
|
30
|
+
done = false,
|
|
31
|
+
label = done ? "Concluído" : "Carregando",
|
|
32
|
+
// A spinner inside a control that already reports its own busy state must not announce
|
|
33
|
+
// itself: a button's accessible name comes from its contents, so a spinner with
|
|
34
|
+
// role="status" and aria-label="Carregando" renames the button to "Carregando
|
|
35
|
+
// Publicar" for the whole time it is working. aria-busy on the control is what says it
|
|
36
|
+
// is busy; this is just the picture of it. KDLS has the same defect and no way to opt
|
|
37
|
+
// out — the spinner is announced inside every one of its loading buttons.
|
|
38
|
+
decorative = false,
|
|
39
|
+
class: extraClass = "",
|
|
40
|
+
} = input;
|
|
41
|
+
|
|
42
|
+
assertSpinnerSize(size);
|
|
43
|
+
const g = geometryFor(size);
|
|
44
|
+
|
|
45
|
+
const classes = [
|
|
46
|
+
"sds-spinner",
|
|
47
|
+
"sds-spinner--solid",
|
|
48
|
+
`sds-spinner--${size}`,
|
|
49
|
+
done ? "sds-spinner--done" : "",
|
|
50
|
+
extraClass,
|
|
51
|
+
].filter(Boolean).join(" ");
|
|
52
|
+
|
|
53
|
+
// --c drives the arc dash animation, --check-len the checkmark draw-on.
|
|
54
|
+
const style = `--c: ${g.circumference}px; --check-len: ${g.checkLen}px`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
<macro|{ }| name="spinner">
|
|
58
|
+
<div
|
|
59
|
+
class=classes
|
|
60
|
+
role=(decorative ? null : "status")
|
|
61
|
+
aria-label=(decorative ? null : label)
|
|
62
|
+
aria-hidden=(decorative ? "true" : null)
|
|
63
|
+
style=style
|
|
64
|
+
>
|
|
65
|
+
<svg class="sds-spinner__svg" viewBox=`0 0 ${g.px} ${g.px}` width=g.px height=g.px fill="none" aria-hidden="true">
|
|
66
|
+
<circle class="sds-spinner__track" cx=g.cx cy=g.cx r=g.r stroke-width=g.sw/>
|
|
67
|
+
<circle class="sds-spinner__arc" cx=g.cx cy=g.cx r=g.r stroke-width=g.sw stroke-linecap="round"/>
|
|
68
|
+
</svg>
|
|
69
|
+
|
|
70
|
+
<if(done)>
|
|
71
|
+
<svg class="sds-spinner__done-svg" viewBox=`0 0 ${g.px} ${g.px}` width=g.px height=g.px fill="none" aria-hidden="true">
|
|
72
|
+
<defs>
|
|
73
|
+
<mask id=`sds-spinner-fill-mask-${size}`>
|
|
74
|
+
<!-- The hole covers the interior only, so the fill reaches the arc at t=0.
|
|
75
|
+
White and black here are mask channels, not colour: the mask reads
|
|
76
|
+
luminance and the values are never painted. -->
|
|
77
|
+
<rect x="0" y="0" width=g.px height=g.px fill="white"/>
|
|
78
|
+
<circle class="sds-spinner__fill-hole" cx=g.cx cy=g.cx r=g.holeR fill="black"/>
|
|
79
|
+
</mask>
|
|
80
|
+
</defs>
|
|
81
|
+
<circle class="sds-spinner__done-fill" cx=g.cx cy=g.cx r=g.fillR mask=`url(#sds-spinner-fill-mask-${size})`/>
|
|
82
|
+
<path class="sds-spinner__check" d=g.check stroke-width=g.checkSw stroke-linecap="round" stroke-linejoin="round"/>
|
|
83
|
+
</svg>
|
|
84
|
+
</if>
|
|
85
|
+
</div>
|
|
86
|
+
</macro>
|
|
87
|
+
|
|
88
|
+
<spinner/>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/* SDS StatCard.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/StatCard/StatCard.css
|
|
3
|
+
by scripts/port-css.mjs. Divergences beyond the mechanical rename are noted inline.
|
|
4
|
+
*//* ── StatCard ───────────────────────────────────────────────────────────
|
|
5
|
+
KPI / big-number card. Typically arranged in a grid row at the top of a page.
|
|
6
|
+
BEM root: .sds-stat-card
|
|
7
|
+
─────────────────────────────────────────────────────────────────── */
|
|
8
|
+
|
|
9
|
+
/* A <dl>: a number with a name is a description list. Its default styling has to be taken
|
|
10
|
+
back — see the note on .sds-card__info-pair, same element, same trap. */
|
|
11
|
+
/* The column is turned around: the DOM reads `<dt>` then `<dd>`, which is the only valid
|
|
12
|
+
order for a description list, and the card draws the number above its name. Nothing in
|
|
13
|
+
here is interactive, so there is no focus order to fall out of step with. */
|
|
14
|
+
.sds-stat-card {
|
|
15
|
+
background: var(--component-bg-color);
|
|
16
|
+
border-radius: var(--radius-md);
|
|
17
|
+
padding: var(--spacing-6);
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column-reverse;
|
|
20
|
+
gap: var(--spacing-1);
|
|
21
|
+
margin: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.sds-stat-card dt,
|
|
25
|
+
.sds-stat-card dd {
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
.sds-stat-card--hug {
|
|
29
|
+
width: fit-content;
|
|
30
|
+
min-width: 200px;
|
|
31
|
+
max-width: 240px;
|
|
32
|
+
}
|
|
33
|
+
.sds-stat-card--fill {
|
|
34
|
+
width: 100%;
|
|
35
|
+
}
|
|
36
|
+
.sds-stat-card__top {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
gap: var(--spacing-2);
|
|
40
|
+
}
|
|
41
|
+
/* 2 steps weaker than __value's --title-color, by design (not a bug) — neutral-70
|
|
42
|
+
auto-inverts the same way --title-color does, so the 2-step gap holds in both themes
|
|
43
|
+
without a dark override: light neutral-90→70 is 2 steps darker-to-lighter, and dark
|
|
44
|
+
mirrors that same gap from the inverted (white) end. */
|
|
45
|
+
.sds-stat-card__icon {
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
font-size: 24px;
|
|
48
|
+
flex-shrink: 0;
|
|
49
|
+
color: var(--color-neutral-70);
|
|
50
|
+
}
|
|
51
|
+
.sds-stat-card__value {
|
|
52
|
+
font-family: var(--font-family-base);
|
|
53
|
+
font-size: 24px;
|
|
54
|
+
font-weight: var(--font-weight-bold);
|
|
55
|
+
line-height: 32px;
|
|
56
|
+
letter-spacing: -0.05em;
|
|
57
|
+
color: var(--title-color);
|
|
58
|
+
}
|
|
59
|
+
.sds-stat-card .sds-stat-card__label {
|
|
60
|
+
font-weight: var(--font-weight-medium);
|
|
61
|
+
}
|
|
62
|
+
/* ── Group wrapper — flex-wrap: cards (hug) hug the text and wrap onto the line ── */
|
|
63
|
+
.sds-stat-card-group {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-wrap: wrap;
|
|
66
|
+
gap: var(--spacing-4);
|
|
67
|
+
}
|
|
68
|
+
/* Mobile: 2 per row; drops to 1 when 2 don't fit (auto-fit + smaller min).
|
|
69
|
+
The cards fill the column, ignoring the 200–240 hug clamp.
|
|
70
|
+
|
|
71
|
+
Divergence: min() around the track minimum. A bare minmax(150px, 1fr) never goes under
|
|
72
|
+
150, so a group placed in a column narrower than that is wider than its column — and
|
|
73
|
+
the page, not the group, is what scrolls. */
|
|
74
|
+
@media (max-width: 799px) {
|
|
75
|
+
.sds-stat-card-group {
|
|
76
|
+
display: grid;
|
|
77
|
+
grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
|
|
78
|
+
}
|
|
79
|
+
.sds-stat-card-group .sds-stat-card {
|
|
80
|
+
width: auto;
|
|
81
|
+
min-width: 0;
|
|
82
|
+
max-width: none;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Same rule the Card, the Accordion and the AttachmentList follow: a container that draws
|
|
87
|
+
its own surface needs the stroke only where that surface matches the ground behind it. */
|
|
88
|
+
.sds-stat-card--bordered {
|
|
89
|
+
border: 1px solid var(--border-static-color);
|
|
90
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!-- sds-stat-card — ported from kdls-design-system v2.5.1 (0f3edf8)
|
|
2
|
+
components/StatCard/StatCard.tsx.
|
|
3
|
+
|
|
4
|
+
A number and what it counts. The value and its label are a description list rather than
|
|
5
|
+
two spans: "2.560 imóveis ativos" should reach a screen reader as one fact, which is the
|
|
6
|
+
same correction the Card's InfoPair needed. KDLS used loose spans. -->
|
|
7
|
+
|
|
8
|
+
$ {
|
|
9
|
+
const {
|
|
10
|
+
value,
|
|
11
|
+
label,
|
|
12
|
+
icon,
|
|
13
|
+
width = "hug",
|
|
14
|
+
// A bordered container separates itself from a ground of its own colour; on a
|
|
15
|
+
// different ground the stroke is one line of noise. Same rule the Card, the Accordion
|
|
16
|
+
// and the AttachmentList follow.
|
|
17
|
+
bordered = false,
|
|
18
|
+
class: extraClass = "",
|
|
19
|
+
} = input;
|
|
20
|
+
|
|
21
|
+
if (value === undefined) throw new Error("sds-stat-card needs a `value`.");
|
|
22
|
+
if (!label) throw new Error("sds-stat-card needs a `label` — a number with no name is not a statistic.");
|
|
23
|
+
if (width !== "hug" && width !== "fill") {
|
|
24
|
+
throw new Error(`Unknown stat card width: "${width}". Allowed: hug, fill`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const renderable = (v) => (v && v.renderBody) || v;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
<!-- A `<dl>`, with the term first — which is what makes it valid.
|
|
31
|
+
|
|
32
|
+
The value is drawn ABOVE its label, and the port wrote the DOM in that order: `<dd>`
|
|
33
|
+
then `<dt>`. `<dl>` requires the term first, so the pairing a screen reader relies on
|
|
34
|
+
was broken by the very markup chosen to express it. The reading order is term then
|
|
35
|
+
description now, and the stylesheet turns the column around so the number still sits
|
|
36
|
+
on top. Nothing here is interactive, so visual order and focus order cannot disagree.
|
|
37
|
+
|
|
38
|
+
The list stays rather than going back to KDLS's loose spans: "2560" and "Imóveis
|
|
39
|
+
ativos" as two unrelated strings is what the `<dl>` was for. -->
|
|
40
|
+
<dl class=[
|
|
41
|
+
"sds-stat-card",
|
|
42
|
+
`sds-stat-card--${width}`,
|
|
43
|
+
bordered ? "sds-stat-card--bordered" : "",
|
|
44
|
+
extraClass,
|
|
45
|
+
].filter(Boolean).join(" ")>
|
|
46
|
+
<dt>
|
|
47
|
+
<sds-text as="span" variant="bodyMd" class="sds-stat-card__label">${label}</sds-text>
|
|
48
|
+
</dt>
|
|
49
|
+
<dd class="sds-stat-card__top">
|
|
50
|
+
<if(icon)>
|
|
51
|
+
<span class="sds-stat-card__icon" aria-hidden="true">
|
|
52
|
+
<sds-icon><${renderable(icon)}/></sds-icon>
|
|
53
|
+
</span>
|
|
54
|
+
</if>
|
|
55
|
+
<span class="sds-stat-card__value">${value}</span>
|
|
56
|
+
</dd>
|
|
57
|
+
</dl>
|