@reliability-design/web 1.3.0 → 1.4.0
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/dist/components/rel-accordion/README.md +13 -13
- package/dist/components/rel-accordion/rel-accordion.ts +80 -45
- package/dist/components/rel-alert/README.md +15 -15
- package/dist/components/rel-alert/rel-alert.ts +161 -159
- package/dist/components/rel-avatar/README.md +15 -15
- package/dist/components/rel-avatar/rel-avatar.ts +42 -38
- package/dist/components/rel-badge/README.md +5 -5
- package/dist/components/rel-badge/rel-badge.ts +69 -17
- package/dist/components/rel-breadcrumb/README.md +7 -7
- package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +16 -13
- package/dist/components/rel-button/README.md +20 -20
- package/dist/components/rel-button/rel-button.ts +327 -105
- package/dist/components/rel-calendar/README.md +5 -5
- package/dist/components/rel-calendar/rel-calendar.ts +61 -45
- package/dist/components/rel-card/README.md +6 -6
- package/dist/components/rel-card/rel-card.ts +88 -35
- package/dist/components/rel-cardmedia/README.md +9 -9
- package/dist/components/rel-cardmedia/rel-cardmedia.ts +27 -20
- package/dist/components/rel-carousel/README.md +3 -3
- package/dist/components/rel-carousel/rel-carousel.ts +174 -90
- package/dist/components/rel-chart/README.md +8 -8
- package/dist/components/rel-chart/rel-chart.ts +59 -41
- package/dist/components/rel-checkbox/README.md +7 -7
- package/dist/components/rel-checkbox/rel-checkbox.ts +61 -61
- package/dist/components/rel-chip/README.md +16 -16
- package/dist/components/rel-chip/rel-chip.ts +143 -111
- package/dist/components/rel-container/README.md +11 -11
- package/dist/components/rel-container/rel-container.ts +35 -9
- package/dist/components/rel-date-picker/README.md +43 -7
- package/dist/components/rel-date-picker/date-format.test.ts +43 -0
- package/dist/components/rel-date-picker/date-format.ts +47 -0
- package/dist/components/rel-date-picker/rel-date-picker.ts +257 -83
- package/dist/components/rel-divider/README.md +9 -9
- package/dist/components/rel-divider/rel-divider.ts +10 -9
- package/dist/components/rel-drawer/README.md +1 -1
- package/dist/components/rel-drawer/rel-drawer-footer.ts +1 -1
- package/dist/components/rel-drawer/rel-drawer.ts +56 -28
- package/dist/components/rel-kbd/README.md +20 -20
- package/dist/components/rel-kbd/rel-kbd.ts +119 -25
- package/dist/components/rel-layout/README.md +1 -1
- package/dist/components/rel-layout/rel-layout.ts +2 -2
- package/dist/components/rel-menu/README.md +15 -15
- package/dist/components/rel-menu/rel-menu.ts +155 -88
- package/dist/components/rel-menubar/README.md +20 -20
- package/dist/components/rel-menubar/rel-menubar.ts +47 -31
- package/dist/components/rel-nav-menu/README.md +21 -21
- package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +17 -14
- package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +33 -14
- package/dist/components/rel-nav-menu/rel-nav-menu.ts +14 -7
- package/dist/components/rel-navbar/README.md +7 -7
- package/dist/components/rel-navbar/rel-navbar.ts +12 -11
- package/dist/components/rel-otp/README.md +3 -3
- package/dist/components/rel-otp/rel-otp.ts +46 -30
- package/dist/components/rel-pagination/README.md +18 -18
- package/dist/components/rel-pagination/rel-pagination.ts +141 -90
- package/dist/components/rel-popover/README.md +13 -13
- package/dist/components/rel-popover/rel-popover-content.ts +39 -14
- package/dist/components/rel-popover/rel-popover.ts +18 -7
- package/dist/components/rel-progress/README.md +5 -5
- package/dist/components/rel-progress/rel-progress.ts +16 -12
- package/dist/components/rel-radio/README.md +9 -9
- package/dist/components/rel-radio/rel-radio.ts +64 -50
- package/dist/components/rel-range-picker/rel-range-picker.ts +120 -117
- package/dist/components/rel-resizable/README.md +4 -4
- package/dist/components/rel-resizable/rel-resizable-group.ts +15 -4
- package/dist/components/rel-resizable/rel-resizable-handle.ts +13 -9
- package/dist/components/rel-resizable/rel-resizable-panel.ts +11 -0
- package/dist/components/rel-segmented-button/README.md +10 -10
- package/dist/components/rel-segmented-button/rel-segmented-button.ts +39 -40
- package/dist/components/rel-select/README.md +14 -14
- package/dist/components/rel-select/rel-select.ts +120 -188
- package/dist/components/rel-sheet/README.md +10 -10
- package/dist/components/rel-sheet/rel-sheet.ts +82 -23
- package/dist/components/rel-sidebar/README.md +5 -5
- package/dist/components/rel-sidebar/rel-sidebar.ts +75 -60
- package/dist/components/rel-skeleton/rel-skeleton.ts +8 -13
- package/dist/components/rel-slider/README.md +10 -10
- package/dist/components/rel-slider/rel-slider.ts +230 -57
- package/dist/components/rel-snackbar/README.md +9 -9
- package/dist/components/rel-snackbar/rel-snackbar.ts +44 -32
- package/dist/components/rel-stepper/README.md +10 -10
- package/dist/components/rel-stepper/rel-stepper.ts +110 -46
- package/dist/components/rel-switch/README.md +5 -5
- package/dist/components/rel-switch/rel-switch.ts +23 -12
- package/dist/components/rel-tab/README.md +13 -13
- package/dist/components/rel-tab/rel-tab.ts +73 -23
- package/dist/components/rel-table/README.md +7 -7
- package/dist/components/rel-table/rel-table-body.ts +2 -1
- package/dist/components/rel-table/rel-table-caption.ts +10 -7
- package/dist/components/rel-table/rel-table-cell.ts +7 -6
- package/dist/components/rel-table/rel-table-footer.ts +4 -3
- package/dist/components/rel-table/rel-table-head.ts +11 -9
- package/dist/components/rel-table/rel-table-header.ts +2 -1
- package/dist/components/rel-table/rel-table-row.ts +5 -4
- package/dist/components/rel-table/rel-table.ts +16 -7
- package/dist/components/rel-textfield/README.md +11 -11
- package/dist/components/rel-textfield/rel-textfield.ts +718 -397
- package/dist/components/rel-toast/README.md +11 -11
- package/dist/components/rel-toast/rel-toast.ts +33 -30
- package/dist/components/rel-tooltip/README.md +7 -7
- package/dist/components/rel-tooltip/rel-tooltip.ts +160 -123
- package/dist/components/rel-topbar/rel-topbar-actions.ts +5 -2
- package/dist/components/rel-topbar/rel-topbar-brand.ts +12 -5
- package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +14 -8
- package/dist/components/rel-topbar/rel-topbar-dropdown.ts +8 -5
- package/dist/components/rel-topbar/rel-topbar-item.ts +27 -22
- package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +4 -1
- package/dist/components/rel-topbar/rel-topbar-profile.ts +71 -50
- package/dist/components/rel-topbar/rel-topbar-utilities.ts +5 -2
- package/dist/components/rel-topbar/rel-topbar.ts +37 -29
- package/dist/index.d.mts +227 -40
- package/dist/index.d.ts +227 -40
- package/dist/index.js +3930 -2247
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4311 -2629
- package/dist/index.mjs.map +1 -1
- package/dist/styles/vars.css +653 -346
- package/dist/vars-WY2XCF5G.css +653 -0
- package/package.json +3 -2
- package/dist/components/rel-range-picker/rel-range-picker.css +0 -349
- package/dist/styles/vars-v2.css +0 -525
- package/dist/vars-I2PC74XD.css +0 -346
- package/dist/vars-v2-VMGWTFJZ.css +0 -525
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-based date formatting for rel-date-picker's selected-value display.
|
|
3
|
+
*
|
|
4
|
+
* Pure (Date + Intl only, no DOM) so it is unit-testable in Node. Tokens are
|
|
5
|
+
* matched longest-first; anything else (separators like `-` `/` `.` and spaces)
|
|
6
|
+
* passes through literally. Wrap literal text that contains token letters in
|
|
7
|
+
* square brackets, e.g. `[Week of] YYYY-MM-DD`.
|
|
8
|
+
*
|
|
9
|
+
* | Token | Meaning | Example (2026-07-21) |
|
|
10
|
+
* |-------|------------------------|----------------------|
|
|
11
|
+
* | YYYY | 4-digit year | 2026 |
|
|
12
|
+
* | YY | 2-digit year | 26 |
|
|
13
|
+
* | MMMM | full month (locale) | July |
|
|
14
|
+
* | MMM | short month (locale) | Jul |
|
|
15
|
+
* | MM | 2-digit month | 07 |
|
|
16
|
+
* | M | month number | 7 |
|
|
17
|
+
* | DD | 2-digit day | 21 |
|
|
18
|
+
* | D | day number | 21 |
|
|
19
|
+
*/
|
|
20
|
+
export function formatDatePattern(
|
|
21
|
+
date: Date,
|
|
22
|
+
pattern: string,
|
|
23
|
+
locale = "en-US"
|
|
24
|
+
): string {
|
|
25
|
+
const pad = (n: number) => String(n).padStart(2, "0");
|
|
26
|
+
const year = date.getFullYear();
|
|
27
|
+
const month = date.getMonth() + 1;
|
|
28
|
+
const day = date.getDate();
|
|
29
|
+
|
|
30
|
+
const tokens: Record<string, string> = {
|
|
31
|
+
YYYY: String(year),
|
|
32
|
+
YY: String(year).slice(-2),
|
|
33
|
+
MMMM: new Intl.DateTimeFormat(locale, { month: "long" }).format(date),
|
|
34
|
+
MMM: new Intl.DateTimeFormat(locale, { month: "short" }).format(date),
|
|
35
|
+
MM: pad(month),
|
|
36
|
+
M: String(month),
|
|
37
|
+
DD: pad(day),
|
|
38
|
+
D: String(day),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// `\[([^\]]*)\]` captures a bracketed literal (emitted without the brackets);
|
|
42
|
+
// otherwise the matched token is substituted from the map.
|
|
43
|
+
return pattern.replace(
|
|
44
|
+
/\[([^\]]*)\]|YYYY|YY|MMMM|MMM|MM|M|DD|D/g,
|
|
45
|
+
(match, literal) => (literal !== undefined ? literal : tokens[match])
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LitElement, html, css, nothing } from "lit";
|
|
2
2
|
import { customElement, property, state, query } from "lit/decorators.js";
|
|
3
|
+
import { formatDatePattern } from "./date-format";
|
|
3
4
|
|
|
4
5
|
interface CalendarDay {
|
|
5
6
|
date: Date;
|
|
@@ -17,17 +18,57 @@ export class RelDatePicker extends LitElement {
|
|
|
17
18
|
@property({ type: String }) label: string | null = null;
|
|
18
19
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
19
20
|
@property({ type: Boolean }) required = false;
|
|
21
|
+
@property({ type: Boolean, reflect: true }) readonly = false;
|
|
22
|
+
|
|
23
|
+
// Date bounds. minDate/maxDate are the standard names; min/max are kept as
|
|
24
|
+
// deprecated aliases (minDate/maxDate win when both are set).
|
|
25
|
+
@property({ type: String, attribute: "min-date" }) minDate: string | null = null;
|
|
26
|
+
@property({ type: String, attribute: "max-date" }) maxDate: string | null = null;
|
|
27
|
+
/** @deprecated use minDate */
|
|
20
28
|
@property({ type: String }) min: string | null = null;
|
|
29
|
+
/** @deprecated use maxDate */
|
|
21
30
|
@property({ type: String }) max: string | null = null;
|
|
31
|
+
|
|
22
32
|
@property({ type: String, attribute: "week-start" }) weekStart: "sun" | "mon" = "sun";
|
|
23
33
|
@property({ type: String }) locale = "en-US";
|
|
34
|
+
|
|
35
|
+
// ── Display formatting of the SELECTED value ──
|
|
36
|
+
// `displayFormat` is a token pattern (YYYY-MM-DD, MM/DD/YYYY, DD/MM/YYYY, …);
|
|
37
|
+
// see date-format.ts for the token table. `formatDate` is a full callback and
|
|
38
|
+
// takes precedence. When neither is set the locale long date is used, so
|
|
39
|
+
// existing consumers are unaffected. Neither affects parsing, the popup
|
|
40
|
+
// calendar, or accessibility — only the visible trigger text.
|
|
41
|
+
@property({ type: String, attribute: "display-format" }) displayFormat: string | null = null;
|
|
42
|
+
/**
|
|
43
|
+
* Full control over the selected-value display; wins over `displayFormat`.
|
|
44
|
+
* Reactive (attribute:false) so assigning it after render re-renders the
|
|
45
|
+
* trigger — frameworks set callbacks as properties post-creation.
|
|
46
|
+
*/
|
|
47
|
+
@property({ attribute: false }) formatDate?: (date: Date) => string;
|
|
24
48
|
@property({ type: Boolean, reflect: true }) open = false;
|
|
25
49
|
@property({ type: Boolean, attribute: "close-on-select" }) closeOnSelect = true;
|
|
26
50
|
@property({ type: Boolean }) clearable = false;
|
|
27
51
|
|
|
52
|
+
// ── Standardized input API (mirrors rel-textfield) ──
|
|
53
|
+
@property({ type: Boolean }) error = false;
|
|
54
|
+
@property({ type: String, attribute: "error-message" }) errorMessage?: string;
|
|
55
|
+
@property({ type: String, attribute: "helper-text" }) helperText?: string;
|
|
56
|
+
@property({ type: String }) name?: string;
|
|
57
|
+
@property({ type: String }) size: "small" | "medium" | "large" = "medium";
|
|
58
|
+
@property({ type: String, reflect: true }) variant: "outlined" = "outlined";
|
|
59
|
+
@property({ type: Boolean, reflect: true }) fullWidth = false;
|
|
60
|
+
|
|
28
61
|
// Custom disabled predicate (not settable via attribute)
|
|
29
62
|
public isDateDisabled?: (date: Date) => boolean;
|
|
30
63
|
|
|
64
|
+
// minDate/maxDate supersede the deprecated min/max aliases
|
|
65
|
+
private get minBound(): string | null {
|
|
66
|
+
return this.minDate ?? this.min;
|
|
67
|
+
}
|
|
68
|
+
private get maxBound(): string | null {
|
|
69
|
+
return this.maxDate ?? this.max;
|
|
70
|
+
}
|
|
71
|
+
|
|
31
72
|
@state() private viewYear: number = new Date().getFullYear();
|
|
32
73
|
@state() private viewMonth: number = new Date().getMonth();
|
|
33
74
|
@state() private focusedDate: Date | null = null;
|
|
@@ -40,11 +81,18 @@ export class RelDatePicker extends LitElement {
|
|
|
40
81
|
|
|
41
82
|
static styles = css`
|
|
42
83
|
:host {
|
|
43
|
-
|
|
44
|
-
|
|
84
|
+
color: var(--rel-text-default);
|
|
85
|
+
display: block;
|
|
86
|
+
font-family: var(--rel-fonts-font-family);
|
|
45
87
|
position: relative;
|
|
46
88
|
}
|
|
47
89
|
|
|
90
|
+
/* Intrinsic width by default; set fullWidth to fill the parent. */
|
|
91
|
+
:host(:not([fullwidth])) {
|
|
92
|
+
display: inline-block;
|
|
93
|
+
width: auto;
|
|
94
|
+
}
|
|
95
|
+
|
|
48
96
|
:host([disabled]) {
|
|
49
97
|
opacity: 0.6;
|
|
50
98
|
cursor: not-allowed;
|
|
@@ -54,16 +102,54 @@ export class RelDatePicker extends LitElement {
|
|
|
54
102
|
pointer-events: none;
|
|
55
103
|
}
|
|
56
104
|
|
|
105
|
+
:host([readonly]) .trigger-button {
|
|
106
|
+
cursor: default;
|
|
107
|
+
}
|
|
108
|
+
|
|
57
109
|
.date-picker-wrapper {
|
|
58
110
|
display: flex;
|
|
59
111
|
flex-direction: column;
|
|
60
|
-
gap: var(--rel-spacing-
|
|
112
|
+
gap: var(--rel-spacing-xs);
|
|
61
113
|
}
|
|
62
114
|
|
|
63
115
|
.label {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
116
|
+
color: var(--rel-text-label);
|
|
117
|
+
|
|
118
|
+
font-family: var(--rel-body-sm-medium-font-family);
|
|
119
|
+
|
|
120
|
+
font-weight: var(--rel-body-sm-medium-font-weight);
|
|
121
|
+
|
|
122
|
+
font-size: var(--rel-body-sm-medium-font-size);
|
|
123
|
+
|
|
124
|
+
line-height: var(--rel-body-sm-medium-line-height);
|
|
125
|
+
|
|
126
|
+
letter-spacing: var(--rel-body-sm-medium-letter-spacing);
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.required-mark {
|
|
131
|
+
color: var(--rel-text-danger);
|
|
132
|
+
margin-left: 2px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Support text (helperText / errorMessage) */
|
|
136
|
+
.date-picker-support {
|
|
137
|
+
color: var(--rel-text-placeholder);
|
|
138
|
+
|
|
139
|
+
font-family: var(--rel-body-xs-regular-font-family);
|
|
140
|
+
|
|
141
|
+
font-weight: var(--rel-body-xs-regular-font-weight);
|
|
142
|
+
|
|
143
|
+
font-size: var(--rel-body-xs-regular-font-size);
|
|
144
|
+
|
|
145
|
+
line-height: var(--rel-body-xs-regular-line-height);
|
|
146
|
+
|
|
147
|
+
letter-spacing: var(--rel-body-xs-regular-letter-spacing);
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.date-picker-support.error {
|
|
152
|
+
color: var(--rel-text-danger);
|
|
67
153
|
}
|
|
68
154
|
|
|
69
155
|
.trigger-button {
|
|
@@ -72,65 +158,98 @@ export class RelDatePicker extends LitElement {
|
|
|
72
158
|
display: flex;
|
|
73
159
|
align-items: center;
|
|
74
160
|
justify-content: space-between;
|
|
75
|
-
gap: var(--rel-spacing-
|
|
76
|
-
padding: var(--rel-spacing-
|
|
77
|
-
background: var(--rel-
|
|
161
|
+
gap: var(--rel-spacing-xs);
|
|
162
|
+
padding: var(--rel-spacing-sm) var(--rel-spacing-md);
|
|
163
|
+
background: var(--rel-bg-surface);
|
|
78
164
|
border: 1px solid var(--rel-border-default);
|
|
79
|
-
border-radius: var(--rel-
|
|
80
|
-
|
|
81
|
-
font-size: var(--rel-fontSizes-md);
|
|
82
|
-
color: var(--rel-text-primary);
|
|
165
|
+
border-radius: var(--rel-border-radius-sm);
|
|
166
|
+
color: var(--rel-text-default);
|
|
83
167
|
cursor: pointer;
|
|
84
168
|
transition: all 0.15s ease;
|
|
85
169
|
text-align: left;
|
|
170
|
+
font-family: var(--rel-body-md-regular-font-family);
|
|
171
|
+
font-weight: var(--rel-body-md-regular-font-weight);
|
|
172
|
+
font-size: var(--rel-body-md-regular-font-size);
|
|
173
|
+
line-height: var(--rel-body-md-regular-line-height);
|
|
174
|
+
letter-spacing: var(--rel-body-md-regular-letter-spacing);
|
|
86
175
|
}
|
|
87
176
|
|
|
88
177
|
.trigger-button:hover:not(:disabled) {
|
|
89
|
-
border-color: var(--rel-
|
|
178
|
+
border-color: var(--rel-border-strong);
|
|
90
179
|
}
|
|
91
180
|
|
|
92
181
|
.trigger-button:focus-visible {
|
|
93
|
-
outline: 2px solid var(--rel-
|
|
182
|
+
outline: 2px solid var(--rel-border-focus);
|
|
94
183
|
outline-offset: 2px;
|
|
95
|
-
border-color: var(--rel-
|
|
184
|
+
border-color: var(--rel-border-focus);
|
|
96
185
|
}
|
|
97
186
|
|
|
98
187
|
.trigger-button:disabled {
|
|
99
188
|
cursor: not-allowed;
|
|
100
|
-
background: var(--rel-surface-
|
|
189
|
+
background: var(--rel-bg-surface-elevated);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Error state */
|
|
193
|
+
.trigger-button.error,
|
|
194
|
+
.trigger-button.error:hover:not(:disabled) {
|
|
195
|
+
border-color: var(--rel-border-danger);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.trigger-button.error:focus-visible {
|
|
199
|
+
outline-color: var(--rel-border-danger);
|
|
200
|
+
border-color: var(--rel-border-danger);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* Size variants (medium is the base .trigger-button style) */
|
|
204
|
+
.date-picker-wrapper.small .trigger-button {
|
|
205
|
+
padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
|
|
206
|
+
font-family: var(--rel-body-sm-regular-font-family);
|
|
207
|
+
font-weight: var(--rel-body-sm-regular-font-weight);
|
|
208
|
+
font-size: var(--rel-body-sm-regular-font-size);
|
|
209
|
+
line-height: var(--rel-body-sm-regular-line-height);
|
|
210
|
+
letter-spacing: var(--rel-body-sm-regular-letter-spacing);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.date-picker-wrapper.large .trigger-button {
|
|
214
|
+
padding: var(--rel-spacing-md) var(--rel-spacing-md);
|
|
215
|
+
font-family: var(--rel-body-lg-regular-font-family);
|
|
216
|
+
font-weight: var(--rel-body-lg-regular-font-weight);
|
|
217
|
+
font-size: var(--rel-body-lg-regular-font-size);
|
|
218
|
+
line-height: var(--rel-body-lg-regular-line-height);
|
|
219
|
+
letter-spacing: var(--rel-body-lg-regular-letter-spacing);
|
|
101
220
|
}
|
|
102
221
|
|
|
103
222
|
.trigger-content {
|
|
104
223
|
flex: 1;
|
|
105
|
-
color: var(--rel-text-
|
|
224
|
+
color: var(--rel-text-default);
|
|
106
225
|
}
|
|
107
226
|
|
|
108
227
|
.trigger-content.placeholder {
|
|
109
|
-
color: var(--rel-
|
|
228
|
+
color: var(--rel-text-placeholder);
|
|
110
229
|
}
|
|
111
230
|
|
|
112
231
|
.trigger-icons {
|
|
113
232
|
display: flex;
|
|
114
233
|
align-items: center;
|
|
115
|
-
gap: var(--rel-spacing-
|
|
234
|
+
gap: var(--rel-spacing-2xs);
|
|
116
235
|
}
|
|
117
236
|
|
|
118
237
|
.icon-button {
|
|
119
238
|
background: none;
|
|
120
239
|
border: none;
|
|
121
|
-
padding: var(--rel-spacing-
|
|
240
|
+
padding: var(--rel-spacing-3xs);
|
|
122
241
|
cursor: pointer;
|
|
123
|
-
color: var(--rel-
|
|
242
|
+
color: var(--rel-text-placeholder);
|
|
124
243
|
display: flex;
|
|
125
244
|
align-items: center;
|
|
126
245
|
justify-content: center;
|
|
127
|
-
border-radius: var(--rel-
|
|
246
|
+
border-radius: var(--rel-border-radius-xs);
|
|
128
247
|
transition: all 0.15s ease;
|
|
129
248
|
}
|
|
130
249
|
|
|
131
250
|
.icon-button:hover {
|
|
132
|
-
background: var(--rel-surface-
|
|
133
|
-
color: var(--rel-
|
|
251
|
+
background: var(--rel-bg-surface-elevated);
|
|
252
|
+
color: var(--rel-text-default);
|
|
134
253
|
}
|
|
135
254
|
|
|
136
255
|
.icon-button svg {
|
|
@@ -143,11 +262,11 @@ export class RelDatePicker extends LitElement {
|
|
|
143
262
|
top: calc(100% + 4px);
|
|
144
263
|
left: 0;
|
|
145
264
|
z-index: 1000;
|
|
146
|
-
background: var(--rel-
|
|
265
|
+
background: var(--rel-bg-surface);
|
|
147
266
|
border: 1px solid var(--rel-border-default);
|
|
148
|
-
border-radius: var(--rel-
|
|
267
|
+
border-radius: var(--rel-border-radius-sm);
|
|
149
268
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
150
|
-
padding: var(--rel-spacing-
|
|
269
|
+
padding: var(--rel-spacing-md);
|
|
151
270
|
min-width: 280px;
|
|
152
271
|
display: none;
|
|
153
272
|
}
|
|
@@ -160,8 +279,8 @@ export class RelDatePicker extends LitElement {
|
|
|
160
279
|
display: flex;
|
|
161
280
|
align-items: center;
|
|
162
281
|
justify-content: space-between;
|
|
163
|
-
margin-bottom: var(--rel-spacing-
|
|
164
|
-
gap: var(--rel-spacing-
|
|
282
|
+
margin-bottom: var(--rel-spacing-md);
|
|
283
|
+
gap: var(--rel-spacing-xs);
|
|
165
284
|
}
|
|
166
285
|
|
|
167
286
|
.nav-button {
|
|
@@ -169,21 +288,21 @@ export class RelDatePicker extends LitElement {
|
|
|
169
288
|
border: none;
|
|
170
289
|
width: 32px;
|
|
171
290
|
height: 32px;
|
|
172
|
-
border-radius: var(--rel-
|
|
291
|
+
border-radius: var(--rel-border-radius-sm);
|
|
173
292
|
display: flex;
|
|
174
293
|
align-items: center;
|
|
175
294
|
justify-content: center;
|
|
176
295
|
cursor: pointer;
|
|
177
|
-
color: var(--rel-
|
|
296
|
+
color: var(--rel-text-default);
|
|
178
297
|
transition: background-color 0.15s ease;
|
|
179
298
|
}
|
|
180
299
|
|
|
181
300
|
.nav-button:hover {
|
|
182
|
-
background: var(--rel-surface-
|
|
301
|
+
background: var(--rel-bg-surface-elevated);
|
|
183
302
|
}
|
|
184
303
|
|
|
185
304
|
.nav-button:focus-visible {
|
|
186
|
-
outline: 2px solid var(--rel-
|
|
305
|
+
outline: 2px solid var(--rel-border-focus);
|
|
187
306
|
outline-offset: 2px;
|
|
188
307
|
}
|
|
189
308
|
|
|
@@ -194,25 +313,27 @@ export class RelDatePicker extends LitElement {
|
|
|
194
313
|
|
|
195
314
|
.dropdown-trigger {
|
|
196
315
|
width: 100%;
|
|
197
|
-
padding: var(--rel-spacing-
|
|
198
|
-
background: var(--rel-
|
|
316
|
+
padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
|
|
317
|
+
background: var(--rel-bg-surface);
|
|
199
318
|
border: 1px solid var(--rel-border-default);
|
|
200
|
-
border-radius: var(--rel-
|
|
201
|
-
|
|
202
|
-
font-size: var(--rel-fontSizes-sm);
|
|
203
|
-
font-weight: var(--rel-fontWeights-medium);
|
|
204
|
-
color: var(--rel-text-heading);
|
|
319
|
+
border-radius: var(--rel-border-radius-sm);
|
|
320
|
+
color: var(--rel-text-label);
|
|
205
321
|
cursor: pointer;
|
|
206
322
|
text-align: center;
|
|
207
323
|
transition: all 0.15s ease;
|
|
324
|
+
font-family: var(--rel-body-sm-medium-font-family);
|
|
325
|
+
font-weight: var(--rel-body-sm-medium-font-weight);
|
|
326
|
+
font-size: var(--rel-body-sm-medium-font-size);
|
|
327
|
+
line-height: var(--rel-body-sm-medium-line-height);
|
|
328
|
+
letter-spacing: var(--rel-body-sm-medium-letter-spacing);
|
|
208
329
|
}
|
|
209
330
|
|
|
210
331
|
.dropdown-trigger:hover {
|
|
211
|
-
background: var(--rel-surface-
|
|
332
|
+
background: var(--rel-bg-surface-elevated);
|
|
212
333
|
}
|
|
213
334
|
|
|
214
335
|
.dropdown-trigger:focus-visible {
|
|
215
|
-
outline: 2px solid var(--rel-
|
|
336
|
+
outline: 2px solid var(--rel-border-focus);
|
|
216
337
|
outline-offset: 2px;
|
|
217
338
|
}
|
|
218
339
|
|
|
@@ -222,9 +343,9 @@ export class RelDatePicker extends LitElement {
|
|
|
222
343
|
left: 0;
|
|
223
344
|
right: 0;
|
|
224
345
|
z-index: 10;
|
|
225
|
-
background: var(--rel-
|
|
346
|
+
background: var(--rel-bg-surface);
|
|
226
347
|
border: 1px solid var(--rel-border-default);
|
|
227
|
-
border-radius: var(--rel-
|
|
348
|
+
border-radius: var(--rel-border-radius-sm);
|
|
228
349
|
box-shadow: var(--rel-shadows-shadow-200);
|
|
229
350
|
max-height: 200px;
|
|
230
351
|
overflow-y: auto;
|
|
@@ -236,81 +357,90 @@ export class RelDatePicker extends LitElement {
|
|
|
236
357
|
}
|
|
237
358
|
|
|
238
359
|
.dropdown-item {
|
|
239
|
-
padding: var(--rel-spacing-
|
|
360
|
+
padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
|
|
240
361
|
cursor: pointer;
|
|
241
|
-
|
|
242
|
-
color: var(--rel-text-primary);
|
|
362
|
+
color: var(--rel-text-default);
|
|
243
363
|
transition: background-color 0.15s ease;
|
|
364
|
+
font-family: var(--rel-body-sm-regular-font-family);
|
|
365
|
+
font-weight: var(--rel-body-sm-regular-font-weight);
|
|
366
|
+
font-size: var(--rel-body-sm-regular-font-size);
|
|
367
|
+
line-height: var(--rel-body-sm-regular-line-height);
|
|
368
|
+
letter-spacing: var(--rel-body-sm-regular-letter-spacing);
|
|
244
369
|
}
|
|
245
370
|
|
|
246
371
|
.dropdown-item:hover {
|
|
247
|
-
background: var(--rel-surface-
|
|
372
|
+
background: var(--rel-bg-surface-elevated);
|
|
248
373
|
}
|
|
249
374
|
|
|
250
375
|
.dropdown-item.selected {
|
|
251
|
-
background: var(--rel-
|
|
376
|
+
background: var(--rel-bg-info-light);
|
|
252
377
|
color: var(--rel-text-info);
|
|
253
|
-
font-weight: var(--rel-
|
|
378
|
+
font-weight: var(--rel-body-md-semibold-font-weight);
|
|
254
379
|
}
|
|
255
380
|
|
|
256
381
|
.weekdays {
|
|
257
382
|
display: grid;
|
|
258
383
|
grid-template-columns: repeat(7, 1fr);
|
|
259
|
-
gap: var(--rel-spacing-
|
|
260
|
-
margin-bottom: var(--rel-spacing-
|
|
384
|
+
gap: var(--rel-spacing-3xs);
|
|
385
|
+
margin-bottom: var(--rel-spacing-xs);
|
|
261
386
|
}
|
|
262
387
|
|
|
263
388
|
.weekday {
|
|
264
389
|
text-align: center;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
color: var(--rel-color-text-placeholder);
|
|
268
|
-
padding: var(--rel-spacing-space-xs);
|
|
390
|
+
color: var(--rel-text-placeholder);
|
|
391
|
+
padding: var(--rel-spacing-xs);
|
|
269
392
|
text-transform: uppercase;
|
|
393
|
+
font-family: var(--rel-body-xs-semibold-font-family);
|
|
394
|
+
font-weight: var(--rel-body-xs-semibold-font-weight);
|
|
395
|
+
font-size: var(--rel-body-xs-semibold-font-size);
|
|
396
|
+
line-height: var(--rel-body-xs-semibold-line-height);
|
|
397
|
+
letter-spacing: var(--rel-body-xs-semibold-letter-spacing);
|
|
270
398
|
}
|
|
271
399
|
|
|
272
400
|
.calendar-grid {
|
|
273
401
|
display: grid;
|
|
274
402
|
grid-template-columns: repeat(7, 1fr);
|
|
275
|
-
gap: var(--rel-spacing-
|
|
403
|
+
gap: var(--rel-spacing-3xs);
|
|
276
404
|
}
|
|
277
405
|
|
|
278
406
|
.day-button {
|
|
279
407
|
aspect-ratio: 1;
|
|
280
408
|
border: none;
|
|
281
409
|
background: transparent;
|
|
282
|
-
border-radius: var(--rel-
|
|
283
|
-
|
|
284
|
-
font-weight: var(--rel-fontWeights-medium);
|
|
285
|
-
color: var(--rel-text-primary);
|
|
410
|
+
border-radius: var(--rel-border-radius-sm);
|
|
411
|
+
color: var(--rel-text-default);
|
|
286
412
|
cursor: pointer;
|
|
287
413
|
position: relative;
|
|
288
414
|
transition: all 0.15s ease;
|
|
289
|
-
font-family: var(--rel-
|
|
415
|
+
font-family: var(--rel-body-sm-medium-font-family);
|
|
416
|
+
font-weight: var(--rel-body-sm-medium-font-weight);
|
|
417
|
+
font-size: var(--rel-body-sm-medium-font-size);
|
|
418
|
+
line-height: var(--rel-body-sm-medium-line-height);
|
|
419
|
+
letter-spacing: var(--rel-body-sm-medium-letter-spacing);
|
|
290
420
|
}
|
|
291
421
|
|
|
292
422
|
.day-button:hover:not(:disabled):not(.selected) {
|
|
293
|
-
background: var(--rel-surface-
|
|
423
|
+
background: var(--rel-bg-surface-elevated);
|
|
294
424
|
}
|
|
295
425
|
|
|
296
426
|
.day-button:focus-visible {
|
|
297
|
-
outline: 2px solid var(--rel-
|
|
427
|
+
outline: 2px solid var(--rel-border-focus);
|
|
298
428
|
outline-offset: -2px;
|
|
299
429
|
z-index: 1;
|
|
300
430
|
}
|
|
301
431
|
|
|
302
432
|
.day-button.today:not(.selected) {
|
|
303
|
-
border: 2px solid var(--rel-
|
|
433
|
+
border: 2px solid var(--rel-border-brand);
|
|
304
434
|
}
|
|
305
435
|
|
|
306
436
|
.day-button.selected {
|
|
307
|
-
background: var(--rel-
|
|
308
|
-
color: var(--rel-
|
|
309
|
-
font-weight: var(--rel-
|
|
437
|
+
background: var(--rel-action-brand-fill);
|
|
438
|
+
color: var(--rel-action-brand-label-icons-primary);
|
|
439
|
+
font-weight: var(--rel-body-md-semibold-font-weight);
|
|
310
440
|
}
|
|
311
441
|
|
|
312
442
|
.day-button.other-month {
|
|
313
|
-
color: var(--rel-
|
|
443
|
+
color: var(--rel-text-placeholder);
|
|
314
444
|
opacity: 0.5;
|
|
315
445
|
}
|
|
316
446
|
|
|
@@ -410,6 +540,21 @@ export class RelDatePicker extends LitElement {
|
|
|
410
540
|
const date = this.parseISODate(iso);
|
|
411
541
|
if (!date) return iso;
|
|
412
542
|
|
|
543
|
+
// 1) explicit callback wins (fall back on error so a bad callback can't
|
|
544
|
+
// blank the field)
|
|
545
|
+
if (typeof this.formatDate === "function") {
|
|
546
|
+
try {
|
|
547
|
+
const out = this.formatDate(date);
|
|
548
|
+
if (typeof out === "string") return out;
|
|
549
|
+
} catch {
|
|
550
|
+
/* fall through to the default */
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// 2) token pattern (e.g. "YYYY-MM-DD")
|
|
554
|
+
if (this.displayFormat) {
|
|
555
|
+
return formatDatePattern(date, this.displayFormat, this.locale);
|
|
556
|
+
}
|
|
557
|
+
// 3) backward-compatible locale long date
|
|
413
558
|
return new Intl.DateTimeFormat(this.locale, {
|
|
414
559
|
year: "numeric",
|
|
415
560
|
month: "long",
|
|
@@ -428,13 +573,13 @@ export class RelDatePicker extends LitElement {
|
|
|
428
573
|
private isDateDisabledInternal(date: Date): boolean {
|
|
429
574
|
if (this.disabled) return true;
|
|
430
575
|
|
|
431
|
-
if (this.
|
|
432
|
-
const minDate = this.parseISODate(this.
|
|
576
|
+
if (this.minBound) {
|
|
577
|
+
const minDate = this.parseISODate(this.minBound);
|
|
433
578
|
if (minDate && date < minDate) return true;
|
|
434
579
|
}
|
|
435
580
|
|
|
436
|
-
if (this.
|
|
437
|
-
const maxDate = this.parseISODate(this.
|
|
581
|
+
if (this.maxBound) {
|
|
582
|
+
const maxDate = this.parseISODate(this.maxBound);
|
|
438
583
|
if (maxDate && date > maxDate) return true;
|
|
439
584
|
}
|
|
440
585
|
|
|
@@ -535,13 +680,13 @@ export class RelDatePicker extends LitElement {
|
|
|
535
680
|
let startYear = currentYear - 100;
|
|
536
681
|
let endYear = currentYear + 10;
|
|
537
682
|
|
|
538
|
-
if (this.
|
|
539
|
-
const minDate = this.parseISODate(this.
|
|
683
|
+
if (this.minBound) {
|
|
684
|
+
const minDate = this.parseISODate(this.minBound);
|
|
540
685
|
if (minDate) startYear = Math.max(startYear, minDate.getFullYear() - 5);
|
|
541
686
|
}
|
|
542
687
|
|
|
543
|
-
if (this.
|
|
544
|
-
const maxDate = this.parseISODate(this.
|
|
688
|
+
if (this.maxBound) {
|
|
689
|
+
const maxDate = this.parseISODate(this.maxBound);
|
|
545
690
|
if (maxDate) endYear = Math.min(endYear, maxDate.getFullYear() + 5);
|
|
546
691
|
}
|
|
547
692
|
|
|
@@ -553,7 +698,7 @@ export class RelDatePicker extends LitElement {
|
|
|
553
698
|
}
|
|
554
699
|
|
|
555
700
|
private toggleCalendarPopover() {
|
|
556
|
-
if (this.disabled) return;
|
|
701
|
+
if (this.disabled || this.readonly) return;
|
|
557
702
|
this.open = !this.open;
|
|
558
703
|
this.dispatchEvent(
|
|
559
704
|
new CustomEvent("rel-open-change", {
|
|
@@ -597,7 +742,7 @@ export class RelDatePicker extends LitElement {
|
|
|
597
742
|
}
|
|
598
743
|
|
|
599
744
|
private selectDay(day: CalendarDay) {
|
|
600
|
-
if (day.isDisabled || this.disabled) return;
|
|
745
|
+
if (day.isDisabled || this.disabled || this.readonly) return;
|
|
601
746
|
|
|
602
747
|
const newValue = this.formatISODate(day.date);
|
|
603
748
|
this.value = newValue;
|
|
@@ -746,14 +891,34 @@ export class RelDatePicker extends LitElement {
|
|
|
746
891
|
const months = this.getMonthsList();
|
|
747
892
|
const years = this.getYearsList();
|
|
748
893
|
|
|
894
|
+
const isError = this.error;
|
|
895
|
+
const belowText = isError && this.errorMessage ? this.errorMessage : this.helperText;
|
|
896
|
+
const describedById = belowText ? "date-picker-desc" : undefined;
|
|
897
|
+
const wrapperClasses = [
|
|
898
|
+
"date-picker-wrapper",
|
|
899
|
+
this.size,
|
|
900
|
+
isError ? "error" : "",
|
|
901
|
+
this.readonly ? "readonly" : "",
|
|
902
|
+
]
|
|
903
|
+
.filter(Boolean)
|
|
904
|
+
.join(" ");
|
|
905
|
+
|
|
749
906
|
return html`
|
|
750
|
-
<div class="
|
|
907
|
+
<div part="base" class="${wrapperClasses}">
|
|
751
908
|
${this.label
|
|
752
|
-
? html`<label class="label" id="date-picker-label"
|
|
909
|
+
? html`<label part="label" class="label" id="date-picker-label"
|
|
910
|
+
>${this.label}${this.required
|
|
911
|
+
? html`<span class="required-mark" aria-hidden="true">*</span>`
|
|
912
|
+
: nothing}</label
|
|
913
|
+
>`
|
|
914
|
+
: nothing}
|
|
915
|
+
|
|
916
|
+
${this.name
|
|
917
|
+
? html`<input type="hidden" name=${this.name} .value=${this.value ?? ""} />`
|
|
753
918
|
: nothing}
|
|
754
919
|
|
|
755
920
|
<button
|
|
756
|
-
class="trigger-button"
|
|
921
|
+
class="trigger-button ${isError ? "error" : ""}"
|
|
757
922
|
type="button"
|
|
758
923
|
?disabled=${this.disabled}
|
|
759
924
|
@click=${this.toggleCalendarPopover}
|
|
@@ -762,6 +927,9 @@ export class RelDatePicker extends LitElement {
|
|
|
762
927
|
aria-haspopup="dialog"
|
|
763
928
|
aria-expanded=${this.open}
|
|
764
929
|
aria-required=${this.required}
|
|
930
|
+
aria-invalid=${isError}
|
|
931
|
+
aria-readonly=${this.readonly}
|
|
932
|
+
aria-describedby=${describedById ?? nothing}
|
|
765
933
|
aria-labelledby=${this.label ? "date-picker-label" : nothing}
|
|
766
934
|
>
|
|
767
935
|
<span class="trigger-content ${this.value ? "" : "placeholder"}">
|
|
@@ -914,6 +1082,12 @@ export class RelDatePicker extends LitElement {
|
|
|
914
1082
|
)}
|
|
915
1083
|
</div>
|
|
916
1084
|
</div>
|
|
1085
|
+
|
|
1086
|
+
${belowText
|
|
1087
|
+
? html`<div class="date-picker-support ${isError ? "error" : ""}" id=${describedById}>
|
|
1088
|
+
${belowText}
|
|
1089
|
+
</div>`
|
|
1090
|
+
: nothing}
|
|
917
1091
|
</div>
|
|
918
1092
|
`;
|
|
919
1093
|
}
|