@sondor-technology/sondor-components 1.0.0 → 1.0.1-develop.2

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.
Files changed (168) hide show
  1. package/README.md +8 -0
  2. package/dist/components/alert/alert.d.ts +13 -0
  3. package/dist/components/alert/alert.d.ts.map +1 -0
  4. package/dist/components/alert/alert.js +105 -0
  5. package/dist/components/badge/badge.d.ts +13 -0
  6. package/dist/components/badge/badge.d.ts.map +1 -0
  7. package/dist/components/badge/badge.js +101 -0
  8. package/dist/components/breadcrumb/breadcrumb.d.ts +19 -0
  9. package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -0
  10. package/dist/components/breadcrumb/breadcrumb.js +99 -0
  11. package/dist/components/button/button.d.ts +23 -0
  12. package/dist/components/button/button.d.ts.map +1 -0
  13. package/dist/components/button/button.js +304 -0
  14. package/dist/components/button-group/button-group.d.ts +6 -0
  15. package/dist/components/button-group/button-group.d.ts.map +1 -0
  16. package/dist/components/button-group/button-group.js +74 -0
  17. package/dist/components/card/card.d.ts +11 -0
  18. package/dist/components/card/card.d.ts.map +1 -0
  19. package/dist/components/card/card.js +54 -0
  20. package/dist/components/checkbox/checkbox.d.ts +28 -0
  21. package/dist/components/checkbox/checkbox.d.ts.map +1 -0
  22. package/dist/components/checkbox/checkbox.js +247 -0
  23. package/dist/components/code-block/code-block.d.ts +20 -0
  24. package/dist/components/code-block/code-block.d.ts.map +1 -0
  25. package/dist/components/code-block/code-block.js +260 -0
  26. package/dist/components/content-card/content-card.d.ts +13 -0
  27. package/dist/components/content-card/content-card.d.ts.map +1 -0
  28. package/dist/components/content-card/content-card.js +140 -0
  29. package/dist/components/divider/divider.d.ts +16 -0
  30. package/dist/components/divider/divider.d.ts.map +1 -0
  31. package/dist/components/divider/divider.js +82 -0
  32. package/dist/components/drawer/drawer.d.ts +22 -0
  33. package/dist/components/drawer/drawer.d.ts.map +1 -0
  34. package/dist/components/drawer/drawer.js +226 -0
  35. package/dist/components/field/field.d.ts +11 -0
  36. package/dist/components/field/field.d.ts.map +1 -0
  37. package/dist/components/field/field.js +32 -0
  38. package/dist/components/footer/footer.d.ts +6 -0
  39. package/dist/components/footer/footer.d.ts.map +1 -0
  40. package/dist/components/footer/footer.js +65 -0
  41. package/dist/components/form/form-step.d.ts +13 -0
  42. package/dist/components/form/form-step.d.ts.map +1 -0
  43. package/dist/components/form/form-step.js +41 -0
  44. package/dist/components/form/form.d.ts +25 -0
  45. package/dist/components/form/form.d.ts.map +1 -0
  46. package/dist/components/form/form.js +358 -0
  47. package/dist/components/grid/grid-row.d.ts +17 -0
  48. package/dist/components/grid/grid-row.d.ts.map +1 -0
  49. package/dist/components/grid/grid-row.js +92 -0
  50. package/dist/components/grid/grid.d.ts +13 -0
  51. package/dist/components/grid/grid.d.ts.map +1 -0
  52. package/dist/components/grid/grid.js +42 -0
  53. package/dist/components/icon/icon-paths.d.ts +116 -0
  54. package/dist/components/icon/icon-paths.d.ts.map +1 -0
  55. package/dist/components/icon/icon-paths.js +121 -0
  56. package/dist/components/icon/icon.d.ts +16 -0
  57. package/dist/components/icon/icon.d.ts.map +1 -0
  58. package/dist/components/icon/icon.js +95 -0
  59. package/dist/components/input/input.d.ts +31 -0
  60. package/dist/components/input/input.d.ts.map +1 -0
  61. package/dist/components/input/input.js +268 -0
  62. package/dist/components/link/link.d.ts +16 -0
  63. package/dist/components/link/link.d.ts.map +1 -0
  64. package/dist/components/link/link.js +116 -0
  65. package/dist/components/metadata/metadata.d.ts +18 -0
  66. package/dist/components/metadata/metadata.d.ts.map +1 -0
  67. package/dist/components/metadata/metadata.js +71 -0
  68. package/dist/components/modal/modal.d.ts +24 -0
  69. package/dist/components/modal/modal.d.ts.map +1 -0
  70. package/dist/components/modal/modal.js +163 -0
  71. package/dist/components/page-layout/page-layout.d.ts +46 -0
  72. package/dist/components/page-layout/page-layout.d.ts.map +1 -0
  73. package/dist/components/page-layout/page-layout.js +697 -0
  74. package/dist/components/radio/radio.d.ts +16 -0
  75. package/dist/components/radio/radio.d.ts.map +1 -0
  76. package/dist/components/radio/radio.js +152 -0
  77. package/dist/components/radio-group/radio-group.d.ts +27 -0
  78. package/dist/components/radio-group/radio-group.d.ts.map +1 -0
  79. package/dist/components/radio-group/radio-group.js +161 -0
  80. package/dist/components/router/router.d.ts +7 -0
  81. package/dist/components/router/router.d.ts.map +1 -0
  82. package/dist/components/router/router.js +37 -0
  83. package/dist/components/select/select.d.ts +16 -0
  84. package/dist/components/select/select.d.ts.map +1 -0
  85. package/dist/components/select/select.js +172 -0
  86. package/dist/components/skeleton/skeleton.d.ts +17 -0
  87. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  88. package/dist/components/skeleton/skeleton.js +78 -0
  89. package/dist/components/switch/switch.d.ts +25 -0
  90. package/dist/components/switch/switch.d.ts.map +1 -0
  91. package/dist/components/switch/switch.js +185 -0
  92. package/dist/components/table/data-table.d.ts +72 -0
  93. package/dist/components/table/data-table.d.ts.map +1 -0
  94. package/dist/components/table/data-table.js +551 -0
  95. package/dist/components/table/table.d.ts +22 -0
  96. package/dist/components/table/table.d.ts.map +1 -0
  97. package/dist/components/table/table.js +167 -0
  98. package/dist/components/tabs/tab-panel.d.ts +8 -0
  99. package/dist/components/tabs/tab-panel.d.ts.map +1 -0
  100. package/dist/components/tabs/tab-panel.js +46 -0
  101. package/dist/components/tabs/tab.d.ts +9 -0
  102. package/dist/components/tabs/tab.d.ts.map +1 -0
  103. package/dist/components/tabs/tab.js +91 -0
  104. package/dist/components/tabs/tabs.d.ts +14 -0
  105. package/dist/components/tabs/tabs.d.ts.map +1 -0
  106. package/dist/components/tabs/tabs.js +85 -0
  107. package/dist/components/textarea/textarea.d.ts +36 -0
  108. package/dist/components/textarea/textarea.d.ts.map +1 -0
  109. package/dist/components/textarea/textarea.js +231 -0
  110. package/dist/components/theme-toggle/theme-toggle.d.ts +15 -0
  111. package/dist/components/theme-toggle/theme-toggle.d.ts.map +1 -0
  112. package/dist/components/theme-toggle/theme-toggle.js +130 -0
  113. package/dist/components/vertical-nav/vertical-nav-group.d.ts +9 -0
  114. package/dist/components/vertical-nav/vertical-nav-group.d.ts.map +1 -0
  115. package/dist/components/vertical-nav/vertical-nav-group.js +111 -0
  116. package/dist/components/vertical-nav/vertical-nav-item.d.ts +8 -0
  117. package/dist/components/vertical-nav/vertical-nav-item.d.ts.map +1 -0
  118. package/dist/components/vertical-nav/vertical-nav-item.js +65 -0
  119. package/dist/styles/index.css +171 -0
  120. package/dist/styles/reset.d.ts +2 -0
  121. package/dist/styles/reset.d.ts.map +1 -0
  122. package/dist/styles/reset.js +50 -0
  123. package/package.json +3 -2
  124. package/src/components/alert/alert.ts +100 -100
  125. package/src/components/badge/badge.ts +96 -96
  126. package/src/components/breadcrumb/breadcrumb.ts +98 -98
  127. package/src/components/button/button.ts +281 -281
  128. package/src/components/button-group/button-group.ts +67 -67
  129. package/src/components/card/card.ts +52 -52
  130. package/src/components/checkbox/checkbox.ts +238 -238
  131. package/src/components/code-block/code-block.ts +256 -256
  132. package/src/components/content-card/content-card.ts +133 -133
  133. package/src/components/divider/divider.ts +68 -68
  134. package/src/components/drawer/drawer.ts +217 -217
  135. package/src/components/field/field.ts +30 -30
  136. package/src/components/footer/footer.ts +58 -58
  137. package/src/components/form/form-step.ts +32 -32
  138. package/src/components/form/form.ts +376 -376
  139. package/src/components/grid/grid-row.ts +75 -75
  140. package/src/components/grid/grid.ts +36 -36
  141. package/src/components/icon/icon-paths.ts +124 -124
  142. package/src/components/icon/icon.ts +82 -82
  143. package/src/components/input/input.ts +248 -248
  144. package/src/components/link/link.ts +97 -97
  145. package/src/components/metadata/metadata.ts +66 -66
  146. package/src/components/modal/modal.ts +158 -158
  147. package/src/components/page-layout/page-layout.ts +704 -704
  148. package/src/components/radio/radio.ts +142 -142
  149. package/src/components/radio-group/radio-group.ts +157 -157
  150. package/src/components/router/router.ts +46 -46
  151. package/src/components/select/select.ts +161 -161
  152. package/src/components/skeleton/skeleton.ts +67 -67
  153. package/src/components/switch/switch.ts +181 -181
  154. package/src/components/table/data-table.ts +556 -556
  155. package/src/components/table/table.ts +153 -153
  156. package/src/components/tabs/tab-panel.ts +30 -30
  157. package/src/components/tabs/tab.ts +76 -76
  158. package/src/components/tabs/tabs.ts +88 -88
  159. package/src/components/textarea/textarea.ts +215 -215
  160. package/src/components/theme-toggle/theme-toggle.ts +131 -131
  161. package/src/components/vertical-nav/vertical-nav-group.ts +96 -96
  162. package/src/components/vertical-nav/vertical-nav-item.ts +49 -49
  163. package/src/styles/globals.css +58 -58
  164. package/src/styles/index.css +80 -80
  165. package/src/styles/reset.ts +50 -50
  166. package/src/styles/theme.css +58 -58
  167. package/src/styles/typography.css +25 -25
  168. package/tsconfig.json +15 -15
@@ -1,281 +1,281 @@
1
- import {LitElement, html, css, nothing} from "lit";
2
- import {customElement, property} from "lit/decorators.js";
3
- import {resetStyles} from "../../styles/reset.js";
4
-
5
- export type ButtonVariant = "primary" | "secondary" | "outline";
6
- export type ButtonSize = "sm" | "md" | "lg";
7
- export type ButtonColor = "primary" | "error" | "success" | "warning" | "info";
8
-
9
- @customElement("st-button")
10
- export class StButton extends LitElement {
11
- @property({type: String}) href?: string;
12
- @property({type: String}) target: "_blank" | "_self" = "_self";
13
- @property({type: Boolean, reflect: true}) disabled = false;
14
- @property({type: Boolean, reflect: true}) loading = false;
15
- @property({type: String, reflect: true}) variant: ButtonVariant = "primary";
16
- @property({type: String, reflect: true}) size: ButtonSize = "md";
17
- @property({type: String, reflect: true}) color: ButtonColor = "primary";
18
- @property({ type: Boolean, reflect: true }) active = false;
19
- @property({ type: String, attribute: 'aria-label' }) ariaLabel: string | null = null;
20
-
21
- static styles = [
22
- resetStyles,
23
- css`
24
- :host {
25
- /* ==========================================================
26
- 1. Base Palette (Defaults to Primary Theme)
27
- ========================================================== */
28
- --_palette-base: var(--st-color-primary);
29
- --_palette-hover: var(--st-color-primary-hover);
30
- --_palette-surface: var(--st-color-surface);
31
- --_palette-surface-hover: var(--st-color-border);
32
-
33
- --_palette-text-on-base: var(--st-color-surface);
34
- --_palette-text-on-surface: var(--st-color-text);
35
-
36
- /* Sizing Tokens */
37
- --_btn-padding: var(--st-spacing-sm) var(--st-spacing-md);
38
- --_btn-font-size: var(--st-font-size-sm);
39
- --_btn-radius: 4px;
40
- --_btn-gap: var(--st-spacing-sm);
41
-
42
- display: inline-block;
43
- }
44
-
45
- /* ==========================================================
46
- 2. Semantic Color Overrides (Swaps the active palette)
47
- ========================================================== */
48
- :host([color="error"]) {
49
- --_palette-base: var(--st-color-error);
50
- --_palette-hover: color-mix(in srgb, var(--st-color-error), black 15%);
51
- --_palette-surface: var(--st-color-error-bg);
52
- --_palette-surface-hover: color-mix(in srgb, var(--st-color-error-bg), black 10%);
53
- --_palette-text-on-base: var(--st-white); /* Force white text */
54
- --_palette-text-on-surface: var(--st-color-error);
55
- }
56
-
57
- :host([color="success"]) {
58
- --_palette-base: var(--st-color-success);
59
- --_palette-hover: color-mix(in srgb, var(--st-color-success), black 15%);
60
- --_palette-surface: var(--st-color-success-bg);
61
- --_palette-surface-hover: color-mix(in srgb, var(--st-color-success-bg), black 10%);
62
- --_palette-text-on-base: var(--st-white);
63
- --_palette-text-on-surface: var(--st-color-success);
64
- }
65
-
66
- :host([color="warning"]) {
67
- --_palette-base: var(--st-color-warning);
68
- --_palette-hover: color-mix(in srgb, var(--st-color-warning), black 15%);
69
- --_palette-surface: var(--st-color-warning-bg);
70
- --_palette-surface-hover: color-mix(in srgb, var(--st-color-warning-bg), black 10%);
71
- --_palette-text-on-base: var(--st-gray-900); /* Amber needs dark text for contrast */
72
- --_palette-text-on-surface: var(--st-color-warning);
73
- }
74
-
75
- :host([color="info"]) {
76
- --_palette-base: var(--st-color-info);
77
- --_palette-hover: color-mix(in srgb, var(--st-color-info), black 15%);
78
- --_palette-surface: var(--st-color-info-bg);
79
- --_palette-surface-hover: color-mix(in srgb, var(--st-color-info-bg), black 10%);
80
- --_palette-text-on-base: var(--st-white);
81
- --_palette-text-on-surface: var(--st-color-info);
82
- }
83
-
84
- /* ==========================================================
85
- 3. Visual Variants (Consumes the active palette)
86
- ========================================================== */
87
-
88
- /* Base (Primary / Solid) */
89
- :host {
90
- --_btn-bg: var(--_palette-base);
91
- --_btn-bg-hover: var(--_palette-hover);
92
- --_btn-text: var(--_palette-text-on-base);
93
- --_btn-border: transparent;
94
- }
95
-
96
- /* Secondary Variant */
97
- :host([variant="secondary"]) {
98
- --_btn-bg: var(--_palette-surface);
99
- --_btn-bg-hover: var(--_palette-surface-hover);
100
- --_btn-text: var(--_palette-text-on-surface);
101
- --_btn-border: transparent;
102
- }
103
-
104
- /* Outline Variant */
105
- :host([variant="outline"]) {
106
- --_btn-bg: transparent;
107
- --_btn-bg-hover: var(--_palette-surface);
108
- --_btn-text: var(--_palette-base);
109
- --_btn-border: var(--_palette-base);
110
- }
111
-
112
- /* ==========================================================
113
- 4. Size Variants
114
- ========================================================== */
115
- :host([size="sm"]) {
116
- --_btn-padding: var(--st-spacing-xs) var(--st-spacing-sm);
117
- --_btn-font-size: var(--st-font-size-xs);
118
- --_btn-radius: 2px;
119
- --_btn-gap: var(--st-spacing-xs);
120
- }
121
-
122
- :host([size="lg"]) {
123
- --_btn-padding: var(--st-spacing-md) var(--st-spacing-lg);
124
- --_btn-font-size: var(--st-font-size-base);
125
- --_btn-radius: 6px;
126
- --_btn-gap: var(--st-spacing-sm);
127
- }
128
-
129
- /* ==========================================================
130
- 5. Base Button Rules
131
- ========================================================== */
132
- .btn {
133
- display: inline-flex;
134
- align-items: center;
135
- justify-content: center;
136
- gap: var(--_btn-gap);
137
-
138
- background-color: var(--_btn-bg);
139
- color: var(--_btn-text);
140
- border: 1px solid var(--_btn-border);
141
- padding: var(--_btn-padding);
142
- font-size: var(--_btn-font-size);
143
- border-radius: var(--_btn-radius);
144
- line-height: 1;
145
-
146
- cursor: pointer;
147
- font-weight: var(--st-font-weight-medium);
148
- transition: all 0.2s ease;
149
- padding: 0.5rem 1rem;
150
-
151
- /* 1. Split the border radius into 4 independent corners */
152
- border-radius: var(--btn-radius-tl, var(--st-radius-md, 0.5rem))
153
- var(--btn-radius-tr, var(--st-radius-md, 0.5rem))
154
- var(--btn-radius-br, var(--st-radius-md, 0.5rem))
155
- var(--btn-radius-bl, var(--st-radius-md, 0.5rem));
156
-
157
- /* 2. Add a hook for the group wrapper to inject a divider line */
158
- box-shadow: var(--btn-divider, none);
159
-
160
- font-weight: 500;
161
- text-decoration: none;
162
- border: 1px solid transparent;
163
- }
164
-
165
- .btn:hover {
166
- color: var(--_btn-text);
167
- background-color: var(--_btn-bg-hover);
168
- }
169
-
170
- /* ==========================================================
171
- Logical Active States (Selected/Toggled)
172
- ========================================================== */
173
- :host([active]) .btn {
174
- filter: brightness(0.9);
175
- box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.2);
176
- border-color: transparent;
177
- color: var(--_btn-text);
178
- background-color: var(--_btn-bg-hover);
179
- }
180
-
181
- :host([active]) .btn[color="primary"] {
182
- filter: brightness(0.85);
183
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2); /* Inset shadow gives a pressed look */
184
- }
185
-
186
- /* ==========================================================
187
- Focus State (Accessibility)
188
- ========================================================== */
189
- /* focus-visible ensures this only shows for keyboard navigation, not mouse clicks */
190
- .btn:focus-visible {
191
- outline: 2px solid var(--st-color-primary);
192
- outline-offset: 2px;
193
- z-index: 1; /* Pulls the focused button forward if it's in a button group */
194
- }
195
-
196
- /* ==========================================================
197
- Physical Active State (Mouse down)
198
- ========================================================== */
199
- .btn:active {
200
- transform: scale(0.98);
201
- }
202
-
203
- /* Disabled & Loading */
204
- :host([disabled]),
205
- :host([loading]) {
206
- pointer-events: none;
207
- }
208
-
209
- :host([disabled]) button {
210
- opacity: 0.5;
211
- cursor: not-allowed;
212
- }
213
-
214
- :host([loading]) button {
215
- opacity: 0.8;
216
- }
217
-
218
- /* Icons & Spinner */
219
- ::slotted(svg),
220
- svg.spinner {
221
- width: 1.25em;
222
- height: 1.25em;
223
- fill: currentColor;
224
- flex-shrink: 0;
225
- }
226
-
227
- svg.spinner {
228
- animation: st-spin 1s linear infinite;
229
- }
230
-
231
- @keyframes st-spin {
232
- from {
233
- transform: rotate(0deg);
234
- }
235
- to {
236
- transform: rotate(360deg);
237
- }
238
- }
239
- `,
240
- ];
241
-
242
- render() {
243
- const content = html`<slot></slot>`;
244
-
245
- if (this.href) {
246
- return html`<a href="${this.href}" target="${this.target}" class="btn" color="${this.color}" aria-label=${this.ariaLabel || nothing}
247
- >${content}</a
248
- >`;
249
- }
250
-
251
- return html`
252
- <button class="btn" ?disabled=${this.disabled || this.loading}>
253
- ${this.loading
254
- ? html`
255
- <svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
256
- <path
257
- opacity="0.2"
258
- fill-rule="evenodd"
259
- clip-rule="evenodd"
260
- d="M12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19ZM12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
261
- fill="currentColor"
262
- />
263
- <path
264
- d="M2 12C2 6.47715 6.47715 2 12 2V5C8.13401 5 5 8.13401 5 12H2Z"
265
- fill="currentColor"
266
- />
267
- </svg>
268
- `
269
- : html`<slot name="prefix"></slot>`}
270
- ${content}
271
- <slot name="suffix"></slot>
272
- </button>
273
- `;
274
- }
275
- }
276
-
277
- declare global {
278
- interface HTMLElementTagNameMap {
279
- "st-button": StButton;
280
- }
281
- }
1
+ import {LitElement, html, css, nothing} from "lit";
2
+ import {customElement, property} from "lit/decorators.js";
3
+ import {resetStyles} from "../../styles/reset.js";
4
+
5
+ export type ButtonVariant = "primary" | "secondary" | "outline";
6
+ export type ButtonSize = "sm" | "md" | "lg";
7
+ export type ButtonColor = "primary" | "error" | "success" | "warning" | "info";
8
+
9
+ @customElement("st-button")
10
+ export class StButton extends LitElement {
11
+ @property({type: String}) href?: string;
12
+ @property({type: String}) target: "_blank" | "_self" = "_self";
13
+ @property({type: Boolean, reflect: true}) disabled = false;
14
+ @property({type: Boolean, reflect: true}) loading = false;
15
+ @property({type: String, reflect: true}) variant: ButtonVariant = "primary";
16
+ @property({type: String, reflect: true}) size: ButtonSize = "md";
17
+ @property({type: String, reflect: true}) color: ButtonColor = "primary";
18
+ @property({ type: Boolean, reflect: true }) active = false;
19
+ @property({ type: String, attribute: 'aria-label' }) ariaLabel: string | null = null;
20
+
21
+ static styles = [
22
+ resetStyles,
23
+ css`
24
+ :host {
25
+ /* ==========================================================
26
+ 1. Base Palette (Defaults to Primary Theme)
27
+ ========================================================== */
28
+ --_palette-base: var(--st-color-primary);
29
+ --_palette-hover: var(--st-color-primary-hover);
30
+ --_palette-surface: var(--st-color-surface);
31
+ --_palette-surface-hover: var(--st-color-border);
32
+
33
+ --_palette-text-on-base: var(--st-color-surface);
34
+ --_palette-text-on-surface: var(--st-color-text);
35
+
36
+ /* Sizing Tokens */
37
+ --_btn-padding: var(--st-spacing-sm) var(--st-spacing-md);
38
+ --_btn-font-size: var(--st-font-size-sm);
39
+ --_btn-radius: 4px;
40
+ --_btn-gap: var(--st-spacing-sm);
41
+
42
+ display: inline-block;
43
+ }
44
+
45
+ /* ==========================================================
46
+ 2. Semantic Color Overrides (Swaps the active palette)
47
+ ========================================================== */
48
+ :host([color="error"]) {
49
+ --_palette-base: var(--st-color-error);
50
+ --_palette-hover: color-mix(in srgb, var(--st-color-error), black 15%);
51
+ --_palette-surface: var(--st-color-error-bg);
52
+ --_palette-surface-hover: color-mix(in srgb, var(--st-color-error-bg), black 10%);
53
+ --_palette-text-on-base: var(--st-white); /* Force white text */
54
+ --_palette-text-on-surface: var(--st-color-error);
55
+ }
56
+
57
+ :host([color="success"]) {
58
+ --_palette-base: var(--st-color-success);
59
+ --_palette-hover: color-mix(in srgb, var(--st-color-success), black 15%);
60
+ --_palette-surface: var(--st-color-success-bg);
61
+ --_palette-surface-hover: color-mix(in srgb, var(--st-color-success-bg), black 10%);
62
+ --_palette-text-on-base: var(--st-white);
63
+ --_palette-text-on-surface: var(--st-color-success);
64
+ }
65
+
66
+ :host([color="warning"]) {
67
+ --_palette-base: var(--st-color-warning);
68
+ --_palette-hover: color-mix(in srgb, var(--st-color-warning), black 15%);
69
+ --_palette-surface: var(--st-color-warning-bg);
70
+ --_palette-surface-hover: color-mix(in srgb, var(--st-color-warning-bg), black 10%);
71
+ --_palette-text-on-base: var(--st-gray-900); /* Amber needs dark text for contrast */
72
+ --_palette-text-on-surface: var(--st-color-warning);
73
+ }
74
+
75
+ :host([color="info"]) {
76
+ --_palette-base: var(--st-color-info);
77
+ --_palette-hover: color-mix(in srgb, var(--st-color-info), black 15%);
78
+ --_palette-surface: var(--st-color-info-bg);
79
+ --_palette-surface-hover: color-mix(in srgb, var(--st-color-info-bg), black 10%);
80
+ --_palette-text-on-base: var(--st-white);
81
+ --_palette-text-on-surface: var(--st-color-info);
82
+ }
83
+
84
+ /* ==========================================================
85
+ 3. Visual Variants (Consumes the active palette)
86
+ ========================================================== */
87
+
88
+ /* Base (Primary / Solid) */
89
+ :host {
90
+ --_btn-bg: var(--_palette-base);
91
+ --_btn-bg-hover: var(--_palette-hover);
92
+ --_btn-text: var(--_palette-text-on-base);
93
+ --_btn-border: transparent;
94
+ }
95
+
96
+ /* Secondary Variant */
97
+ :host([variant="secondary"]) {
98
+ --_btn-bg: var(--_palette-surface);
99
+ --_btn-bg-hover: var(--_palette-surface-hover);
100
+ --_btn-text: var(--_palette-text-on-surface);
101
+ --_btn-border: transparent;
102
+ }
103
+
104
+ /* Outline Variant */
105
+ :host([variant="outline"]) {
106
+ --_btn-bg: transparent;
107
+ --_btn-bg-hover: var(--_palette-surface);
108
+ --_btn-text: var(--_palette-base);
109
+ --_btn-border: var(--_palette-base);
110
+ }
111
+
112
+ /* ==========================================================
113
+ 4. Size Variants
114
+ ========================================================== */
115
+ :host([size="sm"]) {
116
+ --_btn-padding: var(--st-spacing-xs) var(--st-spacing-sm);
117
+ --_btn-font-size: var(--st-font-size-xs);
118
+ --_btn-radius: 2px;
119
+ --_btn-gap: var(--st-spacing-xs);
120
+ }
121
+
122
+ :host([size="lg"]) {
123
+ --_btn-padding: var(--st-spacing-md) var(--st-spacing-lg);
124
+ --_btn-font-size: var(--st-font-size-base);
125
+ --_btn-radius: 6px;
126
+ --_btn-gap: var(--st-spacing-sm);
127
+ }
128
+
129
+ /* ==========================================================
130
+ 5. Base Button Rules
131
+ ========================================================== */
132
+ .btn {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ gap: var(--_btn-gap);
137
+
138
+ background-color: var(--_btn-bg);
139
+ color: var(--_btn-text);
140
+ border: 1px solid var(--_btn-border);
141
+ padding: var(--_btn-padding);
142
+ font-size: var(--_btn-font-size);
143
+ border-radius: var(--_btn-radius);
144
+ line-height: 1;
145
+
146
+ cursor: pointer;
147
+ font-weight: var(--st-font-weight-medium);
148
+ transition: all 0.2s ease;
149
+ padding: 0.5rem 1rem;
150
+
151
+ /* 1. Split the border radius into 4 independent corners */
152
+ border-radius: var(--btn-radius-tl, var(--st-radius-md, 0.5rem))
153
+ var(--btn-radius-tr, var(--st-radius-md, 0.5rem))
154
+ var(--btn-radius-br, var(--st-radius-md, 0.5rem))
155
+ var(--btn-radius-bl, var(--st-radius-md, 0.5rem));
156
+
157
+ /* 2. Add a hook for the group wrapper to inject a divider line */
158
+ box-shadow: var(--btn-divider, none);
159
+
160
+ font-weight: 500;
161
+ text-decoration: none;
162
+ border: 1px solid transparent;
163
+ }
164
+
165
+ .btn:hover {
166
+ color: var(--_btn-text);
167
+ background-color: var(--_btn-bg-hover);
168
+ }
169
+
170
+ /* ==========================================================
171
+ Logical Active States (Selected/Toggled)
172
+ ========================================================== */
173
+ :host([active]) .btn {
174
+ filter: brightness(0.9);
175
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.2);
176
+ border-color: transparent;
177
+ color: var(--_btn-text);
178
+ background-color: var(--_btn-bg-hover);
179
+ }
180
+
181
+ :host([active]) .btn[color="primary"] {
182
+ filter: brightness(0.85);
183
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.2); /* Inset shadow gives a pressed look */
184
+ }
185
+
186
+ /* ==========================================================
187
+ Focus State (Accessibility)
188
+ ========================================================== */
189
+ /* focus-visible ensures this only shows for keyboard navigation, not mouse clicks */
190
+ .btn:focus-visible {
191
+ outline: 2px solid var(--st-color-primary);
192
+ outline-offset: 2px;
193
+ z-index: 1; /* Pulls the focused button forward if it's in a button group */
194
+ }
195
+
196
+ /* ==========================================================
197
+ Physical Active State (Mouse down)
198
+ ========================================================== */
199
+ .btn:active {
200
+ transform: scale(0.98);
201
+ }
202
+
203
+ /* Disabled & Loading */
204
+ :host([disabled]),
205
+ :host([loading]) {
206
+ pointer-events: none;
207
+ }
208
+
209
+ :host([disabled]) button {
210
+ opacity: 0.5;
211
+ cursor: not-allowed;
212
+ }
213
+
214
+ :host([loading]) button {
215
+ opacity: 0.8;
216
+ }
217
+
218
+ /* Icons & Spinner */
219
+ ::slotted(svg),
220
+ svg.spinner {
221
+ width: 1.25em;
222
+ height: 1.25em;
223
+ fill: currentColor;
224
+ flex-shrink: 0;
225
+ }
226
+
227
+ svg.spinner {
228
+ animation: st-spin 1s linear infinite;
229
+ }
230
+
231
+ @keyframes st-spin {
232
+ from {
233
+ transform: rotate(0deg);
234
+ }
235
+ to {
236
+ transform: rotate(360deg);
237
+ }
238
+ }
239
+ `,
240
+ ];
241
+
242
+ render() {
243
+ const content = html`<slot></slot>`;
244
+
245
+ if (this.href) {
246
+ return html`<a href="${this.href}" target="${this.target}" class="btn" color="${this.color}" aria-label=${this.ariaLabel || nothing}
247
+ >${content}</a
248
+ >`;
249
+ }
250
+
251
+ return html`
252
+ <button class="btn" ?disabled=${this.disabled || this.loading}>
253
+ ${this.loading
254
+ ? html`
255
+ <svg class="spinner" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
256
+ <path
257
+ opacity="0.2"
258
+ fill-rule="evenodd"
259
+ clip-rule="evenodd"
260
+ d="M12 19C15.866 19 19 15.866 19 12C19 8.13401 15.866 5 12 5C8.13401 5 5 8.13401 5 12C5 15.866 8.13401 19 12 19ZM12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"
261
+ fill="currentColor"
262
+ />
263
+ <path
264
+ d="M2 12C2 6.47715 6.47715 2 12 2V5C8.13401 5 5 8.13401 5 12H2Z"
265
+ fill="currentColor"
266
+ />
267
+ </svg>
268
+ `
269
+ : html`<slot name="prefix"></slot>`}
270
+ ${content}
271
+ <slot name="suffix"></slot>
272
+ </button>
273
+ `;
274
+ }
275
+ }
276
+
277
+ declare global {
278
+ interface HTMLElementTagNameMap {
279
+ "st-button": StButton;
280
+ }
281
+ }