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
package/lib/components/switch.js
CHANGED
|
@@ -3,6 +3,7 @@ import { TyComponent } from "../base/ty-component.js";
|
|
|
3
3
|
import { ensureStyles } from "../utils/styles.js";
|
|
4
4
|
import { syncCustomFlavorSheet } from "../utils/flavor-sheet.js";
|
|
5
5
|
import { switchStyles, switchCustomFlavorCss } from "../styles/switch.js";
|
|
6
|
+
import { nativeMessage } from "../utils/validity.js";
|
|
6
7
|
export class TySwitch extends TyComponent {
|
|
7
8
|
constructor() {
|
|
8
9
|
super();
|
|
@@ -18,6 +19,9 @@ ensureStyles(shadow, { css: switchStyles, id: "ty-switch" });
|
|
|
18
19
|
onConnect() {
|
|
19
20
|
this.setupEventListeners();
|
|
20
21
|
this._syncCustomFlavor();
|
|
22
|
+
const el = this.shadowRoot.querySelector(".switch-container");
|
|
23
|
+
if (el && this.shadowRoot.activeElement !== el)
|
|
24
|
+
el.classList.remove("focused");
|
|
21
25
|
}
|
|
22
26
|
onDisconnect() {
|
|
23
27
|
this.removeEventListeners();
|
|
@@ -44,8 +48,7 @@ return classes.join(" ");
|
|
|
44
48
|
handleSwitchClick(e) {
|
|
45
49
|
if (this.disabled)
|
|
46
50
|
return;
|
|
47
|
-
|
|
48
|
-
return;
|
|
51
|
+
this.showFocusRing(e instanceof KeyboardEvent);
|
|
49
52
|
const newValue = !this.checked;
|
|
50
53
|
this.checked = newValue;
|
|
51
54
|
setTimeout(() => {
|
|
@@ -59,6 +62,9 @@ this.dispatchEvent(new CustomEvent("input", { detail: eventDetail, bubbles: true
|
|
|
59
62
|
this.dispatchEvent(new CustomEvent("change", { detail: eventDetail, bubbles: true, composed: true }));
|
|
60
63
|
}, 0);
|
|
61
64
|
}
|
|
65
|
+
showFocusRing(on) {
|
|
66
|
+
this.shadowRoot?.querySelector(".switch-container")?.classList.toggle("focused", on);
|
|
67
|
+
}
|
|
62
68
|
handleSwitchKeydown(e) {
|
|
63
69
|
if (this.disabled)
|
|
64
70
|
return;
|
|
@@ -106,7 +112,7 @@ if (!el)
|
|
|
106
112
|
return;
|
|
107
113
|
this._clickHandler = (e) => this.handleSwitchClick(e);
|
|
108
114
|
this._keydownHandler = (e) => this.handleSwitchKeydown(e);
|
|
109
|
-
this._focusHandler = () => el.classList.
|
|
115
|
+
this._focusHandler = () => el.classList.toggle("focused", el.matches(":focus-visible"));
|
|
110
116
|
this._blurHandler = () => el.classList.remove("focused");
|
|
111
117
|
this.addEventListener("click", this._clickHandler);
|
|
112
118
|
el.addEventListener("keydown", this._keydownHandler);
|
|
@@ -121,7 +127,8 @@ const classes = this.buildClassList();
|
|
|
121
127
|
if (!switchEl) {
|
|
122
128
|
switchEl = document.createElement("div");
|
|
123
129
|
switchEl.className = "switch-container " + classes;
|
|
124
|
-
|
|
130
|
+
if (!this.disabled)
|
|
131
|
+
switchEl.tabIndex = 0;
|
|
125
132
|
switchEl.setAttribute("role", "switch");
|
|
126
133
|
switchEl.setAttribute("aria-checked", this.checked ? "true" : "false");
|
|
127
134
|
switchEl.setAttribute("aria-disabled", this.disabled ? "true" : "false");
|
|
@@ -135,8 +142,13 @@ switchEl.appendChild(track);
|
|
|
135
142
|
shadow.appendChild(switchEl);
|
|
136
143
|
}
|
|
137
144
|
else {
|
|
145
|
+
const focused = switchEl.classList.contains("focused") && shadow.activeElement === switchEl;
|
|
138
146
|
switchEl.className = "switch-container " + classes;
|
|
139
|
-
switchEl.
|
|
147
|
+
switchEl.classList.toggle("focused", focused && !this.disabled);
|
|
148
|
+
if (this.disabled)
|
|
149
|
+
switchEl.removeAttribute("tabindex");
|
|
150
|
+
else
|
|
151
|
+
switchEl.tabIndex = 0;
|
|
140
152
|
switchEl.setAttribute("aria-checked", this.checked ? "true" : "false");
|
|
141
153
|
switchEl.setAttribute("aria-disabled", this.disabled ? "true" : "false");
|
|
142
154
|
switchEl.setAttribute("aria-required", this.required ? "true" : "false");
|
|
@@ -159,7 +171,7 @@ this.applyValidity({});
|
|
|
159
171
|
return;
|
|
160
172
|
}
|
|
161
173
|
if (this.required && !this.checked) {
|
|
162
|
-
this.applyValidity({ valueMissing: true }, "
|
|
174
|
+
this.applyValidity({ valueMissing: true }, nativeMessage("input", { type: "checkbox", switch: true, required: true }), anchor ?? undefined);
|
|
163
175
|
}
|
|
164
176
|
else {
|
|
165
177
|
this.applyValidity({});
|
|
@@ -182,6 +194,8 @@ set flavor(value) { this.setProperty("flavor", value); }
|
|
|
182
194
|
get form() { return this._internals.form; }
|
|
183
195
|
}
|
|
184
196
|
TySwitch.formAssociated = true;
|
|
197
|
+
TySwitch.delegatesFocus = true;
|
|
198
|
+
TySwitch.labelClicks = true;
|
|
185
199
|
TySwitch.properties = {
|
|
186
200
|
checked: {
|
|
187
201
|
type: "boolean",
|
package/lib/components/tabs.js
CHANGED
|
@@ -251,7 +251,7 @@ marker.style.top = `${position.top}px`;
|
|
|
251
251
|
marker.style.width = `${position.width}px`;
|
|
252
252
|
marker.style.height = `${position.height}px`;
|
|
253
253
|
if (snap) {
|
|
254
|
-
marker.
|
|
254
|
+
marker.getBoundingClientRect();
|
|
255
255
|
marker.style.transition = '';
|
|
256
256
|
}
|
|
257
257
|
}
|
|
@@ -21,6 +21,10 @@ export interface TyTextareaElement extends HTMLElement {
|
|
|
21
21
|
label?: string;
|
|
22
22
|
disabled?: boolean;
|
|
23
23
|
required?: boolean;
|
|
24
|
+
minLength?: number;
|
|
25
|
+
maxLength?: number;
|
|
26
|
+
tooShortMessage?: string;
|
|
27
|
+
tooLongMessage?: string;
|
|
24
28
|
error?: string;
|
|
25
29
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
26
30
|
rows?: string | number;
|
|
@@ -63,6 +67,26 @@ export declare class TyTextarea extends TyComponent<TextareaState> implements Ty
|
|
|
63
67
|
visual: boolean;
|
|
64
68
|
default: boolean;
|
|
65
69
|
};
|
|
70
|
+
minlength: {
|
|
71
|
+
type: "string";
|
|
72
|
+
visual: boolean;
|
|
73
|
+
default: string;
|
|
74
|
+
};
|
|
75
|
+
maxlength: {
|
|
76
|
+
type: "string";
|
|
77
|
+
visual: boolean;
|
|
78
|
+
default: string;
|
|
79
|
+
};
|
|
80
|
+
tooShortMessage: {
|
|
81
|
+
type: "string";
|
|
82
|
+
visual: boolean;
|
|
83
|
+
default: string;
|
|
84
|
+
};
|
|
85
|
+
tooLongMessage: {
|
|
86
|
+
type: "string";
|
|
87
|
+
visual: boolean;
|
|
88
|
+
default: string;
|
|
89
|
+
};
|
|
66
90
|
error: {
|
|
67
91
|
type: "string";
|
|
68
92
|
visual: boolean;
|
|
@@ -129,6 +153,14 @@ export declare class TyTextarea extends TyComponent<TextareaState> implements Ty
|
|
|
129
153
|
focus(options?: FocusOptions): void;
|
|
130
154
|
get required(): boolean;
|
|
131
155
|
set required(v: boolean);
|
|
156
|
+
get minLength(): number;
|
|
157
|
+
set minLength(v: number);
|
|
158
|
+
get maxLength(): number;
|
|
159
|
+
set maxLength(v: number);
|
|
160
|
+
get tooShortMessage(): string;
|
|
161
|
+
set tooShortMessage(v: string);
|
|
162
|
+
get tooLongMessage(): string;
|
|
163
|
+
set tooLongMessage(v: string);
|
|
132
164
|
get error(): string;
|
|
133
165
|
set error(v: string);
|
|
134
166
|
get size(): 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
@@ -153,17 +185,26 @@ export declare class TyTextarea extends TyComponent<TextareaState> implements Ty
|
|
|
153
185
|
private _destroyScrollbar;
|
|
154
186
|
private emitValueEvent;
|
|
155
187
|
private handleInputEvent;
|
|
156
|
-
/** The user typed since the field was created: blur then shows its validation message. */
|
|
157
|
-
private _userEdited;
|
|
158
188
|
private _valueAtFocus;
|
|
159
189
|
private handleFocusEvent;
|
|
160
190
|
private handleBlurEvent;
|
|
161
191
|
private buildClassList;
|
|
162
192
|
private applyHeightConstraints;
|
|
163
193
|
private setupTextareaEvents;
|
|
194
|
+
private removeTextareaEvents;
|
|
164
195
|
protected render(): void;
|
|
165
|
-
/**
|
|
166
|
-
*
|
|
196
|
+
/**
|
|
197
|
+
* minlength goes on the inner <textarea> for the browser's own too-short
|
|
198
|
+
* message after the user types, maxlength so typing stops at the limit
|
|
199
|
+
* (like ty-input).
|
|
200
|
+
*/
|
|
201
|
+
private syncConstraintAttributes;
|
|
202
|
+
/**
|
|
203
|
+
* required + empty => valueMissing (the browser's own message); otherwise
|
|
204
|
+
* minlength / maxlength, worded like ty-input's (lengthValidity). Empty
|
|
205
|
+
* values only fail `required`, like native. Disabled fields are barred
|
|
206
|
+
* from constraint validation.
|
|
207
|
+
*/
|
|
167
208
|
private updateValidity;
|
|
168
209
|
}
|
|
169
210
|
export {};
|
|
@@ -4,7 +4,8 @@ import { ensureStyles } from '../utils/styles.js';
|
|
|
4
4
|
import { textareaStyles } from '../styles/textarea.js';
|
|
5
5
|
import { CustomScrollbar, isCustomScrollbarEnabled } from '../utils/custom-scrollbar.js';
|
|
6
6
|
import { customScrollbarStyles } from '../styles/custom-scrollbar.js';
|
|
7
|
-
|
|
7
|
+
import { nativeMessage, lengthValidity, toLimit } from '../utils/validity.js';
|
|
8
|
+
import { REQUIRED_ICON_SVG } from '../utils/icons.js';
|
|
8
9
|
export class TyTextarea extends TyComponent {
|
|
9
10
|
constructor() {
|
|
10
11
|
super();
|
|
@@ -14,6 +15,8 @@ this._scrollbar = null;
|
|
|
14
15
|
this._isFocused = false;
|
|
15
16
|
this.handleInputEvent = (e) => {
|
|
16
17
|
this._userEdited = true;
|
|
18
|
+
e.stopPropagation();
|
|
19
|
+
e.stopImmediatePropagation();
|
|
17
20
|
const target = e.target;
|
|
18
21
|
const newValue = target.value;
|
|
19
22
|
this.value = newValue;
|
|
@@ -24,7 +27,6 @@ this._internals.setFormValue(this.value || '');
|
|
|
24
27
|
this.updateValidity();
|
|
25
28
|
this.emitValueEvent('input', e);
|
|
26
29
|
};
|
|
27
|
-
this._userEdited = false;
|
|
28
30
|
this._valueAtFocus = null;
|
|
29
31
|
this.handleFocusEvent = () => {
|
|
30
32
|
this._isFocused = true;
|
|
@@ -46,20 +48,22 @@ ensureStyles(shadow, { css: customScrollbarStyles, id: 'ty-custom-scrollbar' });
|
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
onConnect() {
|
|
51
|
+
this.updateFormValue();
|
|
52
|
+
if (this._rendered) {
|
|
53
|
+
this.render();
|
|
54
|
+
if (this._textareaEl)
|
|
55
|
+
this.setupTextareaEvents(this._textareaEl);
|
|
56
|
+
}
|
|
49
57
|
}
|
|
50
58
|
onDisconnect() {
|
|
51
59
|
this._destroyScrollbar();
|
|
52
|
-
if (this._textareaEl)
|
|
53
|
-
|
|
54
|
-
this._textareaEl.parentNode?.replaceChild(newTextarea, this._textareaEl);
|
|
55
|
-
this._textareaEl = null;
|
|
56
|
-
}
|
|
57
|
-
this._dummyEl = null;
|
|
60
|
+
if (this._textareaEl)
|
|
61
|
+
this.removeTextareaEvents(this._textareaEl);
|
|
58
62
|
}
|
|
59
63
|
onPropertiesChanged(changes) {
|
|
60
64
|
}
|
|
61
65
|
getFormValue() {
|
|
62
|
-
return this.getProperty('value') ||
|
|
66
|
+
return this.getProperty('value') || '';
|
|
63
67
|
}
|
|
64
68
|
get value() { return this.getProperty('value'); }
|
|
65
69
|
set value(v) { this.setProperty('value', v); }
|
|
@@ -76,6 +80,14 @@ this.shadowRoot?.querySelector('textarea')?.focus(options);
|
|
|
76
80
|
}
|
|
77
81
|
get required() { return this.getProperty('required'); }
|
|
78
82
|
set required(v) { this.setProperty('required', v); }
|
|
83
|
+
get minLength() { return toLimit(this.getProperty('minlength')) ?? -1; }
|
|
84
|
+
set minLength(v) { this.setProperty('minlength', v == null || v < 0 ? '' : String(v)); }
|
|
85
|
+
get maxLength() { return toLimit(this.getProperty('maxlength')) ?? -1; }
|
|
86
|
+
set maxLength(v) { this.setProperty('maxlength', v == null || v < 0 ? '' : String(v)); }
|
|
87
|
+
get tooShortMessage() { return this.getProperty('tooShortMessage'); }
|
|
88
|
+
set tooShortMessage(v) { this.setProperty('tooShortMessage', v ?? ''); }
|
|
89
|
+
get tooLongMessage() { return this.getProperty('tooLongMessage'); }
|
|
90
|
+
set tooLongMessage(v) { this.setProperty('tooLongMessage', v ?? ''); }
|
|
79
91
|
get error() { return this.getProperty('error'); }
|
|
80
92
|
set error(v) { this.setProperty('error', v); }
|
|
81
93
|
get size() {
|
|
@@ -182,6 +194,10 @@ textareaEl.style.overflowY = 'hidden';
|
|
|
182
194
|
this._destroyScrollbar();
|
|
183
195
|
}
|
|
184
196
|
}
|
|
197
|
+
else if (maxHeight !== null && measuredHeight >= maxHeight && !this._scrollbar) {
|
|
198
|
+
textareaEl.style.overflowY = 'auto';
|
|
199
|
+
this._setupScrollbar(textareaEl);
|
|
200
|
+
}
|
|
185
201
|
this._scrollbar?.update();
|
|
186
202
|
}
|
|
187
203
|
_setupScrollbar(textareaEl) {
|
|
@@ -218,7 +234,7 @@ value: this.value,
|
|
|
218
234
|
originalEvent
|
|
219
235
|
}
|
|
220
236
|
};
|
|
221
|
-
|
|
237
|
+
this.dispatchEvent(new CustomEvent(type, data));
|
|
222
238
|
}
|
|
223
239
|
buildClassList() {
|
|
224
240
|
const classes = [this.size];
|
|
@@ -248,6 +264,11 @@ textareaEl.addEventListener('input', this.handleInputEvent);
|
|
|
248
264
|
textareaEl.addEventListener('focus', this.handleFocusEvent);
|
|
249
265
|
textareaEl.addEventListener('blur', this.handleBlurEvent);
|
|
250
266
|
}
|
|
267
|
+
removeTextareaEvents(textareaEl) {
|
|
268
|
+
textareaEl.removeEventListener('input', this.handleInputEvent);
|
|
269
|
+
textareaEl.removeEventListener('focus', this.handleFocusEvent);
|
|
270
|
+
textareaEl.removeEventListener('blur', this.handleBlurEvent);
|
|
271
|
+
}
|
|
251
272
|
render() {
|
|
252
273
|
const root = this.shadowRoot;
|
|
253
274
|
const existingContainer = root.querySelector('.textarea-container');
|
|
@@ -257,18 +278,19 @@ const existingError = root.querySelector('.error-message');
|
|
|
257
278
|
if (existingContainer && existingTextarea) {
|
|
258
279
|
if (this.label) {
|
|
259
280
|
if (existingLabel) {
|
|
260
|
-
existingLabel.innerHTML = this.label
|
|
261
|
-
|
|
262
|
-
existingLabel.style.display = 'block';
|
|
281
|
+
existingLabel.innerHTML = `${this.label}${this.required ? `<span class="required-icon">${REQUIRED_ICON_SVG}</span>` : ''}`;
|
|
282
|
+
existingLabel.style.display = 'flex';
|
|
263
283
|
}
|
|
264
284
|
}
|
|
265
285
|
else if (existingLabel) {
|
|
266
286
|
existingLabel.style.display = 'none';
|
|
267
287
|
}
|
|
288
|
+
if (existingTextarea.value !== (this.value || ''))
|
|
268
289
|
existingTextarea.value = this.value || '';
|
|
269
290
|
existingTextarea.placeholder = this.placeholder || '';
|
|
270
291
|
existingTextarea.disabled = this.disabled;
|
|
271
292
|
existingTextarea.required = this.required;
|
|
293
|
+
this.syncConstraintAttributes(existingTextarea);
|
|
272
294
|
existingTextarea.className = this.buildClassList();
|
|
273
295
|
if (this.label)
|
|
274
296
|
existingTextarea.setAttribute('aria-label', this.label);
|
|
@@ -308,9 +330,8 @@ container.className = 'textarea-container';
|
|
|
308
330
|
const labelEl = document.createElement('label');
|
|
309
331
|
labelEl.className = 'ty-field-label';
|
|
310
332
|
if (this.label) {
|
|
311
|
-
labelEl.innerHTML = this.label
|
|
312
|
-
|
|
313
|
-
labelEl.style.display = 'block';
|
|
333
|
+
labelEl.innerHTML = `${this.label}${this.required ? `<span class="required-icon">${REQUIRED_ICON_SVG}</span>` : ''}`;
|
|
334
|
+
labelEl.style.display = 'flex';
|
|
314
335
|
}
|
|
315
336
|
else {
|
|
316
337
|
labelEl.style.display = 'none';
|
|
@@ -320,6 +341,7 @@ textareaEl.value = this.value || '';
|
|
|
320
341
|
textareaEl.placeholder = this.placeholder || '';
|
|
321
342
|
textareaEl.disabled = this.disabled;
|
|
322
343
|
textareaEl.required = this.required;
|
|
344
|
+
this.syncConstraintAttributes(textareaEl);
|
|
323
345
|
textareaEl.className = this.buildClassList();
|
|
324
346
|
if (this.label)
|
|
325
347
|
textareaEl.setAttribute('aria-label', this.label);
|
|
@@ -371,6 +393,11 @@ this._textareaEl = textareaEl;
|
|
|
371
393
|
}
|
|
372
394
|
this.updateValidity();
|
|
373
395
|
}
|
|
396
|
+
syncConstraintAttributes(ta) {
|
|
397
|
+
const set = (name, limit) => limit !== null ? ta.setAttribute(name, String(limit)) : ta.removeAttribute(name);
|
|
398
|
+
set('minlength', toLimit(this.getProperty('minlength')));
|
|
399
|
+
set('maxlength', toLimit(this.getProperty('maxlength')));
|
|
400
|
+
}
|
|
374
401
|
updateValidity() {
|
|
375
402
|
const ta = this.shadowRoot?.querySelector('textarea');
|
|
376
403
|
if (this.disabled) {
|
|
@@ -378,12 +405,22 @@ this.applyValidity({});
|
|
|
378
405
|
return;
|
|
379
406
|
}
|
|
380
407
|
const current = ta ? ta.value : String(this.value ?? '');
|
|
381
|
-
if (
|
|
382
|
-
this.
|
|
408
|
+
if (current.trim() === '') {
|
|
409
|
+
if (this.required) {
|
|
410
|
+
this.applyValidity({ valueMissing: true }, nativeMessage('textarea', { required: true }), ta ?? undefined);
|
|
383
411
|
}
|
|
384
412
|
else {
|
|
385
413
|
this.applyValidity({});
|
|
386
414
|
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const { tooShort, tooLong } = lengthValidity(current, {
|
|
418
|
+
minlength: this.getProperty('minlength'),
|
|
419
|
+
maxlength: this.getProperty('maxlength'),
|
|
420
|
+
tooShortMessage: this.tooShortMessage,
|
|
421
|
+
tooLongMessage: this.tooLongMessage,
|
|
422
|
+
}, ta);
|
|
423
|
+
this.applyValidity({ tooShort: !!tooShort, tooLong: !!tooLong }, tooShort ?? tooLong, ta ?? undefined);
|
|
387
424
|
}
|
|
388
425
|
}
|
|
389
426
|
TyTextarea.formAssociated = true;
|
|
@@ -419,6 +456,26 @@ type: 'boolean',
|
|
|
419
456
|
visual: true,
|
|
420
457
|
default: false
|
|
421
458
|
},
|
|
459
|
+
minlength: {
|
|
460
|
+
type: 'string',
|
|
461
|
+
visual: true,
|
|
462
|
+
default: ''
|
|
463
|
+
},
|
|
464
|
+
maxlength: {
|
|
465
|
+
type: 'string',
|
|
466
|
+
visual: true,
|
|
467
|
+
default: ''
|
|
468
|
+
},
|
|
469
|
+
tooShortMessage: {
|
|
470
|
+
type: 'string',
|
|
471
|
+
visual: true,
|
|
472
|
+
default: ''
|
|
473
|
+
},
|
|
474
|
+
tooLongMessage: {
|
|
475
|
+
type: 'string',
|
|
476
|
+
visual: true,
|
|
477
|
+
default: ''
|
|
478
|
+
},
|
|
422
479
|
error: {
|
|
423
480
|
type: 'string',
|
|
424
481
|
visual: true,
|
package/lib/index.d.ts
CHANGED
|
@@ -75,6 +75,7 @@ declare global {
|
|
|
75
75
|
tyResizeObserver: {
|
|
76
76
|
getSize: (id: string) => ResizeSize | undefined;
|
|
77
77
|
onResize: (id: string, callback: ResizeCallback) => () => void;
|
|
78
|
+
getAllSizes: () => Record<string, ResizeSize>;
|
|
78
79
|
sizes: Record<string, ResizeSize>;
|
|
79
80
|
};
|
|
80
81
|
tyLoader: {
|
package/lib/index.js
CHANGED
package/lib/styles/button.js
CHANGED
|
@@ -69,11 +69,26 @@ color: var(--ty-button-color, ${ink('-strong')});
|
|
|
69
69
|
export const buttonCustomFlavorCss = (base) => solidFlavor(base, 'neutral') + outlinedFlavor(base, 'neutral') + ghostFlavor(base, 'neutral');
|
|
70
70
|
export const buttonStyles = `
|
|
71
71
|
:host {
|
|
72
|
-
|
|
72
|
+
--_rung: var(--ty-button-height);
|
|
73
|
+
display: inline-grid;
|
|
74
|
+
grid-template: minmax(var(--_rung), 1fr) / minmax(min-content, 1fr);
|
|
75
|
+
height: fit-content;
|
|
73
76
|
font-family: inherit;
|
|
74
77
|
}
|
|
78
|
+
:host([action]) {
|
|
79
|
+
--_rung: var(--ty-button-action-size);
|
|
80
|
+
}
|
|
81
|
+
:host([action]:not([wide])) {
|
|
82
|
+
width: fit-content;
|
|
83
|
+
aspect-ratio: 1;
|
|
84
|
+
}
|
|
75
85
|
:host([wide]) {
|
|
76
|
-
display:
|
|
86
|
+
display: grid;
|
|
87
|
+
flex-grow: 1;
|
|
88
|
+
max-height: var(--_rung);
|
|
89
|
+
grid-template-rows: minmax(var(--_rung), max-content);
|
|
90
|
+
}
|
|
91
|
+
:host([wide]) button {
|
|
77
92
|
flex-grow: 1;
|
|
78
93
|
}
|
|
79
94
|
:host {
|
|
@@ -140,6 +155,7 @@ align-items: center;
|
|
|
140
155
|
justify-content: center;
|
|
141
156
|
gap: var(--ty-button-gap);
|
|
142
157
|
height: var(--ty-button-height);
|
|
158
|
+
min-height: 100%;
|
|
143
159
|
padding: var(--ty-button-pad-y) var(--ty-button-pad-x);
|
|
144
160
|
font-size: var(--ty-button-font);
|
|
145
161
|
line-height: var(--ty-button-leading);
|
|
@@ -214,13 +230,11 @@ justify-content: center;
|
|
|
214
230
|
::slotted(ty-icon) {
|
|
215
231
|
flex-shrink: 0;
|
|
216
232
|
}
|
|
217
|
-
:host([wide]) button {
|
|
218
|
-
flex-grow: 1;
|
|
219
|
-
}
|
|
220
233
|
button.action {
|
|
221
234
|
gap: 0px !important;
|
|
222
|
-
height:
|
|
223
|
-
width: var(--ty-button-action-size);
|
|
235
|
+
height: auto;
|
|
236
|
+
min-width: var(--ty-button-action-size);
|
|
237
|
+
min-height: var(--ty-button-action-size);
|
|
224
238
|
padding: 0px !important;
|
|
225
239
|
}
|
|
226
240
|
button.action ::slotted(ty-icon) {
|
|
@@ -272,18 +286,6 @@ button.pill.xs { padding-left: 1em; padding-right: 1em; }
|
|
|
272
286
|
button.pill.sm { padding-left: 1.125em; padding-right: 1.125em; }
|
|
273
287
|
button.pill.lg { padding-left: 1.5em; padding-right: 1.5em; }
|
|
274
288
|
button.pill.xl { padding-left: 1.75em; padding-right: 1.75em; }
|
|
275
|
-
button.pill:has(ty-icon:only-child),
|
|
276
|
-
button.pill:has(slot[name="start"]:only-child),
|
|
277
|
-
button.pill:has(slot[name="end"]:only-child) {
|
|
278
|
-
padding: 0;
|
|
279
|
-
aspect-ratio: 1;
|
|
280
|
-
min-width: var(--ty-size-md);
|
|
281
|
-
}
|
|
282
|
-
button.pill.xs:has(ty-icon:only-child) { min-width: 1.375rem; min-height: 1.375rem; }
|
|
283
|
-
button.pill.sm:has(ty-icon:only-child) { min-width: 1.5rem; min-height: 1.5rem; }
|
|
284
|
-
button.pill.md:has(ty-icon:only-child) { min-width: 2rem; min-height: 2rem; }
|
|
285
|
-
button.pill.lg:has(ty-icon:only-child) { min-width: 2.25rem; min-height: 2.25rem; }
|
|
286
|
-
button.pill.xl:has(ty-icon:only-child) { min-width: 2.5rem; min-height: 2.5rem; }
|
|
287
289
|
button.solid {
|
|
288
290
|
--_ring: var(--ty-color-neutral);
|
|
289
291
|
--_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral));
|
|
@@ -124,7 +124,7 @@ color: var(--ty-calendar-weekend-color, var(--ty-calendar-day-color, var(--ty-te
|
|
|
124
124
|
color: var(--ty-calendar-other-month-color, color-mix(in oklab, var(--ty-text-faint) 65%, transparent));
|
|
125
125
|
}
|
|
126
126
|
.calendar-day-cell.other-month:hover {
|
|
127
|
-
color: var(--ty-calendar-day-hover-color, var(--ty-text-soft
|
|
127
|
+
color: var(--ty-calendar-day-hover-color, var(--ty-text-soft));
|
|
128
128
|
background-color: var(--ty-calendar-day-hover-bg, var(--ty-bg-neutral-soft));
|
|
129
129
|
}
|
|
130
130
|
.calendar-day-cell.disabled {
|
package/lib/styles/calendar.js
CHANGED
package/lib/styles/checkbox.js
CHANGED
|
@@ -14,14 +14,21 @@ export const checkboxStyles = `
|
|
|
14
14
|
:host {
|
|
15
15
|
display: inline-flex;
|
|
16
16
|
width: auto;
|
|
17
|
-
|
|
17
|
+
height: 1.25em;
|
|
18
|
+
height: 1lh;
|
|
19
|
+
align-items: center;
|
|
20
|
+
vertical-align: baseline;
|
|
21
|
+
overflow: visible;
|
|
22
|
+
}
|
|
23
|
+
:host::before {
|
|
24
|
+
content: "\\200b";
|
|
25
|
+
width: 0;
|
|
18
26
|
}
|
|
19
27
|
.checkbox-container {
|
|
20
28
|
display: inline-flex;
|
|
29
|
+
flex-shrink: 0;
|
|
21
30
|
align-items: center;
|
|
22
31
|
justify-content: center;
|
|
23
|
-
min-height: 1.25em;
|
|
24
|
-
min-height: 1lh;
|
|
25
32
|
outline: none;
|
|
26
33
|
transition: var(--ty-local-transition, all 0.15s ease-in-out);
|
|
27
34
|
user-select: none;
|
|
@@ -42,8 +49,7 @@ color: var(--checkbox-color-off-hover, color-mix(in oklab, var(--ty-text) 50%, t
|
|
|
42
49
|
.checkbox-container[aria-checked="true"] {
|
|
43
50
|
color: var(--checkbox-color, var(--ty-text));
|
|
44
51
|
}
|
|
45
|
-
.checkbox-container.focused
|
|
46
|
-
.checkbox-container:focus-visible {
|
|
52
|
+
.checkbox-container.focused {
|
|
47
53
|
box-shadow: 0 0 0 3px var(--checkbox-ring, color-mix(in oklab, var(--ty-color-primary) 25%, transparent));
|
|
48
54
|
}
|
|
49
55
|
.checkbox-icon {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FLAVORS } from "../types/common.js";
|
|
2
2
|
import { fieldSizeVars } from "./field-size.js";
|
|
3
|
-
const datePickerFlavor = (f, fb) => {
|
|
3
|
+
const datePickerFlavor = (f, fb, also = "") => {
|
|
4
4
|
const c = (s) => fb
|
|
5
5
|
? s
|
|
6
6
|
? `var(--ty-color-${f}${s}, var(--ty-color-${f}, var(--ty-color-${fb}${s})))`
|
|
@@ -9,7 +9,7 @@ const c = (s) => fb
|
|
|
9
9
|
? `var(--ty-color-${f}${s}, var(--ty-color-${f}))`
|
|
10
10
|
: `var(--ty-color-${f})`;
|
|
11
11
|
return `
|
|
12
|
-
:host([flavor="${f}"]) {
|
|
12
|
+
:host([flavor="${f}"])${also} {
|
|
13
13
|
--date-picker-accent: var(--ty-input-${f}-border, ${c("-soft")});
|
|
14
14
|
--date-picker-accent-bold: ${c("")};
|
|
15
15
|
--date-picker-ring: color-mix(in oklab, ${c("")} 15%, transparent);
|
|
@@ -26,6 +26,7 @@ return `
|
|
|
26
26
|
}
|
|
27
27
|
`;
|
|
28
28
|
};
|
|
29
|
+
const errorLook = `,\n:host([error]:not([error=""]))`;
|
|
29
30
|
export const datePickerCustomFlavorCss = (base) => datePickerFlavor(base, "neutral");
|
|
30
31
|
export const datePickerStyles = `
|
|
31
32
|
${fieldSizeVars}
|
|
@@ -133,7 +134,18 @@ opacity: 0.6;
|
|
|
133
134
|
border-color: var(--date-picker-accent-bold, var(--ty-date-picker-border-focus));
|
|
134
135
|
box-shadow: 0 0 0 3px var(--date-picker-ring, var(--ty-date-picker-shadow-focus));
|
|
135
136
|
}
|
|
136
|
-
${FLAVORS.filter((f) => f !== "neutral").map((f) => datePickerFlavor(f)).join("")}
|
|
137
|
+
${FLAVORS.filter((f) => f !== "neutral").map((f) => datePickerFlavor(f, undefined, f === "danger" ? errorLook : "")).join("")}
|
|
138
|
+
.error-message {
|
|
139
|
+
font-size: var(--ty-font-xs);
|
|
140
|
+
line-height: var(--ty-leading-xs);
|
|
141
|
+
letter-spacing: var(--ty-tracking-xs);
|
|
142
|
+
color: var(--ty-color-danger);
|
|
143
|
+
margin-top: 4px;
|
|
144
|
+
padding-left: var(--ty-field-outer-pad-x);
|
|
145
|
+
}
|
|
146
|
+
.date-picker-stub.error:not([disabled]) {
|
|
147
|
+
background: var(--ty-bg-danger-soft);
|
|
148
|
+
}
|
|
137
149
|
.stub-text {
|
|
138
150
|
flex: 1;
|
|
139
151
|
white-space: nowrap;
|
package/lib/styles/input.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FLAVORS } from "../types/common.js";
|
|
2
2
|
import { fieldSizeVars } from "./field-size.js";
|
|
3
|
-
const inputFlavor = (f, fb) => {
|
|
3
|
+
const inputFlavor = (f, fb, also = "") => {
|
|
4
4
|
const c = (s) => fb
|
|
5
5
|
? s
|
|
6
6
|
? `var(--ty-color-${f}${s}, var(--ty-color-${f}, var(--ty-color-${fb}${s})))`
|
|
@@ -9,7 +9,7 @@ const c = (s) => fb
|
|
|
9
9
|
? `var(--ty-color-${f}${s}, var(--ty-color-${f}))`
|
|
10
10
|
: `var(--ty-color-${f})`;
|
|
11
11
|
return `
|
|
12
|
-
:host([flavor="${f}"]) {
|
|
12
|
+
:host([flavor="${f}"])${also} {
|
|
13
13
|
--input-accent: var(--ty-input-${f}-border, ${c("-soft")});
|
|
14
14
|
--input-accent-bold: ${c("")};
|
|
15
15
|
--input-ring: color-mix(in oklab, ${c("")} 15%, transparent);
|
|
@@ -26,6 +26,7 @@ return `
|
|
|
26
26
|
}
|
|
27
27
|
`;
|
|
28
28
|
};
|
|
29
|
+
const errorLook = `,\n:host([error]:not([error=""]))`;
|
|
29
30
|
export const inputCustomFlavorCss = (base) => inputFlavor(base, "neutral");
|
|
30
31
|
export const inputStyles = `
|
|
31
32
|
${fieldSizeVars}
|
|
@@ -137,14 +138,9 @@ color: var(--ty-color-danger);
|
|
|
137
138
|
margin-top: 4px;
|
|
138
139
|
padding-left: var(--ty-field-outer-pad-x);
|
|
139
140
|
}
|
|
140
|
-
.input-wrapper.error {
|
|
141
|
-
border-color: var(--ty-color-danger);
|
|
141
|
+
.input-wrapper.error:not(.disabled) {
|
|
142
142
|
background: var(--ty-bg-danger-soft);
|
|
143
143
|
}
|
|
144
|
-
.input-wrapper.error.focused {
|
|
145
|
-
border-color: var(--ty-color-danger-bold);
|
|
146
|
-
box-shadow: 0 0 0 3px var(--input-shadow-focus, var(--ty-input-shadow-focus));
|
|
147
|
-
}
|
|
148
144
|
input {
|
|
149
145
|
flex: 1;
|
|
150
146
|
min-width: 0;
|
|
@@ -177,7 +173,7 @@ input::placeholder {
|
|
|
177
173
|
color: var(--input-placeholder, var(--ty-input-placeholder));
|
|
178
174
|
font-weight: 400;
|
|
179
175
|
}
|
|
180
|
-
${FLAVORS.filter((f) => f !== "neutral").map((f) => inputFlavor(f)).join("")}
|
|
176
|
+
${FLAVORS.filter((f) => f !== "neutral").map((f) => inputFlavor(f, undefined, f === "danger" ? errorLook : "")).join("")}
|
|
181
177
|
input:focus-visible {
|
|
182
178
|
outline: none;
|
|
183
179
|
}
|
package/lib/styles/option.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Option Component Styles */
|
|
2
|
-
export declare const optionStyles = "\n.option-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ty-spacing-2);\n box-sizing: border-box;\n width: 100%;\n\n cursor: pointer;\n user-select: none;\n\n transition: var(--ty-transition-all);\n\n /* Linear-paired typography */\n color: var(--ty-text);\n font-family: inherit;\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: var(--ty-spacing-2) var(--ty-spacing-3);\n border-radius: var(--ty-radius-md);\n}\n\n/* Cloned copy (projected into the select's trigger field): host defaults to\n inline like any unstyled custom element, which ignores width/overflow \u2014\n force a block box so the parent's flex-basis:0 truncation (select.ts\n .select-stub.has-clone slot[name=\"selected\"]) actually clips it, and\n collapse the content to a single ellipsized line instead of wrapping. */\n:host([cloned]) {\n display: block;\n min-width: 0;\n overflow: hidden;\n}\n\n/* The clone sits in the select's TRIGGER, so its type follows the field size\n ladder (styles/field-size.ts) rather than the dropdown list's own scale \u2014\n the --ty-field-* vars inherit from ty-select through the light DOM. The\n fallbacks cover a ty-option rendered outside a select. */\n:host([cloned]) .option-content {\n display: block;\n padding: 0px;\n background: transparent;\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: var(--ty-field-font, var(--ty-font-sm));\n line-height: var(--ty-field-leading, var(--ty-leading-sm));\n letter-spacing: var(--ty-field-tracking, var(--ty-tracking-sm));\n}\n\n.option-content:hover {\n background: var(--ty-bg-neutral-soft);\n}\n\n.option-content[highlighted] {\n background: var(--ty-bg-neutral-soft);\n color: var(--ty-text-strong);\n}\n\n/* Selected: quiet \u2014 bolder text color only, no background slab, no weight change */\n.option-content[selected] {\n background: transparent;\n color: var(--ty-text-bold);\n}\n\n/* Lucide check \u2014 right-aligned. Its box is always reserved so selecting\n (or highlighting) never changes the row's width and rewraps the text. */\n.option-check {\n display: block;\n visibility: hidden;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n margin-left: auto;\n color: var(--ty-color-primary);\n}\n\n.option-content[selected] .option-check {\n visibility: visible;\n}\n\n/* Never show the check on the copy cloned into the select's trigger field */\n:host([cloned]) .option-check {\n display: none;\n}\n\n.option-content[selected]:hover {\n background: var(--ty-bg-neutral-soft);\n}\n\n.option-content[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.option-content[hidden] {}\n\n.option-content * {\n pointer-events: none;\n}\n";
|
|
2
|
+
export declare const optionStyles = "\n/* Options the author hid and options a ty-select search left out, at any\n depth in the select (a framework component's element around each option\n too). !important beats the select's mobile list display:block. */\n:host([hidden]),\n:host([filtered-out]) {\n display: none !important;\n}\n\n.option-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ty-spacing-2);\n box-sizing: border-box;\n width: 100%;\n\n cursor: pointer;\n user-select: none;\n\n transition: var(--ty-transition-all);\n\n /* Linear-paired typography */\n color: var(--ty-text);\n font-family: inherit;\n font-size: var(--ty-font-sm);\n line-height: var(--ty-leading-sm);\n letter-spacing: var(--ty-tracking-sm);\n padding: var(--ty-spacing-2) var(--ty-spacing-3);\n border-radius: var(--ty-radius-md);\n}\n\n/* Cloned copy (projected into the select's trigger field): host defaults to\n inline like any unstyled custom element, which ignores width/overflow \u2014\n force a block box so the parent's flex-basis:0 truncation (select.ts\n .select-stub.has-clone slot[name=\"selected\"]) actually clips it, and\n collapse the content to a single ellipsized line instead of wrapping. */\n:host([cloned]) {\n display: block;\n min-width: 0;\n overflow: hidden;\n}\n\n/* The clone sits in the select's TRIGGER, so its type follows the field size\n ladder (styles/field-size.ts) rather than the dropdown list's own scale \u2014\n the --ty-field-* vars inherit from ty-select through the light DOM. The\n fallbacks cover a ty-option rendered outside a select. */\n:host([cloned]) .option-content {\n display: block;\n padding: 0px;\n background: transparent;\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-size: var(--ty-field-font, var(--ty-font-sm));\n line-height: var(--ty-field-leading, var(--ty-leading-sm));\n letter-spacing: var(--ty-field-tracking, var(--ty-tracking-sm));\n}\n\n.option-content:hover {\n background: var(--ty-bg-neutral-soft);\n}\n\n.option-content[highlighted] {\n background: var(--ty-bg-neutral-soft);\n color: var(--ty-text-strong);\n}\n\n/* Selected: quiet \u2014 bolder text color only, no background slab, no weight change */\n.option-content[selected] {\n background: transparent;\n color: var(--ty-text-bold);\n}\n\n/* Lucide check \u2014 right-aligned. Its box is always reserved so selecting\n (or highlighting) never changes the row's width and rewraps the text. */\n.option-check {\n display: block;\n visibility: hidden;\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n margin-left: auto;\n color: var(--ty-color-primary);\n}\n\n.option-content[selected] .option-check {\n visibility: visible;\n}\n\n/* Never show the check on the copy cloned into the select's trigger field */\n:host([cloned]) .option-check {\n display: none;\n}\n\n.option-content[selected]:hover {\n background: var(--ty-bg-neutral-soft);\n}\n\n.option-content[disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.option-content[hidden] {}\n\n.option-content * {\n pointer-events: none;\n}\n";
|