@fitin/vue 0.1.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/README.md +5 -0
- package/dist/index.es.js +151 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types/components/fitin-canvas.vue.d.ts +31 -0
- package/dist/types/components/fitin-canvas.vue.d.ts.map +1 -0
- package/dist/types/components/fitin-container.vue.d.ts +23 -0
- package/dist/types/components/fitin-container.vue.d.ts.map +1 -0
- package/dist/types/components/hooks.d.ts +12 -0
- package/dist/types/components/hooks.d.ts.map +1 -0
- package/dist/types/components/keys.d.ts +6 -0
- package/dist/types/components/keys.d.ts.map +1 -0
- package/dist/types/components/logging.d.ts +3 -0
- package/dist/types/components/logging.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/index.html +18 -0
- package/package.json +34 -0
- package/src/App.vue +19 -0
- package/src/components/fitin-canvas.vue +104 -0
- package/src/components/fitin-container.vue +90 -0
- package/src/components/hooks.ts +61 -0
- package/src/components/keys.ts +11 -0
- package/src/components/logging.ts +6 -0
- package/src/index.ts +12 -0
- package/src/main.ts +4 -0
- package/tsconfig.app.json +30 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +23 -0
- package/vite.config.ts +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Vue 3 + TypeScript + Vite
|
|
2
|
+
|
|
3
|
+
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
|
4
|
+
|
|
5
|
+
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
|
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { computed as e, createElementBlock as t, defineComponent as n, inject as r, normalizeClass as i, normalizeStyle as a, openBlock as o, provide as s, reactive as c, ref as l, renderSlot as u, watchEffect as d } from "vue";
|
|
2
|
+
import { BehaviorSubject as f } from "rxjs";
|
|
3
|
+
import { Fitin as p } from "@fitin/core";
|
|
4
|
+
//#region src/components/keys.ts
|
|
5
|
+
var m = Symbol("fitin-canvas"), h = Symbol("fitin-container");
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/components/logging.ts
|
|
8
|
+
function g(e) {
|
|
9
|
+
console.error("[@fitin/vue]", e);
|
|
10
|
+
}
|
|
11
|
+
function _(e) {
|
|
12
|
+
console.warn("[@fitin/vue]", e);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/components/fitin-canvas.vue
|
|
16
|
+
var v = /* @__PURE__ */ n({
|
|
17
|
+
inheritAttrs: !1,
|
|
18
|
+
__name: "fitin-canvas",
|
|
19
|
+
props: {
|
|
20
|
+
designWidth: {},
|
|
21
|
+
designHeight: {},
|
|
22
|
+
mode: {},
|
|
23
|
+
minDesignWidth: {},
|
|
24
|
+
minDesignHeight: {},
|
|
25
|
+
wait: {},
|
|
26
|
+
computeScaleXY: { type: Function },
|
|
27
|
+
viewport: {},
|
|
28
|
+
center: { type: Boolean }
|
|
29
|
+
},
|
|
30
|
+
setup(n) {
|
|
31
|
+
let i = n, c = l(), h = e(() => i.center ? {
|
|
32
|
+
position: "absolute",
|
|
33
|
+
top: "50%",
|
|
34
|
+
left: "50%",
|
|
35
|
+
transform: "translate(-50%, -50%)",
|
|
36
|
+
overflow: "hidden"
|
|
37
|
+
} : {
|
|
38
|
+
position: "relative",
|
|
39
|
+
overflow: "hidden"
|
|
40
|
+
}), _, v = new f(void 0);
|
|
41
|
+
s(m, v.asObservable());
|
|
42
|
+
let y = r(m);
|
|
43
|
+
return d((e) => {
|
|
44
|
+
if (y) {
|
|
45
|
+
g("Nested fitin-canvas is forbidden");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
_ = new p(i);
|
|
49
|
+
let t = (e) => {
|
|
50
|
+
e && c.value && (c.value.style.width = `${e.effectiveWidth}px`, c.value.style.height = `${e.effectiveHeight}px`), v.next(e);
|
|
51
|
+
}, n = i.viewport === "parent" ? c.value?.parentElement : i.viewport;
|
|
52
|
+
n ? _.subscribe(n, t) : _.subscribe(t), e(() => {
|
|
53
|
+
_.dispose();
|
|
54
|
+
});
|
|
55
|
+
}), (e, n) => (o(), t("section", {
|
|
56
|
+
ref_key: "canvasRef",
|
|
57
|
+
ref: c,
|
|
58
|
+
role: "fitin-canvas",
|
|
59
|
+
style: a(h.value)
|
|
60
|
+
}, [u(e.$slots, "default")], 4));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/components/hooks.ts
|
|
65
|
+
function y(e) {
|
|
66
|
+
let t = r(h) || [];
|
|
67
|
+
t.push(e), s(h, t);
|
|
68
|
+
}
|
|
69
|
+
function b(e) {
|
|
70
|
+
let t = r(m);
|
|
71
|
+
return t ? ((r(h) || []).find((e) => e === "affect-descendant") && _("There's an ancestor fitin-container resizing all descendants"), d((n) => {
|
|
72
|
+
let r = t.subscribe(e);
|
|
73
|
+
n(() => r.unsubscribe());
|
|
74
|
+
})) : g("A fitin-container must be used within a fitin-canvas context"), t;
|
|
75
|
+
}
|
|
76
|
+
function x() {
|
|
77
|
+
let e = c({
|
|
78
|
+
scaleX: 1,
|
|
79
|
+
scaleY: 1,
|
|
80
|
+
scaleXY: 1,
|
|
81
|
+
effectiveWidth: void 0,
|
|
82
|
+
effectiveHeight: void 0
|
|
83
|
+
});
|
|
84
|
+
return b((t) => {
|
|
85
|
+
t && (e.scaleX = t.scaleX, e.scaleY = t.scaleY, e.scaleXY = t.scaleXY, e.effectiveWidth = t.effectiveWidth, e.effectiveHeight = t.effectiveHeight);
|
|
86
|
+
}), e;
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/components/fitin-container.vue?vue&type=script&setup=true&lang.ts
|
|
90
|
+
var S = ["data-scope"], C = /* @__PURE__ */ n({
|
|
91
|
+
inheritAttrs: !1,
|
|
92
|
+
__name: "fitin-container",
|
|
93
|
+
props: {
|
|
94
|
+
designWidth: {},
|
|
95
|
+
designHeight: {},
|
|
96
|
+
transformOriginX: {},
|
|
97
|
+
transformOriginY: {},
|
|
98
|
+
style: {},
|
|
99
|
+
class: {}
|
|
100
|
+
},
|
|
101
|
+
setup(n) {
|
|
102
|
+
let r = n, s = e(() => r.transformOriginX || r.transformOriginY ? "affect-descendant" : "affect-self");
|
|
103
|
+
y(s.value);
|
|
104
|
+
let c = l({});
|
|
105
|
+
function f(e, t) {
|
|
106
|
+
if (t.transformOriginX || t.transformOriginY) {
|
|
107
|
+
let n, r;
|
|
108
|
+
if (t.transformOriginX && t.transformOriginY) {
|
|
109
|
+
let i = e.transformXY(t.transformOriginX, t.transformOriginY);
|
|
110
|
+
n = i.transform, r = i.transformOrigin;
|
|
111
|
+
} else if (t.transformOriginX) {
|
|
112
|
+
let i = e.transformX(t.transformOriginX);
|
|
113
|
+
n = i.transform, r = i.transformOrigin;
|
|
114
|
+
} else {
|
|
115
|
+
let i = e.transformY(t.transformOriginY);
|
|
116
|
+
n = i.transform, r = i.transformOrigin;
|
|
117
|
+
}
|
|
118
|
+
c.value = {
|
|
119
|
+
position: "absolute",
|
|
120
|
+
width: `${t.designWidth}px`,
|
|
121
|
+
height: `${t.designHeight}px`,
|
|
122
|
+
transform: n,
|
|
123
|
+
transformOrigin: r
|
|
124
|
+
};
|
|
125
|
+
} else c.value = {
|
|
126
|
+
width: `${e.scaleX * t.designWidth}px`,
|
|
127
|
+
height: `${e.scaleY * t.designHeight}px`
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
let p = b();
|
|
131
|
+
return d((e) => {
|
|
132
|
+
if (p) {
|
|
133
|
+
let t = p.subscribe((e) => {
|
|
134
|
+
e && f(e, r);
|
|
135
|
+
});
|
|
136
|
+
e(() => t.unsubscribe());
|
|
137
|
+
}
|
|
138
|
+
}), (e, n) => (o(), t("section", {
|
|
139
|
+
role: "fitin-container",
|
|
140
|
+
"data-scope": s.value,
|
|
141
|
+
style: a([r.style, c.value]),
|
|
142
|
+
class: i(r.class)
|
|
143
|
+
}, [u(e.$slots, "default")], 14, S));
|
|
144
|
+
}
|
|
145
|
+
}), w = { install(e) {
|
|
146
|
+
e.component("FitinCanvas", v), e.component("FitinContainer", C);
|
|
147
|
+
} };
|
|
148
|
+
//#endregion
|
|
149
|
+
export { v as FitinCanvas, C as FitinContainer, w as plugin, b as useFitin, x as useFitinState };
|
|
150
|
+
|
|
151
|
+
//# sourceMappingURL=index.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.es.js","names":[],"sources":["../src/components/keys.ts","../src/components/logging.ts","../src/components/fitin-canvas.vue","../src/components/fitin-canvas.vue","../src/components/hooks.ts","../src/components/fitin-container.vue","../src/components/fitin-container.vue","../src/index.ts"],"sourcesContent":["import { type InjectionKey } from \"vue\";\r\nimport type { Observable } from \"rxjs\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\n\r\nexport const FitinCanvasKey: InjectionKey<\r\n Observable<IResizeEvent | undefined>\r\n> = Symbol(\"fitin-canvas\");\r\n\r\nexport const FitinContainerKey: InjectionKey<\r\n (\"affect-self\" | \"affect-descendant\")[]\r\n> = Symbol(\"fitin-container\");\r\n","export function logE(message: string): void {\r\n console.error(\"[@fitin/vue]\", message);\r\n}\r\nexport function logW(message: string): void {\r\n console.warn(\"[@fitin/vue]\", message);\r\n}\r\n","<script setup lang=\"ts\">\r\nimport {\r\n computed,\r\n inject,\r\n provide,\r\n ref,\r\n watchEffect,\r\n type CSSProperties,\r\n} from \"vue\";\r\nimport { BehaviorSubject } from \"rxjs\";\r\nimport { Fitin, type Mode, type IResizeEvent } from \"@fitin/core\";\r\nimport { FitinCanvasKey } from \"./keys\";\r\nimport { logE } from \"./logging\";\r\n\r\n/**\r\n * Vue SFC does not support TypeScript advanced types(e.g., Omit, Pick and Partial).\r\n * However, these are exactly the types that `FitinOptions` depends on.\r\n * Solution: declare the type from scratch (i.e. rewrite it explicitly without relying on utility types).\r\n */\r\ntype FitinCanvasProps = {\r\n designWidth: number; // physical design width of container\r\n designHeight: number; // physical design height of container\r\n mode?: Mode;\r\n minDesignWidth?: number; // minimum physical design width of container\r\n minDesignHeight?: number; // minimum physical design height of container\r\n wait?: number; // in ms\r\n computeScaleXY?: (\r\n designWidth: number,\r\n designHeight: number,\r\n scaleX: number,\r\n scaleY: number,\r\n ) => number;\r\n viewport?: HTMLElement | \"parent\";\r\n center?: boolean;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\nconst props = defineProps<FitinCanvasProps>();\r\n\r\nconst canvasRef = ref<HTMLElement>();\r\n\r\nconst canvasStyle = computed<CSSProperties>(() =>\r\n props.center\r\n ? {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n left: \"50%\",\r\n transform: \"translate(-50%, -50%)\",\r\n overflow: \"hidden\"\r\n }\r\n : {\r\n position: \"relative\",\r\n overflow: \"hidden\"\r\n },\r\n);\r\n\r\nlet fitin: Fitin;\r\nlet subject = new BehaviorSubject<IResizeEvent | undefined>(undefined);\r\nprovide(FitinCanvasKey, subject.asObservable());\r\nconst resizeObservable = inject(FitinCanvasKey);\r\n\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n logE(\"Nested fitin-canvas is forbidden\");\r\n return;\r\n }\r\n\r\n fitin = new Fitin(props);\r\n\r\n const handleResize = (event: IResizeEvent) => {\r\n if (event && canvasRef.value) {\r\n canvasRef.value.style.width = `${event.effectiveWidth}px`;\r\n canvasRef.value.style.height = `${event.effectiveHeight}px`;\r\n }\r\n subject.next(event);\r\n };\r\n\r\n const viewport =\r\n props.viewport === \"parent\"\r\n ? canvasRef.value?.parentElement\r\n : props.viewport;\r\n if (viewport) {\r\n fitin.subscribe(viewport, handleResize);\r\n } else {\r\n fitin.subscribe(handleResize);\r\n }\r\n\r\n onCleanup(() => {\r\n fitin.dispose();\r\n });\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n ref=\"canvasRef\"\r\n role=\"fitin-canvas\"\r\n :style=\"canvasStyle\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport {\r\n computed,\r\n inject,\r\n provide,\r\n ref,\r\n watchEffect,\r\n type CSSProperties,\r\n} from \"vue\";\r\nimport { BehaviorSubject } from \"rxjs\";\r\nimport { Fitin, type Mode, type IResizeEvent } from \"@fitin/core\";\r\nimport { FitinCanvasKey } from \"./keys\";\r\nimport { logE } from \"./logging\";\r\n\r\n/**\r\n * Vue SFC does not support TypeScript advanced types(e.g., Omit, Pick and Partial).\r\n * However, these are exactly the types that `FitinOptions` depends on.\r\n * Solution: declare the type from scratch (i.e. rewrite it explicitly without relying on utility types).\r\n */\r\ntype FitinCanvasProps = {\r\n designWidth: number; // physical design width of container\r\n designHeight: number; // physical design height of container\r\n mode?: Mode;\r\n minDesignWidth?: number; // minimum physical design width of container\r\n minDesignHeight?: number; // minimum physical design height of container\r\n wait?: number; // in ms\r\n computeScaleXY?: (\r\n designWidth: number,\r\n designHeight: number,\r\n scaleX: number,\r\n scaleY: number,\r\n ) => number;\r\n viewport?: HTMLElement | \"parent\";\r\n center?: boolean;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\nconst props = defineProps<FitinCanvasProps>();\r\n\r\nconst canvasRef = ref<HTMLElement>();\r\n\r\nconst canvasStyle = computed<CSSProperties>(() =>\r\n props.center\r\n ? {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n left: \"50%\",\r\n transform: \"translate(-50%, -50%)\",\r\n overflow: \"hidden\"\r\n }\r\n : {\r\n position: \"relative\",\r\n overflow: \"hidden\"\r\n },\r\n);\r\n\r\nlet fitin: Fitin;\r\nlet subject = new BehaviorSubject<IResizeEvent | undefined>(undefined);\r\nprovide(FitinCanvasKey, subject.asObservable());\r\nconst resizeObservable = inject(FitinCanvasKey);\r\n\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n logE(\"Nested fitin-canvas is forbidden\");\r\n return;\r\n }\r\n\r\n fitin = new Fitin(props);\r\n\r\n const handleResize = (event: IResizeEvent) => {\r\n if (event && canvasRef.value) {\r\n canvasRef.value.style.width = `${event.effectiveWidth}px`;\r\n canvasRef.value.style.height = `${event.effectiveHeight}px`;\r\n }\r\n subject.next(event);\r\n };\r\n\r\n const viewport =\r\n props.viewport === \"parent\"\r\n ? canvasRef.value?.parentElement\r\n : props.viewport;\r\n if (viewport) {\r\n fitin.subscribe(viewport, handleResize);\r\n } else {\r\n fitin.subscribe(handleResize);\r\n }\r\n\r\n onCleanup(() => {\r\n fitin.dispose();\r\n });\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n ref=\"canvasRef\"\r\n role=\"fitin-canvas\"\r\n :style=\"canvasStyle\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","import { inject, provide, reactive, watchEffect } from \"vue\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\nimport { FitinCanvasKey, FitinContainerKey } from \"./keys\";\r\nimport { logE, logW } from \"./logging\";\r\nimport type { Observable } from \"rxjs\";\r\n\r\nexport function provideFitinContainer(\r\n value: \"affect-self\" | \"affect-descendant\",\r\n) {\r\n const paths = inject(FitinContainerKey) || [];\r\n paths.push(value);\r\n provide(FitinContainerKey, paths);\r\n}\r\n\r\nexport function useFitin(\r\n resizeHandler?: (event: undefined | IResizeEvent) => void,\r\n): undefined | Observable<undefined | IResizeEvent> {\r\n const resizeObservable = inject(FitinCanvasKey);\r\n if (resizeObservable) {\r\n const paths = inject(FitinContainerKey) || [];\r\n if (paths.find((path) => path === \"affect-descendant\")) {\r\n logW(\"There's an ancestor fitin-container resizing all descendants\");\r\n }\r\n\r\n watchEffect((onCleanup) => {\r\n const subscription = resizeObservable.subscribe(resizeHandler);\r\n onCleanup(() => subscription.unsubscribe());\r\n });\r\n } else {\r\n logE(\"A fitin-container must be used within a fitin-canvas context\");\r\n }\r\n\r\n return resizeObservable;\r\n}\r\n\r\nexport function useFitinState() {\r\n const state = reactive<{\r\n scaleX: number;\r\n scaleY: number;\r\n scaleXY: number;\r\n effectiveWidth: undefined | number;\r\n effectiveHeight: undefined | number;\r\n }>({\r\n scaleX: 1,\r\n scaleY: 1,\r\n scaleXY: 1,\r\n effectiveWidth: undefined,\r\n effectiveHeight: undefined,\r\n });\r\n useFitin((event) => {\r\n if (event) {\r\n state.scaleX = event.scaleX;\r\n state.scaleY = event.scaleY;\r\n state.scaleXY = event.scaleXY;\r\n state.effectiveWidth = event.effectiveWidth;\r\n state.effectiveHeight = event.effectiveHeight;\r\n }\r\n });\r\n\r\n return state;\r\n}\r\n","<script setup lang=\"ts\">\r\nimport { ref, watchEffect, computed, type CSSProperties } from \"vue\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\nimport { provideFitinContainer, useFitin } from \"./hooks\";\r\n\r\ntype FitinContainerProps = {\r\n designWidth: number;\r\n designHeight: number;\r\n transformOriginX?: \"left\" | \"center\" | \"right\";\r\n transformOriginY?: \"top\" | \"center\" | \"bottom\";\r\n style?: CSSProperties;\r\n class?: string;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\n\r\nconst props = defineProps<FitinContainerProps>();\r\n\r\nconst affectScope = computed(() =>\r\n props.transformOriginX || props.transformOriginY\r\n ? \"affect-descendant\"\r\n : \"affect-self\",\r\n);\r\n\r\nprovideFitinContainer(affectScope.value);\r\n\r\nconst fitinStyle = ref<CSSProperties>({});\r\n\r\nfunction adjustContainer(event: IResizeEvent, props: FitinContainerProps) {\r\n if (props.transformOriginX || props.transformOriginY) {\r\n let transform: string;\r\n let transformOrigin: string;\r\n if (props.transformOriginX && props.transformOriginY) {\r\n const res = event.transformXY(\r\n props.transformOriginX,\r\n props.transformOriginY,\r\n );\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else if (props.transformOriginX) {\r\n const res = event.transformX(props.transformOriginX);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else {\r\n const res = event.transformY(props.transformOriginY!);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n }\r\n fitinStyle.value = {\r\n position: \"absolute\",\r\n width: `${props.designWidth}px`,\r\n height: `${props.designHeight}px`,\r\n transform: transform,\r\n transformOrigin: transformOrigin,\r\n };\r\n } else {\r\n fitinStyle.value = {\r\n width: `${event.scaleX * props.designWidth}px`,\r\n height: `${event.scaleY * props.designHeight}px`,\r\n };\r\n }\r\n}\r\n\r\nconst resizeObservable = useFitin();\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n const subscription = resizeObservable.subscribe(\r\n (event: IResizeEvent | undefined) => {\r\n if (event) {\r\n adjustContainer(event, props);\r\n }\r\n },\r\n );\r\n onCleanup(() => subscription.unsubscribe());\r\n }\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n role=\"fitin-container\"\r\n :data-scope=\"affectScope\"\r\n :style=\"[props.style, fitinStyle]\"\r\n :class=\"props.class\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport { ref, watchEffect, computed, type CSSProperties } from \"vue\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\nimport { provideFitinContainer, useFitin } from \"./hooks\";\r\n\r\ntype FitinContainerProps = {\r\n designWidth: number;\r\n designHeight: number;\r\n transformOriginX?: \"left\" | \"center\" | \"right\";\r\n transformOriginY?: \"top\" | \"center\" | \"bottom\";\r\n style?: CSSProperties;\r\n class?: string;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\n\r\nconst props = defineProps<FitinContainerProps>();\r\n\r\nconst affectScope = computed(() =>\r\n props.transformOriginX || props.transformOriginY\r\n ? \"affect-descendant\"\r\n : \"affect-self\",\r\n);\r\n\r\nprovideFitinContainer(affectScope.value);\r\n\r\nconst fitinStyle = ref<CSSProperties>({});\r\n\r\nfunction adjustContainer(event: IResizeEvent, props: FitinContainerProps) {\r\n if (props.transformOriginX || props.transformOriginY) {\r\n let transform: string;\r\n let transformOrigin: string;\r\n if (props.transformOriginX && props.transformOriginY) {\r\n const res = event.transformXY(\r\n props.transformOriginX,\r\n props.transformOriginY,\r\n );\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else if (props.transformOriginX) {\r\n const res = event.transformX(props.transformOriginX);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else {\r\n const res = event.transformY(props.transformOriginY!);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n }\r\n fitinStyle.value = {\r\n position: \"absolute\",\r\n width: `${props.designWidth}px`,\r\n height: `${props.designHeight}px`,\r\n transform: transform,\r\n transformOrigin: transformOrigin,\r\n };\r\n } else {\r\n fitinStyle.value = {\r\n width: `${event.scaleX * props.designWidth}px`,\r\n height: `${event.scaleY * props.designHeight}px`,\r\n };\r\n }\r\n}\r\n\r\nconst resizeObservable = useFitin();\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n const subscription = resizeObservable.subscribe(\r\n (event: IResizeEvent | undefined) => {\r\n if (event) {\r\n adjustContainer(event, props);\r\n }\r\n },\r\n );\r\n onCleanup(() => subscription.unsubscribe());\r\n }\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n role=\"fitin-container\"\r\n :data-scope=\"affectScope\"\r\n :style=\"[props.style, fitinStyle]\"\r\n :class=\"props.class\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","import type { App, Plugin } from \"vue\";\r\nimport FitinCanvas from \"./components/fitin-canvas.vue\";\r\nimport FitinContainer from \"./components/fitin-container.vue\";\r\nexport { useFitin, useFitinState } from \"./components/hooks\";\r\n\r\nexport { FitinCanvas, FitinContainer };\r\nexport const plugin: Plugin = {\r\n install(app: App) {\r\n app.component(\"FitinCanvas\", FitinCanvas);\r\n app.component(\"FitinContainer\", FitinContainer);\r\n },\r\n};\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("vue"),require("rxjs"),require("@fitin/core")):typeof define==`function`&&define.amd?define([`exports`,`vue`,`rxjs`,`@fitin/core`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.Fitin={},e.Vue,e.rxjs,e.FitinCore))})(this,function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=Symbol(`fitin-canvas`),a=Symbol(`fitin-container`);function o(e){console.error(`[@fitin/vue]`,e)}function s(e){console.warn(`[@fitin/vue]`,e)}var c=(0,t.defineComponent)({inheritAttrs:!1,__name:`fitin-canvas`,props:{designWidth:{},designHeight:{},mode:{},minDesignWidth:{},minDesignHeight:{},wait:{},computeScaleXY:{type:Function},viewport:{},center:{type:Boolean}},setup(e){let a=e,s=(0,t.ref)(),c=(0,t.computed)(()=>a.center?{position:`absolute`,top:`50%`,left:`50%`,transform:`translate(-50%, -50%)`,overflow:`hidden`}:{position:`relative`,overflow:`hidden`}),l,u=new n.BehaviorSubject(void 0);(0,t.provide)(i,u.asObservable());let d=(0,t.inject)(i);return(0,t.watchEffect)(e=>{if(d){o(`Nested fitin-canvas is forbidden`);return}l=new r.Fitin(a);let t=e=>{e&&s.value&&(s.value.style.width=`${e.effectiveWidth}px`,s.value.style.height=`${e.effectiveHeight}px`),u.next(e)},n=a.viewport===`parent`?s.value?.parentElement:a.viewport;n?l.subscribe(n,t):l.subscribe(t),e(()=>{l.dispose()})}),(e,n)=>((0,t.openBlock)(),(0,t.createElementBlock)(`section`,{ref_key:`canvasRef`,ref:s,role:`fitin-canvas`,style:(0,t.normalizeStyle)(c.value)},[(0,t.renderSlot)(e.$slots,`default`)],4))}});function l(e){let n=(0,t.inject)(a)||[];n.push(e),(0,t.provide)(a,n)}function u(e){let n=(0,t.inject)(i);return n?(((0,t.inject)(a)||[]).find(e=>e===`affect-descendant`)&&s(`There's an ancestor fitin-container resizing all descendants`),(0,t.watchEffect)(t=>{let r=n.subscribe(e);t(()=>r.unsubscribe())})):o(`A fitin-container must be used within a fitin-canvas context`),n}function d(){let e=(0,t.reactive)({scaleX:1,scaleY:1,scaleXY:1,effectiveWidth:void 0,effectiveHeight:void 0});return u(t=>{t&&(e.scaleX=t.scaleX,e.scaleY=t.scaleY,e.scaleXY=t.scaleXY,e.effectiveWidth=t.effectiveWidth,e.effectiveHeight=t.effectiveHeight)}),e}var f=[`data-scope`],p=(0,t.defineComponent)({inheritAttrs:!1,__name:`fitin-container`,props:{designWidth:{},designHeight:{},transformOriginX:{},transformOriginY:{},style:{},class:{}},setup(e){let n=e,r=(0,t.computed)(()=>n.transformOriginX||n.transformOriginY?`affect-descendant`:`affect-self`);l(r.value);let i=(0,t.ref)({});function a(e,t){if(t.transformOriginX||t.transformOriginY){let n,r;if(t.transformOriginX&&t.transformOriginY){let i=e.transformXY(t.transformOriginX,t.transformOriginY);n=i.transform,r=i.transformOrigin}else if(t.transformOriginX){let i=e.transformX(t.transformOriginX);n=i.transform,r=i.transformOrigin}else{let i=e.transformY(t.transformOriginY);n=i.transform,r=i.transformOrigin}i.value={position:`absolute`,width:`${t.designWidth}px`,height:`${t.designHeight}px`,transform:n,transformOrigin:r}}else i.value={width:`${e.scaleX*t.designWidth}px`,height:`${e.scaleY*t.designHeight}px`}}let o=u();return(0,t.watchEffect)(e=>{if(o){let t=o.subscribe(e=>{e&&a(e,n)});e(()=>t.unsubscribe())}}),(e,a)=>((0,t.openBlock)(),(0,t.createElementBlock)(`section`,{role:`fitin-container`,"data-scope":r.value,style:(0,t.normalizeStyle)([n.style,i.value]),class:(0,t.normalizeClass)(n.class)},[(0,t.renderSlot)(e.$slots,`default`)],14,f))}});e.FitinCanvas=c,e.FitinContainer=p,e.plugin={install(e){e.component(`FitinCanvas`,c),e.component(`FitinContainer`,p)}},e.useFitin=u,e.useFitinState=d});
|
|
2
|
+
//# sourceMappingURL=index.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.umd.js","names":[],"sources":["../src/components/keys.ts","../src/components/logging.ts","../src/components/fitin-canvas.vue","../src/components/fitin-canvas.vue","../src/components/hooks.ts","../src/components/fitin-container.vue","../src/components/fitin-container.vue","../src/index.ts"],"sourcesContent":["import { type InjectionKey } from \"vue\";\r\nimport type { Observable } from \"rxjs\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\n\r\nexport const FitinCanvasKey: InjectionKey<\r\n Observable<IResizeEvent | undefined>\r\n> = Symbol(\"fitin-canvas\");\r\n\r\nexport const FitinContainerKey: InjectionKey<\r\n (\"affect-self\" | \"affect-descendant\")[]\r\n> = Symbol(\"fitin-container\");\r\n","export function logE(message: string): void {\r\n console.error(\"[@fitin/vue]\", message);\r\n}\r\nexport function logW(message: string): void {\r\n console.warn(\"[@fitin/vue]\", message);\r\n}\r\n","<script setup lang=\"ts\">\r\nimport {\r\n computed,\r\n inject,\r\n provide,\r\n ref,\r\n watchEffect,\r\n type CSSProperties,\r\n} from \"vue\";\r\nimport { BehaviorSubject } from \"rxjs\";\r\nimport { Fitin, type Mode, type IResizeEvent } from \"@fitin/core\";\r\nimport { FitinCanvasKey } from \"./keys\";\r\nimport { logE } from \"./logging\";\r\n\r\n/**\r\n * Vue SFC does not support TypeScript advanced types(e.g., Omit, Pick and Partial).\r\n * However, these are exactly the types that `FitinOptions` depends on.\r\n * Solution: declare the type from scratch (i.e. rewrite it explicitly without relying on utility types).\r\n */\r\ntype FitinCanvasProps = {\r\n designWidth: number; // physical design width of container\r\n designHeight: number; // physical design height of container\r\n mode?: Mode;\r\n minDesignWidth?: number; // minimum physical design width of container\r\n minDesignHeight?: number; // minimum physical design height of container\r\n wait?: number; // in ms\r\n computeScaleXY?: (\r\n designWidth: number,\r\n designHeight: number,\r\n scaleX: number,\r\n scaleY: number,\r\n ) => number;\r\n viewport?: HTMLElement | \"parent\";\r\n center?: boolean;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\nconst props = defineProps<FitinCanvasProps>();\r\n\r\nconst canvasRef = ref<HTMLElement>();\r\n\r\nconst canvasStyle = computed<CSSProperties>(() =>\r\n props.center\r\n ? {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n left: \"50%\",\r\n transform: \"translate(-50%, -50%)\",\r\n overflow: \"hidden\"\r\n }\r\n : {\r\n position: \"relative\",\r\n overflow: \"hidden\"\r\n },\r\n);\r\n\r\nlet fitin: Fitin;\r\nlet subject = new BehaviorSubject<IResizeEvent | undefined>(undefined);\r\nprovide(FitinCanvasKey, subject.asObservable());\r\nconst resizeObservable = inject(FitinCanvasKey);\r\n\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n logE(\"Nested fitin-canvas is forbidden\");\r\n return;\r\n }\r\n\r\n fitin = new Fitin(props);\r\n\r\n const handleResize = (event: IResizeEvent) => {\r\n if (event && canvasRef.value) {\r\n canvasRef.value.style.width = `${event.effectiveWidth}px`;\r\n canvasRef.value.style.height = `${event.effectiveHeight}px`;\r\n }\r\n subject.next(event);\r\n };\r\n\r\n const viewport =\r\n props.viewport === \"parent\"\r\n ? canvasRef.value?.parentElement\r\n : props.viewport;\r\n if (viewport) {\r\n fitin.subscribe(viewport, handleResize);\r\n } else {\r\n fitin.subscribe(handleResize);\r\n }\r\n\r\n onCleanup(() => {\r\n fitin.dispose();\r\n });\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n ref=\"canvasRef\"\r\n role=\"fitin-canvas\"\r\n :style=\"canvasStyle\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport {\r\n computed,\r\n inject,\r\n provide,\r\n ref,\r\n watchEffect,\r\n type CSSProperties,\r\n} from \"vue\";\r\nimport { BehaviorSubject } from \"rxjs\";\r\nimport { Fitin, type Mode, type IResizeEvent } from \"@fitin/core\";\r\nimport { FitinCanvasKey } from \"./keys\";\r\nimport { logE } from \"./logging\";\r\n\r\n/**\r\n * Vue SFC does not support TypeScript advanced types(e.g., Omit, Pick and Partial).\r\n * However, these are exactly the types that `FitinOptions` depends on.\r\n * Solution: declare the type from scratch (i.e. rewrite it explicitly without relying on utility types).\r\n */\r\ntype FitinCanvasProps = {\r\n designWidth: number; // physical design width of container\r\n designHeight: number; // physical design height of container\r\n mode?: Mode;\r\n minDesignWidth?: number; // minimum physical design width of container\r\n minDesignHeight?: number; // minimum physical design height of container\r\n wait?: number; // in ms\r\n computeScaleXY?: (\r\n designWidth: number,\r\n designHeight: number,\r\n scaleX: number,\r\n scaleY: number,\r\n ) => number;\r\n viewport?: HTMLElement | \"parent\";\r\n center?: boolean;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\nconst props = defineProps<FitinCanvasProps>();\r\n\r\nconst canvasRef = ref<HTMLElement>();\r\n\r\nconst canvasStyle = computed<CSSProperties>(() =>\r\n props.center\r\n ? {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n left: \"50%\",\r\n transform: \"translate(-50%, -50%)\",\r\n overflow: \"hidden\"\r\n }\r\n : {\r\n position: \"relative\",\r\n overflow: \"hidden\"\r\n },\r\n);\r\n\r\nlet fitin: Fitin;\r\nlet subject = new BehaviorSubject<IResizeEvent | undefined>(undefined);\r\nprovide(FitinCanvasKey, subject.asObservable());\r\nconst resizeObservable = inject(FitinCanvasKey);\r\n\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n logE(\"Nested fitin-canvas is forbidden\");\r\n return;\r\n }\r\n\r\n fitin = new Fitin(props);\r\n\r\n const handleResize = (event: IResizeEvent) => {\r\n if (event && canvasRef.value) {\r\n canvasRef.value.style.width = `${event.effectiveWidth}px`;\r\n canvasRef.value.style.height = `${event.effectiveHeight}px`;\r\n }\r\n subject.next(event);\r\n };\r\n\r\n const viewport =\r\n props.viewport === \"parent\"\r\n ? canvasRef.value?.parentElement\r\n : props.viewport;\r\n if (viewport) {\r\n fitin.subscribe(viewport, handleResize);\r\n } else {\r\n fitin.subscribe(handleResize);\r\n }\r\n\r\n onCleanup(() => {\r\n fitin.dispose();\r\n });\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n ref=\"canvasRef\"\r\n role=\"fitin-canvas\"\r\n :style=\"canvasStyle\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","import { inject, provide, reactive, watchEffect } from \"vue\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\nimport { FitinCanvasKey, FitinContainerKey } from \"./keys\";\r\nimport { logE, logW } from \"./logging\";\r\nimport type { Observable } from \"rxjs\";\r\n\r\nexport function provideFitinContainer(\r\n value: \"affect-self\" | \"affect-descendant\",\r\n) {\r\n const paths = inject(FitinContainerKey) || [];\r\n paths.push(value);\r\n provide(FitinContainerKey, paths);\r\n}\r\n\r\nexport function useFitin(\r\n resizeHandler?: (event: undefined | IResizeEvent) => void,\r\n): undefined | Observable<undefined | IResizeEvent> {\r\n const resizeObservable = inject(FitinCanvasKey);\r\n if (resizeObservable) {\r\n const paths = inject(FitinContainerKey) || [];\r\n if (paths.find((path) => path === \"affect-descendant\")) {\r\n logW(\"There's an ancestor fitin-container resizing all descendants\");\r\n }\r\n\r\n watchEffect((onCleanup) => {\r\n const subscription = resizeObservable.subscribe(resizeHandler);\r\n onCleanup(() => subscription.unsubscribe());\r\n });\r\n } else {\r\n logE(\"A fitin-container must be used within a fitin-canvas context\");\r\n }\r\n\r\n return resizeObservable;\r\n}\r\n\r\nexport function useFitinState() {\r\n const state = reactive<{\r\n scaleX: number;\r\n scaleY: number;\r\n scaleXY: number;\r\n effectiveWidth: undefined | number;\r\n effectiveHeight: undefined | number;\r\n }>({\r\n scaleX: 1,\r\n scaleY: 1,\r\n scaleXY: 1,\r\n effectiveWidth: undefined,\r\n effectiveHeight: undefined,\r\n });\r\n useFitin((event) => {\r\n if (event) {\r\n state.scaleX = event.scaleX;\r\n state.scaleY = event.scaleY;\r\n state.scaleXY = event.scaleXY;\r\n state.effectiveWidth = event.effectiveWidth;\r\n state.effectiveHeight = event.effectiveHeight;\r\n }\r\n });\r\n\r\n return state;\r\n}\r\n","<script setup lang=\"ts\">\r\nimport { ref, watchEffect, computed, type CSSProperties } from \"vue\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\nimport { provideFitinContainer, useFitin } from \"./hooks\";\r\n\r\ntype FitinContainerProps = {\r\n designWidth: number;\r\n designHeight: number;\r\n transformOriginX?: \"left\" | \"center\" | \"right\";\r\n transformOriginY?: \"top\" | \"center\" | \"bottom\";\r\n style?: CSSProperties;\r\n class?: string;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\n\r\nconst props = defineProps<FitinContainerProps>();\r\n\r\nconst affectScope = computed(() =>\r\n props.transformOriginX || props.transformOriginY\r\n ? \"affect-descendant\"\r\n : \"affect-self\",\r\n);\r\n\r\nprovideFitinContainer(affectScope.value);\r\n\r\nconst fitinStyle = ref<CSSProperties>({});\r\n\r\nfunction adjustContainer(event: IResizeEvent, props: FitinContainerProps) {\r\n if (props.transformOriginX || props.transformOriginY) {\r\n let transform: string;\r\n let transformOrigin: string;\r\n if (props.transformOriginX && props.transformOriginY) {\r\n const res = event.transformXY(\r\n props.transformOriginX,\r\n props.transformOriginY,\r\n );\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else if (props.transformOriginX) {\r\n const res = event.transformX(props.transformOriginX);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else {\r\n const res = event.transformY(props.transformOriginY!);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n }\r\n fitinStyle.value = {\r\n position: \"absolute\",\r\n width: `${props.designWidth}px`,\r\n height: `${props.designHeight}px`,\r\n transform: transform,\r\n transformOrigin: transformOrigin,\r\n };\r\n } else {\r\n fitinStyle.value = {\r\n width: `${event.scaleX * props.designWidth}px`,\r\n height: `${event.scaleY * props.designHeight}px`,\r\n };\r\n }\r\n}\r\n\r\nconst resizeObservable = useFitin();\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n const subscription = resizeObservable.subscribe(\r\n (event: IResizeEvent | undefined) => {\r\n if (event) {\r\n adjustContainer(event, props);\r\n }\r\n },\r\n );\r\n onCleanup(() => subscription.unsubscribe());\r\n }\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n role=\"fitin-container\"\r\n :data-scope=\"affectScope\"\r\n :style=\"[props.style, fitinStyle]\"\r\n :class=\"props.class\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","<script setup lang=\"ts\">\r\nimport { ref, watchEffect, computed, type CSSProperties } from \"vue\";\r\nimport type { IResizeEvent } from \"@fitin/core\";\r\nimport { provideFitinContainer, useFitin } from \"./hooks\";\r\n\r\ntype FitinContainerProps = {\r\n designWidth: number;\r\n designHeight: number;\r\n transformOriginX?: \"left\" | \"center\" | \"right\";\r\n transformOriginY?: \"top\" | \"center\" | \"bottom\";\r\n style?: CSSProperties;\r\n class?: string;\r\n};\r\n\r\ndefineOptions({\r\n inheritAttrs: false,\r\n});\r\n\r\nconst props = defineProps<FitinContainerProps>();\r\n\r\nconst affectScope = computed(() =>\r\n props.transformOriginX || props.transformOriginY\r\n ? \"affect-descendant\"\r\n : \"affect-self\",\r\n);\r\n\r\nprovideFitinContainer(affectScope.value);\r\n\r\nconst fitinStyle = ref<CSSProperties>({});\r\n\r\nfunction adjustContainer(event: IResizeEvent, props: FitinContainerProps) {\r\n if (props.transformOriginX || props.transformOriginY) {\r\n let transform: string;\r\n let transformOrigin: string;\r\n if (props.transformOriginX && props.transformOriginY) {\r\n const res = event.transformXY(\r\n props.transformOriginX,\r\n props.transformOriginY,\r\n );\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else if (props.transformOriginX) {\r\n const res = event.transformX(props.transformOriginX);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n } else {\r\n const res = event.transformY(props.transformOriginY!);\r\n transform = res.transform;\r\n transformOrigin = res.transformOrigin;\r\n }\r\n fitinStyle.value = {\r\n position: \"absolute\",\r\n width: `${props.designWidth}px`,\r\n height: `${props.designHeight}px`,\r\n transform: transform,\r\n transformOrigin: transformOrigin,\r\n };\r\n } else {\r\n fitinStyle.value = {\r\n width: `${event.scaleX * props.designWidth}px`,\r\n height: `${event.scaleY * props.designHeight}px`,\r\n };\r\n }\r\n}\r\n\r\nconst resizeObservable = useFitin();\r\nwatchEffect((onCleanup) => {\r\n if (resizeObservable) {\r\n const subscription = resizeObservable.subscribe(\r\n (event: IResizeEvent | undefined) => {\r\n if (event) {\r\n adjustContainer(event, props);\r\n }\r\n },\r\n );\r\n onCleanup(() => subscription.unsubscribe());\r\n }\r\n});\r\n</script>\r\n\r\n<template>\r\n <section\r\n role=\"fitin-container\"\r\n :data-scope=\"affectScope\"\r\n :style=\"[props.style, fitinStyle]\"\r\n :class=\"props.class\"\r\n >\r\n <slot />\r\n </section>\r\n</template>\r\n","import type { App, Plugin } from \"vue\";\r\nimport FitinCanvas from \"./components/fitin-canvas.vue\";\r\nimport FitinContainer from \"./components/fitin-container.vue\";\r\nexport { useFitin, useFitinState } from \"./components/hooks\";\r\n\r\nexport { FitinCanvas, FitinContainer };\r\nexport const plugin: Plugin = {\r\n install(app: App) {\r\n app.component(\"FitinCanvas\", FitinCanvas);\r\n app.component(\"FitinContainer\", FitinContainer);\r\n },\r\n};\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Mode } from "@fitin/core";
|
|
2
|
+
/**
|
|
3
|
+
* Vue SFC does not support TypeScript advanced types(e.g., Omit, Pick and Partial).
|
|
4
|
+
* However, these are exactly the types that `FitinOptions` depends on.
|
|
5
|
+
* Solution: declare the type from scratch (i.e. rewrite it explicitly without relying on utility types).
|
|
6
|
+
*/
|
|
7
|
+
type FitinCanvasProps = {
|
|
8
|
+
designWidth: number;
|
|
9
|
+
designHeight: number;
|
|
10
|
+
mode?: Mode;
|
|
11
|
+
minDesignWidth?: number;
|
|
12
|
+
minDesignHeight?: number;
|
|
13
|
+
wait?: number;
|
|
14
|
+
computeScaleXY?: (designWidth: number, designHeight: number, scaleX: number, scaleY: number) => number;
|
|
15
|
+
viewport?: HTMLElement | "parent";
|
|
16
|
+
center?: boolean;
|
|
17
|
+
};
|
|
18
|
+
declare var __VLS_1: {};
|
|
19
|
+
type __VLS_Slots = {} & {
|
|
20
|
+
default?: (props: typeof __VLS_1) => any;
|
|
21
|
+
};
|
|
22
|
+
declare const __VLS_base: import("vue").DefineComponent<FitinCanvasProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FitinCanvasProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
24
|
+
declare const _default: typeof __VLS_export;
|
|
25
|
+
export default _default;
|
|
26
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
27
|
+
new (): {
|
|
28
|
+
$slots: S;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=fitin-canvas.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fitin-canvas.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fitin-canvas.vue"],"names":[],"mappings":"AAoHA,OAAO,EAAS,KAAK,IAAI,EAAqB,MAAM,aAAa,CAAC;AAIlE;;;;GAIG;AACH,KAAK,gBAAgB,GAAG;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,CACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,KACX,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAsFF,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAO/C,QAAA,MAAM,UAAU,4SAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type CSSProperties } from "vue";
|
|
2
|
+
type FitinContainerProps = {
|
|
3
|
+
designWidth: number;
|
|
4
|
+
designHeight: number;
|
|
5
|
+
transformOriginX?: "left" | "center" | "right";
|
|
6
|
+
transformOriginY?: "top" | "center" | "bottom";
|
|
7
|
+
style?: CSSProperties;
|
|
8
|
+
class?: string;
|
|
9
|
+
};
|
|
10
|
+
declare var __VLS_1: {};
|
|
11
|
+
type __VLS_Slots = {} & {
|
|
12
|
+
default?: (props: typeof __VLS_1) => any;
|
|
13
|
+
};
|
|
14
|
+
declare const __VLS_base: import("vue").DefineComponent<FitinContainerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FitinContainerProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
18
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
19
|
+
new (): {
|
|
20
|
+
$slots: S;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=fitin-container.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fitin-container.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fitin-container.vue"],"names":[],"mappings":"AAAA,OA6FO,EAA8B,KAAK,aAAa,EAAE,MAAM,KAAK,CAAC;AAIrE,KAAK,mBAAmB,GAAG;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC/C,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC/C,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA+FF,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AAK/C,QAAA,MAAM,UAAU,kTAEd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IResizeEvent } from "@fitin/core";
|
|
2
|
+
import type { Observable } from "rxjs";
|
|
3
|
+
export declare function provideFitinContainer(value: "affect-self" | "affect-descendant"): void;
|
|
4
|
+
export declare function useFitin(resizeHandler?: (event: undefined | IResizeEvent) => void): undefined | Observable<undefined | IResizeEvent>;
|
|
5
|
+
export declare function useFitinState(): {
|
|
6
|
+
scaleX: number;
|
|
7
|
+
scaleY: number;
|
|
8
|
+
scaleXY: number;
|
|
9
|
+
effectiveWidth: undefined | number;
|
|
10
|
+
effectiveHeight: undefined | number;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/components/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,GAAG,mBAAmB,QAK3C;AAED,wBAAgB,QAAQ,CACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,KAAK,IAAI,GACxD,SAAS,GAAG,UAAU,CAAC,SAAS,GAAG,YAAY,CAAC,CAiBlD;AAED,wBAAgB,aAAa;YAEjB,MAAM;YACN,MAAM;aACL,MAAM;oBACC,SAAS,GAAG,MAAM;qBACjB,SAAS,GAAG,MAAM;EAmBtC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type InjectionKey } from "vue";
|
|
2
|
+
import type { Observable } from "rxjs";
|
|
3
|
+
import type { IResizeEvent } from "@fitin/core";
|
|
4
|
+
export declare const FitinCanvasKey: InjectionKey<Observable<IResizeEvent | undefined>>;
|
|
5
|
+
export declare const FitinContainerKey: InjectionKey<("affect-self" | "affect-descendant")[]>;
|
|
6
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../../src/components/keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,KAAK,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,cAAc,EAAE,YAAY,CACvC,UAAU,CAAC,YAAY,GAAG,SAAS,CAAC,CACZ,CAAC;AAE3B,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAC1C,CAAC,aAAa,GAAG,mBAAmB,CAAC,EAAE,CACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../src/components/logging.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AACD,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Plugin } from "vue";
|
|
2
|
+
import FitinCanvas from "./components/fitin-canvas.vue";
|
|
3
|
+
import FitinContainer from "./components/fitin-container.vue";
|
|
4
|
+
export { useFitin, useFitinState } from "./components/hooks";
|
|
5
|
+
export { FitinCanvas, FitinContainer };
|
|
6
|
+
export declare const plugin: Plugin;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,MAAM,EAAE,MAAM,KAAK,CAAC;AACvC,OAAO,WAAW,MAAM,+BAA+B,CAAC;AACxD,OAAO,cAAc,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AACvC,eAAO,MAAM,MAAM,EAAE,MAKpB,CAAC"}
|
package/index.html
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>vue</title>
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
margin: 0;
|
|
11
|
+
}
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="app"></div>
|
|
16
|
+
<script type="module" src="/src/main.ts"></script>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fitin/vue",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.umd.js",
|
|
7
|
+
"module": "./dist/index.es.js",
|
|
8
|
+
"types": "./dist/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.es.js",
|
|
12
|
+
"require": "./dist/index.umd.js",
|
|
13
|
+
"types": "./dist/types/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@fitin/core": "0.1.0",
|
|
18
|
+
"rxjs": "^7.8.2",
|
|
19
|
+
"vue": "^3.5.41"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^24.13.3",
|
|
23
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
24
|
+
"@vue/tsconfig": "^0.9.1",
|
|
25
|
+
"typescript": "~6.0.2",
|
|
26
|
+
"vite": "^8.2.2",
|
|
27
|
+
"vue-tsc": "^3.3.11"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"dev": "vite",
|
|
31
|
+
"build": "vue-tsc -b --noEmit && vite build && vue-tsc -b",
|
|
32
|
+
"preview": "vite preview"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/App.vue
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import FitinCanvas from "./components/fitin-canvas.vue";
|
|
3
|
+
import FitinContainer from "./components/fitin-container.vue";
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<FitinCanvas :design-width="920" :design-height="680">
|
|
8
|
+
<FitinContainer :design-width="200" :design-height="300">
|
|
9
|
+
<div
|
|
10
|
+
style="
|
|
11
|
+
height: 100%;
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
background: red;
|
|
15
|
+
"
|
|
16
|
+
></div>
|
|
17
|
+
</FitinContainer>
|
|
18
|
+
</FitinCanvas>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
computed,
|
|
4
|
+
inject,
|
|
5
|
+
provide,
|
|
6
|
+
ref,
|
|
7
|
+
watchEffect,
|
|
8
|
+
type CSSProperties,
|
|
9
|
+
} from "vue";
|
|
10
|
+
import { BehaviorSubject } from "rxjs";
|
|
11
|
+
import { Fitin, type Mode, type IResizeEvent } from "@fitin/core";
|
|
12
|
+
import { FitinCanvasKey } from "./keys";
|
|
13
|
+
import { logE } from "./logging";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Vue SFC does not support TypeScript advanced types(e.g., Omit, Pick and Partial).
|
|
17
|
+
* However, these are exactly the types that `FitinOptions` depends on.
|
|
18
|
+
* Solution: declare the type from scratch (i.e. rewrite it explicitly without relying on utility types).
|
|
19
|
+
*/
|
|
20
|
+
type FitinCanvasProps = {
|
|
21
|
+
designWidth: number; // physical design width of container
|
|
22
|
+
designHeight: number; // physical design height of container
|
|
23
|
+
mode?: Mode;
|
|
24
|
+
minDesignWidth?: number; // minimum physical design width of container
|
|
25
|
+
minDesignHeight?: number; // minimum physical design height of container
|
|
26
|
+
wait?: number; // in ms
|
|
27
|
+
computeScaleXY?: (
|
|
28
|
+
designWidth: number,
|
|
29
|
+
designHeight: number,
|
|
30
|
+
scaleX: number,
|
|
31
|
+
scaleY: number,
|
|
32
|
+
) => number;
|
|
33
|
+
viewport?: HTMLElement | "parent";
|
|
34
|
+
center?: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
defineOptions({
|
|
38
|
+
inheritAttrs: false,
|
|
39
|
+
});
|
|
40
|
+
const props = defineProps<FitinCanvasProps>();
|
|
41
|
+
|
|
42
|
+
const canvasRef = ref<HTMLElement>();
|
|
43
|
+
|
|
44
|
+
const canvasStyle = computed<CSSProperties>(() =>
|
|
45
|
+
props.center
|
|
46
|
+
? {
|
|
47
|
+
position: "absolute",
|
|
48
|
+
top: "50%",
|
|
49
|
+
left: "50%",
|
|
50
|
+
transform: "translate(-50%, -50%)",
|
|
51
|
+
overflow: "hidden"
|
|
52
|
+
}
|
|
53
|
+
: {
|
|
54
|
+
position: "relative",
|
|
55
|
+
overflow: "hidden"
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
let fitin: Fitin;
|
|
60
|
+
let subject = new BehaviorSubject<IResizeEvent | undefined>(undefined);
|
|
61
|
+
provide(FitinCanvasKey, subject.asObservable());
|
|
62
|
+
const resizeObservable = inject(FitinCanvasKey);
|
|
63
|
+
|
|
64
|
+
watchEffect((onCleanup) => {
|
|
65
|
+
if (resizeObservable) {
|
|
66
|
+
logE("Nested fitin-canvas is forbidden");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fitin = new Fitin(props);
|
|
71
|
+
|
|
72
|
+
const handleResize = (event: IResizeEvent) => {
|
|
73
|
+
if (event && canvasRef.value) {
|
|
74
|
+
canvasRef.value.style.width = `${event.effectiveWidth}px`;
|
|
75
|
+
canvasRef.value.style.height = `${event.effectiveHeight}px`;
|
|
76
|
+
}
|
|
77
|
+
subject.next(event);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const viewport =
|
|
81
|
+
props.viewport === "parent"
|
|
82
|
+
? canvasRef.value?.parentElement
|
|
83
|
+
: props.viewport;
|
|
84
|
+
if (viewport) {
|
|
85
|
+
fitin.subscribe(viewport, handleResize);
|
|
86
|
+
} else {
|
|
87
|
+
fitin.subscribe(handleResize);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
onCleanup(() => {
|
|
91
|
+
fitin.dispose();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<template>
|
|
97
|
+
<section
|
|
98
|
+
ref="canvasRef"
|
|
99
|
+
role="fitin-canvas"
|
|
100
|
+
:style="canvasStyle"
|
|
101
|
+
>
|
|
102
|
+
<slot />
|
|
103
|
+
</section>
|
|
104
|
+
</template>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watchEffect, computed, type CSSProperties } from "vue";
|
|
3
|
+
import type { IResizeEvent } from "@fitin/core";
|
|
4
|
+
import { provideFitinContainer, useFitin } from "./hooks";
|
|
5
|
+
|
|
6
|
+
type FitinContainerProps = {
|
|
7
|
+
designWidth: number;
|
|
8
|
+
designHeight: number;
|
|
9
|
+
transformOriginX?: "left" | "center" | "right";
|
|
10
|
+
transformOriginY?: "top" | "center" | "bottom";
|
|
11
|
+
style?: CSSProperties;
|
|
12
|
+
class?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
defineOptions({
|
|
16
|
+
inheritAttrs: false,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const props = defineProps<FitinContainerProps>();
|
|
20
|
+
|
|
21
|
+
const affectScope = computed(() =>
|
|
22
|
+
props.transformOriginX || props.transformOriginY
|
|
23
|
+
? "affect-descendant"
|
|
24
|
+
: "affect-self",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
provideFitinContainer(affectScope.value);
|
|
28
|
+
|
|
29
|
+
const fitinStyle = ref<CSSProperties>({});
|
|
30
|
+
|
|
31
|
+
function adjustContainer(event: IResizeEvent, props: FitinContainerProps) {
|
|
32
|
+
if (props.transformOriginX || props.transformOriginY) {
|
|
33
|
+
let transform: string;
|
|
34
|
+
let transformOrigin: string;
|
|
35
|
+
if (props.transformOriginX && props.transformOriginY) {
|
|
36
|
+
const res = event.transformXY(
|
|
37
|
+
props.transformOriginX,
|
|
38
|
+
props.transformOriginY,
|
|
39
|
+
);
|
|
40
|
+
transform = res.transform;
|
|
41
|
+
transformOrigin = res.transformOrigin;
|
|
42
|
+
} else if (props.transformOriginX) {
|
|
43
|
+
const res = event.transformX(props.transformOriginX);
|
|
44
|
+
transform = res.transform;
|
|
45
|
+
transformOrigin = res.transformOrigin;
|
|
46
|
+
} else {
|
|
47
|
+
const res = event.transformY(props.transformOriginY!);
|
|
48
|
+
transform = res.transform;
|
|
49
|
+
transformOrigin = res.transformOrigin;
|
|
50
|
+
}
|
|
51
|
+
fitinStyle.value = {
|
|
52
|
+
position: "absolute",
|
|
53
|
+
width: `${props.designWidth}px`,
|
|
54
|
+
height: `${props.designHeight}px`,
|
|
55
|
+
transform: transform,
|
|
56
|
+
transformOrigin: transformOrigin,
|
|
57
|
+
};
|
|
58
|
+
} else {
|
|
59
|
+
fitinStyle.value = {
|
|
60
|
+
width: `${event.scaleX * props.designWidth}px`,
|
|
61
|
+
height: `${event.scaleY * props.designHeight}px`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const resizeObservable = useFitin();
|
|
67
|
+
watchEffect((onCleanup) => {
|
|
68
|
+
if (resizeObservable) {
|
|
69
|
+
const subscription = resizeObservable.subscribe(
|
|
70
|
+
(event: IResizeEvent | undefined) => {
|
|
71
|
+
if (event) {
|
|
72
|
+
adjustContainer(event, props);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
onCleanup(() => subscription.unsubscribe());
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<template>
|
|
82
|
+
<section
|
|
83
|
+
role="fitin-container"
|
|
84
|
+
:data-scope="affectScope"
|
|
85
|
+
:style="[props.style, fitinStyle]"
|
|
86
|
+
:class="props.class"
|
|
87
|
+
>
|
|
88
|
+
<slot />
|
|
89
|
+
</section>
|
|
90
|
+
</template>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { inject, provide, reactive, watchEffect } from "vue";
|
|
2
|
+
import type { IResizeEvent } from "@fitin/core";
|
|
3
|
+
import { FitinCanvasKey, FitinContainerKey } from "./keys";
|
|
4
|
+
import { logE, logW } from "./logging";
|
|
5
|
+
import type { Observable } from "rxjs";
|
|
6
|
+
|
|
7
|
+
export function provideFitinContainer(
|
|
8
|
+
value: "affect-self" | "affect-descendant",
|
|
9
|
+
) {
|
|
10
|
+
const paths = inject(FitinContainerKey) || [];
|
|
11
|
+
paths.push(value);
|
|
12
|
+
provide(FitinContainerKey, paths);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function useFitin(
|
|
16
|
+
resizeHandler?: (event: undefined | IResizeEvent) => void,
|
|
17
|
+
): undefined | Observable<undefined | IResizeEvent> {
|
|
18
|
+
const resizeObservable = inject(FitinCanvasKey);
|
|
19
|
+
if (resizeObservable) {
|
|
20
|
+
const paths = inject(FitinContainerKey) || [];
|
|
21
|
+
if (paths.find((path) => path === "affect-descendant")) {
|
|
22
|
+
logW("There's an ancestor fitin-container resizing all descendants");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
watchEffect((onCleanup) => {
|
|
26
|
+
const subscription = resizeObservable.subscribe(resizeHandler);
|
|
27
|
+
onCleanup(() => subscription.unsubscribe());
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
logE("A fitin-container must be used within a fitin-canvas context");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return resizeObservable;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function useFitinState() {
|
|
37
|
+
const state = reactive<{
|
|
38
|
+
scaleX: number;
|
|
39
|
+
scaleY: number;
|
|
40
|
+
scaleXY: number;
|
|
41
|
+
effectiveWidth: undefined | number;
|
|
42
|
+
effectiveHeight: undefined | number;
|
|
43
|
+
}>({
|
|
44
|
+
scaleX: 1,
|
|
45
|
+
scaleY: 1,
|
|
46
|
+
scaleXY: 1,
|
|
47
|
+
effectiveWidth: undefined,
|
|
48
|
+
effectiveHeight: undefined,
|
|
49
|
+
});
|
|
50
|
+
useFitin((event) => {
|
|
51
|
+
if (event) {
|
|
52
|
+
state.scaleX = event.scaleX;
|
|
53
|
+
state.scaleY = event.scaleY;
|
|
54
|
+
state.scaleXY = event.scaleXY;
|
|
55
|
+
state.effectiveWidth = event.effectiveWidth;
|
|
56
|
+
state.effectiveHeight = event.effectiveHeight;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return state;
|
|
61
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type InjectionKey } from "vue";
|
|
2
|
+
import type { Observable } from "rxjs";
|
|
3
|
+
import type { IResizeEvent } from "@fitin/core";
|
|
4
|
+
|
|
5
|
+
export const FitinCanvasKey: InjectionKey<
|
|
6
|
+
Observable<IResizeEvent | undefined>
|
|
7
|
+
> = Symbol("fitin-canvas");
|
|
8
|
+
|
|
9
|
+
export const FitinContainerKey: InjectionKey<
|
|
10
|
+
("affect-self" | "affect-descendant")[]
|
|
11
|
+
> = Symbol("fitin-container");
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { App, Plugin } from "vue";
|
|
2
|
+
import FitinCanvas from "./components/fitin-canvas.vue";
|
|
3
|
+
import FitinContainer from "./components/fitin-container.vue";
|
|
4
|
+
export { useFitin, useFitinState } from "./components/hooks";
|
|
5
|
+
|
|
6
|
+
export { FitinCanvas, FitinContainer };
|
|
7
|
+
export const plugin: Plugin = {
|
|
8
|
+
install(app: App) {
|
|
9
|
+
app.component("FitinCanvas", FitinCanvas);
|
|
10
|
+
app.component("FitinContainer", FitinContainer);
|
|
11
|
+
},
|
|
12
|
+
};
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
5
|
+
"types": ["vite/client"],
|
|
6
|
+
"allowArbitraryExtensions": true,
|
|
7
|
+
|
|
8
|
+
/* Linting */
|
|
9
|
+
"noUnusedLocals": true,
|
|
10
|
+
"noUnusedParameters": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"erasableSyntaxOnly": true,
|
|
13
|
+
|
|
14
|
+
/* Bundler */
|
|
15
|
+
"noEmit": false,
|
|
16
|
+
"declaration": true,
|
|
17
|
+
"declarationMap": true,
|
|
18
|
+
"emitDeclarationOnly": true,
|
|
19
|
+
"outDir": "dist/types",
|
|
20
|
+
"rootDir": "src"
|
|
21
|
+
},
|
|
22
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
|
23
|
+
"exclude": [
|
|
24
|
+
"**/*.test.ts",
|
|
25
|
+
"**/*.spec.ts",
|
|
26
|
+
"**/__tests__/**",
|
|
27
|
+
"src/main.ts",
|
|
28
|
+
"src/App.vue"
|
|
29
|
+
]
|
|
30
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "es2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
|
|
16
|
+
/* Linting */
|
|
17
|
+
"noUnusedLocals": true,
|
|
18
|
+
"noUnusedParameters": true,
|
|
19
|
+
"erasableSyntaxOnly": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true
|
|
21
|
+
},
|
|
22
|
+
"include": ["vite.config.ts"]
|
|
23
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import vue from "@vitejs/plugin-vue";
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [vue()],
|
|
6
|
+
build: {
|
|
7
|
+
sourcemap: true,
|
|
8
|
+
lib: {
|
|
9
|
+
entry: "src/index.ts",
|
|
10
|
+
name: "Fitin",
|
|
11
|
+
fileName: (format) => `index.${format}.js`,
|
|
12
|
+
formats: ["es", "umd"],
|
|
13
|
+
},
|
|
14
|
+
rolldownOptions: {
|
|
15
|
+
external: ["vue", "rxjs", "@fitin/core"],
|
|
16
|
+
output: {
|
|
17
|
+
format: "umd",
|
|
18
|
+
globals: {
|
|
19
|
+
vue: "Vue",
|
|
20
|
+
rxjs: "rxjs",
|
|
21
|
+
"@fitin/core": "FitinCore",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|