@teriusu/rich-editor 0.9.8 → 0.9.10
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/extensions/PdfBlock.d.ts.map +1 -1
- package/dist/extensions/PdfBlock.js +288 -226
- package/dist/extensions/PdfBlock.test.js +258 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/styles/editor.css +1 -1
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/resize.d.ts.map +1 -1
- package/dist/utils/resize.js +18 -1
- package/package.json +1 -1
- package/dist/components/PdfViewer.svelte +0 -160
- package/dist/components/PdfViewer.svelte.d.ts +0 -9
- package/dist/components/PdfViewer.svelte.d.ts.map +0 -1
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { onMount } from "svelte";
|
|
3
|
-
import { ChevronLeft, ChevronRight } from "lucide-svelte";
|
|
4
|
-
import { getPdfJs } from "../utils/pdf";
|
|
5
|
-
|
|
6
|
-
let {
|
|
7
|
-
src,
|
|
8
|
-
fileName,
|
|
9
|
-
label
|
|
10
|
-
}: { src: string; fileName?: string; label?: string } = $props();
|
|
11
|
-
|
|
12
|
-
const cleanName = (raw?: string) =>
|
|
13
|
-
(raw || "").replace(/[?#].*$/, "").trim() || "PDF 문서";
|
|
14
|
-
|
|
15
|
-
/** `label` 이 있으면 그것, 없으면 파일명. */
|
|
16
|
-
const displayName = $derived(label?.trim() || cleanName(fileName));
|
|
17
|
-
|
|
18
|
-
let canvasEl: HTMLCanvasElement | undefined = $state();
|
|
19
|
-
let containerEl: HTMLDivElement | undefined = $state();
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
-
let pdf: any = $state(null);
|
|
22
|
-
let page = $state(1);
|
|
23
|
-
let total = $state(0);
|
|
24
|
-
let loading = $state(true);
|
|
25
|
-
let error = $state(false);
|
|
26
|
-
let rendering = false;
|
|
27
|
-
|
|
28
|
-
async function renderPage() {
|
|
29
|
-
if (!pdf || !canvasEl || !containerEl || rendering) return;
|
|
30
|
-
rendering = true;
|
|
31
|
-
try {
|
|
32
|
-
const pageObj = await pdf.getPage(page);
|
|
33
|
-
const unscaledViewport = pageObj.getViewport({ scale: 1 });
|
|
34
|
-
const availableWidth = containerEl.clientWidth;
|
|
35
|
-
if (availableWidth <= 0) return;
|
|
36
|
-
const scale = availableWidth / unscaledViewport.width;
|
|
37
|
-
const viewport = pageObj.getViewport({ scale });
|
|
38
|
-
const dpr = window.devicePixelRatio || 1;
|
|
39
|
-
canvasEl.width = viewport.width * dpr;
|
|
40
|
-
canvasEl.height = viewport.height * dpr;
|
|
41
|
-
canvasEl.style.width = `${viewport.width}px`;
|
|
42
|
-
canvasEl.style.height = `${viewport.height}px`;
|
|
43
|
-
const ctx = canvasEl.getContext("2d");
|
|
44
|
-
if (!ctx) return;
|
|
45
|
-
ctx.resetTransform();
|
|
46
|
-
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
|
|
47
|
-
ctx.scale(dpr, dpr);
|
|
48
|
-
await pageObj.render({ canvasContext: ctx, viewport }).promise;
|
|
49
|
-
} finally {
|
|
50
|
-
rendering = false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
$effect(() => {
|
|
55
|
-
if (pdf && page) renderPage();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
onMount(() => {
|
|
59
|
-
let cancelled = false;
|
|
60
|
-
|
|
61
|
-
(async () => {
|
|
62
|
-
try {
|
|
63
|
-
loading = true;
|
|
64
|
-
error = false;
|
|
65
|
-
const pdfjsLib = await getPdfJs();
|
|
66
|
-
const loadingTask = pdfjsLib.getDocument(src);
|
|
67
|
-
const pdfDoc = await loadingTask.promise;
|
|
68
|
-
if (!cancelled) {
|
|
69
|
-
pdf = pdfDoc;
|
|
70
|
-
total = pdfDoc.numPages;
|
|
71
|
-
loading = false;
|
|
72
|
-
}
|
|
73
|
-
} catch (e) {
|
|
74
|
-
console.error("[PdfViewer] PDF 로드 실패:", src, e);
|
|
75
|
-
if (!cancelled) {
|
|
76
|
-
error = true;
|
|
77
|
-
loading = false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
})();
|
|
81
|
-
|
|
82
|
-
// ResizeObserver
|
|
83
|
-
let timeout: ReturnType<typeof setTimeout>;
|
|
84
|
-
const observer = new ResizeObserver(() => {
|
|
85
|
-
clearTimeout(timeout);
|
|
86
|
-
timeout = setTimeout(renderPage, 100);
|
|
87
|
-
});
|
|
88
|
-
if (containerEl) observer.observe(containerEl);
|
|
89
|
-
|
|
90
|
-
return () => {
|
|
91
|
-
cancelled = true;
|
|
92
|
-
observer.disconnect();
|
|
93
|
-
clearTimeout(timeout);
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
</script>
|
|
97
|
-
|
|
98
|
-
{#if error}
|
|
99
|
-
<div class="border border-border rounded-lg p-4 text-center">
|
|
100
|
-
<p class="text-sm text-muted-foreground">PDF를 불러올 수 없습니다.</p>
|
|
101
|
-
<a
|
|
102
|
-
href={src}
|
|
103
|
-
target="_blank"
|
|
104
|
-
rel="noopener noreferrer"
|
|
105
|
-
class="text-sm text-primary hover:underline"
|
|
106
|
-
>
|
|
107
|
-
직접 다운로드
|
|
108
|
-
</a>
|
|
109
|
-
</div>
|
|
110
|
-
{:else if loading}
|
|
111
|
-
<div class="border border-border rounded-lg p-8 text-center">
|
|
112
|
-
<p class="text-sm text-muted-foreground animate-pulse">PDF 로딩 중...</p>
|
|
113
|
-
</div>
|
|
114
|
-
{:else}
|
|
115
|
-
<div class="border border-border rounded-lg overflow-hidden my-2">
|
|
116
|
-
<div class="flex items-center gap-2 px-3 py-1 border-b border-border bg-muted">
|
|
117
|
-
<span class="text-xs text-muted-foreground truncate min-w-0">
|
|
118
|
-
{displayName}
|
|
119
|
-
</span>
|
|
120
|
-
<span class="text-xs text-muted-foreground tabular-nums ml-auto shrink-0">
|
|
121
|
-
{page} / {total}
|
|
122
|
-
</span>
|
|
123
|
-
</div>
|
|
124
|
-
|
|
125
|
-
<div
|
|
126
|
-
bind:this={containerEl}
|
|
127
|
-
class="flex items-center justify-center"
|
|
128
|
-
>
|
|
129
|
-
<canvas bind:this={canvasEl} class="shadow-sm"></canvas>
|
|
130
|
-
</div>
|
|
131
|
-
|
|
132
|
-
{#if total > 1}
|
|
133
|
-
<div
|
|
134
|
-
class="flex items-center justify-center gap-4 px-3 py-1 border-t border-border bg-muted"
|
|
135
|
-
>
|
|
136
|
-
<button
|
|
137
|
-
type="button"
|
|
138
|
-
onclick={() => (page = Math.max(1, page - 1))}
|
|
139
|
-
disabled={page <= 1}
|
|
140
|
-
class="p-1.5 rounded hover:bg-muted transition-colors disabled:opacity-30"
|
|
141
|
-
title="이전 페이지"
|
|
142
|
-
>
|
|
143
|
-
<ChevronLeft class="w-4 h-4" />
|
|
144
|
-
</button>
|
|
145
|
-
<span class="text-sm tabular-nums">
|
|
146
|
-
{page} / {total}
|
|
147
|
-
</span>
|
|
148
|
-
<button
|
|
149
|
-
type="button"
|
|
150
|
-
onclick={() => (page = Math.min(total, page + 1))}
|
|
151
|
-
disabled={page >= total}
|
|
152
|
-
class="p-1.5 rounded hover:bg-muted transition-colors disabled:opacity-30"
|
|
153
|
-
title="다음 페이지"
|
|
154
|
-
>
|
|
155
|
-
<ChevronRight class="w-4 h-4" />
|
|
156
|
-
</button>
|
|
157
|
-
</div>
|
|
158
|
-
{/if}
|
|
159
|
-
</div>
|
|
160
|
-
{/if}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
type $$ComponentProps = {
|
|
2
|
-
src: string;
|
|
3
|
-
fileName?: string;
|
|
4
|
-
label?: string;
|
|
5
|
-
};
|
|
6
|
-
declare const PdfViewer: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
-
type PdfViewer = ReturnType<typeof PdfViewer>;
|
|
8
|
-
export default PdfViewer;
|
|
9
|
-
//# sourceMappingURL=PdfViewer.svelte.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PdfViewer.svelte.d.ts","sourceRoot":"","sources":["../../src/components/PdfViewer.svelte.ts"],"names":[],"mappings":"AAOC,KAAK,gBAAgB,GAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AA8I7E,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|