@orbitkit/components 0.0.1 → 0.2.0-beta.1
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/astro/accordion/Accordion.astro +34 -0
- package/dist/astro/accordion/AccordionItem.astro +16 -0
- package/dist/astro/accordion/AccordionTrigger.astro +33 -0
- package/dist/astro/accordion/AcordionContent.astro +26 -0
- package/dist/astro/accordion/accordion.ts +125 -0
- package/dist/astro/accordion/index.ts +6 -0
- package/dist/astro/alert/Alert.astro +30 -30
- package/dist/astro/alert/AlertDescription.astro +10 -10
- package/dist/astro/alert/AlertTitle.astro +15 -15
- package/dist/astro/alert/alertVariants.ts +51 -51
- package/dist/astro/alert/index.ts +6 -6
- package/dist/astro/avatar/Avatar.astro +16 -16
- package/dist/astro/avatar/AvatarFallback.astro +18 -18
- package/dist/astro/avatar/AvatarImage.astro +14 -14
- package/dist/astro/avatar/avatarVariants.ts +23 -23
- package/dist/astro/avatar/index.ts +6 -6
- package/dist/astro/badge/Badge.astro +22 -22
- package/dist/astro/badge/badgeVariants.ts +37 -37
- package/dist/astro/badge/index.ts +4 -4
- package/dist/astro/breadcrumb/Breadcrumb.astro +12 -12
- package/dist/astro/breadcrumb/BreadcrumbEllipsis.astro +20 -20
- package/dist/astro/breadcrumb/BreadcrumbItem.astro +15 -15
- package/dist/astro/breadcrumb/BreadcrumbLink.astro +18 -18
- package/dist/astro/breadcrumb/BreadcrumbList.astro +18 -18
- package/dist/astro/breadcrumb/BreadcrumbPage.astro +18 -18
- package/dist/astro/breadcrumb/BreadcrumbSeparator.astro +17 -17
- package/dist/astro/breadcrumb/index.ts +17 -17
- package/dist/astro/button/Button.astro +29 -29
- package/dist/astro/button/buttonVariants.ts +61 -61
- package/dist/astro/button/index.ts +4 -4
- package/dist/astro/card/Card.astro +18 -18
- package/dist/astro/card/CardContent.astro +12 -12
- package/dist/astro/card/CardDescription.astro +12 -12
- package/dist/astro/card/CardFooter.astro +15 -15
- package/dist/astro/card/CardHeader.astro +12 -12
- package/dist/astro/card/CardTitle.astro +18 -18
- package/dist/astro/card/index.ts +15 -15
- package/dist/astro/checkbox/Checkbox.astro +38 -38
- package/dist/astro/checkbox/index.ts +3 -3
- package/dist/astro/collapsible/Collapsible.astro +34 -0
- package/dist/astro/collapsible/CollapsibleContent.astro +20 -0
- package/dist/astro/collapsible/collapsible.ts +81 -0
- package/dist/astro/collapsible/index.ts +4 -0
- package/dist/astro/divider/Divider.astro +22 -0
- package/dist/astro/divider/index.ts +3 -0
- package/dist/astro/drawer/Drawer.astro +19 -0
- package/dist/astro/drawer/DrawerContent.astro +74 -0
- package/dist/astro/drawer/DrawerDescription.astro +12 -0
- package/dist/astro/drawer/DrawerFooter.astro +15 -0
- package/dist/astro/drawer/DrawerHeader.astro +12 -0
- package/dist/astro/drawer/DrawerTitle.astro +18 -0
- package/dist/astro/drawer/drawer.ts +104 -0
- package/dist/astro/drawer/drawerVariants.ts +83 -0
- package/dist/astro/drawer/index.ts +15 -0
- package/dist/astro/dropdown/DropdownMenu.astro +19 -0
- package/dist/astro/dropdown/DropdownMenuContent.astro +42 -0
- package/dist/astro/dropdown/DropdownMenuGroup.astro +3 -0
- package/dist/astro/dropdown/DropdownMenuItem.astro +27 -0
- package/dist/astro/dropdown/DropdownMenuLabel.astro +3 -0
- package/dist/astro/dropdown/DropdownMenuSeparator.astro +6 -0
- package/dist/astro/dropdown/dropdown.ts +157 -0
- package/dist/astro/dropdown/dropdownVariants.ts +134 -0
- package/dist/astro/dropdown/index.ts +15 -0
- package/dist/astro/input/Input.astro +18 -18
- package/dist/astro/input/index.ts +4 -4
- package/dist/astro/input/inputVariants.ts +30 -30
- package/dist/astro/kbd/Kbd.astro +18 -0
- package/dist/astro/kbd/index.ts +3 -0
- package/dist/astro/label/Label.astro +14 -14
- package/dist/astro/label/index.ts +3 -3
- package/dist/astro/list/List.astro +25 -0
- package/dist/astro/list/ListItem.astro +39 -0
- package/dist/astro/list/ListVariants.ts +65 -0
- package/dist/astro/list/index.ts +5 -0
- package/dist/astro/modal/Modal.astro +19 -0
- package/dist/astro/modal/ModalContent.astro +71 -0
- package/dist/astro/modal/ModalDescription.astro +12 -0
- package/dist/astro/modal/ModalFooter.astro +15 -0
- package/dist/astro/modal/ModalHeader.astro +12 -0
- package/dist/astro/modal/ModalTitle.astro +18 -0
- package/dist/astro/modal/index.ts +15 -0
- package/dist/astro/modal/modal.ts +101 -0
- package/dist/astro/pagination/Pagination.astro +12 -0
- package/dist/astro/pagination/PaginationContent.astro +15 -0
- package/dist/astro/pagination/PaginationEllipsis.astro +33 -0
- package/dist/astro/pagination/PaginationItem.astro +12 -0
- package/dist/astro/pagination/PaginationLink.astro +21 -0
- package/dist/astro/pagination/PaginationNext.astro +29 -0
- package/dist/astro/pagination/PaginationPrevious.astro +34 -0
- package/dist/astro/pagination/index.ts +13 -0
- package/dist/astro/pagination/paginationVariants.ts +26 -0
- package/dist/astro/popover/Popover.astro +17 -0
- package/dist/astro/popover/PopoverContent.astro +39 -0
- package/dist/astro/popover/index.ts +4 -0
- package/dist/astro/popover/popover.ts +113 -0
- package/dist/astro/popover/popoverVariants.ts +115 -0
- package/dist/astro/progress/Progress.astro +23 -23
- package/dist/astro/progress/index.ts +4 -4
- package/dist/astro/progress/progressContainer.astro +17 -17
- package/dist/astro/radio/Radio.astro +26 -26
- package/dist/astro/radio/index.ts +3 -3
- package/dist/astro/select/Option.astro +11 -11
- package/dist/astro/select/Select.astro +39 -39
- package/dist/astro/select/index.ts +5 -5
- package/dist/astro/select/selectVariants.ts +30 -30
- package/dist/astro/skeleton/Skeleton.astro +12 -0
- package/dist/astro/skeleton/SkeletonItem.astro +18 -0
- package/dist/astro/skeleton/index.ts +4 -0
- package/dist/astro/stat/Stat.astro +12 -0
- package/dist/astro/stat/StatDescription.astro +12 -0
- package/dist/astro/stat/StatTitle.astro +18 -0
- package/dist/astro/stat/StatValue.astro +12 -0
- package/dist/astro/stat/index.ts +6 -0
- package/dist/astro/switch/Switch.astro +19 -19
- package/dist/astro/switch/index.ts +3 -3
- package/dist/astro/tab/Tab.astro +33 -0
- package/dist/astro/tab/TabContent.astro +19 -0
- package/dist/astro/tab/TabList.astro +19 -0
- package/dist/astro/tab/TabTrigger.astro +24 -0
- package/dist/astro/tab/index.ts +6 -0
- package/dist/astro/tab/tab.ts +142 -0
- package/dist/astro/textarea/Textarea.astro +19 -19
- package/dist/astro/textarea/TextareaVariants.ts +30 -30
- package/dist/astro/textarea/index.ts +4 -4
- package/dist/astro/tooltip/Tooltip.astro +40 -0
- package/dist/astro/tooltip/TooltipContent.astro +39 -0
- package/dist/astro/tooltip/index.ts +6 -0
- package/dist/astro/tooltip/tooltip.ts +137 -0
- package/dist/astro/tooltip/tooltipVariants.ts +115 -0
- package/dist/index.js +57 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { cn } from "@/utils/cn";
|
|
3
|
-
import { type HTMLAttributes } from "astro/types";
|
|
4
|
-
|
|
5
|
-
interface Props extends Omit<HTMLAttributes<"input">, "type"> {}
|
|
6
|
-
|
|
7
|
-
const { class: className, id, ...attrs } = Astro.props;
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
<label class="inline-flex cursor-pointer items-center" id={id}>
|
|
11
|
-
<input {...attrs} id={id} type="checkbox" class="peer sr-only" />
|
|
12
|
-
<span
|
|
13
|
-
class={cn(
|
|
14
|
-
"relative w-11 h-6 bg-input-border rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full after:content-[''] after:absolute after:top-0.5 after:start-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
15
|
-
className,
|
|
16
|
-
)}
|
|
17
|
-
>
|
|
18
|
-
</span>
|
|
19
|
-
</label>
|
|
1
|
+
---
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import { type HTMLAttributes } from "astro/types";
|
|
4
|
+
|
|
5
|
+
interface Props extends Omit<HTMLAttributes<"input">, "type"> {}
|
|
6
|
+
|
|
7
|
+
const { class: className, id, ...attrs } = Astro.props;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<label class="inline-flex cursor-pointer items-center" id={id}>
|
|
11
|
+
<input {...attrs} id={id} type="checkbox" class="peer sr-only" />
|
|
12
|
+
<span
|
|
13
|
+
class={cn(
|
|
14
|
+
"relative w-11 h-6 bg-input-border rounded-full peer peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full after:content-[''] after:absolute after:top-0.5 after:start-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
15
|
+
className,
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
</span>
|
|
19
|
+
</label>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import Switch from "./Switch.astro";
|
|
2
|
-
|
|
3
|
-
export { Switch };
|
|
1
|
+
import Switch from "./Switch.astro";
|
|
2
|
+
|
|
3
|
+
export { Switch };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import type { HTMLAttributes } from "astro/types";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"div"> {
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { class: className, defaultValue, ...attrs } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
{...attrs}
|
|
14
|
+
data-tab
|
|
15
|
+
data-default-value={defaultValue}
|
|
16
|
+
class={cn(className)}
|
|
17
|
+
>
|
|
18
|
+
<slot />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
import { Tab } from "./tab";
|
|
23
|
+
|
|
24
|
+
function init() {
|
|
25
|
+
const tabs = document.querySelectorAll<HTMLElement>("[data-tab]");
|
|
26
|
+
tabs.forEach((tab) => {
|
|
27
|
+
new Tab(tab);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
init();
|
|
32
|
+
document.addEventListener("astro:page-load", () => init());
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
value: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const { value } = Astro.props;
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<div
|
|
10
|
+
role="tabpanel"
|
|
11
|
+
aria-orientation="horizontal"
|
|
12
|
+
data-tab-content
|
|
13
|
+
data-state="inactive"
|
|
14
|
+
data-value={value}
|
|
15
|
+
hidden
|
|
16
|
+
class="mt-2 w-full"
|
|
17
|
+
>
|
|
18
|
+
<slot />
|
|
19
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import type { HTMLAttributes } from "astro/types";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"div"> {}
|
|
6
|
+
|
|
7
|
+
const { class: className } = Astro.props;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
role="tablist"
|
|
12
|
+
data-tab-list
|
|
13
|
+
class={cn(
|
|
14
|
+
"flex flex-row justify-between flex-wrap bg-surface border border-border p-1 rounded-lg w-fit",
|
|
15
|
+
className,
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
<slot />
|
|
19
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import type { HTMLAttributes } from "astro/types";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"button"> {
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { class: className, value } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<button
|
|
13
|
+
role="tab"
|
|
14
|
+
aria-orientation="horizontal"
|
|
15
|
+
data-selected="false"
|
|
16
|
+
data-value={value}
|
|
17
|
+
data-tab-trigger
|
|
18
|
+
class={cn(
|
|
19
|
+
"rounded-sm px-3 py-1.5 flex justify-center gap-1.5 items-center font-medium cursor-pointer outline-none [&_svg]:pointer-events-none [&_svg]:shrink-0 transition-colors duration-100 ease-in data-[selected=true]:bg-secondary",
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
>
|
|
23
|
+
<slot />
|
|
24
|
+
</button>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
export class Tab {
|
|
2
|
+
private tab: HTMLElement;
|
|
3
|
+
private tabList: HTMLElement | null;
|
|
4
|
+
private tabsTrigger: NodeListOf<HTMLElement> | null;
|
|
5
|
+
private tabContents: NodeListOf<HTMLElement> | null;
|
|
6
|
+
private contentMap: Map<string, HTMLElement> = new Map();
|
|
7
|
+
|
|
8
|
+
constructor(tabWrapper: HTMLElement) {
|
|
9
|
+
this.tab = tabWrapper;
|
|
10
|
+
this.tabList = this.tab.querySelector("[data-tab-list]");
|
|
11
|
+
this.tabsTrigger =
|
|
12
|
+
this.tabList?.querySelectorAll("[data-tab-trigger]") || null;
|
|
13
|
+
this.tabContents = this.tab.querySelectorAll("[data-tab-content]");
|
|
14
|
+
|
|
15
|
+
this.initializeContentMap();
|
|
16
|
+
this.init();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private init() {
|
|
20
|
+
this.setupAccessibility();
|
|
21
|
+
this.setupEventListeners();
|
|
22
|
+
this.setDefaultTab();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private initializeContentMap(): void {
|
|
26
|
+
this.tabContents?.forEach((content) => {
|
|
27
|
+
const value = content.dataset.value?.toLowerCase();
|
|
28
|
+
if (value) {
|
|
29
|
+
if (this.contentMap.has(value)) {
|
|
30
|
+
console.warn(
|
|
31
|
+
`Duplicate data-value "${value}" found in content elements`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
this.contentMap.set(value, content);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private setupAccessibility() {
|
|
40
|
+
this.tabsTrigger?.forEach((trigger) => {
|
|
41
|
+
const triggerValue = trigger.dataset.value?.toLowerCase();
|
|
42
|
+
if (!triggerValue) return;
|
|
43
|
+
|
|
44
|
+
const content = this.contentMap.get(triggerValue);
|
|
45
|
+
if (!content) {
|
|
46
|
+
console.warn(`No content found for trigger value: ${triggerValue}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const uniqueId = Math.random().toString(36).substring(2, 9);
|
|
51
|
+
const triggerId = trigger.id || `tab-trigger-${triggerValue}-${uniqueId}`;
|
|
52
|
+
const contentId = content.id || `tab-content-${triggerValue}-${uniqueId}`;
|
|
53
|
+
|
|
54
|
+
trigger.setAttribute("id", triggerId);
|
|
55
|
+
trigger.setAttribute("aria-controls", contentId);
|
|
56
|
+
|
|
57
|
+
content.setAttribute("id", contentId);
|
|
58
|
+
content.setAttribute("aria-labelledby", triggerId);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private setupEventListeners() {
|
|
63
|
+
this.tabsTrigger?.forEach((trigger) => {
|
|
64
|
+
trigger.addEventListener("click", () => this.activateTab(trigger));
|
|
65
|
+
trigger.addEventListener("keydown", (e) =>
|
|
66
|
+
this.handleKeydown(e, trigger),
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private handleKeydown(event: KeyboardEvent, item: HTMLElement) {
|
|
72
|
+
const items = Array.from(this.tabsTrigger || []);
|
|
73
|
+
const currentItemIndex = items.indexOf(item);
|
|
74
|
+
|
|
75
|
+
const keyActions: Record<string, () => void> = {
|
|
76
|
+
ArrowRight: () => this.setFocusItem(items, currentItemIndex + 1),
|
|
77
|
+
ArrowLeft: () => this.setFocusItem(items, currentItemIndex - 1),
|
|
78
|
+
Home: () => this.setFocusItem(items, 0),
|
|
79
|
+
End: () => this.setFocusItem(items, items.length - 1),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const action = keyActions[event.key];
|
|
83
|
+
if (action) {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
action();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private setFocusItem(items: HTMLElement[], index: number) {
|
|
90
|
+
const newIndex = index % items.length;
|
|
91
|
+
if (items[newIndex]) {
|
|
92
|
+
this.activateTab(items[newIndex]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private setDefaultTab() {
|
|
97
|
+
const defaultTrigger = this.getDefaultTrigger();
|
|
98
|
+
if (defaultTrigger) {
|
|
99
|
+
this.activateTab(defaultTrigger);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private getDefaultTrigger(): HTMLElement | undefined {
|
|
104
|
+
if (!this.tabsTrigger) return;
|
|
105
|
+
|
|
106
|
+
const defaultValue = this.tab.dataset.defaultValue?.toLowerCase();
|
|
107
|
+
if (defaultValue) {
|
|
108
|
+
return Array.from(this.tabsTrigger || []).find(
|
|
109
|
+
(trigger) => trigger.dataset.value?.toLowerCase() === defaultValue,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return this.tabsTrigger[0];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private activateTab(trigger: HTMLElement) {
|
|
116
|
+
this.tabsTrigger?.forEach((t) => {
|
|
117
|
+
t.setAttribute("aria-selected", "false");
|
|
118
|
+
t.setAttribute("data-selected", "false");
|
|
119
|
+
t.setAttribute("tabindex", "-1");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
this.tabContents?.forEach((c) => {
|
|
123
|
+
c.setAttribute("data-state", "active");
|
|
124
|
+
c.setAttribute("hidden", "");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const triggerValue = trigger.dataset.value?.toLowerCase();
|
|
128
|
+
if (triggerValue) {
|
|
129
|
+
const content = this.contentMap.get(triggerValue);
|
|
130
|
+
if (content) {
|
|
131
|
+
content.removeAttribute("hidden");
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
content.setAttribute("data-state", "active");
|
|
134
|
+
trigger.setAttribute("aria-selected", "true");
|
|
135
|
+
trigger.setAttribute("data-selected", "true");
|
|
136
|
+
trigger.setAttribute("tabindex", "0");
|
|
137
|
+
}, 100);
|
|
138
|
+
trigger.focus();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { cn } from "@/utils/cn";
|
|
3
|
-
import { type HTMLAttributes } from "astro/types";
|
|
4
|
-
import type { VariantProps } from "class-variance-authority";
|
|
5
|
-
import { textareaVariants } from "./TextareaVariants";
|
|
6
|
-
|
|
7
|
-
interface Props
|
|
8
|
-
extends Omit<HTMLAttributes<"textarea">, "disabled">,
|
|
9
|
-
VariantProps<typeof textareaVariants> {}
|
|
10
|
-
|
|
11
|
-
const { class: className, variant, disabled, ...attrs } = Astro.props;
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
<textarea
|
|
15
|
-
{...attrs}
|
|
16
|
-
disabled={disabled}
|
|
17
|
-
class={cn(textareaVariants({ variant, disabled, className }))}
|
|
18
|
-
>
|
|
19
|
-
</textarea>
|
|
1
|
+
---
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import { type HTMLAttributes } from "astro/types";
|
|
4
|
+
import type { VariantProps } from "class-variance-authority";
|
|
5
|
+
import { textareaVariants } from "./TextareaVariants";
|
|
6
|
+
|
|
7
|
+
interface Props
|
|
8
|
+
extends Omit<HTMLAttributes<"textarea">, "disabled">,
|
|
9
|
+
VariantProps<typeof textareaVariants> {}
|
|
10
|
+
|
|
11
|
+
const { class: className, variant, disabled, ...attrs } = Astro.props;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<textarea
|
|
15
|
+
{...attrs}
|
|
16
|
+
disabled={disabled}
|
|
17
|
+
class={cn(textareaVariants({ variant, disabled, className }))}
|
|
18
|
+
>
|
|
19
|
+
</textarea>
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { cva } from "class-variance-authority";
|
|
2
|
-
|
|
3
|
-
const baseClass =
|
|
4
|
-
"block w-full p-2.5 mb-2 text-sm rounded-lg outline-1 -outline-offset-1";
|
|
5
|
-
|
|
6
|
-
const textareaVariants = cva(baseClass, {
|
|
7
|
-
variants: {
|
|
8
|
-
variant: {
|
|
9
|
-
default:
|
|
10
|
-
"text-foreground bg-input outline-input-border placeholder-input-placeholder",
|
|
11
|
-
},
|
|
12
|
-
disabled: {
|
|
13
|
-
false: null,
|
|
14
|
-
true: "bg-input/40 outline-input-border/40 text-muted-foreground cursor-not-allowed ",
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
compoundVariants: [
|
|
18
|
-
{
|
|
19
|
-
variant: "default",
|
|
20
|
-
disabled: false,
|
|
21
|
-
class: "focus:outline-2 focus:-outline-offset-2 focus:outline-primary",
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
defaultVariants: {
|
|
25
|
-
variant: "default",
|
|
26
|
-
disabled: false,
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
export { textareaVariants };
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
|
|
3
|
+
const baseClass =
|
|
4
|
+
"block w-full p-2.5 mb-2 text-sm rounded-lg outline-1 -outline-offset-1";
|
|
5
|
+
|
|
6
|
+
const textareaVariants = cva(baseClass, {
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default:
|
|
10
|
+
"text-foreground bg-input outline-input-border placeholder-input-placeholder",
|
|
11
|
+
},
|
|
12
|
+
disabled: {
|
|
13
|
+
false: null,
|
|
14
|
+
true: "bg-input/40 outline-input-border/40 text-muted-foreground cursor-not-allowed ",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
compoundVariants: [
|
|
18
|
+
{
|
|
19
|
+
variant: "default",
|
|
20
|
+
disabled: false,
|
|
21
|
+
class: "focus:outline-2 focus:-outline-offset-2 focus:outline-primary",
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
variant: "default",
|
|
26
|
+
disabled: false,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export { textareaVariants };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Textarea from "./Textarea.astro";
|
|
2
|
-
import { textareaVariants } from "./TextareaVariants";
|
|
3
|
-
|
|
4
|
-
export { Textarea, textareaVariants };
|
|
1
|
+
import Textarea from "./Textarea.astro";
|
|
2
|
+
import { textareaVariants } from "./TextareaVariants";
|
|
3
|
+
|
|
4
|
+
export { Textarea, textareaVariants };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props {
|
|
3
|
+
disableHoverableContent?: boolean;
|
|
4
|
+
openDelay?: number;
|
|
5
|
+
closeDelay?: number;
|
|
6
|
+
duration?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
openDelay = 150,
|
|
11
|
+
closeDelay = 150,
|
|
12
|
+
duration = 200,
|
|
13
|
+
disableHoverableContent = false,
|
|
14
|
+
} = Astro.props;
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<div
|
|
18
|
+
class="relative inline-flex"
|
|
19
|
+
data-tooltip
|
|
20
|
+
data-open-delay={openDelay}
|
|
21
|
+
data-close-delay={closeDelay}
|
|
22
|
+
data-duration={duration}
|
|
23
|
+
data-disable-hoverable-content={disableHoverableContent}
|
|
24
|
+
>
|
|
25
|
+
<slot />
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<script>
|
|
29
|
+
import { Tooltip } from "./tooltip";
|
|
30
|
+
|
|
31
|
+
function init() {
|
|
32
|
+
const tooltips = document.querySelectorAll<HTMLElement>("[data-tooltip]");
|
|
33
|
+
tooltips.forEach((tooltip) => {
|
|
34
|
+
new Tooltip(tooltip);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
init();
|
|
39
|
+
document.addEventListener("astro:page-load", () => init());
|
|
40
|
+
</script>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { cn } from "@/utils/cn";
|
|
3
|
+
import type { HTMLAttributes } from "astro/types";
|
|
4
|
+
import type { VariantProps } from "class-variance-authority";
|
|
5
|
+
import { tooltipArrowVariants, tooltipVariants } from "./tooltipVariants";
|
|
6
|
+
|
|
7
|
+
interface Props
|
|
8
|
+
extends HTMLAttributes<"div">,
|
|
9
|
+
VariantProps<typeof tooltipVariants> {
|
|
10
|
+
sideOffset?: number;
|
|
11
|
+
arrow?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
class: className,
|
|
16
|
+
side,
|
|
17
|
+
alignment,
|
|
18
|
+
sideOffset = 2,
|
|
19
|
+
arrow = true,
|
|
20
|
+
...attrs
|
|
21
|
+
} = Astro.props;
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
<div
|
|
25
|
+
{...attrs}
|
|
26
|
+
role="tooltip"
|
|
27
|
+
data-tooltip-content
|
|
28
|
+
aria-hidden="false"
|
|
29
|
+
data-state="closed"
|
|
30
|
+
data-side={sideOffset}
|
|
31
|
+
data-alignment={alignment}
|
|
32
|
+
class={cn(tooltipVariants({ side, alignment, className }))}
|
|
33
|
+
style={{
|
|
34
|
+
"--tooltip-offset": `calc(var(--spacing) * ${sideOffset})`,
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<slot />
|
|
38
|
+
{arrow && <span class={cn(tooltipArrowVariants({ side, alignment }))} />}
|
|
39
|
+
</div>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import Tooltip from "./Tooltip.astro";
|
|
2
|
+
import TooltipContent from "./TooltipContent.astro";
|
|
3
|
+
import TooltipTrigger from "./TooltipTrigger.astro";
|
|
4
|
+
import { tooltipVariants } from "./tooltipVariants";
|
|
5
|
+
|
|
6
|
+
export { Tooltip, TooltipContent, TooltipTrigger, tooltipVariants };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
export class Tooltip {
|
|
2
|
+
// References to tooltip elements
|
|
3
|
+
private tooltip: HTMLElement;
|
|
4
|
+
private trigger: HTMLElement | null;
|
|
5
|
+
private content: HTMLElement | null;
|
|
6
|
+
|
|
7
|
+
// Tooltip configuration options
|
|
8
|
+
private duration: number;
|
|
9
|
+
private openDelay: number;
|
|
10
|
+
private closeDelay: number;
|
|
11
|
+
|
|
12
|
+
// Timers for managing tooltip open/close/hide delays
|
|
13
|
+
private openTimerId: number | null = null;
|
|
14
|
+
private closeTimerId: number | null = null;
|
|
15
|
+
private hideTimerId: number | null = null;
|
|
16
|
+
|
|
17
|
+
constructor(tooltip: HTMLElement) {
|
|
18
|
+
this.tooltip = tooltip;
|
|
19
|
+
this.content = this.tooltip.querySelector("[data-tooltip-content]");
|
|
20
|
+
this.trigger = this.tooltip.querySelector("[data-trigger]");
|
|
21
|
+
|
|
22
|
+
this.duration = parseFloat(tooltip.dataset.duration || "200");
|
|
23
|
+
this.openDelay = parseFloat(tooltip.dataset.openDelay || "0");
|
|
24
|
+
this.closeDelay = parseFloat(tooltip.dataset.closeDelay || "0");
|
|
25
|
+
|
|
26
|
+
if (!this.tooltip || !this.content || !this.trigger) {
|
|
27
|
+
console.error("Tooltip not initialized properly", {
|
|
28
|
+
container: this.tooltip,
|
|
29
|
+
trigger: this.trigger,
|
|
30
|
+
content: this.content,
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// If you want to use animations instead of transitions
|
|
36
|
+
// set animation duration instead of transition duration.
|
|
37
|
+
this.content.style.transitionDuration = `${this.duration}ms`;
|
|
38
|
+
|
|
39
|
+
this.init();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private init() {
|
|
43
|
+
this.setupAccessibility();
|
|
44
|
+
this.setupEventListeners();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private setupAccessibility() {
|
|
48
|
+
if (!this.trigger || !this.content) return;
|
|
49
|
+
|
|
50
|
+
const id =
|
|
51
|
+
this.content.id ||
|
|
52
|
+
`tooltip-id-${Math.random().toString(36).substring(2, 9)}`;
|
|
53
|
+
this.content.id = id;
|
|
54
|
+
this.trigger.setAttribute("aria-describedby", id);
|
|
55
|
+
this.setState("closed");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private setupEventListeners() {
|
|
59
|
+
if (!this.trigger || !this.content) return;
|
|
60
|
+
|
|
61
|
+
this.trigger!.addEventListener("mouseenter", () => this.showTooltip());
|
|
62
|
+
this.trigger!.addEventListener("mouseleave", () => this.hideTooltip());
|
|
63
|
+
this.trigger.addEventListener("focus", () => this.showTooltip(true));
|
|
64
|
+
this.trigger.addEventListener("blur", () => this.hideTooltip(true));
|
|
65
|
+
|
|
66
|
+
if (this.tooltip.dataset.disableHoverableContent === "false") {
|
|
67
|
+
this.content.addEventListener("mouseenter", () => this.showTooltip());
|
|
68
|
+
this.content.addEventListener("mouseleave", () => this.hideTooltip());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
document.addEventListener("keydown", (e) => this.handleKeyDown(e));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private showTooltip(instant: boolean = false) {
|
|
75
|
+
this.clearCloseTimer();
|
|
76
|
+
this.content?.classList.remove("hidden");
|
|
77
|
+
|
|
78
|
+
if (instant) {
|
|
79
|
+
this.setState("open");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.openTimerId = window.setTimeout(() => {
|
|
84
|
+
this.setState("open");
|
|
85
|
+
this.openTimerId = null;
|
|
86
|
+
}, this.openDelay);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private hideTooltip(instant: boolean = false) {
|
|
90
|
+
this.clearOpenTimer();
|
|
91
|
+
|
|
92
|
+
if (instant) {
|
|
93
|
+
this.setState("closed");
|
|
94
|
+
this.content?.classList.add("hidden");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.closeTimerId = window.setTimeout(() => {
|
|
99
|
+
this.setState("closed");
|
|
100
|
+
this.hideTimerId = window.setTimeout(() => {
|
|
101
|
+
this.content?.classList.add("hidden");
|
|
102
|
+
this.closeTimerId = null;
|
|
103
|
+
this.hideTimerId = null;
|
|
104
|
+
}, this.duration);
|
|
105
|
+
}, this.closeDelay);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private setState(state: "open" | "closed") {
|
|
109
|
+
this.content?.setAttribute("aria-hidden", `${state === "closed"}`);
|
|
110
|
+
this.content?.setAttribute("data-state", state);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private clearOpenTimer() {
|
|
114
|
+
if (this.openTimerId) {
|
|
115
|
+
window.clearTimeout(this.openTimerId);
|
|
116
|
+
this.openTimerId = null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private clearCloseTimer() {
|
|
121
|
+
if (this.closeTimerId) {
|
|
122
|
+
window.clearTimeout(this.closeTimerId);
|
|
123
|
+
this.closeTimerId = null;
|
|
124
|
+
}
|
|
125
|
+
if (this.hideTimerId) {
|
|
126
|
+
window.clearTimeout(this.hideTimerId);
|
|
127
|
+
this.hideTimerId = null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private handleKeyDown = (event: KeyboardEvent) => {
|
|
132
|
+
if (event.key === "Escape" && this.content!.dataset.status === "open") {
|
|
133
|
+
this.hideTooltip(true);
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|