@fusion.dev/helix-core 0.158.0 → 0.160.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/custom-elements.json +403 -18
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/mixins/mixin-field/mixin-field.js +2 -1
- package/dist/mixins/mixin-picker-feedback/mixin-picker-feedback.d.ts +13 -1
- package/dist/mixins/mixin-picker-feedback/mixin-picker-feedback.js +26 -3
- package/dist/mixins/mixin-segmented-field/mixin-segmented-field.d.ts +12 -0
- package/dist/mixins/mixin-segmented-field/mixin-segmented-field.js +96 -39
- package/dist/utils/calendar/calendar.d.ts +50 -22
- package/dist/utils/calendar/calendar.js +134 -32
- package/dist/utils/date-segments/date-segments.d.ts +46 -14
- package/dist/utils/date-segments/date-segments.js +175 -27
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export { MixinControllerValue, type MixinControllerValueInterface, } from './mix
|
|
|
46
46
|
export { type DismissibleElement, MixinDismissible, } from './mixins/mixin-dismissible/mixin-dismissible.js';
|
|
47
47
|
export { MixinField, type MixinFieldInterface } from './mixins/mixin-field/mixin-field.js';
|
|
48
48
|
export { MixinPickerEditing, type MixinPickerEditingInterface, } from './mixins/mixin-picker-editing/mixin-picker-editing.js';
|
|
49
|
-
export { MixinPickerFeedback, type MixinPickerFeedbackInterface, } from './mixins/mixin-picker-feedback/mixin-picker-feedback.js';
|
|
49
|
+
export { MixinPickerFeedback, type MixinPickerFeedbackInterface, type PickerFailure, } from './mixins/mixin-picker-feedback/mixin-picker-feedback.js';
|
|
50
50
|
export { MixinPickerField, type MixinPickerFieldInterface, } from './mixins/mixin-picker-field/mixin-picker-field.js';
|
|
51
51
|
export { MixinSegmentedField, type MixinSegmentedFieldInterface, } from './mixins/mixin-segmented-field/mixin-segmented-field.js';
|
|
52
52
|
export { MixinSelectableItem, type MixinSelectableItemInterface, } from './mixins/mixin-selectable-item/mixin-selectable-item.js';
|
|
@@ -56,7 +56,7 @@ export { anchorElement } from './utils/anchor-element/anchor-element.js';
|
|
|
56
56
|
export { arrowReach, sideOf } from './utils/arrow/arrow.js';
|
|
57
57
|
export { assignSlots } from './utils/assign-slots/assign-slots.js';
|
|
58
58
|
export { type DrawAutofillOptions, drawAutofill, } from './utils/autofill-select/autofill-select.js';
|
|
59
|
-
export { addDays, addMonths, type Barring, barredBy, type CalendarView, calendarLocale, type DateCalendar, localToday, MONTH_CALENDARS, type MonthCalendar, type MonthSystem, monthOf, monthOut, monthSystem, type PeriodCell, type PeriodPage, periodCells, periodKey, periodMove, sameMonth, todayIn, weekendOf, weekStartOf, YEARS_SHOWN, yearOut, yearPageOf, } from './utils/calendar/calendar.js';
|
|
59
|
+
export { addDays, addMonths, type Barring, barredBy, type CalendarParts, type CalendarView, calendarLocale, type DateCalendar, localToday, MONTH_CALENDARS, type MonthCalendar, type MonthSystem, monthOf, monthOut, monthSystem, type PeriodCell, type PeriodPage, periodCells, periodKey, periodMove, sameMonth, todayIn, weekendOf, weekStartOf, YEARS_SHOWN, yearOut, yearPageOf, } from './utils/calendar/calendar.js';
|
|
60
60
|
export { capturePointer } from './utils/capture-pointer/capture-pointer.js';
|
|
61
61
|
export { centerInView } from './utils/center-in-view/center-in-view.js';
|
|
62
62
|
export { ariaChord, type ChordPress, chordParts, matchesChord, printableChord, selectsAll, } from './utils/chord/chord.js';
|
|
@@ -72,7 +72,7 @@ export { createSheet } from './utils/create-sheet/create-sheet.js';
|
|
|
72
72
|
export { type Color, type ColorFormat, formatColor, parseColor, toCss, toHsl, toOklch, toRgb, } from './utils/css-color/css-color.js';
|
|
73
73
|
export { customElement, definedTags, duplicateRegistrations, } from './utils/custom-element/custom-element.js';
|
|
74
74
|
export { type DataOption, type DataOptionItem, dataOptions, drawOptions, windowOf, } from './utils/data-options/data-options.js';
|
|
75
|
-
export { segmentName } from './utils/date-segments/date-segments.js';
|
|
75
|
+
export { readWrittenDate, readWrittenTime, segmentName, } from './utils/date-segments/date-segments.js';
|
|
76
76
|
export { type DrawDismissOptions, drawDismiss, drawDismissGlyph, } from './utils/draw-dismiss/draw-dismiss.js';
|
|
77
77
|
export { type DrawIconOptions, drawIcon } from './utils/draw-icon/draw-icon.js';
|
|
78
78
|
export { CHART_PLOT, drawTooltip, type ReadingCursor } from './utils/draw-tooltip/draw-tooltip.js';
|
package/dist/index.js
CHANGED
|
@@ -72,7 +72,7 @@ export { createSheet } from './utils/create-sheet/create-sheet.js';
|
|
|
72
72
|
export { formatColor, parseColor, toCss, toHsl, toOklch, toRgb, } from './utils/css-color/css-color.js';
|
|
73
73
|
export { customElement, definedTags, duplicateRegistrations, } from './utils/custom-element/custom-element.js';
|
|
74
74
|
export { dataOptions, drawOptions, windowOf, } from './utils/data-options/data-options.js';
|
|
75
|
-
export { segmentName } from './utils/date-segments/date-segments.js';
|
|
75
|
+
export { readWrittenDate, readWrittenTime, segmentName, } from './utils/date-segments/date-segments.js';
|
|
76
76
|
export { drawDismiss, drawDismissGlyph, } from './utils/draw-dismiss/draw-dismiss.js';
|
|
77
77
|
export { drawIcon } from './utils/draw-icon/draw-icon.js';
|
|
78
78
|
export { CHART_PLOT, drawTooltip } from './utils/draw-tooltip/draw-tooltip.js';
|
|
@@ -151,7 +151,8 @@ export const MixinField = (Base) => {
|
|
|
151
151
|
super.willUpdate(changed);
|
|
152
152
|
this.shownFeedback = this.resolvedFeedback;
|
|
153
153
|
this.toggleState('invalid', this.shownFeedback !== '');
|
|
154
|
-
this.internals.ariaInvalid =
|
|
154
|
+
this.internals.ariaInvalid =
|
|
155
|
+
this.shownFeedback !== '' ? 'true' : this.validates ? 'false' : null;
|
|
155
156
|
}
|
|
156
157
|
formResetCallback() {
|
|
157
158
|
;
|
|
@@ -19,11 +19,23 @@ export declare class MixinPickerFeedbackInterface {
|
|
|
19
19
|
* picker and says why.
|
|
20
20
|
*/
|
|
21
21
|
invalid: boolean;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Whether a reader is told the answer is wrong: `invalid`, `feedback`, a
|
|
24
|
+
* held answer the picker refuses, or a missing answer once the reader has
|
|
25
|
+
* committed one or a form has refused the picker.
|
|
26
|
+
*/
|
|
23
27
|
protected get marked(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* What the picker's own validation finds: `missing` for a required picker
|
|
30
|
+
* with nothing chosen, `refused` for an answer it holds and refuses, or
|
|
31
|
+
* nothing. Read in `willUpdate`, so a picker answers it from its properties.
|
|
32
|
+
*/
|
|
33
|
+
protected get failure(): PickerFailure | undefined;
|
|
24
34
|
/** The `feedback` line, or nothing while there is none. */
|
|
25
35
|
protected renderPickerFeedback(): TemplateResult | typeof nothing;
|
|
26
36
|
}
|
|
37
|
+
/** What a picker's own validation finds, which `marked` reads. */
|
|
38
|
+
export type PickerFailure = 'missing' | 'refused';
|
|
27
39
|
/**
|
|
28
40
|
* `feedback` and `invalid` for a picker that stands on its own as a form
|
|
29
41
|
* control: Color Picker, Date Picker and Time Picker.
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html, nothing } from 'lit';
|
|
8
|
-
import { property } from 'lit/decorators.js';
|
|
8
|
+
import { property, state } from 'lit/decorators.js';
|
|
9
9
|
import { hostAria } from '../../utils/host-aria/host-aria.js';
|
|
10
10
|
export const MixinPickerFeedback = (Base) => {
|
|
11
11
|
class PickerFeedbackElement extends Base {
|
|
@@ -13,16 +13,36 @@ export const MixinPickerFeedback = (Base) => {
|
|
|
13
13
|
super(...arguments);
|
|
14
14
|
this.feedback = '';
|
|
15
15
|
this.invalid = false;
|
|
16
|
+
this.touched = false;
|
|
16
17
|
}
|
|
17
18
|
get marked() {
|
|
18
|
-
|
|
19
|
+
if (this.invalid || this.feedback !== '') {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
const failure = this.failure;
|
|
23
|
+
return failure === 'refused' || (failure === 'missing' && this.touched);
|
|
24
|
+
}
|
|
25
|
+
get failure() {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
formResetCallback() {
|
|
29
|
+
super.formResetCallback();
|
|
30
|
+
this.touched = false;
|
|
31
|
+
}
|
|
32
|
+
firstUpdated(changed) {
|
|
33
|
+
super.firstUpdated(changed);
|
|
34
|
+
const touch = () => {
|
|
35
|
+
this.touched = true;
|
|
36
|
+
};
|
|
37
|
+
this.addEventListener('invalid', touch);
|
|
38
|
+
this.addEventListener('change', touch);
|
|
19
39
|
}
|
|
20
40
|
get validityFeedback() {
|
|
21
41
|
return this.feedback;
|
|
22
42
|
}
|
|
23
43
|
willUpdate(changed) {
|
|
24
44
|
super.willUpdate(changed);
|
|
25
|
-
this.internals.ariaInvalid = this.marked ? 'true' :
|
|
45
|
+
this.internals.ariaInvalid = this.marked ? 'true' : 'false';
|
|
26
46
|
this.toggleState('invalid', this.marked);
|
|
27
47
|
}
|
|
28
48
|
updated(changed) {
|
|
@@ -42,5 +62,8 @@ export const MixinPickerFeedback = (Base) => {
|
|
|
42
62
|
__decorate([
|
|
43
63
|
property({ reflect: true, type: Boolean })
|
|
44
64
|
], PickerFeedbackElement.prototype, "invalid", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
state()
|
|
67
|
+
], PickerFeedbackElement.prototype, "touched", void 0);
|
|
45
68
|
return PickerFeedbackElement;
|
|
46
69
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type TemplateResult } from 'lit';
|
|
2
2
|
import type { HelixFormElement } from '../../helix-form-element/helix-form-element.js';
|
|
3
|
+
import type { MonthSystem } from '../../utils/calendar/calendar.js';
|
|
3
4
|
import { type SegmentedKind, type SegmentOptions } from '../../utils/date-segments/date-segments.js';
|
|
4
5
|
import type { MixinControllerOpenInterface } from '../mixin-controller-open/mixin-controller-open.js';
|
|
5
6
|
import type { MixinControllerValueInterface } from '../mixin-controller-value/mixin-controller-value.js';
|
|
@@ -34,8 +35,17 @@ export declare class MixinSegmentedFieldInterface {
|
|
|
34
35
|
* time, in place of a line of text.
|
|
35
36
|
*/
|
|
36
37
|
segmented: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* What a screen reader hears before the segments of a range's first date or
|
|
40
|
+
* time, after each segment's own name.
|
|
41
|
+
*/
|
|
42
|
+
rangeStartLabel: string;
|
|
43
|
+
/** What a screen reader hears before the segments of a range's second date or time. */
|
|
44
|
+
rangeEndLabel: string;
|
|
37
45
|
/** Whether the segments are drawn: `segmented`, where the family can hold them. */
|
|
38
46
|
protected get segmentsShown(): boolean;
|
|
47
|
+
/** How many rows of segments the value takes: two for a range, one otherwise. */
|
|
48
|
+
protected get segmentGroups(): number;
|
|
39
49
|
/** The row of segments, the group a description is carried to, or `null` while none is drawn. */
|
|
40
50
|
protected get segmentGroup(): HTMLElement | null;
|
|
41
51
|
/** Whether this family can show segments in its current shape. */
|
|
@@ -46,6 +56,8 @@ export declare class MixinSegmentedFieldInterface {
|
|
|
46
56
|
protected get segmentLocale(): string;
|
|
47
57
|
/** The clock and the seconds a time is laid out with. */
|
|
48
58
|
protected get segmentOptions(): SegmentOptions;
|
|
59
|
+
/** The calendar a date's parts are counted in, or `undefined` for the Gregorian calendar. */
|
|
60
|
+
protected get segmentSystem(): MonthSystem | undefined;
|
|
49
61
|
/** The row of segments, in the locale's order, with what it writes between them. */
|
|
50
62
|
protected renderSegments(): TemplateResult;
|
|
51
63
|
}
|
|
@@ -18,18 +18,23 @@ export const MixinSegmentedField = (Base) => {
|
|
|
18
18
|
this.emptyMessage = '{kind, select, date {Enter a date.} other {Enter a time.}}';
|
|
19
19
|
this.emptySegmentLabel = 'Empty';
|
|
20
20
|
this.incompleteMessage = '{kind, select, date {Enter a whole date.} other {Enter a whole time.}}';
|
|
21
|
+
this.rangeEndLabel = 'End';
|
|
22
|
+
this.rangeStartLabel = 'Start';
|
|
21
23
|
this.segmented = false;
|
|
22
|
-
this.parts = {};
|
|
24
|
+
this.parts = [{}];
|
|
23
25
|
this.typed = '';
|
|
24
26
|
this.own = false;
|
|
25
27
|
this.touchApple = appleTouch(typeof navigator === 'undefined' ? undefined : navigator);
|
|
26
28
|
this.entered = undefined;
|
|
29
|
+
this.opener = undefined;
|
|
27
30
|
this.handleSegmentKeydown = (event) => {
|
|
28
31
|
const element = event.currentTarget;
|
|
29
32
|
const kind = element.dataset.segment;
|
|
33
|
+
const row = Number(element.dataset.row ?? 0);
|
|
30
34
|
const twelve = isTwelveHourLayout(this.layout);
|
|
31
35
|
if (event.key === 'ArrowDown' && event.altKey) {
|
|
32
36
|
event.preventDefault();
|
|
37
|
+
this.opener = element;
|
|
33
38
|
this.handleTriggerClick();
|
|
34
39
|
return;
|
|
35
40
|
}
|
|
@@ -57,14 +62,15 @@ export const MixinSegmentedField = (Base) => {
|
|
|
57
62
|
const edit = segmentKey(event.key, {
|
|
58
63
|
kind,
|
|
59
64
|
locale: this.segmentLocale,
|
|
60
|
-
segments: this.parts,
|
|
65
|
+
segments: this.parts[row] ?? {},
|
|
66
|
+
system: this.segmentSystem,
|
|
61
67
|
twelve,
|
|
62
68
|
typed: this.typed,
|
|
63
69
|
});
|
|
64
70
|
if (edit) {
|
|
65
71
|
event.preventDefault();
|
|
66
72
|
this.typed = edit.typed;
|
|
67
|
-
this.take(edit.segments);
|
|
73
|
+
this.take(row, edit.segments);
|
|
68
74
|
if (edit.advance) {
|
|
69
75
|
this.moveFocus(element, 1);
|
|
70
76
|
}
|
|
@@ -96,12 +102,34 @@ export const MixinSegmentedField = (Base) => {
|
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
static { this.words = ''; }
|
|
105
|
+
returnFocus() {
|
|
106
|
+
const opener = this.opener;
|
|
107
|
+
this.opener = undefined;
|
|
108
|
+
if (opener?.isConnected && this.segmentsShown) {
|
|
109
|
+
this.returning = true;
|
|
110
|
+
opener.focus();
|
|
111
|
+
this.returning = false;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
super.returnFocus();
|
|
115
|
+
}
|
|
99
116
|
get segmentable() {
|
|
100
117
|
return true;
|
|
101
118
|
}
|
|
102
119
|
get segmentsShown() {
|
|
103
120
|
return this.segmented && this.segmentable;
|
|
104
121
|
}
|
|
122
|
+
get segmentGroups() {
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
joined(rows) {
|
|
126
|
+
const values = rows.map((one) => segmentsValue(this.segmentedKind, one, this.layout, this.segmentSystem));
|
|
127
|
+
return values.some((one) => one === '') ? '' : values.join(',');
|
|
128
|
+
}
|
|
129
|
+
rowsOf(value) {
|
|
130
|
+
const values = this.segmentGroups > 1 ? value.split(',') : [value];
|
|
131
|
+
return Array.from({ length: this.segmentGroups }, (_, row) => segmentsOf(this.segmentedKind, (values[row] ?? '').trim(), this.segmentSystem));
|
|
132
|
+
}
|
|
105
133
|
get segmentedKind() {
|
|
106
134
|
return 'date';
|
|
107
135
|
}
|
|
@@ -111,6 +139,9 @@ export const MixinSegmentedField = (Base) => {
|
|
|
111
139
|
get segmentOptions() {
|
|
112
140
|
return {};
|
|
113
141
|
}
|
|
142
|
+
get segmentSystem() {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
114
145
|
get layout() {
|
|
115
146
|
return segmentLayout(this.segmentedKind, this.segmentLocale, this.segmentOptions);
|
|
116
147
|
}
|
|
@@ -126,9 +157,9 @@ export const MixinSegmentedField = (Base) => {
|
|
|
126
157
|
get segmentElements() {
|
|
127
158
|
return [...(this.renderRoot?.querySelectorAll('[part~="segment"]') ?? [])];
|
|
128
159
|
}
|
|
129
|
-
take(next) {
|
|
130
|
-
this.parts = next;
|
|
131
|
-
const value =
|
|
160
|
+
take(row, next) {
|
|
161
|
+
this.parts = this.parts.map((one, index) => (index === row ? next : one));
|
|
162
|
+
const value = this.joined(this.parts);
|
|
132
163
|
if (value === this.value) {
|
|
133
164
|
this.sync();
|
|
134
165
|
return;
|
|
@@ -136,7 +167,7 @@ export const MixinSegmentedField = (Base) => {
|
|
|
136
167
|
this.own = true;
|
|
137
168
|
if (!this.requestValue(value)) {
|
|
138
169
|
this.own = false;
|
|
139
|
-
this.parts =
|
|
170
|
+
this.parts = this.rowsOf(this.value);
|
|
140
171
|
}
|
|
141
172
|
}
|
|
142
173
|
moveFocus(from, by) {
|
|
@@ -149,13 +180,13 @@ export const MixinSegmentedField = (Base) => {
|
|
|
149
180
|
this.own = false;
|
|
150
181
|
if (!own &&
|
|
151
182
|
this.segmentsShown &&
|
|
152
|
-
|
|
153
|
-
this.parts =
|
|
183
|
+
(this.parts.length !== this.segmentGroups || this.joined(this.parts) !== this.value)) {
|
|
184
|
+
this.parts = this.rowsOf(this.value);
|
|
154
185
|
}
|
|
155
186
|
}
|
|
156
187
|
formResetCallback() {
|
|
157
188
|
super.formResetCallback();
|
|
158
|
-
this.parts =
|
|
189
|
+
this.parts = this.rowsOf('');
|
|
159
190
|
this.typed = '';
|
|
160
191
|
}
|
|
161
192
|
connectedCallback() {
|
|
@@ -175,7 +206,9 @@ export const MixinSegmentedField = (Base) => {
|
|
|
175
206
|
return;
|
|
176
207
|
}
|
|
177
208
|
const anchor = this.anchor ?? undefined;
|
|
178
|
-
const partial = isPartial(this.segmentedKind, this.
|
|
209
|
+
const partial = this.parts.some((one) => isPartial(this.segmentedKind, one, this.layout, this.segmentSystem)) ||
|
|
210
|
+
(this.value === '' &&
|
|
211
|
+
this.parts.some((one) => Object.values(one).some((part) => part !== undefined)));
|
|
179
212
|
const fault = verdictFlags(this.validate());
|
|
180
213
|
if (partial) {
|
|
181
214
|
this.internals.setValidity({ badInput: true }, this.badInputMessage ||
|
|
@@ -197,51 +230,67 @@ export const MixinSegmentedField = (Base) => {
|
|
|
197
230
|
const layout = this.layout;
|
|
198
231
|
const twelve = isTwelveHourLayout(layout);
|
|
199
232
|
const locale = this.segmentLocale;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
233
|
+
const system = this.segmentSystem;
|
|
234
|
+
const rows = this.segmentGroups;
|
|
235
|
+
const row = (index) => {
|
|
236
|
+
const parts = this.parts[index] ?? {};
|
|
237
|
+
const prefix = index === 0 ? this.controlId : `${this.controlId}-end`;
|
|
238
|
+
const rowName = rows > 1 ? `${prefix}-row` : '';
|
|
239
|
+
return html `${rows > 1
|
|
240
|
+
? html `<span id=${rowName} hidden
|
|
241
|
+
>${index === 0 ? this.rangeStartLabel : this.rangeEndLabel}</span
|
|
242
|
+
>`
|
|
243
|
+
: nothing}${layout.map((slot) => {
|
|
244
|
+
if ('literal' in slot) {
|
|
245
|
+
return html `<span part="literal" aria-hidden="true">${slot.literal}</span>`;
|
|
246
|
+
}
|
|
247
|
+
const kind = slot.kind;
|
|
248
|
+
const shown = shownValue(kind, parts, twelve);
|
|
249
|
+
const { max, min } = segmentRange(kind, parts, twelve, system);
|
|
250
|
+
const text = segmentText(kind, parts, twelve, locale);
|
|
251
|
+
const empty = shown === undefined;
|
|
252
|
+
const id = `${prefix}-${kind}`;
|
|
253
|
+
const editable = !this.isDisabled && !this.readOnly;
|
|
254
|
+
const spin = !this.touchApple;
|
|
255
|
+
const named = [id, rowName, this.labeled ? this.labelId : ''].filter(Boolean).join(' ');
|
|
256
|
+
return html `<span
|
|
224
257
|
part="segment${empty ? ' segment-placeholder' : ''}"
|
|
225
258
|
id=${id}
|
|
259
|
+
data-row=${rows > 1 ? index : nothing}
|
|
226
260
|
data-segment=${kind}
|
|
227
261
|
role=${spin ? 'spinbutton' : 'textbox'}
|
|
228
262
|
tabindex=${this.isDisabled ? '-1' : '0'}
|
|
229
263
|
inputmode=${kind === 'dayPeriod' ? nothing : 'numeric'}
|
|
230
264
|
enterkeyhint=${editable ? 'next' : nothing}
|
|
231
|
-
aria-label=${
|
|
232
|
-
aria-labelledby=${
|
|
265
|
+
aria-label=${named === id ? segmentName(kind, locale) : `${segmentName(kind, locale)},`}
|
|
266
|
+
aria-labelledby=${named === id ? nothing : named}
|
|
233
267
|
aria-invalid=${this.invalidity ?? nothing}
|
|
234
268
|
aria-valuemin=${spin ? min : nothing}
|
|
235
269
|
aria-valuemax=${spin ? max : nothing}
|
|
236
270
|
aria-valuenow=${spin ? (shown ?? nothing) : nothing}
|
|
237
|
-
aria-valuetext=${spin ? (empty ? this.emptySegmentLabel : segmentValueText(kind,
|
|
271
|
+
aria-valuetext=${spin ? (empty ? this.emptySegmentLabel : segmentValueText(kind, parts, twelve, locale, system)) : nothing}
|
|
238
272
|
aria-disabled=${this.isDisabled ? 'true' : nothing}
|
|
239
273
|
aria-required=${this.required ? 'true' : nothing}
|
|
240
274
|
aria-readonly=${this.readOnly ? 'true' : nothing}
|
|
241
275
|
@keydown=${this.handleSegmentKeydown}
|
|
242
276
|
>${text}</span
|
|
243
277
|
>`;
|
|
244
|
-
|
|
278
|
+
})}`;
|
|
279
|
+
};
|
|
280
|
+
return html `<div
|
|
281
|
+
part="segments"
|
|
282
|
+
id=${this.controlId}
|
|
283
|
+
role="group"
|
|
284
|
+
aria-labelledby=${this.labeled ? this.labelId : nothing}
|
|
285
|
+
aria-describedby=${this.describedBy ?? nothing}
|
|
286
|
+
aria-invalid=${this.invalidity ?? nothing}
|
|
287
|
+
@focusin=${this.handleSegmentsFocusIn}
|
|
288
|
+
@focusout=${this.handleSegmentsFocusOut}
|
|
289
|
+
@keypress=${this.handleKeypress}
|
|
290
|
+
>
|
|
291
|
+
${Array.from({ length: rows }, (_, index) => index === 0
|
|
292
|
+
? row(0)
|
|
293
|
+
: html `<span part="literal range-separator" aria-hidden="true"> – </span>${row(index)}`)}
|
|
245
294
|
</div>`;
|
|
246
295
|
}
|
|
247
296
|
}
|
|
@@ -257,6 +306,14 @@ export const MixinSegmentedField = (Base) => {
|
|
|
257
306
|
words,
|
|
258
307
|
property({ attribute: 'incomplete-message' })
|
|
259
308
|
], SegmentedFieldElement.prototype, "incompleteMessage", void 0);
|
|
309
|
+
__decorate([
|
|
310
|
+
words,
|
|
311
|
+
property({ attribute: 'range-end-label' })
|
|
312
|
+
], SegmentedFieldElement.prototype, "rangeEndLabel", void 0);
|
|
313
|
+
__decorate([
|
|
314
|
+
words,
|
|
315
|
+
property({ attribute: 'range-start-label' })
|
|
316
|
+
], SegmentedFieldElement.prototype, "rangeStartLabel", void 0);
|
|
260
317
|
__decorate([
|
|
261
318
|
property({ type: Boolean })
|
|
262
319
|
], SegmentedFieldElement.prototype, "segmented", void 0);
|
|
@@ -44,11 +44,13 @@ export type DateCalendar = 'buddhist' | 'gregory' | 'iso8601' | 'japanese' | 'ro
|
|
|
44
44
|
* The language tag a date family formats with: `locale`, with the calendar it
|
|
45
45
|
* writes dates in.
|
|
46
46
|
*
|
|
47
|
-
* That is `calendar` where it
|
|
48
|
-
* the locale's own calendar where its months are the Gregorian months,
|
|
49
|
-
* `gregory`. **A calendar with months of its own
|
|
50
|
-
* or `islamic-umalqura` for `ar-SA` in
|
|
51
|
-
*
|
|
47
|
+
* That is `calendar` where it names a `DateCalendar` or a `MonthCalendar`,
|
|
48
|
+
* then the locale's own calendar where its months are the Gregorian months,
|
|
49
|
+
* then `gregory`. **A calendar with months of its own that only the locale
|
|
50
|
+
* names, such as `persian` for `fa-IR` or `islamic-umalqura` for `ar-SA` in
|
|
51
|
+
* some engines, is written as `gregory`**, so a page that asked for no other
|
|
52
|
+
* calendar keeps the Gregorian dates it had. Before the date families drew
|
|
53
|
+
* such a calendar's own months, a heading in Mehr 1405 over the days of
|
|
52
54
|
* October 2026 named a month the grid did not show.
|
|
53
55
|
*
|
|
54
56
|
* `locale` unchanged where nothing moves, so a page in a Gregorian locale
|
|
@@ -69,34 +71,55 @@ export declare const sameMonth: (left: Date, right: Date) => boolean;
|
|
|
69
71
|
*/
|
|
70
72
|
export declare const addMonths: (date: Date, months: number) => Date;
|
|
71
73
|
/**
|
|
72
|
-
* The calendars
|
|
73
|
-
* names one: the months of the year in Iran, Israel,
|
|
74
|
-
* Egypt's Coptic church,
|
|
75
|
-
*
|
|
74
|
+
* The calendars the date families draw with months of their own, when
|
|
75
|
+
* `calendar` names one: the months of the year in Iran, Israel, the Islamic
|
|
76
|
+
* calendars, Ethiopia, Egypt's Coptic church, India's national calendar, and
|
|
77
|
+
* the Chinese and Korean lunisolar calendars. Every calendar `Intl` knows
|
|
78
|
+
* whose months are not the Gregorian months.
|
|
76
79
|
*/
|
|
77
|
-
export type MonthCalendar = 'coptic' | 'ethiopic' | 'hebrew' | 'indian' | 'islamic-civil' | 'islamic-umalqura' | 'persian';
|
|
80
|
+
export type MonthCalendar = 'chinese' | 'coptic' | 'dangi' | 'ethioaa' | 'ethiopic' | 'hebrew' | 'indian' | 'islamic' | 'islamic-civil' | 'islamic-rgsa' | 'islamic-tbla' | 'islamic-umalqura' | 'persian';
|
|
78
81
|
/** The `MonthCalendar` names, for a check at run time. */
|
|
79
82
|
export declare const MONTH_CALENDARS: readonly string[];
|
|
83
|
+
/** A date as a calendar counts it: its year, its month from 1, and its day from 1. */
|
|
84
|
+
export interface CalendarParts {
|
|
85
|
+
day: number;
|
|
86
|
+
month: number;
|
|
87
|
+
year: number;
|
|
88
|
+
}
|
|
80
89
|
/**
|
|
81
|
-
* The months of a calendar, as
|
|
82
|
-
* still a Gregorian `Date` at midnight UTC, and a
|
|
83
|
-
* from its first.
|
|
90
|
+
* The days, months, and years of a calendar, as the date families page and
|
|
91
|
+
* edit them. Every date is still a Gregorian `Date` at midnight UTC, and a
|
|
92
|
+
* month is the run of days from its first.
|
|
84
93
|
*/
|
|
85
94
|
export interface MonthSystem {
|
|
86
95
|
/** A date some months away, its day kept where the month is long enough. */
|
|
87
96
|
add(date: Date, months: number): Date;
|
|
97
|
+
/**
|
|
98
|
+
* A date some years away: the month of the same name where the year has
|
|
99
|
+
* one, so Nisan stays Nisan across a Hebrew leap year, and the day kept
|
|
100
|
+
* where the month is long enough.
|
|
101
|
+
*/
|
|
102
|
+
addYears(date: Date, years: number): Date;
|
|
88
103
|
/** The day of its month, from 1. */
|
|
89
104
|
day(date: Date): number;
|
|
105
|
+
/** How many days a month of a year has. */
|
|
106
|
+
days(year: number, month: number): number;
|
|
107
|
+
/** The date of a year, month, and day, the month and the day kept inside the year and the month. */
|
|
108
|
+
from(year: number, month: number, day: number): Date;
|
|
90
109
|
/** The month a date is in, as `month` writes it: `YYYY-MM`, or its first day where the months are the calendar's own. */
|
|
91
110
|
key(date: Date): string;
|
|
111
|
+
/** How many months a year has: 12, or 13 in a Hebrew leap year, in Ethiopia, and in a Chinese leap year. */
|
|
112
|
+
months(year: number): number;
|
|
113
|
+
/** A date's year, month, and day, as the calendar counts them. */
|
|
114
|
+
parts(date: Date): CalendarParts;
|
|
92
115
|
/** Whether two dates fall in one month. */
|
|
93
116
|
same(left: Date, right: Date): boolean;
|
|
94
117
|
/** The first day of the month a date is in. */
|
|
95
118
|
start(date: Date): Date;
|
|
96
119
|
}
|
|
97
120
|
/**
|
|
98
|
-
* The months a calendar pages through: its own for a
|
|
99
|
-
* and the Gregorian months for every other.
|
|
121
|
+
* The days, months, and years a calendar pages through: its own for a
|
|
122
|
+
* `MonthCalendar` name, and the Gregorian months for every other.
|
|
100
123
|
*/
|
|
101
124
|
export declare const monthSystem: (calendar?: string) => MonthSystem;
|
|
102
125
|
/** What bars a date, besides `min` and `max`. */
|
|
@@ -138,9 +161,9 @@ export declare const yearPageOf: (year: number) => number;
|
|
|
138
161
|
*/
|
|
139
162
|
export declare const periodMove: (key: string, at: number, along: number) => number | null;
|
|
140
163
|
/** Whether a month, as its first day, lies wholly outside `min` and `max`, either of which may be empty. */
|
|
141
|
-
export declare const monthOut: (first: Date, min: string, max: string) => boolean;
|
|
164
|
+
export declare const monthOut: (first: Date, min: string, max: string, system?: MonthSystem) => boolean;
|
|
142
165
|
/** Whether a year lies wholly outside `min` and `max`, either of which may be empty. */
|
|
143
|
-
export declare const yearOut: (year: number, min: string, max: string) => boolean;
|
|
166
|
+
export declare const yearOut: (year: number, min: string, max: string, system?: MonthSystem) => boolean;
|
|
144
167
|
/** One month or year in the months or the years view. */
|
|
145
168
|
export interface PeriodCell {
|
|
146
169
|
/** The month's index in its year, or the year. */
|
|
@@ -164,16 +187,19 @@ export interface PeriodPage {
|
|
|
164
187
|
page: number;
|
|
165
188
|
/** The first of the month the calendar shows. */
|
|
166
189
|
shown: Date;
|
|
190
|
+
/** The calendar the months and the years are counted in, Gregorian where none is given. */
|
|
191
|
+
system?: MonthSystem | undefined;
|
|
167
192
|
/** Today, as `YYYY-MM-DD`. */
|
|
168
193
|
today: string;
|
|
169
194
|
/** Which view: `month` for the months of a year, `year` for a page of years. */
|
|
170
195
|
view: 'month' | 'year';
|
|
171
196
|
}
|
|
172
197
|
/**
|
|
173
|
-
* The
|
|
174
|
-
*
|
|
198
|
+
* The cells of the months or the years view, in reading order: the months of
|
|
199
|
+
* `page`, twelve or the thirteen a calendar's year may have, or the twelve
|
|
200
|
+
* years on the page that holds it.
|
|
175
201
|
*/
|
|
176
|
-
export declare const periodCells: ({ max, min, page, shown, today, view }: PeriodPage) => PeriodCell[];
|
|
202
|
+
export declare const periodCells: ({ max, min, page, shown, system, today, view, }: PeriodPage) => PeriodCell[];
|
|
177
203
|
/**
|
|
178
204
|
* Where a key takes the tab stop in the months or the years, or `null` for a
|
|
179
205
|
* key the grid leaves alone.
|
|
@@ -181,9 +207,11 @@ export declare const periodCells: ({ max, min, page, shown, today, view }: Perio
|
|
|
181
207
|
* `stop` is the month's index or the year the stop is on, `year` the year the
|
|
182
208
|
* months view shows, and `along` which way the inline keys go, as
|
|
183
209
|
* `periodMove` takes it. A move off the months of one year lands in the next
|
|
184
|
-
* or the last, and a move off a page of years turns the page.
|
|
210
|
+
* or the last, and a move off a page of years turns the page. `months` says
|
|
211
|
+
* how many months a year has, twelve where it is not given. The page keys
|
|
212
|
+
* move the months a year, to the month in the same place.
|
|
185
213
|
*/
|
|
186
|
-
export declare const periodKey: (view: 'month' | 'year', stop: number, year: number, key: string, along: number) => {
|
|
214
|
+
export declare const periodKey: (view: 'month' | 'year', stop: number, year: number, key: string, along: number, months?: (year: number) => number) => {
|
|
187
215
|
focus: number;
|
|
188
216
|
pageYear: number;
|
|
189
217
|
} | null;
|