cisse-vue-ui 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -1
- package/dist/{CollapsibleCard.vue_vue_type_script_setup_true_lang-Do0H2ZOe.cjs → CollapsibleCard.vue_vue_type_script_setup_true_lang-CPV2dtkO.cjs} +67 -125
- package/dist/CollapsibleCard.vue_vue_type_script_setup_true_lang-CPV2dtkO.cjs.map +1 -0
- package/dist/{CollapsibleCard.vue_vue_type_script_setup_true_lang-Cymj-zkh.js → CollapsibleCard.vue_vue_type_script_setup_true_lang-D0eSGYea.js} +68 -126
- package/dist/CollapsibleCard.vue_vue_type_script_setup_true_lang-D0eSGYea.js.map +1 -0
- package/dist/{Dropdown.vue_vue_type_script_setup_true_lang-D65uMijW.js → Dropdown.vue_vue_type_script_setup_true_lang-B9DsCY8M.js} +26 -74
- package/dist/Dropdown.vue_vue_type_script_setup_true_lang-B9DsCY8M.js.map +1 -0
- package/dist/{Dropdown.vue_vue_type_script_setup_true_lang-H6wsySqi.cjs → Dropdown.vue_vue_type_script_setup_true_lang-nMP2OxXp.cjs} +25 -73
- package/dist/Dropdown.vue_vue_type_script_setup_true_lang-nMP2OxXp.cjs.map +1 -0
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-DoawksKc.cjs → PageLayout.vue_vue_type_script_setup_true_lang-Bnw5L-xO.cjs} +2 -2
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-DoawksKc.cjs.map → PageLayout.vue_vue_type_script_setup_true_lang-Bnw5L-xO.cjs.map} +1 -1
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-J1I-WjM-.js → PageLayout.vue_vue_type_script_setup_true_lang-D8uD3-Fe.js} +2 -2
- package/dist/{PageLayout.vue_vue_type_script_setup_true_lang-J1I-WjM-.js.map → PageLayout.vue_vue_type_script_setup_true_lang-D8uD3-Fe.js.map} +1 -1
- package/dist/{Switch.vue_vue_type_script_setup_true_lang-C2_5u-HL.js → Switch.vue_vue_type_script_setup_true_lang-dRPxDu8I.js} +33 -103
- package/dist/Switch.vue_vue_type_script_setup_true_lang-dRPxDu8I.js.map +1 -0
- package/dist/{Switch.vue_vue_type_script_setup_true_lang-V-FtNcTd.cjs → Switch.vue_vue_type_script_setup_true_lang-wRTWorCd.cjs} +32 -102
- package/dist/Switch.vue_vue_type_script_setup_true_lang-wRTWorCd.cjs.map +1 -0
- package/dist/components/core/Dropdown.vue.d.ts +2 -4
- package/dist/components/core/index.cjs +2 -2
- package/dist/components/core/index.js +2 -2
- package/dist/components/form/index.cjs +1 -1
- package/dist/components/form/index.js +1 -1
- package/dist/components/index.cjs +4 -4
- package/dist/components/index.js +4 -4
- package/dist/components/layout/index.cjs +1 -1
- package/dist/components/layout/index.js +1 -1
- package/dist/composables/index.cjs +8 -4
- package/dist/composables/index.cjs.map +1 -1
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/index.js +5 -1
- package/dist/composables/index.js.map +1 -1
- package/dist/composables/useDropdown.d.ts +51 -0
- package/dist/composables/useModal.d.ts +60 -0
- package/dist/{index-D_7WQIhA.cjs → index-C-qIi_nO.cjs} +5 -5
- package/dist/index-C-qIi_nO.cjs.map +1 -0
- package/dist/{index-CNQJxtkC.js → index-DUVvDjHF.js} +5 -5
- package/dist/index-DUVvDjHF.js.map +1 -0
- package/dist/index.cjs +13 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -6
- package/dist/index.js.map +1 -1
- package/dist/useDropdown-DHFnd259.cjs +130 -0
- package/dist/useDropdown-DHFnd259.cjs.map +1 -0
- package/dist/useDropdown-iVu14E6s.js +131 -0
- package/dist/useDropdown-iVu14E6s.js.map +1 -0
- package/dist/{useExportCSV-B9o9lJ3D.js → useModal-Aq8hn152.js} +40 -1
- package/dist/useModal-Aq8hn152.js.map +1 -0
- package/dist/{useExportCSV-BPC_hd25.cjs → useModal-DDF_ZS8C.cjs} +40 -1
- package/dist/useModal-DDF_ZS8C.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/CollapsibleCard.vue_vue_type_script_setup_true_lang-Cymj-zkh.js.map +0 -1
- package/dist/CollapsibleCard.vue_vue_type_script_setup_true_lang-Do0H2ZOe.cjs.map +0 -1
- package/dist/Dropdown.vue_vue_type_script_setup_true_lang-D65uMijW.js.map +0 -1
- package/dist/Dropdown.vue_vue_type_script_setup_true_lang-H6wsySqi.cjs.map +0 -1
- package/dist/Switch.vue_vue_type_script_setup_true_lang-C2_5u-HL.js.map +0 -1
- package/dist/Switch.vue_vue_type_script_setup_true_lang-V-FtNcTd.cjs.map +0 -1
- package/dist/index-CNQJxtkC.js.map +0 -1
- package/dist/index-D_7WQIhA.cjs.map +0 -1
- package/dist/useExportCSV-B9o9lJ3D.js.map +0 -1
- package/dist/useExportCSV-BPC_hd25.cjs.map +0 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ref, computed, watch, onUnmounted, nextTick } from "vue";
|
|
2
|
+
function useDropdown(triggerRef, dropdownRef, options = {}) {
|
|
3
|
+
const { teleport = true, align = "left", gap = 8, onOpen, onClose } = options;
|
|
4
|
+
const isOpen = ref(false);
|
|
5
|
+
const highlightedIndex = ref(-1);
|
|
6
|
+
const dropdownPosition = ref({ top: 0, left: 0, right: 0, width: 0 });
|
|
7
|
+
const updatePosition = () => {
|
|
8
|
+
if (!triggerRef.value || !teleport) return;
|
|
9
|
+
const rect = triggerRef.value.getBoundingClientRect();
|
|
10
|
+
dropdownPosition.value = {
|
|
11
|
+
top: rect.bottom + window.scrollY + gap,
|
|
12
|
+
left: rect.left + window.scrollX,
|
|
13
|
+
right: window.innerWidth - rect.right - window.scrollX,
|
|
14
|
+
width: rect.width
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
const open = () => {
|
|
18
|
+
isOpen.value = true;
|
|
19
|
+
nextTick(updatePosition);
|
|
20
|
+
onOpen == null ? void 0 : onOpen();
|
|
21
|
+
};
|
|
22
|
+
const close = () => {
|
|
23
|
+
isOpen.value = false;
|
|
24
|
+
highlightedIndex.value = -1;
|
|
25
|
+
onClose == null ? void 0 : onClose();
|
|
26
|
+
};
|
|
27
|
+
const toggle = () => {
|
|
28
|
+
if (isOpen.value) {
|
|
29
|
+
close();
|
|
30
|
+
} else {
|
|
31
|
+
open();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const handleClickOutside = (event) => {
|
|
35
|
+
var _a, _b;
|
|
36
|
+
const target = event.target;
|
|
37
|
+
const isInsideTrigger = (_a = triggerRef.value) == null ? void 0 : _a.contains(target);
|
|
38
|
+
const isInsideDropdown = (_b = dropdownRef.value) == null ? void 0 : _b.contains(target);
|
|
39
|
+
if (!isInsideTrigger && !isInsideDropdown) {
|
|
40
|
+
close();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const scrollToHighlighted = (dropdownEl) => {
|
|
44
|
+
nextTick(() => {
|
|
45
|
+
if (dropdownEl) {
|
|
46
|
+
const highlighted = dropdownEl.querySelector(
|
|
47
|
+
`[data-index="${highlightedIndex.value}"]`
|
|
48
|
+
);
|
|
49
|
+
if (highlighted) {
|
|
50
|
+
highlighted.scrollIntoView({ block: "nearest" });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
const handleKeydown = (event, navOptions) => {
|
|
56
|
+
const { itemCount, onSelect, onOpen: onOpenNav, handleOpenKeys = false } = navOptions;
|
|
57
|
+
if (!isOpen.value) {
|
|
58
|
+
if (handleOpenKeys && (event.key === "Enter" || event.key === " " || event.key === "ArrowDown")) {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
onOpenNav == null ? void 0 : onOpenNav();
|
|
61
|
+
open();
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
switch (event.key) {
|
|
66
|
+
case "ArrowDown":
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
highlightedIndex.value = Math.min(highlightedIndex.value + 1, itemCount - 1);
|
|
69
|
+
break;
|
|
70
|
+
case "ArrowUp":
|
|
71
|
+
event.preventDefault();
|
|
72
|
+
highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0);
|
|
73
|
+
break;
|
|
74
|
+
case "Enter":
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
if (highlightedIndex.value >= 0) {
|
|
77
|
+
onSelect == null ? void 0 : onSelect(highlightedIndex.value);
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
case "Escape":
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
close();
|
|
83
|
+
break;
|
|
84
|
+
case "Tab":
|
|
85
|
+
close();
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const dropdownStyle = computed(() => {
|
|
90
|
+
if (!teleport) return {};
|
|
91
|
+
return {
|
|
92
|
+
position: "absolute",
|
|
93
|
+
top: `${dropdownPosition.value.top}px`,
|
|
94
|
+
left: align === "right" ? "auto" : `${dropdownPosition.value.left}px`,
|
|
95
|
+
right: align === "right" ? `${dropdownPosition.value.right}px` : "auto",
|
|
96
|
+
width: `${dropdownPosition.value.width}px`
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
watch(isOpen, (newValue) => {
|
|
100
|
+
if (newValue) {
|
|
101
|
+
document.addEventListener("click", handleClickOutside);
|
|
102
|
+
window.addEventListener("scroll", updatePosition, true);
|
|
103
|
+
window.addEventListener("resize", updatePosition);
|
|
104
|
+
} else {
|
|
105
|
+
document.removeEventListener("click", handleClickOutside);
|
|
106
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
107
|
+
window.removeEventListener("resize", updatePosition);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
onUnmounted(() => {
|
|
111
|
+
document.removeEventListener("click", handleClickOutside);
|
|
112
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
113
|
+
window.removeEventListener("resize", updatePosition);
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
isOpen,
|
|
117
|
+
highlightedIndex,
|
|
118
|
+
dropdownPosition,
|
|
119
|
+
dropdownStyle,
|
|
120
|
+
open,
|
|
121
|
+
close,
|
|
122
|
+
toggle,
|
|
123
|
+
updatePosition,
|
|
124
|
+
handleKeydown,
|
|
125
|
+
scrollToHighlighted
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
useDropdown as u
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=useDropdown-iVu14E6s.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDropdown-iVu14E6s.js","sources":["../src/composables/useDropdown.ts"],"sourcesContent":["import { ref, computed, watch, onUnmounted, nextTick, type Ref, type ComputedRef } from 'vue'\n\nexport interface UseDropdownOptions {\n /** Whether teleport is enabled (affects position calculation) */\n teleport?: boolean\n /** Alignment for position calculation */\n align?: 'left' | 'right'\n /** Gap between trigger and dropdown in pixels */\n gap?: number\n /** Callback when dropdown opens */\n onOpen?: () => void\n /** Callback when dropdown closes */\n onClose?: () => void\n}\n\nexport interface UseDropdownReturn {\n /** Whether the dropdown is currently open */\n isOpen: Ref<boolean>\n /** Current highlighted index for keyboard navigation */\n highlightedIndex: Ref<number>\n /** Calculated position for teleported dropdown */\n dropdownPosition: Ref<{ top: number; left: number; right: number; width: number }>\n /** Computed style object for teleported dropdown */\n dropdownStyle: ComputedRef<Record<string, string>>\n /** Open the dropdown */\n open: () => void\n /** Close the dropdown */\n close: () => void\n /** Toggle the dropdown */\n toggle: () => void\n /** Update position (call after DOM changes) */\n updatePosition: () => void\n /** Handle keyboard navigation */\n handleKeydown: (event: KeyboardEvent, options: KeyboardNavigationOptions) => void\n /** Scroll to highlighted item */\n scrollToHighlighted: (dropdownEl: HTMLElement | null) => void\n}\n\nexport interface KeyboardNavigationOptions {\n /** Total number of items to navigate */\n itemCount: number\n /** Called when Enter is pressed on a highlighted item */\n onSelect?: (index: number) => void\n /** Called when the dropdown should open (Space/Enter/ArrowDown when closed) */\n onOpen?: () => void\n /** Whether to handle open keys (Space/Enter/ArrowDown) when closed */\n handleOpenKeys?: boolean\n}\n\nexport function useDropdown(\n triggerRef: Ref<HTMLElement | null | undefined>,\n dropdownRef: Ref<HTMLElement | null | undefined>,\n options: UseDropdownOptions = {}\n): UseDropdownReturn {\n const { teleport = true, align = 'left', gap = 8, onOpen, onClose } = options\n\n const isOpen = ref(false)\n const highlightedIndex = ref(-1)\n const dropdownPosition = ref({ top: 0, left: 0, right: 0, width: 0 })\n\n const updatePosition = () => {\n if (!triggerRef.value || !teleport) return\n const rect = triggerRef.value.getBoundingClientRect()\n dropdownPosition.value = {\n top: rect.bottom + window.scrollY + gap,\n left: rect.left + window.scrollX,\n right: window.innerWidth - rect.right - window.scrollX,\n width: rect.width,\n }\n }\n\n const open = () => {\n isOpen.value = true\n nextTick(updatePosition)\n onOpen?.()\n }\n\n const close = () => {\n isOpen.value = false\n highlightedIndex.value = -1\n onClose?.()\n }\n\n const toggle = () => {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as Node\n const isInsideTrigger = triggerRef.value?.contains(target)\n const isInsideDropdown = dropdownRef.value?.contains(target)\n if (!isInsideTrigger && !isInsideDropdown) {\n close()\n }\n }\n\n const scrollToHighlighted = (dropdownEl: HTMLElement | null) => {\n nextTick(() => {\n if (dropdownEl) {\n const highlighted = dropdownEl.querySelector(\n `[data-index=\"${highlightedIndex.value}\"]`\n ) as HTMLElement\n if (highlighted) {\n highlighted.scrollIntoView({ block: 'nearest' })\n }\n }\n })\n }\n\n const handleKeydown = (event: KeyboardEvent, navOptions: KeyboardNavigationOptions) => {\n const { itemCount, onSelect, onOpen: onOpenNav, handleOpenKeys = false } = navOptions\n\n if (!isOpen.value) {\n if (handleOpenKeys && (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown')) {\n event.preventDefault()\n onOpenNav?.()\n open()\n }\n return\n }\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n highlightedIndex.value = Math.min(highlightedIndex.value + 1, itemCount - 1)\n break\n case 'ArrowUp':\n event.preventDefault()\n highlightedIndex.value = Math.max(highlightedIndex.value - 1, 0)\n break\n case 'Enter':\n event.preventDefault()\n if (highlightedIndex.value >= 0) {\n onSelect?.(highlightedIndex.value)\n }\n break\n case 'Escape':\n event.preventDefault()\n close()\n break\n case 'Tab':\n close()\n break\n }\n }\n\n const dropdownStyle = computed(() => {\n if (!teleport) return {} as Record<string, string>\n return {\n position: 'absolute',\n top: `${dropdownPosition.value.top}px`,\n left: align === 'right' ? 'auto' : `${dropdownPosition.value.left}px`,\n right: align === 'right' ? `${dropdownPosition.value.right}px` : 'auto',\n width: `${dropdownPosition.value.width}px`,\n } as Record<string, string>\n })\n\n // Event listener management\n watch(isOpen, (newValue) => {\n if (newValue) {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('scroll', updatePosition, true)\n window.addEventListener('resize', updatePosition)\n } else {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('scroll', updatePosition, true)\n window.removeEventListener('resize', updatePosition)\n }\n })\n\n onUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('scroll', updatePosition, true)\n window.removeEventListener('resize', updatePosition)\n })\n\n return {\n isOpen,\n highlightedIndex,\n dropdownPosition,\n dropdownStyle,\n open,\n close,\n toggle,\n updatePosition,\n handleKeydown,\n scrollToHighlighted,\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -122,9 +122,48 @@ function useExportCSV() {
|
|
|
122
122
|
escapeCSV
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
|
+
function useModal(options) {
|
|
126
|
+
const {
|
|
127
|
+
initialOpen = false,
|
|
128
|
+
initialData = null,
|
|
129
|
+
onOpen,
|
|
130
|
+
onClose
|
|
131
|
+
} = options ?? {};
|
|
132
|
+
const isOpen = ref(initialOpen);
|
|
133
|
+
const data = ref(initialData);
|
|
134
|
+
const open = (newData) => {
|
|
135
|
+
data.value = newData ?? null;
|
|
136
|
+
isOpen.value = true;
|
|
137
|
+
onOpen == null ? void 0 : onOpen(data.value);
|
|
138
|
+
};
|
|
139
|
+
const close = () => {
|
|
140
|
+
isOpen.value = false;
|
|
141
|
+
data.value = null;
|
|
142
|
+
onClose == null ? void 0 : onClose();
|
|
143
|
+
};
|
|
144
|
+
const toggle = () => {
|
|
145
|
+
if (isOpen.value) {
|
|
146
|
+
close();
|
|
147
|
+
} else {
|
|
148
|
+
open();
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
isOpen,
|
|
153
|
+
data,
|
|
154
|
+
open,
|
|
155
|
+
close,
|
|
156
|
+
toggle
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function useModals(modals) {
|
|
160
|
+
return modals;
|
|
161
|
+
}
|
|
125
162
|
export {
|
|
126
163
|
useDarkMode as a,
|
|
127
164
|
useExportCSV as b,
|
|
165
|
+
useModal as c,
|
|
166
|
+
useModals as d,
|
|
128
167
|
useNotifications as u
|
|
129
168
|
};
|
|
130
|
-
//# sourceMappingURL=
|
|
169
|
+
//# sourceMappingURL=useModal-Aq8hn152.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModal-Aq8hn152.js","sources":["../src/composables/useNotifications.ts","../src/composables/useDarkMode.ts","../src/composables/useExportCSV.ts","../src/composables/useModal.ts"],"sourcesContent":["import { ref, readonly } from 'vue'\nimport type { Notification, NotificationType, NotificationOptions } from '@/types'\n\n/**\n * Composable for managing notifications/toasts\n * Standalone implementation without Pinia dependency\n */\nexport function useNotifications() {\n const notifications = ref<Notification[]>([])\n let idCounter = 0\n\n const generateId = () => `notification-${++idCounter}-${Date.now()}`\n\n const notify = (\n type: NotificationType,\n message: string,\n options: NotificationOptions = {},\n ): string => {\n const id = generateId()\n const notification: Notification = {\n id,\n type,\n message,\n title: options.title ?? null,\n duration: options.duration ?? 5000,\n }\n\n notifications.value.push(notification)\n\n if (notification.duration && notification.duration > 0) {\n setTimeout(() => remove(id), notification.duration)\n }\n\n return id\n }\n\n const success = (message: string, options?: NotificationOptions) =>\n notify('success', message, options)\n\n const warning = (message: string, options?: NotificationOptions) =>\n notify('warning', message, options)\n\n const error = (message: string, options?: NotificationOptions) =>\n notify('error', message, options)\n\n const info = (message: string, options?: NotificationOptions) =>\n notify('info', message, options)\n\n const remove = (id: string) => {\n notifications.value = notifications.value.filter((n) => n.id !== id)\n }\n\n const clear = () => {\n notifications.value = []\n }\n\n return {\n notifications: readonly(notifications),\n notify,\n success,\n warning,\n error,\n info,\n remove,\n clear,\n }\n}\n","import { ref, watch, onMounted } from 'vue'\n\nexport interface DarkModeOptions {\n selector?: string\n attribute?: string\n storageKey?: string\n defaultValue?: boolean\n}\n\n/**\n * Composable for managing dark mode state\n */\nexport function useDarkMode(options: DarkModeOptions = {}) {\n const {\n selector = 'html',\n attribute = 'class',\n storageKey = 'dark-mode',\n defaultValue = false,\n } = options\n\n const isDark = ref(defaultValue)\n\n const getInitialValue = (): boolean => {\n if (typeof window === 'undefined') return defaultValue\n\n const stored = localStorage.getItem(storageKey)\n if (stored !== null) {\n return stored === 'true'\n }\n\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n }\n\n const updateDOM = (dark: boolean) => {\n if (typeof document === 'undefined') return\n\n const element = document.querySelector(selector)\n if (!element) return\n\n if (attribute === 'class') {\n element.classList.toggle('dark', dark)\n } else {\n element.setAttribute(attribute, dark ? 'dark' : 'light')\n }\n }\n\n const toggle = () => {\n isDark.value = !isDark.value\n }\n\n const set = (value: boolean) => {\n isDark.value = value\n }\n\n watch(isDark, (newValue) => {\n updateDOM(newValue)\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(storageKey, String(newValue))\n }\n })\n\n onMounted(() => {\n isDark.value = getInitialValue()\n updateDOM(isDark.value)\n })\n\n return {\n isDark,\n toggle,\n set,\n }\n}\n","/**\n * Composable for exporting data to CSV format\n */\nexport function useExportCSV() {\n const escapeCSV = (value: unknown): string => {\n if (value === null || value === undefined) return ''\n const str = String(value)\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`\n }\n return str\n }\n\n const exportToCSV = <T extends Record<string, unknown>>(\n data: T[],\n columns: { key: keyof T; label: string }[],\n filename: string = 'export.csv',\n ) => {\n if (!data || data.length === 0) {\n console.warn('No data to export')\n return\n }\n\n // Create header row\n const headers = columns.map((col) => escapeCSV(col.label)).join(',')\n\n // Create data rows\n const rows = data.map((item) =>\n columns.map((col) => escapeCSV(item[col.key])).join(','),\n )\n\n // Combine header and rows\n const csv = [headers, ...rows].join('\\n')\n\n // Create and trigger download\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.setAttribute('href', url)\n link.setAttribute('download', filename)\n link.style.visibility = 'hidden'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n }\n\n return {\n exportToCSV,\n escapeCSV,\n }\n}\n","import { ref, type Ref } from 'vue'\n\nexport interface UseModalReturn<T = unknown> {\n /** Whether the modal is currently open */\n isOpen: Ref<boolean>\n /** Data associated with the modal (e.g., item being edited) */\n data: Ref<T | null>\n /** Open the modal, optionally with data */\n open: (newData?: T) => void\n /** Close the modal and clear data */\n close: () => void\n /** Toggle the modal state */\n toggle: () => void\n}\n\n/**\n * Composable for managing modal state\n *\n * @example\n * ```ts\n * // Simple modal\n * const createModal = useModal()\n * createModal.open()\n * createModal.close()\n *\n * // Modal with data (e.g., for editing)\n * const editModal = useModal<User>()\n * editModal.open(selectedUser)\n * // Access editModal.data.value in modal\n *\n * // With onClose callback\n * const deleteModal = useModal<Item>({ onClose: () => refetch() })\n * ```\n */\nexport function useModal<T = unknown>(options?: {\n /** Initial open state */\n initialOpen?: boolean\n /** Initial data */\n initialData?: T | null\n /** Callback when modal opens */\n onOpen?: (data: T | null) => void\n /** Callback when modal closes */\n onClose?: () => void\n}): UseModalReturn<T> {\n const {\n initialOpen = false,\n initialData = null,\n onOpen,\n onClose,\n } = options ?? {}\n\n const isOpen = ref(initialOpen)\n const data = ref<T | null>(initialData) as Ref<T | null>\n\n const open = (newData?: T) => {\n data.value = newData ?? null\n isOpen.value = true\n onOpen?.(data.value)\n }\n\n const close = () => {\n isOpen.value = false\n data.value = null\n onClose?.()\n }\n\n const toggle = () => {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n return {\n isOpen,\n data,\n open,\n close,\n toggle,\n }\n}\n\n/**\n * Create multiple related modals at once\n * Useful when a page has several modals (create, edit, delete, etc.)\n *\n * @example\n * ```ts\n * const modals = useModals({\n * create: useModal(),\n * edit: useModal<User>(),\n * delete: useModal<User>(),\n * })\n *\n * modals.create.open()\n * modals.edit.open(user)\n * modals.delete.close()\n * ```\n */\nexport function useModals<T extends Record<string, UseModalReturn<unknown>>>(\n modals: T\n): T {\n return modals\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -123,7 +123,46 @@ function useExportCSV() {
|
|
|
123
123
|
escapeCSV
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
+
function useModal(options) {
|
|
127
|
+
const {
|
|
128
|
+
initialOpen = false,
|
|
129
|
+
initialData = null,
|
|
130
|
+
onOpen,
|
|
131
|
+
onClose
|
|
132
|
+
} = options ?? {};
|
|
133
|
+
const isOpen = vue.ref(initialOpen);
|
|
134
|
+
const data = vue.ref(initialData);
|
|
135
|
+
const open = (newData) => {
|
|
136
|
+
data.value = newData ?? null;
|
|
137
|
+
isOpen.value = true;
|
|
138
|
+
onOpen == null ? void 0 : onOpen(data.value);
|
|
139
|
+
};
|
|
140
|
+
const close = () => {
|
|
141
|
+
isOpen.value = false;
|
|
142
|
+
data.value = null;
|
|
143
|
+
onClose == null ? void 0 : onClose();
|
|
144
|
+
};
|
|
145
|
+
const toggle = () => {
|
|
146
|
+
if (isOpen.value) {
|
|
147
|
+
close();
|
|
148
|
+
} else {
|
|
149
|
+
open();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
return {
|
|
153
|
+
isOpen,
|
|
154
|
+
data,
|
|
155
|
+
open,
|
|
156
|
+
close,
|
|
157
|
+
toggle
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function useModals(modals) {
|
|
161
|
+
return modals;
|
|
162
|
+
}
|
|
126
163
|
exports.useDarkMode = useDarkMode;
|
|
127
164
|
exports.useExportCSV = useExportCSV;
|
|
165
|
+
exports.useModal = useModal;
|
|
166
|
+
exports.useModals = useModals;
|
|
128
167
|
exports.useNotifications = useNotifications;
|
|
129
|
-
//# sourceMappingURL=
|
|
168
|
+
//# sourceMappingURL=useModal-DDF_ZS8C.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useModal-DDF_ZS8C.cjs","sources":["../src/composables/useNotifications.ts","../src/composables/useDarkMode.ts","../src/composables/useExportCSV.ts","../src/composables/useModal.ts"],"sourcesContent":["import { ref, readonly } from 'vue'\nimport type { Notification, NotificationType, NotificationOptions } from '@/types'\n\n/**\n * Composable for managing notifications/toasts\n * Standalone implementation without Pinia dependency\n */\nexport function useNotifications() {\n const notifications = ref<Notification[]>([])\n let idCounter = 0\n\n const generateId = () => `notification-${++idCounter}-${Date.now()}`\n\n const notify = (\n type: NotificationType,\n message: string,\n options: NotificationOptions = {},\n ): string => {\n const id = generateId()\n const notification: Notification = {\n id,\n type,\n message,\n title: options.title ?? null,\n duration: options.duration ?? 5000,\n }\n\n notifications.value.push(notification)\n\n if (notification.duration && notification.duration > 0) {\n setTimeout(() => remove(id), notification.duration)\n }\n\n return id\n }\n\n const success = (message: string, options?: NotificationOptions) =>\n notify('success', message, options)\n\n const warning = (message: string, options?: NotificationOptions) =>\n notify('warning', message, options)\n\n const error = (message: string, options?: NotificationOptions) =>\n notify('error', message, options)\n\n const info = (message: string, options?: NotificationOptions) =>\n notify('info', message, options)\n\n const remove = (id: string) => {\n notifications.value = notifications.value.filter((n) => n.id !== id)\n }\n\n const clear = () => {\n notifications.value = []\n }\n\n return {\n notifications: readonly(notifications),\n notify,\n success,\n warning,\n error,\n info,\n remove,\n clear,\n }\n}\n","import { ref, watch, onMounted } from 'vue'\n\nexport interface DarkModeOptions {\n selector?: string\n attribute?: string\n storageKey?: string\n defaultValue?: boolean\n}\n\n/**\n * Composable for managing dark mode state\n */\nexport function useDarkMode(options: DarkModeOptions = {}) {\n const {\n selector = 'html',\n attribute = 'class',\n storageKey = 'dark-mode',\n defaultValue = false,\n } = options\n\n const isDark = ref(defaultValue)\n\n const getInitialValue = (): boolean => {\n if (typeof window === 'undefined') return defaultValue\n\n const stored = localStorage.getItem(storageKey)\n if (stored !== null) {\n return stored === 'true'\n }\n\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n }\n\n const updateDOM = (dark: boolean) => {\n if (typeof document === 'undefined') return\n\n const element = document.querySelector(selector)\n if (!element) return\n\n if (attribute === 'class') {\n element.classList.toggle('dark', dark)\n } else {\n element.setAttribute(attribute, dark ? 'dark' : 'light')\n }\n }\n\n const toggle = () => {\n isDark.value = !isDark.value\n }\n\n const set = (value: boolean) => {\n isDark.value = value\n }\n\n watch(isDark, (newValue) => {\n updateDOM(newValue)\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(storageKey, String(newValue))\n }\n })\n\n onMounted(() => {\n isDark.value = getInitialValue()\n updateDOM(isDark.value)\n })\n\n return {\n isDark,\n toggle,\n set,\n }\n}\n","/**\n * Composable for exporting data to CSV format\n */\nexport function useExportCSV() {\n const escapeCSV = (value: unknown): string => {\n if (value === null || value === undefined) return ''\n const str = String(value)\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`\n }\n return str\n }\n\n const exportToCSV = <T extends Record<string, unknown>>(\n data: T[],\n columns: { key: keyof T; label: string }[],\n filename: string = 'export.csv',\n ) => {\n if (!data || data.length === 0) {\n console.warn('No data to export')\n return\n }\n\n // Create header row\n const headers = columns.map((col) => escapeCSV(col.label)).join(',')\n\n // Create data rows\n const rows = data.map((item) =>\n columns.map((col) => escapeCSV(item[col.key])).join(','),\n )\n\n // Combine header and rows\n const csv = [headers, ...rows].join('\\n')\n\n // Create and trigger download\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.setAttribute('href', url)\n link.setAttribute('download', filename)\n link.style.visibility = 'hidden'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n }\n\n return {\n exportToCSV,\n escapeCSV,\n }\n}\n","import { ref, type Ref } from 'vue'\n\nexport interface UseModalReturn<T = unknown> {\n /** Whether the modal is currently open */\n isOpen: Ref<boolean>\n /** Data associated with the modal (e.g., item being edited) */\n data: Ref<T | null>\n /** Open the modal, optionally with data */\n open: (newData?: T) => void\n /** Close the modal and clear data */\n close: () => void\n /** Toggle the modal state */\n toggle: () => void\n}\n\n/**\n * Composable for managing modal state\n *\n * @example\n * ```ts\n * // Simple modal\n * const createModal = useModal()\n * createModal.open()\n * createModal.close()\n *\n * // Modal with data (e.g., for editing)\n * const editModal = useModal<User>()\n * editModal.open(selectedUser)\n * // Access editModal.data.value in modal\n *\n * // With onClose callback\n * const deleteModal = useModal<Item>({ onClose: () => refetch() })\n * ```\n */\nexport function useModal<T = unknown>(options?: {\n /** Initial open state */\n initialOpen?: boolean\n /** Initial data */\n initialData?: T | null\n /** Callback when modal opens */\n onOpen?: (data: T | null) => void\n /** Callback when modal closes */\n onClose?: () => void\n}): UseModalReturn<T> {\n const {\n initialOpen = false,\n initialData = null,\n onOpen,\n onClose,\n } = options ?? {}\n\n const isOpen = ref(initialOpen)\n const data = ref<T | null>(initialData) as Ref<T | null>\n\n const open = (newData?: T) => {\n data.value = newData ?? null\n isOpen.value = true\n onOpen?.(data.value)\n }\n\n const close = () => {\n isOpen.value = false\n data.value = null\n onClose?.()\n }\n\n const toggle = () => {\n if (isOpen.value) {\n close()\n } else {\n open()\n }\n }\n\n return {\n isOpen,\n data,\n open,\n close,\n toggle,\n }\n}\n\n/**\n * Create multiple related modals at once\n * Useful when a page has several modals (create, edit, delete, etc.)\n *\n * @example\n * ```ts\n * const modals = useModals({\n * create: useModal(),\n * edit: useModal<User>(),\n * delete: useModal<User>(),\n * })\n *\n * modals.create.open()\n * modals.edit.open(user)\n * modals.delete.close()\n * ```\n */\nexport function useModals<T extends Record<string, UseModalReturn<unknown>>>(\n modals: T\n): T {\n return modals\n}\n"],"names":["ref","readonly","watch","onMounted"],"mappings":"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"}
|