orio-ui 1.23.2 → 1.24.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.
Files changed (40) hide show
  1. package/README.md +3 -3
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/canvas.d.ts +1 -1
  4. package/dist/runtime/canvas.js +4 -1
  5. package/dist/runtime/components/Calendar.d.vue.ts +33 -0
  6. package/dist/runtime/components/Calendar.vue +251 -0
  7. package/dist/runtime/components/Calendar.vue.d.ts +33 -0
  8. package/dist/runtime/components/Canvas/context.d.ts +9 -0
  9. package/dist/runtime/components/Canvas/index.d.vue.ts +3 -0
  10. package/dist/runtime/components/Canvas/index.vue +19 -2
  11. package/dist/runtime/components/Canvas/index.vue.d.ts +3 -0
  12. package/dist/runtime/components/Canvas/tools/exportTool.d.ts +53 -6
  13. package/dist/runtime/components/Canvas/tools/exportTool.js +79 -32
  14. package/dist/runtime/components/Form.d.vue.ts +1 -1
  15. package/dist/runtime/components/Form.vue.d.ts +1 -1
  16. package/dist/runtime/components/date/Picker.d.vue.ts +26 -0
  17. package/dist/runtime/components/date/Picker.vue +54 -0
  18. package/dist/runtime/components/date/Picker.vue.d.ts +26 -0
  19. package/dist/runtime/components/date/PickerTrigger.d.vue.ts +23 -0
  20. package/dist/runtime/components/date/PickerTrigger.vue +80 -0
  21. package/dist/runtime/components/date/PickerTrigger.vue.d.ts +23 -0
  22. package/dist/runtime/components/date/RangePicker.d.vue.ts +28 -0
  23. package/dist/runtime/components/date/RangePicker.vue +148 -0
  24. package/dist/runtime/components/date/RangePicker.vue.d.ts +28 -0
  25. package/dist/runtime/components/view/Dates.d.vue.ts +2 -5
  26. package/dist/runtime/components/view/Dates.vue +17 -23
  27. package/dist/runtime/components/view/Dates.vue.d.ts +2 -5
  28. package/dist/runtime/i18n/en.json +8 -5
  29. package/dist/runtime/i18n/uk.json +8 -5
  30. package/dist/runtime/index.d.ts +4 -2
  31. package/dist/runtime/index.js +6 -2
  32. package/dist/runtime/utils/date.d.ts +10 -0
  33. package/dist/runtime/utils/date.js +38 -0
  34. package/package.json +1 -1
  35. package/dist/runtime/components/DatePicker.d.vue.ts +0 -15
  36. package/dist/runtime/components/DatePicker.vue +0 -24
  37. package/dist/runtime/components/DatePicker.vue.d.ts +0 -15
  38. package/dist/runtime/components/DateRangePicker.d.vue.ts +0 -18
  39. package/dist/runtime/components/DateRangePicker.vue +0 -67
  40. package/dist/runtime/components/DateRangePicker.vue.d.ts +0 -18
package/README.md CHANGED
@@ -8,7 +8,7 @@ A delightful, lightweight component library for Nuxt 3+ applications. Built with
8
8
 
9
9
  ## Features
10
10
 
11
- ✨ **56 Components** - Beautiful, accessible components ready to use
11
+ ✨ **58 Components** - Beautiful, accessible components ready to use
12
12
  🎨 **Themeable** - 5 built-in accent themes with light/dark mode support
13
13
  🚀 **Auto-imported** - Works seamlessly with Nuxt's auto-import system
14
14
  📦 **Tree-shakeable** - Only bundle what you use
@@ -67,7 +67,7 @@ function handleClick() {
67
67
 
68
68
  ## What's Included
69
69
 
70
- ### Components (56)
70
+ ### Components (58)
71
71
 
72
72
  #### Form Controls
73
73
 
@@ -194,7 +194,7 @@ npm run docs:dev
194
194
  orio-ui/
195
195
  ├── src/
196
196
  │ ├── runtime/
197
- │ │ ├── components/ # 56 Vue components
197
+ │ │ ├── components/ # 58 Vue components
198
198
  │ │ ├── composables/ # 13 composables
199
199
  │ │ ├── assets/css/ # Theme CSS files
200
200
  │ │ └── utils/ # Icon registry
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0 || ^4.0.0"
6
6
  },
7
- "version": "1.23.2",
7
+ "version": "1.24.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
@@ -18,4 +18,4 @@ export { rotateTool, type RotateToolOptions, } from "./components/Canvas/tools/r
18
18
  export { resizeTool, type ResizeToolOptions, } from "./components/Canvas/tools/resizeTool.js";
19
19
  export { transformTool, type TransformToolOptions, } from "./components/Canvas/tools/transformTool.js";
20
20
  export { imageTool, type ImageToolOptions, type ImageNodeData, } from "./components/Canvas/tools/imageTool.js";
21
- export { exportTool, type ExportToolOptions, type ExportFormat, } from "./components/Canvas/tools/exportTool.js";
21
+ export { exportTool, performExport, renderCanvasSnapshot, DEFAULT_EXPORT_OPTIONS, type ExportToolOptions, type ExportOptions, type ExportResult, type ExportFormat, type CanvasSnapshot, } from "./components/Canvas/tools/exportTool.js";
@@ -45,5 +45,8 @@ export {
45
45
  imageTool
46
46
  } from "./components/Canvas/tools/imageTool.js";
47
47
  export {
48
- exportTool
48
+ exportTool,
49
+ performExport,
50
+ renderCanvasSnapshot,
51
+ DEFAULT_EXPORT_OPTIONS
49
52
  } from "./components/Canvas/tools/exportTool.js";
@@ -0,0 +1,33 @@
1
+ export type MarkerVariant = "accent" | "success" | "alert" | "danger" | "muted";
2
+ export interface CalendarMarker {
3
+ variant: MarkerVariant;
4
+ start: string;
5
+ end: string;
6
+ }
7
+ export interface CalendarProps {
8
+ selected?: string | null;
9
+ markers?: CalendarMarker[];
10
+ getMarker?: (iso: string) => CalendarMarker | null;
11
+ isDisabled?: (iso: string) => boolean;
12
+ weekStartsOn?: 0 | 1;
13
+ }
14
+ type __VLS_Props = CalendarProps;
15
+ type __VLS_ModelProps = {
16
+ "anchor"?: string | null;
17
+ };
18
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
19
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
+ select: (iso: string) => any;
21
+ dayEnter: (iso: string) => any;
22
+ "update:anchor": (value: string | null) => any;
23
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
24
+ onSelect?: ((iso: string) => any) | undefined;
25
+ onDayEnter?: ((iso: string) => any) | undefined;
26
+ "onUpdate:anchor"?: ((value: string | null) => any) | undefined;
27
+ }>, {
28
+ selected: string | null;
29
+ markers: CalendarMarker[];
30
+ weekStartsOn: 0 | 1;
31
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
32
+ declare const _default: typeof __VLS_export;
33
+ export default _default;
@@ -0,0 +1,251 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { useI18n } from "vue-i18n";
4
+ import {
5
+ addMonths,
6
+ formatISO,
7
+ isSameDay,
8
+ parseISO,
9
+ startOfMonth
10
+ } from "../utils/date";
11
+ const props = defineProps({
12
+ selected: { type: [String, null], required: false, default: null },
13
+ markers: { type: Array, required: false, default: () => [] },
14
+ getMarker: { type: Function, required: false },
15
+ isDisabled: { type: Function, required: false },
16
+ weekStartsOn: { type: Number, required: false, default: 1 }
17
+ });
18
+ const anchor = defineModel("anchor", { type: [String, null], ...{ default: null } });
19
+ const emit = defineEmits(["select", "dayEnter"]);
20
+ const { locale, t } = useI18n();
21
+ const today = /* @__PURE__ */ new Date();
22
+ const visibleMonth = computed(
23
+ () => startOfMonth(parseISO(anchor.value) ?? /* @__PURE__ */ new Date())
24
+ );
25
+ function shift(delta) {
26
+ anchor.value = formatISO(addMonths(visibleMonth.value, delta));
27
+ }
28
+ const monthLabel = computed(
29
+ () => new Intl.DateTimeFormat(locale.value, {
30
+ month: "long",
31
+ year: "numeric"
32
+ }).format(visibleMonth.value)
33
+ );
34
+ const weekdayLabels = computed(() => {
35
+ const sunday = new Date(2024, 0, 7);
36
+ return Array.from({ length: 7 }, (_, i) => {
37
+ const d = new Date(sunday);
38
+ d.setDate(sunday.getDate() + (i + props.weekStartsOn) % 7);
39
+ return new Intl.DateTimeFormat(locale.value, { weekday: "short" }).format(
40
+ d
41
+ );
42
+ });
43
+ });
44
+ function resolveMarker(iso) {
45
+ if (props.getMarker) {
46
+ const m = props.getMarker(iso);
47
+ if (m) {
48
+ return {
49
+ variant: m.variant,
50
+ isStart: iso === m.start,
51
+ isEnd: iso === m.end
52
+ };
53
+ }
54
+ }
55
+ for (let i = props.markers.length - 1; i >= 0; i--) {
56
+ const m = props.markers[i];
57
+ if (iso >= m.start && iso <= m.end) {
58
+ return {
59
+ variant: m.variant,
60
+ isStart: iso === m.start,
61
+ isEnd: iso === m.end
62
+ };
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ const days = computed(() => {
68
+ const first = visibleMonth.value;
69
+ const startWeekday = first.getDay();
70
+ const offset = (startWeekday - props.weekStartsOn + 7) % 7;
71
+ const gridStart = new Date(first);
72
+ gridStart.setDate(gridStart.getDate() - offset);
73
+ const sel = parseISO(props.selected);
74
+ const result = [];
75
+ for (let i = 0; i < 42; i++) {
76
+ const d = new Date(gridStart);
77
+ d.setDate(gridStart.getDate() + i);
78
+ const iso = formatISO(d);
79
+ result.push({
80
+ iso,
81
+ label: d.getDate(),
82
+ inMonth: d.getMonth() === first.getMonth(),
83
+ isToday: isSameDay(d, today),
84
+ isSelected: !!sel && isSameDay(d, sel),
85
+ isDisabled: props.isDisabled?.(iso) ?? false,
86
+ marker: resolveMarker(iso)
87
+ });
88
+ }
89
+ return result;
90
+ });
91
+ function onSelect(day) {
92
+ if (day.isDisabled) return;
93
+ emit("select", day.iso);
94
+ }
95
+ function onEnter(day) {
96
+ emit("dayEnter", day.iso);
97
+ }
98
+ </script>
99
+
100
+ <template>
101
+ <div class="calendar">
102
+ <div class="calendar-nav">
103
+ <orio-button
104
+ variant="subdued"
105
+ icon="chevron-left"
106
+ :aria-label="t('calendar.previousMonth')"
107
+ @click="shift(-1)"
108
+ />
109
+ <span class="calendar-month-title">{{ monthLabel }}</span>
110
+ <orio-button
111
+ variant="subdued"
112
+ icon="chevron-right"
113
+ :aria-label="t('calendar.nextMonth')"
114
+ @click="shift(1)"
115
+ />
116
+ </div>
117
+ <div class="calendar-weekdays">
118
+ <span v-for="w in weekdayLabels" :key="w" class="calendar-weekday">
119
+ {{ w }}
120
+ </span>
121
+ </div>
122
+ <div class="calendar-grid">
123
+ <button
124
+ v-for="day in days"
125
+ :key="day.iso"
126
+ type="button"
127
+ class="calendar-day"
128
+ :class="{
129
+ 'out-of-month': !day.inMonth,
130
+ today: day.isToday,
131
+ selected: day.isSelected,
132
+ 'has-marker': !!day.marker,
133
+ [`marker-${day.marker?.variant}`]: !!day.marker,
134
+ 'marker-start': day.marker?.isStart,
135
+ 'marker-end': day.marker?.isEnd
136
+ }"
137
+ :disabled="day.isDisabled"
138
+ @click="onSelect(day)"
139
+ @mouseenter="onEnter(day)"
140
+ >
141
+ <orio-badge v-if="day.isSelected" pill variant="primary">
142
+ {{ day.label }}
143
+ </orio-badge>
144
+ <template v-else>{{ day.label }}</template>
145
+ </button>
146
+ </div>
147
+ </div>
148
+ </template>
149
+
150
+ <style scoped>
151
+ .calendar {
152
+ display: inline-block;
153
+ background: var(--color-bg);
154
+ border: 1px solid var(--color-border);
155
+ border-radius: var(--border-radius-md);
156
+ padding: 0.75rem;
157
+ user-select: none;
158
+ font-size: var(--control-font-size, var(--font-md));
159
+ color: var(--color-text);
160
+ min-width: 17rem;
161
+ }
162
+
163
+ .calendar-nav {
164
+ display: flex;
165
+ align-items: center;
166
+ justify-content: space-between;
167
+ gap: 0.5rem;
168
+ margin-bottom: 0.5rem;
169
+ }
170
+
171
+ .calendar-month-title {
172
+ font-weight: 600;
173
+ text-transform: capitalize;
174
+ }
175
+
176
+ .calendar-weekdays,
177
+ .calendar-grid {
178
+ display: grid;
179
+ grid-template-columns: repeat(7, 1fr);
180
+ }
181
+
182
+ .calendar-weekday {
183
+ text-align: center;
184
+ font-size: var(--font-xs);
185
+ color: var(--color-muted);
186
+ padding: 0.25rem 0;
187
+ text-transform: uppercase;
188
+ }
189
+
190
+ .calendar-day {
191
+ aspect-ratio: 1;
192
+ display: flex;
193
+ align-items: center;
194
+ justify-content: center;
195
+ background: transparent;
196
+ border: 0;
197
+ color: inherit;
198
+ cursor: pointer;
199
+ border-radius: var(--border-radius-sm);
200
+ font-size: inherit;
201
+ transition: background-color 0.15s ease, color 0.15s ease;
202
+ }
203
+ .calendar-day:hover:not(:disabled):not(.has-marker):not(.selected) {
204
+ background-color: var(--color-surface);
205
+ }
206
+ .calendar-day.out-of-month {
207
+ color: var(--color-muted);
208
+ opacity: 0.45;
209
+ }
210
+ .calendar-day.today {
211
+ box-shadow: inset 0 0 0 1px var(--color-accent);
212
+ }
213
+ .calendar-day.has-marker {
214
+ background-color: var(--marker-bg);
215
+ color: var(--marker-color);
216
+ border-radius: 0;
217
+ }
218
+ .calendar-day.has-marker.marker-start {
219
+ border-top-left-radius: var(--border-radius-sm);
220
+ border-bottom-left-radius: var(--border-radius-sm);
221
+ }
222
+ .calendar-day.has-marker.marker-end {
223
+ border-top-right-radius: var(--border-radius-sm);
224
+ border-bottom-right-radius: var(--border-radius-sm);
225
+ }
226
+ .calendar-day.marker-accent {
227
+ --marker-bg: var(--color-accent-soft);
228
+ --marker-color: var(--color-accent);
229
+ }
230
+ .calendar-day.marker-success {
231
+ --marker-bg: var(--color-success-soft);
232
+ --marker-color: var(--color-success);
233
+ }
234
+ .calendar-day.marker-alert {
235
+ --marker-bg: var(--color-alert-soft);
236
+ --marker-color: var(--color-alert);
237
+ }
238
+ .calendar-day.marker-danger {
239
+ --marker-bg: var(--color-danger-soft);
240
+ --marker-color: var(--color-danger);
241
+ }
242
+ .calendar-day.marker-muted {
243
+ --marker-bg: var(--color-surface);
244
+ --marker-color: var(--color-muted);
245
+ }
246
+ .calendar-day:disabled {
247
+ color: var(--color-muted);
248
+ cursor: not-allowed;
249
+ opacity: 0.4;
250
+ }
251
+ </style>
@@ -0,0 +1,33 @@
1
+ export type MarkerVariant = "accent" | "success" | "alert" | "danger" | "muted";
2
+ export interface CalendarMarker {
3
+ variant: MarkerVariant;
4
+ start: string;
5
+ end: string;
6
+ }
7
+ export interface CalendarProps {
8
+ selected?: string | null;
9
+ markers?: CalendarMarker[];
10
+ getMarker?: (iso: string) => CalendarMarker | null;
11
+ isDisabled?: (iso: string) => boolean;
12
+ weekStartsOn?: 0 | 1;
13
+ }
14
+ type __VLS_Props = CalendarProps;
15
+ type __VLS_ModelProps = {
16
+ "anchor"?: string | null;
17
+ };
18
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
19
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
+ select: (iso: string) => any;
21
+ dayEnter: (iso: string) => any;
22
+ "update:anchor": (value: string | null) => any;
23
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
24
+ onSelect?: ((iso: string) => any) | undefined;
25
+ onDayEnter?: ((iso: string) => any) | undefined;
26
+ "onUpdate:anchor"?: ((value: string | null) => any) | undefined;
27
+ }>, {
28
+ selected: string | null;
29
+ markers: CalendarMarker[];
30
+ weekStartsOn: 0 | 1;
31
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
32
+ declare const _default: typeof __VLS_export;
33
+ export default _default;
@@ -1,5 +1,6 @@
1
1
  import { type ComputedRef, type InjectionKey, type Ref } from "vue";
2
2
  import type { CanvasNode, CanvasTool, CanvasToolApi } from "./types.js";
3
+ import type { ExportOptions, ExportResult } from "./tools/exportTool.js";
3
4
  export interface CanvasContext {
4
5
  tools: Ref<CanvasTool[]>;
5
6
  activeToolId: Ref<string | null>;
@@ -33,6 +34,14 @@ export interface CanvasContext {
33
34
  endAction: () => void;
34
35
  /** Keyboard handler for undo/redo shortcuts. Attach to the stage element. */
35
36
  onKeyDown: (e: KeyboardEvent) => void;
37
+ /**
38
+ * Export the current canvas as an image. Overrides merge over the registered
39
+ * `exportTool` options (if any) and the built-in defaults. Without
40
+ * `onExport`/`download` overrides the call triggers a browser download for
41
+ * backwards compatibility; pass `{ download: false }` or supply `onExport`
42
+ * to consume the result instead (e.g. push to a cart, upload to a backend).
43
+ */
44
+ exportCanvas: (overrides?: ExportOptions) => Promise<ExportResult>;
36
45
  }
37
46
  export declare const CANVAS_CONTEXT: InjectionKey<CanvasContext>;
38
47
  export declare function useCanvasContext(): CanvasContext;
@@ -1,4 +1,5 @@
1
1
  import type { CanvasNode, CanvasTool, CanvasToolApi } from "./types.js";
2
+ import { type ExportOptions, type ExportResult } from "./tools/exportTool.js";
2
3
  export interface CanvasProps {
3
4
  /**
4
5
  * Unique name for this canvas instance. Required so detached toolbars and
@@ -31,6 +32,7 @@ export interface CanvasProps {
31
32
  type __VLS_Props = CanvasProps;
32
33
  declare function getToolOptions<T extends Record<string, unknown>>(id: string): T;
33
34
  declare function setActiveTool(id: string | null): void;
35
+ declare function exportCanvas(overrides?: ExportOptions): Promise<ExportResult>;
34
36
  type __VLS_ModelProps = {
35
37
  "nodes"?: CanvasNode[];
36
38
  };
@@ -54,6 +56,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
54
56
  redo: () => void;
55
57
  canUndo: import("vue").ComputedRef<boolean>;
56
58
  canRedo: import("vue").ComputedRef<boolean>;
59
+ exportCanvas: typeof exportCanvas;
57
60
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
58
61
  "update:nodes": (value: CanvasNode<unknown>[]) => any;
59
62
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
@@ -15,6 +15,9 @@ import { useCanvasNodes } from "./composables/useCanvasNodes";
15
15
  import { useCanvasSetup } from "./composables/useCanvasSetup";
16
16
  import Stage from "./components/Stage.vue";
17
17
  import Toolbar from "./components/Toolbar.vue";
18
+ import {
19
+ performExport
20
+ } from "./tools/exportTool";
18
21
  const props = defineProps({
19
22
  name: { type: String, required: true },
20
23
  tools: { type: Array, required: false, default: () => [] },
@@ -122,6 +125,18 @@ function handleKeyDown(e) {
122
125
  }
123
126
  onKeyDown(e);
124
127
  }
128
+ function exportCanvas(overrides = {}) {
129
+ const toolOpts = getToolOptions("export");
130
+ return performExport(
131
+ {
132
+ nodes: nodes.value,
133
+ tools: props.tools,
134
+ width: props.width,
135
+ height: props.height
136
+ },
137
+ { ...toolOpts, ...overrides }
138
+ );
139
+ }
125
140
  const context = {
126
141
  tools: toolsRef,
127
142
  activeToolId,
@@ -146,7 +161,8 @@ const context = {
146
161
  endAction,
147
162
  onKeyDown: handleKeyDown,
148
163
  cursorOverride,
149
- setCursor
164
+ setCursor,
165
+ exportCanvas
150
166
  };
151
167
  provide(CANVAS_CONTEXT, context);
152
168
  let registeredName = null;
@@ -190,7 +206,8 @@ defineExpose({
190
206
  undo,
191
207
  redo,
192
208
  canUndo,
193
- canRedo
209
+ canRedo,
210
+ exportCanvas
194
211
  });
195
212
  </script>
196
213
 
@@ -1,4 +1,5 @@
1
1
  import type { CanvasNode, CanvasTool, CanvasToolApi } from "./types.js";
2
+ import { type ExportOptions, type ExportResult } from "./tools/exportTool.js";
2
3
  export interface CanvasProps {
3
4
  /**
4
5
  * Unique name for this canvas instance. Required so detached toolbars and
@@ -31,6 +32,7 @@ export interface CanvasProps {
31
32
  type __VLS_Props = CanvasProps;
32
33
  declare function getToolOptions<T extends Record<string, unknown>>(id: string): T;
33
34
  declare function setActiveTool(id: string | null): void;
35
+ declare function exportCanvas(overrides?: ExportOptions): Promise<ExportResult>;
34
36
  type __VLS_ModelProps = {
35
37
  "nodes"?: CanvasNode[];
36
38
  };
@@ -54,6 +56,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
54
56
  redo: () => void;
55
57
  canUndo: import("vue").ComputedRef<boolean>;
56
58
  canRedo: import("vue").ComputedRef<boolean>;
59
+ exportCanvas: typeof exportCanvas;
57
60
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
58
61
  "update:nodes": (value: CanvasNode<unknown>[]) => any;
59
62
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
@@ -1,18 +1,65 @@
1
- import type { CanvasTool } from "../types.js";
1
+ import type { CanvasNode, CanvasTool } from "../types.js";
2
2
  /**
3
3
  * Image formats Canvas2D's `toBlob`/`toDataURL` natively supports across
4
4
  * modern browsers. Anything else (e.g. AVIF, TIFF) is encoder-dependent and
5
5
  * not guaranteed to round-trip.
6
6
  */
7
7
  export type ExportFormat = "png" | "jpeg" | "webp";
8
- export interface ExportToolOptions extends Record<string, unknown> {
9
- /** Output format. Defaults to PNG. */
8
+ export interface ExportResult {
9
+ blob: Blob;
10
+ dataURL: string;
11
+ /** Same bytes as `blob`, wrapped as a `File` with the configured filename. */
12
+ file: File;
10
13
  format: ExportFormat;
14
+ /** Output pixel width (already multiplied by `scale`). */
15
+ width: number;
16
+ /** Output pixel height (already multiplied by `scale`). */
17
+ height: number;
18
+ filename: string;
19
+ }
20
+ export interface ExportOptions {
21
+ /** Output format. Defaults to PNG. */
22
+ format?: ExportFormat;
11
23
  /** Quality for lossy formats (jpeg, webp), 0–1. Ignored for PNG. */
12
- quality: number;
24
+ quality?: number;
13
25
  /** File name without extension. */
14
- filename: string;
26
+ filename?: string;
15
27
  /** Pixel scale relative to the visible canvas (1 = same size). */
16
- scale: number;
28
+ scale?: number;
29
+ /**
30
+ * If provided, receives the export result instead of (or alongside) the
31
+ * download. Use to push the image into application state (e.g. a cart) or
32
+ * upload to a backend. Async — the canvas awaits the returned Promise.
33
+ */
34
+ onExport?: (result: ExportResult) => void | Promise<void>;
35
+ /**
36
+ * Trigger a browser download. Defaults to `true` when `onExport` is not
37
+ * provided, `false` when it is.
38
+ */
39
+ download?: boolean;
40
+ }
41
+ export interface ExportToolOptions extends Required<Pick<ExportOptions, "format" | "quality" | "filename" | "scale">>, Pick<ExportOptions, "onExport" | "download">, Record<string, unknown> {
17
42
  }
43
+ export declare const DEFAULT_EXPORT_OPTIONS: ExportToolOptions;
44
+ export interface CanvasSnapshot {
45
+ nodes: CanvasNode[];
46
+ tools: CanvasTool[];
47
+ width: number;
48
+ height: number;
49
+ }
50
+ /**
51
+ * Render the snapshot to an offscreen canvas and produce a Blob/dataURL/File.
52
+ * Pure: does not download or invoke callbacks.
53
+ *
54
+ * The offscreen canvas is sized exactly to `snapshot.width × snapshot.height`
55
+ * (× `scale`), so any node geometry outside the canvas is naturally clipped —
56
+ * the result captures only what would be visible on the live canvas.
57
+ */
58
+ export declare function renderCanvasSnapshot(snapshot: CanvasSnapshot, options?: ExportOptions): Promise<ExportResult>;
59
+ /**
60
+ * Render the snapshot, then optionally hand the result to `onExport` and/or
61
+ * trigger a browser download. Resolves with the result so callers can chain
62
+ * additional work (uploads, state updates).
63
+ */
64
+ export declare function performExport(snapshot: CanvasSnapshot, options?: ExportOptions): Promise<ExportResult>;
18
65
  export declare function exportTool(options?: Partial<ExportToolOptions>): CanvasTool<never, ExportToolOptions>;