@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,429 @@
|
|
|
1
|
+
/* SDS DatePicker.
|
|
2
|
+
Ported from kdls-design-system v2.5.1 (0f3edf8) components/DatePicker/DatePicker.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-datepicker__day--selected
|
|
7
|
+
[data-color-scheme="lya"] .sds-datepicker__year-item--selected
|
|
8
|
+
[data-color-scheme="lya"] .sds-datepicker__day--today
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* The dark theme's range highlight was rgba(41, 142, 230, 0.15) in three places — Kenlo
|
|
12
|
+
blue at 15%, written into a component that carries no brand, and the reason the override
|
|
13
|
+
exists at all is that --color-primary-10 is too pale on a dark background.
|
|
14
|
+
|
|
15
|
+
It is now the scheme's own colour at the same 15%, which is what the literal was for
|
|
16
|
+
whichever scheme is installed. It reads the -solid companion rather than the slot
|
|
17
|
+
itself: the slot can hold a gradient, and color-mix cannot take one. *//* =========================================================
|
|
18
|
+
SDS Datepicker
|
|
19
|
+
Figma: node 2932:8901 / 1945:24854
|
|
20
|
+
========================================================= */
|
|
21
|
+
|
|
22
|
+
/* ── Root wrapper (trigger + floating panel) ── */
|
|
23
|
+
.sds-datepicker-root {
|
|
24
|
+
display: inline-block;
|
|
25
|
+
}
|
|
26
|
+
.sds-datepicker-root .sds-input-phone-wrap--hug {
|
|
27
|
+
min-width: 200px;
|
|
28
|
+
}
|
|
29
|
+
.sds-datepicker-root .sds-input__native {
|
|
30
|
+
field-sizing: content;
|
|
31
|
+
caret-color: transparent;
|
|
32
|
+
}
|
|
33
|
+
/* Pointer cursor on the trigger input (it's not an editable field) */
|
|
34
|
+
.sds-datepicker-root .sds-input,
|
|
35
|
+
.sds-datepicker-root .sds-input__native {
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
/* Wait cursor when isLoading */
|
|
39
|
+
.sds-datepicker-root--loading,
|
|
40
|
+
.sds-datepicker-root--loading .sds-input,
|
|
41
|
+
.sds-datepicker-root--loading .sds-input__native {
|
|
42
|
+
cursor: wait;
|
|
43
|
+
}
|
|
44
|
+
/* disabled overrides the trigger input's cursor:pointer (higher specificity) */
|
|
45
|
+
.sds-datepicker-root .sds-input.sds-input--disabled,
|
|
46
|
+
.sds-datepicker-root .sds-input--disabled .sds-input__native {
|
|
47
|
+
cursor: not-allowed;
|
|
48
|
+
}
|
|
49
|
+
/* ── Chevron rotation when open ── */
|
|
50
|
+
.sds-datepicker-root .sds-input__icon--right:not(.sds-input__icon--right--clickable),
|
|
51
|
+
.sds-datepicker-root .sds-pill__icon-right:not(.sds-pill__icon-right--clickable) {
|
|
52
|
+
transition: transform 200ms ease;
|
|
53
|
+
}
|
|
54
|
+
.sds-datepicker-root--open .sds-input__icon--right:not(.sds-input__icon--right--clickable),
|
|
55
|
+
.sds-datepicker-root--open .sds-pill__icon-right:not(.sds-pill__icon-right--clickable) {
|
|
56
|
+
transform: rotate(180deg);
|
|
57
|
+
}
|
|
58
|
+
.sds-datepicker-root--fill {
|
|
59
|
+
width: 100%;
|
|
60
|
+
}
|
|
61
|
+
.sds-datepicker-root--fill .sds-floating,
|
|
62
|
+
.sds-datepicker-root--fill .sds-input-wrapper {
|
|
63
|
+
width: 100%;
|
|
64
|
+
}
|
|
65
|
+
/* ── Calendar panel ── */
|
|
66
|
+
.sds-datepicker {
|
|
67
|
+
width: 296px;
|
|
68
|
+
background: var(--component-bg-color);
|
|
69
|
+
border: 1px solid var(--border-static-color);
|
|
70
|
+
border-radius: var(--radius-md); /* corner-radius-medium = 12px default */
|
|
71
|
+
box-shadow: var(--shadow-drop-md);
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
font-family: var(--font-family-base);
|
|
74
|
+
user-select: none;
|
|
75
|
+
}
|
|
76
|
+
/* ── Header (nav row) ── */
|
|
77
|
+
.sds-datepicker__header {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
justify-content: space-between;
|
|
81
|
+
padding: var(--spacing-2) var(--spacing-1) var(--spacing-2) var(--spacing-4);
|
|
82
|
+
border-bottom: 1px solid var(--color-neutral-10);
|
|
83
|
+
}
|
|
84
|
+
.sds-datepicker__nav {
|
|
85
|
+
display: flex;
|
|
86
|
+
gap: 0;
|
|
87
|
+
}
|
|
88
|
+
/* ── The calendar is a table, and stays one ──────────────────────────────────
|
|
89
|
+
`display: flex` on the <table>, the <tr>s and the <th>s took the table apart: a flex
|
|
90
|
+
container is not a table box, so the browser drops the row and cell roles with it, and
|
|
91
|
+
a screen reader reads the whole weekday row as one run — "DSTQQSS" followed by every
|
|
92
|
+
long name in sequence — instead of seven column headers. The port exists to give this
|
|
93
|
+
grid real headers; laying it out with flex threw that away again.
|
|
94
|
+
|
|
95
|
+
`table-layout: fixed` is what the flex was for: it gives the seven columns equal width
|
|
96
|
+
without anything having to claim `flex: 1`. */
|
|
97
|
+
.sds-datepicker__grid {
|
|
98
|
+
width: 100%;
|
|
99
|
+
table-layout: fixed;
|
|
100
|
+
border-collapse: collapse;
|
|
101
|
+
padding: var(--spacing-2);
|
|
102
|
+
}
|
|
103
|
+
.sds-datepicker__weekdays {
|
|
104
|
+
background: var(--color-neutral-10);
|
|
105
|
+
}
|
|
106
|
+
/* A <tr>. It needs no layout of its own now that the table lays itself out — the rule is
|
|
107
|
+
here because the class is written, and a class with no rule behind it is a class nobody
|
|
108
|
+
can tell is dead. */
|
|
109
|
+
.sds-datepicker__week-row {
|
|
110
|
+
height: 40px;
|
|
111
|
+
}
|
|
112
|
+
.sds-datepicker__weekdays th {
|
|
113
|
+
height: 40px;
|
|
114
|
+
padding: 0;
|
|
115
|
+
font-size: var(--font-size-body-md);
|
|
116
|
+
font-weight: var(--font-weight-medium);
|
|
117
|
+
color: var(--color-neutral-50);
|
|
118
|
+
text-align: center;
|
|
119
|
+
vertical-align: middle;
|
|
120
|
+
}
|
|
121
|
+
.sds-datepicker__day {
|
|
122
|
+
display: inline-flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
width: 40px;
|
|
126
|
+
height: 40px;
|
|
127
|
+
vertical-align: middle;
|
|
128
|
+
border: none;
|
|
129
|
+
background: transparent;
|
|
130
|
+
/* soft, the install default — the four schemes are set below, and this cell needs its
|
|
131
|
+
own numbers rather than the ladder. See the note there. */
|
|
132
|
+
border-radius: 11px;
|
|
133
|
+
font-family: var(--font-family-base);
|
|
134
|
+
font-size: var(--font-size-body-md);
|
|
135
|
+
font-weight: var(--font-weight-medium);
|
|
136
|
+
letter-spacing: -0.4px;
|
|
137
|
+
color: var(--color-neutral-90);
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
transition: background-color 120ms ease;
|
|
140
|
+
flex-shrink: 0;
|
|
141
|
+
outline: none;
|
|
142
|
+
}
|
|
143
|
+
.sds-datepicker__day:hover:not(.sds-datepicker__day--disabled) {
|
|
144
|
+
background: var(--color-opacity-05);
|
|
145
|
+
}
|
|
146
|
+
.sds-datepicker__day:focus-visible {
|
|
147
|
+
box-shadow: var(--focus-ring);
|
|
148
|
+
}
|
|
149
|
+
.sds-datepicker__day--other {
|
|
150
|
+
color: var(--color-neutral-40);
|
|
151
|
+
}
|
|
152
|
+
.sds-datepicker__day--today {
|
|
153
|
+
border: 1px solid var(--color-primary-50-solid);
|
|
154
|
+
color: var(--color-primary-50-solid);
|
|
155
|
+
font-weight: var(--font-weight-semibold);
|
|
156
|
+
}
|
|
157
|
+
.sds-datepicker__day--selected {
|
|
158
|
+
background: var(--color-primary-50) !important;
|
|
159
|
+
color: var(--color-on-primary) !important;
|
|
160
|
+
font-weight: var(--font-weight-medium);
|
|
161
|
+
border: none;
|
|
162
|
+
}
|
|
163
|
+
/* ── Footer ── */
|
|
164
|
+
.sds-datepicker__footer {
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
justify-content: space-between;
|
|
168
|
+
padding: var(--spacing-4);
|
|
169
|
+
border-top: 1px solid var(--color-neutral-10);
|
|
170
|
+
}
|
|
171
|
+
/* ── Year picker grid ── */
|
|
172
|
+
.sds-datepicker__year-grid {
|
|
173
|
+
display: grid;
|
|
174
|
+
grid-template-columns: repeat(4, 1fr);
|
|
175
|
+
row-gap: 1rem;
|
|
176
|
+
padding: var(--spacing-2);
|
|
177
|
+
}
|
|
178
|
+
.sds-datepicker__year-item {
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: center;
|
|
182
|
+
height: 40px;
|
|
183
|
+
border: none;
|
|
184
|
+
background: transparent;
|
|
185
|
+
border-radius: 11px; /* soft, the install default — schemes at the end of the file */
|
|
186
|
+
font-family: var(--font-family-base);
|
|
187
|
+
font-size: var(--font-size-body-md);
|
|
188
|
+
font-weight: var(--font-weight-medium);
|
|
189
|
+
letter-spacing: -0.4px;
|
|
190
|
+
color: var(--color-neutral-90);
|
|
191
|
+
cursor: pointer;
|
|
192
|
+
transition: background-color 120ms ease;
|
|
193
|
+
outline: none;
|
|
194
|
+
}
|
|
195
|
+
.sds-datepicker__year-item:hover {
|
|
196
|
+
background: var(--color-opacity-05);
|
|
197
|
+
}
|
|
198
|
+
.sds-datepicker__year-item:focus-visible {
|
|
199
|
+
box-shadow: var(--focus-ring);
|
|
200
|
+
}
|
|
201
|
+
.sds-datepicker__year-item--today {
|
|
202
|
+
border: 1px solid var(--color-primary-50-solid);
|
|
203
|
+
color: var(--color-primary-50-solid);
|
|
204
|
+
font-weight: var(--font-weight-semibold);
|
|
205
|
+
}
|
|
206
|
+
.sds-datepicker__year-item--selected {
|
|
207
|
+
background: var(--color-primary-50) !important;
|
|
208
|
+
color: var(--color-on-primary) !important;
|
|
209
|
+
font-weight: var(--font-weight-bold);
|
|
210
|
+
}
|
|
211
|
+
/* ── Range selection ── */
|
|
212
|
+
/* A <td>, sized by the fixed table layout rather than by a flex basis. */
|
|
213
|
+
.sds-datepicker__day-wrap {
|
|
214
|
+
width: 40px;
|
|
215
|
+
height: 40px;
|
|
216
|
+
padding: 0;
|
|
217
|
+
text-align: center;
|
|
218
|
+
}
|
|
219
|
+
.sds-datepicker__day-wrap--in-range {
|
|
220
|
+
background: var(--color-primary-10);
|
|
221
|
+
}
|
|
222
|
+
.sds-datepicker__day-wrap--range-start {
|
|
223
|
+
background: linear-gradient(to right, transparent 50%, var(--color-primary-10) 50%);
|
|
224
|
+
}
|
|
225
|
+
.sds-datepicker__day-wrap--range-end {
|
|
226
|
+
background: linear-gradient(to left, transparent 50%, var(--color-primary-10) 50%);
|
|
227
|
+
}
|
|
228
|
+
/* ── Month picker grid (navigation) ── */
|
|
229
|
+
.sds-datepicker__month-grid {
|
|
230
|
+
display: grid;
|
|
231
|
+
grid-template-columns: repeat(4, 1fr);
|
|
232
|
+
row-gap: 1rem;
|
|
233
|
+
padding: var(--spacing-2);
|
|
234
|
+
}
|
|
235
|
+
.sds-datepicker__month-item {
|
|
236
|
+
display: flex;
|
|
237
|
+
align-items: center;
|
|
238
|
+
justify-content: center;
|
|
239
|
+
width: 100%;
|
|
240
|
+
height: 40px;
|
|
241
|
+
border: none;
|
|
242
|
+
background: transparent;
|
|
243
|
+
border-radius: 11px; /* soft, the install default — schemes at the end of the file */
|
|
244
|
+
font-family: var(--font-family-base);
|
|
245
|
+
font-size: var(--font-size-body-md);
|
|
246
|
+
font-weight: var(--font-weight-medium);
|
|
247
|
+
letter-spacing: -0.4px;
|
|
248
|
+
color: var(--color-neutral-90);
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
transition: background-color 120ms ease;
|
|
251
|
+
outline: none;
|
|
252
|
+
}
|
|
253
|
+
.sds-datepicker__month-item:hover {
|
|
254
|
+
background: var(--color-opacity-05);
|
|
255
|
+
}
|
|
256
|
+
.sds-datepicker__month-item:focus-visible {
|
|
257
|
+
box-shadow: var(--focus-ring);
|
|
258
|
+
}
|
|
259
|
+
.sds-datepicker__month-item--today {
|
|
260
|
+
border: 1px solid var(--color-primary-50-solid);
|
|
261
|
+
color: var(--color-primary-50-solid);
|
|
262
|
+
font-weight: var(--font-weight-semibold);
|
|
263
|
+
}
|
|
264
|
+
.sds-datepicker__month-item--selected {
|
|
265
|
+
background: var(--color-primary-50) !important;
|
|
266
|
+
color: var(--color-on-primary) !important;
|
|
267
|
+
font-weight: var(--font-weight-medium);
|
|
268
|
+
}
|
|
269
|
+
/* ── Disabled (whole calendar) — cursor on the wrapper; the trigger (Input/Pill) already blocks on its own ── */
|
|
270
|
+
.sds-datepicker--disabled {
|
|
271
|
+
cursor: not-allowed;
|
|
272
|
+
opacity: 0.5;
|
|
273
|
+
}
|
|
274
|
+
/* ── Disabled day cells ── */
|
|
275
|
+
.sds-datepicker__day--disabled {
|
|
276
|
+
color: var(--color-neutral-40);
|
|
277
|
+
cursor: not-allowed;
|
|
278
|
+
}
|
|
279
|
+
/* ── Dark mode ── */
|
|
280
|
+
[data-theme="dark"] .sds-datepicker {
|
|
281
|
+
border-color: var(--border-interactive-color);
|
|
282
|
+
box-shadow: var(--shadow-drop-lg);
|
|
283
|
+
}
|
|
284
|
+
[data-theme="dark"] .sds-datepicker__header {
|
|
285
|
+
border-bottom-color: var(--border-static-color);
|
|
286
|
+
}
|
|
287
|
+
[data-theme="dark"] .sds-datepicker__day--other {
|
|
288
|
+
color: var(--color-neutral-50);
|
|
289
|
+
}
|
|
290
|
+
[data-theme="dark"] .sds-datepicker__footer {
|
|
291
|
+
border-top-color: var(--border-static-color);
|
|
292
|
+
}
|
|
293
|
+
[data-theme="dark"] .sds-datepicker__day-wrap--in-range {
|
|
294
|
+
background: color-mix(in srgb, var(--color-primary-50-solid) 15%, transparent);
|
|
295
|
+
}
|
|
296
|
+
[data-theme="dark"] .sds-datepicker__day-wrap--range-start {
|
|
297
|
+
background: linear-gradient(to right, transparent 50%, color-mix(in srgb, var(--color-primary-50-solid) 15%, transparent) 50%);
|
|
298
|
+
}
|
|
299
|
+
[data-theme="dark"] .sds-datepicker__day-wrap--range-end {
|
|
300
|
+
background: linear-gradient(to left, transparent 50%, color-mix(in srgb, var(--color-primary-50-solid) 15%, transparent) 50%);
|
|
301
|
+
}
|
|
302
|
+
/* ── Only-time: same width and height as the time panel in hasTime ── */
|
|
303
|
+
.sds-datepicker--only-time {
|
|
304
|
+
width: 90px;
|
|
305
|
+
height: 370px; /* header 56 + border 1 + weekdays 40 + grid 5sem 216 + border 1 + footer 56 */
|
|
306
|
+
display: flex;
|
|
307
|
+
flex-direction: column;
|
|
308
|
+
}
|
|
309
|
+
.sds-datepicker--only-time .sds-datepicker__time-panel {
|
|
310
|
+
position: static;
|
|
311
|
+
width: 100%;
|
|
312
|
+
border-left: none;
|
|
313
|
+
flex: 1;
|
|
314
|
+
min-height: 0;
|
|
315
|
+
}
|
|
316
|
+
.sds-datepicker--only-time .sds-datepicker__footer {
|
|
317
|
+
justify-content: center;
|
|
318
|
+
}
|
|
319
|
+
/* ── Has-time: extra width on the right via absolute positioning ── */
|
|
320
|
+
.sds-datepicker--has-time {
|
|
321
|
+
position: relative;
|
|
322
|
+
width: 386px;
|
|
323
|
+
}
|
|
324
|
+
.sds-datepicker__calendar-col {
|
|
325
|
+
width: 296px;
|
|
326
|
+
}
|
|
327
|
+
.sds-datepicker__time-panel {
|
|
328
|
+
position: absolute;
|
|
329
|
+
right: 0;
|
|
330
|
+
top: 0;
|
|
331
|
+
bottom: 0;
|
|
332
|
+
width: 90px;
|
|
333
|
+
border-left: 1px solid var(--border-static-color);
|
|
334
|
+
background: var(--component-bg-color);
|
|
335
|
+
display: flex;
|
|
336
|
+
flex-direction: column;
|
|
337
|
+
align-items: center;
|
|
338
|
+
padding: var(--spacing-0-5) 0;
|
|
339
|
+
box-sizing: border-box;
|
|
340
|
+
overflow: hidden;
|
|
341
|
+
}
|
|
342
|
+
/* ── Time list ── */
|
|
343
|
+
.sds-datepicker__time-list {
|
|
344
|
+
display: flex;
|
|
345
|
+
flex-direction: column;
|
|
346
|
+
gap: var(--spacing-1);
|
|
347
|
+
flex: 1;
|
|
348
|
+
overflow-y: auto;
|
|
349
|
+
}
|
|
350
|
+
/* ── Time slot button ── */
|
|
351
|
+
.sds-datepicker__time-slot {
|
|
352
|
+
text-align: left;
|
|
353
|
+
padding: var(--spacing-1) var(--spacing-2);
|
|
354
|
+
margin: 0 var(--spacing-2);
|
|
355
|
+
border-radius: var(--radius-sm);
|
|
356
|
+
border: none;
|
|
357
|
+
background: transparent;
|
|
358
|
+
font-family: var(--font-family-base);
|
|
359
|
+
font-size: var(--font-size-body-md);
|
|
360
|
+
color: var(--body-color);
|
|
361
|
+
cursor: pointer;
|
|
362
|
+
white-space: nowrap;
|
|
363
|
+
transition: background-color 120ms ease;
|
|
364
|
+
}
|
|
365
|
+
.sds-datepicker__time-slot:hover:not(.sds-datepicker__time-slot--disabled) {
|
|
366
|
+
background: var(--color-opacity-05);
|
|
367
|
+
}
|
|
368
|
+
.sds-datepicker__time-slot--selected {
|
|
369
|
+
background: var(--color-opacity-05);
|
|
370
|
+
color: var(--color-neutral-90);
|
|
371
|
+
font-weight: var(--font-weight-bold);
|
|
372
|
+
}
|
|
373
|
+
.sds-datepicker__time-slot--disabled {
|
|
374
|
+
color: var(--color-neutral-40);
|
|
375
|
+
cursor: not-allowed;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* The grid is a <table> rather than nested divs — see the component header. These take the
|
|
379
|
+
table's own spacing off so the cells sit exactly where the divs did. */
|
|
380
|
+
.sds-datepicker__grid {
|
|
381
|
+
border-collapse: collapse;
|
|
382
|
+
width: 100%;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.sds-datepicker__grid th {
|
|
386
|
+
font-weight: inherit;
|
|
387
|
+
padding: 0;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.sds-datepicker__grid td {
|
|
391
|
+
padding: 0;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/* A wrapper for the invisible weekday name, which must not take part in the layout. */
|
|
395
|
+
.sds-datepicker__weekdays th > span[aria-hidden] {
|
|
396
|
+
display: block;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/* ── Corner radius schemes ────────────────────────────────────────────────────
|
|
400
|
+
The same numbers as the Pill, because it is the same control: 40px tall. Rafael, after
|
|
401
|
+
watching me invent a third set: the dropdown's items are 40px like a pill, so the radius
|
|
402
|
+
can be the pill's for each scheme.
|
|
403
|
+
|
|
404
|
+
height 40px flat 0 soft 11px medium 15px rounded 20px (a circle)
|
|
405
|
+
as a fraction 0 0.275 0.375 0.5
|
|
406
|
+
|
|
407
|
+
Two earlier tries are worth naming, because each was right about one half. `--radius-lg`
|
|
408
|
+
fixed `flat` and left `soft`, `medium` and `rounded` as three identical circles — every
|
|
409
|
+
value past half of 40px is clamped to 20. `--radius-sm` gave four distinct values and
|
|
410
|
+
stopped at 16px, so `rounded` was a rounded square; Rafael: no `rounded` the day has to
|
|
411
|
+
be really round.
|
|
412
|
+
|
|
413
|
+
The bare values above are `soft`'s, because an install that never picks a scheme has no
|
|
414
|
+
attribute at all and falls through to them. See Pill.css for the long version. */
|
|
415
|
+
[data-radius="flat"] .sds-datepicker__day { border-radius: 0; }
|
|
416
|
+
[data-radius="flat"] .sds-datepicker__month-item { border-radius: 0; }
|
|
417
|
+
[data-radius="flat"] .sds-datepicker__year-item { border-radius: 0; }
|
|
418
|
+
|
|
419
|
+
[data-radius="soft"] .sds-datepicker__day { border-radius: 11px; }
|
|
420
|
+
[data-radius="soft"] .sds-datepicker__month-item { border-radius: 11px; }
|
|
421
|
+
[data-radius="soft"] .sds-datepicker__year-item { border-radius: 11px; }
|
|
422
|
+
|
|
423
|
+
[data-radius="medium"] .sds-datepicker__day { border-radius: 15px; }
|
|
424
|
+
[data-radius="medium"] .sds-datepicker__month-item { border-radius: 15px; }
|
|
425
|
+
[data-radius="medium"] .sds-datepicker__year-item { border-radius: 15px; }
|
|
426
|
+
|
|
427
|
+
[data-radius="rounded"] .sds-datepicker__day { border-radius: var(--radius-full); }
|
|
428
|
+
[data-radius="rounded"] .sds-datepicker__month-item { border-radius: var(--radius-full); }
|
|
429
|
+
[data-radius="rounded"] .sds-datepicker__year-item { border-radius: var(--radius-full); }
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything the DatePicker knows about dates, with no DOM in sight.
|
|
3
|
+
*
|
|
4
|
+
* Ported from kdls-design-system v2.5.1 (0f3edf8) components/DatePicker/DatePicker.tsx and
|
|
5
|
+
* dateUtils.ts, where it is spread across the render body of a 575-line component. Dates
|
|
6
|
+
* are where off-by-ones live — a month grid that starts on the wrong weekday, a range whose
|
|
7
|
+
* ends are the wrong way round, a "last 30 days" that is 29 or 31 — and none of it needs a
|
|
8
|
+
* browser to test.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const MONTHS = [
|
|
12
|
+
'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho',
|
|
13
|
+
'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
export const MONTHS_SHORT = [
|
|
17
|
+
'Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
/** Sunday first, as the grid is laid out. Two S's and two Q's is Portuguese, not a typo. */
|
|
21
|
+
export const WEEKDAYS = ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'];
|
|
22
|
+
|
|
23
|
+
/** The full names, for the header a screen reader reads. KDLS has only the initials. */
|
|
24
|
+
export const WEEKDAY_NAMES = [
|
|
25
|
+
'domingo', 'segunda-feira', 'terça-feira', 'quarta-feira',
|
|
26
|
+
'quinta-feira', 'sexta-feira', 'sábado',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export const pad2 = (n) => String(n).padStart(2, '0');
|
|
30
|
+
|
|
31
|
+
export const formatDate = (d) => `${pad2(d.getDate())} ${MONTHS_SHORT[d.getMonth()]} ${d.getFullYear()}`;
|
|
32
|
+
export const formatTime = (d) => `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
33
|
+
|
|
34
|
+
/** The same day, whatever the time on it. */
|
|
35
|
+
export const isSameDay = (a, b) => Boolean(a) && Boolean(b)
|
|
36
|
+
&& a.getFullYear() === b.getFullYear()
|
|
37
|
+
&& a.getMonth() === b.getMonth()
|
|
38
|
+
&& a.getDate() === b.getDate();
|
|
39
|
+
|
|
40
|
+
/** Midnight on the day of `date`, which is what comparing days means. */
|
|
41
|
+
export const startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* What the trigger says.
|
|
45
|
+
*
|
|
46
|
+
* The range cases are KDLS's and they are the reason this is worth testing: a whole month
|
|
47
|
+
* reads as "Março 2026", two days in one month as "01 — 15 Mar 2026", and only a range that
|
|
48
|
+
* crosses a year spells both sides out.
|
|
49
|
+
*/
|
|
50
|
+
export function triggerLabel({ isRange, value, hasTime, onlyTime }) {
|
|
51
|
+
if (isRange) {
|
|
52
|
+
const start = value?.start ?? null;
|
|
53
|
+
const end = value?.end ?? null;
|
|
54
|
+
if (!start) return '';
|
|
55
|
+
if (!end) return `${formatDate(start)} — ...`;
|
|
56
|
+
|
|
57
|
+
const sameYear = start.getFullYear() === end.getFullYear();
|
|
58
|
+
const sameMonth = sameYear && start.getMonth() === end.getMonth();
|
|
59
|
+
|
|
60
|
+
if (sameMonth) {
|
|
61
|
+
const lastDay = new Date(start.getFullYear(), start.getMonth() + 1, 0).getDate();
|
|
62
|
+
if (start.getDate() === 1 && end.getDate() === lastDay) {
|
|
63
|
+
return `${MONTHS[start.getMonth()]} ${start.getFullYear()}`;
|
|
64
|
+
}
|
|
65
|
+
return `${pad2(start.getDate())} — ${pad2(end.getDate())} ${MONTHS_SHORT[start.getMonth()]} ${start.getFullYear()}`;
|
|
66
|
+
}
|
|
67
|
+
if (sameYear) {
|
|
68
|
+
return `${pad2(start.getDate())} ${MONTHS_SHORT[start.getMonth()]} — ${pad2(end.getDate())} ${MONTHS_SHORT[end.getMonth()]} ${end.getFullYear()}`;
|
|
69
|
+
}
|
|
70
|
+
return `${formatDate(start)} — ${formatDate(end)}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!value) return '';
|
|
74
|
+
if (onlyTime) return formatTime(value);
|
|
75
|
+
if (hasTime) return `${formatDate(value)} — ${formatTime(value)}`;
|
|
76
|
+
return formatDate(value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The bounds once disablePast and disableFuture have had their say. */
|
|
80
|
+
export function effectiveBounds({ minDate, maxDate, disablePast, disableFuture, today = new Date() }) {
|
|
81
|
+
const midnight = startOfDay(today);
|
|
82
|
+
const min = minDate && disablePast
|
|
83
|
+
? (minDate.getTime() > midnight.getTime() ? minDate : midnight)
|
|
84
|
+
: minDate ?? (disablePast ? midnight : undefined);
|
|
85
|
+
const max = maxDate && disableFuture
|
|
86
|
+
? (maxDate.getTime() < midnight.getTime() ? maxDate : midnight)
|
|
87
|
+
: maxDate ?? (disableFuture ? midnight : undefined);
|
|
88
|
+
return { min, max };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function isDisabledDate(date, options = {}) {
|
|
92
|
+
const {
|
|
93
|
+
min, max, filterDate, disableToday, excludeDates, includeDates, today = new Date(),
|
|
94
|
+
} = options;
|
|
95
|
+
|
|
96
|
+
const day = startOfDay(date).getTime();
|
|
97
|
+
if (min && day < startOfDay(min).getTime()) return true;
|
|
98
|
+
if (max && day > startOfDay(max).getTime()) return true;
|
|
99
|
+
if (filterDate && !filterDate(date)) return true;
|
|
100
|
+
if (disableToday && isSameDay(date, today)) return true;
|
|
101
|
+
if (excludeDates?.some((d) => isSameDay(d, date))) return true;
|
|
102
|
+
if (includeDates?.length && !includeDates.some((d) => isSameDay(d, date))) return true;
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The six-or-so weeks a month is drawn in, with the days either side that fill the corners.
|
|
108
|
+
*
|
|
109
|
+
* `current` says whether a cell belongs to the month being shown — the greyed-out ones at
|
|
110
|
+
* each end are still real dates and still selectable, which is KDLS's behaviour.
|
|
111
|
+
*/
|
|
112
|
+
export function monthGrid(year, month) {
|
|
113
|
+
const firstWeekday = new Date(year, month, 1).getDay();
|
|
114
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
115
|
+
const daysInPrevious = new Date(year, month, 0).getDate();
|
|
116
|
+
|
|
117
|
+
const cells = [];
|
|
118
|
+
for (let i = firstWeekday - 1; i >= 0; i--) {
|
|
119
|
+
cells.push({ date: new Date(year, month - 1, daysInPrevious - i), current: false });
|
|
120
|
+
}
|
|
121
|
+
for (let day = 1; day <= daysInMonth; day++) {
|
|
122
|
+
cells.push({ date: new Date(year, month, day), current: true });
|
|
123
|
+
}
|
|
124
|
+
while (cells.length % 7 !== 0) {
|
|
125
|
+
cells.push({
|
|
126
|
+
date: new Date(year, month + 1, cells.length - daysInMonth - firstWeekday + 1),
|
|
127
|
+
current: false,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const weeks = [];
|
|
132
|
+
for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7));
|
|
133
|
+
return weeks;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The sixteen years the year picker shows, aligned so the pages never shift. */
|
|
137
|
+
export function yearGrid(year) {
|
|
138
|
+
const base = Math.floor(year / 16) * 16;
|
|
139
|
+
return Array.from({ length: 16 }, (_, i) => base + i);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const DEFAULT_TIME_INTERVAL = 60;
|
|
143
|
+
|
|
144
|
+
/** Every time slot in a day, at the given spacing. */
|
|
145
|
+
export function timeSlots(step = DEFAULT_TIME_INTERVAL, today = new Date()) {
|
|
146
|
+
const slots = [];
|
|
147
|
+
const y = today.getFullYear();
|
|
148
|
+
const m = today.getMonth();
|
|
149
|
+
const d = today.getDate();
|
|
150
|
+
for (let hour = 0; hour < 24; hour++) {
|
|
151
|
+
for (let minute = 0; minute < 60; minute += step) {
|
|
152
|
+
slots.push(new Date(y, m, d, hour, minute));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return slots;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function isDisabledTime(slot, options = {}) {
|
|
159
|
+
const {
|
|
160
|
+
min, max, onlyTime, hasTime, reference, filterTime, includeTimes, excludeTimes,
|
|
161
|
+
} = options;
|
|
162
|
+
|
|
163
|
+
const slotMinutes = slot.getHours() * 60 + slot.getMinutes();
|
|
164
|
+
|
|
165
|
+
if (min) {
|
|
166
|
+
const minMinutes = min.getHours() * 60 + min.getMinutes();
|
|
167
|
+
const minCarriesTime = min.getHours() !== 0 || min.getMinutes() !== 0;
|
|
168
|
+
if (onlyTime) {
|
|
169
|
+
if (slotMinutes < minMinutes) return true;
|
|
170
|
+
} else if (hasTime && minCarriesTime && reference && isSameDay(reference, min)) {
|
|
171
|
+
if (slotMinutes < minMinutes) return true;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (max) {
|
|
176
|
+
const maxMinutes = max.getHours() * 60 + max.getMinutes();
|
|
177
|
+
const maxCarriesTime = max.getHours() !== 23 || max.getMinutes() !== 59;
|
|
178
|
+
if (onlyTime) {
|
|
179
|
+
if (slotMinutes > maxMinutes) return true;
|
|
180
|
+
} else if (hasTime && maxCarriesTime && reference && isSameDay(reference, max)) {
|
|
181
|
+
if (slotMinutes > maxMinutes) return true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const sameClock = (t) => t.getHours() === slot.getHours() && t.getMinutes() === slot.getMinutes();
|
|
186
|
+
if (filterTime && !filterTime(slot)) return true;
|
|
187
|
+
if (includeTimes?.length && !includeTimes.some(sameClock)) return true;
|
|
188
|
+
if (excludeTimes?.some(sameClock)) return true;
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Strictly between the two ends, whichever way round they were given. */
|
|
193
|
+
export function isBetween(date, start, end) {
|
|
194
|
+
if (!start || !end) return false;
|
|
195
|
+
const t = date.getTime();
|
|
196
|
+
const lo = Math.min(start.getTime(), end.getTime());
|
|
197
|
+
const hi = Math.max(start.getTime(), end.getTime());
|
|
198
|
+
return t > lo && t < hi;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** The two ends of a range, in order. */
|
|
202
|
+
export function orderRange(a, b) {
|
|
203
|
+
return a.getTime() < b.getTime() ? { start: a, end: b } : { start: b, end: a };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* A minDate for "the last n days".
|
|
208
|
+
*
|
|
209
|
+
* includeToday counts today as one of the n. Carried from KDLS's dateUtils, where the
|
|
210
|
+
* doc comment is the only thing that makes the off-by-one legible.
|
|
211
|
+
*/
|
|
212
|
+
export function lastDays(n, includeToday = true, today = new Date()) {
|
|
213
|
+
const d = new Date(today);
|
|
214
|
+
d.setHours(0, 0, 0, 0);
|
|
215
|
+
d.setDate(d.getDate() - (includeToday ? n - 1 : n));
|
|
216
|
+
return d;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** A maxDate for "the next n days". */
|
|
220
|
+
export function nextDays(n, includeToday = true, today = new Date()) {
|
|
221
|
+
const d = new Date(today);
|
|
222
|
+
d.setHours(0, 0, 0, 0);
|
|
223
|
+
d.setDate(d.getDate() + (includeToday ? n - 1 : n));
|
|
224
|
+
return d;
|
|
225
|
+
}
|