@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,78 @@
|
|
|
1
|
+
/* SDS Pagination.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Pagination/Pagination.css
|
|
3
|
+
by scripts/port-css.mjs. Divergences beyond the mechanical rename are noted inline.
|
|
4
|
+
*//* ── Pagination ─────────────────────────────────────────────────────────
|
|
5
|
+
3-column grid: info (left) | page controls (center) | jump/spacer (right).
|
|
6
|
+
BEM root: .sds-pagination
|
|
7
|
+
─────────────────────────────────────────────────────────────────── */
|
|
8
|
+
|
|
9
|
+
.sds-pagination {
|
|
10
|
+
display: grid;
|
|
11
|
+
grid-template-columns: 1fr auto 1fr;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: var(--spacing-4);
|
|
14
|
+
}
|
|
15
|
+
@media (max-width: 799px) {
|
|
16
|
+
.sds-pagination {
|
|
17
|
+
grid-template-columns: 1fr;
|
|
18
|
+
justify-items: center;
|
|
19
|
+
gap: var(--spacing-3);
|
|
20
|
+
}
|
|
21
|
+
.sds-pagination__spacer {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/* ── Left info ("Showing [10 ▼] of 48 items") ── */
|
|
26
|
+
.sds-pagination__info {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: var(--spacing-2);
|
|
30
|
+
}
|
|
31
|
+
.sds-pagination__info-text {
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
}
|
|
34
|
+
/* ── Center: prev button + pills + next button ── */
|
|
35
|
+
.sds-pagination__controls {
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: var(--spacing-4); /* 16px between arrows and page group */
|
|
39
|
+
/* Divergence: the arrows stay put and the numbers scroll between them.
|
|
40
|
+
Ten pages at 44px need 500px before the arrows and the gaps, so on a phone this row
|
|
41
|
+
did not fit — measured at 375px, it reached 422 and took the whole page sideways
|
|
42
|
+
with it. KDLS has the same row and says nothing about what happens when it is too
|
|
43
|
+
wide. Scrolling the numbers keeps prev and next where the thumb expects them. */
|
|
44
|
+
max-width: 100%;
|
|
45
|
+
min-width: 0;
|
|
46
|
+
}
|
|
47
|
+
.sds-pagination__pages {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: var(--spacing-2); /* 8px between pills and ellipsis */
|
|
51
|
+
min-width: 0;
|
|
52
|
+
overflow-x: auto;
|
|
53
|
+
/* Room for the scrollbar so it does not sit on top of the pills. */
|
|
54
|
+
padding-bottom: var(--spacing-1);
|
|
55
|
+
}
|
|
56
|
+
.sds-pagination__controls > .sds-icon-button,
|
|
57
|
+
.sds-pagination__controls > button {
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
}
|
|
60
|
+
.sds-pagination__controls .sds-pill {
|
|
61
|
+
width: 44px;
|
|
62
|
+
padding: 0;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
}
|
|
65
|
+
/* ── Ellipsis between page groups ── */
|
|
66
|
+
.sds-pagination__ellipsis {
|
|
67
|
+
font-family: var(--font-family-base);
|
|
68
|
+
font-size: var(--font-size-body-sm);
|
|
69
|
+
color: var(--body-color);
|
|
70
|
+
padding: 0 var(--spacing-1);
|
|
71
|
+
display: inline-flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
height: 40px;
|
|
74
|
+
}
|
|
75
|
+
/* ── Right spacer — mirrors info width to keep controls centered ── */
|
|
76
|
+
.sds-pagination__spacer {
|
|
77
|
+
/* intentionally empty */
|
|
78
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which page numbers a pagination control shows.
|
|
3
|
+
*
|
|
4
|
+
* Ported verbatim from kdls-design-system v2.5.1 (0f3edf8) components/Pagination/Pagination.tsx.
|
|
5
|
+
* Pulled out because it is pure and because the edge cases — the first pages, the last
|
|
6
|
+
* pages, a total small enough that no gap is needed — are exactly where an off-by-one
|
|
7
|
+
* hides and nobody notices until a customer cannot reach page 2.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Every page size the component will accept. */
|
|
11
|
+
export const PAGE_SIZES = [10, 20, 50, 500];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The sizes the selector offers, which is not the same list.
|
|
15
|
+
*
|
|
16
|
+
* 500 is accepted and never offered — KDLS marks it `@internal`, for a caller that sets it
|
|
17
|
+
* itself (its own icon catalogue does). Offering it put "500 itens por página" in front of
|
|
18
|
+
* a visitor as an ordinary choice, and a listing of five hundred property cards is a page
|
|
19
|
+
* that takes seconds to paint and cannot be scrolled back from.
|
|
20
|
+
*/
|
|
21
|
+
export const PAGE_SIZE_OPTIONS = [10, 20, 50];
|
|
22
|
+
export const SIBLING_COUNTS = [1, 2, 3];
|
|
23
|
+
|
|
24
|
+
export const GAP = '…';
|
|
25
|
+
|
|
26
|
+
/** How many pages a total splits into. Always at least one, even with nothing to show. */
|
|
27
|
+
export const pageCount = (totalItems, pageSize) => Math.max(1, Math.ceil(totalItems / pageSize));
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The first page, the last page, and `siblingCount` pages either side of the current one.
|
|
31
|
+
* A gap marker stands wherever the run is broken.
|
|
32
|
+
*/
|
|
33
|
+
export function buildPages(page, totalPages, siblingCount = 1) {
|
|
34
|
+
const near = new Set(
|
|
35
|
+
[
|
|
36
|
+
1,
|
|
37
|
+
totalPages,
|
|
38
|
+
...Array.from({ length: siblingCount * 2 + 1 }, (_, i) => page - siblingCount + i),
|
|
39
|
+
].filter((p) => p >= 1 && p <= totalPages),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const result = [];
|
|
43
|
+
let previous = null;
|
|
44
|
+
|
|
45
|
+
for (const p of [...near].sort((a, b) => a - b)) {
|
|
46
|
+
if (previous !== null && p - previous > 1) result.push(GAP);
|
|
47
|
+
result.push(p);
|
|
48
|
+
previous = p;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function assertPageSize(size) {
|
|
55
|
+
if (!PAGE_SIZES.includes(size)) {
|
|
56
|
+
throw new Error(`Unknown page size: "${size}". Allowed: ${PAGE_SIZES.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
return size;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function assertSiblingCount(count) {
|
|
62
|
+
if (!SIBLING_COUNTS.includes(count)) {
|
|
63
|
+
throw new Error(`Unknown sibling count: "${count}". Allowed: ${SIBLING_COUNTS.join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
return count;
|
|
66
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<!-- sds-pagination — ported from kdls-design-system v2.5.1 (0f3edf8)
|
|
2
|
+
components/Pagination/Pagination.tsx.
|
|
3
|
+
|
|
4
|
+
Which page numbers to show is in pagination-pages.js, tested on its own: the edges are
|
|
5
|
+
exactly where an off-by-one hides until a customer cannot reach page 2.
|
|
6
|
+
|
|
7
|
+
It hydrates, because the buttons have to navigate. It holds no state — the current page
|
|
8
|
+
comes from the caller, which is the thing that knows what it is showing.
|
|
9
|
+
|
|
10
|
+
Divergences:
|
|
11
|
+
|
|
12
|
+
It is a <nav> with an aria-label, and the page buttons carry aria-current. KDLS rendered
|
|
13
|
+
loose Pills, so a screen reader met a row of unrelated buttons with no way to tell which
|
|
14
|
+
page it was on.
|
|
15
|
+
|
|
16
|
+
The gap is aria-hidden. An ellipsis read aloud says nothing useful, and the pages either
|
|
17
|
+
side of it already say what is skipped. -->
|
|
18
|
+
|
|
19
|
+
import { buildPages, pageCount, GAP, PAGE_SIZES, PAGE_SIZE_OPTIONS, assertPageSize, assertSiblingCount }
|
|
20
|
+
from "./pagination-pages.js";
|
|
21
|
+
|
|
22
|
+
class {
|
|
23
|
+
go(page) {
|
|
24
|
+
const { currentPage, totalItems, pageSize = 20, disabled, onChange } = this.input;
|
|
25
|
+
if (disabled) return;
|
|
26
|
+
const total = pageCount(totalItems, pageSize);
|
|
27
|
+
if (page < 1 || page > total || page === currentPage) return;
|
|
28
|
+
onChange?.(page, pageSize);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
previous() { this.go(this.input.currentPage - 1); }
|
|
32
|
+
next() { this.go(this.input.currentPage + 1); }
|
|
33
|
+
|
|
34
|
+
handleSizeChange(size) {
|
|
35
|
+
const next = Number(size);
|
|
36
|
+
// Changing the page size moves the visitor back to the first page: staying on page 9
|
|
37
|
+
// of a list that now has four is how a "no results" screen appears out of nowhere.
|
|
38
|
+
this.input.onChange?.(1, next);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
$ {
|
|
43
|
+
const {
|
|
44
|
+
currentPage,
|
|
45
|
+
totalItems,
|
|
46
|
+
pageSize = 20,
|
|
47
|
+
siblingCount = 2,
|
|
48
|
+
showSizeChanger = false,
|
|
49
|
+
hideOnSinglePage = false,
|
|
50
|
+
disabled = false,
|
|
51
|
+
label = "Paginação",
|
|
52
|
+
class: extraClass = "",
|
|
53
|
+
} = input;
|
|
54
|
+
|
|
55
|
+
if (typeof currentPage !== "number") throw new Error("sds-pagination needs a numeric `currentPage`.");
|
|
56
|
+
if (typeof totalItems !== "number") throw new Error("sds-pagination needs a numeric `totalItems`.");
|
|
57
|
+
assertPageSize(pageSize);
|
|
58
|
+
assertSiblingCount(siblingCount);
|
|
59
|
+
|
|
60
|
+
const totalPages = pageCount(totalItems, pageSize);
|
|
61
|
+
// No items, no page buttons. `pageCount` clamps to 1 so that nothing divides by zero,
|
|
62
|
+
// and the clamp leaked into the buttons: an empty list rendered an active "1", telling
|
|
63
|
+
// the visitor they are on page 1 of a list that has nothing on any page. KDLS renders
|
|
64
|
+
// none, and the info text beside it already says there is nothing.
|
|
65
|
+
const pages = totalItems === 0 ? [] : buildPages(currentPage, totalPages, siblingCount);
|
|
66
|
+
const hidden = hideOnSinglePage && totalPages <= 1;
|
|
67
|
+
|
|
68
|
+
const first = totalItems === 0 ? 0 : (currentPage - 1) * pageSize + 1;
|
|
69
|
+
const last = Math.min(currentPage * pageSize, totalItems);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
<if(!hidden)>
|
|
73
|
+
<nav class=`sds-pagination ${extraClass}`.trim() aria-label=label>
|
|
74
|
+
<div class="sds-pagination__info">
|
|
75
|
+
<sds-text as="span" variant="labelRegular" class="sds-pagination__info-text">
|
|
76
|
+
${first}–${last} de ${totalItems}
|
|
77
|
+
</sds-text>
|
|
78
|
+
<if(showSizeChanger)>
|
|
79
|
+
<sds-select
|
|
80
|
+
label="Itens por página"
|
|
81
|
+
trigger="navButton"
|
|
82
|
+
value=String(pageSize)
|
|
83
|
+
options=PAGE_SIZE_OPTIONS.map((size) => ({ label: String(size), value: String(size) }))
|
|
84
|
+
onChange=(size) => component.handleSizeChange(size)
|
|
85
|
+
disabled=disabled
|
|
86
|
+
// `clearable={false}`, because sds-select defaults it to true and a page size has
|
|
87
|
+
// no empty. Clearing reported `null`, which `Number(null)` turned into a page size
|
|
88
|
+
// of 0 — and `pageCount` divides by it. There is no state of this control that
|
|
89
|
+
// means "no size": every list has one.
|
|
90
|
+
clearable=false
|
|
91
|
+
/>
|
|
92
|
+
</if>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
// The controls come SECOND, and the spacer last.
|
|
96
|
+
//
|
|
97
|
+
// The grid is `1fr auto 1fr` and places children in order, so whatever is second takes
|
|
98
|
+
// the centre column. With the spacer there, the page buttons were pushed into the
|
|
99
|
+
// trailing 1fr and sat left-aligned inside it rather than centred under the list. KDLS
|
|
100
|
+
// emits info → controls → spacer for exactly this reason.
|
|
101
|
+
<div class="sds-pagination__controls">
|
|
102
|
+
<sds-icon-button
|
|
103
|
+
variant="neutral"
|
|
104
|
+
aria-label="Página anterior"
|
|
105
|
+
disabled=(disabled || currentPage <= 1)
|
|
106
|
+
onClick=() => component.previous()
|
|
107
|
+
>
|
|
108
|
+
<@icon><fluent-chevron-left-regular/></@icon>
|
|
109
|
+
</sds-icon-button>
|
|
110
|
+
|
|
111
|
+
<div class="sds-pagination__pages">
|
|
112
|
+
<for|entry| of=pages>
|
|
113
|
+
<if(entry === GAP)>
|
|
114
|
+
<span class="sds-pagination__ellipsis" aria-hidden="true">${GAP}</span>
|
|
115
|
+
</if>
|
|
116
|
+
<else>
|
|
117
|
+
<sds-pill
|
|
118
|
+
label=String(entry)
|
|
119
|
+
active=(entry === currentPage)
|
|
120
|
+
disabled=disabled
|
|
121
|
+
aria-label=`Página ${entry}`
|
|
122
|
+
aria-current=(entry === currentPage ? "page" : null)
|
|
123
|
+
onClick=() => component.go(entry)
|
|
124
|
+
/>
|
|
125
|
+
</else>
|
|
126
|
+
</for>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<sds-icon-button
|
|
130
|
+
variant="neutral"
|
|
131
|
+
aria-label="Próxima página"
|
|
132
|
+
disabled=(disabled || currentPage >= totalPages)
|
|
133
|
+
onClick=() => component.next()
|
|
134
|
+
>
|
|
135
|
+
<@icon><fluent-chevron-right-regular/></@icon>
|
|
136
|
+
</sds-icon-button>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<div class="sds-pagination__spacer" aria-hidden="true"/>
|
|
140
|
+
</nav>
|
|
141
|
+
</if>
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/* SDS Pill.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Pill/Pill.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-pill--off:hover:not(:disabled):not(.sds-pill--loading)
|
|
7
|
+
[data-color-scheme="lya"] .sds-pill--on
|
|
8
|
+
[data-color-scheme="lya"] .sds-pill--on:hover:not(:disabled):not(.sds-pill--loading)
|
|
9
|
+
[data-color-scheme="lya"] .sds-pill--on:active:not(:disabled):not(.sds-pill--loading)
|
|
10
|
+
*//* ============================================================
|
|
11
|
+
SDS Pill — Filter Chip
|
|
12
|
+
Height: 40px (equal to Toggle)
|
|
13
|
+
Status: off (outlined) | on (filled primary)
|
|
14
|
+
States: enabled | hover | pressed | focused | disabled
|
|
15
|
+
Icons: left icon | chevron | filter | notification badge
|
|
16
|
+
============================================================ */
|
|
17
|
+
|
|
18
|
+
.sds-pill {
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: var(--spacing-2);
|
|
22
|
+
height: 40px;
|
|
23
|
+
|
|
24
|
+
padding: 0 var(--spacing-4);
|
|
25
|
+
/* soft, the install default — see the note by the scheme overrides below */
|
|
26
|
+
border-radius: 11px;
|
|
27
|
+
font-family: var(--font-family-base);
|
|
28
|
+
font-size: var(--font-size-body-md); /* 16px */
|
|
29
|
+
font-weight: var(--font-weight-medium);
|
|
30
|
+
line-height: var(--lh-body-md); /* 24px */
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
border: 1px solid transparent;
|
|
34
|
+
transition:
|
|
35
|
+
background-color 120ms ease,
|
|
36
|
+
color 120ms ease,
|
|
37
|
+
border-color 120ms ease,
|
|
38
|
+
box-shadow 120ms ease;
|
|
39
|
+
position: relative;
|
|
40
|
+
outline: none;
|
|
41
|
+
-webkit-font-smoothing: antialiased;
|
|
42
|
+
user-select: none;
|
|
43
|
+
}
|
|
44
|
+
/* ──────────────────────────────────────────────
|
|
45
|
+
STATUS: OFF — outlined / ghost
|
|
46
|
+
────────────────────────────────────────────── */
|
|
47
|
+
.sds-pill--off {
|
|
48
|
+
background-color: var(--component-bg-color);
|
|
49
|
+
color: var(--color-neutral-80);
|
|
50
|
+
border-color: var(--border-interactive-color);
|
|
51
|
+
}
|
|
52
|
+
.sds-pill--off:hover:not(:disabled):not(.sds-pill--loading) {
|
|
53
|
+
background-color: var(--component-bg-color);
|
|
54
|
+
border-color: var(--color-primary-50-solid);
|
|
55
|
+
}
|
|
56
|
+
.sds-pill--off:active:not(:disabled):not(.sds-pill--loading) {
|
|
57
|
+
background-color: var(--color-neutral-20);
|
|
58
|
+
border-color: var(--color-neutral-60);
|
|
59
|
+
color: var(--color-neutral-90);
|
|
60
|
+
}
|
|
61
|
+
.sds-pill--off:focus-visible {
|
|
62
|
+
box-shadow: var(--focus-ring);
|
|
63
|
+
}
|
|
64
|
+
/* ──────────────────────────────────────────────
|
|
65
|
+
STATUS: ON — filled primary
|
|
66
|
+
────────────────────────────────────────────── */
|
|
67
|
+
.sds-pill--on {
|
|
68
|
+
background: var(--color-primary-50);
|
|
69
|
+
color: var(--color-on-primary);
|
|
70
|
+
border-color: var(--color-primary-50-solid);
|
|
71
|
+
}
|
|
72
|
+
.sds-pill--on:hover:not(:disabled):not(.sds-pill--loading) {
|
|
73
|
+
background: var(--color-primary-60);
|
|
74
|
+
border-color: var(--color-primary-60-solid);
|
|
75
|
+
}
|
|
76
|
+
.sds-pill--on:active:not(:disabled):not(.sds-pill--loading) {
|
|
77
|
+
background: var(--color-primary-70);
|
|
78
|
+
border-color: var(--color-primary-70-solid);
|
|
79
|
+
}
|
|
80
|
+
.sds-pill--on:focus-visible {
|
|
81
|
+
box-shadow: var(--focus-ring);
|
|
82
|
+
}
|
|
83
|
+
/* ──────────────────────────────────────────────
|
|
84
|
+
DISABLED
|
|
85
|
+
────────────────────────────────────────────── */
|
|
86
|
+
.sds-pill:disabled,
|
|
87
|
+
.sds-pill[aria-disabled="true"] {
|
|
88
|
+
background-color: var(--color-neutral-20) !important;
|
|
89
|
+
border-color: var(--border-static-color) !important;
|
|
90
|
+
color: var(--color-neutral-40) !important;
|
|
91
|
+
cursor: not-allowed;
|
|
92
|
+
}
|
|
93
|
+
.sds-pill--loading {
|
|
94
|
+
cursor: wait;
|
|
95
|
+
}
|
|
96
|
+
.sds-pill--off:disabled,
|
|
97
|
+
.sds-pill--off[aria-disabled="true"] {
|
|
98
|
+
background-color: transparent !important;
|
|
99
|
+
}
|
|
100
|
+
[data-theme="dark"] .sds-pill:disabled,
|
|
101
|
+
[data-theme="dark"] .sds-pill[aria-disabled="true"] {
|
|
102
|
+
background-color: var(--color-neutral-30) !important;
|
|
103
|
+
border-color: var(--border-interactive-color) !important;
|
|
104
|
+
color: var(--color-neutral-40) !important;
|
|
105
|
+
}
|
|
106
|
+
[data-theme="dark"] .sds-pill--off:disabled,
|
|
107
|
+
[data-theme="dark"] .sds-pill--off[aria-disabled="true"] {
|
|
108
|
+
background-color: transparent !important;
|
|
109
|
+
}
|
|
110
|
+
/* ──────────────────────────────────────────────
|
|
111
|
+
INNER ELEMENTS
|
|
112
|
+
────────────────────────────────────────────── */
|
|
113
|
+
.sds-pill__icon,
|
|
114
|
+
.sds-pill__icon-right {
|
|
115
|
+
display: inline-flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
font-size: 24px;
|
|
118
|
+
flex-shrink: 0;
|
|
119
|
+
}
|
|
120
|
+
.sds-pill__label {
|
|
121
|
+
text-align: left;
|
|
122
|
+
}
|
|
123
|
+
/* ── Width ── */
|
|
124
|
+
.sds-pill--fill { width: 100%; justify-content: flex-start; }
|
|
125
|
+
.sds-pill--fill .sds-pill__label { flex: 1; }
|
|
126
|
+
/* ── Clickable icon-right (dismiss) ── */
|
|
127
|
+
.sds-pill__icon-right--clickable {
|
|
128
|
+
cursor: pointer;
|
|
129
|
+
border-radius: var(--radius-sm);
|
|
130
|
+
transition: background-color 120ms ease;
|
|
131
|
+
padding: var(--spacing-0-5);
|
|
132
|
+
}
|
|
133
|
+
.sds-pill__icon-right--clickable:hover { background-color: var(--color-opacity-05); }
|
|
134
|
+
.sds-pill__icon-right--clickable:active { background-color: var(--color-opacity-10); }
|
|
135
|
+
/* ── Corner Radius Scheme overrides ──
|
|
136
|
+
Carried from KDLS unchanged, including the numbers, which are not arbitrary: they are a
|
|
137
|
+
proportion of the control's own height, and that is what keeps the four schemes reading
|
|
138
|
+
as one family rather than four unrelated shapes.
|
|
139
|
+
|
|
140
|
+
height 40px flat 0 soft 11px medium 15px rounded 20px (a capsule)
|
|
141
|
+
as a fraction 0 0.275 0.375 0.5
|
|
142
|
+
|
|
143
|
+
The same fractions give the Toggle's 32px item 9px and 12px — see Toggle.css. A radius
|
|
144
|
+
taken from --radius-md instead would be 16px and 24px here, and 24px on a 40px control
|
|
145
|
+
is past half its height, so the medium scheme would draw the same capsule as rounded and
|
|
146
|
+
two of the four schemes would collapse into one.
|
|
147
|
+
|
|
148
|
+
(Briefly changed to --radius-md - 2px on 2026-09-10 and changed back the same day:
|
|
149
|
+
Rafael pointed out that KDLS gets soft, medium and rounded right as they stand.)
|
|
150
|
+
|
|
151
|
+
The base value is `soft`, because `soft` is what an install without a data-radius
|
|
152
|
+
attribute gets.
|
|
153
|
+
|
|
154
|
+
KDLS's default scheme was `default`, Kenlo's own, and it lived unnamed in :root — so
|
|
155
|
+
KDLS's base rule here is `default`'s value and the four named schemes override it. SDS
|
|
156
|
+
removed `default` and promoted `soft`, and foundations/theme-server.js deliberately does
|
|
157
|
+
not stamp an attribute for the value that is already the default. The base rule was
|
|
158
|
+
therefore still answering for a scheme that no longer exists: with the install defaults
|
|
159
|
+
this control rendered as a capsule instead of 11px.
|
|
160
|
+
|
|
161
|
+
tokens.css already solves this the same way — :root carries soft's values and each
|
|
162
|
+
[data-radius] block overrides them. The named rules below stay for when the attribute is
|
|
163
|
+
stamped, and `rounded` is now explicit because it can no longer fall through to the base.
|
|
164
|
+
*/
|
|
165
|
+
[data-radius="flat"] .sds-pill { border-radius: 0; }
|
|
166
|
+
/* Kept in parity with Toggle's outer container, which is the same 40px tall */
|
|
167
|
+
[data-radius="soft"] .sds-pill { border-radius: 11px; }
|
|
168
|
+
[data-radius="medium"] .sds-pill { border-radius: 15px; }
|
|
169
|
+
[data-radius="rounded"] .sds-pill { border-radius: var(--radius-full); }
|
|
170
|
+
/* ── Notification inside active Pill — inverted colors ── */
|
|
171
|
+
.sds-pill--on .sds-notification {
|
|
172
|
+
background-color: var(--color-on-primary);
|
|
173
|
+
color: var(--color-primary-50-solid);
|
|
174
|
+
}
|
|
175
|
+
/* ── Notification inside disabled Pill ── */
|
|
176
|
+
.sds-pill:disabled .sds-notification,
|
|
177
|
+
.sds-pill[aria-disabled="true"] .sds-notification {
|
|
178
|
+
background-color: var(--color-neutral-40);
|
|
179
|
+
color: var(--color-neutral-20);
|
|
180
|
+
}
|
|
181
|
+
[data-theme="dark"] .sds-pill:disabled .sds-notification,
|
|
182
|
+
[data-theme="dark"] .sds-pill[aria-disabled="true"] .sds-notification {
|
|
183
|
+
color: var(--color-neutral-30);
|
|
184
|
+
}
|
|
185
|
+
/* ──────────────────────────────────────────────
|
|
186
|
+
DARK MODE
|
|
187
|
+
────────────────────────────────────────────── */
|
|
188
|
+
[data-theme="dark"] .sds-pill--off:hover:not(:disabled):not(.sds-pill--loading) {
|
|
189
|
+
background-color: transparent;
|
|
190
|
+
}
|
|
191
|
+
[data-theme="dark"] .sds-pill--off:active:not(:disabled):not(.sds-pill--loading) {
|
|
192
|
+
background-color: var(--color-neutral-30);
|
|
193
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Pill's vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/Pill/Pill.tsx.
|
|
5
|
+
*
|
|
6
|
+
* Only `width` is a closed set: everything else about a pill is a boolean or a label.
|
|
7
|
+
* It was read as `width === "fill" ? … : ""`, which silently treated every typo as hug.
|
|
8
|
+
*/
|
|
9
|
+
export const PILL_WIDTHS = ['hug', 'fill'];
|
|
10
|
+
|
|
11
|
+
export function assertPillWidth(width) {
|
|
12
|
+
if (!PILL_WIDTHS.includes(width)) {
|
|
13
|
+
throw new Error(`Unknown pill width: "${width}". Allowed: ${PILL_WIDTHS.join(', ')}`);
|
|
14
|
+
}
|
|
15
|
+
return width;
|
|
16
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<!-- sds-pill — ported from kdls-design-system v2.5.1 (0f3edf8) components/Pill/Pill.tsx.
|
|
2
|
+
|
|
3
|
+
A toggle shaped like a chip: a filter that is on or off. It is a real <button> with
|
|
4
|
+
aria-pressed, which is what tells a screen reader this is a toggle and not a link — and it
|
|
5
|
+
hydrates, for the same reason every button does.
|
|
6
|
+
|
|
7
|
+
A known limitation, carried over rather than fixed: when the right icon has its own
|
|
8
|
+
action it is a <span role="button">, not a real button. A <button> cannot contain another
|
|
9
|
+
<button> — that is invalid HTML — and the pill itself is the button. Making the icon
|
|
10
|
+
properly focusable means the pill stops being a <button> and becomes a container with two
|
|
11
|
+
of them inside, which changes its whole keyboard and ARIA story. That is a design decision,
|
|
12
|
+
not a port decision, so it is left as KDLS had it and recorded here.
|
|
13
|
+
|
|
14
|
+
Divergence: notification renders through sds-notification instead of being drawn inline. -->
|
|
15
|
+
import { assertPillWidth } from "./pill-variants.js";
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class {
|
|
19
|
+
handleClick(event) {
|
|
20
|
+
const { disabled, isLoading, onClick } = this.input;
|
|
21
|
+
if (disabled || isLoading) {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
onClick?.(event);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Enter and Space on the right icon.
|
|
30
|
+
*
|
|
31
|
+
* It carries `role="button"` and `tabindex="0"`, so the keyboard can reach it and a
|
|
32
|
+
* screen reader announces it as a button — and then nothing happened, because only
|
|
33
|
+
* `click` was wired. A control that takes focus, says it is a button and does nothing
|
|
34
|
+
* when you press it is worse than one you cannot reach: you are told it works.
|
|
35
|
+
*
|
|
36
|
+
* KDLS has this handler; the port dropped it. `stopPropagation` matters as much as the
|
|
37
|
+
* call: without it the key reaches the pill it sits inside and opens what you were
|
|
38
|
+
* trying to clear.
|
|
39
|
+
*/
|
|
40
|
+
iconRightKey(event) {
|
|
41
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
this.handleIconRight(event);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
handleIconRight(event) {
|
|
47
|
+
event.stopPropagation();
|
|
48
|
+
const { disabled, isLoading, onClickIconRight } = this.input;
|
|
49
|
+
if (disabled || isLoading) {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
onClickIconRight?.(event);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
$ {
|
|
58
|
+
const {
|
|
59
|
+
label,
|
|
60
|
+
active = false,
|
|
61
|
+
width = "hug",
|
|
62
|
+
iconLeft,
|
|
63
|
+
iconRight,
|
|
64
|
+
onClickIconRight,
|
|
65
|
+
iconRightLabel = "Remover",
|
|
66
|
+
showNotification = false,
|
|
67
|
+
notificationCount,
|
|
68
|
+
isLoading = false,
|
|
69
|
+
disabled = false,
|
|
70
|
+
class: extraClass = "",
|
|
71
|
+
} = input;
|
|
72
|
+
|
|
73
|
+
assertPillWidth(width);
|
|
74
|
+
|
|
75
|
+
// Marko camelCases a hyphenated attribute written on a component tag, capitalising only
|
|
76
|
+
// the letter after the hyphen: aria-haspopup arrives as `ariaHaspopup`, not
|
|
77
|
+
// `ariaHasPopup`. Guessing that spelling by hand is how an attribute silently goes
|
|
78
|
+
// missing — the pill announced itself as a pressed switch for exactly that reason. So
|
|
79
|
+
// the rule is applied rather than remembered, and both forms are read: a template writes
|
|
80
|
+
// the first, a test or a loop passes the second.
|
|
81
|
+
const aria = (name) => input[`aria-${name}`]
|
|
82
|
+
?? input[`aria${name[0].toUpperCase()}${name.slice(1)}`]
|
|
83
|
+
?? null;
|
|
84
|
+
|
|
85
|
+
const ariaLabel = aria("label");
|
|
86
|
+
// A pill is a toggle by default, and aria-pressed is what says so. Two callers need it
|
|
87
|
+
// to be something else, and a control cannot be two things at once:
|
|
88
|
+
//
|
|
89
|
+
// aria-current a navigation marker — the page you are on, in Pagination
|
|
90
|
+
// aria-haspopup a disclosure — the trigger of a Select, which opens a listbox
|
|
91
|
+
//
|
|
92
|
+
// Either one takes over the announcement. A button claiming to be a pressed switch *and*
|
|
93
|
+
// the current page, or a pressed switch that also opens a menu, tells a screen reader two
|
|
94
|
+
// stories about itself and the visitor hears the wrong one.
|
|
95
|
+
const ariaCurrent = aria("current");
|
|
96
|
+
const ariaHasPopup = aria("haspopup");
|
|
97
|
+
const ariaExpanded = aria("expanded");
|
|
98
|
+
const ariaControls = aria("controls");
|
|
99
|
+
if (!label && !ariaLabel) {
|
|
100
|
+
throw new Error("sds-pill needs a `label`, or an `aria-label` when it shows only an icon.");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const renderable = (value) => (value && value.renderBody) || value;
|
|
104
|
+
const loading = isLoading && !disabled;
|
|
105
|
+
|
|
106
|
+
const classes = [
|
|
107
|
+
"sds-pill",
|
|
108
|
+
active ? "sds-pill--on" : "sds-pill--off",
|
|
109
|
+
disabled ? "sds-pill--disabled" : "",
|
|
110
|
+
loading ? "sds-pill--loading" : "",
|
|
111
|
+
width === "fill" ? "sds-pill--fill" : "",
|
|
112
|
+
extraClass,
|
|
113
|
+
].filter(Boolean).join(" ");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
class=classes
|
|
119
|
+
aria-pressed=(ariaCurrent || ariaHasPopup ? null : (active ? "true" : "false"))
|
|
120
|
+
aria-current=ariaCurrent
|
|
121
|
+
aria-haspopup=ariaHasPopup
|
|
122
|
+
aria-expanded=ariaExpanded
|
|
123
|
+
aria-controls=ariaControls
|
|
124
|
+
aria-busy=(loading ? "true" : null)
|
|
125
|
+
aria-label=ariaLabel
|
|
126
|
+
disabled=(disabled || null)
|
|
127
|
+
on-click("handleClick")
|
|
128
|
+
>
|
|
129
|
+
<if(loading)>
|
|
130
|
+
<sds-spinner size="sm" decorative/>
|
|
131
|
+
</if>
|
|
132
|
+
<else-if(iconLeft)>
|
|
133
|
+
<span class="sds-pill__icon" aria-hidden="true">
|
|
134
|
+
<sds-icon size="sm"><${renderable(iconLeft)}/></sds-icon>
|
|
135
|
+
</span>
|
|
136
|
+
</else-if>
|
|
137
|
+
|
|
138
|
+
<if(label)>
|
|
139
|
+
<span class="sds-pill__label">${label}</span>
|
|
140
|
+
</if>
|
|
141
|
+
|
|
142
|
+
<if(showNotification || notificationCount !== undefined)>
|
|
143
|
+
<!-- No wrapper: KDLS renders it as a direct flex child, and a wrapper with no rule
|
|
144
|
+
behind it is an unstyled block in the middle of a row. -->
|
|
145
|
+
<sds-notification count=notificationCount size=(notificationCount === undefined ? 8 : 16)/>
|
|
146
|
+
</if>
|
|
147
|
+
|
|
148
|
+
<if(iconRight && onClickIconRight)>
|
|
149
|
+
<span
|
|
150
|
+
class="sds-pill__icon-right sds-pill__icon-right--clickable"
|
|
151
|
+
role="button"
|
|
152
|
+
tabindex="0"
|
|
153
|
+
aria-label=iconRightLabel
|
|
154
|
+
on-click("handleIconRight")
|
|
155
|
+
on-keydown("iconRightKey")
|
|
156
|
+
>
|
|
157
|
+
<sds-icon size="sm"><${renderable(iconRight)}/></sds-icon>
|
|
158
|
+
</span>
|
|
159
|
+
</if>
|
|
160
|
+
<else-if(iconRight)>
|
|
161
|
+
<span class="sds-pill__icon-right" aria-hidden="true">
|
|
162
|
+
<sds-icon size="sm"><${renderable(iconRight)}/></sds-icon>
|
|
163
|
+
</span>
|
|
164
|
+
</else-if>
|
|
165
|
+
</button>
|