@sondor-technology/sondor-components 1.0.1-develop.13 → 1.0.1-develop.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/alert/alert.constants.d.ts +3 -0
- package/dist/components/alert/alert.constants.d.ts.map +1 -0
- package/dist/components/alert/alert.constants.js +2 -0
- package/dist/components/alert/alert.constants.js.map +1 -0
- package/dist/components/alert/alert.d.ts +4 -3
- package/dist/components/alert/alert.d.ts.map +1 -1
- package/dist/components/alert/alert.js +21 -11
- package/dist/components/alert/alert.js.map +1 -0
- package/dist/components/badge/badge.constants.d.ts +3 -0
- package/dist/components/badge/badge.constants.d.ts.map +1 -0
- package/dist/components/badge/badge.constants.js +2 -0
- package/dist/components/badge/badge.constants.js.map +1 -0
- package/dist/components/badge/badge.d.ts +1 -1
- package/dist/components/badge/badge.d.ts.map +1 -1
- package/dist/components/badge/badge.js +3 -2
- package/dist/components/badge/badge.js.map +1 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.js +2 -1
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -0
- package/dist/components/button/button.constants.d.ts +7 -0
- package/dist/components/button/button.constants.d.ts.map +1 -0
- package/dist/components/button/button.constants.js +4 -0
- package/dist/components/button/button.constants.js.map +1 -0
- package/dist/components/button/button.d.ts +8 -4
- package/dist/components/button/button.d.ts.map +1 -1
- package/dist/components/button/button.js +181 -137
- package/dist/components/button/button.js.map +1 -0
- package/dist/components/button-group/button-group.d.ts +1 -0
- package/dist/components/button-group/button-group.d.ts.map +1 -1
- package/dist/components/button-group/button-group.js +17 -21
- package/dist/components/button-group/button-group.js.map +1 -0
- package/dist/components/calendar/calendar.d.ts +36 -0
- package/dist/components/calendar/calendar.d.ts.map +1 -0
- package/dist/components/calendar/calendar.js +439 -0
- package/dist/components/calendar/calendar.js.map +1 -0
- package/dist/components/checkbox/checkbox.constants.d.ts +3 -0
- package/dist/components/checkbox/checkbox.constants.d.ts.map +1 -0
- package/dist/components/checkbox/checkbox.constants.js +2 -0
- package/dist/components/checkbox/checkbox.constants.js.map +1 -0
- package/dist/components/checkbox/checkbox.d.ts +5 -1
- package/dist/components/checkbox/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox/checkbox.js +21 -5
- package/dist/components/checkbox/checkbox.js.map +1 -0
- package/dist/components/code-block/code-block.d.ts +7 -7
- package/dist/components/code-block/code-block.d.ts.map +1 -1
- package/dist/components/code-block/code-block.js +130 -66
- package/dist/components/code-block/code-block.js.map +1 -0
- package/dist/components/content-card/content-card.d.ts.map +1 -1
- package/dist/components/content-card/content-card.js +10 -15
- package/dist/components/content-card/content-card.js.map +1 -0
- package/dist/components/cron-builder/cron-builder.d.ts +34 -0
- package/dist/components/cron-builder/cron-builder.d.ts.map +1 -0
- package/dist/components/cron-builder/cron-builder.js +456 -0
- package/dist/components/cron-builder/cron-builder.js.map +1 -0
- package/dist/components/divider/divider.constants.d.ts +5 -0
- package/dist/components/divider/divider.constants.d.ts.map +1 -0
- package/dist/components/divider/divider.constants.js +3 -0
- package/dist/components/divider/divider.constants.js.map +1 -0
- package/dist/components/divider/divider.d.ts +4 -2
- package/dist/components/divider/divider.d.ts.map +1 -1
- package/dist/components/divider/divider.js +18 -9
- package/dist/components/divider/divider.js.map +1 -0
- package/dist/components/drawer/drawer.d.ts +7 -4
- package/dist/components/drawer/drawer.d.ts.map +1 -1
- package/dist/components/drawer/drawer.js +73 -30
- package/dist/components/drawer/drawer.js.map +1 -0
- package/dist/components/field/field.d.ts +2 -2
- package/dist/components/field/field.d.ts.map +1 -1
- package/dist/components/field/field.js +8 -9
- package/dist/components/field/field.js.map +1 -0
- package/dist/components/footer/footer.d.ts +8 -1
- package/dist/components/footer/footer.d.ts.map +1 -1
- package/dist/components/footer/footer.js +42 -12
- package/dist/components/footer/footer.js.map +1 -0
- package/dist/components/form/form-step.js +1 -0
- package/dist/components/form/form-step.js.map +1 -0
- package/dist/components/form/form.d.ts +3 -0
- package/dist/components/form/form.d.ts.map +1 -1
- package/dist/components/form/form.js +109 -69
- package/dist/components/form/form.js.map +1 -0
- package/dist/components/grid/grid-row.d.ts +3 -3
- package/dist/components/grid/grid-row.d.ts.map +1 -1
- package/dist/components/grid/grid-row.js +36 -22
- package/dist/components/grid/grid-row.js.map +1 -0
- package/dist/components/grid/grid.d.ts +2 -2
- package/dist/components/grid/grid.d.ts.map +1 -1
- package/dist/components/grid/grid.js +5 -2
- package/dist/components/grid/grid.js.map +1 -0
- package/dist/components/icon/icon-paths.d.ts +161 -86
- package/dist/components/icon/icon-paths.d.ts.map +1 -1
- package/dist/components/icon/icon-paths.js +176 -106
- package/dist/components/icon/icon-paths.js.map +1 -0
- package/dist/components/icon/icon.d.ts +1 -1
- package/dist/components/icon/icon.d.ts.map +1 -1
- package/dist/components/icon/icon.js +6 -5
- package/dist/components/icon/icon.js.map +1 -0
- package/dist/components/input/input.d.ts +10 -0
- package/dist/components/input/input.d.ts.map +1 -1
- package/dist/components/input/input.js +59 -43
- package/dist/components/input/input.js.map +1 -0
- package/dist/components/link/link.d.ts +6 -6
- package/dist/components/link/link.d.ts.map +1 -1
- package/dist/components/link/link.js +42 -19
- package/dist/components/link/link.js.map +1 -0
- package/dist/components/metadata/metadata.d.ts +3 -3
- package/dist/components/metadata/metadata.d.ts.map +1 -1
- package/dist/components/metadata/metadata.js +23 -20
- package/dist/components/metadata/metadata.js.map +1 -0
- package/dist/components/modal/modal.d.ts +4 -16
- package/dist/components/modal/modal.d.ts.map +1 -1
- package/dist/components/modal/modal.js +99 -62
- package/dist/components/modal/modal.js.map +1 -0
- package/dist/components/page-layout/page-layout.d.ts +4 -3
- package/dist/components/page-layout/page-layout.d.ts.map +1 -1
- package/dist/components/page-layout/page-layout.js +95 -68
- package/dist/components/page-layout/page-layout.js.map +1 -0
- package/dist/components/pin-input/pin-input.d.ts +33 -0
- package/dist/components/pin-input/pin-input.d.ts.map +1 -0
- package/dist/components/pin-input/pin-input.js +253 -0
- package/dist/components/pin-input/pin-input.js.map +1 -0
- package/dist/components/popover/popover.d.ts +26 -0
- package/dist/components/popover/popover.d.ts.map +1 -0
- package/dist/components/popover/popover.js +196 -0
- package/dist/components/popover/popover.js.map +1 -0
- package/dist/components/radio/radio.d.ts +8 -0
- package/dist/components/radio/radio.d.ts.map +1 -1
- package/dist/components/radio/radio.js +8 -12
- package/dist/components/radio/radio.js.map +1 -0
- package/dist/components/radio-group/radio-group.d.ts +6 -1
- package/dist/components/radio-group/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group/radio-group.js +44 -18
- package/dist/components/radio-group/radio-group.js.map +1 -0
- package/dist/components/router/router.d.ts +5 -7
- package/dist/components/router/router.d.ts.map +1 -1
- package/dist/components/router/router.js +54 -38
- package/dist/components/router/router.js.map +1 -0
- package/dist/components/select/select.d.ts +5 -4
- package/dist/components/select/select.d.ts.map +1 -1
- package/dist/components/select/select.js +40 -9
- package/dist/components/select/select.js.map +1 -0
- package/dist/components/skeleton/skeleton.d.ts +3 -2
- package/dist/components/skeleton/skeleton.d.ts.map +1 -1
- package/dist/components/skeleton/skeleton.js +10 -13
- package/dist/components/skeleton/skeleton.js.map +1 -0
- package/dist/components/switch/switch.d.ts +12 -0
- package/dist/components/switch/switch.d.ts.map +1 -1
- package/dist/components/switch/switch.js +28 -22
- package/dist/components/switch/switch.js.map +1 -0
- package/dist/components/table/data-table.d.ts +3 -25
- package/dist/components/table/data-table.d.ts.map +1 -1
- package/dist/components/table/data-table.js +211 -146
- package/dist/components/table/data-table.js.map +1 -0
- package/dist/components/table/table.d.ts +3 -3
- package/dist/components/table/table.d.ts.map +1 -1
- package/dist/components/table/table.js +39 -20
- package/dist/components/table/table.js.map +1 -0
- package/dist/components/tabs/tab-panel.d.ts +3 -1
- package/dist/components/tabs/tab-panel.d.ts.map +1 -1
- package/dist/components/tabs/tab-panel.js +21 -11
- package/dist/components/tabs/tab-panel.js.map +1 -0
- package/dist/components/tabs/tab.d.ts +5 -1
- package/dist/components/tabs/tab.d.ts.map +1 -1
- package/dist/components/tabs/tab.js +46 -28
- package/dist/components/tabs/tab.js.map +1 -0
- package/dist/components/tabs/tabs.d.ts +4 -0
- package/dist/components/tabs/tabs.d.ts.map +1 -1
- package/dist/components/tabs/tabs.js +76 -13
- package/dist/components/tabs/tabs.js.map +1 -0
- package/dist/components/textarea/textarea.d.ts +13 -0
- package/dist/components/textarea/textarea.d.ts.map +1 -1
- package/dist/components/textarea/textarea.js +59 -13
- package/dist/components/textarea/textarea.js.map +1 -0
- package/dist/components/theme-toggle/theme-toggle.constants.d.ts +3 -0
- package/dist/components/theme-toggle/theme-toggle.constants.d.ts.map +1 -0
- package/dist/components/theme-toggle/theme-toggle.constants.js +2 -0
- package/dist/components/theme-toggle/theme-toggle.constants.js.map +1 -0
- package/dist/components/theme-toggle/theme-toggle.d.ts +3 -2
- package/dist/components/theme-toggle/theme-toggle.d.ts.map +1 -1
- package/dist/components/theme-toggle/theme-toggle.js +46 -19
- package/dist/components/theme-toggle/theme-toggle.js.map +1 -0
- package/dist/components/time-picker/time-picker.d.ts +38 -0
- package/dist/components/time-picker/time-picker.d.ts.map +1 -0
- package/dist/components/time-picker/time-picker.js +280 -0
- package/dist/components/time-picker/time-picker.js.map +1 -0
- package/dist/components/toggle-group/toggle-button.d.ts +23 -0
- package/dist/components/toggle-group/toggle-button.d.ts.map +1 -0
- package/dist/components/toggle-group/toggle-button.js +115 -0
- package/dist/components/toggle-group/toggle-button.js.map +1 -0
- package/dist/components/toggle-group/toggle-group.d.ts +32 -0
- package/dist/components/toggle-group/toggle-group.d.ts.map +1 -0
- package/dist/components/toggle-group/toggle-group.js +150 -0
- package/dist/components/toggle-group/toggle-group.js.map +1 -0
- package/dist/components/tooltip/tooltip.d.ts +33 -0
- package/dist/components/tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip/tooltip.js +293 -0
- package/dist/components/tooltip/tooltip.js.map +1 -0
- package/dist/components/vertical-nav/vertical-nav-group.d.ts +5 -2
- package/dist/components/vertical-nav/vertical-nav-group.d.ts.map +1 -1
- package/dist/components/vertical-nav/vertical-nav-group.js +50 -14
- package/dist/components/vertical-nav/vertical-nav-group.js.map +1 -0
- package/dist/components/vertical-nav/vertical-nav-item.d.ts +3 -2
- package/dist/components/vertical-nav/vertical-nav-item.d.ts.map +1 -1
- package/dist/components/vertical-nav/vertical-nav-item.js +30 -8
- package/dist/components/vertical-nav/vertical-nav-item.js.map +1 -0
- package/dist/styles/index.css +49 -17
- package/dist/styles/reset.js +1 -0
- package/dist/styles/reset.js.map +1 -0
- package/package.json +30 -1
- package/src/components/alert/alert.constants.ts +2 -0
- package/src/components/alert/alert.ts +24 -15
- package/src/components/badge/badge.constants.ts +2 -0
- package/src/components/badge/badge.ts +3 -4
- package/src/components/breadcrumb/breadcrumb.ts +2 -2
- package/src/components/button/button.constants.ts +8 -0
- package/src/components/button/button.ts +184 -144
- package/src/components/button-group/button-group.ts +18 -22
- package/src/components/calendar/calendar.ts +444 -0
- package/src/components/checkbox/checkbox.constants.ts +2 -0
- package/src/components/checkbox/checkbox.ts +33 -18
- package/src/components/code-block/code-block.ts +151 -84
- package/src/components/content-card/content-card.ts +10 -16
- package/src/components/cron-builder/cron-builder.ts +452 -0
- package/src/components/divider/divider.constants.ts +5 -0
- package/src/components/divider/divider.ts +22 -11
- package/src/components/drawer/drawer.ts +79 -34
- package/src/components/field/field.ts +9 -11
- package/src/components/footer/footer.ts +43 -12
- package/src/components/form/form.ts +121 -84
- package/src/components/grid/grid-row.ts +45 -32
- package/src/components/grid/grid.ts +7 -4
- package/src/components/icon/icon-paths.ts +175 -106
- package/src/components/icon/icon.ts +6 -6
- package/src/components/input/input.ts +59 -45
- package/src/components/link/link.ts +45 -21
- package/src/components/metadata/metadata.ts +26 -24
- package/src/components/modal/modal.ts +108 -74
- package/src/components/page-layout/page-layout.ts +97 -72
- package/src/components/pin-input/pin-input.ts +249 -0
- package/src/components/popover/popover.ts +192 -0
- package/src/components/radio/radio.ts +8 -13
- package/src/components/radio-group/radio-group.ts +45 -21
- package/src/components/router/router.ts +73 -50
- package/src/components/select/select.ts +41 -80
- package/src/components/skeleton/skeleton.ts +14 -14
- package/src/components/switch/switch.ts +31 -25
- package/src/components/table/data-table.ts +248 -177
- package/src/components/table/table.ts +52 -29
- package/src/components/tabs/tab-panel.ts +25 -13
- package/src/components/tabs/tab.ts +58 -33
- package/src/components/tabs/tabs.ts +77 -15
- package/src/components/textarea/textarea.ts +63 -15
- package/src/components/theme-toggle/theme-toggle.constants.ts +2 -0
- package/src/components/theme-toggle/theme-toggle.ts +47 -22
- package/src/components/time-picker/time-picker.ts +272 -0
- package/src/components/toggle-group/toggle-button.ts +104 -0
- package/src/components/toggle-group/toggle-group.ts +148 -0
- package/src/components/tooltip/tooltip.ts +286 -0
- package/src/components/vertical-nav/vertical-nav-group.ts +57 -18
- package/src/components/vertical-nav/vertical-nav-item.ts +35 -12
- package/src/styles/globals.css +27 -4
- package/src/styles/theme.css +40 -32
- package/tsconfig.json +2 -1
- package/dist/components/card/card.d.ts +0 -11
- package/dist/components/card/card.d.ts.map +0 -1
- package/dist/components/card/card.js +0 -54
- package/src/components/card/card.ts +0 -53
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {LitElement, html, css, PropertyValues} from "lit";
|
|
2
2
|
import {customElement, property, query} from "lit/decorators.js";
|
|
3
|
-
import {ifDefined} from "lit/directives/if-defined.js";
|
|
3
|
+
import {ifDefined} from "lit/directives/if-defined.js";
|
|
4
4
|
import {resetStyles} from "../../styles/reset.js";
|
|
5
5
|
|
|
6
6
|
export type InputType = "text" | "password" | "email" | "number" | "search" | "url";
|
|
@@ -8,6 +8,7 @@ export type InputType = "text" | "password" | "email" | "number" | "search" | "u
|
|
|
8
8
|
@customElement("st-input")
|
|
9
9
|
export class StInput extends LitElement {
|
|
10
10
|
static formAssociated = true;
|
|
11
|
+
static shadowRootOptions = {...LitElement.shadowRootOptions, delegatesFocus: true};
|
|
11
12
|
private _internals: ElementInternals;
|
|
12
13
|
|
|
13
14
|
@query("input") private _inputEl!: HTMLInputElement;
|
|
@@ -17,8 +18,9 @@ export class StInput extends LitElement {
|
|
|
17
18
|
@property({type: String}) placeholder = "";
|
|
18
19
|
@property({type: String}) type: InputType = "text";
|
|
19
20
|
@property({attribute: "help-text"}) helpText = "";
|
|
21
|
+
@property({type: String}) error = "";
|
|
22
|
+
@property({ type: String }) autocomplete?: string;
|
|
20
23
|
|
|
21
|
-
// Validation Properties
|
|
22
24
|
@property({type: Boolean, reflect: true}) required = false;
|
|
23
25
|
@property({type: Number}) minlength?: number;
|
|
24
26
|
@property({type: Number}) maxlength?: number;
|
|
@@ -32,12 +34,10 @@ export class StInput extends LitElement {
|
|
|
32
34
|
super();
|
|
33
35
|
this._internals = this.attachInternals();
|
|
34
36
|
|
|
35
|
-
// 1. Trigger error state if the user clicks away and the field is invalid
|
|
36
37
|
this.addEventListener("focusout", () => {
|
|
37
|
-
this.invalid = !this._inputEl.validity.valid;
|
|
38
|
+
this.invalid = !!this.error || !this._inputEl.validity.valid;
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
// 2. Trigger error state if the st-form tries to submit and fails
|
|
41
41
|
this.addEventListener("invalid", () => {
|
|
42
42
|
this.invalid = true;
|
|
43
43
|
});
|
|
@@ -61,41 +61,34 @@ export class StInput extends LitElement {
|
|
|
61
61
|
font-weight: var(--st-font-weight-medium);
|
|
62
62
|
color: var(--st-color-text);
|
|
63
63
|
margin-bottom: 0.5em;
|
|
64
|
+
cursor: pointer;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
/* 1. The Wrapper acts as the visual input field */
|
|
67
67
|
.input-wrapper {
|
|
68
68
|
display: flex;
|
|
69
69
|
align-items: center;
|
|
70
70
|
gap: var(--st-spacing-sm);
|
|
71
71
|
width: 100%;
|
|
72
|
-
|
|
73
72
|
background-color: var(--st-color-bg);
|
|
74
73
|
border: 1px solid var(--st-color-border);
|
|
75
74
|
border-radius: 4px;
|
|
76
|
-
|
|
77
|
-
/* Horizontal padding on the wrapper, vertical on the input */
|
|
78
75
|
padding: 0 var(--st-spacing-md);
|
|
79
76
|
transition:
|
|
80
77
|
border-color 0.2s ease,
|
|
81
78
|
box-shadow 0.2s ease;
|
|
82
79
|
}
|
|
83
80
|
|
|
84
|
-
/* 2. Apply focus ring to the wrapper when the internal input is focused */
|
|
85
81
|
.input-wrapper:focus-within {
|
|
86
82
|
border-color: var(--st-color-primary);
|
|
87
83
|
box-shadow: 0 0 0 1px var(--st-color-primary);
|
|
88
84
|
}
|
|
89
85
|
|
|
90
|
-
/* 3. The actual input becomes transparent and fills the wrapper */
|
|
91
86
|
input {
|
|
92
87
|
flex: 1;
|
|
93
88
|
width: 100%;
|
|
94
89
|
border: none;
|
|
95
90
|
background: transparent;
|
|
96
91
|
outline: none;
|
|
97
|
-
|
|
98
|
-
/* Vertical padding stretches the wrapper */
|
|
99
92
|
padding: var(--st-spacing-sm) 0;
|
|
100
93
|
font-size: var(--st-font-size-base);
|
|
101
94
|
color: var(--st-color-text);
|
|
@@ -105,92 +98,98 @@ export class StInput extends LitElement {
|
|
|
105
98
|
color: var(--st-color-text-muted);
|
|
106
99
|
}
|
|
107
100
|
|
|
108
|
-
/* Slotted Icons */
|
|
109
101
|
::slotted(svg) {
|
|
110
102
|
width: 1.25em;
|
|
111
103
|
height: 1.25em;
|
|
112
|
-
/* Default icons to the muted text color */
|
|
113
104
|
color: var(--st-color-text-muted);
|
|
114
105
|
fill: currentColor;
|
|
115
106
|
flex-shrink: 0;
|
|
116
107
|
}
|
|
117
108
|
|
|
118
|
-
/* Interactive Slotted Elements (like clear buttons) */
|
|
119
109
|
::slotted(st-button) {
|
|
120
|
-
/* Pull the button back slightly so it aligns nicely with the input padding */
|
|
121
110
|
margin-right: calc(var(--st-spacing-sm) * -1);
|
|
122
111
|
}
|
|
123
112
|
|
|
124
|
-
|
|
113
|
+
.help-text {
|
|
114
|
+
font-size: var(--st-font-size-xs);
|
|
115
|
+
color: var(--st-color-text-muted);
|
|
116
|
+
margin: 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* 🚀 NEW: Explicit error text styling */
|
|
120
|
+
.error-text {
|
|
121
|
+
font-size: var(--st-font-size-xs);
|
|
122
|
+
color: var(--st-color-error, #dc2626);
|
|
123
|
+
margin: 0;
|
|
124
|
+
font-weight: 500;
|
|
125
|
+
}
|
|
126
|
+
|
|
125
127
|
:host([invalid]) .input-wrapper {
|
|
126
|
-
border-color: var(--st-color-error);
|
|
128
|
+
border-color: var(--st-color-error, #dc2626);
|
|
127
129
|
}
|
|
130
|
+
|
|
128
131
|
:host([invalid]) .input-wrapper:focus-within {
|
|
129
|
-
box-shadow: 0 0 0 1px var(--st-color-error);
|
|
132
|
+
box-shadow: 0 0 0 1px var(--st-color-error, #dc2626);
|
|
130
133
|
}
|
|
134
|
+
|
|
131
135
|
:host([invalid]) .help-text {
|
|
132
|
-
color: var(--st-color-error);
|
|
136
|
+
color: var(--st-color-error, #dc2626);
|
|
133
137
|
}
|
|
134
138
|
|
|
135
|
-
/* Disabled & Readonly States */
|
|
136
139
|
:host([disabled]) .input-wrapper {
|
|
137
140
|
opacity: 0.5;
|
|
138
141
|
cursor: not-allowed;
|
|
139
142
|
background-color: var(--st-color-surface);
|
|
140
143
|
}
|
|
144
|
+
|
|
141
145
|
:host([disabled]) input {
|
|
142
146
|
cursor: not-allowed;
|
|
143
147
|
}
|
|
148
|
+
|
|
144
149
|
:host([readonly]) .input-wrapper {
|
|
145
150
|
background-color: var(--st-color-surface);
|
|
146
151
|
}
|
|
147
|
-
|
|
148
|
-
.help-text {
|
|
149
|
-
font-size: var(--st-font-size-xs);
|
|
150
|
-
color: var(--st-color-text-muted);
|
|
151
|
-
margin: 0;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
:host([invalid]) .input-wrapper {
|
|
155
|
-
border-color: var(--st-color-error);
|
|
156
|
-
}
|
|
157
|
-
:host([invalid]) .help-text {
|
|
158
|
-
color: var(--st-color-error);
|
|
159
|
-
}
|
|
160
152
|
`,
|
|
161
153
|
];
|
|
162
154
|
|
|
163
155
|
override updated(changedProperties: PropertyValues<this>) {
|
|
164
156
|
super.updated(changedProperties);
|
|
165
157
|
|
|
166
|
-
// Sync the value to the form engine
|
|
167
158
|
if (changedProperties.has("value")) {
|
|
168
159
|
this._internals.setFormValue(this.value);
|
|
169
160
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
161
|
+
|
|
162
|
+
if (changedProperties.has("value") || changedProperties.has("error") || changedProperties.has("required")) {
|
|
163
|
+
this._syncValidity();
|
|
164
|
+
}
|
|
173
165
|
}
|
|
174
166
|
|
|
175
167
|
private _syncValidity() {
|
|
176
168
|
if (!this._inputEl) return;
|
|
169
|
+
|
|
170
|
+
if (this.error) {
|
|
171
|
+
this._internals.setValidity({ customError: true }, this.error, this._inputEl);
|
|
172
|
+
this.invalid = true;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
177
175
|
|
|
178
|
-
// setValidity arguments: (ValidityState object, Custom Error Message, Anchor Element for Tooltip)
|
|
179
176
|
this._internals.setValidity(
|
|
180
177
|
this._inputEl.validity,
|
|
181
178
|
this._inputEl.validationMessage,
|
|
182
179
|
this._inputEl,
|
|
183
180
|
);
|
|
181
|
+
|
|
182
|
+
if (this.invalid && this._inputEl.validity.valid) {
|
|
183
|
+
this.invalid = false;
|
|
184
|
+
}
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
formResetCallback() {
|
|
187
188
|
this.value = "";
|
|
188
189
|
this._internals.setFormValue("");
|
|
189
|
-
// Need to wait for the render cycle to finish before checking validity on reset
|
|
190
190
|
this.updateComplete.then(() => this._syncValidity());
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
// Expose standard native methods so external scripts can call them on the component
|
|
194
193
|
checkValidity() {
|
|
195
194
|
return this._internals.checkValidity();
|
|
196
195
|
}
|
|
@@ -200,10 +199,10 @@ export class StInput extends LitElement {
|
|
|
200
199
|
}
|
|
201
200
|
|
|
202
201
|
private _handleInput(e: Event) {
|
|
203
|
-
const target = e.target as
|
|
202
|
+
const target = e.target as HTMLInputElement;
|
|
204
203
|
this.value = target.value;
|
|
205
204
|
|
|
206
|
-
if (this.invalid && target.validity.valid) {
|
|
205
|
+
if (this.invalid && target.validity.valid && !this.error) {
|
|
207
206
|
this.invalid = false;
|
|
208
207
|
}
|
|
209
208
|
|
|
@@ -215,6 +214,12 @@ export class StInput extends LitElement {
|
|
|
215
214
|
}
|
|
216
215
|
|
|
217
216
|
render() {
|
|
217
|
+
const descriptionId = this.error ? "error-text" : (this.helpText ? "help-text" : undefined);
|
|
218
|
+
|
|
219
|
+
const isSensitive = this.type === "password" || this.type === "email";
|
|
220
|
+
const safeSpellcheck = isSensitive ? "false" : undefined;
|
|
221
|
+
const safeAutocapitalize = isSensitive ? "none" : undefined;
|
|
222
|
+
|
|
218
223
|
return html`
|
|
219
224
|
<div class="form-control">
|
|
220
225
|
${this.label ? html`<label for="input">${this.label}</label>` : ""}
|
|
@@ -234,6 +239,11 @@ export class StInput extends LitElement {
|
|
|
234
239
|
minlength=${ifDefined(this.minlength)}
|
|
235
240
|
maxlength=${ifDefined(this.maxlength)}
|
|
236
241
|
pattern=${ifDefined(this.pattern)}
|
|
242
|
+
autocomplete=${ifDefined(this.autocomplete as any)}
|
|
243
|
+
spellcheck=${ifDefined(safeSpellcheck)}
|
|
244
|
+
autocapitalize=${ifDefined(safeAutocapitalize)}
|
|
245
|
+
aria-invalid=${this.invalid ? "true" : "false"}
|
|
246
|
+
aria-describedby=${ifDefined(descriptionId)}
|
|
237
247
|
@input=${this._handleInput}
|
|
238
248
|
@change=${this._handleChange}
|
|
239
249
|
/>
|
|
@@ -241,7 +251,11 @@ export class StInput extends LitElement {
|
|
|
241
251
|
<slot name="suffix"></slot>
|
|
242
252
|
</div>
|
|
243
253
|
|
|
244
|
-
${this.
|
|
254
|
+
${this.error
|
|
255
|
+
? html`<div id="error-text" class="error-text">${this.error}</div>`
|
|
256
|
+
: this.helpText
|
|
257
|
+
? html`<div id="help-text" class="help-text">${this.helpText}</div>`
|
|
258
|
+
: ""}
|
|
245
259
|
</div>
|
|
246
260
|
`;
|
|
247
261
|
}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {LitElement, html, css} from "lit";
|
|
2
|
+
import {customElement, property} from "lit/decorators.js";
|
|
3
|
+
import {ifDefined} from "lit/directives/if-defined.js";
|
|
4
|
+
import {resetStyles} from "../../styles/reset.js";
|
|
4
5
|
|
|
5
|
-
@customElement(
|
|
6
|
+
@customElement("st-link")
|
|
6
7
|
export class StLink extends LitElement {
|
|
7
|
-
@property({
|
|
8
|
-
@property({
|
|
9
|
-
@property({
|
|
10
|
-
@property({
|
|
11
|
-
@property({
|
|
8
|
+
@property({type: String}) href = "#";
|
|
9
|
+
@property({type: String}) target: "_blank" | "_self" = "_self";
|
|
10
|
+
@property({type: String, reflect: true}) size: "sm" | "md" | "lg" = "md";
|
|
11
|
+
@property({type: String, reflect: true}) variant: "inline" | "standalone" = "inline";
|
|
12
|
+
@property({type: String, reflect: true}) color: "default" | "primary" | "muted" = "primary";
|
|
12
13
|
|
|
13
14
|
static styles = [
|
|
14
15
|
resetStyles,
|
|
15
16
|
css`
|
|
16
17
|
:host {
|
|
17
18
|
display: inline-flex;
|
|
18
|
-
align-items:
|
|
19
|
+
align-items: baseline; /* Ensures it sits perfectly inside a line of text */
|
|
20
|
+
vertical-align: baseline;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
a {
|
|
@@ -24,7 +26,17 @@ export class StLink extends LitElement {
|
|
|
24
26
|
gap: 0.25em;
|
|
25
27
|
text-decoration: none;
|
|
26
28
|
font-weight: 500;
|
|
27
|
-
transition:
|
|
29
|
+
transition:
|
|
30
|
+
color 0.2s ease,
|
|
31
|
+
opacity 0.2s ease,
|
|
32
|
+
text-decoration-thickness 0.2s ease;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Accessibility: Clear focus indicators for keyboard navigation */
|
|
36
|
+
a:focus-visible {
|
|
37
|
+
outline: 2px solid var(--st-color-primary);
|
|
38
|
+
outline-offset: 2px;
|
|
39
|
+
border-radius: 2px;
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
/* ==========================================================
|
|
@@ -54,24 +66,28 @@ export class StLink extends LitElement {
|
|
|
54
66
|
/* ==========================================================
|
|
55
67
|
Sizes
|
|
56
68
|
========================================================== */
|
|
57
|
-
:host([size="sm"]) a {
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
:host([size="sm"]) a {
|
|
70
|
+
font-size: 0.875rem;
|
|
71
|
+
}
|
|
72
|
+
:host([size="md"]) a {
|
|
73
|
+
font-size: 1rem;
|
|
74
|
+
}
|
|
75
|
+
:host([size="lg"]) a {
|
|
76
|
+
font-size: 1.125rem;
|
|
77
|
+
}
|
|
60
78
|
|
|
61
79
|
/* ==========================================================
|
|
62
80
|
Variants
|
|
63
81
|
========================================================== */
|
|
64
|
-
/* inline links live inside paragraphs and underline on hover */
|
|
65
82
|
:host([variant="inline"]) a {
|
|
66
83
|
text-decoration: underline;
|
|
67
84
|
text-underline-offset: 4px;
|
|
68
|
-
font-weight: inherit;
|
|
85
|
+
font-weight: inherit;
|
|
69
86
|
}
|
|
70
87
|
:host([variant="inline"]) a:hover {
|
|
71
88
|
text-decoration-thickness: 2px;
|
|
72
89
|
}
|
|
73
90
|
|
|
74
|
-
/* standalone links (e.g., footers, sidebars) have no underline by default */
|
|
75
91
|
:host([variant="standalone"]) a {
|
|
76
92
|
text-decoration: none;
|
|
77
93
|
}
|
|
@@ -79,12 +95,20 @@ export class StLink extends LitElement {
|
|
|
79
95
|
text-decoration: underline;
|
|
80
96
|
text-underline-offset: 4px;
|
|
81
97
|
}
|
|
82
|
-
|
|
98
|
+
`,
|
|
83
99
|
];
|
|
84
100
|
|
|
85
101
|
render() {
|
|
102
|
+
// SECURITY: Prevent XSS via javascript: URI injection
|
|
103
|
+
const sanitizedHref = this.href?.trim().toLowerCase().startsWith("javascript:")
|
|
104
|
+
? "#blocked"
|
|
105
|
+
: this.href;
|
|
106
|
+
|
|
107
|
+
// SECURITY: Prevent Reverse Tabnabbing for external links
|
|
108
|
+
const secureRel = this.target === "_blank" ? "noopener noreferrer" : undefined;
|
|
109
|
+
|
|
86
110
|
return html`
|
|
87
|
-
<a href="${
|
|
111
|
+
<a href="${sanitizedHref}" target="${this.target}" rel="${ifDefined(secureRel)}">
|
|
88
112
|
<slot></slot>
|
|
89
113
|
</a>
|
|
90
114
|
`;
|
|
@@ -93,6 +117,6 @@ export class StLink extends LitElement {
|
|
|
93
117
|
|
|
94
118
|
declare global {
|
|
95
119
|
interface HTMLElementTagNameMap {
|
|
96
|
-
|
|
120
|
+
"st-link": StLink;
|
|
97
121
|
}
|
|
98
|
-
}
|
|
122
|
+
}
|
|
@@ -1,58 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import {LitElement, nothing, PropertyValues} from "lit";
|
|
2
|
+
import {customElement, property} from "lit/decorators.js";
|
|
3
3
|
|
|
4
|
-
@customElement(
|
|
4
|
+
@customElement("st-metadata")
|
|
5
5
|
export class StMetadata extends LitElement {
|
|
6
|
-
@property({
|
|
7
|
-
@property({
|
|
8
|
-
@property({
|
|
6
|
+
@property({type: String}) pageTitle = "";
|
|
7
|
+
@property({type: String}) description = "";
|
|
8
|
+
@property({type: String}) image = "";
|
|
9
9
|
|
|
10
|
-
protected createRenderRoot() {
|
|
10
|
+
protected createRenderRoot() {
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
// 🚀 Added strict PropertyValues typing and super call
|
|
15
|
+
override updated(changedProperties: PropertyValues<this>) {
|
|
16
|
+
super.updated(changedProperties);
|
|
13
17
|
this._updateMetadata();
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
private _updateMetadata() {
|
|
17
|
-
|
|
18
|
-
const siteName = (import.meta as any).env?.VITE_SITE_NAME || '';
|
|
21
|
+
const siteName = (import.meta as any).env?.VITE_SITE_NAME || "";
|
|
19
22
|
|
|
20
23
|
if (this.pageTitle) {
|
|
21
|
-
// If site name is configured, append it; otherwise use the title standalone
|
|
22
24
|
document.title = siteName ? `${this.pageTitle} - ${siteName}` : this.pageTitle;
|
|
23
|
-
this._setMeta(
|
|
25
|
+
this._setMeta("property", "og:title", this.pageTitle);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
if (this.description) {
|
|
27
|
-
this._setMeta(
|
|
28
|
-
this._setMeta(
|
|
29
|
+
this._setMeta("name", "description", this.description);
|
|
30
|
+
this._setMeta("property", "og:description", this.description);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
if (this.image) {
|
|
32
|
-
this._setMeta(
|
|
34
|
+
this._setMeta("property", "og:image", this.image);
|
|
33
35
|
}
|
|
34
|
-
|
|
36
|
+
|
|
35
37
|
this._setCanonical(window.location.href);
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
private _setMeta(attrName:
|
|
40
|
+
private _setMeta(attrName: "name" | "property", attrValue: string, content: string) {
|
|
39
41
|
let meta = document.head.querySelector(`meta[${attrName}="${attrValue}"]`);
|
|
40
42
|
if (!meta) {
|
|
41
|
-
meta = document.createElement(
|
|
43
|
+
meta = document.createElement("meta");
|
|
42
44
|
meta.setAttribute(attrName, attrValue);
|
|
43
45
|
document.head.appendChild(meta);
|
|
44
46
|
}
|
|
45
|
-
meta.setAttribute(
|
|
47
|
+
meta.setAttribute("content", content);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
private _setCanonical(url: string) {
|
|
49
51
|
let link = document.head.querySelector('link[rel="canonical"]');
|
|
50
52
|
if (!link) {
|
|
51
|
-
link = document.createElement(
|
|
52
|
-
link.setAttribute(
|
|
53
|
+
link = document.createElement("link");
|
|
54
|
+
link.setAttribute("rel", "canonical");
|
|
53
55
|
document.head.appendChild(link);
|
|
54
56
|
}
|
|
55
|
-
link.setAttribute(
|
|
57
|
+
link.setAttribute("href", url);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
render() {
|
|
@@ -62,6 +64,6 @@ export class StMetadata extends LitElement {
|
|
|
62
64
|
|
|
63
65
|
declare global {
|
|
64
66
|
interface HTMLElementTagNameMap {
|
|
65
|
-
|
|
67
|
+
"st-metadata": StMetadata;
|
|
66
68
|
}
|
|
67
|
-
}
|
|
69
|
+
}
|