@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.
@@ -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"}