@studiocms/ui 0.4.16 → 1.0.0-beta.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/dist/components/Accordion/Accordion.astro +1 -0
- package/dist/components/Accordion/Item.astro +8 -6
- package/dist/components/Accordion/accordion.css +35 -21
- package/dist/components/Accordion/accordion.d.ts +46 -1
- package/dist/components/Accordion/accordion.js +95 -70
- package/dist/components/Badge/Badge.astro +2 -2
- package/dist/components/Badge/badge.css +32 -32
- package/dist/components/Breadcrumbs/breadcrumbs.css +1 -1
- package/dist/components/Button/button.css +93 -93
- package/dist/components/Card/card.css +4 -4
- package/dist/components/Checkbox/checkbox.css +26 -26
- package/dist/components/Divider/Divider.astro +1 -1
- package/dist/components/Divider/divider.css +2 -2
- package/dist/components/Dropdown/Dropdown.astro +2 -2
- package/dist/components/Dropdown/dropdown.css +26 -26
- package/dist/components/Footer/footer.css +4 -4
- package/dist/components/Icon/Icon.astro +114 -6
- package/dist/components/Icon/IconBase.astro +108 -7
- package/dist/components/Icon/errors.d.ts +29 -0
- package/dist/components/Icon/errors.js +25 -0
- package/dist/components/Input/input.css +9 -9
- package/dist/components/Modal/Modal.astro +1 -1
- package/dist/components/Modal/modal.css +4 -4
- package/dist/components/Progress/progress.css +7 -7
- package/dist/components/RadioGroup/radiogroup.css +21 -21
- package/dist/components/SearchSelect/SearchSelect.astro +29 -27
- package/dist/components/SearchSelect/searchselect.css +26 -15
- package/dist/components/SearchSelect/searchselect.js +29 -9
- package/dist/components/Select/Select.astro +28 -26
- package/dist/components/Select/select.css +32 -20
- package/dist/components/Select/select.js +1 -1
- package/dist/components/Sidebar/Double.astro +4 -4
- package/dist/components/Sidebar/Single.astro +2 -2
- package/dist/components/Skeleton/Skeleton.astro +61 -0
- package/dist/components/Skeleton/skeleton.css +111 -0
- package/dist/components/Skeleton/skeleton.d.ts +161 -0
- package/dist/components/Skeleton/skeleton.js +71 -0
- package/dist/components/Tabs/TabItem.astro +14 -9
- package/dist/components/Tabs/Tabs.astro +91 -54
- package/dist/components/Tabs/tabs.css +14 -14
- package/dist/components/Tabs/tabs.d.ts +17 -1
- package/dist/components/Tabs/tabs.js +99 -76
- package/dist/components/Textarea/textarea.css +8 -8
- package/dist/components/Toast/toaster.css +26 -23
- package/dist/components/Toast/toaster.js +4 -0
- package/dist/components/Toggle/toggle.css +13 -13
- package/dist/components/Tooltip/Tooltip.astro +119 -0
- package/dist/components/Tooltip/tooltip.css +187 -0
- package/dist/components/Tooltip/tooltip.d.ts +46 -0
- package/dist/components/Tooltip/tooltip.js +330 -0
- package/dist/components/User/User.astro +1 -1
- package/dist/components/User/user.css +3 -3
- package/dist/css/colors.css +85 -83
- package/dist/css/prose.css +360 -0
- package/dist/css/resets.css +3 -3
- package/dist/events.d.ts +104 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +120 -313
- package/dist/toolbar/index.js +5 -5
- package/dist/types/index.d.ts +2 -0
- package/dist/utils/iconifyUtils.d.ts +1 -1
- package/dist/virtuals.d.js +0 -0
- package/dist/virtuals.d.ts +564 -0
- package/package.json +5 -1
- package/dist/components/Icon/iconType.d.ts +0 -2
- package/dist/components/ThemeToggle/ThemeToggle.astro +0 -21
- package/dist/components/ThemeToggle/themetoggle.css +0 -17
- package/dist/components/ThemeToggle/themetoggle.d.ts +0 -1
- package/dist/components/ThemeToggle/themetoggle.js +0 -4
- /package/dist/{components/Icon/iconType.js → events.d.js} +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { z } from 'astro/zod';
|
|
2
|
+
export declare const SkeletonSchema: z.ZodUnion<[z.ZodObject<{
|
|
3
|
+
/**
|
|
4
|
+
* The variant of the skeleton.
|
|
5
|
+
*/
|
|
6
|
+
variant: z.ZodLiteral<"text">;
|
|
7
|
+
/**
|
|
8
|
+
* The class of the skeleton. Defaults to `undefined`.
|
|
9
|
+
*/
|
|
10
|
+
class: z.ZodOptional<z.ZodString>;
|
|
11
|
+
/**
|
|
12
|
+
* The radius of the skeleton. Defaults to `lg`.
|
|
13
|
+
*/
|
|
14
|
+
radius: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"none">, z.ZodLiteral<"sm">, z.ZodLiteral<"md">, z.ZodLiteral<"lg">]>>;
|
|
15
|
+
/**
|
|
16
|
+
* The animation of the skeleton. Defaults to `slide`.
|
|
17
|
+
*/
|
|
18
|
+
animation: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"none">, z.ZodLiteral<"slide">, z.ZodLiteral<"pulse">]>>;
|
|
19
|
+
/**
|
|
20
|
+
* The width of the skeleton. Defaults to `100%`.
|
|
21
|
+
*/
|
|
22
|
+
width: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
23
|
+
/**
|
|
24
|
+
* The height of the skeleton. Defaults to `100%`.
|
|
25
|
+
*/
|
|
26
|
+
height: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
27
|
+
}, "strip", z.ZodTypeAny, {
|
|
28
|
+
variant: "text";
|
|
29
|
+
width?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
30
|
+
height?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
31
|
+
class?: string | undefined;
|
|
32
|
+
radius?: "sm" | "none" | "md" | "lg" | undefined;
|
|
33
|
+
animation?: "none" | "slide" | "pulse" | undefined;
|
|
34
|
+
}, {
|
|
35
|
+
variant: "text";
|
|
36
|
+
width?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
37
|
+
height?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
38
|
+
class?: string | undefined;
|
|
39
|
+
radius?: "sm" | "none" | "md" | "lg" | undefined;
|
|
40
|
+
animation?: "none" | "slide" | "pulse" | undefined;
|
|
41
|
+
}>, z.ZodObject<z.objectUtil.extendShape<{
|
|
42
|
+
/**
|
|
43
|
+
* The variant of the skeleton.
|
|
44
|
+
*/
|
|
45
|
+
variant: z.ZodLiteral<"text">;
|
|
46
|
+
/**
|
|
47
|
+
* The class of the skeleton. Defaults to `undefined`.
|
|
48
|
+
*/
|
|
49
|
+
class: z.ZodOptional<z.ZodString>;
|
|
50
|
+
/**
|
|
51
|
+
* The radius of the skeleton. Defaults to `lg`.
|
|
52
|
+
*/
|
|
53
|
+
radius: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"none">, z.ZodLiteral<"sm">, z.ZodLiteral<"md">, z.ZodLiteral<"lg">]>>;
|
|
54
|
+
/**
|
|
55
|
+
* The animation of the skeleton. Defaults to `slide`.
|
|
56
|
+
*/
|
|
57
|
+
animation: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"none">, z.ZodLiteral<"slide">, z.ZodLiteral<"pulse">]>>;
|
|
58
|
+
/**
|
|
59
|
+
* The width of the skeleton. Defaults to `100%`.
|
|
60
|
+
*/
|
|
61
|
+
width: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
62
|
+
/**
|
|
63
|
+
* The height of the skeleton. Defaults to `100%`.
|
|
64
|
+
*/
|
|
65
|
+
height: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
66
|
+
}, {
|
|
67
|
+
/**
|
|
68
|
+
* The variant of the skeleton. `card` is used for cards which contain other Skeleton components.
|
|
69
|
+
*/
|
|
70
|
+
variant: z.ZodLiteral<"card">;
|
|
71
|
+
/**
|
|
72
|
+
* The direction of the skeleton. Defaults to `column`.
|
|
73
|
+
*/
|
|
74
|
+
direction: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"row">, z.ZodLiteral<"column">]>>;
|
|
75
|
+
/**
|
|
76
|
+
* The horizontal alignment of the skeleton. Defaults to `center`.
|
|
77
|
+
*/
|
|
78
|
+
hAlign: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"start">, z.ZodLiteral<"center">, z.ZodLiteral<"end">]>>;
|
|
79
|
+
/**
|
|
80
|
+
* The vertical alignment of the skeleton. Defaults to `center`.
|
|
81
|
+
*/
|
|
82
|
+
vAlign: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"start">, z.ZodLiteral<"center">, z.ZodLiteral<"end">]>>;
|
|
83
|
+
/**
|
|
84
|
+
* The gap between the skeletons. Defaults to `0.5rem`.
|
|
85
|
+
*/
|
|
86
|
+
gap: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
87
|
+
}>, "strip", z.ZodTypeAny, {
|
|
88
|
+
variant: "card";
|
|
89
|
+
width?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
90
|
+
height?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
91
|
+
class?: string | undefined;
|
|
92
|
+
radius?: "sm" | "none" | "md" | "lg" | undefined;
|
|
93
|
+
animation?: "none" | "slide" | "pulse" | undefined;
|
|
94
|
+
direction?: "row" | "column" | undefined;
|
|
95
|
+
hAlign?: "center" | "start" | "end" | undefined;
|
|
96
|
+
vAlign?: "center" | "start" | "end" | undefined;
|
|
97
|
+
gap?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
98
|
+
}, {
|
|
99
|
+
variant: "card";
|
|
100
|
+
width?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
101
|
+
height?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
102
|
+
class?: string | undefined;
|
|
103
|
+
radius?: "sm" | "none" | "md" | "lg" | undefined;
|
|
104
|
+
animation?: "none" | "slide" | "pulse" | undefined;
|
|
105
|
+
direction?: "row" | "column" | undefined;
|
|
106
|
+
hAlign?: "center" | "start" | "end" | undefined;
|
|
107
|
+
vAlign?: "center" | "start" | "end" | undefined;
|
|
108
|
+
gap?: `${number}px` | `${number}rem` | `${number}%` | undefined;
|
|
109
|
+
}>, z.ZodObject<z.objectUtil.extendShape<{
|
|
110
|
+
/**
|
|
111
|
+
* The variant of the skeleton.
|
|
112
|
+
*/
|
|
113
|
+
variant: z.ZodLiteral<"text">;
|
|
114
|
+
/**
|
|
115
|
+
* The class of the skeleton. Defaults to `undefined`.
|
|
116
|
+
*/
|
|
117
|
+
class: z.ZodOptional<z.ZodString>;
|
|
118
|
+
/**
|
|
119
|
+
* The radius of the skeleton. Defaults to `lg`.
|
|
120
|
+
*/
|
|
121
|
+
radius: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"none">, z.ZodLiteral<"sm">, z.ZodLiteral<"md">, z.ZodLiteral<"lg">]>>;
|
|
122
|
+
/**
|
|
123
|
+
* The animation of the skeleton. Defaults to `slide`.
|
|
124
|
+
*/
|
|
125
|
+
animation: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"none">, z.ZodLiteral<"slide">, z.ZodLiteral<"pulse">]>>;
|
|
126
|
+
/**
|
|
127
|
+
* The width of the skeleton. Defaults to `100%`.
|
|
128
|
+
*/
|
|
129
|
+
width: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
130
|
+
/**
|
|
131
|
+
* The height of the skeleton. Defaults to `100%`.
|
|
132
|
+
*/
|
|
133
|
+
height: z.ZodOptional<z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>>;
|
|
134
|
+
}, {
|
|
135
|
+
/**
|
|
136
|
+
* The variant of the skeleton. `circle` is used for circles which contain other Skeleton components.
|
|
137
|
+
*/
|
|
138
|
+
variant: z.ZodUnion<[z.ZodLiteral<"circle">, z.ZodLiteral<"block">]>;
|
|
139
|
+
/**
|
|
140
|
+
* The width of the skeleton.
|
|
141
|
+
*/
|
|
142
|
+
width: z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>;
|
|
143
|
+
/**
|
|
144
|
+
* The height of the skeleton.
|
|
145
|
+
*/
|
|
146
|
+
height: z.ZodUnion<[z.ZodType<`${number}px`, z.ZodTypeDef, `${number}px`>, z.ZodType<`${number}rem`, z.ZodTypeDef, `${number}rem`>, z.ZodType<`${number}%`, z.ZodTypeDef, `${number}%`>]>;
|
|
147
|
+
}>, "strip", z.ZodTypeAny, {
|
|
148
|
+
width: `${number}px` | `${number}rem` | `${number}%`;
|
|
149
|
+
height: `${number}px` | `${number}rem` | `${number}%`;
|
|
150
|
+
variant: "circle" | "block";
|
|
151
|
+
class?: string | undefined;
|
|
152
|
+
radius?: "sm" | "none" | "md" | "lg" | undefined;
|
|
153
|
+
animation?: "none" | "slide" | "pulse" | undefined;
|
|
154
|
+
}, {
|
|
155
|
+
width: `${number}px` | `${number}rem` | `${number}%`;
|
|
156
|
+
height: `${number}px` | `${number}rem` | `${number}%`;
|
|
157
|
+
variant: "circle" | "block";
|
|
158
|
+
class?: string | undefined;
|
|
159
|
+
radius?: "sm" | "none" | "md" | "lg" | undefined;
|
|
160
|
+
animation?: "none" | "slide" | "pulse" | undefined;
|
|
161
|
+
}>]>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "astro/zod";
|
|
2
|
+
const measurementPx = z.custom();
|
|
3
|
+
const measurementRem = z.custom();
|
|
4
|
+
const measurementPercent = z.custom();
|
|
5
|
+
const measurement = z.union([measurementPx, measurementRem, measurementPercent]);
|
|
6
|
+
const BaseSkeletonSchema = z.object({
|
|
7
|
+
/**
|
|
8
|
+
* The variant of the skeleton.
|
|
9
|
+
*/
|
|
10
|
+
variant: z.literal("text"),
|
|
11
|
+
/**
|
|
12
|
+
* The class of the skeleton. Defaults to `undefined`.
|
|
13
|
+
*/
|
|
14
|
+
class: z.string().optional(),
|
|
15
|
+
/**
|
|
16
|
+
* The radius of the skeleton. Defaults to `lg`.
|
|
17
|
+
*/
|
|
18
|
+
radius: z.union([z.literal("none"), z.literal("sm"), z.literal("md"), z.literal("lg")]).optional(),
|
|
19
|
+
/**
|
|
20
|
+
* The animation of the skeleton. Defaults to `slide`.
|
|
21
|
+
*/
|
|
22
|
+
animation: z.union([z.literal("none"), z.literal("slide"), z.literal("pulse")]).optional(),
|
|
23
|
+
/**
|
|
24
|
+
* The width of the skeleton. Defaults to `100%`.
|
|
25
|
+
*/
|
|
26
|
+
width: measurement.optional(),
|
|
27
|
+
/**
|
|
28
|
+
* The height of the skeleton. Defaults to `100%`.
|
|
29
|
+
*/
|
|
30
|
+
height: measurement.optional()
|
|
31
|
+
});
|
|
32
|
+
const CardSkeletonSchema = BaseSkeletonSchema.extend({
|
|
33
|
+
/**
|
|
34
|
+
* The variant of the skeleton. `card` is used for cards which contain other Skeleton components.
|
|
35
|
+
*/
|
|
36
|
+
variant: z.literal("card"),
|
|
37
|
+
/**
|
|
38
|
+
* The direction of the skeleton. Defaults to `column`.
|
|
39
|
+
*/
|
|
40
|
+
direction: z.union([z.literal("row"), z.literal("column")]).optional(),
|
|
41
|
+
/**
|
|
42
|
+
* The horizontal alignment of the skeleton. Defaults to `center`.
|
|
43
|
+
*/
|
|
44
|
+
hAlign: z.union([z.literal("start"), z.literal("center"), z.literal("end")]).optional(),
|
|
45
|
+
/**
|
|
46
|
+
* The vertical alignment of the skeleton. Defaults to `center`.
|
|
47
|
+
*/
|
|
48
|
+
vAlign: z.union([z.literal("start"), z.literal("center"), z.literal("end")]).optional(),
|
|
49
|
+
/**
|
|
50
|
+
* The gap between the skeletons. Defaults to `0.5rem`.
|
|
51
|
+
*/
|
|
52
|
+
gap: measurement.optional()
|
|
53
|
+
});
|
|
54
|
+
const BlockCircleSchema = BaseSkeletonSchema.extend({
|
|
55
|
+
/**
|
|
56
|
+
* The variant of the skeleton. `circle` is used for circles which contain other Skeleton components.
|
|
57
|
+
*/
|
|
58
|
+
variant: z.union([z.literal("circle"), z.literal("block")]),
|
|
59
|
+
/**
|
|
60
|
+
* The width of the skeleton.
|
|
61
|
+
*/
|
|
62
|
+
width: measurement,
|
|
63
|
+
/**
|
|
64
|
+
* The height of the skeleton.
|
|
65
|
+
*/
|
|
66
|
+
height: measurement
|
|
67
|
+
});
|
|
68
|
+
const SkeletonSchema = z.union([BaseSkeletonSchema, CardSkeletonSchema, BlockCircleSchema]);
|
|
69
|
+
export {
|
|
70
|
+
SkeletonSchema
|
|
71
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
+
import type { AvailableIcons } from 'studiocms:ui/icons';
|
|
2
3
|
import type { StudioCMSColorway } from '../../utils/colors.js';
|
|
3
4
|
import { generateID } from '../../utils/generateID.js';
|
|
4
|
-
import type { HeroIconName } from '../Icon/iconType.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The props for the TabItem component.
|
|
@@ -10,7 +10,7 @@ interface Props {
|
|
|
10
10
|
/**
|
|
11
11
|
* The icon to display next to the tab.
|
|
12
12
|
*/
|
|
13
|
-
icon?:
|
|
13
|
+
icon?: AvailableIcons;
|
|
14
14
|
/**
|
|
15
15
|
* The label of the tab.
|
|
16
16
|
*/
|
|
@@ -19,19 +19,24 @@ interface Props {
|
|
|
19
19
|
* The color of the tab. Defaults to `primary`.
|
|
20
20
|
*/
|
|
21
21
|
color?: Exclude<StudioCMSColorway, 'default'>;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the tab should be active by default.
|
|
24
|
+
*/
|
|
25
|
+
active?: boolean;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
const id = generateID('tab');
|
|
25
29
|
|
|
26
|
-
const { icon, label, color = 'primary' } = Astro.props;
|
|
30
|
+
const { icon, label, color = 'primary', active = false } = Astro.props;
|
|
27
31
|
---
|
|
28
|
-
<sui-tab-item
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
<sui-tab-item
|
|
33
|
+
data-icon={icon}
|
|
34
|
+
data-label={label}
|
|
35
|
+
data-color={color}
|
|
36
|
+
data-tab-id={id}
|
|
37
|
+
data-active={active ? 'true' : undefined}
|
|
33
38
|
>
|
|
34
|
-
|
|
39
|
+
<slot />
|
|
35
40
|
</sui-tab-item>
|
|
36
41
|
<style>
|
|
37
42
|
sui-tab-item {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
+
import type { AvailableIcons } from 'studiocms:ui/icons';
|
|
2
3
|
import type { StudioCMSColorway } from '../../utils/colors.js';
|
|
3
4
|
import { generateID } from '../../utils/generateID.js';
|
|
4
5
|
import Icon from '../Icon/Icon.astro';
|
|
5
|
-
import type { HeroIconName } from '../Icon/iconType.js';
|
|
6
6
|
import './tabs.css';
|
|
7
7
|
|
|
8
8
|
interface Tab {
|
|
9
|
-
icon?:
|
|
9
|
+
icon?: AvailableIcons;
|
|
10
10
|
label: string;
|
|
11
11
|
color: Exclude<StudioCMSColorway, 'default'>;
|
|
12
12
|
tabId: string;
|
|
13
|
+
active?: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -35,63 +36,94 @@ interface Props {
|
|
|
35
36
|
align?: 'left' | 'center' | 'right';
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Parses data attributes from an HTML tag string.
|
|
41
|
+
* @param tagContent The string content of the HTML tag.
|
|
42
|
+
* @returns An object of key-value pairs for the parsed attributes.
|
|
43
|
+
*/
|
|
44
|
+
const getAttributes = (tagContent: string) => {
|
|
45
|
+
const attributes: { [key: string]: string | boolean } = {};
|
|
41
46
|
const attributeRegex = /data-([\w-]+)="([^"]*)"/g;
|
|
47
|
+
for (const match of tagContent.matchAll(attributeRegex)) {
|
|
48
|
+
const [, key, value] = match;
|
|
49
|
+
if (!key || !value) continue;
|
|
50
|
+
if (key === 'icon' || key === 'label' || key === 'color') {
|
|
51
|
+
attributes[key] = value;
|
|
52
|
+
} else if (key === 'tab-id') {
|
|
53
|
+
attributes.tabId = value;
|
|
54
|
+
} else if (key === 'active') {
|
|
55
|
+
attributes.active = value === 'true';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return attributes;
|
|
59
|
+
};
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Extracts direct child Tab info from an HTML string, ignoring nested tabs.
|
|
63
|
+
* This function uses a two-pass approach to handle nesting.
|
|
64
|
+
* 1. It first scans for all nested `sui-tabs-container` elements and records their start and end positions.
|
|
65
|
+
* 2. It then finds all `sui-tab-item` elements and includes only those that do not fall within the nested ranges.
|
|
66
|
+
* @param html The raw HTML string from the rendered slot.
|
|
67
|
+
* @returns An array of Tab objects for direct children only.
|
|
68
|
+
*/
|
|
69
|
+
const extractTabInfoWithRegex = (html: string): Tab[] => {
|
|
70
|
+
const nestedContainerRanges: { start: number; end: number }[] = [];
|
|
71
|
+
const containerRegex = /<div[^>]*?class="[^"]*?\bsui-tabs-container\b[^"]*?".*?>/gi;
|
|
72
|
+
for (const containerMatch of html.matchAll(containerRegex)) {
|
|
73
|
+
const startIndex = containerMatch.index;
|
|
74
|
+
let openCount = 0;
|
|
75
|
+
const searchArea = html.substring(startIndex);
|
|
76
|
+
const tagRegex = /<\/?div/gi;
|
|
77
|
+
for (const tagMatch of searchArea.matchAll(tagRegex)) {
|
|
78
|
+
if (tagMatch[0].toLowerCase() === '<div') {
|
|
79
|
+
openCount++;
|
|
80
|
+
} else {
|
|
81
|
+
openCount--;
|
|
64
82
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
83
|
+
if (openCount === 0) {
|
|
84
|
+
const endIndex = startIndex + tagMatch.index + tagMatch[0].length;
|
|
85
|
+
nestedContainerRanges.push({ start: startIndex, end: endIndex });
|
|
86
|
+
break;
|
|
68
87
|
}
|
|
69
88
|
}
|
|
70
|
-
|
|
71
|
-
tabs.push(attributes as unknown as Tab);
|
|
72
89
|
}
|
|
73
90
|
|
|
91
|
+
const tabs: Tab[] = [];
|
|
92
|
+
const tabItemRegex = /<sui-tab-item([^>]*?)>/gi;
|
|
93
|
+
for (const tabMatch of html.matchAll(tabItemRegex)) {
|
|
94
|
+
const tabIndex = tabMatch.index;
|
|
95
|
+
const isNested = nestedContainerRanges.some(
|
|
96
|
+
(range) => tabIndex > range.start && tabIndex < range.end
|
|
97
|
+
);
|
|
98
|
+
if (!isNested) {
|
|
99
|
+
const attributes = getAttributes(tabMatch[1]);
|
|
100
|
+
if (attributes.tabId) {
|
|
101
|
+
tabs.push(attributes as unknown as Tab);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
74
105
|
return tabs;
|
|
75
106
|
};
|
|
76
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Injects the `active` class into the specified tab item in an HTML string.
|
|
110
|
+
* @param tabId The `data-tab-id` of the tab to mark as active.
|
|
111
|
+
* @param html The raw HTML string to modify.
|
|
112
|
+
* @returns The modified HTML string with the active tab.
|
|
113
|
+
*/
|
|
77
114
|
const markTabAsActive = (tabId: string, html: string): string => {
|
|
78
115
|
if (!tabId) return html;
|
|
79
116
|
|
|
80
117
|
const updatedHtml = html.replace(
|
|
81
118
|
/<sui-tab-item[^>]*data-tab-id="([^"]*)"[^>]*>/g,
|
|
82
119
|
(match, tabIdValue) => {
|
|
83
|
-
// Check if the tabId matches
|
|
84
120
|
if (tabIdValue === tabId) {
|
|
85
|
-
// Check if the element already has a class attribute
|
|
86
121
|
if (match.includes('class="')) {
|
|
87
|
-
// If class attribute exists, add 'active' to the class attribute
|
|
88
122
|
return match.replace(/(class="[^"]*)"/, '$1 active"');
|
|
89
123
|
}
|
|
90
|
-
|
|
91
|
-
// If class attribute does not exist, add it
|
|
92
124
|
return match.replace(/(<sui-tab-item[^>]*data-tab-id="[^"]*")/, '$1 class="active"');
|
|
93
125
|
}
|
|
94
|
-
return match;
|
|
126
|
+
return match;
|
|
95
127
|
}
|
|
96
128
|
);
|
|
97
129
|
|
|
@@ -111,7 +143,8 @@ const syncKey = originalSyncKey ? `sui-tabs-${originalSyncKey}` : undefined;
|
|
|
111
143
|
|
|
112
144
|
const tabContents = await Astro.slots.render('default');
|
|
113
145
|
const tabs = extractTabInfoWithRegex(tabContents);
|
|
114
|
-
const
|
|
146
|
+
const defaultActiveTab = tabs.find((tab) => tab.active) ?? tabs[0];
|
|
147
|
+
const finalizedTabContents = markTabAsActive(defaultActiveTab?.tabId || '', tabContents);
|
|
115
148
|
const containerId = generateID('sui-tabs-container');
|
|
116
149
|
---
|
|
117
150
|
|
|
@@ -124,27 +157,31 @@ const containerId = generateID('sui-tabs-container');
|
|
|
124
157
|
class:list={[variant, align]}
|
|
125
158
|
>
|
|
126
159
|
<div class="sui-tabs-list" role="tablist">
|
|
127
|
-
{tabs.map((tab, i) =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
160
|
+
{tabs.map((tab, i) => {
|
|
161
|
+
const isActive = tab.tabId === defaultActiveTab?.tabId;
|
|
162
|
+
return (
|
|
163
|
+
<button
|
|
164
|
+
role="tab"
|
|
165
|
+
type="button"
|
|
166
|
+
class="sui-tab-header"
|
|
167
|
+
id={syncKey ? `${syncKey}-${i}` : undefined}
|
|
168
|
+
tabindex={isActive ? 0 : -1}
|
|
169
|
+
data-tab-child={tab.tabId}
|
|
170
|
+
class:list={[isActive && "active", tab.color, syncKey && `${syncKey}:${i}`]}
|
|
171
|
+
>
|
|
172
|
+
{tab.icon && (
|
|
173
|
+
<Icon name={tab.icon} width={24} height={24} />
|
|
174
|
+
)}
|
|
175
|
+
<span>{tab.label}</span>
|
|
176
|
+
</button>
|
|
177
|
+
)
|
|
178
|
+
})}
|
|
143
179
|
</div>
|
|
144
180
|
<div class="sui-tabs-content">
|
|
145
181
|
<Fragment set:html={finalizedTabContents} />
|
|
146
182
|
</div>
|
|
147
183
|
</div>
|
|
184
|
+
|
|
148
185
|
<script>
|
|
149
186
|
import "studiocms:ui/scripts/tabs"
|
|
150
187
|
</script>
|
|
@@ -48,29 +48,29 @@
|
|
|
48
48
|
pointer-events: none;
|
|
49
49
|
}
|
|
50
50
|
.sui-tabs-container.default .sui-tab-header:focus-visible {
|
|
51
|
-
outline: 2px solid
|
|
51
|
+
outline: 2px solid var(--text-normal);
|
|
52
52
|
outline-offset: 2px;
|
|
53
53
|
}
|
|
54
54
|
.sui-tabs-container.default .sui-tab-header:hover {
|
|
55
|
-
background-color:
|
|
55
|
+
background-color: var(--default-flat-active) !important;
|
|
56
56
|
}
|
|
57
57
|
.sui-tabs-container.default .sui-tab-header.active {
|
|
58
|
-
background-color:
|
|
58
|
+
background-color: var(--primary-flat-active) !important;
|
|
59
59
|
}
|
|
60
60
|
.sui-tabs-container.default .sui-tab-header.success.active {
|
|
61
|
-
background-color:
|
|
61
|
+
background-color: var(--success-flat-active) !important;
|
|
62
62
|
}
|
|
63
63
|
.sui-tabs-container.default .sui-tab-header.warning.active {
|
|
64
|
-
background-color:
|
|
64
|
+
background-color: var(--warning-flat-active) !important;
|
|
65
65
|
}
|
|
66
66
|
.sui-tabs-container.default .sui-tab-header.danger.active {
|
|
67
|
-
background-color:
|
|
67
|
+
background-color: var(--danger-flat-active) !important;
|
|
68
68
|
}
|
|
69
69
|
.sui-tabs-container.default .sui-tab-header.danger.info {
|
|
70
|
-
background-color:
|
|
70
|
+
background-color: var(--info-flat-active) !important;
|
|
71
71
|
}
|
|
72
72
|
.sui-tabs-container.default .sui-tab-header.danger.mono {
|
|
73
|
-
background-color:
|
|
73
|
+
background-color: var(--mono-flat-active) !important;
|
|
74
74
|
}
|
|
75
75
|
.sui-tabs-container.starlight .sui-tabs-list {
|
|
76
76
|
margin-bottom: 1rem;
|
|
@@ -83,21 +83,21 @@
|
|
|
83
83
|
left: 0;
|
|
84
84
|
width: 100%;
|
|
85
85
|
height: 2px;
|
|
86
|
-
background-color:
|
|
86
|
+
background-color: var(--border);
|
|
87
87
|
}
|
|
88
88
|
.sui-tabs-container.starlight .sui-tab-header {
|
|
89
89
|
padding: 0.25rem 1.25rem;
|
|
90
|
-
color:
|
|
90
|
+
color: var(--text-muted);
|
|
91
91
|
}
|
|
92
92
|
.sui-tabs-container.starlight .sui-tab-header.active {
|
|
93
93
|
font-weight: 600;
|
|
94
|
-
color:
|
|
94
|
+
color: var(--text-normal);
|
|
95
95
|
}
|
|
96
96
|
.sui-tabs-container.starlight .sui-tab-header.active::after {
|
|
97
97
|
content: "";
|
|
98
98
|
width: 100%;
|
|
99
99
|
height: 2px;
|
|
100
|
-
background-color:
|
|
100
|
+
background-color: var(--primary-base);
|
|
101
101
|
position: absolute;
|
|
102
102
|
bottom: 0;
|
|
103
103
|
left: 0;
|
|
@@ -108,9 +108,9 @@
|
|
|
108
108
|
width: calc(100% - 2px);
|
|
109
109
|
bottom: 1px;
|
|
110
110
|
left: 1px;
|
|
111
|
-
border: 2px solid
|
|
111
|
+
border: 2px solid var(--primary-base);
|
|
112
112
|
background-color: transparent;
|
|
113
|
-
outline: 1px solid
|
|
113
|
+
outline: 1px solid var(--text-normal);
|
|
114
114
|
}
|
|
115
115
|
.sui-tabs-content {
|
|
116
116
|
width: 100%;
|
|
@@ -1 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Handles the logic of switching tabs, updating ARIA attributes, and syncing state.
|
|
3
|
+
* @param tabContainer The main container of the tab system.
|
|
4
|
+
* @param newActiveHeader The header element of the tab to be activated.
|
|
5
|
+
* @param originatedFromSync A flag to prevent cyclic updates with synced tabs.
|
|
6
|
+
*/
|
|
7
|
+
declare const switchTab: (tabContainer: HTMLDivElement, newActiveHeader: HTMLElement, originatedFromSync?: boolean) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Sets up a single tab container, wiring up ARIA attributes and event listeners.
|
|
10
|
+
* @param tabContainer The main container element of a tab system to set up.
|
|
11
|
+
*/
|
|
12
|
+
declare const setupTabContainer: (tabContainer: HTMLDivElement) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Initializes all tab systems on the page.
|
|
15
|
+
* Finds all tab containers and applies the setup logic to each.
|
|
16
|
+
*/
|
|
17
|
+
declare const loadTabs: () => void;
|