@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,98 +1,98 @@
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-link')
6
- export class StLink extends LitElement {
7
- @property({ type: String }) href = '#';
8
- @property({ type: String }) target: '_blank' | '_self' = '_self';
9
- @property({ type: String, reflect: true }) size: 'sm' | 'md' | 'lg' = 'md';
10
- @property({ type: String, reflect: true }) variant: 'inline' | 'standalone' = 'inline';
11
- @property({ type: String, reflect: true }) color: 'default' | 'primary' | 'muted' = 'primary';
12
-
13
- static styles = [
14
- resetStyles,
15
- css`
16
- :host {
17
- display: inline-flex;
18
- align-items: center;
19
- }
20
-
21
- a {
22
- display: inline-flex;
23
- align-items: center;
24
- gap: 0.25em;
25
- text-decoration: none;
26
- font-weight: 500;
27
- transition: color 0.2s ease, opacity 0.2s ease;
28
- }
29
-
30
- /* ==========================================================
31
- Colors
32
- ========================================================== */
33
- :host([color="primary"]) a {
34
- color: var(--st-color-primary);
35
- }
36
- :host([color="default"]) a {
37
- color: var(--st-color-text);
38
- }
39
- :host([color="muted"]) a {
40
- color: var(--st-color-text-muted);
41
- }
42
-
43
- /* Hover states */
44
- :host([color="primary"]) a:hover {
45
- filter: brightness(1.1);
46
- }
47
- :host([color="default"]) a:hover {
48
- color: var(--st-color-primary);
49
- }
50
- :host([color="muted"]) a:hover {
51
- color: var(--st-color-text);
52
- }
53
-
54
- /* ==========================================================
55
- Sizes
56
- ========================================================== */
57
- :host([size="sm"]) a { font-size: 0.875rem; }
58
- :host([size="md"]) a { font-size: 1rem; }
59
- :host([size="lg"]) a { font-size: 1.125rem; }
60
-
61
- /* ==========================================================
62
- Variants
63
- ========================================================== */
64
- /* inline links live inside paragraphs and underline on hover */
65
- :host([variant="inline"]) a {
66
- text-decoration: underline;
67
- text-underline-offset: 4px;
68
- font-weight: inherit; /* Inherits from surrounding paragraph text */
69
- }
70
- :host([variant="inline"]) a:hover {
71
- text-decoration-thickness: 2px;
72
- }
73
-
74
- /* standalone links (e.g., footers, sidebars) have no underline by default */
75
- :host([variant="standalone"]) a {
76
- text-decoration: none;
77
- }
78
- :host([variant="standalone"]) a:hover {
79
- text-decoration: underline;
80
- text-underline-offset: 4px;
81
- }
82
- `
83
- ];
84
-
85
- render() {
86
- return html`
87
- <a href="${this.href}" target="${this.target}">
88
- <slot></slot>
89
- </a>
90
- `;
91
- }
92
- }
93
-
94
- declare global {
95
- interface HTMLElementTagNameMap {
96
- 'st-link': StLink;
97
- }
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-link')
6
+ export class StLink extends LitElement {
7
+ @property({ type: String }) href = '#';
8
+ @property({ type: String }) target: '_blank' | '_self' = '_self';
9
+ @property({ type: String, reflect: true }) size: 'sm' | 'md' | 'lg' = 'md';
10
+ @property({ type: String, reflect: true }) variant: 'inline' | 'standalone' = 'inline';
11
+ @property({ type: String, reflect: true }) color: 'default' | 'primary' | 'muted' = 'primary';
12
+
13
+ static styles = [
14
+ resetStyles,
15
+ css`
16
+ :host {
17
+ display: inline-flex;
18
+ align-items: center;
19
+ }
20
+
21
+ a {
22
+ display: inline-flex;
23
+ align-items: center;
24
+ gap: 0.25em;
25
+ text-decoration: none;
26
+ font-weight: 500;
27
+ transition: color 0.2s ease, opacity 0.2s ease;
28
+ }
29
+
30
+ /* ==========================================================
31
+ Colors
32
+ ========================================================== */
33
+ :host([color="primary"]) a {
34
+ color: var(--st-color-primary);
35
+ }
36
+ :host([color="default"]) a {
37
+ color: var(--st-color-text);
38
+ }
39
+ :host([color="muted"]) a {
40
+ color: var(--st-color-text-muted);
41
+ }
42
+
43
+ /* Hover states */
44
+ :host([color="primary"]) a:hover {
45
+ filter: brightness(1.1);
46
+ }
47
+ :host([color="default"]) a:hover {
48
+ color: var(--st-color-primary);
49
+ }
50
+ :host([color="muted"]) a:hover {
51
+ color: var(--st-color-text);
52
+ }
53
+
54
+ /* ==========================================================
55
+ Sizes
56
+ ========================================================== */
57
+ :host([size="sm"]) a { font-size: 0.875rem; }
58
+ :host([size="md"]) a { font-size: 1rem; }
59
+ :host([size="lg"]) a { font-size: 1.125rem; }
60
+
61
+ /* ==========================================================
62
+ Variants
63
+ ========================================================== */
64
+ /* inline links live inside paragraphs and underline on hover */
65
+ :host([variant="inline"]) a {
66
+ text-decoration: underline;
67
+ text-underline-offset: 4px;
68
+ font-weight: inherit; /* Inherits from surrounding paragraph text */
69
+ }
70
+ :host([variant="inline"]) a:hover {
71
+ text-decoration-thickness: 2px;
72
+ }
73
+
74
+ /* standalone links (e.g., footers, sidebars) have no underline by default */
75
+ :host([variant="standalone"]) a {
76
+ text-decoration: none;
77
+ }
78
+ :host([variant="standalone"]) a:hover {
79
+ text-decoration: underline;
80
+ text-underline-offset: 4px;
81
+ }
82
+ `
83
+ ];
84
+
85
+ render() {
86
+ return html`
87
+ <a href="${this.href}" target="${this.target}">
88
+ <slot></slot>
89
+ </a>
90
+ `;
91
+ }
92
+ }
93
+
94
+ declare global {
95
+ interface HTMLElementTagNameMap {
96
+ 'st-link': StLink;
97
+ }
98
98
  }
@@ -1,67 +1,67 @@
1
- import { LitElement, nothing } from 'lit';
2
- import { customElement, property } from 'lit/decorators.js';
3
-
4
- @customElement('st-metadata')
5
- export class StMetadata extends LitElement {
6
- @property({ type: String }) pageTitle = '';
7
- @property({ type: String }) description = '';
8
- @property({ type: String }) image = '';
9
-
10
- protected createRenderRoot() { return this; }
11
-
12
- updated() {
13
- this._updateMetadata();
14
- }
15
-
16
- private _updateMetadata() {
17
- // Read site name from environment variable (e.g., VITE_SITE_NAME)
18
- const siteName = (import.meta as any).env?.VITE_SITE_NAME || '';
19
-
20
- if (this.pageTitle) {
21
- // If site name is configured, append it; otherwise use the title standalone
22
- document.title = siteName ? `${this.pageTitle} - ${siteName}` : this.pageTitle;
23
- this._setMeta('property', 'og:title', this.pageTitle);
24
- }
25
-
26
- if (this.description) {
27
- this._setMeta('name', 'description', this.description);
28
- this._setMeta('property', 'og:description', this.description);
29
- }
30
-
31
- if (this.image) {
32
- this._setMeta('property', 'og:image', this.image);
33
- }
34
-
35
- this._setCanonical(window.location.href);
36
- }
37
-
38
- private _setMeta(attrName: 'name' | 'property', attrValue: string, content: string) {
39
- let meta = document.head.querySelector(`meta[${attrName}="${attrValue}"]`);
40
- if (!meta) {
41
- meta = document.createElement('meta');
42
- meta.setAttribute(attrName, attrValue);
43
- document.head.appendChild(meta);
44
- }
45
- meta.setAttribute('content', content);
46
- }
47
-
48
- private _setCanonical(url: string) {
49
- let link = document.head.querySelector('link[rel="canonical"]');
50
- if (!link) {
51
- link = document.createElement('link');
52
- link.setAttribute('rel', 'canonical');
53
- document.head.appendChild(link);
54
- }
55
- link.setAttribute('href', url);
56
- }
57
-
58
- render() {
59
- return nothing;
60
- }
61
- }
62
-
63
- declare global {
64
- interface HTMLElementTagNameMap {
65
- 'st-metadata': StMetadata;
66
- }
1
+ import { LitElement, nothing } from 'lit';
2
+ import { customElement, property } from 'lit/decorators.js';
3
+
4
+ @customElement('st-metadata')
5
+ export class StMetadata extends LitElement {
6
+ @property({ type: String }) pageTitle = '';
7
+ @property({ type: String }) description = '';
8
+ @property({ type: String }) image = '';
9
+
10
+ protected createRenderRoot() { return this; }
11
+
12
+ updated() {
13
+ this._updateMetadata();
14
+ }
15
+
16
+ private _updateMetadata() {
17
+ // Read site name from environment variable (e.g., VITE_SITE_NAME)
18
+ const siteName = (import.meta as any).env?.VITE_SITE_NAME || '';
19
+
20
+ if (this.pageTitle) {
21
+ // If site name is configured, append it; otherwise use the title standalone
22
+ document.title = siteName ? `${this.pageTitle} - ${siteName}` : this.pageTitle;
23
+ this._setMeta('property', 'og:title', this.pageTitle);
24
+ }
25
+
26
+ if (this.description) {
27
+ this._setMeta('name', 'description', this.description);
28
+ this._setMeta('property', 'og:description', this.description);
29
+ }
30
+
31
+ if (this.image) {
32
+ this._setMeta('property', 'og:image', this.image);
33
+ }
34
+
35
+ this._setCanonical(window.location.href);
36
+ }
37
+
38
+ private _setMeta(attrName: 'name' | 'property', attrValue: string, content: string) {
39
+ let meta = document.head.querySelector(`meta[${attrName}="${attrValue}"]`);
40
+ if (!meta) {
41
+ meta = document.createElement('meta');
42
+ meta.setAttribute(attrName, attrValue);
43
+ document.head.appendChild(meta);
44
+ }
45
+ meta.setAttribute('content', content);
46
+ }
47
+
48
+ private _setCanonical(url: string) {
49
+ let link = document.head.querySelector('link[rel="canonical"]');
50
+ if (!link) {
51
+ link = document.createElement('link');
52
+ link.setAttribute('rel', 'canonical');
53
+ document.head.appendChild(link);
54
+ }
55
+ link.setAttribute('href', url);
56
+ }
57
+
58
+ render() {
59
+ return nothing;
60
+ }
61
+ }
62
+
63
+ declare global {
64
+ interface HTMLElementTagNameMap {
65
+ 'st-metadata': StMetadata;
66
+ }
67
67
  }
@@ -1,159 +1,159 @@
1
- import { LitElement, html, css, PropertyValues } from 'lit';
2
- import { customElement, property, query } from 'lit/decorators.js';
3
- import { resetStyles } from '../../styles/reset.js';
4
-
5
- @customElement('st-modal')
6
- export class StModal extends LitElement {
7
- /**
8
- * Controls whether the modal is open.
9
- */
10
- @property({ type: Boolean, reflect: true }) open = false;
11
-
12
- /**
13
- * Title text displayed in the modal header.
14
- */
15
- @property({ type: String }) heading = '';
16
-
17
- @query('dialog') private dialogEl!: HTMLDialogElement;
18
-
19
- static styles = [
20
- resetStyles,
21
- css`
22
- :host {
23
- display: contents;
24
- }
25
-
26
- dialog {
27
- padding: 0;
28
- border: 1px solid var(--st-color-border);
29
- border-radius: var(--st-radius-lg, 0.5rem);
30
- background-color: var(--st-color-surface);
31
- color: var(--st-color-text);
32
- width: 100%;
33
- max-width: 500px;
34
- box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
35
- font-family: var(--st-font-family, inherit);
36
- }
37
-
38
- dialog::backdrop {
39
- background-color: rgba(0, 0, 0, 0.5);
40
- backdrop-filter: blur(2px);
41
- }
42
-
43
- .modal-header {
44
- display: flex;
45
- align-items: center;
46
- justify-content: space-between;
47
- padding: var(--st-spacing-md) var(--st-spacing-lg);
48
- border-bottom: 1px solid var(--st-color-border);
49
- }
50
-
51
- .modal-title {
52
- font-size: 1.125rem;
53
- font-weight: 600;
54
- margin: 0;
55
- }
56
-
57
- .close-btn {
58
- background: none;
59
- border: none;
60
- cursor: pointer;
61
- color: var(--st-color-text-muted);
62
- padding: 0.25rem;
63
- display: flex;
64
- align-items: center;
65
- justify-content: center;
66
- border-radius: var(--st-radius-sm);
67
- transition: color 0.2s, background-color 0.2s;
68
- }
69
-
70
- .close-btn:hover {
71
- color: var(--st-color-text);
72
- background-color: var(--st-color-surface-muted, #f1f5f9);
73
- }
74
-
75
- .modal-body {
76
- padding: var(--st-spacing-lg);
77
- font-size: var(--st-font-size-sm, 0.875rem);
78
- line-height: 1.5;
79
- }
80
-
81
- .modal-footer {
82
- display: flex;
83
- align-items: center;
84
- justify-content: flex-end;
85
- gap: var(--st-spacing-sm);
86
- padding: var(--st-spacing-md) var(--st-spacing-lg);
87
- border-top: 1px solid var(--st-color-border);
88
- background-color: var(--st-color-surface-muted, #f8fafc);
89
- }
90
- `
91
- ];
92
-
93
- updated(changedProperties: PropertyValues) {
94
- if (changedProperties.has('open')) {
95
- if (this.dialogEl) {
96
- if (this.open && !this.dialogEl.open) {
97
- this.dialogEl.showModal();
98
- } else if (!this.open && this.dialogEl.open) {
99
- this.dialogEl.close();
100
- }
101
- }
102
- }
103
- }
104
-
105
- private handleClose() {
106
- this.open = false;
107
- this.dispatchEvent(new CustomEvent('st-close', { bubbles: true, composed: true }));
108
- }
109
-
110
- private onDialogClose() {
111
- if (this.open) {
112
- this.open = false;
113
- this.dispatchEvent(new CustomEvent('st-close', { bubbles: true, composed: true }));
114
- }
115
- }
116
-
117
- private handleBackdropClick(e: MouseEvent) {
118
- const rect = this.dialogEl.getBoundingClientRect();
119
- if (
120
- e.clientX < rect.left ||
121
- e.clientX > rect.right ||
122
- e.clientY < rect.top ||
123
- e.clientY > rect.bottom
124
- ) {
125
- this.handleClose();
126
- }
127
- }
128
-
129
- render() {
130
- return html`
131
- <dialog
132
- @cancel=${this.handleClose}
133
- @click=${this.handleBackdropClick}
134
- @close=${this.onDialogClose}
135
- >
136
- <div class="modal-header" @click=${(e: MouseEvent) => e.stopPropagation()}>
137
- <slot name="header">
138
- <h3 class="modal-title">${this.heading}</h3>
139
- </slot>
140
- <button class="close-btn" @click=${this.handleClose} aria-label="Close modal">
141
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
142
- </button>
143
- </div>
144
- <div class="modal-body" @click=${(e: MouseEvent) => e.stopPropagation()}>
145
- <slot></slot>
146
- </div>
147
- <div class="modal-footer" @click=${(e: MouseEvent) => e.stopPropagation()}>
148
- <slot name="footer"></slot>
149
- </div>
150
- </dialog>
151
- `;
152
- }
153
- }
154
-
155
- declare global {
156
- interface HTMLElementTagNameMap {
157
- 'st-modal': StModal;
158
- }
1
+ import { LitElement, html, css, PropertyValues } from 'lit';
2
+ import { customElement, property, query } from 'lit/decorators.js';
3
+ import { resetStyles } from '../../styles/reset.js';
4
+
5
+ @customElement('st-modal')
6
+ export class StModal extends LitElement {
7
+ /**
8
+ * Controls whether the modal is open.
9
+ */
10
+ @property({ type: Boolean, reflect: true }) open = false;
11
+
12
+ /**
13
+ * Title text displayed in the modal header.
14
+ */
15
+ @property({ type: String }) heading = '';
16
+
17
+ @query('dialog') private dialogEl!: HTMLDialogElement;
18
+
19
+ static styles = [
20
+ resetStyles,
21
+ css`
22
+ :host {
23
+ display: contents;
24
+ }
25
+
26
+ dialog {
27
+ padding: 0;
28
+ border: 1px solid var(--st-color-border);
29
+ border-radius: var(--st-radius-lg, 0.5rem);
30
+ background-color: var(--st-color-surface);
31
+ color: var(--st-color-text);
32
+ width: 100%;
33
+ max-width: 500px;
34
+ box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
35
+ font-family: var(--st-font-family, inherit);
36
+ }
37
+
38
+ dialog::backdrop {
39
+ background-color: rgba(0, 0, 0, 0.5);
40
+ backdrop-filter: blur(2px);
41
+ }
42
+
43
+ .modal-header {
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: space-between;
47
+ padding: var(--st-spacing-md) var(--st-spacing-lg);
48
+ border-bottom: 1px solid var(--st-color-border);
49
+ }
50
+
51
+ .modal-title {
52
+ font-size: 1.125rem;
53
+ font-weight: 600;
54
+ margin: 0;
55
+ }
56
+
57
+ .close-btn {
58
+ background: none;
59
+ border: none;
60
+ cursor: pointer;
61
+ color: var(--st-color-text-muted);
62
+ padding: 0.25rem;
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ border-radius: var(--st-radius-sm);
67
+ transition: color 0.2s, background-color 0.2s;
68
+ }
69
+
70
+ .close-btn:hover {
71
+ color: var(--st-color-text);
72
+ background-color: var(--st-color-surface-muted, #f1f5f9);
73
+ }
74
+
75
+ .modal-body {
76
+ padding: var(--st-spacing-lg);
77
+ font-size: var(--st-font-size-sm, 0.875rem);
78
+ line-height: 1.5;
79
+ }
80
+
81
+ .modal-footer {
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: flex-end;
85
+ gap: var(--st-spacing-sm);
86
+ padding: var(--st-spacing-md) var(--st-spacing-lg);
87
+ border-top: 1px solid var(--st-color-border);
88
+ background-color: var(--st-color-surface-muted, #f8fafc);
89
+ }
90
+ `
91
+ ];
92
+
93
+ updated(changedProperties: PropertyValues) {
94
+ if (changedProperties.has('open')) {
95
+ if (this.dialogEl) {
96
+ if (this.open && !this.dialogEl.open) {
97
+ this.dialogEl.showModal();
98
+ } else if (!this.open && this.dialogEl.open) {
99
+ this.dialogEl.close();
100
+ }
101
+ }
102
+ }
103
+ }
104
+
105
+ private handleClose() {
106
+ this.open = false;
107
+ this.dispatchEvent(new CustomEvent('st-close', { bubbles: true, composed: true }));
108
+ }
109
+
110
+ private onDialogClose() {
111
+ if (this.open) {
112
+ this.open = false;
113
+ this.dispatchEvent(new CustomEvent('st-close', { bubbles: true, composed: true }));
114
+ }
115
+ }
116
+
117
+ private handleBackdropClick(e: MouseEvent) {
118
+ const rect = this.dialogEl.getBoundingClientRect();
119
+ if (
120
+ e.clientX < rect.left ||
121
+ e.clientX > rect.right ||
122
+ e.clientY < rect.top ||
123
+ e.clientY > rect.bottom
124
+ ) {
125
+ this.handleClose();
126
+ }
127
+ }
128
+
129
+ render() {
130
+ return html`
131
+ <dialog
132
+ @cancel=${this.handleClose}
133
+ @click=${this.handleBackdropClick}
134
+ @close=${this.onDialogClose}
135
+ >
136
+ <div class="modal-header" @click=${(e: MouseEvent) => e.stopPropagation()}>
137
+ <slot name="header">
138
+ <h3 class="modal-title">${this.heading}</h3>
139
+ </slot>
140
+ <button class="close-btn" @click=${this.handleClose} aria-label="Close modal">
141
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
142
+ </button>
143
+ </div>
144
+ <div class="modal-body" @click=${(e: MouseEvent) => e.stopPropagation()}>
145
+ <slot></slot>
146
+ </div>
147
+ <div class="modal-footer" @click=${(e: MouseEvent) => e.stopPropagation()}>
148
+ <slot name="footer"></slot>
149
+ </div>
150
+ </dialog>
151
+ `;
152
+ }
153
+ }
154
+
155
+ declare global {
156
+ interface HTMLElementTagNameMap {
157
+ 'st-modal': StModal;
158
+ }
159
159
  }