@starwind-ui/core 1.5.1 → 1.6.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/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/src/components/dialog/Dialog.astro +20 -4
- package/dist/src/components/dropdown/Dropdown.astro +5 -0
- package/dist/src/components/dropdown/DropdownTrigger.astro +2 -3
- package/dist/src/components/select/Select.astro +30 -2
- package/dist/src/components/select/SelectContent.astro +19 -8
- package/dist/src/components/table/Table.astro +18 -0
- package/dist/src/components/table/TableBody.astro +16 -0
- package/dist/src/components/table/TableCaption.astro +16 -0
- package/dist/src/components/table/TableCell.astro +16 -0
- package/dist/src/components/table/TableFoot.astro +16 -0
- package/dist/src/components/table/TableHead.astro +16 -0
- package/dist/src/components/table/TableHeader.astro +16 -0
- package/dist/src/components/table/TableRow.astro +16 -0
- package/dist/src/components/table/index.ts +21 -0
- package/dist/src/components/tabs/Tabs.astro +23 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,14 +14,15 @@ var registry_default = {
|
|
|
14
14
|
{ name: "button", type: "component", version: "2.0.1", dependencies: [] },
|
|
15
15
|
{ name: "card", type: "component", version: "1.1.0", dependencies: [] },
|
|
16
16
|
{ name: "checkbox", type: "component", version: "1.2.0", dependencies: [] },
|
|
17
|
-
{ name: "dialog", type: "component", version: "1.1.
|
|
18
|
-
{ name: "dropdown", type: "component", version: "1.0.
|
|
17
|
+
{ name: "dialog", type: "component", version: "1.1.2", dependencies: [] },
|
|
18
|
+
{ name: "dropdown", type: "component", version: "1.0.2", dependencies: [] },
|
|
19
19
|
{ name: "input", type: "component", version: "1.1.1", dependencies: [] },
|
|
20
20
|
{ name: "label", type: "component", version: "1.1.1", dependencies: [] },
|
|
21
21
|
{ name: "pagination", type: "component", version: "2.0.1", dependencies: [] },
|
|
22
|
-
{ name: "select", type: "component", version: "1.
|
|
22
|
+
{ name: "select", type: "component", version: "1.3.0", dependencies: [] },
|
|
23
23
|
{ name: "switch", type: "component", version: "1.1.0", dependencies: [] },
|
|
24
|
-
{ name: "
|
|
24
|
+
{ name: "table", type: "component", version: "1.0.0", dependencies: [] },
|
|
25
|
+
{ name: "tabs", type: "component", version: "1.2.0", dependencies: [] },
|
|
25
26
|
{ name: "textarea", type: "component", version: "1.1.1", dependencies: [] },
|
|
26
27
|
{ name: "tooltip", type: "component", version: "1.1.1", dependencies: [] }
|
|
27
28
|
]
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/registry.json"],"sourcesContent":["import { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport componentRegistry from \"./registry.json\" with { type: \"json\" };\n\n/**\n * Component metadata interface describing a Starwind UI component\n */\nexport interface ComponentMeta {\n\tname: string;\n\tversion: string;\n\ttype: \"component\";\n\tdependencies: string[];\n}\n\n/**\n * Registry interface containing all available components\n */\nexport interface Registry {\n\tcomponents: ComponentMeta[];\n}\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n\n/**\n * Get the absolute path to a component file\n * @param {string} componentName - The name of the component\n * @param {string} fileName - The name of the file within the component\n * @returns {string} The absolute path to the component file\n */\nexport const getComponentPath = (componentName: string, fileName: string): string => {\n\t// In production (when installed as a dependency), the components will be in dist/src/components\n\t// In development, they will be in src/components\n\tconst componentsDir = __dirname.includes(\"dist\") ? \"src/components\" : \"src/components\";\n\treturn join(__dirname, componentsDir, componentName, fileName);\n};\n\n/**\n * Map of all components and their metadata from registry\n */\nexport const registry = componentRegistry.components as ComponentMeta[];\n","{\n\t\"$schema\": \"https://starwind.dev/registry-schema.json\",\n\t\"components\": [\n\t\t{ \"name\": \"accordion\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"alert\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"avatar\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"badge\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"breadcrumb\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"button\", \"type\": \"component\", \"version\": \"2.0.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"card\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"checkbox\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"dialog\", \"type\": \"component\", \"version\": \"1.1.
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/registry.json"],"sourcesContent":["import { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport componentRegistry from \"./registry.json\" with { type: \"json\" };\n\n/**\n * Component metadata interface describing a Starwind UI component\n */\nexport interface ComponentMeta {\n\tname: string;\n\tversion: string;\n\ttype: \"component\";\n\tdependencies: string[];\n}\n\n/**\n * Registry interface containing all available components\n */\nexport interface Registry {\n\tcomponents: ComponentMeta[];\n}\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n\n/**\n * Get the absolute path to a component file\n * @param {string} componentName - The name of the component\n * @param {string} fileName - The name of the file within the component\n * @returns {string} The absolute path to the component file\n */\nexport const getComponentPath = (componentName: string, fileName: string): string => {\n\t// In production (when installed as a dependency), the components will be in dist/src/components\n\t// In development, they will be in src/components\n\tconst componentsDir = __dirname.includes(\"dist\") ? \"src/components\" : \"src/components\";\n\treturn join(__dirname, componentsDir, componentName, fileName);\n};\n\n/**\n * Map of all components and their metadata from registry\n */\nexport const registry = componentRegistry.components as ComponentMeta[];\n","{\n\t\"$schema\": \"https://starwind.dev/registry-schema.json\",\n\t\"components\": [\n\t\t{ \"name\": \"accordion\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"alert\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"avatar\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"badge\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"breadcrumb\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"button\", \"type\": \"component\", \"version\": \"2.0.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"card\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"checkbox\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"dialog\", \"type\": \"component\", \"version\": \"1.1.2\", \"dependencies\": [] },\n\t\t{ \"name\": \"dropdown\", \"type\": \"component\", \"version\": \"1.0.2\", \"dependencies\": [] },\n\t\t{ \"name\": \"input\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"label\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"pagination\", \"type\": \"component\", \"version\": \"2.0.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"select\", \"type\": \"component\", \"version\": \"1.3.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"switch\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"table\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"tabs\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n\t\t{ \"name\": \"textarea\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n\t\t{ \"name\": \"tooltip\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] }\n\t]\n}\n"],"mappings":";AAAA,SAAS,YAAY;AACrB,SAAS,qBAAqB;;;ACD9B;AAAA,EACC,SAAW;AAAA,EACX,YAAc;AAAA,IACb,EAAE,MAAQ,aAAa,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IACnF,EAAE,MAAQ,SAAS,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC/E,EAAE,MAAQ,UAAU,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAChF,EAAE,MAAQ,SAAS,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC/E,EAAE,MAAQ,cAAc,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IACpF,EAAE,MAAQ,UAAU,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAChF,EAAE,MAAQ,QAAQ,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC9E,EAAE,MAAQ,YAAY,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAClF,EAAE,MAAQ,UAAU,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAChF,EAAE,MAAQ,YAAY,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAClF,EAAE,MAAQ,SAAS,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC/E,EAAE,MAAQ,SAAS,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC/E,EAAE,MAAQ,cAAc,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IACpF,EAAE,MAAQ,UAAU,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAChF,EAAE,MAAQ,UAAU,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAChF,EAAE,MAAQ,SAAS,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC/E,EAAE,MAAQ,QAAQ,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAC9E,EAAE,MAAQ,YAAY,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,IAClF,EAAE,MAAQ,WAAW,MAAQ,aAAa,SAAW,SAAS,cAAgB,CAAC,EAAE;AAAA,EAClF;AACD;;;ADFA,IAAM,YAAY,cAAc,IAAI,IAAI,KAAK,YAAY,GAAG,CAAC;AAQtD,IAAM,mBAAmB,CAAC,eAAuB,aAA6B;AAGpF,QAAM,gBAAgB,UAAU,SAAS,MAAM,IAAI,mBAAmB;AACtE,SAAO,KAAK,WAAW,eAAe,eAAe,QAAQ;AAC9D;AAKO,IAAM,WAAW,iBAAkB;","names":[]}
|
|
@@ -90,7 +90,11 @@ const { class: className, ...rest } = Astro.props;
|
|
|
90
90
|
// Add click handlers to all close buttons
|
|
91
91
|
this.closeButtons?.forEach((button) => {
|
|
92
92
|
button.addEventListener("click", () => {
|
|
93
|
-
this
|
|
93
|
+
// Only close if this is the topmost dialog
|
|
94
|
+
const openDialogs = document.querySelectorAll("dialog[open]");
|
|
95
|
+
if (openDialogs.length > 0 && openDialogs[openDialogs.length - 1] === this.dialog) {
|
|
96
|
+
this.close();
|
|
97
|
+
}
|
|
94
98
|
});
|
|
95
99
|
});
|
|
96
100
|
|
|
@@ -104,7 +108,11 @@ const { class: className, ...rest } = Astro.props;
|
|
|
104
108
|
e.clientY <= dialogDimensions.bottom;
|
|
105
109
|
|
|
106
110
|
if (!clickedInDialog) {
|
|
107
|
-
this
|
|
111
|
+
// Only close if this is the topmost dialog
|
|
112
|
+
const openDialogs = document.querySelectorAll("dialog[open]");
|
|
113
|
+
if (openDialogs.length > 0 && openDialogs[openDialogs.length - 1] === this.dialog) {
|
|
114
|
+
this.close();
|
|
115
|
+
}
|
|
108
116
|
}
|
|
109
117
|
});
|
|
110
118
|
|
|
@@ -113,7 +121,11 @@ const { class: className, ...rest } = Astro.props;
|
|
|
113
121
|
if (e.key === "Escape") {
|
|
114
122
|
// prevent default dialog closing behavior so we can add closing animation
|
|
115
123
|
e.preventDefault();
|
|
116
|
-
this
|
|
124
|
+
// Only close if this is the topmost dialog
|
|
125
|
+
const openDialogs = document.querySelectorAll("dialog[open]");
|
|
126
|
+
if (openDialogs.length > 0 && openDialogs[openDialogs.length - 1] === this.dialog) {
|
|
127
|
+
this.close();
|
|
128
|
+
}
|
|
117
129
|
}
|
|
118
130
|
});
|
|
119
131
|
|
|
@@ -130,7 +142,11 @@ const { class: className, ...rest } = Astro.props;
|
|
|
130
142
|
*/
|
|
131
143
|
if (form.method === "dialog") {
|
|
132
144
|
e.preventDefault();
|
|
133
|
-
this
|
|
145
|
+
// Only close if this is the topmost dialog
|
|
146
|
+
const openDialogs = document.querySelectorAll("dialog[open]");
|
|
147
|
+
if (openDialogs.length > 0 && openDialogs[openDialogs.length - 1] === this.dialog) {
|
|
148
|
+
this.close();
|
|
149
|
+
}
|
|
134
150
|
}
|
|
135
151
|
});
|
|
136
152
|
});
|
|
@@ -35,6 +35,7 @@ const { class: className, openOnHover = false, closeDelay = 200, ...rest } = Ast
|
|
|
35
35
|
private items: HTMLElement[] = [];
|
|
36
36
|
private currentFocusIndex: number = -1;
|
|
37
37
|
private isOpen: boolean = false;
|
|
38
|
+
private isClosing: boolean = false;
|
|
38
39
|
private animationDuration = 150;
|
|
39
40
|
private openOnHover: boolean;
|
|
40
41
|
private closeDelay: number;
|
|
@@ -178,6 +179,7 @@ const { class: className, openOnHover = false, closeDelay = 200, ...rest } = Ast
|
|
|
178
179
|
if (this.openOnHover) {
|
|
179
180
|
this.trigger.addEventListener("pointerenter", (e) => {
|
|
180
181
|
if (e.pointerType !== "mouse") return;
|
|
182
|
+
if (this.isClosing) return;
|
|
181
183
|
if (!this.isOpen) {
|
|
182
184
|
this.openDropdown();
|
|
183
185
|
} else {
|
|
@@ -264,6 +266,7 @@ const { class: className, openOnHover = false, closeDelay = 200, ...rest } = Ast
|
|
|
264
266
|
}
|
|
265
267
|
|
|
266
268
|
private openDropdown() {
|
|
269
|
+
if (this.isClosing) return;
|
|
267
270
|
if (!this.content || !this.trigger || this.trigger.disabled) return;
|
|
268
271
|
|
|
269
272
|
this.isOpen = true;
|
|
@@ -283,6 +286,7 @@ const { class: className, openOnHover = false, closeDelay = 200, ...rest } = Ast
|
|
|
283
286
|
private closeDropdown() {
|
|
284
287
|
if (!this.content || !this.trigger) return;
|
|
285
288
|
|
|
289
|
+
this.isClosing = true;
|
|
286
290
|
this.isOpen = false;
|
|
287
291
|
this.content.setAttribute("data-state", "closed");
|
|
288
292
|
|
|
@@ -296,6 +300,7 @@ const { class: className, openOnHover = false, closeDelay = 200, ...rest } = Ast
|
|
|
296
300
|
setTimeout(() => {
|
|
297
301
|
if (!this.content) return;
|
|
298
302
|
this.content.style.display = "none";
|
|
303
|
+
this.isClosing = false;
|
|
299
304
|
}, this.animationDuration - 10);
|
|
300
305
|
|
|
301
306
|
this.trigger.setAttribute("aria-expanded", "false");
|
|
@@ -13,7 +13,7 @@ const dropdownTrigger = tv({
|
|
|
13
13
|
base: [
|
|
14
14
|
"starwind-dropdown-trigger",
|
|
15
15
|
"inline-flex items-center justify-center",
|
|
16
|
-
"focus-visible:
|
|
16
|
+
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
|
|
17
17
|
],
|
|
18
18
|
});
|
|
19
19
|
|
|
@@ -28,14 +28,13 @@ if (Astro.slots.has("default")) {
|
|
|
28
28
|
|
|
29
29
|
{
|
|
30
30
|
asChild && hasChildren ? (
|
|
31
|
-
<div class=
|
|
31
|
+
<div class={`starwind-dropdown-trigger ${className}`} data-as-child>
|
|
32
32
|
<slot />
|
|
33
33
|
</div>
|
|
34
34
|
) : (
|
|
35
35
|
<button
|
|
36
36
|
class={dropdownTrigger({ class: className })}
|
|
37
37
|
type="button"
|
|
38
|
-
role="button"
|
|
39
38
|
aria-haspopup="true"
|
|
40
39
|
aria-expanded="false"
|
|
41
40
|
data-state="closed"
|
|
@@ -2,15 +2,27 @@
|
|
|
2
2
|
import type { HTMLAttributes } from "astro/types";
|
|
3
3
|
|
|
4
4
|
type Props = HTMLAttributes<"div"> & {
|
|
5
|
+
/**
|
|
6
|
+
* The name of the select field for form handling
|
|
7
|
+
*/
|
|
5
8
|
name?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The value of the item that should be selected by default
|
|
11
|
+
*/
|
|
12
|
+
defaultValue?: string;
|
|
6
13
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
14
|
children: any;
|
|
8
15
|
};
|
|
9
16
|
|
|
10
|
-
const { class: className, name, ...rest } = Astro.props;
|
|
17
|
+
const { class: className, name, defaultValue, ...rest } = Astro.props;
|
|
11
18
|
---
|
|
12
19
|
|
|
13
|
-
<div
|
|
20
|
+
<div
|
|
21
|
+
class:list={["starwind-select", "relative", className]}
|
|
22
|
+
data-name={name}
|
|
23
|
+
data-value={defaultValue}
|
|
24
|
+
{...rest}
|
|
25
|
+
>
|
|
14
26
|
<slot />
|
|
15
27
|
</div>
|
|
16
28
|
|
|
@@ -50,6 +62,7 @@ const { class: className, name, ...rest } = Astro.props;
|
|
|
50
62
|
this.setupAccessibility(selectIdx);
|
|
51
63
|
this.setupEvents();
|
|
52
64
|
this.setupSelectField();
|
|
65
|
+
this.setInitialState();
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
private setupSelectField() {
|
|
@@ -398,6 +411,21 @@ const { class: className, name, ...rest } = Astro.props;
|
|
|
398
411
|
this.closeSelect();
|
|
399
412
|
}
|
|
400
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Sets the initial state based on the default value attribute
|
|
416
|
+
*/
|
|
417
|
+
private setInitialState(): void {
|
|
418
|
+
const defaultValue = this.select.dataset.value;
|
|
419
|
+
if (defaultValue) {
|
|
420
|
+
const item = this.content?.querySelector(`[data-value="${defaultValue}"]`);
|
|
421
|
+
|
|
422
|
+
if (item && item instanceof HTMLElement) {
|
|
423
|
+
this.handleSelection(item);
|
|
424
|
+
this.selectedItem = item;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
401
429
|
/**
|
|
402
430
|
* TODO: add position logic to avoid collisions with window boundary
|
|
403
431
|
* It will need to switch to top or bottom depending on space available
|
|
@@ -8,6 +8,11 @@ type Props = HTMLAttributes<"div"> & {
|
|
|
8
8
|
* @default bottom
|
|
9
9
|
*/
|
|
10
10
|
side?: "top" | "bottom";
|
|
11
|
+
/**
|
|
12
|
+
* Alignment of the dropdown
|
|
13
|
+
* @default start
|
|
14
|
+
*/
|
|
15
|
+
align?: "start" | "center" | "end";
|
|
11
16
|
/**
|
|
12
17
|
* Offset distance in pixels
|
|
13
18
|
* @default 4
|
|
@@ -25,17 +30,20 @@ const selectContent = tv({
|
|
|
25
30
|
"starwind-select-content",
|
|
26
31
|
"bg-popover text-popover-foreground absolute z-50 min-w-[8rem] rounded-md border shadow-md",
|
|
27
32
|
"fade-in-0 zoom-in-95 animate-in overflow-hidden will-change-transform",
|
|
28
|
-
"data-[state=closed]:
|
|
29
|
-
"left-0",
|
|
33
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
30
34
|
],
|
|
31
35
|
variants: {
|
|
32
36
|
side: {
|
|
33
|
-
bottom:
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
bottom: "slide-in-from-top-2 data-[state=closed]:slide-out-to-top-2 top-full",
|
|
38
|
+
top: "slide-in-from-bottom-2 data-[state=closed]:slide-out-to-bottom-2 bottom-full",
|
|
39
|
+
},
|
|
40
|
+
align: {
|
|
41
|
+
start: "slide-in-from-left-1 data-[state=closed]:slide-out-to-left-1 left-0",
|
|
42
|
+
center: "left-1/2 -translate-x-1/2",
|
|
43
|
+
end: "slide-in-from-right-1 data-[state=closed]:slide-out-to-right-1 right-0",
|
|
36
44
|
},
|
|
37
45
|
},
|
|
38
|
-
defaultVariants: { side: "bottom" },
|
|
46
|
+
defaultVariants: { side: "bottom", align: "start" },
|
|
39
47
|
});
|
|
40
48
|
|
|
41
49
|
const selectContentInner = tv({
|
|
@@ -45,6 +53,7 @@ const selectContentInner = tv({
|
|
|
45
53
|
const {
|
|
46
54
|
class: className,
|
|
47
55
|
side = "bottom",
|
|
56
|
+
align = "start",
|
|
48
57
|
sideOffset = 4,
|
|
49
58
|
animationDuration = 150,
|
|
50
59
|
...rest
|
|
@@ -52,16 +61,18 @@ const {
|
|
|
52
61
|
---
|
|
53
62
|
|
|
54
63
|
<div
|
|
55
|
-
class={selectContent({ side, class: className })}
|
|
64
|
+
class={selectContent({ side, align, class: className })}
|
|
56
65
|
role="listbox"
|
|
57
66
|
data-side={side}
|
|
67
|
+
data-align={align}
|
|
58
68
|
data-state="closed"
|
|
59
69
|
tabindex="-1"
|
|
60
70
|
style={{
|
|
61
|
-
"--select-content-offset": `calc(100% + ${sideOffset}px)`,
|
|
62
71
|
// hide the content initially. Script will remove this
|
|
63
72
|
display: "none",
|
|
64
73
|
animationDuration: `${animationDuration}ms`,
|
|
74
|
+
marginTop: side === "bottom" ? `${sideOffset}px` : undefined,
|
|
75
|
+
marginBottom: side === "top" ? `${sideOffset}px` : undefined,
|
|
65
76
|
}}
|
|
66
77
|
{...rest}
|
|
67
78
|
>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"table"> & VariantProps<typeof table>;
|
|
6
|
+
|
|
7
|
+
const table = tv({
|
|
8
|
+
base: "w-full caption-bottom text-sm",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<div data-table-container class="relative w-full overflow-x-auto">
|
|
15
|
+
<table data-table class={table({ class: className })} {...rest} role="table">
|
|
16
|
+
<slot />
|
|
17
|
+
</table>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"tbody"> & VariantProps<typeof tableBody>;
|
|
6
|
+
|
|
7
|
+
const tableBody = tv({
|
|
8
|
+
base: "[&_tr:last-child]:border-0",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<tbody data-table-body class={tableBody({ class: className })} {...rest}>
|
|
15
|
+
<slot />
|
|
16
|
+
</tbody>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"caption"> & VariantProps<typeof tableCaption>;
|
|
6
|
+
|
|
7
|
+
const tableCaption = tv({
|
|
8
|
+
base: "text-muted-foreground mt-4 text-sm",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<caption data-table-caption class={tableCaption({ class: className })} {...rest}>
|
|
15
|
+
<slot />
|
|
16
|
+
</caption>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"td"> & VariantProps<typeof tableCell>;
|
|
6
|
+
|
|
7
|
+
const tableCell = tv({
|
|
8
|
+
base: "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<td data-table-cell class={tableCell({ class: className })} {...rest}>
|
|
15
|
+
<slot />
|
|
16
|
+
</td>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"tfoot"> & VariantProps<typeof tableFoot>;
|
|
6
|
+
|
|
7
|
+
const tableFoot = tv({
|
|
8
|
+
base: "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<tfoot data-table-foot class={tableFoot({ class: className })} {...rest}>
|
|
15
|
+
<slot />
|
|
16
|
+
</tfoot>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"th"> & VariantProps<typeof tableHead>;
|
|
6
|
+
|
|
7
|
+
const tableHead = tv({
|
|
8
|
+
base: "text-muted-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<th data-table-head class={tableHead({ class: className })} {...rest} role="columnheader">
|
|
15
|
+
<slot />
|
|
16
|
+
</th>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"thead"> & VariantProps<typeof tableHeader>;
|
|
6
|
+
|
|
7
|
+
const tableHeader = tv({
|
|
8
|
+
base: "[&_tr]:border-b",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<thead data-table-header class={tableHeader({ class: className })} {...rest}>
|
|
15
|
+
<slot />
|
|
16
|
+
</thead>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv, type VariantProps } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
type Props = HTMLAttributes<"tr"> & VariantProps<typeof tableRow>;
|
|
6
|
+
|
|
7
|
+
const tableRow = tv({
|
|
8
|
+
base: "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const { class: className, ...rest } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<tr data-table-row class={tableRow({ class: className })} {...rest} role="row">
|
|
15
|
+
<slot />
|
|
16
|
+
</tr>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Table from "./Table.astro";
|
|
2
|
+
import TableBody from "./TableBody.astro";
|
|
3
|
+
import TableCaption from "./TableCaption.astro";
|
|
4
|
+
import TableCell from "./TableCell.astro";
|
|
5
|
+
import TableFoot from "./TableFoot.astro";
|
|
6
|
+
import TableHeader from "./TableHeader.astro";
|
|
7
|
+
import TableHead from "./TableHead.astro";
|
|
8
|
+
import TableRow from "./TableRow.astro";
|
|
9
|
+
|
|
10
|
+
export { Table, TableBody, TableCaption, TableCell, TableFoot, TableHead, TableHeader, TableRow };
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
Root: Table,
|
|
14
|
+
Body: TableBody,
|
|
15
|
+
Caption: TableCaption,
|
|
16
|
+
Cell: TableCell,
|
|
17
|
+
Foot: TableFoot,
|
|
18
|
+
Head: TableHead,
|
|
19
|
+
Header: TableHeader,
|
|
20
|
+
Row: TableRow,
|
|
21
|
+
};
|
|
@@ -42,11 +42,13 @@ const { defaultValue, syncKey, class: className, ...rest } = Astro.props;
|
|
|
42
42
|
private storageKey: string;
|
|
43
43
|
private valueToTriggerMap: Map<string, HTMLButtonElement>;
|
|
44
44
|
private valueToContentMap: Map<string, HTMLElement>;
|
|
45
|
+
private parentHandler: TabsHandler | null = null;
|
|
45
46
|
|
|
46
|
-
constructor(tabs: HTMLElement, idx: number) {
|
|
47
|
+
constructor(tabs: HTMLElement, idx: number, parentHandler: TabsHandler | null = null) {
|
|
47
48
|
this.tabs = tabs;
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
49
|
+
this.parentHandler = parentHandler;
|
|
50
|
+
this.triggers = Array.from(tabs.querySelectorAll(":scope > [data-tabs-list] > [data-tabs-trigger]"));
|
|
51
|
+
this.contents = Array.from(tabs.querySelectorAll(":scope > [data-tabs-content]"));
|
|
50
52
|
this.tabsId = `starwind-tabs${idx}`;
|
|
51
53
|
this.syncKey = tabs.dataset.syncKey;
|
|
52
54
|
this.storageKey = this.syncKey
|
|
@@ -228,6 +230,20 @@ const { defaultValue, syncKey, class: className, ...rest } = Astro.props;
|
|
|
228
230
|
c.setAttribute("data-state", isActive ? "active" : "inactive");
|
|
229
231
|
c.hidden = !isActive;
|
|
230
232
|
});
|
|
233
|
+
|
|
234
|
+
// Initialize any nested tabs in the active content
|
|
235
|
+
if (content.hasAttribute("data-state") && content.getAttribute("data-state") === "active") {
|
|
236
|
+
const nestedTabs = content.querySelectorAll<HTMLElement>(".starwind-tabs");
|
|
237
|
+
|
|
238
|
+
nestedTabs.forEach((nestedTab, nestedIdx) => {
|
|
239
|
+
// Skip tabs that already have instances
|
|
240
|
+
if (!tabInstances.has(nestedTab)) {
|
|
241
|
+
const uniqueIdx = 1000 + nestedIdx;
|
|
242
|
+
const handler = new TabsHandler(nestedTab, uniqueIdx, this);
|
|
243
|
+
tabInstances.set(nestedTab, handler);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
231
247
|
}
|
|
232
248
|
}
|
|
233
249
|
|
|
@@ -235,8 +251,11 @@ const { defaultValue, syncKey, class: className, ...rest } = Astro.props;
|
|
|
235
251
|
const tabInstances = new WeakMap<HTMLElement, TabsHandler>();
|
|
236
252
|
|
|
237
253
|
const setupTabs = () => {
|
|
254
|
+
// First handle top-level tabs
|
|
238
255
|
document.querySelectorAll<HTMLElement>(".starwind-tabs").forEach((tabs, idx) => {
|
|
239
|
-
|
|
256
|
+
// Skip tabs that are nested within other tab contents
|
|
257
|
+
const isNested = !!tabs.closest("[data-tabs-content]");
|
|
258
|
+
if (!isNested && !tabInstances.has(tabs)) {
|
|
240
259
|
tabInstances.set(tabs, new TabsHandler(tabs, idx));
|
|
241
260
|
}
|
|
242
261
|
});
|