@studiocms/ui 0.0.1 → 0.1.0
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/README.md +28 -544
- package/package.json +10 -5
- package/src/components/Button.astro +58 -57
- package/src/components/Card.astro +11 -11
- package/src/components/Center.astro +2 -2
- package/src/components/Checkbox.astro +28 -27
- package/src/components/Divider.astro +8 -8
- package/src/components/Dropdown/Dropdown.astro +48 -40
- package/src/components/Dropdown/dropdown.ts +7 -6
- package/src/components/Footer.astro +120 -0
- package/src/components/Input.astro +15 -14
- package/src/components/Modal/Modal.astro +53 -29
- package/src/components/Modal/modal.ts +10 -9
- package/src/components/RadioGroup.astro +24 -24
- package/src/components/Row.astro +7 -7
- package/src/components/SearchSelect.astro +35 -31
- package/src/components/Select.astro +38 -29
- package/src/components/Sidebar/Double.astro +12 -12
- package/src/components/Sidebar/Single.astro +6 -6
- package/src/components/Sidebar/helpers.ts +7 -7
- package/src/components/Textarea.astro +26 -15
- package/src/components/ThemeToggle.astro +11 -8
- package/src/components/Toast/Toaster.astro +31 -30
- package/src/components/Toggle.astro +20 -20
- package/src/components/User.astro +15 -14
- package/src/components/index.ts +23 -22
- package/src/components.ts +1 -0
- package/src/css/colors.css +65 -65
- package/src/layouts/RootLayout.astro +1 -1
- package/src/types/index.ts +1 -1
- package/src/utils/ThemeHelper.ts +128 -117
|
@@ -8,9 +8,9 @@ interface Option {
|
|
|
8
8
|
value: string;
|
|
9
9
|
disabled?: boolean;
|
|
10
10
|
color?: StudioCMSColorway;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
11
|
+
icon?: HeroIconName;
|
|
12
|
+
href?: string;
|
|
13
|
+
}
|
|
14
14
|
|
|
15
15
|
interface Props {
|
|
16
16
|
options: Option[];
|
|
@@ -18,27 +18,34 @@ interface Props {
|
|
|
18
18
|
id: string;
|
|
19
19
|
align?: 'start' | 'center' | 'end';
|
|
20
20
|
triggerOn?: 'left' | 'right' | 'both';
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const {
|
|
21
|
+
offset?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
options,
|
|
26
|
+
disabled = false,
|
|
27
|
+
align = 'center',
|
|
28
|
+
id,
|
|
29
|
+
triggerOn = 'left',
|
|
30
|
+
offset = 0,
|
|
31
|
+
} = Astro.props;
|
|
25
32
|
---
|
|
26
33
|
<div
|
|
27
|
-
class="dropdown-container"
|
|
34
|
+
class="sui-dropdown-container"
|
|
28
35
|
class:list={[disabled && 'disabled']}
|
|
29
36
|
data-align={align}
|
|
30
37
|
id={`${id}-container`}
|
|
31
38
|
data-trigger={triggerOn}
|
|
32
|
-
transition:persist
|
|
39
|
+
transition:persist
|
|
40
|
+
transition:persist-props
|
|
33
41
|
>
|
|
34
|
-
<div class="dropdown-toggle" id={`${id}-toggle-btn`}>
|
|
42
|
+
<div class="sui-dropdown-toggle" id={`${id}-toggle-btn`}>
|
|
35
43
|
<slot />
|
|
36
44
|
</div>
|
|
37
|
-
<ul class="dropdown
|
|
45
|
+
<ul class="sui-dropdown" class:list={[align]} role="listbox" id={`${id}-dropdown`} transition:persist transition:persist-props>
|
|
38
46
|
{options.map(({ value, disabled, color, label, icon, href }) => (
|
|
39
47
|
<li
|
|
40
|
-
class="dropdown-option"
|
|
41
|
-
role="option"
|
|
48
|
+
class="sui-dropdown-option"
|
|
42
49
|
data-value={value}
|
|
43
50
|
class:list={[disabled && "disabled", icon && "has-icon", color, href && "has-href"]}
|
|
44
51
|
>
|
|
@@ -46,7 +53,7 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
46
53
|
<Icon width={24} height={24} name={icon} />
|
|
47
54
|
)}
|
|
48
55
|
{href ? (
|
|
49
|
-
<a href={href} class="dropdown-link">{label}</a>
|
|
56
|
+
<a href={href} class="sui-dropdown-link">{label}</a>
|
|
50
57
|
) : (
|
|
51
58
|
<span>{label}</span>
|
|
52
59
|
)}
|
|
@@ -55,18 +62,18 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
55
62
|
</ul>
|
|
56
63
|
</div>
|
|
57
64
|
<style define:vars={{ offset: `${offset}px` }}>
|
|
58
|
-
.dropdown-toggle {
|
|
65
|
+
.sui-dropdown-toggle {
|
|
59
66
|
width: fit-content;
|
|
60
67
|
}
|
|
61
68
|
|
|
62
|
-
.dropdown-container {
|
|
69
|
+
.sui-dropdown-container {
|
|
63
70
|
position: relative;
|
|
64
71
|
display: flex;
|
|
65
72
|
flex-direction: column;
|
|
66
73
|
gap: .25rem;
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
.dropdown {
|
|
76
|
+
.sui-dropdown {
|
|
70
77
|
position: absolute;
|
|
71
78
|
list-style: none;
|
|
72
79
|
margin: 0;
|
|
@@ -134,11 +141,11 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
.dropdown.initialized {
|
|
144
|
+
.sui-dropdown.initialized {
|
|
138
145
|
animation: pop-down .15s ease forwards;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
|
-
.dropdown.initialized.active {
|
|
148
|
+
.sui-dropdown.initialized.active {
|
|
142
149
|
display: flex;
|
|
143
150
|
border: 1px solid hsl(var(--border));
|
|
144
151
|
height: auto;
|
|
@@ -147,36 +154,36 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
147
154
|
animation: pop-up .15s ease forwards;
|
|
148
155
|
}
|
|
149
156
|
|
|
150
|
-
.dropdown.initialized.below {
|
|
157
|
+
.sui-dropdown.initialized.below {
|
|
151
158
|
top: calc(100% + .25rem + var(--offset)) !important;
|
|
152
159
|
bottom: auto;
|
|
153
160
|
|
|
154
161
|
transform-origin: top center;
|
|
155
162
|
}
|
|
156
163
|
|
|
157
|
-
.dropdown.below.start {
|
|
164
|
+
.sui-dropdown.below.start {
|
|
158
165
|
transform-origin: top left;
|
|
159
166
|
}
|
|
160
167
|
|
|
161
|
-
.dropdown.below.end {
|
|
168
|
+
.sui-dropdown.below.end {
|
|
162
169
|
transform-origin: top right;
|
|
163
170
|
}
|
|
164
171
|
|
|
165
|
-
.dropdown.above {
|
|
172
|
+
.sui-dropdown.above {
|
|
166
173
|
top: auto;
|
|
167
174
|
bottom: calc(100% + .25rem + var(--offset)) !important;
|
|
168
175
|
transform-origin: bottom center;
|
|
169
176
|
}
|
|
170
177
|
|
|
171
|
-
.dropdown.above.start {
|
|
178
|
+
.sui-dropdown.above.start {
|
|
172
179
|
transform-origin: bottom left;
|
|
173
180
|
}
|
|
174
181
|
|
|
175
|
-
.dropdown.above.end {
|
|
182
|
+
.sui-dropdown.above.end {
|
|
176
183
|
transform-origin: bottom right;
|
|
177
184
|
}
|
|
178
185
|
|
|
179
|
-
.dropdown-option {
|
|
186
|
+
.sui-dropdown-option {
|
|
180
187
|
padding: .5rem .75rem;
|
|
181
188
|
cursor: pointer;
|
|
182
189
|
font-size: .975em;
|
|
@@ -187,67 +194,68 @@ const { options, disabled = false, align = 'center', id, triggerOn = 'left', off
|
|
|
187
194
|
align-items: center;
|
|
188
195
|
width: 100%;
|
|
189
196
|
white-space: normal;
|
|
197
|
+
user-select: none;
|
|
190
198
|
}
|
|
191
199
|
|
|
192
|
-
.dropdown-option:hover {
|
|
200
|
+
.sui-dropdown-option:hover {
|
|
193
201
|
background-color: hsl(var(--background-step-3));
|
|
194
202
|
}
|
|
195
203
|
|
|
196
|
-
.dropdown-option.has-href {
|
|
204
|
+
.sui-dropdown-option.has-href {
|
|
197
205
|
padding: 0;
|
|
198
206
|
}
|
|
199
207
|
|
|
200
|
-
.dropdown-link {
|
|
208
|
+
.sui-dropdown-link {
|
|
201
209
|
padding: .5rem .75rem;
|
|
202
210
|
width: 100%;
|
|
203
211
|
}
|
|
204
212
|
|
|
205
|
-
.dropdown-option.primary {
|
|
213
|
+
.sui-dropdown-option.primary {
|
|
206
214
|
color: hsl(var(--primary-base));
|
|
207
215
|
}
|
|
208
216
|
|
|
209
|
-
.dropdown-option.primary:hover {
|
|
217
|
+
.sui-dropdown-option.primary:hover {
|
|
210
218
|
background-color: hsl(var(--primary-base));
|
|
211
219
|
color: hsl(var(--text-inverted));
|
|
212
220
|
}
|
|
213
221
|
|
|
214
|
-
.dropdown-option.success {
|
|
222
|
+
.sui-dropdown-option.success {
|
|
215
223
|
color: hsl(var(--success-base));
|
|
216
224
|
}
|
|
217
225
|
|
|
218
|
-
.dropdown-option.success:hover {
|
|
226
|
+
.sui-dropdown-option.success:hover {
|
|
219
227
|
background-color: hsl(var(--success-base));
|
|
220
228
|
color: hsl(var(--text-dark));
|
|
221
229
|
}
|
|
222
230
|
|
|
223
|
-
.dropdown-option.warning {
|
|
231
|
+
.sui-dropdown-option.warning {
|
|
224
232
|
color: hsl(var(--warning-base));
|
|
225
233
|
}
|
|
226
234
|
|
|
227
|
-
.dropdown-option.warning:hover {
|
|
235
|
+
.sui-dropdown-option.warning:hover {
|
|
228
236
|
background-color: hsl(var(--warning-base));
|
|
229
237
|
color: hsl(var(--text-dark));
|
|
230
238
|
}
|
|
231
239
|
|
|
232
|
-
.dropdown-option.danger {
|
|
240
|
+
.sui-dropdown-option.danger {
|
|
233
241
|
color: hsl(var(--danger-base));
|
|
234
242
|
}
|
|
235
243
|
|
|
236
|
-
.dropdown-option.danger:hover {
|
|
244
|
+
.sui-dropdown-option.danger:hover {
|
|
237
245
|
background-color: hsl(var(--danger-base));
|
|
238
246
|
color: hsl(var(--text-light));
|
|
239
247
|
}
|
|
240
248
|
|
|
241
|
-
.dropdown-option.disabled {
|
|
249
|
+
.sui-dropdown-option.disabled {
|
|
242
250
|
pointer-events: none;
|
|
243
251
|
color: hsl(var(--text-muted));
|
|
244
252
|
}
|
|
245
253
|
|
|
246
|
-
.dropdown-option.end {
|
|
254
|
+
.sui-dropdown-option.end {
|
|
247
255
|
justify-content: space-between;
|
|
248
256
|
}
|
|
249
257
|
|
|
250
|
-
.dropdown-option.has-icon {
|
|
258
|
+
.sui-dropdown-option.has-icon {
|
|
251
259
|
padding-left: .5rem;
|
|
252
260
|
}
|
|
253
261
|
</style>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
class DropdownHelper {
|
|
2
|
-
container: HTMLDivElement;
|
|
3
|
-
toggleEl: HTMLDivElement;
|
|
4
|
-
dropdown: HTMLUListElement;
|
|
2
|
+
private container: HTMLDivElement;
|
|
3
|
+
private toggleEl: HTMLDivElement;
|
|
4
|
+
private dropdown: HTMLUListElement;
|
|
5
|
+
|
|
6
|
+
private alignment: 'start' | 'center' | 'end';
|
|
7
|
+
private triggerOn: 'left' | 'right' | 'both';
|
|
8
|
+
private fullWidth = false;
|
|
5
9
|
|
|
6
|
-
alignment: 'start' | 'center' | 'end';
|
|
7
|
-
triggerOn: 'left' | 'right' | 'both';
|
|
8
10
|
active = false;
|
|
9
|
-
fullWidth = false;
|
|
10
11
|
|
|
11
12
|
constructor(id: string, fullWidth?: boolean) {
|
|
12
13
|
this.container = document.getElementById(`${id}-container`) as HTMLDivElement;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from 'astro/types';
|
|
3
|
+
|
|
4
|
+
interface Props extends HTMLAttributes<'footer'> {
|
|
5
|
+
links: {
|
|
6
|
+
[label: string]: {
|
|
7
|
+
label: string;
|
|
8
|
+
href: string;
|
|
9
|
+
}[];
|
|
10
|
+
};
|
|
11
|
+
copyright: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { copyright, links, ...props } = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<footer {...props}>
|
|
18
|
+
<div class="upper">
|
|
19
|
+
<div>
|
|
20
|
+
<slot name="brand" />
|
|
21
|
+
</div>
|
|
22
|
+
<div class="links">
|
|
23
|
+
{Object.keys(links).map((groupLabel) => (
|
|
24
|
+
<ul>
|
|
25
|
+
<li class="sui-footer-link-label">{groupLabel}</li>
|
|
26
|
+
{links[groupLabel]!.map((item) => (
|
|
27
|
+
<li>
|
|
28
|
+
<a href={item.href}>{item.label}</a>
|
|
29
|
+
</li>
|
|
30
|
+
))}
|
|
31
|
+
</ul>
|
|
32
|
+
))}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<hr class="separator" />
|
|
36
|
+
<div class="lower">
|
|
37
|
+
<span class="copyright-span">{copyright}</span>
|
|
38
|
+
<slot name="socials" />
|
|
39
|
+
</div>
|
|
40
|
+
</footer>
|
|
41
|
+
<style>
|
|
42
|
+
footer {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: 2rem;
|
|
46
|
+
background-color: hsl(var(--background-step-1));
|
|
47
|
+
padding: 2rem 10vw;
|
|
48
|
+
color: hsl(var(--text-normal)) !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.upper, .lower {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: row;
|
|
54
|
+
justify-content: space-between;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.links {
|
|
58
|
+
display: flex;
|
|
59
|
+
justify-content: flex-end;
|
|
60
|
+
flex-direction: row;
|
|
61
|
+
flex-wrap: wrap;
|
|
62
|
+
gap: 2rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.links ul {
|
|
66
|
+
list-style-type: none;
|
|
67
|
+
margin: 0 !important;
|
|
68
|
+
padding: 0 !important;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.links ul li, .links ul li * {
|
|
72
|
+
color: hsl(var(--text-normal)) !important;
|
|
73
|
+
width: fit-content;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.links ul li:has(a):hover {
|
|
77
|
+
text-decoration: underline;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.sui-footer-link-label {
|
|
81
|
+
font-size: 1.125em;
|
|
82
|
+
font-weight: 700;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.separator {
|
|
86
|
+
height: 1px;
|
|
87
|
+
width: 100%;
|
|
88
|
+
border: none;
|
|
89
|
+
background: hsl(var(--border));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.lower {
|
|
93
|
+
align-items: center;
|
|
94
|
+
flex-wrap: wrap;
|
|
95
|
+
gap: 1rem;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@media screen and (max-width: 1440px) {
|
|
99
|
+
footer {
|
|
100
|
+
padding: 2rem;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@media screen and (max-width: 1280px) {
|
|
105
|
+
.upper {
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
gap: 2rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.links {
|
|
111
|
+
justify-content: flex-start;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@media screen and (max-width: 640px) {
|
|
116
|
+
.links ul {
|
|
117
|
+
width: calc(50% - 1rem);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
@@ -11,7 +11,7 @@ interface Props extends HTMLAttributes<'input'> {
|
|
|
11
11
|
disabled?: boolean;
|
|
12
12
|
defaultValue?: string;
|
|
13
13
|
class?: string;
|
|
14
|
-
}
|
|
14
|
+
}
|
|
15
15
|
|
|
16
16
|
const {
|
|
17
17
|
label,
|
|
@@ -26,16 +26,18 @@ const {
|
|
|
26
26
|
} = Astro.props;
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
<label for={name} class="input-label" class:list={[disabled && "disabled"]}>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
<label for={name} class="sui-input-label" class:list={[disabled && "disabled"]}>
|
|
30
|
+
{label && (
|
|
31
|
+
<span class="label">
|
|
32
|
+
{label} <span class="req-star">{isRequired && "*"}</span>
|
|
33
|
+
</span>
|
|
34
|
+
)}
|
|
33
35
|
<input
|
|
34
36
|
placeholder={placeholder}
|
|
35
37
|
name={name}
|
|
36
38
|
id={name}
|
|
37
39
|
type={type}
|
|
38
|
-
class="input"
|
|
40
|
+
class="sui-input"
|
|
39
41
|
class:list={[className]}
|
|
40
42
|
required={isRequired}
|
|
41
43
|
disabled={disabled}
|
|
@@ -44,15 +46,14 @@ const {
|
|
|
44
46
|
/>
|
|
45
47
|
</label>
|
|
46
48
|
<style>
|
|
47
|
-
.input-label {
|
|
49
|
+
.sui-input-label {
|
|
48
50
|
width: 100%;
|
|
49
51
|
display: flex;
|
|
50
52
|
flex-direction: column;
|
|
51
53
|
gap: .25rem;
|
|
52
|
-
margin-top: .5rem;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
.input-label.disabled {
|
|
56
|
+
.sui-input-label.disabled {
|
|
56
57
|
opacity: 0.5;
|
|
57
58
|
pointer-events: none;
|
|
58
59
|
color: hsl(var(--text-muted));
|
|
@@ -62,7 +63,7 @@ const {
|
|
|
62
63
|
font-size: 14px;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
.input {
|
|
66
|
+
.sui-input {
|
|
66
67
|
padding: .5rem 1rem;
|
|
67
68
|
border-radius: 8px;
|
|
68
69
|
border: 1px solid hsl(var(--border));
|
|
@@ -71,18 +72,18 @@ const {
|
|
|
71
72
|
transition: all .15s ease;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
.input:hover {
|
|
75
|
+
.sui-input:hover {
|
|
75
76
|
background: hsl(var(--background-step-3));
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
.input:active,
|
|
79
|
-
.input:focus {
|
|
79
|
+
.sui-input:active,
|
|
80
|
+
.sui-input:focus {
|
|
80
81
|
border: 1px solid hsl(var(--primary-base));
|
|
81
82
|
outline: none;
|
|
82
83
|
background: hsl(var(--background-step-2));
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
.disabled .input:active {
|
|
86
|
+
.disabled .sui-input:active {
|
|
86
87
|
border: 1px solid hsl(var(--border));
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -1,57 +1,80 @@
|
|
|
1
1
|
---
|
|
2
|
+
import type { StudioCMSColorway } from 'src/utils/colors';
|
|
2
3
|
import Icon from '../../utils/Icon.astro';
|
|
3
4
|
import Button from '../Button.astro';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
interface ButtonType {
|
|
7
|
+
label: string;
|
|
8
|
+
color: StudioCMSColorway;
|
|
9
|
+
}
|
|
6
10
|
|
|
7
11
|
interface Props {
|
|
8
12
|
id: string;
|
|
9
13
|
size?: 'sm' | 'md' | 'lg';
|
|
10
14
|
dismissable?: boolean;
|
|
11
|
-
|
|
15
|
+
cancelButton?: string | ButtonType;
|
|
16
|
+
actionButton?: string | ButtonType;
|
|
12
17
|
isForm?: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
id,
|
|
22
|
+
size = 'md',
|
|
23
|
+
dismissable = true,
|
|
24
|
+
isForm = false,
|
|
25
|
+
cancelButton,
|
|
26
|
+
actionButton,
|
|
27
|
+
} = Astro.props;
|
|
16
28
|
---
|
|
17
|
-
<!-- Should: Be centered on mobile, scroll happens inside, blur bg -->
|
|
18
29
|
<dialog
|
|
19
30
|
popover
|
|
20
31
|
id={id}
|
|
21
32
|
data-dismissable={`${dismissable}`}
|
|
22
|
-
data-
|
|
23
|
-
|
|
33
|
+
data-has-action-button={actionButton}
|
|
34
|
+
data-has-cancel-button={cancelButton}
|
|
35
|
+
class="sui-modal"
|
|
24
36
|
class:list={[size]}
|
|
25
37
|
data-form={`${isForm}`}
|
|
26
38
|
>
|
|
27
|
-
<div class="modal-header">
|
|
39
|
+
<div class="sui-modal-header">
|
|
28
40
|
<slot name="header" />
|
|
29
|
-
{(dismissable ||
|
|
41
|
+
{(dismissable || (!cancelButton && !actionButton)) && (
|
|
30
42
|
<button class="x-mark-container" id={`${id}-btn-x`}>
|
|
31
43
|
<Icon name="x-mark" width={24} height={24} class={'dismiss-icon'} />
|
|
32
44
|
</button>
|
|
33
45
|
)}
|
|
34
46
|
</div>
|
|
35
47
|
<form id={`${id}-form-element`}>
|
|
36
|
-
<div class="modal-body">
|
|
48
|
+
<div class="sui-modal-body">
|
|
37
49
|
<slot />
|
|
38
50
|
</div>
|
|
39
|
-
<div class="modal-footer">
|
|
40
|
-
{
|
|
41
|
-
<Button
|
|
42
|
-
|
|
51
|
+
<div class="sui-modal-footer">
|
|
52
|
+
{cancelButton && (
|
|
53
|
+
<Button
|
|
54
|
+
id={`${id}-btn-cancel`}
|
|
55
|
+
color={typeof cancelButton === 'string' ? 'danger' : cancelButton.color}
|
|
56
|
+
variant='flat'
|
|
57
|
+
type={isForm ? 'reset' : 'button'}
|
|
58
|
+
>
|
|
59
|
+
{typeof cancelButton === 'string' ? cancelButton : cancelButton.label}
|
|
43
60
|
</Button>
|
|
44
61
|
)}
|
|
45
|
-
{
|
|
46
|
-
<Button
|
|
47
|
-
|
|
62
|
+
{actionButton && (
|
|
63
|
+
<Button
|
|
64
|
+
id={`${id}-btn-confirm`}
|
|
65
|
+
type={'submit'}
|
|
66
|
+
color={typeof actionButton === 'string' ? 'primary' : actionButton.color}
|
|
67
|
+
variant='solid'
|
|
68
|
+
type={isForm ? 'submit' : 'button'}
|
|
69
|
+
>
|
|
70
|
+
{typeof actionButton === 'string' ? actionButton : actionButton.label}
|
|
48
71
|
</Button>
|
|
49
72
|
)}
|
|
50
73
|
</div>
|
|
51
74
|
</form>
|
|
52
75
|
</dialog>
|
|
53
76
|
<style>
|
|
54
|
-
.modal {
|
|
77
|
+
.sui-modal {
|
|
55
78
|
border: 1px solid hsl(var(--border));
|
|
56
79
|
border-radius: .5rem;
|
|
57
80
|
padding: 1.5rem;
|
|
@@ -59,35 +82,36 @@ const { id, size = 'md', dismissable = true, isForm = false, buttons = [] } = As
|
|
|
59
82
|
animation: hide .25s ease;
|
|
60
83
|
overflow: visible;
|
|
61
84
|
margin: auto;
|
|
85
|
+
z-index: 50;
|
|
62
86
|
}
|
|
63
87
|
|
|
64
|
-
.modal.sm {
|
|
88
|
+
.sui-modal.sm {
|
|
65
89
|
width: 384px;
|
|
66
90
|
}
|
|
67
91
|
|
|
68
|
-
.modal.md {
|
|
92
|
+
.sui-modal.md {
|
|
69
93
|
width: 448px;
|
|
70
94
|
}
|
|
71
95
|
|
|
72
|
-
.modal.lg {
|
|
96
|
+
.sui-modal.lg {
|
|
73
97
|
width: 608px;
|
|
74
98
|
}
|
|
75
99
|
|
|
76
|
-
.modal[open] {
|
|
100
|
+
.sui-modal[open] {
|
|
77
101
|
animation: show .25s ease-in-out;
|
|
78
102
|
}
|
|
79
103
|
|
|
80
|
-
html:has(.modal[open]),
|
|
81
|
-
body:has(.modal[open]) {
|
|
104
|
+
html:has(.sui-modal[open]),
|
|
105
|
+
body:has(.sui-modal[open]) {
|
|
82
106
|
overflow: hidden;
|
|
83
107
|
}
|
|
84
108
|
|
|
85
|
-
.modal[open]::backdrop {
|
|
109
|
+
.sui-modal[open]::backdrop {
|
|
86
110
|
background-color: rgba(0, 0, 0, 0.75);
|
|
87
111
|
animation: backdrop .3s ease-in-out forwards;
|
|
88
112
|
}
|
|
89
113
|
|
|
90
|
-
.modal-header:has(*) {
|
|
114
|
+
.sui-modal-header:has(*) {
|
|
91
115
|
margin-bottom: 1rem;
|
|
92
116
|
|
|
93
117
|
display: flex;
|
|
@@ -115,11 +139,11 @@ const { id, size = 'md', dismissable = true, isForm = false, buttons = [] } = As
|
|
|
115
139
|
background-color: hsl(var(--default-base));
|
|
116
140
|
}
|
|
117
141
|
|
|
118
|
-
.modal-footer {
|
|
142
|
+
.sui-modal-footer {
|
|
119
143
|
display: none;
|
|
120
144
|
}
|
|
121
145
|
|
|
122
|
-
.modal-footer:has(*) {
|
|
146
|
+
.sui-modal-footer:has(*) {
|
|
123
147
|
display: flex;
|
|
124
148
|
flex-direction: row;
|
|
125
149
|
gap: 1rem;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class ModalHelper {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
private element: HTMLDialogElement;
|
|
3
|
+
private cancelButton: HTMLButtonElement | undefined;
|
|
4
|
+
private confirmButton: HTMLButtonElement | undefined;
|
|
5
5
|
|
|
6
6
|
private isForm = false;
|
|
7
7
|
private modalForm: HTMLFormElement;
|
|
@@ -33,21 +33,22 @@ class ModalHelper {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
private addButtonListeners = (id: string, dismissable: boolean) => {
|
|
36
|
-
if (
|
|
36
|
+
if (
|
|
37
|
+
dismissable ||
|
|
38
|
+
(!this.element.dataset.hasCancelButton && !this.element.dataset.hasActionButton)
|
|
39
|
+
) {
|
|
37
40
|
const xMarkButton = document.getElementById(`${id}-btn-x`) as HTMLButtonElement;
|
|
38
41
|
xMarkButton.addEventListener('click', this.hide);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
if (!this.element.dataset.
|
|
44
|
+
if (!!this.element.dataset.hasCancelButton && !this.element.dataset.hasActionButton) return;
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (usedButtons.includes('cancel')) {
|
|
46
|
+
if (this.element.dataset.hasCancelButton) {
|
|
46
47
|
this.cancelButton = document.getElementById(`${id}-btn-cancel`) as HTMLButtonElement;
|
|
47
48
|
this.cancelButton.addEventListener('click', this.hide);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
if (
|
|
51
|
+
if (this.element.dataset.hasActionButton) {
|
|
51
52
|
this.confirmButton = document.getElementById(`${id}-btn-confirm`) as HTMLButtonElement;
|
|
52
53
|
this.confirmButton.addEventListener('click', this.hide);
|
|
53
54
|
}
|