nuxt-ui-elements-pro 0.1.10 → 0.1.11

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.
Files changed (72) hide show
  1. package/dist/module.d.mts +5 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +240 -1
  4. package/dist/runtime/components/EventCalendar.vue +2 -2
  5. package/dist/runtime/components/FeedbackWidget.d.vue.ts +118 -0
  6. package/dist/runtime/components/FeedbackWidget.vue +141 -0
  7. package/dist/runtime/components/FeedbackWidget.vue.d.ts +118 -0
  8. package/dist/runtime/components/GanttChart.d.vue.ts +138 -0
  9. package/dist/runtime/components/GanttChart.vue +206 -0
  10. package/dist/runtime/components/GanttChart.vue.d.ts +138 -0
  11. package/dist/runtime/components/event-calendar/EventCalendarTimeGrid.vue +23 -3
  12. package/dist/runtime/components/feedback-widget/FeedbackWidgetButton.d.vue.ts +22 -0
  13. package/dist/runtime/components/feedback-widget/FeedbackWidgetButton.vue +27 -0
  14. package/dist/runtime/components/feedback-widget/FeedbackWidgetButton.vue.d.ts +22 -0
  15. package/dist/runtime/components/feedback-widget/FeedbackWidgetPanel.d.vue.ts +42 -0
  16. package/dist/runtime/components/feedback-widget/FeedbackWidgetPanel.vue +288 -0
  17. package/dist/runtime/components/feedback-widget/FeedbackWidgetPanel.vue.d.ts +42 -0
  18. package/dist/runtime/components/gantt-chart/GanttChartDependencies.d.vue.ts +16 -0
  19. package/dist/runtime/components/gantt-chart/GanttChartDependencies.vue +70 -0
  20. package/dist/runtime/components/gantt-chart/GanttChartDependencies.vue.d.ts +16 -0
  21. package/dist/runtime/components/gantt-chart/GanttChartHeader.d.vue.ts +41 -0
  22. package/dist/runtime/components/gantt-chart/GanttChartHeader.vue +56 -0
  23. package/dist/runtime/components/gantt-chart/GanttChartHeader.vue.d.ts +41 -0
  24. package/dist/runtime/components/gantt-chart/GanttChartTimeline.d.vue.ts +34 -0
  25. package/dist/runtime/components/gantt-chart/GanttChartTimeline.vue +193 -0
  26. package/dist/runtime/components/gantt-chart/GanttChartTimeline.vue.d.ts +34 -0
  27. package/dist/runtime/composables/useEventCalendar.d.ts +2 -0
  28. package/dist/runtime/composables/useEventCalendar.js +8 -6
  29. package/dist/runtime/composables/useEventCalendarContext.d.ts +2 -7
  30. package/dist/runtime/composables/useEventCalendarContext.js +4 -11
  31. package/dist/runtime/composables/useFeedbackWidget.d.ts +46 -0
  32. package/dist/runtime/composables/useFeedbackWidget.js +137 -0
  33. package/dist/runtime/composables/useFeedbackWidgetContext.d.ts +3 -0
  34. package/dist/runtime/composables/useFeedbackWidgetContext.js +4 -0
  35. package/dist/runtime/composables/useGanttChart.d.ts +52 -0
  36. package/dist/runtime/composables/useGanttChart.js +224 -0
  37. package/dist/runtime/composables/useGanttChartContext.d.ts +3 -0
  38. package/dist/runtime/composables/useGanttChartContext.js +4 -0
  39. package/dist/runtime/composables/useGanttChartDragDrop.d.ts +28 -0
  40. package/dist/runtime/composables/useGanttChartDragDrop.js +68 -0
  41. package/dist/runtime/composables/useGanttChartKeyboard.d.ts +14 -0
  42. package/dist/runtime/composables/useGanttChartKeyboard.js +92 -0
  43. package/dist/runtime/composables/useGanttChartResize.d.ts +26 -0
  44. package/dist/runtime/composables/useGanttChartResize.js +89 -0
  45. package/dist/runtime/composables/useOrgChartContext.d.ts +2 -7
  46. package/dist/runtime/composables/useOrgChartContext.js +4 -11
  47. package/dist/runtime/index.d.ts +1 -0
  48. package/dist/runtime/index.js +1 -0
  49. package/dist/runtime/server/api/_feedback.post.d.ts +3 -0
  50. package/dist/runtime/server/api/_feedback.post.js +115 -0
  51. package/dist/runtime/server/nodemailer.d.ts +29 -0
  52. package/dist/runtime/server/utils/feedback-captcha.d.ts +1 -0
  53. package/dist/runtime/server/utils/feedback-captcha.js +27 -0
  54. package/dist/runtime/server/utils/feedback-rate-limit.d.ts +4 -0
  55. package/dist/runtime/server/utils/feedback-rate-limit.js +26 -0
  56. package/dist/runtime/types/event-calendar.d.ts +10 -4
  57. package/dist/runtime/types/feedback-widget.d.ts +110 -0
  58. package/dist/runtime/types/feedback-widget.js +0 -0
  59. package/dist/runtime/types/gantt-chart.d.ts +223 -0
  60. package/dist/runtime/types/gantt-chart.js +0 -0
  61. package/dist/runtime/types/index.d.ts +4 -0
  62. package/dist/runtime/types/index.js +4 -0
  63. package/dist/runtime/utils/createComponentContext.d.ts +15 -0
  64. package/dist/runtime/utils/createComponentContext.js +17 -0
  65. package/dist/runtime/utils/date.d.ts +10 -0
  66. package/dist/runtime/utils/date.js +9 -0
  67. package/dist/runtime/utils/event-calendar.d.ts +1 -9
  68. package/dist/runtime/utils/event-calendar.js +2 -9
  69. package/dist/runtime/utils/gantt-chart.d.ts +85 -0
  70. package/dist/runtime/utils/gantt-chart.js +549 -0
  71. package/dist/runtime/utils/recurrence.js +2 -1
  72. package/package.json +17 -8
@@ -0,0 +1,288 @@
1
+ <script setup>
2
+ import { onMounted, onUnmounted, ref, watch } from "vue";
3
+ import { useFeedbackWidgetContext } from "../../composables/useFeedbackWidgetContext";
4
+ defineProps({
5
+ title: { type: String, required: true }
6
+ });
7
+ const ctx = useFeedbackWidgetContext();
8
+ const captchaContainerRef = ref(null);
9
+ let captchaWidgetId = null;
10
+ const CAPTCHA_SCRIPTS = {
11
+ turnstile: "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit",
12
+ recaptcha: "https://www.google.com/recaptcha/api.js?render=explicit",
13
+ hcaptcha: "https://js.hcaptcha.com/1/api.js?render=explicit"
14
+ };
15
+ function loadCaptchaScript(provider) {
16
+ const existingScript = document.querySelector(`script[data-captcha-provider="${provider}"]`);
17
+ if (existingScript) return Promise.resolve();
18
+ return new Promise((resolve, reject) => {
19
+ const script = document.createElement("script");
20
+ script.src = CAPTCHA_SCRIPTS[provider];
21
+ script.async = true;
22
+ script.defer = true;
23
+ script.dataset.captchaProvider = provider;
24
+ script.onload = () => resolve();
25
+ script.onerror = () => reject(new Error(`Failed to load ${provider} script`));
26
+ document.head.appendChild(script);
27
+ });
28
+ }
29
+ function renderCaptcha() {
30
+ if (!captchaContainerRef.value || !ctx.captchaEnabled.value) return;
31
+ const provider = ctx.captchaProvider.value;
32
+ const siteKey = ctx.captchaSiteKey.value;
33
+ if (!provider || !siteKey) return;
34
+ if (captchaContainerRef.value) {
35
+ captchaContainerRef.value.innerHTML = "";
36
+ }
37
+ const callback = (token) => ctx.setCaptchaToken(token);
38
+ if (provider === "turnstile" && window.turnstile) {
39
+ captchaWidgetId = window.turnstile.render(captchaContainerRef.value, {
40
+ sitekey: siteKey,
41
+ callback
42
+ });
43
+ } else if (provider === "recaptcha" && window.grecaptcha) {
44
+ captchaWidgetId = window.grecaptcha.render(captchaContainerRef.value, {
45
+ sitekey: siteKey,
46
+ callback
47
+ });
48
+ } else if (provider === "hcaptcha" && window.hcaptcha) {
49
+ captchaWidgetId = window.hcaptcha.render(captchaContainerRef.value, {
50
+ sitekey: siteKey,
51
+ callback
52
+ });
53
+ }
54
+ }
55
+ watch(() => ctx.isOpen.value, async (open) => {
56
+ if (open && ctx.captchaEnabled.value && ctx.captchaProvider.value) {
57
+ try {
58
+ await loadCaptchaScript(ctx.captchaProvider.value);
59
+ setTimeout(renderCaptcha, 100);
60
+ } catch {
61
+ }
62
+ }
63
+ });
64
+ function onKeydown(e) {
65
+ if (e.key === "Escape" && ctx.isOpen.value) {
66
+ ctx.close();
67
+ }
68
+ }
69
+ onMounted(() => {
70
+ document.addEventListener("keydown", onKeydown);
71
+ });
72
+ onUnmounted(() => {
73
+ document.removeEventListener("keydown", onKeydown);
74
+ });
75
+ </script>
76
+
77
+ <template>
78
+ <div
79
+ data-slot="panel"
80
+ :class="[
81
+ ctx.ui.value.panel({ class: ctx.propUi.value?.panel }),
82
+ ctx.isOpen.value ? ctx.ui.value.panelVisible({ class: ctx.propUi.value?.panelVisible }) : ctx.ui.value.panelHidden({ class: ctx.propUi.value?.panelHidden })
83
+ ]"
84
+ >
85
+ <!-- Success state -->
86
+ <template v-if="ctx.isSubmitted.value">
87
+ <slot name="success" :reset="ctx.reset" :close="ctx.close">
88
+ <div data-slot="successState" :class="ctx.ui.value.successState({ class: ctx.propUi.value?.successState })">
89
+ <UIcon name="i-lucide-check-circle-2" :class="ctx.ui.value.successIcon({ class: ctx.propUi.value?.successIcon })" />
90
+ <p :class="ctx.ui.value.successTitle({ class: ctx.propUi.value?.successTitle })">Thank you!</p>
91
+ <p :class="ctx.ui.value.successMessage({ class: ctx.propUi.value?.successMessage })">
92
+ Your feedback has been submitted successfully.
93
+ </p>
94
+ <UButton size="sm" color="neutral" variant="outline" @click="ctx.reset">
95
+ Send more feedback
96
+ </UButton>
97
+ </div>
98
+ </slot>
99
+ </template>
100
+
101
+ <!-- Main form flow -->
102
+ <template v-else>
103
+ <!-- Header -->
104
+ <slot name="header" :title="title" :close="ctx.close">
105
+ <div data-slot="panelHeader" :class="ctx.ui.value.panelHeader({ class: ctx.propUi.value?.panelHeader })">
106
+ <span :class="ctx.ui.value.panelTitle({ class: ctx.propUi.value?.panelTitle })">{{ title }}</span>
107
+ <UButton
108
+ size="xs"
109
+ color="neutral"
110
+ variant="ghost"
111
+ icon="i-lucide-x"
112
+ square
113
+ :class="ctx.ui.value.panelCloseButton({ class: ctx.propUi.value?.panelCloseButton })"
114
+ aria-label="Close feedback panel"
115
+ @click="ctx.close"
116
+ />
117
+ </div>
118
+ </slot>
119
+
120
+ <!-- Type selector (step 1) -->
121
+ <template v-if="!ctx.selectedType.value">
122
+ <slot
123
+ name="type-selector"
124
+ :types="ctx.feedbackTypes.value"
125
+ :selected="ctx.selectedType.value"
126
+ :select="(id) => ctx.selectedType.value = id"
127
+ >
128
+ <div data-slot="typeSelector" :class="ctx.ui.value.typeSelector({ class: ctx.propUi.value?.typeSelector })">
129
+ <button
130
+ v-for="feedbackType in ctx.feedbackTypes.value"
131
+ :key="feedbackType.id"
132
+ type="button"
133
+ data-slot="typeOption"
134
+ :class="[
135
+ ctx.ui.value.typeOption({ class: ctx.propUi.value?.typeOption }),
136
+ ctx.selectedType.value === feedbackType.id && ctx.ui.value.typeOptionSelected({ class: ctx.propUi.value?.typeOptionSelected })
137
+ ]"
138
+ @click="ctx.selectedType.value = feedbackType.id"
139
+ >
140
+ <UIcon
141
+ v-if="feedbackType.icon"
142
+ :name="feedbackType.icon"
143
+ :class="ctx.ui.value.typeOptionIcon({ class: ctx.propUi.value?.typeOptionIcon })"
144
+ />
145
+ <div>
146
+ <div :class="ctx.ui.value.typeOptionLabel({ class: ctx.propUi.value?.typeOptionLabel })">
147
+ {{ feedbackType.label }}
148
+ </div>
149
+ <div
150
+ v-if="feedbackType.description"
151
+ :class="ctx.ui.value.typeOptionDescription({ class: ctx.propUi.value?.typeOptionDescription })"
152
+ >
153
+ {{ feedbackType.description }}
154
+ </div>
155
+ </div>
156
+ </button>
157
+ </div>
158
+ </slot>
159
+ </template>
160
+
161
+ <!-- Form (step 2) -->
162
+ <template v-else>
163
+ <slot
164
+ name="form"
165
+ :email="ctx.email.value"
166
+ :message="ctx.message.value"
167
+ :screenshot="ctx.screenshot.value"
168
+ >
169
+ <div data-slot="form" :class="ctx.ui.value.form({ class: ctx.propUi.value?.form })">
170
+ <!-- Back button -->
171
+ <UButton
172
+ size="xs"
173
+ color="neutral"
174
+ variant="ghost"
175
+ icon="i-lucide-arrow-left"
176
+ label="Back"
177
+ data-slot="backButton"
178
+ :class="ctx.ui.value.backButton({ class: ctx.propUi.value?.backButton })"
179
+ @click="ctx.selectedType.value = null"
180
+ />
181
+
182
+ <!-- Email -->
183
+ <div data-slot="formField" :class="ctx.ui.value.formField({ class: ctx.propUi.value?.formField })">
184
+ <label :class="ctx.ui.value.formLabel({ class: ctx.propUi.value?.formLabel })">Email</label>
185
+ <UInput
186
+ :model-value="ctx.email.value"
187
+ type="email"
188
+ :color="ctx.color.value"
189
+ :placeholder="ctx.emailPlaceholder.value"
190
+ data-slot="formInput"
191
+ @update:model-value="ctx.email.value = $event"
192
+ />
193
+ </div>
194
+
195
+ <!-- Message -->
196
+ <div data-slot="formField" :class="ctx.ui.value.formField({ class: ctx.propUi.value?.formField })">
197
+ <label :class="ctx.ui.value.formLabel({ class: ctx.propUi.value?.formLabel })">Message</label>
198
+ <UTextarea
199
+ :model-value="ctx.message.value"
200
+ :color="ctx.color.value"
201
+ :placeholder="ctx.messagePlaceholder.value"
202
+ :rows="3"
203
+ data-slot="formTextarea"
204
+ class="resize-none"
205
+ @update:model-value="ctx.message.value = $event"
206
+ />
207
+ </div>
208
+
209
+ <!-- Screenshot -->
210
+ <template v-if="ctx.showScreenshot.value">
211
+ <div v-if="ctx.screenshot.value" :class="ctx.ui.value.screenshotPreview({ class: ctx.propUi.value?.screenshotPreview })">
212
+ <img :src="ctx.screenshot.value" alt="Screenshot preview" :class="ctx.ui.value.screenshotImage({ class: ctx.propUi.value?.screenshotImage })">
213
+ <UButton
214
+ size="xs"
215
+ color="neutral"
216
+ variant="ghost"
217
+ icon="i-lucide-x"
218
+ square
219
+ :class="ctx.ui.value.screenshotRemove({ class: ctx.propUi.value?.screenshotRemove })"
220
+ aria-label="Remove screenshot"
221
+ @click="ctx.removeScreenshot"
222
+ />
223
+ </div>
224
+ <UButton
225
+ v-else
226
+ size="xs"
227
+ color="neutral"
228
+ variant="ghost"
229
+ icon="i-lucide-camera"
230
+ label="Capture screenshot"
231
+ :class="ctx.ui.value.screenshotButton({ class: ctx.propUi.value?.screenshotButton })"
232
+ @click="ctx.captureScreenshot"
233
+ />
234
+ </template>
235
+
236
+ <!-- Honeypot (invisible to real users) -->
237
+ <div :class="ctx.ui.value.honeypot({ class: ctx.propUi.value?.honeypot })" aria-hidden="true" tabindex="-1">
238
+ <label for="_feedback_hp">Leave this empty</label>
239
+ <input
240
+ id="_feedback_hp"
241
+ :value="ctx.honeypot.value"
242
+ type="text"
243
+ name="_hp"
244
+ autocomplete="off"
245
+ tabindex="-1"
246
+ @input="ctx.honeypot.value = $event.target.value"
247
+ >
248
+ </div>
249
+
250
+ <!-- CAPTCHA -->
251
+ <div
252
+ v-if="ctx.captchaEnabled.value"
253
+ ref="captchaContainerRef"
254
+ data-slot="captchaContainer"
255
+ :class="ctx.ui.value.captchaContainer({ class: ctx.propUi.value?.captchaContainer })"
256
+ />
257
+ </div>
258
+ </slot>
259
+
260
+ <!-- Error message -->
261
+ <p v-if="ctx.submitError.value" data-slot="errorMessage" :class="ctx.ui.value.errorMessage({ class: ctx.propUi.value?.errorMessage })">
262
+ {{ ctx.submitError.value }}
263
+ </p>
264
+
265
+ <!-- Submit area -->
266
+ <slot
267
+ name="submit-area"
268
+ :submit="ctx.submit"
269
+ :is-valid="ctx.isValid.value"
270
+ :is-submitting="ctx.isSubmitting.value"
271
+ >
272
+ <div data-slot="submitArea" :class="ctx.ui.value.submitArea({ class: ctx.propUi.value?.submitArea })">
273
+ <span class="text-xs text-muted">
274
+ {{ ctx.feedbackTypes.value.find((t) => t.id === ctx.selectedType.value)?.label }}
275
+ </span>
276
+ <UButton
277
+ size="sm"
278
+ :color="ctx.color.value"
279
+ :disabled="!ctx.isValid.value || ctx.isSubmitting.value"
280
+ :label="ctx.isSubmitting.value ? 'Sending...' : 'Submit'"
281
+ @click="ctx.submit"
282
+ />
283
+ </div>
284
+ </slot>
285
+ </template>
286
+ </template>
287
+ </div>
288
+ </template>
@@ -0,0 +1,42 @@
1
+ type __VLS_Props = {
2
+ title: string;
3
+ };
4
+ declare var __VLS_1: {
5
+ reset: () => void;
6
+ close: () => void;
7
+ }, __VLS_16: {
8
+ title: string;
9
+ close: () => void;
10
+ }, __VLS_25: {
11
+ types: import("../../types/feedback-widget.js").FeedbackType[];
12
+ selected: (string & {}) | null;
13
+ select: (id: string) => string;
14
+ }, __VLS_32: {
15
+ email: string;
16
+ message: string;
17
+ screenshot: string | null;
18
+ }, __VLS_69: {
19
+ submit: () => Promise<void>;
20
+ isValid: boolean;
21
+ isSubmitting: boolean;
22
+ };
23
+ type __VLS_Slots = {} & {
24
+ success?: (props: typeof __VLS_1) => any;
25
+ } & {
26
+ header?: (props: typeof __VLS_16) => any;
27
+ } & {
28
+ 'type-selector'?: (props: typeof __VLS_25) => any;
29
+ } & {
30
+ form?: (props: typeof __VLS_32) => any;
31
+ } & {
32
+ 'submit-area'?: (props: typeof __VLS_69) => any;
33
+ };
34
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
+ declare const _default: typeof __VLS_export;
37
+ export default _default;
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -0,0 +1,16 @@
1
+ import type { GanttDependencyPath } from "../../types/gantt-chart.js";
2
+ declare var __VLS_1: {
3
+ paths: GanttDependencyPath[];
4
+ };
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_1) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,70 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { useGanttChartContext } from "../../composables/useGanttChartContext";
4
+ import { buildDependencyPath } from "../../utils/gantt-chart";
5
+ const ctx = useGanttChartContext();
6
+ const activePaths = computed(() => {
7
+ const basePaths = ctx.layout.value.dependencyPaths;
8
+ const dragId = ctx.draggedTaskId.value;
9
+ const dragPreview = ctx.dragPreview.value;
10
+ const resizeId = ctx.resizingTaskId.value;
11
+ const resizePreview = ctx.resizePreview.value;
12
+ if ((!dragId || !dragPreview) && (!resizeId || !resizePreview)) {
13
+ return basePaths;
14
+ }
15
+ const activeId = dragId ?? resizeId;
16
+ const preview = dragPreview ?? resizePreview;
17
+ if (!activeId || !preview) return basePaths;
18
+ return basePaths.map((dep) => {
19
+ const isFromActive = dep.from.task.id === activeId;
20
+ const isToActive = dep.to.task.id === activeId;
21
+ if (!isFromActive && !isToActive) return dep;
22
+ const adjustedFrom = isFromActive ? { ...dep.from, leftPx: preview.leftPx, widthPx: preview.widthPx } : dep.from;
23
+ const adjustedTo = isToActive ? { ...dep.to, leftPx: preview.leftPx, widthPx: preview.widthPx } : dep.to;
24
+ const result = buildDependencyPath(adjustedFrom, adjustedTo, ctx.rowHeight.value);
25
+ return { ...dep, path: result.path, fromPoint: result.fromPoint, toPoint: result.toPoint };
26
+ });
27
+ });
28
+ </script>
29
+
30
+ <template>
31
+ <svg
32
+ v-if="activePaths.length > 0"
33
+ data-slot="dependencyLayer"
34
+ :class="ctx.ui.value.dependencyLayer({ class: ctx.propUi.value?.dependencyLayer })"
35
+ :width="ctx.layout.value.totalWidth"
36
+ :height="ctx.layout.value.totalHeight"
37
+ :viewBox="`0 0 ${ctx.layout.value.totalWidth} ${ctx.layout.value.totalHeight}`"
38
+ aria-hidden="true"
39
+ >
40
+ <!-- Arrowhead marker definition -->
41
+ <defs>
42
+ <marker
43
+ id="gantt-arrowhead"
44
+ viewBox="0 0 10 10"
45
+ refX="10"
46
+ refY="5"
47
+ markerWidth="6"
48
+ markerHeight="6"
49
+ orient="auto-start-reverse"
50
+ >
51
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="currentColor" class="text-muted" />
52
+ </marker>
53
+ </defs>
54
+
55
+ <slot :paths="activePaths">
56
+ <template v-for="dep in activePaths" :key="`${dep.dependency.fromId}-${dep.dependency.toId}`">
57
+ <path
58
+ data-slot="dependencyArrow"
59
+ :d="dep.path"
60
+ :class="ctx.ui.value.dependencyArrow({ class: ctx.propUi.value?.dependencyArrow })"
61
+ stroke-width="1.5"
62
+ marker-end="url(#gantt-arrowhead)"
63
+ />
64
+ <!-- Connection dots at both ends -->
65
+ <circle :cx="dep.fromPoint.x" :cy="dep.fromPoint.y" r="3" fill="currentColor" class="text-muted" />
66
+ <circle :cx="dep.toPoint.x" :cy="dep.toPoint.y" r="3" fill="currentColor" class="text-muted" />
67
+ </template>
68
+ </slot>
69
+ </svg>
70
+ </template>
@@ -0,0 +1,16 @@
1
+ import type { GanttDependencyPath } from "../../types/gantt-chart.js";
2
+ declare var __VLS_1: {
3
+ paths: GanttDependencyPath[];
4
+ };
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_1) => any;
7
+ };
8
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
9
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
10
+ declare const _default: typeof __VLS_export;
11
+ export default _default;
12
+ type __VLS_WithSlots<T, S> = T & {
13
+ new (): {
14
+ $slots: S;
15
+ };
16
+ };
@@ -0,0 +1,41 @@
1
+ import type { GanttZoomLevel } from "../../types/gantt-chart.js";
2
+ import type { Component } from "vue";
3
+ export interface GanttChartHeaderProps {
4
+ /** Rendered element type @defaultValue 'div' */
5
+ as?: string | Component;
6
+ }
7
+ export interface GanttChartHeaderSlots {
8
+ default: (props: {
9
+ title: string;
10
+ prev: () => void;
11
+ next: () => void;
12
+ today: () => void;
13
+ zoomLevel: GanttZoomLevel;
14
+ setZoomLevel: (level: GanttZoomLevel) => void;
15
+ zoomLevels: GanttZoomLevel[];
16
+ }) => any;
17
+ /** Replace just the title element */
18
+ title: (props: {
19
+ title: string;
20
+ }) => any;
21
+ /** Replace just the navigation buttons */
22
+ nav: (props: {
23
+ prev: () => void;
24
+ next: () => void;
25
+ today: () => void;
26
+ }) => any;
27
+ /** Replace just the zoom level switcher */
28
+ "zoom-switcher": (props: {
29
+ zoomLevel: GanttZoomLevel;
30
+ setZoomLevel: (level: GanttZoomLevel) => void;
31
+ zoomLevels: GanttZoomLevel[];
32
+ }) => any;
33
+ }
34
+ declare const _default: typeof __VLS_export;
35
+ export default _default;
36
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<GanttChartHeaderProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<GanttChartHeaderProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, GanttChartHeaderSlots>;
37
+ type __VLS_WithSlots<T, S> = T & {
38
+ new (): {
39
+ $slots: S;
40
+ };
41
+ };
@@ -0,0 +1,56 @@
1
+ <script>
2
+ import { Primitive } from "reka-ui";
3
+ import { useGanttChartContext } from "../../composables/useGanttChartContext";
4
+ </script>
5
+
6
+ <script setup>
7
+ const props = defineProps({
8
+ as: { type: null, required: false }
9
+ });
10
+ defineSlots();
11
+ const ctx = useGanttChartContext();
12
+ </script>
13
+
14
+ <template>
15
+ <Primitive :as="props.as ?? 'div'" data-slot="header" :class="ctx.ui.value.header({ class: ctx.propUi.value?.header })">
16
+ <slot
17
+ :title="ctx.headerTitle.value"
18
+ :prev="ctx.goToPrev"
19
+ :next="ctx.goToNext"
20
+ :today="ctx.goToToday"
21
+ :zoom-level="ctx.zoomLevel.value"
22
+ :set-zoom-level="ctx.setZoomLevel"
23
+ :zoom-levels="ctx.zoomLevels.value">
24
+ <slot name="title" :title="ctx.headerTitle.value">
25
+ <span data-slot="headerTitle" :class="ctx.ui.value.headerTitle({ class: ctx.propUi.value?.headerTitle })" aria-live="polite" aria-atomic="true">
26
+ {{ ctx.headerTitle.value }}
27
+ </span>
28
+ </slot>
29
+
30
+ <div data-slot="headerActions" :class="ctx.ui.value.headerActions({ class: ctx.propUi.value?.headerActions })">
31
+ <slot name="zoom-switcher" :zoom-level="ctx.zoomLevel.value" :set-zoom-level="ctx.setZoomLevel" :zoom-levels="ctx.zoomLevels.value">
32
+ <div data-slot="zoomSwitcher" role="group" aria-label="Zoom level" :class="ctx.ui.value.zoomSwitcher({ class: ctx.propUi.value?.zoomSwitcher })">
33
+ <UButton
34
+ v-for="level in ctx.zoomLevels.value"
35
+ :key="level"
36
+ :label="level"
37
+ size="xs"
38
+ :color="ctx.zoomLevel.value === level ? ctx.color.value : 'neutral'"
39
+ :variant="ctx.zoomLevel.value === level ? 'subtle' : 'ghost'"
40
+ :aria-pressed="ctx.zoomLevel.value === level"
41
+ class="capitalize"
42
+ @click="ctx.setZoomLevel(level)" />
43
+ </div>
44
+ </slot>
45
+
46
+ <slot name="nav" :prev="ctx.goToPrev" :next="ctx.goToNext" :today="ctx.goToToday">
47
+ <div data-slot="headerNav" :class="ctx.ui.value.headerNav({ class: ctx.propUi.value?.headerNav })">
48
+ <UButton icon="i-lucide-chevron-left" color="neutral" variant="ghost" size="xs" square aria-label="Previous" @click="ctx.goToPrev" />
49
+ <UButton label="Today" color="neutral" variant="ghost" size="xs" aria-label="Go to today" @click="ctx.goToToday" />
50
+ <UButton icon="i-lucide-chevron-right" color="neutral" variant="ghost" size="xs" square aria-label="Next" @click="ctx.goToNext" />
51
+ </div>
52
+ </slot>
53
+ </div>
54
+ </slot>
55
+ </Primitive>
56
+ </template>
@@ -0,0 +1,41 @@
1
+ import type { GanttZoomLevel } from "../../types/gantt-chart.js";
2
+ import type { Component } from "vue";
3
+ export interface GanttChartHeaderProps {
4
+ /** Rendered element type @defaultValue 'div' */
5
+ as?: string | Component;
6
+ }
7
+ export interface GanttChartHeaderSlots {
8
+ default: (props: {
9
+ title: string;
10
+ prev: () => void;
11
+ next: () => void;
12
+ today: () => void;
13
+ zoomLevel: GanttZoomLevel;
14
+ setZoomLevel: (level: GanttZoomLevel) => void;
15
+ zoomLevels: GanttZoomLevel[];
16
+ }) => any;
17
+ /** Replace just the title element */
18
+ title: (props: {
19
+ title: string;
20
+ }) => any;
21
+ /** Replace just the navigation buttons */
22
+ nav: (props: {
23
+ prev: () => void;
24
+ next: () => void;
25
+ today: () => void;
26
+ }) => any;
27
+ /** Replace just the zoom level switcher */
28
+ "zoom-switcher": (props: {
29
+ zoomLevel: GanttZoomLevel;
30
+ setZoomLevel: (level: GanttZoomLevel) => void;
31
+ zoomLevels: GanttZoomLevel[];
32
+ }) => any;
33
+ }
34
+ declare const _default: typeof __VLS_export;
35
+ export default _default;
36
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<GanttChartHeaderProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<GanttChartHeaderProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, GanttChartHeaderSlots>;
37
+ type __VLS_WithSlots<T, S> = T & {
38
+ new (): {
39
+ $slots: S;
40
+ };
41
+ };
@@ -0,0 +1,34 @@
1
+ declare var __VLS_1: {}, __VLS_10: {
2
+ paths: import("../../types/gantt-chart.js").GanttDependencyPath[];
3
+ }, __VLS_12: {
4
+ task: import("../../types/gantt-chart.js").GanttTask;
5
+ bar: import("../../types/gantt-chart.js").GanttTaskBar;
6
+ }, __VLS_14: {
7
+ task: import("../../types/gantt-chart.js").GanttTask;
8
+ bar: import("../../types/gantt-chart.js").GanttTaskBar;
9
+ expanded: boolean;
10
+ toggle: () => void;
11
+ }, __VLS_21: {
12
+ task: import("../../types/gantt-chart.js").GanttTask;
13
+ bar: import("../../types/gantt-chart.js").GanttTaskBar;
14
+ };
15
+ type __VLS_Slots = {} & {
16
+ 'today-marker'?: (props: typeof __VLS_1) => any;
17
+ } & {
18
+ dependency?: (props: typeof __VLS_10) => any;
19
+ } & {
20
+ milestone?: (props: typeof __VLS_12) => any;
21
+ } & {
22
+ 'group-header'?: (props: typeof __VLS_14) => any;
23
+ } & {
24
+ 'task-bar'?: (props: typeof __VLS_21) => any;
25
+ };
26
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
27
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
28
+ declare const _default: typeof __VLS_export;
29
+ export default _default;
30
+ type __VLS_WithSlots<T, S> = T & {
31
+ new (): {
32
+ $slots: S;
33
+ };
34
+ };