@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,181 @@
|
|
|
1
|
+
/* SDS SearchBar.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/Field/Field.css — the shell.
|
|
3
|
+
KDLS's own SearchBar.css adds only the suggestions panel, which lands here in Phase 2.
|
|
4
|
+
by scripts/port-css.mjs. Divergences beyond the mechanical rename are noted inline.
|
|
5
|
+
|
|
6
|
+
Rules removed with the brand families they targeted:
|
|
7
|
+
[data-color-scheme="lya"] .sds-search-bar__input
|
|
8
|
+
[data-color-scheme="lya"] .sds-search-bar:focus-within
|
|
9
|
+
*//* ══════════════════════════════════════════════════════════════════════════
|
|
10
|
+
SEARCH BAR — the field shell (Input has its own; see the component header)
|
|
11
|
+
Structure mirrored from Input: flex row (gap + padding), 24px icons
|
|
12
|
+
as children, floating label or placeholder.
|
|
13
|
+
Sizes: lg 56px · md 48px · sm 40px
|
|
14
|
+
══════════════════════════════════════════════════════════════════════════ */
|
|
15
|
+
|
|
16
|
+
.sds-search-bar {
|
|
17
|
+
position: relative;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: var(--spacing-3);
|
|
21
|
+
padding: 0 var(--spacing-4);
|
|
22
|
+
border: 1px solid var(--border-interactive-color);
|
|
23
|
+
border-radius: var(--radius-md);
|
|
24
|
+
background-color: var(--component-bg-color);
|
|
25
|
+
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
26
|
+
cursor: text;
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
}
|
|
29
|
+
/* ── Heights ── */
|
|
30
|
+
.sds-search-bar--lg { height: 56px; min-height: 56px; }
|
|
31
|
+
.sds-search-bar--md { height: 48px; min-height: 48px; }
|
|
32
|
+
.sds-search-bar--sm { height: 40px; min-height: 40px; }
|
|
33
|
+
/* ── Hover / Focus ── */
|
|
34
|
+
.sds-search-bar:hover:not(:focus-within):not(.sds-search-bar--disabled) {
|
|
35
|
+
border-color: var(--color-primary-50-solid);
|
|
36
|
+
}
|
|
37
|
+
.sds-search-bar:focus-within {
|
|
38
|
+
border-color: var(--color-primary-50-solid);
|
|
39
|
+
box-shadow: var(--focus-ring);
|
|
40
|
+
}
|
|
41
|
+
/* ── Feedback ── */
|
|
42
|
+
.sds-search-bar--feedback-success { border-color: var(--color-success-50); }
|
|
43
|
+
.sds-search-bar--feedback-alert { border-color: var(--color-alert-50); }
|
|
44
|
+
.sds-search-bar--feedback-error { border-color: var(--color-error-50); }
|
|
45
|
+
.sds-search-bar--feedback-success:focus-within,
|
|
46
|
+
.sds-search-bar--feedback-alert:focus-within,
|
|
47
|
+
.sds-search-bar--feedback-error:focus-within {
|
|
48
|
+
box-shadow: var(--focus-ring);
|
|
49
|
+
}
|
|
50
|
+
/* ── Icons (flex children, 24px) ── */
|
|
51
|
+
.sds-search-bar__icon {
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
font-size: 24px;
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
width: 24px;
|
|
58
|
+
height: 24px;
|
|
59
|
+
color: var(--color-neutral-90);
|
|
60
|
+
}
|
|
61
|
+
/* KDLS styled a bare <button> here. SDS renders sds-icon-button instead — a handler in
|
|
62
|
+
this template would make Marko serialise every field on the page — so the icon slot only
|
|
63
|
+
has to make room for it. */
|
|
64
|
+
.sds-search-bar__icon--right:has(.sds-icon-button) {
|
|
65
|
+
width: auto;
|
|
66
|
+
height: auto;
|
|
67
|
+
}
|
|
68
|
+
/* ── Spinner (loading, in place of iconRight) ── */
|
|
69
|
+
.sds-search-bar__spinner {
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
flex-shrink: 0;
|
|
74
|
+
width: 24px;
|
|
75
|
+
height: 24px;
|
|
76
|
+
color: var(--color-neutral-50);
|
|
77
|
+
}
|
|
78
|
+
/* ── The field itself (label + control) ── */
|
|
79
|
+
.sds-search-bar__field {
|
|
80
|
+
flex: 1;
|
|
81
|
+
position: relative;
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-direction: column;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
min-width: 0;
|
|
86
|
+
}
|
|
87
|
+
.sds-search-bar--lg .sds-search-bar__field { min-height: 52px; }
|
|
88
|
+
/* Invisible spacer — same technique as Input (hug grows with the label) */
|
|
89
|
+
.sds-search-bar__field::before {
|
|
90
|
+
content: attr(data-label);
|
|
91
|
+
font-family: var(--font-family-base);
|
|
92
|
+
font-size: var(--font-size-body-md);
|
|
93
|
+
font-weight: var(--font-weight-regular);
|
|
94
|
+
white-space: nowrap;
|
|
95
|
+
display: block;
|
|
96
|
+
height: 0;
|
|
97
|
+
overflow: hidden;
|
|
98
|
+
visibility: hidden;
|
|
99
|
+
pointer-events: none;
|
|
100
|
+
}
|
|
101
|
+
/* ── Controle nativo ── */
|
|
102
|
+
.sds-search-bar__input {
|
|
103
|
+
border: none;
|
|
104
|
+
outline: none;
|
|
105
|
+
background: transparent;
|
|
106
|
+
font-family: var(--font-family-base);
|
|
107
|
+
font-size: var(--font-size-body-md);
|
|
108
|
+
font-weight: var(--font-weight-regular);
|
|
109
|
+
color: var(--color-neutral-90);
|
|
110
|
+
width: 100%;
|
|
111
|
+
line-height: 1;
|
|
112
|
+
caret-color: var(--color-primary-50-solid);
|
|
113
|
+
}
|
|
114
|
+
/* ── Label base ── */
|
|
115
|
+
.sds-search-bar__label {
|
|
116
|
+
position: absolute;
|
|
117
|
+
left: 0;
|
|
118
|
+
top: 50%;
|
|
119
|
+
transform: translateY(-50%);
|
|
120
|
+
pointer-events: none;
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
}
|
|
123
|
+
.sds-search-bar__field .sds-search-bar__label {
|
|
124
|
+
line-height: 1;
|
|
125
|
+
}
|
|
126
|
+
/* ── Label 'float' — rises on focus/fill ── */
|
|
127
|
+
.sds-search-bar--label-float .sds-search-bar__label {
|
|
128
|
+
color: var(--color-neutral-50);
|
|
129
|
+
transform-origin: top left;
|
|
130
|
+
transition: top 120ms ease, font-size 120ms ease, color 120ms ease, transform 120ms ease;
|
|
131
|
+
}
|
|
132
|
+
.sds-search-bar--label-float.sds-search-bar--filled .sds-search-bar__label,
|
|
133
|
+
.sds-search-bar--label-float:focus-within .sds-search-bar__label {
|
|
134
|
+
top: var(--spacing-2);
|
|
135
|
+
transform: none;
|
|
136
|
+
font-size: var(--font-size-label-sm);
|
|
137
|
+
line-height: var(--lh-label-sm);
|
|
138
|
+
}
|
|
139
|
+
.sds-search-bar--label-float .sds-search-bar__input {
|
|
140
|
+
padding-top: var(--spacing-5);
|
|
141
|
+
padding-bottom: var(--spacing-1);
|
|
142
|
+
}
|
|
143
|
+
/* ── Label 'placeholder' — disappears on focus/fill ── */
|
|
144
|
+
.sds-search-bar--label-placeholder .sds-search-bar__label {
|
|
145
|
+
color: var(--placeholder-color);
|
|
146
|
+
transition: opacity 120ms ease;
|
|
147
|
+
}
|
|
148
|
+
.sds-search-bar--label-placeholder.sds-search-bar--filled .sds-search-bar__label,
|
|
149
|
+
.sds-search-bar--label-placeholder:focus-within .sds-search-bar__label {
|
|
150
|
+
opacity: 0;
|
|
151
|
+
}
|
|
152
|
+
/* ── Loading — wait cursor on the root (mouse target); pointer-events only on the input
|
|
153
|
+
blocks click/typing without canceling the cursor (mirrors Select) ── */
|
|
154
|
+
.sds-search-bar--loading { cursor: wait; }
|
|
155
|
+
.sds-search-bar--loading .sds-search-bar__input {
|
|
156
|
+
cursor: wait;
|
|
157
|
+
pointer-events: none;
|
|
158
|
+
}
|
|
159
|
+
/* ── Disabled ── */
|
|
160
|
+
.sds-search-bar--disabled {
|
|
161
|
+
border-color: var(--border-static-color);
|
|
162
|
+
background-color: var(--color-neutral-10);
|
|
163
|
+
cursor: not-allowed;
|
|
164
|
+
}
|
|
165
|
+
.sds-search-bar--disabled > * { pointer-events: none; }
|
|
166
|
+
.sds-search-bar--disabled .sds-search-bar__input,
|
|
167
|
+
.sds-search-bar--disabled .sds-search-bar__label,
|
|
168
|
+
.sds-search-bar--disabled .sds-search-bar__icon {
|
|
169
|
+
color: var(--color-neutral-40);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* `hug` is the old behaviour: the shell is as wide as what is put in it. `fill` takes the
|
|
173
|
+
width it is given, which is what a search box inside a menu or a toolbar needs. */
|
|
174
|
+
.sds-search-bar--hug {
|
|
175
|
+
width: max-content;
|
|
176
|
+
max-width: 100%;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.sds-search-bar--fill {
|
|
180
|
+
width: 100%;
|
|
181
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SearchBar's vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/Field/Field.tsx, where these
|
|
5
|
+
* were TypeScript unions. TypeScript checks them at build time and disappears; in Marko
|
|
6
|
+
* they have to be checked at render time or an unknown value renders an unstyled shell.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const SEARCH_BAR_SIZES = ['sm', 'md', 'lg'];
|
|
10
|
+
export const SEARCH_BAR_FEEDBACK = ['none', 'success', 'alert', 'error'];
|
|
11
|
+
export const SEARCH_BAR_LABEL_MODES = ['float', 'placeholder'];
|
|
12
|
+
export const SEARCH_BAR_WIDTHS = ['hug', 'fill'];
|
|
13
|
+
|
|
14
|
+
const assert = (name, allowed) => (value) => {
|
|
15
|
+
if (!allowed.includes(value)) {
|
|
16
|
+
throw new Error(`Unknown search bar ${name}: "${value}". Allowed: ${allowed.join(', ')}`);
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const assertSearchBarSize = assert('size', SEARCH_BAR_SIZES);
|
|
22
|
+
export const assertSearchBarFeedback = assert('feedback', SEARCH_BAR_FEEDBACK);
|
|
23
|
+
export const assertSearchBarLabelMode = assert('labelMode', SEARCH_BAR_LABEL_MODES);
|
|
24
|
+
export const assertSearchBarWidth = assert('width', SEARCH_BAR_WIDTHS);
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<!-- sds-search-bar — ported from kdls-design-system v2.5.1 (0f3edf8), from two files:
|
|
2
|
+
components/Field/Field.tsx is the shell you see here, and components/SearchBar's
|
|
3
|
+
suggestions panel lands in this same component rather than wrapping it.
|
|
4
|
+
|
|
5
|
+
KDLS split them because its Field was meant as a general primitive. It never became
|
|
6
|
+
one — SearchBar is the only thing that imports it, and Input carries its own copy of
|
|
7
|
+
the markup. Rafael, 2026-09-10, named the reason that split has no future here: a
|
|
8
|
+
field in a Kenlo site is 56px, full stop, and SearchBar is the only one that varies,
|
|
9
|
+
at 40 and 48. A shell whose only job is to be three heights for one consumer is that
|
|
10
|
+
consumer. So Input refuses `size` and points here, and there is one component instead
|
|
11
|
+
of two that look the same.
|
|
12
|
+
|
|
13
|
+
Today it is the box, the icons either side, the floating label and the focus ring,
|
|
14
|
+
with the native control supplied as the body.
|
|
15
|
+
|
|
16
|
+
The search behaviour is not here yet, and that is the shape of what is missing:
|
|
17
|
+
`onChange`, `onSearch`, `onSuggestionSelect`, `onKeyDown`, `recentSearches` and the
|
|
18
|
+
panel they drive. They arrive together, in this component, when the panel does — not
|
|
19
|
+
wrapped around it. At that point it stops taking an <input> from the caller and owns
|
|
20
|
+
its own. `width` is here already because the shell has to be placeable. It
|
|
21
|
+
defaults to `fill`: the shell takes the width it is given, which is what a search box
|
|
22
|
+
in a menu, a toolbar or a control column needs, and what Input has always had. `hug`
|
|
23
|
+
is the opt-out, for the rare case where the shell should be as wide as its contents;
|
|
24
|
+
it was the default and it was the wrong one — a menu's search box sized itself to the
|
|
25
|
+
word "Buscar" and left the panel beside it.
|
|
26
|
+
|
|
27
|
+
It holds no state, and does not want any. `filled` is the caller's answer to "does
|
|
28
|
+
this control have a value", because the caller is the one holding the value. A shell
|
|
29
|
+
that tracked that itself would serialise its whole input on every instance.
|
|
30
|
+
|
|
31
|
+
Divergence: a clickable right icon is an sds-icon-button, not a handler in this
|
|
32
|
+
template. That is not cosmetic. An `on-*` bound to a value makes Marko serialise the
|
|
33
|
+
component holding it, and it decides at compile time — so a handler here would
|
|
34
|
+
serialise every instance on the page, clickable icon or not. Icon was found doing
|
|
35
|
+
exactly this. The button also arrives with focus, Enter, Space and a required name,
|
|
36
|
+
which KDLS's bare <button> with an optional aria-label did not guarantee. -->
|
|
37
|
+
|
|
38
|
+
import searchIcon from "../../icons/generated/fluent-search-regular.marko";
|
|
39
|
+
import dismissIcon from "../../icons/generated/fluent-dismiss-regular.marko";
|
|
40
|
+
import { assertSearchBarSize, assertSearchBarFeedback, assertSearchBarLabelMode, assertSearchBarWidth } from "./search-bar-variants.js";
|
|
41
|
+
|
|
42
|
+
$ {
|
|
43
|
+
const {
|
|
44
|
+
size = "lg",
|
|
45
|
+
label,
|
|
46
|
+
labelMode = "float",
|
|
47
|
+
width = "fill",
|
|
48
|
+
htmlFor,
|
|
49
|
+
filled = false,
|
|
50
|
+
onClear,
|
|
51
|
+
clearLabel = "Limpar busca",
|
|
52
|
+
disabled = false,
|
|
53
|
+
isLoading = false,
|
|
54
|
+
feedback = "none",
|
|
55
|
+
iconLeft = searchIcon,
|
|
56
|
+
iconRight,
|
|
57
|
+
onClickIconRight,
|
|
58
|
+
iconRightLabel,
|
|
59
|
+
class: extraClass = "",
|
|
60
|
+
} = input;
|
|
61
|
+
|
|
62
|
+
assertSearchBarSize(size);
|
|
63
|
+
assertSearchBarFeedback(feedback);
|
|
64
|
+
assertSearchBarLabelMode(labelMode);
|
|
65
|
+
assertSearchBarWidth(width);
|
|
66
|
+
|
|
67
|
+
if (onClickIconRight && !iconRightLabel) {
|
|
68
|
+
throw new Error("sds-search-bar needs an `iconRightLabel` when `onClickIconRight` is set — an icon button with no name is announced as just \"button\".");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const renderable = (value) => (value && value.renderBody) || value;
|
|
72
|
+
|
|
73
|
+
// The two halves of the same gesture. Empty, the magnifier on the left says what the box
|
|
74
|
+
// is for; typing, it has said it, and the space belongs to the text — so it steps aside
|
|
75
|
+
// and the way back to empty appears on the right instead. This holds for any `iconLeft`,
|
|
76
|
+
// not just the default one: in a search box the left edge is the text's the moment there
|
|
77
|
+
// is text.
|
|
78
|
+
//
|
|
79
|
+
// No state is needed for either. `filled` is the caller's answer to "is there a value",
|
|
80
|
+
// which the caller already holds, and a shell that tracked it itself would serialise its
|
|
81
|
+
// whole input on every instance.
|
|
82
|
+
const showIconLeft = iconLeft && !filled;
|
|
83
|
+
|
|
84
|
+
// A clear button is only offered when there is something to clear AND someone to clear
|
|
85
|
+
// it. Drawing one without `onClear` is the KDLS Uploader's download button: it renders,
|
|
86
|
+
// it takes focus, and clicking does nothing.
|
|
87
|
+
const showClear = filled && onClear && !disabled && !isLoading;
|
|
88
|
+
|
|
89
|
+
const classes = [
|
|
90
|
+
"sds-search-bar",
|
|
91
|
+
`sds-search-bar--${size}`,
|
|
92
|
+
`sds-search-bar--label-${labelMode}`,
|
|
93
|
+
`sds-search-bar--${width}`,
|
|
94
|
+
filled ? "sds-search-bar--filled" : "",
|
|
95
|
+
disabled ? "sds-search-bar--disabled" : "",
|
|
96
|
+
isLoading ? "sds-search-bar--loading" : "",
|
|
97
|
+
feedback !== "none" ? `sds-search-bar--feedback-${feedback}` : "",
|
|
98
|
+
extraClass,
|
|
99
|
+
].filter(Boolean).join(" ");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
<div class=classes>
|
|
103
|
+
<if(showIconLeft)>
|
|
104
|
+
<span class="sds-search-bar__icon sds-search-bar__icon--left" aria-hidden="true">
|
|
105
|
+
<sds-icon><${renderable(iconLeft)}/></sds-icon>
|
|
106
|
+
</span>
|
|
107
|
+
</if>
|
|
108
|
+
|
|
109
|
+
<!-- data-label feeds the invisible ::before spacer, which is how the box grows to fit a
|
|
110
|
+
label longer than its value. -->
|
|
111
|
+
<div class="sds-search-bar__field" data-label=label>
|
|
112
|
+
<if(label)>
|
|
113
|
+
<sds-text as="label" variant="bodyMd" class="sds-search-bar__label" for=htmlFor>
|
|
114
|
+
${label}
|
|
115
|
+
</sds-text>
|
|
116
|
+
</if>
|
|
117
|
+
<${input.renderBody}/>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<if(isLoading)>
|
|
121
|
+
<span class="sds-search-bar__spinner" aria-hidden="true">
|
|
122
|
+
<sds-spinner size="sm" decorative/>
|
|
123
|
+
</span>
|
|
124
|
+
</if>
|
|
125
|
+
<else-if(showClear)>
|
|
126
|
+
// Ahead of `iconRight`: whatever else the right side was for, clearing the search the
|
|
127
|
+
// reader is looking at is the more immediate thing to offer.
|
|
128
|
+
<span class="sds-search-bar__icon sds-search-bar__icon--right">
|
|
129
|
+
<sds-icon-button
|
|
130
|
+
variant="neutral"
|
|
131
|
+
size="sm"
|
|
132
|
+
aria-label=clearLabel
|
|
133
|
+
onClick=onClear
|
|
134
|
+
>
|
|
135
|
+
<@icon><${dismissIcon}/></@icon>
|
|
136
|
+
</sds-icon-button>
|
|
137
|
+
</span>
|
|
138
|
+
</else-if>
|
|
139
|
+
<else-if(iconRight && onClickIconRight)>
|
|
140
|
+
<span class="sds-search-bar__icon sds-search-bar__icon--right">
|
|
141
|
+
<sds-icon-button
|
|
142
|
+
variant="neutral"
|
|
143
|
+
size="sm"
|
|
144
|
+
aria-label=iconRightLabel
|
|
145
|
+
disabled=(disabled || null)
|
|
146
|
+
onClick=onClickIconRight
|
|
147
|
+
>
|
|
148
|
+
<@icon><${renderable(iconRight)}/></@icon>
|
|
149
|
+
</sds-icon-button>
|
|
150
|
+
</span>
|
|
151
|
+
</else-if>
|
|
152
|
+
<else-if(iconRight)>
|
|
153
|
+
<span class="sds-search-bar__icon sds-search-bar__icon--right" aria-hidden="true">
|
|
154
|
+
<sds-icon><${renderable(iconRight)}/></sds-icon>
|
|
155
|
+
</span>
|
|
156
|
+
</else-if>
|
|
157
|
+
</div>
|