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

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 +31 -0
  21. package/dist/components/checkbox/checkbox.d.ts.map +1 -0
  22. package/dist/components/checkbox/checkbox.js +265 -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 +14 -0
  42. package/dist/components/form/form-step.d.ts.map +1 -0
  43. package/dist/components/form/form-step.js +44 -0
  44. package/dist/components/form/form.d.ts +30 -0
  45. package/dist/components/form/form.d.ts.map +1 -0
  46. package/dist/components/form/form.js +456 -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 +132 -0
  54. package/dist/components/icon/icon-paths.d.ts.map +1 -0
  55. package/dist/components/icon/icon-paths.js +137 -0
  56. package/dist/components/icon/icon.d.ts +17 -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 +35 -0
  69. package/dist/components/modal/modal.d.ts.map +1 -0
  70. package/dist/components/modal/modal.js +251 -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 +31 -0
  81. package/dist/components/router/router.d.ts.map +1 -0
  82. package/dist/components/router/router.js +97 -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 +16 -0
  87. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  88. package/dist/components/skeleton/skeleton.js +149 -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 +15 -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 +127 -0
  116. package/dist/components/vertical-nav/vertical-nav-item.d.ts +14 -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 +85 -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 +7 -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 +266 -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 +36 -32
  138. package/src/components/form/form.ts +492 -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 +140 -124
  142. package/src/components/icon/icon.ts +84 -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 +246 -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 +133 -46
  151. package/src/components/select/select.ts +161 -161
  152. package/src/components/skeleton/skeleton.ts +134 -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 +115 -96
  162. package/src/components/vertical-nav/vertical-nav-item.ts +72 -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,47 +1,134 @@
1
- class AppRouter {
2
- constructor() {
3
- window.addEventListener('popstate', () => this._notify());
4
-
5
- document.addEventListener('click', (e) => {
6
- // 1. Ignore modified clicks (Ctrl+Click, etc)
7
- if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
8
- return;
9
- }
10
-
11
- // 2. Safely traverse the path
12
- const path = e.composedPath();
13
- const link = path.find((el: any) =>
14
- el && typeof el.hasAttribute === 'function' && el.hasAttribute('href')
15
- ) as HTMLElement | undefined;
16
-
17
- if (!link) return;
18
-
19
- const href = link.getAttribute('href');
20
- const target = link.getAttribute('target');
21
-
22
- // 3. Ignore external links
23
- if (!href || href.startsWith('http') || href.startsWith('mailto:') || target === '_blank') {
24
- return;
25
- }
26
-
27
- // 4. Intercept internal links
28
- if (href.startsWith('/')) {
29
- e.preventDefault();
30
- window.history.pushState(null, '', href);
31
- this._notify();
32
- }
33
- });
34
-
35
- // Broadcast initial route on load
36
- // Use setTimeout to ensure all Lit components have registered first
37
- setTimeout(() => this._notify(), 0);
38
- }
39
-
40
- private _notify() {
41
- window.dispatchEvent(new CustomEvent('route-changed', {
42
- detail: window.location.pathname
43
- }));
44
- }
45
- }
46
-
1
+ export interface RouteDefinition {
2
+ component: string;
3
+ [key: string]: unknown; // Allows consuming apps to attach custom metadata (e.g., titles, auth roles)
4
+ }
5
+
6
+ export type RouteConfig = Record<string, RouteDefinition>;
7
+
8
+ export interface RouteMatch {
9
+ path: string;
10
+ component: string;
11
+ params: Record<string, string>;
12
+ definition: RouteDefinition;
13
+ }
14
+
15
+ function getRouteWeight(pattern: string): number {
16
+ const segments = pattern.split('/').filter(Boolean);
17
+ return segments.reduce((weight, seg) => {
18
+ return weight + (seg.startsWith(':') ? 1 : 10);
19
+ }, 0);
20
+ }
21
+
22
+ export class AppRouter {
23
+ private _routes: RouteConfig = {};
24
+ private _initialized = false;
25
+
26
+ constructor(routes?: RouteConfig) {
27
+ if (routes) {
28
+ this.setRoutes(routes);
29
+ }
30
+
31
+ window.addEventListener('popstate', () => this._notify());
32
+
33
+ document.addEventListener('click', (e) => {
34
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
35
+ return;
36
+ }
37
+
38
+ const path = e.composedPath();
39
+ const link = path.find((el: any) =>
40
+ el && typeof el.hasAttribute === 'function' && el.hasAttribute('href')
41
+ ) as HTMLElement | undefined;
42
+
43
+ if (!link) return;
44
+
45
+ const href = link.getAttribute('href');
46
+ const target = link.getAttribute('target');
47
+
48
+ if (!href || href.startsWith('http') || href.startsWith('mailto:') || target === '_blank') {
49
+ return;
50
+ }
51
+
52
+ if (href.startsWith('/')) {
53
+ e.preventDefault();
54
+ this.navigate(href);
55
+ }
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Register or update the route configuration for this application.
61
+ */
62
+ public setRoutes(routes: RouteConfig) {
63
+ this._routes = routes;
64
+
65
+ // Trigger initial route resolution once routes are registered
66
+ if (!this._initialized) {
67
+ this._initialized = true;
68
+ setTimeout(() => this._notify(), 0);
69
+ } else {
70
+ this._notify();
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Programmatically navigate to an internal path.
76
+ */
77
+ public navigate(path: string) {
78
+ window.history.pushState(null, '', path);
79
+ this._notify();
80
+ }
81
+
82
+ /**
83
+ * Matches a URL path against the registered routes.
84
+ */
85
+ public matchRoute(currentPath: string): RouteMatch | null {
86
+ const sortedRoutes = Object.entries(this._routes).sort(
87
+ ([patternA], [patternB]) => getRouteWeight(patternB) - getRouteWeight(patternA)
88
+ );
89
+
90
+ for (const [pattern, routeDef] of sortedRoutes) {
91
+ const paramNames: string[] = [];
92
+ const regexPath = pattern.replace(/:([a-zA-Z0-9_]+)/g, (_, paramName) => {
93
+ paramNames.push(paramName);
94
+ return '([^/]+)';
95
+ });
96
+
97
+ const regex = new RegExp(`^${regexPath}$`);
98
+ const match = currentPath.match(regex);
99
+
100
+ if (match) {
101
+ const params: Record<string, string> = {};
102
+ paramNames.forEach((name, index) => {
103
+ params[name] = decodeURIComponent(match[index + 1]);
104
+ });
105
+
106
+ return {
107
+ path: currentPath,
108
+ component: routeDef.component,
109
+ params,
110
+ definition: routeDef
111
+ };
112
+ }
113
+ }
114
+
115
+ return null;
116
+ }
117
+
118
+ private _notify() {
119
+ const currentPath = window.location.pathname;
120
+ const match = this.matchRoute(currentPath);
121
+
122
+ window.dispatchEvent(new CustomEvent('route-changed', {
123
+ detail: {
124
+ path: currentPath,
125
+ component: match ? match.component : 'not-found-page',
126
+ params: match ? match.params : {},
127
+ definition: match ? match.definition : null
128
+ }
129
+ }));
130
+ }
131
+ }
132
+
133
+ // Export a singleton instance for standard app-wide use
47
134
  export const router = new AppRouter();
@@ -1,162 +1,162 @@
1
- import { LitElement, html, css } from 'lit';
2
- import { customElement, property } from 'lit/decorators.js';
3
- import { resetStyles } from '../../styles/reset';
4
-
5
- @customElement('st-select')
6
- export class StSelect extends LitElement {
7
- @property({ type: String, reflect: true }) size: 'sm' | 'md' | 'lg' = 'md';
8
- @property({ type: String, reflect: true }) variant: 'outline' | 'filled' = 'outline';
9
- @property({ type: String, reflect: true }) color: 'default' | 'primary' | 'error' = 'default';
10
-
11
- // Internal state to handle the chevron animation when the slotted select is focused
12
- @property({ type: Boolean, reflect: true }) focused = false;
13
-
14
- constructor() {
15
- super();
16
- // Track focus states to animate the chevron
17
- this.addEventListener('focusin', () => this.focused = true);
18
- this.addEventListener('focusout', () => this.focused = false);
19
- }
20
-
21
- static styles = [
22
- resetStyles,
23
- css`
24
- :host {
25
- display: inline-block;
26
- width: 100%;
27
- position: relative;
28
- }
29
-
30
- .select-wrapper {
31
- position: relative;
32
- display: flex;
33
- align-items: center;
34
- width: 100%;
35
- }
36
-
37
- /*
38
- Target the native select provided by the user in the Light DOM.
39
- This completely bypasses the browser rendering bug.
40
- */
41
- ::slotted(select) {
42
- appearance: none;
43
- -webkit-appearance: none;
44
- width: 100%;
45
- font-family: inherit;
46
- background-color: transparent;
47
- border-radius: var(--st-radius-md, 0.5rem);
48
- color: var(--st-color-text);
49
- cursor: pointer;
50
- outline: none;
51
- transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
52
- }
53
-
54
- ::slotted(select:disabled) {
55
- opacity: 0.6;
56
- cursor: not-allowed;
57
- }
58
-
59
- /* ==========================================================
60
- Sizes
61
- ========================================================== */
62
- :host([size="sm"]) ::slotted(select) {
63
- padding: 0.25rem 2rem 0.25rem 0.75rem;
64
- font-size: 0.875rem;
65
- height: 2rem;
66
- }
67
- :host([size="md"]) ::slotted(select) {
68
- padding: 0.5rem 2.5rem 0.5rem 1rem;
69
- font-size: 1rem;
70
- height: 2.5rem;
71
- }
72
- :host([size="lg"]) ::slotted(select) {
73
- padding: 0.75rem 3rem 0.75rem 1.25rem;
74
- font-size: 1.125rem;
75
- height: 3rem;
76
- }
77
-
78
- /* Multiple select formatting (No fixed height, no right padding for chevron) */
79
- ::slotted(select[multiple]) {
80
- height: auto !important;
81
- padding-right: 1rem !important;
82
- }
83
-
84
- /* ==========================================================
85
- Variants & Colors
86
- ========================================================== */
87
- :host([variant="outline"]) ::slotted(select) {
88
- border: 1px solid var(--st-color-border);
89
- }
90
- :host([variant="outline"][color="default"]) ::slotted(select:focus-visible) {
91
- border-color: var(--st-color-primary);
92
- box-shadow: 0 0 0 2px rgba(var(--st-color-primary-rgb, 99, 102, 241), 0.2);
93
- }
94
-
95
- :host([variant="filled"]) ::slotted(select) {
96
- border: 1px solid transparent;
97
- background-color: var(--st-color-surface-hover, rgba(0, 0, 0, 0.05));
98
- }
99
- :host([variant="filled"]) ::slotted(select:not(:disabled):hover) {
100
- background-color: var(--st-color-surface-active, rgba(0, 0, 0, 0.1));
101
- }
102
- :host([variant="filled"][color="default"]) ::slotted(select:focus-visible) {
103
- border-color: var(--st-color-primary);
104
- background-color: transparent;
105
- }
106
-
107
- /* Error Color State */
108
- :host([color="error"]) ::slotted(select) {
109
- border-color: var(--st-color-error, #ef4444);
110
- }
111
- :host([color="error"]) ::slotted(select:focus-visible) {
112
- box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
113
- }
114
-
115
- /* Primary Color State */
116
- :host([color="primary"]) ::slotted(select) {
117
- border-color: var(--st-color-primary);
118
- }
119
-
120
- /* ==========================================================
121
- Chevron Icon
122
- ========================================================== */
123
- .chevron {
124
- position: absolute;
125
- right: 0.75rem;
126
- width: 1.25rem;
127
- height: 1.25rem;
128
- pointer-events: none;
129
- color: var(--st-color-text-muted);
130
- transition: transform 0.2s ease, color 0.2s ease;
131
- }
132
-
133
- /* Animate chevron when the wrapper detects focus */
134
- :host([focused]) .chevron {
135
- transform: rotate(180deg);
136
- color: var(--st-color-primary);
137
- }
138
-
139
- /* Hide chevron if the user slots a native multiple select */
140
- ::slotted(select[multiple]) ~ .chevron {
141
- display: none;
142
- }
143
- `
144
- ];
145
-
146
- render() {
147
- return html`
148
- <div class="select-wrapper">
149
- <slot></slot>
150
- <svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
151
- <polyline points="6 9 12 15 18 9"></polyline>
152
- </svg>
153
- </div>
154
- `;
155
- }
156
- }
157
-
158
- declare global {
159
- interface HTMLElementTagNameMap {
160
- 'st-select': StSelect;
161
- }
1
+ import { LitElement, html, css } from 'lit';
2
+ import { customElement, property } from 'lit/decorators.js';
3
+ import { resetStyles } from '../../styles/reset.js';
4
+
5
+ @customElement('st-select')
6
+ export class StSelect extends LitElement {
7
+ @property({ type: String, reflect: true }) size: 'sm' | 'md' | 'lg' = 'md';
8
+ @property({ type: String, reflect: true }) variant: 'outline' | 'filled' = 'outline';
9
+ @property({ type: String, reflect: true }) color: 'default' | 'primary' | 'error' = 'default';
10
+
11
+ // Internal state to handle the chevron animation when the slotted select is focused
12
+ @property({ type: Boolean, reflect: true }) focused = false;
13
+
14
+ constructor() {
15
+ super();
16
+ // Track focus states to animate the chevron
17
+ this.addEventListener('focusin', () => this.focused = true);
18
+ this.addEventListener('focusout', () => this.focused = false);
19
+ }
20
+
21
+ static styles = [
22
+ resetStyles,
23
+ css`
24
+ :host {
25
+ display: inline-block;
26
+ width: 100%;
27
+ position: relative;
28
+ }
29
+
30
+ .select-wrapper {
31
+ position: relative;
32
+ display: flex;
33
+ align-items: center;
34
+ width: 100%;
35
+ }
36
+
37
+ /*
38
+ Target the native select provided by the user in the Light DOM.
39
+ This completely bypasses the browser rendering bug.
40
+ */
41
+ ::slotted(select) {
42
+ appearance: none;
43
+ -webkit-appearance: none;
44
+ width: 100%;
45
+ font-family: inherit;
46
+ background-color: transparent;
47
+ border-radius: var(--st-radius-md, 0.5rem);
48
+ color: var(--st-color-text);
49
+ cursor: pointer;
50
+ outline: none;
51
+ transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s;
52
+ }
53
+
54
+ ::slotted(select:disabled) {
55
+ opacity: 0.6;
56
+ cursor: not-allowed;
57
+ }
58
+
59
+ /* ==========================================================
60
+ Sizes
61
+ ========================================================== */
62
+ :host([size="sm"]) ::slotted(select) {
63
+ padding: 0.25rem 2rem 0.25rem 0.75rem;
64
+ font-size: 0.875rem;
65
+ height: 2rem;
66
+ }
67
+ :host([size="md"]) ::slotted(select) {
68
+ padding: 0.5rem 2.5rem 0.5rem 1rem;
69
+ font-size: 1rem;
70
+ height: 2.5rem;
71
+ }
72
+ :host([size="lg"]) ::slotted(select) {
73
+ padding: 0.75rem 3rem 0.75rem 1.25rem;
74
+ font-size: 1.125rem;
75
+ height: 3rem;
76
+ }
77
+
78
+ /* Multiple select formatting (No fixed height, no right padding for chevron) */
79
+ ::slotted(select[multiple]) {
80
+ height: auto !important;
81
+ padding-right: 1rem !important;
82
+ }
83
+
84
+ /* ==========================================================
85
+ Variants & Colors
86
+ ========================================================== */
87
+ :host([variant="outline"]) ::slotted(select) {
88
+ border: 1px solid var(--st-color-border);
89
+ }
90
+ :host([variant="outline"][color="default"]) ::slotted(select:focus-visible) {
91
+ border-color: var(--st-color-primary);
92
+ box-shadow: 0 0 0 2px rgba(var(--st-color-primary-rgb, 99, 102, 241), 0.2);
93
+ }
94
+
95
+ :host([variant="filled"]) ::slotted(select) {
96
+ border: 1px solid transparent;
97
+ background-color: var(--st-color-surface-hover, rgba(0, 0, 0, 0.05));
98
+ }
99
+ :host([variant="filled"]) ::slotted(select:not(:disabled):hover) {
100
+ background-color: var(--st-color-surface-active, rgba(0, 0, 0, 0.1));
101
+ }
102
+ :host([variant="filled"][color="default"]) ::slotted(select:focus-visible) {
103
+ border-color: var(--st-color-primary);
104
+ background-color: transparent;
105
+ }
106
+
107
+ /* Error Color State */
108
+ :host([color="error"]) ::slotted(select) {
109
+ border-color: var(--st-color-error, #ef4444);
110
+ }
111
+ :host([color="error"]) ::slotted(select:focus-visible) {
112
+ box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
113
+ }
114
+
115
+ /* Primary Color State */
116
+ :host([color="primary"]) ::slotted(select) {
117
+ border-color: var(--st-color-primary);
118
+ }
119
+
120
+ /* ==========================================================
121
+ Chevron Icon
122
+ ========================================================== */
123
+ .chevron {
124
+ position: absolute;
125
+ right: 0.75rem;
126
+ width: 1.25rem;
127
+ height: 1.25rem;
128
+ pointer-events: none;
129
+ color: var(--st-color-text-muted);
130
+ transition: transform 0.2s ease, color 0.2s ease;
131
+ }
132
+
133
+ /* Animate chevron when the wrapper detects focus */
134
+ :host([focused]) .chevron {
135
+ transform: rotate(180deg);
136
+ color: var(--st-color-primary);
137
+ }
138
+
139
+ /* Hide chevron if the user slots a native multiple select */
140
+ ::slotted(select[multiple]) ~ .chevron {
141
+ display: none;
142
+ }
143
+ `
144
+ ];
145
+
146
+ render() {
147
+ return html`
148
+ <div class="select-wrapper">
149
+ <slot></slot>
150
+ <svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
151
+ <polyline points="6 9 12 15 18 9"></polyline>
152
+ </svg>
153
+ </div>
154
+ `;
155
+ }
156
+ }
157
+
158
+ declare global {
159
+ interface HTMLElementTagNameMap {
160
+ 'st-select': StSelect;
161
+ }
162
162
  }