@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.
@@ -6,7 +6,7 @@ interface Option {
6
6
  label: string;
7
7
  value: string;
8
8
  disabled?: boolean;
9
- };
9
+ }
10
10
 
11
11
  interface Props {
12
12
  label: string;
@@ -18,7 +18,7 @@ interface Props {
18
18
  isRequired?: boolean;
19
19
  horizontal?: boolean;
20
20
  class?: string;
21
- };
21
+ }
22
22
 
23
23
  const {
24
24
  label,
@@ -34,7 +34,7 @@ const {
34
34
  ---
35
35
 
36
36
  <div
37
- class="radio-container"
37
+ class="sui-radio-container"
38
38
  class:list={[
39
39
  disabled && "disabled",
40
40
  horizontal && "horizontal",
@@ -45,18 +45,18 @@ const {
45
45
  <span>
46
46
  {label} <span class="req-star">{isRequired && "*"}</span>
47
47
  </span>
48
- <div class="radio-inputs">
48
+ <div class="sui-radio-inputs">
49
49
  {options.map(({ label, value, disabled: individuallyDisabled }) => (
50
50
  <label
51
51
  for={value}
52
- class="radio-label"
52
+ class="sui-radio-label"
53
53
  class:list={[ individuallyDisabled && "disabled" ]}
54
54
  >
55
- <div class="radio-box-container">
56
- <div class="radio-box" />
55
+ <div class="sui-radio-box-container">
56
+ <div class="sui-radio-box" />
57
57
  </div>
58
58
  <input
59
- class="radio-toggle"
59
+ class="sui-radio-toggle"
60
60
  type="radio"
61
61
  value={value}
62
62
  id={value}
@@ -71,18 +71,18 @@ const {
71
71
  </div>
72
72
  </div>
73
73
  <style>
74
- .radio-container {
74
+ .sui-radio-container {
75
75
  display: flex;
76
76
  flex-direction: column;
77
77
  gap: .5rem;
78
78
  }
79
79
 
80
- .radio-container.disabled {
80
+ .sui-radio-container.disabled {
81
81
  opacity: 0.5;
82
82
  color: hsl(var(--text-muted));
83
83
  }
84
84
 
85
- .radio-label.disabled {
85
+ .sui-radio-label.disabled {
86
86
  opacity: 0.5;
87
87
  color: hsl(var(--text-muted));
88
88
  pointer-events: none;
@@ -93,17 +93,17 @@ const {
93
93
  font-weight: 700;
94
94
  }
95
95
 
96
- .radio-inputs {
96
+ .sui-radio-inputs {
97
97
  display: flex;
98
98
  flex-direction: column;
99
99
  gap: .75rem;
100
100
  }
101
101
 
102
- .radio-container.horizontal .radio-inputs {
102
+ .sui-radio-container.horizontal .sui-radio-inputs {
103
103
  flex-direction: row;
104
104
  }
105
105
 
106
- .radio-label {
106
+ .sui-radio-label {
107
107
  display: flex;
108
108
  flex-direction: row;
109
109
  gap: .5rem;
@@ -111,41 +111,41 @@ const {
111
111
  align-items: center;
112
112
  }
113
113
 
114
- .radio-label:hover .radio-box {
114
+ .sui-radio-label:hover .sui-radio-box {
115
115
  outline-color: hsl(var(--default-hover));
116
116
  }
117
117
 
118
- .radio-container:not(.disabled) .radio-label:active .radio-box {
118
+ .sui-radio-container:not(.disabled) .sui-radio-label:active .sui-radio-box {
119
119
  outline-color: hsl(var(--default-active));
120
120
  scale: 0.9;
121
121
  }
122
122
 
123
- .radio-label:has(.radio-toggle:checked) .radio-box {
123
+ .sui-radio-label:has(.sui-radio-toggle:checked) .sui-radio-box {
124
124
  background-color: hsl(var(--text-normal));
125
125
  outline-color: hsl(var(--text-normal));
126
126
  }
127
127
 
128
- .radio-container.primary .radio-label:has(.radio-toggle:checked) .radio-box {
128
+ .sui-radio-container.primary .sui-radio-label:has(.sui-radio-toggle:checked) .sui-radio-box {
129
129
  background-color: hsl(var(--primary-base));
130
130
  outline-color: hsl(var(--primary-base));
131
131
  }
132
132
 
133
- .radio-container.success .radio-label:has(.radio-toggle:checked) .radio-box {
133
+ .sui-radio-container.success .sui-radio-label:has(.sui-radio-toggle:checked) .sui-radio-box {
134
134
  background-color: hsl(var(--success-base));
135
135
  outline-color: hsl(var(--success-base));
136
136
  }
137
137
 
138
- .radio-container.warning .radio-label:has(.radio-toggle:checked) .radio-box {
138
+ .sui-radio-container.warning .sui-radio-label:has(.sui-radio-toggle:checked) .sui-radio-box {
139
139
  background-color: hsl(var(--warning-base));
140
140
  outline-color: hsl(var(--warning-base));
141
141
  }
142
142
 
143
- .radio-container.danger .radio-label:has(.radio-toggle:checked) .radio-box {
143
+ .sui-radio-container.danger .sui-radio-label:has(.sui-radio-toggle:checked) .sui-radio-box {
144
144
  background-color: hsl(var(--danger-base));
145
145
  outline-color: hsl(var(--danger-base));
146
146
  }
147
147
 
148
- .radio-box-container {
148
+ .sui-radio-box-container {
149
149
  width: 20px;
150
150
  height: 20px;
151
151
  display: flex;
@@ -155,7 +155,7 @@ const {
155
155
  cursor: pointer;
156
156
  }
157
157
 
158
- .radio-box {
158
+ .sui-radio-box {
159
159
  width: 12px;
160
160
  height: 12px;
161
161
  border-radius: 20px;
@@ -164,7 +164,7 @@ const {
164
164
  transition: all .15s ease;
165
165
  }
166
166
 
167
- .radio-toggle {
167
+ .sui-radio-toggle {
168
168
  width: 0;
169
169
  height: 0;
170
170
  visibility: hidden;
@@ -4,35 +4,35 @@ import type { HTMLAttributes } from 'astro/types';
4
4
  interface Props extends HTMLAttributes<'div'> {
5
5
  alignCenter?: boolean;
6
6
  gapSize?: 'sm' | 'md' | 'lg';
7
- };
7
+ }
8
8
 
9
9
  const { alignCenter, gapSize = 'md', ...props } = Astro.props;
10
10
  ---
11
11
 
12
- <div class="row" class:list={[alignCenter && "align", gapSize]} {...props}>
12
+ <div class="sui-row" class:list={[alignCenter && "align", gapSize]} {...props}>
13
13
  <slot />
14
14
  </div>
15
15
  <style>
16
- .row {
16
+ .sui-row {
17
17
  display: flex;
18
18
  flex-direction: row;
19
19
  position: relative;
20
20
  flex-wrap: wrap;
21
21
  }
22
22
 
23
- .row.align {
23
+ .sui-row.align {
24
24
  align-items: center;
25
25
  }
26
26
 
27
- .row.sm {
27
+ .sui-row.sm {
28
28
  gap: .5rem;
29
29
  }
30
30
 
31
- .row.md {
31
+ .sui-row.md {
32
32
  gap: 1rem;
33
33
  }
34
34
 
35
- .row.lg {
35
+ .sui-row.lg {
36
36
  gap: 2rem;
37
37
  }
38
38
  </style>
@@ -7,7 +7,7 @@ interface Option {
7
7
  label: string;
8
8
  value: string;
9
9
  disabled?: boolean;
10
- };
10
+ }
11
11
 
12
12
  interface Props {
13
13
  label?: string;
@@ -18,7 +18,8 @@ interface Props {
18
18
  options: Option[];
19
19
  disabled?: boolean;
20
20
  fullWidth?: boolean;
21
- };
21
+ placeholder?: string;
22
+ }
22
23
 
23
24
  const {
24
25
  label,
@@ -29,29 +30,31 @@ const {
29
30
  options = [],
30
31
  disabled,
31
32
  fullWidth,
33
+ placeholder,
32
34
  } = Astro.props;
33
35
  ---
34
36
 
35
37
  <div
36
38
  id={`${name}-container`}
37
- class="search-select-label"
39
+ class="sui-search-select-label"
38
40
  class:list={[disabled && "disabled", className, fullWidth && "full"]}
39
41
  >
40
- <label class="label" for={`${name}-search-select-btn`}>
41
- {label}
42
- <span class="req-star">{isRequired && "*"}</span>
43
- </label>
44
- <div class="search-input-wrapper" id={`${name}-search-input-wrapper`}>
42
+ <div class="sui-search-input-wrapper" id={`${name}-search-input-wrapper`}>
45
43
  <Input
46
- placeholder={options.find((x) => x.value === defaultValue)?.label || "Select"}
44
+ placeholder={options.find((x) => x.value === defaultValue)?.label || (placeholder || "Select")}
45
+ role='combobox'
46
+ aria-controls={`${name}-dropdown`}
47
+ aria-expanded="false"
48
+ label={label || ''}
49
+ isRequired={isRequired || false}
47
50
  />
48
- <Icon name="chevron-up-down" class="search-select-indicator" width={24} height={24} />
51
+ <Icon name="chevron-up-down" class="sui-search-select-indicator" width={24} height={24} />
49
52
  </div>
50
- <ul class="search-select-dropdown" role="listbox" id={`${name}-dropdown`}>
53
+ <ul class="sui-search-select-dropdown" role="listbox" id={`${name}-dropdown`}>
51
54
  {
52
55
  options.map((x, i) => (
53
56
  <li
54
- class="search-select-option"
57
+ class="sui-search-select-option"
55
58
  role="option"
56
59
  value={x.value}
57
60
  class:list={[
@@ -67,7 +70,7 @@ const {
67
70
  ))
68
71
  }
69
72
  </ul>
70
- <select class="hidden-select" id={name} name={name} required={isRequired}>
73
+ <select class="sui-hidden-select" id={name} name={name} required={isRequired}>
71
74
  <option value={""}> Select </option>
72
75
  {
73
76
  options.map((x) => (
@@ -116,12 +119,14 @@ const {
116
119
  };
117
120
 
118
121
  if (active) {
122
+ searchInput.ariaExpanded = false;
119
123
  dropdown.classList.remove("active", "above");
120
124
  active = false;
121
125
  return;
122
126
  }
123
127
 
124
128
  active = true;
129
+ searchInput.ariaExpanded = true;
125
130
 
126
131
  if (
127
132
  CustomRect.top >= 0 &&
@@ -300,7 +305,7 @@ const {
300
305
  for (const option of options) {
301
306
  const element = document.createElement('li');
302
307
  element.classList.add(...[
303
- 'search-select-option',
308
+ 'sui-search-select-option',
304
309
  option.disabled && "disabled",
305
310
  focusIndex === i && 'focused',
306
311
  ].filter(Boolean));
@@ -322,7 +327,7 @@ const {
322
327
  }
323
328
  </script>
324
329
  <style is:global>
325
- .search-select-label {
330
+ .sui-search-select-label {
326
331
  width: fit-content;
327
332
  display: flex;
328
333
  flex-direction: column;
@@ -331,11 +336,11 @@ const {
331
336
  position: relative;
332
337
  }
333
338
 
334
- .search-select-label.full {
339
+ .sui-search-select-label.full {
335
340
  width: 100%;
336
341
  }
337
342
 
338
- .search-select-label.disabled {
343
+ .sui-search-select-label.disabled {
339
344
  opacity: 0.5;
340
345
  pointer-events: none;
341
346
  color: hsl(var(--text-muted));
@@ -350,7 +355,7 @@ const {
350
355
  font-weight: 700;
351
356
  }
352
357
 
353
- .search-select-dropdown {
358
+ .sui-search-select-dropdown {
354
359
  position: absolute;
355
360
  width: 100%;
356
361
  border: 1px solid hsl(var(--border));
@@ -368,34 +373,34 @@ const {
368
373
  box-shadow: 0px 4px 8px hsl(var(--shadow), 0.5);
369
374
  }
370
375
 
371
- .search-select-dropdown.above {
376
+ .sui-search-select-dropdown.above {
372
377
  top: auto;
373
378
  bottom: calc(100% - 18px + 0.25rem);
374
379
  }
375
380
 
376
- .search-select-option, .empty-search-results {
381
+ .sui-search-select-option, .empty-search-results {
377
382
  padding: 0.5rem;
378
383
  cursor: pointer;
379
384
  font-size: 0.975em;
380
385
  transition: all 0.15s ease;
381
386
  }
382
387
 
383
- .search-select-option.disabled {
388
+ .sui-search-select-option.disabled {
384
389
  pointer-events: none;
385
390
  color: hsl(var(--text-muted));
386
391
  }
387
392
 
388
- .search-select-option:hover, .search-select-option.focused {
393
+ .sui-search-select-option:hover, .sui-search-select-option.focused {
389
394
  background-color: hsl(var(--background-step-3));
390
395
  }
391
396
 
392
- .search-select-option.selected {
397
+ .sui-search-select-option.selected {
393
398
  background-color: hsl(var(--primary-base));
394
399
  color: hsl(var(--text-inverted));
395
400
  cursor: default;
396
401
  }
397
402
 
398
- .hidden-select {
403
+ .sui-hidden-select {
399
404
  height: 0;
400
405
  width: 0;
401
406
  border: none;
@@ -406,25 +411,24 @@ const {
406
411
  opacity: 0;
407
412
  }
408
413
 
409
- .search-input-wrapper {
414
+ .sui-search-input-wrapper {
410
415
  width: 100%;
411
416
  position: relative;
412
417
  height: fit-content;
413
418
  cursor: pointer;
414
419
  }
415
420
 
416
- .search-select-indicator {
421
+ .sui-search-select-indicator {
417
422
  position: absolute;
418
- top: calc(65% + 1px);
419
- transform: translateY(-65%);
420
- right: .5rem;
423
+ bottom: .75rem;
424
+ right: .75rem;
421
425
  }
422
426
 
423
- .search-input-wrapper:has(input:focus) + .search-select-dropdown {
427
+ .sui-search-input-wrapper:has(input:focus) + .sui-search-select-dropdown {
424
428
  display: flex;
425
429
  }
426
430
 
427
- .search-select-dropdown.active, .search-select-dropdown:has(> li:active) {
431
+ .sui-search-select-dropdown.active, .sui-search-select-dropdown:has(> li:active) {
428
432
  display: flex;
429
433
  }
430
434
  </style>
@@ -6,7 +6,7 @@ interface Option {
6
6
  label: string;
7
7
  value: string;
8
8
  disabled?: boolean;
9
- };
9
+ }
10
10
 
11
11
  interface Props {
12
12
  label?: string;
@@ -17,7 +17,8 @@ interface Props {
17
17
  options: Option[];
18
18
  disabled?: boolean;
19
19
  fullWidth?: boolean;
20
- };
20
+ placeholder?: string;
21
+ }
21
22
 
22
23
  const {
23
24
  label,
@@ -28,21 +29,26 @@ const {
28
29
  options = [],
29
30
  disabled,
30
31
  fullWidth,
32
+ placeholder,
31
33
  } = Astro.props;
32
34
  ---
33
35
 
34
36
  <div
35
37
  id={`${name}-container`}
36
- class="select-label"
38
+ class="sui-select-label"
37
39
  class:list={[disabled && "disabled", className, fullWidth && "full"]}
38
40
  >
39
- <label class="label" for={`${name}-select-btn`}>
40
- {label}
41
- <span class="req-star">{isRequired && "*"}</span>
42
- </label>
41
+ {label && (
42
+ <label class="label" for={`${name}-select-btn`}>
43
+ {label}
44
+ <span class="req-star">{isRequired && "*"}</span>
45
+ </label>
46
+ )}
43
47
  <button
44
- class="select-button"
48
+ class="sui-select-button"
45
49
  role="combobox"
50
+ aria-controls={`${name}-dropdown`}
51
+ aria-expanded="false"
46
52
  id={`${name}-select-btn`}
47
53
  type="button"
48
54
  >
@@ -50,16 +56,16 @@ const {
50
56
  {
51
57
  defaultValue
52
58
  ? options.find((x) => x.value === defaultValue)?.label
53
- : "Select"
59
+ : placeholder || "Select"
54
60
  }
55
61
  </span>
56
62
  <Icon name="chevron-up-down" width={24} height={24} />
57
63
  </button>
58
- <ul class="select-dropdown" role="listbox" id={`${name}-dropdown`}>
64
+ <ul class="sui-select-dropdown" role="listbox" id={`${name}-dropdown`}>
59
65
  {
60
66
  options.map((x, i) => (
61
67
  <li
62
- class="select-option"
68
+ class="sui-select-option"
63
69
  role="option"
64
70
  value={x.value}
65
71
  class:list={[
@@ -75,7 +81,7 @@ const {
75
81
  ))
76
82
  }
77
83
  </ul>
78
- <select class="hidden-select" id={name} name={name} required={isRequired}>
84
+ <select class="sui-hidden-select" id={name} name={name} required={isRequired}>
79
85
  <option value={""}> Select </option>
80
86
  {
81
87
  options.map((x) => (
@@ -123,12 +129,14 @@ const {
123
129
  };
124
130
 
125
131
  if (active) {
132
+ button.ariaExpanded = false;
126
133
  dropdown.classList.remove("active", "above");
127
134
  active = false;
128
135
  return;
129
136
  }
130
137
 
131
138
  active = true;
139
+ button.ariaExpanded = true;
132
140
 
133
141
  if (
134
142
  CustomRect.top >= 0 &&
@@ -213,20 +221,21 @@ const {
213
221
  );
214
222
  </script>
215
223
  <style>
216
- .select-label {
224
+ .sui-select-label {
217
225
  width: fit-content;
218
226
  display: flex;
219
227
  flex-direction: column;
220
228
  gap: 0.25rem;
221
229
  min-width: 200px;
222
230
  position: relative;
231
+ height: fit-content;
223
232
  }
224
233
 
225
- .select-label.full {
234
+ .sui-select-label.full, .sui-select-label.full .sui-select-button {
226
235
  width: 100%;
227
236
  }
228
237
 
229
- .select-label.disabled {
238
+ .sui-select-label.disabled {
230
239
  opacity: 0.5;
231
240
  pointer-events: none;
232
241
  color: hsl(var(--text-muted));
@@ -241,7 +250,7 @@ const {
241
250
  font-weight: 700;
242
251
  }
243
252
 
244
- .select-button {
253
+ .sui-select-button {
245
254
  padding: 0.5rem 0.75rem 0.5rem 1rem;
246
255
  border-radius: 8px;
247
256
  border: 1px solid hsl(var(--border));
@@ -256,18 +265,18 @@ const {
256
265
  gap: 1rem;
257
266
  }
258
267
 
259
- .select-button:hover {
268
+ .sui-select-button:hover {
260
269
  background: hsl(var(--background-step-3));
261
270
  }
262
271
 
263
- .select-button.active,
264
- .select-button:active,
265
- .select-button:has(+ .select-dropdown.active) {
272
+ .sui-select-button.active,
273
+ .sui-select-button:active,
274
+ .sui-select-button:has(+ .sui-select-dropdown.active) {
266
275
  border: 1px solid hsl(var(--primary-base));
267
276
  background: hsl(var(--background-step-2));
268
277
  }
269
278
 
270
- .select-dropdown {
279
+ .sui-select-dropdown {
271
280
  position: absolute;
272
281
  width: 100%;
273
282
  border: 1px solid hsl(var(--border));
@@ -285,43 +294,43 @@ const {
285
294
  box-shadow: 0px 4px 8px hsl(var(--shadow), 0.5);
286
295
  }
287
296
 
288
- .select-dropdown.active {
297
+ .sui-select-dropdown.active {
289
298
  display: flex;
290
299
  }
291
300
 
292
- .select-dropdown.above {
301
+ .sui-select-dropdown.above {
293
302
  top: auto;
294
303
  bottom: calc(100% - 18px + 0.25rem);
295
304
  }
296
305
 
297
- .select-option {
306
+ .sui-select-option {
298
307
  padding: 0.5rem;
299
308
  cursor: pointer;
300
309
  font-size: 0.975em;
301
310
  transition: all 0.15s ease;
302
311
  }
303
312
 
304
- .select-option.disabled {
313
+ .sui-select-option.disabled {
305
314
  pointer-events: none;
306
315
  color: hsl(var(--text-muted));
307
316
  }
308
317
 
309
- .select-option:hover, .select-option:focus {
318
+ .sui-select-option:hover, .sui-select-option:focus {
310
319
  background-color: hsl(var(--background-step-3));
311
320
  }
312
321
 
313
- .select-option:focus {
322
+ .sui-select-option:focus {
314
323
  outline: none;
315
324
  border: none;
316
325
  }
317
326
 
318
- .select-option.selected {
327
+ .sui-select-option.selected {
319
328
  background-color: hsl(var(--primary-base));
320
329
  color: hsl(var(--text-inverted));
321
330
  cursor: default;
322
331
  }
323
332
 
324
- .hidden-select {
333
+ .sui-hidden-select {
325
334
  height: 0;
326
335
  width: 0;
327
336
  border: none;
@@ -1,13 +1,13 @@
1
- <div id="sidebars" class="active inner">
2
- <div id="sidebar-outer">
1
+ <div id="sui-sidebars" class="active inner">
2
+ <div id="sui-sidebar-outer">
3
3
  <slot name="outer" />
4
4
  </div>
5
- <div id="sidebar-inner">
5
+ <div id="sui-sidebar-inner">
6
6
  <slot name="inner" />
7
7
  </div>
8
8
  </div>
9
9
  <style>
10
- #sidebars {
10
+ #sui-sidebars {
11
11
  --sidebars-container-width: calc((280px + 1px) * 2);
12
12
  display: flex;
13
13
  align-items: center;
@@ -19,11 +19,11 @@
19
19
  height: 100%;
20
20
  }
21
21
 
22
- #sidebars.active {
22
+ #sui-sidebars.active {
23
23
  transform: translateX(0%);
24
24
  }
25
25
 
26
- #sidebar-outer {
26
+ #sui-sidebar-outer {
27
27
  height: 100%;
28
28
  min-width: 280px;
29
29
  width: 280px;
@@ -39,7 +39,7 @@
39
39
  padding: 1.5rem;
40
40
  }
41
41
 
42
- #sidebar-inner {
42
+ #sui-sidebar-inner {
43
43
  min-width: 280px;
44
44
  width: 280px;
45
45
  height: 100%;
@@ -56,7 +56,7 @@
56
56
  }
57
57
 
58
58
  @media screen and (max-width: 1200px) {
59
- #sidebars {
59
+ #sui-sidebars {
60
60
  --sidebars-container-width: calc(280px + 1px);
61
61
  }
62
62
 
@@ -64,7 +64,7 @@
64
64
  display: block;
65
65
  }
66
66
 
67
- #sidebars.inner {
67
+ #sui-sidebars.inner {
68
68
  #sidebar-outer,
69
69
  #sidebar-inner {
70
70
  transform: translateX(-100%);
@@ -73,7 +73,7 @@
73
73
  }
74
74
 
75
75
  @media screen and (max-width: 840px) {
76
- #sidebars {
76
+ #sui-sidebars {
77
77
  transform: translateX(-100%);
78
78
  position: absolute;
79
79
  top: 0;
@@ -82,8 +82,8 @@
82
82
  width: 100%;
83
83
  }
84
84
 
85
- #sidebar-outer,
86
- #sidebar-inner {
85
+ #sui-sidebar-outer,
86
+ #sui-sidebar-inner {
87
87
  width: 100%;
88
88
  flex: 0 0 100%;
89
89
  }