@webx-ui/core 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Icon/icons.d.ts +4 -0
- package/dist/components/ImageEditor/ImageEditor.d.ts +67 -0
- package/dist/components/ImageEditor/crop.d.ts +46 -0
- package/dist/components/ImageEditor/index.d.ts +3 -0
- package/dist/components/ImageEditor/types.d.ts +128 -0
- package/dist/components/Kanban/Kanban.d.ts +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/composables/imageEditor.d.ts +19 -0
- package/dist/composables/useModal.d.ts +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5390 -4795
- package/dist/index.js.map +1 -1
- package/dist/internal/ImageEditorDialog.d.ts +128 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
|
@@ -19,6 +19,10 @@ export declare const builtinIcons: {
|
|
|
19
19
|
readonly search: "<circle cx=\"11\" cy=\"11\" r=\"6.5\"/><path d=\"m16 16 4.5 4.5\"/>";
|
|
20
20
|
readonly filter: "<path d=\"M4 5.5h16l-6.2 7.2v5.1l-3.6 2v-7.1z\"/>";
|
|
21
21
|
readonly crop: "<path d=\"M6.5 2.5v13a2 2 0 0 0 2 2h13\"/><path d=\"M2.5 6.5h13a2 2 0 0 1 2 2v13\"/>";
|
|
22
|
+
readonly 'rotate-left': "<path d=\"M19.4 13.8A7.5 7.5 0 1 0 12 5\"/><path d=\"M14.3 2.9 12 5l2.3 2.1\"/>";
|
|
23
|
+
readonly 'rotate-right': "<path d=\"M4.6 13.8A7.5 7.5 0 1 1 12 5\"/><path d=\"M9.7 2.9 12 5l-2.3 2.1\"/>";
|
|
24
|
+
readonly 'flip-horizontal': "<path d=\"M12 3v18\" stroke-dasharray=\"3 3\"/><path d=\"M9.2 7.2v9.6L3.6 12z\"/><path d=\"M14.8 7.2v9.6L20.4 12z\"/>";
|
|
25
|
+
readonly 'flip-vertical': "<path d=\"M3 12h18\" stroke-dasharray=\"3 3\"/><path d=\"M7.2 9.2h9.6L12 3.6z\"/><path d=\"M7.2 14.8h9.6L12 20.4z\"/>";
|
|
22
26
|
readonly refresh: "<path d=\"M4 12a8 8 0 0 1 13.7-5.6L20 8.5\"/><path d=\"M20 4.5v4h-4\"/><path d=\"M20 12a8 8 0 0 1-13.7 5.6L4 15.5\"/><path d=\"M4 19.5v-4h4\"/>";
|
|
23
27
|
readonly upload: "<path d=\"M12 16V4m0 0-4.5 4.5M12 4l4.5 4.5\"/><path d=\"M4 15v3.5A1.5 1.5 0 0 0 5.5 20h13a1.5 1.5 0 0 0 1.5-1.5V15\"/>";
|
|
24
28
|
readonly download: "<path d=\"M12 4v12m0 0-4.5-4.5M12 16l4.5-4.5\"/><path d=\"M4 15v3.5A1.5 1.5 0 0 0 5.5 20h13a1.5 1.5 0 0 0 1.5-1.5V15\"/>";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ImageEditorCrop, ImageEditorProps, ImageEditorRatio, ImageEditorRatioOption, ImageEditorResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Draws the result and hands it over. Exposed, so a page with a footer of its own can
|
|
4
|
+
* ask for it without the editor carrying one.
|
|
5
|
+
*/
|
|
6
|
+
declare function apply(): Promise<ImageEditorResult | undefined>;
|
|
7
|
+
declare const _default: import('vue').DefineComponent<ImageEditorProps, {
|
|
8
|
+
/** Draws the result, emits `save` and answers with it. */
|
|
9
|
+
apply: typeof apply;
|
|
10
|
+
/** Back to the whole picture, the right way up. */
|
|
11
|
+
reset: () => void;
|
|
12
|
+
crop: import('vue').ComputedRef<ImageEditorCrop>;
|
|
13
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
14
|
+
crop: (crop: ImageEditorCrop) => any;
|
|
15
|
+
error: (error: unknown) => any;
|
|
16
|
+
cancel: () => any;
|
|
17
|
+
load: (size: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
}) => any;
|
|
21
|
+
save: (result: ImageEditorResult) => any;
|
|
22
|
+
}, string, import('vue').PublicProps, Readonly<ImageEditorProps> & Readonly<{
|
|
23
|
+
onCrop?: ((crop: ImageEditorCrop) => any) | undefined;
|
|
24
|
+
onError?: ((error: unknown) => any) | undefined;
|
|
25
|
+
onCancel?: (() => any) | undefined;
|
|
26
|
+
onLoad?: ((size: {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
}) => any) | undefined;
|
|
30
|
+
onSave?: ((result: ImageEditorResult) => any) | undefined;
|
|
31
|
+
}>, {
|
|
32
|
+
disabled: boolean;
|
|
33
|
+
footer: boolean;
|
|
34
|
+
background: string;
|
|
35
|
+
format: "auto" | "image/jpeg" | "image/png" | "image/webp";
|
|
36
|
+
resizable: boolean;
|
|
37
|
+
minSize: number;
|
|
38
|
+
maxWidth: number;
|
|
39
|
+
saveLabel: string;
|
|
40
|
+
cancelLabel: string;
|
|
41
|
+
ratio: ImageEditorRatio;
|
|
42
|
+
fileName: string;
|
|
43
|
+
aspect: number;
|
|
44
|
+
ratios: (ImageEditorRatio | ImageEditorRatioOption)[];
|
|
45
|
+
rotatable: boolean;
|
|
46
|
+
flippable: boolean;
|
|
47
|
+
maxHeight: number;
|
|
48
|
+
quality: number;
|
|
49
|
+
crossOrigin: "anonymous" | "use-credentials" | "";
|
|
50
|
+
resetLabel: string;
|
|
51
|
+
rotateLeftLabel: string;
|
|
52
|
+
rotateRightLabel: string;
|
|
53
|
+
flipHorizontalLabel: string;
|
|
54
|
+
flipVerticalLabel: string;
|
|
55
|
+
ratioLabel: string;
|
|
56
|
+
cropLabel: string;
|
|
57
|
+
widthLabel: string;
|
|
58
|
+
freeLabel: string;
|
|
59
|
+
originalLabel: string;
|
|
60
|
+
errorText: string;
|
|
61
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
62
|
+
stage: HTMLDivElement;
|
|
63
|
+
frame: HTMLDivElement;
|
|
64
|
+
image: HTMLImageElement;
|
|
65
|
+
cropBox: HTMLDivElement;
|
|
66
|
+
}, HTMLDivElement>;
|
|
67
|
+
export default _default;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ImageEditorCrop } from './types';
|
|
2
|
+
/** The eight grips, named after the compass the way every editor names them. */
|
|
3
|
+
export type CropHandle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
|
|
4
|
+
export interface CropBounds {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
9
|
+
/** `1.7778` → `16:9`. Falls back to a decimal for a ratio that is nobody's convention. */
|
|
10
|
+
export declare function ratioLabelFor(value: number): string;
|
|
11
|
+
/** The whole picture, or the largest rectangle of `ratio` in the middle of it. */
|
|
12
|
+
export declare function fullCrop(bounds: CropBounds, ratio?: number): ImageEditorCrop;
|
|
13
|
+
/**
|
|
14
|
+
* The largest rectangle of `ratio` that fits inside `crop`, kept where `crop` was — used
|
|
15
|
+
* when the ratio changes and when a turn leaves the old crop the wrong shape.
|
|
16
|
+
*/
|
|
17
|
+
export declare function fitRatio(crop: ImageEditorCrop, ratio: number, bounds: CropBounds): ImageEditorCrop;
|
|
18
|
+
/** Dragged from inside: the crop slides, and stops at the edges of the picture. */
|
|
19
|
+
export declare function moveCrop(start: ImageEditorCrop, dx: number, dy: number, bounds: CropBounds): ImageEditorCrop;
|
|
20
|
+
/**
|
|
21
|
+
* Dragged by a grip.
|
|
22
|
+
*
|
|
23
|
+
* The opposite corner — or the opposite edge, for the four in the middle — is the anchor
|
|
24
|
+
* and does not move; everything else follows the pointer. With a ratio the rectangle is
|
|
25
|
+
* brought back to that ratio before it is fitted inside the picture, so a locked crop
|
|
26
|
+
* cannot be nudged out of shape by dragging it into a corner.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resizeCrop(handle: CropHandle, point: {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
}, start: ImageEditorCrop, bounds: CropBounds, { ratio, min }?: {
|
|
32
|
+
ratio?: number;
|
|
33
|
+
min?: number;
|
|
34
|
+
}): ImageEditorCrop;
|
|
35
|
+
/**
|
|
36
|
+
* The crop follows the picture through a quarter turn, so what was framed stays framed.
|
|
37
|
+
* `bounds` is the space *before* the turn; the space after it has its sides swapped.
|
|
38
|
+
*/
|
|
39
|
+
export declare function turnCrop(crop: ImageEditorCrop, bounds: CropBounds, direction: 1 | -1): ImageEditorCrop;
|
|
40
|
+
/** The same, for a mirroring. */
|
|
41
|
+
export declare function mirrorCrop(crop: ImageEditorCrop, bounds: CropBounds, axis: 'x' | 'y'): ImageEditorCrop;
|
|
42
|
+
/** The largest whole-pixel size of the same shape that fits within the caps. */
|
|
43
|
+
export declare function fitInside(width: number, height: number, maxWidth?: number, maxHeight?: number): {
|
|
44
|
+
width: number;
|
|
45
|
+
height: number;
|
|
46
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/** A rectangle of the picture, in the pixels of the image *after* its quarter turns. */
|
|
2
|
+
export interface ImageEditorCrop {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A ratio the crop can be locked to: a number (width ÷ height), `free` for no lock, or
|
|
10
|
+
* `original` for whatever the picture itself is.
|
|
11
|
+
*/
|
|
12
|
+
export type ImageEditorRatio = number | 'free' | 'original';
|
|
13
|
+
export interface ImageEditorRatioOption {
|
|
14
|
+
value: ImageEditorRatio;
|
|
15
|
+
/** Derived from the number when it is left out — `1.7778` reads as `16:9`. */
|
|
16
|
+
label?: string;
|
|
17
|
+
}
|
|
18
|
+
/** What the editor hands over. Nothing is uploaded; this is a blob and its measurements. */
|
|
19
|
+
export interface ImageEditorResult {
|
|
20
|
+
blob: Blob;
|
|
21
|
+
/** The same bytes named, ready to be posted straight to a server. */
|
|
22
|
+
file: File;
|
|
23
|
+
/** MIME type of the blob. */
|
|
24
|
+
type: string;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
/**
|
|
28
|
+
* The crop, in the pixels of the turned picture — turn by `rotation`, mirror by the
|
|
29
|
+
* flips, then cut this out, and a server arrives at the same picture.
|
|
30
|
+
*/
|
|
31
|
+
crop: ImageEditorCrop;
|
|
32
|
+
/** Quarter turns, clockwise: 0, 90, 180 or 270. */
|
|
33
|
+
rotation: number;
|
|
34
|
+
flipX: boolean;
|
|
35
|
+
flipY: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface ImageEditorProps {
|
|
38
|
+
/** The picture: a URL, or the `File` an upload field just handed you. */
|
|
39
|
+
src: string | Blob;
|
|
40
|
+
/**
|
|
41
|
+
* Name for the file in the result. Taken from `src` when it is a URL or a `File`, and
|
|
42
|
+
* its extension is put right to match the format actually written.
|
|
43
|
+
*/
|
|
44
|
+
fileName?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Locks the crop to one ratio and takes the picker away — `1` for an avatar. The
|
|
47
|
+
* ratios offered stay if `ratios` is given as well.
|
|
48
|
+
*/
|
|
49
|
+
aspect?: number;
|
|
50
|
+
/** The ratios offered. Empty hides the picker and leaves the crop free. */
|
|
51
|
+
ratios?: (ImageEditorRatio | ImageEditorRatioOption)[];
|
|
52
|
+
/** Which of them the editor opens on. Defaults to the first. */
|
|
53
|
+
ratio?: ImageEditorRatio;
|
|
54
|
+
/** Quarter turns, left and right. */
|
|
55
|
+
rotatable?: boolean;
|
|
56
|
+
/** Mirroring, across and down. */
|
|
57
|
+
flippable?: boolean;
|
|
58
|
+
/** Offers the output size — the field that scales the cut-out down before it is written. */
|
|
59
|
+
resizable?: boolean;
|
|
60
|
+
/** Largest output, in pixels. A bigger crop is scaled down to fit inside it. */
|
|
61
|
+
maxWidth?: number;
|
|
62
|
+
maxHeight?: number;
|
|
63
|
+
/** Smallest crop, in the picture's own pixels. */
|
|
64
|
+
minSize?: number;
|
|
65
|
+
/**
|
|
66
|
+
* What to write. `auto` keeps the source's format where it is one a browser can write
|
|
67
|
+
* (JPEG, PNG, WebP) and falls back to JPEG.
|
|
68
|
+
*/
|
|
69
|
+
format?: 'auto' | 'image/jpeg' | 'image/png' | 'image/webp';
|
|
70
|
+
/** 0 to 1, for the formats that have a quality. */
|
|
71
|
+
quality?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Painted behind the picture when the format has no transparency, since transparent
|
|
74
|
+
* turns black in a JPEG.
|
|
75
|
+
*/
|
|
76
|
+
background?: string;
|
|
77
|
+
/**
|
|
78
|
+
* `crossorigin` for the `<img>`. Anonymous by default: a canvas that has drawn a
|
|
79
|
+
* picture from a host which sent no CORS header cannot be read back, so the export
|
|
80
|
+
* would fail — this way it fails at loading, where it can be seen.
|
|
81
|
+
*/
|
|
82
|
+
crossOrigin?: 'anonymous' | 'use-credentials' | '';
|
|
83
|
+
/** The editor's own Cancel and Save. Off when the panel around it has its own. */
|
|
84
|
+
footer?: boolean;
|
|
85
|
+
disabled?: boolean;
|
|
86
|
+
saveLabel?: string;
|
|
87
|
+
cancelLabel?: string;
|
|
88
|
+
resetLabel?: string;
|
|
89
|
+
rotateLeftLabel?: string;
|
|
90
|
+
rotateRightLabel?: string;
|
|
91
|
+
flipHorizontalLabel?: string;
|
|
92
|
+
flipVerticalLabel?: string;
|
|
93
|
+
/** Accessible name of the ratio picker, and of the crop box itself. */
|
|
94
|
+
ratioLabel?: string;
|
|
95
|
+
cropLabel?: string;
|
|
96
|
+
/** The output-size field. */
|
|
97
|
+
widthLabel?: string;
|
|
98
|
+
freeLabel?: string;
|
|
99
|
+
originalLabel?: string;
|
|
100
|
+
/** Shown in place of the picture when it will not load. */
|
|
101
|
+
errorText?: string;
|
|
102
|
+
}
|
|
103
|
+
export interface ImageEditorEmits {
|
|
104
|
+
/** The picture, cut and turned. */
|
|
105
|
+
save: [result: ImageEditorResult];
|
|
106
|
+
cancel: [];
|
|
107
|
+
/** The picture loaded, at this size. */
|
|
108
|
+
load: [size: {
|
|
109
|
+
width: number;
|
|
110
|
+
height: number;
|
|
111
|
+
}];
|
|
112
|
+
/** It did not load, or could not be written. */
|
|
113
|
+
error: [error: unknown];
|
|
114
|
+
/** The crop moved or was resized, in the pixels of the turned picture. */
|
|
115
|
+
crop: [crop: ImageEditorCrop];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* What `openImageEditor` takes: the editor's own props, and the panel it arrives in.
|
|
119
|
+
*
|
|
120
|
+
* A type rather than an interface so that it can be handed to `createModal`, which asks
|
|
121
|
+
* for something a bag of props can be made of.
|
|
122
|
+
*/
|
|
123
|
+
export type ImageEditorModalProps = ImageEditorProps & {
|
|
124
|
+
/** Heading of the panel. */
|
|
125
|
+
title?: string;
|
|
126
|
+
/** Width of the panel: a number in pixels, or any CSS length. */
|
|
127
|
+
width?: number | string;
|
|
128
|
+
};
|
|
@@ -6,7 +6,7 @@ declare const _default: <T extends KanbanCard = KanbanCard>(__VLS_props: NonNull
|
|
|
6
6
|
readonly "onUpdate:collapsed"?: ((value: KanbanId[]) => any) | undefined;
|
|
7
7
|
readonly "onColumn-move"?: ((move: import('./types').KanbanColumnMove<T>) => any) | undefined;
|
|
8
8
|
readonly "onAdd-column"?: (() => any) | undefined;
|
|
9
|
-
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, "
|
|
9
|
+
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, "onMove" | "onAdd" | "onUpdate:collapsed" | "onColumn-move" | "onAdd-column"> & ({
|
|
10
10
|
collapsed?: KanbanId[];
|
|
11
11
|
} & KanbanProps<T>) & Partial<{}>> & import('vue').PublicProps;
|
|
12
12
|
expose(exposed: import('vue').ShallowUnwrapRef<{
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ImageEditorModalProps, ImageEditorResult } from '../components/ImageEditor/types';
|
|
2
|
+
/**
|
|
3
|
+
* Opens the picture in a panel and answers with what came out of it.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* const edited = await openImageEditor({ src: file.url, aspect: 16 / 9 })
|
|
7
|
+
* if (!edited) return
|
|
8
|
+
* await upload(edited.file)
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Nothing is uploaded and nothing is replaced: the answer is a blob, its measurements and
|
|
12
|
+
* the crop it was cut from, and the screen that asked decides where all that goes. Closed
|
|
13
|
+
* without saving — the ✕, escape, Cancel — it answers `undefined`, which is not an error.
|
|
14
|
+
*
|
|
15
|
+
* It is [`createModal`](/guide/modals) over `WxImageEditor` in a dialog, and worth reading
|
|
16
|
+
* as the example: one line names the component, the type of its answer and the event that
|
|
17
|
+
* carries it, and every call site is a single `await`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const openImageEditor: (props?: ImageEditorModalProps | undefined, options?: import('./useModal').ModalOptions) => import('./useModal').ModalPromise<ImageEditorResult>;
|
|
@@ -58,8 +58,11 @@ export declare function openModal<T = unknown>(component: Component, options?: M
|
|
|
58
58
|
*
|
|
59
59
|
* const product = await productBrowser({ multiple: false })
|
|
60
60
|
* ```
|
|
61
|
+
*
|
|
62
|
+
* `P` is any object — an `interface` of props included, which a `Record<string, unknown>`
|
|
63
|
+
* would have turned away for want of an index signature.
|
|
61
64
|
*/
|
|
62
|
-
export declare function createModal<T = unknown, P extends
|
|
65
|
+
export declare function createModal<T = unknown, P extends object = Record<string, never>>(component: Component, defaults?: ModalOptions): (props?: P, options?: ModalOptions) => ModalPromise<T>;
|
|
63
66
|
/**
|
|
64
67
|
* The handle of the modal a component is being shown in. Outside one it answers all the
|
|
65
68
|
* same, with `isModal: false` and calls that do nothing — so a component can be written
|
package/dist/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@ export { useElementWidth } from './composables/useElementWidth';
|
|
|
6
6
|
export { useToast, toast, toastQueue, dismissToast, removeToast, clearToasts, type ToastApi, type ToastHandle, type ToastOptions, type ToastRecord, type ToastType, type ToastAction, } from './composables/useToast';
|
|
7
7
|
export { openModal, createModal, useModal, connectModals, modalKey, type ModalHandle, type ModalOptions, type ModalPromise, } from './composables/useModal';
|
|
8
8
|
export { confirm, type ConfirmOptions } from './composables/confirm';
|
|
9
|
+
export { openImageEditor } from './composables/imageEditor';
|
|
9
10
|
export { useResponsiveShell, shellLayoutFor, type ResponsiveShell, type ResponsiveShellOptions, type ShellLayout, } from './composables/useResponsiveShell';
|