@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,298 @@
|
|
|
1
|
+
/* SDS Nav.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Nav/Nav.css
|
|
3
|
+
by scripts/port-css.mjs. Divergences beyond the mechanical rename are noted inline.
|
|
4
|
+
*//* ============================================================
|
|
5
|
+
SDS Nav
|
|
6
|
+
Navigation container — horizontal (top bar) or vertical (sidebar)
|
|
7
|
+
Items reuse sds-menu__item styles
|
|
8
|
+
============================================================ */
|
|
9
|
+
|
|
10
|
+
/* ── Root ── */
|
|
11
|
+
.sds-nav {
|
|
12
|
+
display: flex;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
}
|
|
15
|
+
.sds-nav--horizontal {
|
|
16
|
+
flex-direction: row;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: var(--spacing-4);
|
|
19
|
+
/* Divergence: it wraps rather than pushing the page out. Five items at 375px measured
|
|
20
|
+
427px wide, which is a horizontal scrollbar under the whole document — and the items
|
|
21
|
+
that did not fit were unreachable either way. KDLS lets it overflow.
|
|
22
|
+
|
|
23
|
+
It wraps rather than scrolls, and that was measured too. `overflow-x: auto` was the
|
|
24
|
+
first fix and it broke every menu a nav item holds: CSS computes `overflow-y` to
|
|
25
|
+
`auto` as soon as `overflow-x` is not `visible`, so a 71px nav clipped a 332px menu
|
|
26
|
+
panel to nothing. Wrapping costs height on a crowded row and hides nothing. */
|
|
27
|
+
min-width: 0;
|
|
28
|
+
max-width: 100%;
|
|
29
|
+
flex-wrap: wrap;
|
|
30
|
+
}
|
|
31
|
+
.sds-nav--vertical {
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
align-items: stretch;
|
|
34
|
+
gap: 0;
|
|
35
|
+
width: 100%;
|
|
36
|
+
}
|
|
37
|
+
/* ── Header / Footer slots ── */
|
|
38
|
+
.sds-nav__header {
|
|
39
|
+
flex-shrink: 0;
|
|
40
|
+
padding: var(--spacing-3) var(--spacing-4);
|
|
41
|
+
border-bottom: 1px solid var(--border-static-color);
|
|
42
|
+
}
|
|
43
|
+
.sds-nav__footer {
|
|
44
|
+
flex-shrink: 0;
|
|
45
|
+
margin-top: auto;
|
|
46
|
+
padding: var(--spacing-3) var(--spacing-4);
|
|
47
|
+
border-top: 1px solid var(--border-static-color);
|
|
48
|
+
}
|
|
49
|
+
/* ── Item ── */
|
|
50
|
+
.sds-nav__item {
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
gap: var(--spacing-3);
|
|
54
|
+
padding: var(--spacing-2) var(--spacing-4);
|
|
55
|
+
min-height: 40px;
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
color: var(--color-neutral-80);
|
|
58
|
+
font-family: var(--font-family-base);
|
|
59
|
+
font-size: var(--font-size-body-md);
|
|
60
|
+
font-weight: var(--font-weight-regular);
|
|
61
|
+
line-height: var(--lh-body-md);
|
|
62
|
+
border-radius: 11px; /* soft, the install default — schemes at the end */
|
|
63
|
+
border: none;
|
|
64
|
+
background: transparent;
|
|
65
|
+
text-align: left;
|
|
66
|
+
text-decoration: none;
|
|
67
|
+
transition: background-color 120ms ease, color 120ms ease;
|
|
68
|
+
user-select: none;
|
|
69
|
+
box-sizing: border-box;
|
|
70
|
+
white-space: nowrap;
|
|
71
|
+
}
|
|
72
|
+
.sds-nav--vertical .sds-nav__item {
|
|
73
|
+
width: 100%;
|
|
74
|
+
margin: 0 var(--spacing-1);
|
|
75
|
+
width: calc(100% - var(--spacing-2));
|
|
76
|
+
}
|
|
77
|
+
/* `:where(a, button)` rather than `a, button`.
|
|
78
|
+
These are scoped to the interactive elements on purpose — an item that is neither a link
|
|
79
|
+
nor a button is not hoverable and should not pretend to be. But naming the element
|
|
80
|
+
raised the specificity to (0,3,1), which beats every intent rule at (0,3,0) no matter
|
|
81
|
+
what order they are in: an item with `intent="error"` got the generic grey hover instead
|
|
82
|
+
of its red one, while its text colour — declared only on the intent rule — did change.
|
|
83
|
+
Half the style applied, which is worse than none.
|
|
84
|
+
`:where()` contributes nothing to specificity, so the scoping survives and the intent
|
|
85
|
+
rules below win on source order, which is what they were written to do. */
|
|
86
|
+
:where(a, button).sds-nav__item:hover:not(.sds-nav__item--disabled) {
|
|
87
|
+
background-color: var(--color-opacity-05);
|
|
88
|
+
}
|
|
89
|
+
:where(a, button).sds-nav__item:focus-visible {
|
|
90
|
+
outline: none;
|
|
91
|
+
background-color: var(--color-opacity-08);
|
|
92
|
+
box-shadow: var(--focus-ring-inset);
|
|
93
|
+
}
|
|
94
|
+
:where(a, button).sds-nav__item:active {
|
|
95
|
+
background-color: var(--color-opacity-10);
|
|
96
|
+
}
|
|
97
|
+
.sds-nav__item--active {
|
|
98
|
+
color: var(--color-neutral-90);
|
|
99
|
+
font-weight: var(--font-weight-bold);
|
|
100
|
+
}
|
|
101
|
+
.sds-nav__item--active:hover:not(.sds-nav__item--disabled) {
|
|
102
|
+
background-color: var(--color-opacity-05);
|
|
103
|
+
}
|
|
104
|
+
.sds-nav__item--disabled {
|
|
105
|
+
opacity: 0.4;
|
|
106
|
+
cursor: not-allowed;
|
|
107
|
+
}
|
|
108
|
+
/* ── Intent items ── */
|
|
109
|
+
.sds-nav__item--primary:hover:not(.sds-nav__item--disabled),
|
|
110
|
+
.sds-nav__item--primary:focus-visible {
|
|
111
|
+
background: var(--color-primary-10);
|
|
112
|
+
color: var(--color-primary-90-solid);
|
|
113
|
+
}
|
|
114
|
+
.sds-nav__item--primary:active {
|
|
115
|
+
background: var(--color-primary-30);
|
|
116
|
+
color: var(--color-primary-90-solid);
|
|
117
|
+
}
|
|
118
|
+
.sds-nav__item--error:hover:not(.sds-nav__item--disabled),
|
|
119
|
+
.sds-nav__item--error:focus-visible {
|
|
120
|
+
background-color: var(--color-error-10);
|
|
121
|
+
color: var(--color-error-10-on);
|
|
122
|
+
}
|
|
123
|
+
.sds-nav__item--error:active {
|
|
124
|
+
background-color: var(--color-error-30);
|
|
125
|
+
color: var(--color-error-30-on);
|
|
126
|
+
}
|
|
127
|
+
.sds-nav__item--success:hover:not(.sds-nav__item--disabled),
|
|
128
|
+
.sds-nav__item--success:focus-visible {
|
|
129
|
+
background-color: var(--color-success-10);
|
|
130
|
+
color: var(--color-success-10-on);
|
|
131
|
+
}
|
|
132
|
+
.sds-nav__item--success:active {
|
|
133
|
+
background-color: var(--color-success-30);
|
|
134
|
+
color: var(--color-success-30-on);
|
|
135
|
+
}
|
|
136
|
+
.sds-nav__item--alert:hover:not(.sds-nav__item--disabled),
|
|
137
|
+
.sds-nav__item--alert:focus-visible {
|
|
138
|
+
background-color: var(--color-alert-10);
|
|
139
|
+
color: var(--color-alert-10-on);
|
|
140
|
+
}
|
|
141
|
+
.sds-nav__item--alert:active {
|
|
142
|
+
background-color: var(--color-alert-30);
|
|
143
|
+
color: var(--color-alert-30-on);
|
|
144
|
+
}
|
|
145
|
+
/* ── Item slots ── */
|
|
146
|
+
.sds-nav__item-icon {
|
|
147
|
+
display: inline-flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
flex-shrink: 0;
|
|
150
|
+
color: inherit;
|
|
151
|
+
}
|
|
152
|
+
.sds-nav__item-label {
|
|
153
|
+
flex: 1;
|
|
154
|
+
white-space: nowrap;
|
|
155
|
+
}
|
|
156
|
+
.sds-nav__item-tooltip-icon {
|
|
157
|
+
display: inline-flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
flex-shrink: 0;
|
|
160
|
+
}
|
|
161
|
+
/* ── Separator ── */
|
|
162
|
+
.sds-nav__separator {
|
|
163
|
+
height: 1px;
|
|
164
|
+
background: var(--color-neutral-20);
|
|
165
|
+
margin: var(--spacing-1) var(--spacing-3);
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
}
|
|
168
|
+
.sds-nav--horizontal .sds-nav__separator {
|
|
169
|
+
width: 1px;
|
|
170
|
+
height: 24px;
|
|
171
|
+
margin: 0 var(--spacing-2);
|
|
172
|
+
}
|
|
173
|
+
/* ── Dark mode ── */
|
|
174
|
+
[data-theme="dark"] .sds-nav__header {
|
|
175
|
+
border-bottom-color: var(--border-interactive-color);
|
|
176
|
+
}
|
|
177
|
+
[data-theme="dark"] .sds-nav__footer {
|
|
178
|
+
border-top-color: var(--border-interactive-color);
|
|
179
|
+
}
|
|
180
|
+
[data-theme="dark"] .sds-nav__separator {
|
|
181
|
+
background: var(--border-interactive-color);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* ── List semantics ────────────────────────────────────────────────────────────
|
|
185
|
+
SDS renders the nav as a real <ul> of <li>, which KDLS did not: it laid the items
|
|
186
|
+
out as bare elements. The list is the correct structure — a screen reader announces
|
|
187
|
+
"list, 5 items" and gives the visitor a way to move through them — and these rules
|
|
188
|
+
are what make it look the way KDLS's did. */
|
|
189
|
+
/* The gap between ITEMS lives here, not on the nav.
|
|
190
|
+
KDLS has no list element: its items are direct children of the nav, so the nav's own
|
|
191
|
+
16px gap separated them. Here they sit inside a <ul>, so that gap fell between the
|
|
192
|
+
header, the list and the footer instead, and the list supplied 4px of its own —
|
|
193
|
+
measured 4px between two adjacent items where KDLS has 16. Vertical was worse: KDLS
|
|
194
|
+
stacks its rows flush and here every row gained 4px it never had. */
|
|
195
|
+
.sds-nav__list {
|
|
196
|
+
list-style: none;
|
|
197
|
+
margin: 0;
|
|
198
|
+
padding: 0;
|
|
199
|
+
display: flex;
|
|
200
|
+
gap: var(--spacing-4);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* The items live on the list, so the list is what has to wrap — putting it on .sds-nav
|
|
204
|
+
changed nothing, and five items still measured 448px inside a 375px window. */
|
|
205
|
+
.sds-nav--horizontal .sds-nav__list {
|
|
206
|
+
flex-wrap: wrap;
|
|
207
|
+
min-width: 0;
|
|
208
|
+
/* And the items keep their own height. A flex container stretches its children by
|
|
209
|
+
default, so inside a 56px header the <li> grew to 56 and pulled the row with it — a
|
|
210
|
+
40px control with a 56px hover box around it. KDLS has no list element here at all;
|
|
211
|
+
the <ul>/<li> is this port's addition, for the "list, 5 items" a screen reader
|
|
212
|
+
announces, and it must not change what anything looks like. */
|
|
213
|
+
align-items: center;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.sds-nav--horizontal .sds-nav__list-item {
|
|
217
|
+
align-items: center;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.sds-nav--vertical .sds-nav__list {
|
|
221
|
+
flex-direction: column;
|
|
222
|
+
/* Flush, as in KDLS: a vertical nav is a list of rows and a gap between them reads as a
|
|
223
|
+
gap between groups. The rows already have their own padding. */
|
|
224
|
+
gap: 0;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.sds-nav__list-item {
|
|
228
|
+
display: flex;
|
|
229
|
+
min-width: 0;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.sds-nav--vertical .sds-nav__list-item {
|
|
233
|
+
width: 100%;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* The separator is a real <hr>, which KDLS draws as a div — so the element's own border has
|
|
237
|
+
to go before it can be a line. The colour reads --border-static-color rather than
|
|
238
|
+
--color-neutral-20: the same value today, but this is a border and that is the token for
|
|
239
|
+
one, so it follows if the border ever stops being neutral-20.
|
|
240
|
+
|
|
241
|
+
The horizontal inset stays KDLS's: the base rule insets a vertical nav's line by 12px,
|
|
242
|
+
and the horizontal variant overrides it anyway. */
|
|
243
|
+
.sds-nav__separator {
|
|
244
|
+
border: 0;
|
|
245
|
+
align-self: stretch;
|
|
246
|
+
background: var(--border-static-color);
|
|
247
|
+
margin: var(--spacing-1) var(--spacing-3);
|
|
248
|
+
width: 1px;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.sds-nav--vertical .sds-nav__separator {
|
|
252
|
+
width: auto;
|
|
253
|
+
height: 1px;
|
|
254
|
+
margin: var(--spacing-1) 0;
|
|
255
|
+
align-self: auto;
|
|
256
|
+
flex: 1;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* Native chrome reset.
|
|
260
|
+
SDS renders these rows as real <button> and <a> elements, which KDLS did not — it used
|
|
261
|
+
bare <div>s with click handlers. A button brings keyboard activation, focus and the
|
|
262
|
+
disabled state from the browser, and these lines are the whole price: without them the
|
|
263
|
+
browser's own button border and background show through the design.
|
|
264
|
+
|
|
265
|
+
`width: 100%` was in here and does not belong: a width is layout, not chrome, and the
|
|
266
|
+
browser supplies no width to reset. KDLS sets it only on a vertical nav, where the row
|
|
267
|
+
should fill the column. Incondicional, it stretched every horizontal item to the width
|
|
268
|
+
of its slot, so the hover box was far wider than the label inside it. The same shape of
|
|
269
|
+
mistake as the ColorPicker's reset erasing a border the design had asked for — a chrome
|
|
270
|
+
reset names the properties the design is silent about, and nothing else. */
|
|
271
|
+
.sds-nav__item {
|
|
272
|
+
appearance: none;
|
|
273
|
+
border: 0;
|
|
274
|
+
background: none;
|
|
275
|
+
text-align: left;
|
|
276
|
+
text-decoration: none;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* ── Corner radius: the 40px family ───────────────────────────────────────────
|
|
280
|
+
A row in a menu, a select or a dropdown is 40px tall, which makes it the same control
|
|
281
|
+
as the Pill and the navButton — so it takes the same four values. Rafael, pointing at
|
|
282
|
+
the theme bar's own menu: these are reactive, but not in the right way; they should be
|
|
283
|
+
40px like the navButton and have the radius resolved here.
|
|
284
|
+
|
|
285
|
+
height 40px flat 0 soft 11px medium 15px rounded 20px (a capsule)
|
|
286
|
+
as a fraction 0 0.275 0.375 0.5
|
|
287
|
+
|
|
288
|
+
`--radius-sm` was what they had, and it tops out at 16px — so `rounded` drew a rounded
|
|
289
|
+
rectangle where every other 40px control in the system drew a capsule. See Pill.css for
|
|
290
|
+
the arithmetic; the numbers are a fraction of the control's own height, which is what
|
|
291
|
+
keeps the family reading as one thing.
|
|
292
|
+
|
|
293
|
+
The bare value is `soft`'s, because an install that never picks a scheme has no
|
|
294
|
+
attribute at all and falls through to it. */
|
|
295
|
+
[data-radius="flat"] .sds-nav__item { border-radius: 0; }
|
|
296
|
+
[data-radius="soft"] .sds-nav__item { border-radius: 11px; }
|
|
297
|
+
[data-radius="medium"] .sds-nav__item { border-radius: 15px; }
|
|
298
|
+
[data-radius="rounded"] .sds-nav__item { border-radius: var(--radius-full); }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Nav vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/Nav/Nav.tsx.
|
|
5
|
+
* `intent` is shared with Menu — the two use the same set, and a nav item that deletes
|
|
6
|
+
* something should look like a menu item that deletes something.
|
|
7
|
+
*
|
|
8
|
+
* Divergence: `primary` is the slot, as it was. The badge a nav item can carry used
|
|
9
|
+
* variant="primary" in KDLS, which no longer exists as a Badge colour; it is
|
|
10
|
+
* `scheme-color` here, which is the same thing under its surviving name.
|
|
11
|
+
*/
|
|
12
|
+
export const NAV_ORIENTATIONS = ['horizontal', 'vertical'];
|
|
13
|
+
export const NAV_INTENTS = ['primary', 'neutral', 'error', 'success', 'alert'];
|
|
14
|
+
|
|
15
|
+
function assertOneOf(label, value, allowed) {
|
|
16
|
+
if (!allowed.includes(value)) {
|
|
17
|
+
throw new Error(`Unknown nav ${label}: "${value}". Allowed: ${allowed.join(', ')}`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const assertOrientation = (v) => assertOneOf('orientation', v, NAV_ORIENTATIONS);
|
|
23
|
+
export const assertIntent = (v) => (v === undefined ? v : assertOneOf('intent', v, NAV_INTENTS));
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<!-- sds-nav — ported from kdls-design-system v2.5.1 (0f3edf8) components/Nav/Nav.tsx.
|
|
2
|
+
|
|
3
|
+
Items arrive as attribute tags, not as nested children:
|
|
4
|
+
|
|
5
|
+
<sds-nav orientation="vertical">
|
|
6
|
+
<@item active href="/">Início</@item>
|
|
7
|
+
<@item separator/>
|
|
8
|
+
<@item icon=searchIcon badge="3">Buscar</@item>
|
|
9
|
+
</sds-nav>
|
|
10
|
+
|
|
11
|
+
A separator is an item that draws a line instead of a label, rather than a tag of its
|
|
12
|
+
own. Marko groups attribute tags by name, so <@item> and <@separator> would arrive as two
|
|
13
|
+
separate arrays and the order between them would be lost — every separator would sink to
|
|
14
|
+
the bottom of the list. One tag keeps the order the author wrote.
|
|
15
|
+
|
|
16
|
+
KDLS passed orientation down through a React context that Menu also read. Marko 5 has no
|
|
17
|
+
context, so the parent takes its items as data and renders them itself — see
|
|
18
|
+
`.claude/component-rules.md` §2c, where this is decided once for every compound component
|
|
19
|
+
rather than reinvented per component.
|
|
20
|
+
|
|
21
|
+
Each item is an <a> when it has an href and a <button> otherwise, which is what decides
|
|
22
|
+
whether it lands in the browser's link list or its button list.
|
|
23
|
+
|
|
24
|
+
`tooltip`, `tooltipIcon` and `tooltipPosition` are here now that Tooltip is. An item can
|
|
25
|
+
explain itself two ways, as in KDLS: the label itself becomes the trigger, or a separate
|
|
26
|
+
info affordance sits beside it. Tooltip's own touch question is still open and is recorded
|
|
27
|
+
there, not repeated here. -->
|
|
28
|
+
|
|
29
|
+
import { assertOrientation, assertIntent } from "./nav-variants.js";
|
|
30
|
+
|
|
31
|
+
class {
|
|
32
|
+
handleItemClick(item, event) {
|
|
33
|
+
if (item.disabled) {
|
|
34
|
+
event.preventDefault();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
item.onClick?.(event);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
$ {
|
|
42
|
+
const { orientation = "horizontal", header, footer, class: extraClass = "" } = input;
|
|
43
|
+
assertOrientation(orientation);
|
|
44
|
+
|
|
45
|
+
const renderable = (value) => (value && value.renderBody) || value;
|
|
46
|
+
|
|
47
|
+
// Attribute tags arrive as a single object when used once and an array when repeated.
|
|
48
|
+
const asList = (value) => (value === undefined ? [] : [].concat(value));
|
|
49
|
+
const items = asList(input.item);
|
|
50
|
+
|
|
51
|
+
for (const item of items) assertIntent(item.intent);
|
|
52
|
+
|
|
53
|
+
// Marko camel-cases a hyphenated attribute on a custom tag, so both spellings arrive
|
|
54
|
+
// and a consumer should not have to know which.
|
|
55
|
+
const ariaLabel = input["aria-label"] ?? input.ariaLabel ?? null;
|
|
56
|
+
|
|
57
|
+
const classes = ["sds-nav", `sds-nav--${orientation}`, extraClass].filter(Boolean).join(" ");
|
|
58
|
+
|
|
59
|
+
const classFor = (item) => [
|
|
60
|
+
"sds-nav__item",
|
|
61
|
+
item.active ? "sds-nav__item--active" : "",
|
|
62
|
+
item.disabled ? "sds-nav__item--disabled" : "",
|
|
63
|
+
item.intent ? `sds-nav__item--${item.intent}` : "",
|
|
64
|
+
item.class ?? "",
|
|
65
|
+
].filter(Boolean).join(" ");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
<nav class=classes aria-label=ariaLabel>
|
|
69
|
+
<if(header)>
|
|
70
|
+
<div class="sds-nav__header"><${renderable(header)}/></div>
|
|
71
|
+
</if>
|
|
72
|
+
|
|
73
|
+
<ul class="sds-nav__list">
|
|
74
|
+
<for|entry| of=items>
|
|
75
|
+
<li class="sds-nav__list-item">
|
|
76
|
+
<if(entry.separator)>
|
|
77
|
+
<hr class="sds-nav__separator"/>
|
|
78
|
+
</if>
|
|
79
|
+
<else>
|
|
80
|
+
<macro|{ }| name="content">
|
|
81
|
+
<if(entry.icon)>
|
|
82
|
+
<span class="sds-nav__item-icon" aria-hidden="true">
|
|
83
|
+
<sds-icon><${renderable(entry.icon)}/></sds-icon>
|
|
84
|
+
</span>
|
|
85
|
+
</if>
|
|
86
|
+
<if(entry.tooltip && !entry.tooltipIcon)>
|
|
87
|
+
<sds-tooltip content=entry.tooltip placement=(entry.tooltipPosition ?? "top")>
|
|
88
|
+
<span class="sds-nav__item-label"><${entry.renderBody}/></span>
|
|
89
|
+
</sds-tooltip>
|
|
90
|
+
</if>
|
|
91
|
+
<else>
|
|
92
|
+
<span class="sds-nav__item-label"><${entry.renderBody}/></span>
|
|
93
|
+
</else>
|
|
94
|
+
<if(entry.tooltip && entry.tooltipIcon)>
|
|
95
|
+
<span class="sds-nav__item-tooltip-icon">
|
|
96
|
+
<sds-tooltip content=entry.tooltip placement=(entry.tooltipPosition ?? "top")/>
|
|
97
|
+
</span>
|
|
98
|
+
</if>
|
|
99
|
+
<if(entry.badge)>
|
|
100
|
+
<sds-badge label=entry.badge variant="scheme-color" appearance="tone-50" size="sm"/>
|
|
101
|
+
</if>
|
|
102
|
+
</macro>
|
|
103
|
+
|
|
104
|
+
<if(entry.href)>
|
|
105
|
+
<a
|
|
106
|
+
class=classFor(entry)
|
|
107
|
+
href=(entry.disabled ? null : entry.href)
|
|
108
|
+
target=(entry.targetBlank ? "_blank" : null)
|
|
109
|
+
rel=(entry.targetBlank ? "noopener noreferrer" : null)
|
|
110
|
+
aria-disabled=(entry.disabled ? "true" : null)
|
|
111
|
+
aria-current=(entry.active ? "page" : null)
|
|
112
|
+
on-click("handleItemClick", entry)
|
|
113
|
+
>
|
|
114
|
+
<content/>
|
|
115
|
+
</a>
|
|
116
|
+
</if>
|
|
117
|
+
<else-if(entry.onClick)>
|
|
118
|
+
<button
|
|
119
|
+
type="button"
|
|
120
|
+
class=classFor(entry)
|
|
121
|
+
disabled=(entry.disabled || null)
|
|
122
|
+
aria-current=(entry.active ? "page" : null)
|
|
123
|
+
on-click("handleItemClick", entry)
|
|
124
|
+
>
|
|
125
|
+
<content/>
|
|
126
|
+
</button>
|
|
127
|
+
</else-if>
|
|
128
|
+
<else-if(entry.custom)>
|
|
129
|
+
<!-- The item is already a control — a Menu, most often. KDLS does not wrap
|
|
130
|
+
those at all: its Header renders <Menu> as a direct child of <Nav>, with
|
|
131
|
+
no Nav.Item around it. Wrapping added a second box with its own padding,
|
|
132
|
+
so a 40px trigger sat inside a 56px row and the hover area was bigger
|
|
133
|
+
than the thing you were pointing at.
|
|
134
|
+
|
|
135
|
+
The <li> stays, because the list semantics are this port's addition and
|
|
136
|
+
must not change what anything looks like: it carries no padding of its
|
|
137
|
+
own, so it is transparent to layout. -->
|
|
138
|
+
<content/>
|
|
139
|
+
</else-if>
|
|
140
|
+
<else>
|
|
141
|
+
<!-- Divergence: an item that neither navigates nor acts is not a control.
|
|
142
|
+
KDLS makes every item without an href a <button>, and that button is
|
|
143
|
+
empty of behaviour — nothing to click, but a tab stop, a hover state and
|
|
144
|
+
a focus ring all the same. Worse where the item holds a control of its
|
|
145
|
+
own: the Header puts an sds-menu in one, so a <button> ended up inside a
|
|
146
|
+
<button>, which is invalid HTML the browser silently rearranges, and it
|
|
147
|
+
drew a second hover area around the first. Rafael saw the outer one. -->
|
|
148
|
+
<div
|
|
149
|
+
class=classFor(entry)
|
|
150
|
+
aria-current=(entry.active ? "page" : null)
|
|
151
|
+
aria-disabled=(entry.disabled ? "true" : null)
|
|
152
|
+
>
|
|
153
|
+
<content/>
|
|
154
|
+
</div>
|
|
155
|
+
</else>
|
|
156
|
+
</else>
|
|
157
|
+
</li>
|
|
158
|
+
</for>
|
|
159
|
+
</ul>
|
|
160
|
+
|
|
161
|
+
<if(footer)>
|
|
162
|
+
<div class="sds-nav__footer"><${renderable(footer)}/></div>
|
|
163
|
+
</if>
|
|
164
|
+
</nav>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* SDS Notification.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Notification/Notification.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-notification--primary
|
|
7
|
+
*/.sds-notification {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
font-family: var(--font-family-base);
|
|
12
|
+
font-weight: var(--font-weight-semibold);
|
|
13
|
+
white-space: nowrap;
|
|
14
|
+
user-select: none;
|
|
15
|
+
flex-shrink: 0;
|
|
16
|
+
}
|
|
17
|
+
/* ── Fill: primary ── */
|
|
18
|
+
.sds-notification--primary {
|
|
19
|
+
background: var(--color-primary-50);
|
|
20
|
+
color: var(--color-on-primary);
|
|
21
|
+
}
|
|
22
|
+
/* ── Fill: neutral ── */
|
|
23
|
+
.sds-notification--neutral {
|
|
24
|
+
background-color: var(--color-neutral-80);
|
|
25
|
+
color: var(--color-white);
|
|
26
|
+
}
|
|
27
|
+
/* ── Fill: error ── */
|
|
28
|
+
.sds-notification--error {
|
|
29
|
+
background-color: var(--color-error-50);
|
|
30
|
+
color: var(--color-white);
|
|
31
|
+
}
|
|
32
|
+
/* ── Fill: alert ── */
|
|
33
|
+
.sds-notification--alert {
|
|
34
|
+
background-color: var(--color-alert-50);
|
|
35
|
+
color: var(--color-white);
|
|
36
|
+
}
|
|
37
|
+
/* ── Fill: success ── */
|
|
38
|
+
.sds-notification--success {
|
|
39
|
+
background-color: var(--color-success-50);
|
|
40
|
+
color: var(--color-white);
|
|
41
|
+
}
|
|
42
|
+
/* ── Dot (size 8) ── */
|
|
43
|
+
.sds-notification--dot {
|
|
44
|
+
width: 8px;
|
|
45
|
+
height: 8px;
|
|
46
|
+
border-radius: var(--radius-full);
|
|
47
|
+
}
|
|
48
|
+
/* ── Size 16 ── */
|
|
49
|
+
.sds-notification--16 {
|
|
50
|
+
height: 16px;
|
|
51
|
+
min-width: 16px;
|
|
52
|
+
padding: 0 var(--spacing-1);
|
|
53
|
+
border-radius: var(--radius-full);
|
|
54
|
+
font-size: 10px;
|
|
55
|
+
line-height: var(--lh-label-sm);
|
|
56
|
+
}
|
|
57
|
+
/* ── Size 20 ── */
|
|
58
|
+
.sds-notification--20 {
|
|
59
|
+
height: 20px;
|
|
60
|
+
min-width: 20px;
|
|
61
|
+
padding: 0 5px;
|
|
62
|
+
border-radius: var(--radius-full);
|
|
63
|
+
font-size: 11px;
|
|
64
|
+
line-height: var(--lh-body-sm);
|
|
65
|
+
}
|
|
66
|
+
/* ── Size 24 ── */
|
|
67
|
+
.sds-notification--24 {
|
|
68
|
+
height: 24px;
|
|
69
|
+
min-width: 24px;
|
|
70
|
+
padding: 0 6px;
|
|
71
|
+
border-radius: var(--radius-full);
|
|
72
|
+
font-size: 12px;
|
|
73
|
+
line-height: var(--lh-body-sm);
|
|
74
|
+
}
|
|
75
|
+
/* ── Variant: square (fixed radius proportional to size) ── */
|
|
76
|
+
.sds-notification--16.sds-notification--square { border-radius: 4px; }
|
|
77
|
+
.sds-notification--20.sds-notification--square { border-radius: 6px; }
|
|
78
|
+
.sds-notification--24.sds-notification--square { border-radius: 8px; }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Notification vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/Notification/Notification.tsx.
|
|
5
|
+
* Divergence: none. `primary` was already the slot.
|
|
6
|
+
*/
|
|
7
|
+
export const NOTIFICATION_SIZES = [8, 16, 20, 24];
|
|
8
|
+
export const NOTIFICATION_VARIANTS = ['primary', 'neutral', 'error', 'alert', 'success'];
|
|
9
|
+
export const NOTIFICATION_SHAPES = ['circle', 'square'];
|
|
10
|
+
|
|
11
|
+
function assertOneOf(label, value, allowed) {
|
|
12
|
+
if (!allowed.includes(value)) {
|
|
13
|
+
throw new Error(`Unknown notification ${label}: "${value}". Allowed: ${allowed.join(', ')}`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const assertNotificationSize = (v) => assertOneOf('size', v, NOTIFICATION_SIZES);
|
|
19
|
+
export const assertNotificationVariant = (v) => assertOneOf('variant', v, NOTIFICATION_VARIANTS);
|
|
20
|
+
export const assertNotificationShape = (v) => assertOneOf('shape', v, NOTIFICATION_SHAPES);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* What the badge reads out. Undefined when there is no count — a dot carries no number,
|
|
24
|
+
* and a badge that shows nothing should not announce anything either.
|
|
25
|
+
*/
|
|
26
|
+
export function notificationLabel({ count, max = 99, showPlus = false }) {
|
|
27
|
+
if (count === undefined) return '';
|
|
28
|
+
if (count > max) return `+${max}`;
|
|
29
|
+
return showPlus ? `+${count}` : String(count);
|
|
30
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<!-- sds-notification — ported from kdls-design-system v2.5.1 (0f3edf8)
|
|
2
|
+
components/Notification/Notification.tsx.
|
|
3
|
+
|
|
4
|
+
A count badge. At size 8 it is a bare dot with no number, and is hidden from assistive
|
|
5
|
+
tech: the thing it marks carries the meaning, and "notification" announced next to it
|
|
6
|
+
says nothing a screen reader user can act on.
|
|
7
|
+
|
|
8
|
+
Divergences: the [data-color-scheme="lya"] override on the primary variant is gone with
|
|
9
|
+
the scheme; primary reads the slot, as it already did. Validation throws on an unknown
|
|
10
|
+
size, variant or shape rather than rendering an unstyled badge. -->
|
|
11
|
+
|
|
12
|
+
import { assertNotificationSize, assertNotificationVariant, assertNotificationShape,
|
|
13
|
+
notificationLabel } from "./notification-variants.js";
|
|
14
|
+
|
|
15
|
+
$ {
|
|
16
|
+
const {
|
|
17
|
+
size = 20,
|
|
18
|
+
variant = "primary",
|
|
19
|
+
shape = "circle",
|
|
20
|
+
count,
|
|
21
|
+
max = 99,
|
|
22
|
+
showPlus = false,
|
|
23
|
+
showZero = false,
|
|
24
|
+
class: extraClass = "",
|
|
25
|
+
} = input;
|
|
26
|
+
|
|
27
|
+
assertNotificationSize(size);
|
|
28
|
+
assertNotificationVariant(variant);
|
|
29
|
+
assertNotificationShape(shape);
|
|
30
|
+
|
|
31
|
+
// At zero the badge disappears unless the caller says otherwise — a "0" badge is
|
|
32
|
+
// usually noise, but a counter that must show it exists is a real case.
|
|
33
|
+
const hidden = size !== 8 && count === 0 && !showZero;
|
|
34
|
+
|
|
35
|
+
const label = notificationLabel({ count, max, showPlus });
|
|
36
|
+
|
|
37
|
+
const classes = [
|
|
38
|
+
"sds-notification",
|
|
39
|
+
size === 8 ? "sds-notification--dot" : `sds-notification--${size}`,
|
|
40
|
+
`sds-notification--${variant}`,
|
|
41
|
+
shape === "square" && size !== 8 ? "sds-notification--square" : "",
|
|
42
|
+
extraClass,
|
|
43
|
+
].filter(Boolean).join(" ");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
<if(!hidden)>
|
|
47
|
+
<if(size === 8)>
|
|
48
|
+
<span class=classes aria-hidden="true"/>
|
|
49
|
+
</if>
|
|
50
|
+
<else>
|
|
51
|
+
<span class=classes aria-label=(count !== undefined ? `${label} notificações` : null)>
|
|
52
|
+
${label}
|
|
53
|
+
</span>
|
|
54
|
+
</else>
|
|
55
|
+
</if>
|