tyrell-components 1.0.0-TC57 → 1.0.0-TC59
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/css/tyrell-colors-static.css +14 -0
- package/css/tyrell-theme.css +1 -0
- package/css/tyrell.css +8 -6
- package/dist/tyrell-colors-static.css +1 -1
- package/dist/tyrell-theme.css +1 -1
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.d.ts +20 -15
- package/lib/base/ty-component.js +58 -25
- package/lib/components/button.d.ts +14 -0
- package/lib/components/button.js +55 -7
- package/lib/components/calendar-month.d.ts +7 -1
- package/lib/components/calendar-month.js +35 -28
- package/lib/components/calendar-navigation.js +19 -6
- package/lib/components/calendar.d.ts +25 -4
- package/lib/components/calendar.js +98 -67
- package/lib/components/checkbox.d.ts +6 -1
- package/lib/components/checkbox.js +20 -6
- package/lib/components/copy.d.ts +2 -0
- package/lib/components/copy.js +15 -31
- package/lib/components/date-picker.d.ts +52 -19
- package/lib/components/date-picker.js +211 -147
- package/lib/components/file-upload.d.ts +2 -1
- package/lib/components/file-upload.js +8 -3
- package/lib/components/input.d.ts +4 -6
- package/lib/components/input.js +37 -62
- package/lib/components/modal.js +86 -9
- package/lib/components/option.js +2 -5
- package/lib/components/popup.js +99 -11
- package/lib/components/radio.d.ts +8 -1
- package/lib/components/radio.js +14 -29
- package/lib/components/resize-observer.js +2 -0
- package/lib/components/scroll-container.js +2 -0
- package/lib/components/select.d.ts +53 -6
- package/lib/components/select.js +127 -29
- package/lib/components/switch.d.ts +7 -1
- package/lib/components/switch.js +20 -6
- package/lib/components/tabs.js +1 -1
- package/lib/components/textarea.d.ts +45 -4
- package/lib/components/textarea.js +75 -18
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/styles/button.js +21 -19
- package/lib/styles/calendar-month.js +1 -1
- package/lib/styles/calendar.js +3 -0
- package/lib/styles/checkbox.js +11 -5
- package/lib/styles/date-picker.js +15 -3
- package/lib/styles/input.js +5 -9
- package/lib/styles/option.d.ts +1 -1
- package/lib/styles/option.js +4 -0
- package/lib/styles/popup.d.ts +1 -1
- package/lib/styles/popup.js +2 -0
- package/lib/styles/radio.js +10 -4
- package/lib/styles/select-base.js +24 -3
- package/lib/styles/select.d.ts +1 -1
- package/lib/styles/select.js +4 -0
- package/lib/styles/switch.js +10 -5
- package/lib/styles/tag.js +2 -1
- package/lib/styles/textarea.d.ts +1 -1
- package/lib/styles/textarea.js +7 -0
- package/lib/utils/calendar-utils.d.ts +49 -0
- package/lib/utils/calendar-utils.js +63 -6
- package/lib/utils/scroll-lock.d.ts +10 -4
- package/lib/utils/scroll-lock.js +102 -2
- package/lib/utils/upgrade-properties.d.ts +21 -0
- package/lib/utils/upgrade-properties.js +47 -0
- package/lib/utils/validity.d.ts +89 -5
- package/lib/utils/validity.js +198 -25
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -1
- package/lib/base/ty-component.d.ts.map +0 -1
- package/lib/base/ty-component.js.map +0 -1
- package/lib/components/button.d.ts.map +0 -1
- package/lib/components/button.js.map +0 -1
- package/lib/components/calendar-month.d.ts.map +0 -1
- package/lib/components/calendar-month.js.map +0 -1
- package/lib/components/calendar-navigation.d.ts.map +0 -1
- package/lib/components/calendar-navigation.js.map +0 -1
- package/lib/components/calendar.d.ts.map +0 -1
- package/lib/components/calendar.js.map +0 -1
- package/lib/components/checkbox.d.ts.map +0 -1
- package/lib/components/checkbox.js.map +0 -1
- package/lib/components/copy.d.ts.map +0 -1
- package/lib/components/copy.js.map +0 -1
- package/lib/components/date-picker.d.ts.map +0 -1
- package/lib/components/date-picker.js.map +0 -1
- package/lib/components/dropdown.d.ts +0 -403
- package/lib/components/dropdown.d.ts.map +0 -1
- package/lib/components/dropdown.js +0 -1315
- package/lib/components/dropdown.js.map +0 -1
- package/lib/components/icon.d.ts.map +0 -1
- package/lib/components/icon.js.map +0 -1
- package/lib/components/input.d.ts.map +0 -1
- package/lib/components/input.js.map +0 -1
- package/lib/components/modal.d.ts.map +0 -1
- package/lib/components/modal.js.map +0 -1
- package/lib/components/multiselect.d.ts +0 -389
- package/lib/components/multiselect.d.ts.map +0 -1
- package/lib/components/multiselect.js +0 -1301
- package/lib/components/multiselect.js.map +0 -1
- package/lib/components/option.d.ts.map +0 -1
- package/lib/components/option.js.map +0 -1
- package/lib/components/popup.d.ts.map +0 -1
- package/lib/components/popup.js.map +0 -1
- package/lib/components/resize-observer.d.ts.map +0 -1
- package/lib/components/resize-observer.js.map +0 -1
- package/lib/components/scroll-container.d.ts.map +0 -1
- package/lib/components/scroll-container.js.map +0 -1
- package/lib/components/step.d.ts.map +0 -1
- package/lib/components/step.js.map +0 -1
- package/lib/components/tab.d.ts.map +0 -1
- package/lib/components/tab.js.map +0 -1
- package/lib/components/tabs.d.ts.map +0 -1
- package/lib/components/tabs.js.map +0 -1
- package/lib/components/tag.d.ts.map +0 -1
- package/lib/components/tag.js.map +0 -1
- package/lib/components/textarea.d.ts.map +0 -1
- package/lib/components/textarea.js.map +0 -1
- package/lib/components/tooltip.d.ts.map +0 -1
- package/lib/components/tooltip.js.map +0 -1
- package/lib/components/wizard.d.ts.map +0 -1
- package/lib/components/wizard.js.map +0 -1
- package/lib/icons/fontawesome/brands.d.ts.map +0 -1
- package/lib/icons/fontawesome/brands.js.map +0 -1
- package/lib/icons/fontawesome/regular.d.ts.map +0 -1
- package/lib/icons/fontawesome/regular.js.map +0 -1
- package/lib/icons/fontawesome/solid.d.ts.map +0 -1
- package/lib/icons/fontawesome/solid.js.map +0 -1
- package/lib/icons/heroicons/micro.d.ts.map +0 -1
- package/lib/icons/heroicons/micro.js.map +0 -1
- package/lib/icons/heroicons/mini.d.ts.map +0 -1
- package/lib/icons/heroicons/mini.js.map +0 -1
- package/lib/icons/heroicons/outline.d.ts.map +0 -1
- package/lib/icons/heroicons/outline.js.map +0 -1
- package/lib/icons/heroicons/solid.d.ts.map +0 -1
- package/lib/icons/heroicons/solid.js.map +0 -1
- package/lib/icons/lucide.d.ts.map +0 -1
- package/lib/icons/lucide.js.map +0 -1
- package/lib/icons/material/filled.d.ts.map +0 -1
- package/lib/icons/material/filled.js.map +0 -1
- package/lib/icons/material/outlined.d.ts.map +0 -1
- package/lib/icons/material/outlined.js.map +0 -1
- package/lib/icons/material/round.d.ts.map +0 -1
- package/lib/icons/material/round.js.map +0 -1
- package/lib/icons/material/sharp.d.ts.map +0 -1
- package/lib/icons/material/sharp.js.map +0 -1
- package/lib/icons/material/two-tone.d.ts.map +0 -1
- package/lib/icons/material/two-tone.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/styles/button.d.ts.map +0 -1
- package/lib/styles/button.js.map +0 -1
- package/lib/styles/calendar-month.d.ts.map +0 -1
- package/lib/styles/calendar-month.js.map +0 -1
- package/lib/styles/calendar-navigation.d.ts.map +0 -1
- package/lib/styles/calendar-navigation.js.map +0 -1
- package/lib/styles/calendar.d.ts.map +0 -1
- package/lib/styles/calendar.js.map +0 -1
- package/lib/styles/copy.d.ts.map +0 -1
- package/lib/styles/copy.js.map +0 -1
- package/lib/styles/date-picker.d.ts.map +0 -1
- package/lib/styles/date-picker.js.map +0 -1
- package/lib/styles/dropdown.d.ts +0 -12
- package/lib/styles/dropdown.d.ts.map +0 -1
- package/lib/styles/dropdown.js +0 -725
- package/lib/styles/dropdown.js.map +0 -1
- package/lib/styles/icon.d.ts.map +0 -1
- package/lib/styles/icon.js.map +0 -1
- package/lib/styles/input.d.ts.map +0 -1
- package/lib/styles/input.js.map +0 -1
- package/lib/styles/modal.d.ts.map +0 -1
- package/lib/styles/modal.js.map +0 -1
- package/lib/styles/multiselect.d.ts +0 -6
- package/lib/styles/multiselect.d.ts.map +0 -1
- package/lib/styles/multiselect.js +0 -568
- package/lib/styles/multiselect.js.map +0 -1
- package/lib/styles/option.d.ts.map +0 -1
- package/lib/styles/option.js.map +0 -1
- package/lib/styles/popup.d.ts.map +0 -1
- package/lib/styles/popup.js.map +0 -1
- package/lib/styles/resize-observer.d.ts.map +0 -1
- package/lib/styles/resize-observer.js.map +0 -1
- package/lib/styles/scroll-container.d.ts.map +0 -1
- package/lib/styles/scroll-container.js.map +0 -1
- package/lib/styles/step.d.ts.map +0 -1
- package/lib/styles/step.js.map +0 -1
- package/lib/styles/tab.d.ts.map +0 -1
- package/lib/styles/tab.js.map +0 -1
- package/lib/styles/tabs.d.ts.map +0 -1
- package/lib/styles/tabs.js.map +0 -1
- package/lib/styles/tag.d.ts.map +0 -1
- package/lib/styles/tag.js.map +0 -1
- package/lib/styles/textarea.d.ts.map +0 -1
- package/lib/styles/textarea.js.map +0 -1
- package/lib/styles/tooltip.d.ts.map +0 -1
- package/lib/styles/tooltip.js.map +0 -1
- package/lib/styles/wizard.d.ts.map +0 -1
- package/lib/styles/wizard.js.map +0 -1
- package/lib/types/common.d.ts.map +0 -1
- package/lib/types/common.js.map +0 -1
- package/lib/utils/calendar-utils.d.ts.map +0 -1
- package/lib/utils/calendar-utils.js.map +0 -1
- package/lib/utils/icon-registry.d.ts.map +0 -1
- package/lib/utils/icon-registry.js.map +0 -1
- package/lib/utils/locale.d.ts.map +0 -1
- package/lib/utils/locale.js.map +0 -1
- package/lib/utils/number-format.d.ts.map +0 -1
- package/lib/utils/number-format.js.map +0 -1
- package/lib/utils/parse-boolean.d.ts +0 -39
- package/lib/utils/parse-boolean.d.ts.map +0 -1
- package/lib/utils/parse-boolean.js +0 -23
- package/lib/utils/parse-boolean.js.map +0 -1
- package/lib/utils/positioning.d.ts.map +0 -1
- package/lib/utils/positioning.js.map +0 -1
- package/lib/utils/property-capture.d.ts.map +0 -1
- package/lib/utils/property-capture.js.map +0 -1
- package/lib/utils/property-manager.d.ts.map +0 -1
- package/lib/utils/property-manager.js.map +0 -1
- package/lib/utils/resize-observer.d.ts.map +0 -1
- package/lib/utils/resize-observer.js.map +0 -1
- package/lib/utils/scroll-lock.d.ts.map +0 -1
- package/lib/utils/scroll-lock.js.map +0 -1
- package/lib/utils/styles.d.ts.map +0 -1
- package/lib/utils/styles.js.map +0 -1
- package/lib/version.d.ts.map +0 -1
- package/lib/version.js.map +0 -1
|
@@ -9,17 +9,28 @@
|
|
|
9
9
|
* - Property change events via 'prop:change' (separate from user 'change' events)
|
|
10
10
|
*/
|
|
11
11
|
import { PropertyManager, PropertyConfig, PropertyChange } from '../utils/property-manager.js';
|
|
12
|
+
import { upgradeProperties } from '../utils/upgrade-properties.js';
|
|
13
|
+
export { upgradeProperties };
|
|
12
14
|
/**
|
|
13
15
|
* Base class for all Ty components with unified property lifecycle
|
|
14
16
|
*/
|
|
15
17
|
export declare abstract class TyComponent<T = any> extends HTMLElement {
|
|
16
18
|
static formAssociated: boolean;
|
|
17
19
|
protected static properties: Record<string, PropertyConfig>;
|
|
20
|
+
/** attachShadow delegatesFocus: the host itself counts as focusable when
|
|
21
|
+
* its focusable role element lives in the shadow (checkbox/switch) —
|
|
22
|
+
* Firefox checks the host, not the validation anchor, on a blocked submit. */
|
|
23
|
+
protected static delegatesFocus: boolean;
|
|
24
|
+
/** A wrapping <label> delegates clicks to the host (see watchLabelForwards). */
|
|
25
|
+
protected static labelClicks: boolean;
|
|
18
26
|
protected props: PropertyManager<T>;
|
|
19
27
|
protected _internals: ElementInternals;
|
|
20
28
|
private _validity;
|
|
21
29
|
protected _connected: boolean;
|
|
22
30
|
protected _rendered: boolean;
|
|
31
|
+
/** The user edited the field since it was created or its form reset:
|
|
32
|
+
* blur then shows its validation message (like native :user-invalid). */
|
|
33
|
+
protected _userEdited: boolean;
|
|
23
34
|
constructor();
|
|
24
35
|
/**
|
|
25
36
|
* Define which attributes to observe
|
|
@@ -55,11 +66,14 @@ export declare abstract class TyComponent<T = any> extends HTMLElement {
|
|
|
55
66
|
* Disconnected callback
|
|
56
67
|
*/
|
|
57
68
|
disconnectedCallback(): void;
|
|
69
|
+
/** The form owner changed (moved, `form` attribute): see ValidityController.track(). */
|
|
70
|
+
formAssociatedCallback(): void;
|
|
58
71
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
72
|
+
* upgradeProperties(), plus declared properties without an accessor of
|
|
73
|
+
* their own name (e.g. ty-input's `minlength`): those go straight to
|
|
74
|
+
* setProperty().
|
|
61
75
|
*/
|
|
62
|
-
private
|
|
76
|
+
private _upgradeProperties;
|
|
63
77
|
/**
|
|
64
78
|
* THE CORE LIFECYCLE METHOD
|
|
65
79
|
* All property changes flow through here
|
|
@@ -137,18 +151,6 @@ export declare abstract class TyComponent<T = any> extends HTMLElement {
|
|
|
137
151
|
* the role element as aria-label, giving it an accessible name.
|
|
138
152
|
*/
|
|
139
153
|
protected applyLabelName(roleEl: HTMLElement): void;
|
|
140
|
-
private _handlingActivationClick;
|
|
141
|
-
/**
|
|
142
|
-
* Guard for click-driven toggle handlers (checkbox/switch) on components
|
|
143
|
-
* whose whole host is the click target AND that expect a wrapping
|
|
144
|
-
* <label> to delegate to them. Some browsers still forward a label's own
|
|
145
|
-
* synthetic click to the associated control even when the original click
|
|
146
|
-
* already targeted that control directly, firing 'click' twice for one
|
|
147
|
-
* user gesture. Both arrive synchronously in the same task, so a flag
|
|
148
|
-
* cleared on the next microtask catches only the spurious duplicate —
|
|
149
|
-
* two genuinely separate clicks are always in different tasks.
|
|
150
|
-
*/
|
|
151
|
-
protected isDuplicateActivationClick(): boolean;
|
|
152
154
|
private _resetDefaults;
|
|
153
155
|
/**
|
|
154
156
|
* Form reset callback - called when form.reset() is invoked.
|
|
@@ -157,6 +159,9 @@ export declare abstract class TyComponent<T = any> extends HTMLElement {
|
|
|
157
159
|
* semantics). Non-form state (e.g. a checkbox's submission `value`, a
|
|
158
160
|
* ty-radio's option `value`) is deliberately left alone — the old
|
|
159
161
|
* blanket 'value' reset corrupted radio groups by wiping child values.
|
|
162
|
+
* Like a native control the field also looks untouched again: the
|
|
163
|
+
* validation message it showed is gone (an `error` the author set stays)
|
|
164
|
+
* and a blur shows nothing until the user edits it.
|
|
160
165
|
*/
|
|
161
166
|
formResetCallback(): void;
|
|
162
167
|
/**
|
package/lib/base/ty-component.js
CHANGED
|
@@ -1,18 +1,47 @@
|
|
|
1
1
|
import { PropertyManager } from '../utils/property-manager.js';
|
|
2
2
|
import { ValidityController } from '../utils/validity.js';
|
|
3
|
+
import { upgradeProperties } from '../utils/upgrade-properties.js';
|
|
4
|
+
export { upgradeProperties };
|
|
5
|
+
const labelClickHosts = new WeakSet();
|
|
6
|
+
const directClicks = new WeakMap();
|
|
7
|
+
let labelForwardsWatched = false;
|
|
8
|
+
function watchLabelForwards() {
|
|
9
|
+
if (labelForwardsWatched)
|
|
10
|
+
return;
|
|
11
|
+
labelForwardsWatched = true;
|
|
12
|
+
window.addEventListener('click', (e) => {
|
|
13
|
+
const path = e.composedPath();
|
|
14
|
+
const host = path.find((n) => labelClickHosts.has(n));
|
|
15
|
+
if (!host)
|
|
16
|
+
return;
|
|
17
|
+
const at = `${e.clientX},${e.clientY}`;
|
|
18
|
+
if (path[0] !== host) {
|
|
19
|
+
directClicks.set(host, at);
|
|
20
|
+
setTimeout(() => { if (directClicks.get(host) === at)
|
|
21
|
+
directClicks.delete(host); });
|
|
22
|
+
}
|
|
23
|
+
else if (directClicks.get(host) === at) {
|
|
24
|
+
e.stopImmediatePropagation();
|
|
25
|
+
}
|
|
26
|
+
}, true);
|
|
27
|
+
}
|
|
3
28
|
export class TyComponent extends HTMLElement {
|
|
4
29
|
constructor() {
|
|
5
30
|
super();
|
|
6
31
|
this._connected = false;
|
|
7
32
|
this._rendered = false;
|
|
8
|
-
this.
|
|
33
|
+
this._userEdited = false;
|
|
9
34
|
this._resetDefaults = null;
|
|
10
35
|
const ctor = this.constructor;
|
|
11
36
|
this.props = new PropertyManager(ctor.properties);
|
|
12
37
|
this._internals = this.attachInternals();
|
|
13
38
|
this._validity = new ValidityController(this, this._internals);
|
|
14
39
|
if (!this.shadowRoot) {
|
|
15
|
-
this.attachShadow({ mode: 'open' });
|
|
40
|
+
this.attachShadow({ mode: 'open', delegatesFocus: ctor.delegatesFocus });
|
|
41
|
+
}
|
|
42
|
+
if (ctor.labelClicks) {
|
|
43
|
+
labelClickHosts.add(this);
|
|
44
|
+
watchLabelForwards();
|
|
16
45
|
}
|
|
17
46
|
}
|
|
18
47
|
static get observedAttributes() {
|
|
@@ -81,7 +110,6 @@ this._handlePropertyChanges([change]);
|
|
|
81
110
|
}
|
|
82
111
|
}
|
|
83
112
|
connectedCallback() {
|
|
84
|
-
this._connected = true;
|
|
85
113
|
if (!this._resetDefaults) {
|
|
86
114
|
this._resetDefaults = new Map();
|
|
87
115
|
const ctor = this.constructor;
|
|
@@ -92,10 +120,10 @@ const attr = this.getAttribute(this._toKebabCase(name));
|
|
|
92
120
|
this._resetDefaults.set(name, attr ?? (typeof config.default === 'function' ? config.default() : config.default) ?? null);
|
|
93
121
|
}
|
|
94
122
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.
|
|
98
|
-
|
|
123
|
+
this._upgradeProperties();
|
|
124
|
+
this._connected = true;
|
|
125
|
+
if (this._validates)
|
|
126
|
+
this._validity.track();
|
|
99
127
|
this.onConnect();
|
|
100
128
|
if (!this._rendered) {
|
|
101
129
|
this.render();
|
|
@@ -104,21 +132,28 @@ this._rendered = true;
|
|
|
104
132
|
}
|
|
105
133
|
disconnectedCallback() {
|
|
106
134
|
this._connected = false;
|
|
135
|
+
if (this._validates)
|
|
136
|
+
this._validity.track();
|
|
107
137
|
this.onDisconnect();
|
|
108
138
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
for (const propName of Object.keys(ctor.properties)) {
|
|
113
|
-
const descriptor = Object.getOwnPropertyDescriptor(this, propName);
|
|
114
|
-
if (descriptor && descriptor.value !== undefined) {
|
|
115
|
-
const change = this.props.updateProperty(propName, descriptor.value, 'property');
|
|
116
|
-
if (change) {
|
|
117
|
-
changes.push(change);
|
|
118
|
-
}
|
|
139
|
+
formAssociatedCallback() {
|
|
140
|
+
if (this._validates)
|
|
141
|
+
this._validity.track();
|
|
119
142
|
}
|
|
143
|
+
_upgradeProperties() {
|
|
144
|
+
for (const name of Object.keys(this.constructor.properties)) {
|
|
145
|
+
if (!Object.prototype.hasOwnProperty.call(this, name))
|
|
146
|
+
continue;
|
|
147
|
+
const value = this[name];
|
|
148
|
+
delete this[name];
|
|
149
|
+
if (value === undefined)
|
|
150
|
+
continue;
|
|
151
|
+
if (name in this)
|
|
152
|
+
this[name] = value;
|
|
153
|
+
else
|
|
154
|
+
this.setProperty(name, value);
|
|
120
155
|
}
|
|
121
|
-
|
|
156
|
+
upgradeProperties(this);
|
|
122
157
|
}
|
|
123
158
|
_handlePropertyChanges(changes) {
|
|
124
159
|
if (changes.length === 0)
|
|
@@ -212,14 +247,10 @@ roleEl.setAttribute('aria-label', text);
|
|
|
212
247
|
else
|
|
213
248
|
roleEl.removeAttribute('aria-label');
|
|
214
249
|
}
|
|
215
|
-
isDuplicateActivationClick() {
|
|
216
|
-
if (this._handlingActivationClick)
|
|
217
|
-
return true;
|
|
218
|
-
this._handlingActivationClick = true;
|
|
219
|
-
queueMicrotask(() => { this._handlingActivationClick = false; });
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
250
|
formResetCallback() {
|
|
251
|
+
this._userEdited = false;
|
|
252
|
+
if (this._validates)
|
|
253
|
+
this._validity.reset();
|
|
223
254
|
for (const [name, def] of this._resetDefaults ?? []) {
|
|
224
255
|
this.setProperty(name, def);
|
|
225
256
|
}
|
|
@@ -230,3 +261,5 @@ onFormReset() {
|
|
|
230
261
|
}
|
|
231
262
|
TyComponent.formAssociated = true;
|
|
232
263
|
TyComponent.properties = {};
|
|
264
|
+
TyComponent.delegatesFocus = false;
|
|
265
|
+
TyComponent.labelClicks = false;
|
|
@@ -89,11 +89,25 @@ export declare class TyButton extends TyComponent<ButtonState> implements TyButt
|
|
|
89
89
|
};
|
|
90
90
|
};
|
|
91
91
|
private _structureInitialized;
|
|
92
|
+
private _formDisabled;
|
|
92
93
|
private _customFlavorSheet;
|
|
94
|
+
private _ownClick;
|
|
93
95
|
constructor();
|
|
96
|
+
/**
|
|
97
|
+
* A real press inside the host's content box that missed the button: the
|
|
98
|
+
* empty host below a wide button that a min-height made taller, or around
|
|
99
|
+
* one a page's display: flex stretched. Nothing there looks like the
|
|
100
|
+
* button, so it's no press. Host padding and border are outside the
|
|
101
|
+
* content box.
|
|
102
|
+
*/
|
|
103
|
+
private _pressOffButton;
|
|
94
104
|
protected onConnect(): void;
|
|
95
105
|
protected onDisconnect(): void;
|
|
96
106
|
protected onPropertiesChanged(changes: PropertyChange[]): void;
|
|
107
|
+
formDisabledCallback(disabled: boolean): void;
|
|
108
|
+
private get _isDisabled();
|
|
109
|
+
/** Focus the inner <button>. The host itself isn't focusable. */
|
|
110
|
+
focus(options?: FocusOptions): void;
|
|
97
111
|
/**
|
|
98
112
|
* Custom flavors: adopt generated per-flavor rules pointed at the user's
|
|
99
113
|
* design tokens (--ty-solid-X / --ty-color-X / --ty-bg-X), falling back to
|
package/lib/components/button.js
CHANGED
|
@@ -4,12 +4,37 @@ import { ensureStyles, buildClassList } from "../utils/styles.js";
|
|
|
4
4
|
import { buttonStyles, buttonCustomFlavorCss } from "../styles/button.js";
|
|
5
5
|
import { syncCustomFlavorSheet } from "../utils/flavor-sheet.js";
|
|
6
6
|
import { getLoaderSvg } from "../utils/loader-registry.js";
|
|
7
|
+
import { asSubmitAttempt } from "../utils/validity.js";
|
|
7
8
|
export class TyButton extends TyComponent {
|
|
8
9
|
constructor() {
|
|
9
10
|
super();
|
|
10
11
|
this._structureInitialized = false;
|
|
12
|
+
this._formDisabled = false;
|
|
11
13
|
this._customFlavorSheet = null;
|
|
14
|
+
this._ownClick = null;
|
|
12
15
|
ensureStyles(this.shadowRoot, { css: buttonStyles, id: "ty-button" });
|
|
16
|
+
this.addEventListener("click", (e) => {
|
|
17
|
+
const button = this.shadowRoot.querySelector("button");
|
|
18
|
+
if (!button || e === this._ownClick)
|
|
19
|
+
return;
|
|
20
|
+
if (e.composedPath().includes(button))
|
|
21
|
+
return;
|
|
22
|
+
e.stopImmediatePropagation();
|
|
23
|
+
if (!this._pressOffButton(e))
|
|
24
|
+
button.click();
|
|
25
|
+
}, true);
|
|
26
|
+
}
|
|
27
|
+
_pressOffButton(e) {
|
|
28
|
+
if (!e.isTrusted || !(e instanceof MouseEvent))
|
|
29
|
+
return false;
|
|
30
|
+
const r = this.getBoundingClientRect();
|
|
31
|
+
const s = getComputedStyle(this);
|
|
32
|
+
const px = (p) => parseFloat(s.getPropertyValue(p)) || 0;
|
|
33
|
+
const left = r.left + px("border-left-width") + px("padding-left");
|
|
34
|
+
const right = r.right - px("border-right-width") - px("padding-right");
|
|
35
|
+
const top = r.top + px("border-top-width") + px("padding-top");
|
|
36
|
+
const bottom = r.bottom - px("border-bottom-width") - px("padding-bottom");
|
|
37
|
+
return e.clientX >= left && e.clientX < right && e.clientY >= top && e.clientY < bottom;
|
|
13
38
|
}
|
|
14
39
|
onConnect() {
|
|
15
40
|
this._syncCustomFlavor();
|
|
@@ -20,6 +45,21 @@ if (changes.some((c) => c.name === "flavor")) {
|
|
|
20
45
|
this._syncCustomFlavor();
|
|
21
46
|
}
|
|
22
47
|
}
|
|
48
|
+
formDisabledCallback(disabled) {
|
|
49
|
+
this._formDisabled = disabled;
|
|
50
|
+
if (this._structureInitialized)
|
|
51
|
+
this.render();
|
|
52
|
+
}
|
|
53
|
+
get _isDisabled() {
|
|
54
|
+
return this.disabled || this._formDisabled;
|
|
55
|
+
}
|
|
56
|
+
focus(options) {
|
|
57
|
+
const button = this.shadowRoot?.querySelector("button");
|
|
58
|
+
if (button)
|
|
59
|
+
button.focus(options);
|
|
60
|
+
else
|
|
61
|
+
super.focus(options);
|
|
62
|
+
}
|
|
23
63
|
_syncCustomFlavor() {
|
|
24
64
|
const { base } = this.parseFlavor();
|
|
25
65
|
this._customFlavorSheet = syncCustomFlavorSheet(this.shadowRoot, this._customFlavorSheet, base, () => buttonCustomFlavorCss(base));
|
|
@@ -118,7 +158,7 @@ if (this.name && this.value) {
|
|
|
118
158
|
this._internals.setFormValue(this.value);
|
|
119
159
|
}
|
|
120
160
|
try {
|
|
121
|
-
form.requestSubmit();
|
|
161
|
+
asSubmitAttempt(() => form.requestSubmit());
|
|
122
162
|
}
|
|
123
163
|
finally {
|
|
124
164
|
if (this.name && this.value)
|
|
@@ -136,7 +176,7 @@ initializeButtonStructure() {
|
|
|
136
176
|
const shadow = this.shadowRoot;
|
|
137
177
|
const classes = this.buildClasses();
|
|
138
178
|
const button = document.createElement("button");
|
|
139
|
-
button.disabled = this.
|
|
179
|
+
button.disabled = this._isDisabled;
|
|
140
180
|
button.className = classes;
|
|
141
181
|
button.setAttribute("part", "button");
|
|
142
182
|
const loader = document.createElement("span");
|
|
@@ -155,15 +195,21 @@ button.appendChild(startSlot);
|
|
|
155
195
|
button.appendChild(defaultSlot);
|
|
156
196
|
button.appendChild(endSlot);
|
|
157
197
|
button.addEventListener("click", (e) => {
|
|
158
|
-
|
|
198
|
+
const path = e.composedPath();
|
|
199
|
+
if (path.slice(0, path.indexOf(button)).some((n) => n instanceof Element && n.localName === "ty-popup"))
|
|
159
200
|
return;
|
|
160
201
|
e.stopPropagation();
|
|
161
|
-
this.
|
|
162
|
-
|
|
202
|
+
if (this._isDisabled || this.loading)
|
|
203
|
+
return;
|
|
204
|
+
const click = new CustomEvent("click", {
|
|
163
205
|
bubbles: true,
|
|
164
206
|
composed: true,
|
|
207
|
+
cancelable: true,
|
|
165
208
|
detail: { originalEvent: e },
|
|
166
|
-
})
|
|
209
|
+
});
|
|
210
|
+
this._ownClick = click;
|
|
211
|
+
if (this.dispatchEvent(click))
|
|
212
|
+
this.handleFormAction();
|
|
167
213
|
});
|
|
168
214
|
this.applyLoadingState(button);
|
|
169
215
|
shadow.appendChild(button);
|
|
@@ -174,12 +220,14 @@ const isLoading = this.loading;
|
|
|
174
220
|
button.classList.toggle("loading", isLoading);
|
|
175
221
|
if (isLoading) {
|
|
176
222
|
button.setAttribute("aria-busy", "true");
|
|
223
|
+
button.setAttribute("aria-disabled", "true");
|
|
177
224
|
const loader = button.querySelector(".loader-icon");
|
|
178
225
|
if (loader)
|
|
179
226
|
loader.innerHTML = getLoaderSvg();
|
|
180
227
|
}
|
|
181
228
|
else {
|
|
182
229
|
button.removeAttribute("aria-busy");
|
|
230
|
+
button.removeAttribute("aria-disabled");
|
|
183
231
|
}
|
|
184
232
|
}
|
|
185
233
|
render() {
|
|
@@ -191,7 +239,7 @@ return;
|
|
|
191
239
|
const classes = this.buildClasses();
|
|
192
240
|
const button = shadow.querySelector("button");
|
|
193
241
|
if (button) {
|
|
194
|
-
button.disabled = this.
|
|
242
|
+
button.disabled = this._isDisabled;
|
|
195
243
|
button.className = classes;
|
|
196
244
|
this.applyLoadingState(button);
|
|
197
245
|
}
|
|
@@ -32,7 +32,7 @@ export interface DayClickDetail {
|
|
|
32
32
|
export declare class TyCalendarMonth extends HTMLElement {
|
|
33
33
|
private _displayYear;
|
|
34
34
|
private _displayMonth;
|
|
35
|
-
private _locale
|
|
35
|
+
private _locale?;
|
|
36
36
|
private _size;
|
|
37
37
|
private _width?;
|
|
38
38
|
private _minWidth?;
|
|
@@ -97,6 +97,12 @@ export declare class TyCalendarMonth extends HTMLElement {
|
|
|
97
97
|
* Useful when external data changes (e.g., async event loading)
|
|
98
98
|
*/
|
|
99
99
|
refresh(): void;
|
|
100
|
+
/**
|
|
101
|
+
* A day was picked (click, Enter, Space): it becomes the grid's tab stop and
|
|
102
|
+
* takes the focus, which render() keeps on it when the pick re-renders the
|
|
103
|
+
* grid. Then the events go out.
|
|
104
|
+
*/
|
|
105
|
+
private pickDay;
|
|
100
106
|
private dispatchDayClick;
|
|
101
107
|
/**
|
|
102
108
|
* WAI-ARIA grid pattern: gridcell + roving tabindex (exactly one cell in
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ensureStyles } from '../utils/styles.js';
|
|
2
|
+
import { liftProperties, upgradeProperties } from '../utils/upgrade-properties.js';
|
|
2
3
|
import { syncCustomFlavorSheet } from '../utils/flavor-sheet.js';
|
|
3
4
|
import { calendarMonthStyles, calendarMonthCustomFlavorCss } from '../styles/calendar-month.js';
|
|
4
|
-
import { getCalendarMonthDays, getLocalizedWeekdays,
|
|
5
|
+
import { getCalendarMonthDays, getLocalizedWeekdays, localMidnight, parseDateDay, utcMidnight } from '../utils/calendar-utils.js';
|
|
5
6
|
import { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';
|
|
6
7
|
function defaultDayContent(dayContext) {
|
|
7
8
|
return dayContext.dayInMonth.toString();
|
|
@@ -24,10 +25,10 @@ return value instanceof HTMLElement;
|
|
|
24
25
|
function isoToUTCTimestamp(iso) {
|
|
25
26
|
if (!iso)
|
|
26
27
|
return null;
|
|
27
|
-
const parsed =
|
|
28
|
+
const parsed = parseDateDay(iso);
|
|
28
29
|
if (!parsed)
|
|
29
30
|
return null;
|
|
30
|
-
return
|
|
31
|
+
return utcMidnight(parsed.year, parsed.month, parsed.day);
|
|
31
32
|
}
|
|
32
33
|
function normalizeSizeValue(value) {
|
|
33
34
|
if (!value || value === '')
|
|
@@ -44,7 +45,6 @@ return ['display-year', 'display-month', 'locale', 'size', 'min', 'max', 'flavor
|
|
|
44
45
|
}
|
|
45
46
|
constructor() {
|
|
46
47
|
super();
|
|
47
|
-
this._locale = 'en-US';
|
|
48
48
|
this._size = 'md';
|
|
49
49
|
this._customFlavorSheet = null;
|
|
50
50
|
this._focusedIndex = null;
|
|
@@ -53,6 +53,7 @@ const today = new Date();
|
|
|
53
53
|
this._displayYear = today.getFullYear();
|
|
54
54
|
this._displayMonth = today.getMonth() + 1;
|
|
55
55
|
this.attachShadow({ mode: 'open' });
|
|
56
|
+
liftProperties(this);
|
|
56
57
|
}
|
|
57
58
|
connectedCallback() {
|
|
58
59
|
if (!this._displayMonth) {
|
|
@@ -62,23 +63,15 @@ if (!this._displayYear) {
|
|
|
62
63
|
this._displayYear = new Date().getFullYear();
|
|
63
64
|
}
|
|
64
65
|
if (!this._locale) {
|
|
65
|
-
this._locale = this.getAttribute('locale') ||
|
|
66
|
+
this._locale = this.getAttribute('locale') || undefined;
|
|
66
67
|
}
|
|
67
68
|
const sizeAttr = this.getAttribute('size');
|
|
68
69
|
if (sizeAttr && (sizeAttr === 'sm' || sizeAttr === 'md' || sizeAttr === 'lg')) {
|
|
69
70
|
this._size = sizeAttr;
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
-
if (plainDayContentFn && !this._dayContentFn) {
|
|
73
|
-
this._dayContentFn = plainDayContentFn;
|
|
74
|
-
delete this.dayContentFn;
|
|
75
|
-
}
|
|
76
|
-
const plainCustomCSS = this.customCSS;
|
|
77
|
-
if (plainCustomCSS && !this._customCSS) {
|
|
78
|
-
this._customCSS = plainCustomCSS;
|
|
79
|
-
delete this.customCSS;
|
|
80
|
-
}
|
|
72
|
+
upgradeProperties(this);
|
|
81
73
|
this._localeObserver = observeLocaleChanges(this, () => {
|
|
74
|
+
if (!this._locale)
|
|
82
75
|
this.render();
|
|
83
76
|
});
|
|
84
77
|
this._syncCustomFlavor();
|
|
@@ -102,7 +95,7 @@ this.displayMonth = n;
|
|
|
102
95
|
}
|
|
103
96
|
}
|
|
104
97
|
else if (name === 'locale') {
|
|
105
|
-
this._locale = newValue ||
|
|
98
|
+
this._locale = newValue || undefined;
|
|
106
99
|
this.render();
|
|
107
100
|
}
|
|
108
101
|
else if (name === 'size') {
|
|
@@ -143,11 +136,11 @@ this.render();
|
|
|
143
136
|
}
|
|
144
137
|
}
|
|
145
138
|
get locale() {
|
|
146
|
-
return getEffectiveLocale(this, this.
|
|
139
|
+
return getEffectiveLocale(this, this._locale);
|
|
147
140
|
}
|
|
148
141
|
set locale(value) {
|
|
149
142
|
if (this._locale !== value) {
|
|
150
|
-
this._locale = value;
|
|
143
|
+
this._locale = value || undefined;
|
|
151
144
|
this.render();
|
|
152
145
|
}
|
|
153
146
|
}
|
|
@@ -239,6 +232,7 @@ set value(timestamp) {
|
|
|
239
232
|
const newValue = timestamp ?? undefined;
|
|
240
233
|
if (this._value !== newValue) {
|
|
241
234
|
this._value = newValue;
|
|
235
|
+
this._focusedIndex = null;
|
|
242
236
|
this.render();
|
|
243
237
|
}
|
|
244
238
|
}
|
|
@@ -276,6 +270,15 @@ this.shadowRoot.adoptedStyleSheets = [...existing, this._customCSS];
|
|
|
276
270
|
refresh() {
|
|
277
271
|
this.render();
|
|
278
272
|
}
|
|
273
|
+
pickDay(cell, dayContext, domEvent) {
|
|
274
|
+
const index = this._cellElements.indexOf(cell);
|
|
275
|
+
if (index !== -1) {
|
|
276
|
+
this._cellElements.forEach((c) => c.setAttribute('tabindex', c === cell ? '0' : '-1'));
|
|
277
|
+
this._focusedIndex = index;
|
|
278
|
+
cell.focus({ preventScroll: true });
|
|
279
|
+
}
|
|
280
|
+
this.dispatchDayClick(dayContext, domEvent);
|
|
281
|
+
}
|
|
279
282
|
dispatchDayClick(dayContext, _domEvent) {
|
|
280
283
|
const detail = {
|
|
281
284
|
dayContext,
|
|
@@ -297,7 +300,7 @@ cancelable: true,
|
|
|
297
300
|
this.dispatchEvent(event);
|
|
298
301
|
}
|
|
299
302
|
}
|
|
300
|
-
renderDayCell(dayContext, disabled, isRoving) {
|
|
303
|
+
renderDayCell(dayContext, disabled, isRoving, label) {
|
|
301
304
|
const dayElement = document.createElement('div');
|
|
302
305
|
const content = this._dayContentFn
|
|
303
306
|
? this._dayContentFn(dayContext)
|
|
@@ -319,8 +322,7 @@ else if (isDOMElement(content)) {
|
|
|
319
322
|
dayElement.appendChild(content);
|
|
320
323
|
}
|
|
321
324
|
dayElement.setAttribute('role', 'gridcell');
|
|
322
|
-
dayElement.setAttribute('aria-label', new
|
|
323
|
-
.format(new Date(dayContext.localValue)));
|
|
325
|
+
dayElement.setAttribute('aria-label', label.format(new Date(dayContext.localValue)));
|
|
324
326
|
dayElement.setAttribute('aria-selected', String(!!dayContext.isSelected));
|
|
325
327
|
if (dayContext.today)
|
|
326
328
|
dayElement.setAttribute('aria-current', 'date');
|
|
@@ -331,13 +333,13 @@ dayElement.setAttribute('tabindex', '-1');
|
|
|
331
333
|
else {
|
|
332
334
|
dayElement.setAttribute('tabindex', isRoving ? '0' : '-1');
|
|
333
335
|
dayElement.addEventListener('click', (event) => {
|
|
334
|
-
this.
|
|
336
|
+
this.pickDay(dayElement, dayContext, event);
|
|
335
337
|
});
|
|
336
338
|
dayElement.addEventListener('keydown', (event) => {
|
|
337
339
|
const ke = event;
|
|
338
340
|
if (ke.key === 'Enter' || ke.key === ' ') {
|
|
339
341
|
ke.preventDefault();
|
|
340
|
-
this.
|
|
342
|
+
this.pickDay(dayElement, dayContext, event);
|
|
341
343
|
}
|
|
342
344
|
});
|
|
343
345
|
}
|
|
@@ -351,7 +353,7 @@ ensureStyles(root, { css: calendarMonthStyles, id: 'ty-calendar-month' });
|
|
|
351
353
|
this.applyCustomCSS();
|
|
352
354
|
this.applyWidthProperties();
|
|
353
355
|
let selection;
|
|
354
|
-
if (this._value) {
|
|
356
|
+
if (this._value !== undefined) {
|
|
355
357
|
const date = new Date(this._value);
|
|
356
358
|
selection = {
|
|
357
359
|
year: date.getFullYear(),
|
|
@@ -360,13 +362,16 @@ day: date.getDate()
|
|
|
360
362
|
};
|
|
361
363
|
}
|
|
362
364
|
const days = getCalendarMonthDays(this._displayYear, this._displayMonth, selection);
|
|
363
|
-
const
|
|
365
|
+
const locale = this.locale;
|
|
366
|
+
const weekdays = getLocalizedWeekdays(locale, 'short');
|
|
367
|
+
const dayLabel = new Intl.DateTimeFormat(locale, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
|
368
|
+
const hadFocus = !!root.activeElement;
|
|
364
369
|
root.innerHTML = '';
|
|
365
370
|
const calendarContainer = document.createElement('div');
|
|
366
371
|
calendarContainer.className = `calendar-flex-container calendar-size-${this._size}`;
|
|
367
372
|
calendarContainer.setAttribute('role', 'grid');
|
|
368
|
-
calendarContainer.setAttribute('aria-label', new Intl.DateTimeFormat(
|
|
369
|
-
.format(
|
|
373
|
+
calendarContainer.setAttribute('aria-label', new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' })
|
|
374
|
+
.format(localMidnight(this._displayYear, this._displayMonth, 1)));
|
|
370
375
|
const headerRow = document.createElement('div');
|
|
371
376
|
headerRow.className = 'calendar-row calendar-header-row';
|
|
372
377
|
headerRow.setAttribute('role', 'row');
|
|
@@ -421,7 +426,7 @@ dayRow.setAttribute('role', 'row');
|
|
|
421
426
|
week.forEach(dayContext => {
|
|
422
427
|
const disabled = (minTs !== null && dayContext.value < minTs) ||
|
|
423
428
|
(maxTs !== null && dayContext.value > maxTs);
|
|
424
|
-
const dayCell = this.renderDayCell(dayContext, disabled, flatIndex === effectiveFocusedIndex);
|
|
429
|
+
const dayCell = this.renderDayCell(dayContext, disabled, flatIndex === effectiveFocusedIndex, dayLabel);
|
|
425
430
|
dayCell.className = `${dayCell.className} calendar-cell calendar-day-cell`;
|
|
426
431
|
dayRow.appendChild(dayCell);
|
|
427
432
|
this._cellElements[flatIndex] = dayCell;
|
|
@@ -452,6 +457,8 @@ nextCell.focus();
|
|
|
452
457
|
}
|
|
453
458
|
});
|
|
454
459
|
root.appendChild(calendarContainer);
|
|
460
|
+
if (hadFocus)
|
|
461
|
+
this._cellElements[effectiveFocusedIndex]?.focus({ preventScroll: true });
|
|
455
462
|
}
|
|
456
463
|
}
|
|
457
464
|
if (!customElements.get('ty-calendar-month')) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ensureStyles } from '../utils/styles.js';
|
|
2
2
|
import { calendarNavigationStyles } from '../styles/calendar-navigation.js';
|
|
3
|
-
import { getMonthName,
|
|
3
|
+
import { getMonthName, parseDateDay } from '../utils/calendar-utils.js';
|
|
4
4
|
import { getEffectiveLocale, observeLocaleChanges } from '../utils/locale.js';
|
|
5
5
|
import { TyComponent } from '../base/ty-component.js';
|
|
6
6
|
const CHEVRON_LEFT_SVG = `<?xml version='1.0' encoding='UTF-8'?>
|
|
@@ -31,6 +31,7 @@ onConnect() {
|
|
|
31
31
|
this._state.displayMonth = this.displayMonth;
|
|
32
32
|
this._state.displayYear = this.displayYear;
|
|
33
33
|
this._localeObserver = observeLocaleChanges(this, () => {
|
|
34
|
+
if (!this.getProperty('locale'))
|
|
34
35
|
this.render();
|
|
35
36
|
});
|
|
36
37
|
this.render();
|
|
@@ -122,8 +123,8 @@ static monthIndex(year, month) {
|
|
|
122
123
|
return year * 12 + (month - 1);
|
|
123
124
|
}
|
|
124
125
|
boundIndices() {
|
|
125
|
-
const min =
|
|
126
|
-
const max =
|
|
126
|
+
const min = parseDateDay(this.min);
|
|
127
|
+
const max = parseDateDay(this.max);
|
|
127
128
|
return {
|
|
128
129
|
minIdx: min ? TyCalendarNavigation.monthIndex(min.year, min.month) : null,
|
|
129
130
|
maxIdx: max ? TyCalendarNavigation.monthIndex(max.year, max.month) : null,
|
|
@@ -175,6 +176,12 @@ this.style.removeProperty('--nav-width');
|
|
|
175
176
|
}
|
|
176
177
|
const months = this.view === 'months';
|
|
177
178
|
const monthName = getMonthName(this._state.displayMonth, this.locale, 'long');
|
|
179
|
+
const had = root.activeElement;
|
|
180
|
+
const place = !had ? null
|
|
181
|
+
: had.classList.contains('nav-title') ? 'title'
|
|
182
|
+
: had.className.includes('-prev') ? 'prev'
|
|
183
|
+
: had.className.includes('-next') ? 'next'
|
|
184
|
+
: null;
|
|
178
185
|
root.innerHTML = '';
|
|
179
186
|
const header = document.createElement('div');
|
|
180
187
|
header.className = 'calendar-navigation-header';
|
|
@@ -206,11 +213,17 @@ const step = months ? 12 : 1;
|
|
|
206
213
|
const unit = months ? 'year' : 'month';
|
|
207
214
|
const arrows = document.createElement('div');
|
|
208
215
|
arrows.className = 'nav-group nav-arrows';
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
const prev = this.createButton(`nav-btn nav-${unit}-prev`, `Previous ${unit}`, CHEVRON_LEFT_SVG, () => this.navigateBy(-step), this.isNavDisabled(-step));
|
|
217
|
+
const next = this.createButton(`nav-btn nav-${unit}-next`, `Next ${unit}`, CHEVRON_RIGHT_SVG, () => this.navigateBy(step), this.isNavDisabled(step));
|
|
218
|
+
arrows.appendChild(prev);
|
|
219
|
+
arrows.appendChild(next);
|
|
211
220
|
header.appendChild(title);
|
|
212
221
|
header.appendChild(arrows);
|
|
213
222
|
root.appendChild(header);
|
|
223
|
+
if (place) {
|
|
224
|
+
const successor = place === 'prev' ? prev : place === 'next' ? next : title;
|
|
225
|
+
(successor.disabled ? title : successor).focus({ preventScroll: true });
|
|
226
|
+
}
|
|
214
227
|
}
|
|
215
228
|
}
|
|
216
229
|
TyCalendarNavigation.properties = {
|
|
@@ -251,7 +264,7 @@ return num;
|
|
|
251
264
|
locale: {
|
|
252
265
|
type: 'string',
|
|
253
266
|
visual: true,
|
|
254
|
-
default: '
|
|
267
|
+
default: ''
|
|
255
268
|
},
|
|
256
269
|
size: {
|
|
257
270
|
type: 'string',
|