chaeditor 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.
Files changed (40) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.ko.md +250 -0
  3. package/README.md +242 -0
  4. package/dist/core.cjs +1034 -0
  5. package/dist/core.d.mts +347 -0
  6. package/dist/core.d.ts +347 -0
  7. package/dist/core.mjs +988 -0
  8. package/dist/default-host.cjs +243 -0
  9. package/dist/default-host.d.mts +52 -0
  10. package/dist/default-host.d.ts +52 -0
  11. package/dist/default-host.mjs +239 -0
  12. package/dist/default-markdown-primitive-registry-B3PGEkqs.d.mts +12 -0
  13. package/dist/default-markdown-primitive-registry-CqzwhHj2.d.ts +12 -0
  14. package/dist/image-upload-kind-BJqItE_C.d.mts +18 -0
  15. package/dist/image-upload-kind-BJqItE_C.d.ts +18 -0
  16. package/dist/index.cjs +8736 -0
  17. package/dist/index.d.mts +7 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.mjs +8668 -0
  20. package/dist/markdown-editor-B1qvE40Z.d.mts +460 -0
  21. package/dist/markdown-editor-Ce6DpnQk.d.ts +460 -0
  22. package/dist/markdown-primitive-contract-BXsqbKwY.d.mts +124 -0
  23. package/dist/markdown-primitive-contract-BXsqbKwY.d.ts +124 -0
  24. package/dist/panda-primitives.cjs +1299 -0
  25. package/dist/panda-primitives.d.mts +21127 -0
  26. package/dist/panda-primitives.d.ts +21127 -0
  27. package/dist/panda-primitives.mjs +1285 -0
  28. package/dist/react.cjs +8558 -0
  29. package/dist/react.d.mts +35 -0
  30. package/dist/react.d.ts +35 -0
  31. package/dist/react.mjs +8531 -0
  32. package/dist/toolbar-preset-B9ttTEol.d.ts +236 -0
  33. package/dist/toolbar-preset-DIsQN390.d.mts +236 -0
  34. package/package.json +151 -0
  35. package/recipes/host-presets/README.md +16 -0
  36. package/recipes/host-presets/emotion-host-preset.tsx.template +109 -0
  37. package/recipes/host-presets/styled-components-host-preset.tsx.template +102 -0
  38. package/recipes/host-presets/tailwind-host-preset.tsx.template +116 -0
  39. package/recipes/host-presets/vanilla-extract-host-preset.tsx.template +116 -0
  40. package/styled-system/styles.css +3370 -0
@@ -0,0 +1,243 @@
1
+ 'use strict';
2
+
3
+ // src/integrations/default-host/api/upload-editor-file.ts
4
+ var uploadEditorFile = async ({
5
+ contentType,
6
+ file
7
+ }) => {
8
+ const formData = new FormData();
9
+ formData.set("contentType", contentType);
10
+ formData.set("file", file);
11
+ const response = await fetch("/api/attachments", {
12
+ body: formData,
13
+ method: "POST"
14
+ });
15
+ let body = {};
16
+ try {
17
+ body = await response.json();
18
+ } catch {
19
+ body = {
20
+ error: response.ok ? "Attachment response parse failed" : "Attachment upload failed",
21
+ message: response.statusText || void 0
22
+ };
23
+ }
24
+ if (!response.ok || !body.url || !body.fileName || typeof body.fileSize !== "number" || !body.contentType) {
25
+ throw new Error(body.error ?? body.message ?? "Attachment upload failed");
26
+ }
27
+ return {
28
+ contentType: body.contentType,
29
+ fileName: body.fileName,
30
+ fileSize: body.fileSize,
31
+ url: body.url
32
+ };
33
+ };
34
+
35
+ // src/shared/lib/image/optimize-image-file.ts
36
+ var OUTPUT_TYPE = "image/webp";
37
+ var OPTIMIZABLE_IMAGE_TYPES = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/webp"]);
38
+ var resolveImageOptimizationDimensions = ({
39
+ height,
40
+ maxHeight,
41
+ maxWidth,
42
+ width
43
+ }) => {
44
+ const scale = Math.min(1, maxWidth / width, maxHeight / height);
45
+ return {
46
+ height: Math.max(1, Math.round(height * scale)),
47
+ width: Math.max(1, Math.round(width * scale))
48
+ };
49
+ };
50
+ var resolveOptimizedImageFileName = (fileName) => fileName.replace(/\.[^./]+$/, "") + ".webp";
51
+ var loadImageElement = (file, errorLabel) => new Promise((resolve, reject) => {
52
+ const objectUrl = URL.createObjectURL(file);
53
+ const image = new Image();
54
+ image.onload = () => {
55
+ URL.revokeObjectURL(objectUrl);
56
+ resolve(image);
57
+ };
58
+ image.onerror = () => {
59
+ URL.revokeObjectURL(objectUrl);
60
+ reject(new Error(`[${errorLabel}] Failed to decode the image.`));
61
+ };
62
+ image.src = objectUrl;
63
+ });
64
+ var convertCanvasToBlob = ({
65
+ canvas,
66
+ errorLabel,
67
+ outputQuality
68
+ }) => new Promise((resolve, reject) => {
69
+ canvas.toBlob(
70
+ (blob) => {
71
+ if (!blob) {
72
+ reject(new Error(`[${errorLabel}] Failed to convert the canvas to a blob.`));
73
+ return;
74
+ }
75
+ resolve(blob);
76
+ },
77
+ OUTPUT_TYPE,
78
+ outputQuality
79
+ );
80
+ });
81
+ var optimizeImageFile = async ({
82
+ errorLabel,
83
+ file,
84
+ maxHeight,
85
+ maxWidth,
86
+ outputQuality
87
+ }) => {
88
+ if (!OPTIMIZABLE_IMAGE_TYPES.has(file.type)) {
89
+ return file;
90
+ }
91
+ const image = await loadImageElement(file, errorLabel);
92
+ const { height, width } = resolveImageOptimizationDimensions({
93
+ height: image.naturalHeight,
94
+ maxHeight,
95
+ maxWidth,
96
+ width: image.naturalWidth
97
+ });
98
+ const canvas = document.createElement("canvas");
99
+ const context = canvas.getContext("2d");
100
+ if (!context) {
101
+ throw new Error(`[${errorLabel}] Failed to create a canvas context.`);
102
+ }
103
+ canvas.width = width;
104
+ canvas.height = height;
105
+ context.drawImage(image, 0, 0, width, height);
106
+ const optimizedBlob = await convertCanvasToBlob({
107
+ canvas,
108
+ errorLabel,
109
+ outputQuality
110
+ });
111
+ if (optimizedBlob.size >= file.size) {
112
+ return file;
113
+ }
114
+ return new File([optimizedBlob], resolveOptimizedImageFileName(file.name), {
115
+ lastModified: file.lastModified,
116
+ type: OUTPUT_TYPE
117
+ });
118
+ };
119
+
120
+ // src/shared/lib/image/optimize-content-image-file.ts
121
+ var CONTENT_MAX_WIDTH = 1600;
122
+ var CONTENT_MAX_HEIGHT = 1600;
123
+ var CONTENT_OUTPUT_QUALITY = 0.84;
124
+ var optimizeContentImageFile = (file) => optimizeImageFile({
125
+ errorLabel: "content-image-optimization",
126
+ file,
127
+ maxHeight: CONTENT_MAX_HEIGHT,
128
+ maxWidth: CONTENT_MAX_WIDTH,
129
+ outputQuality: CONTENT_OUTPUT_QUALITY
130
+ });
131
+
132
+ // src/shared/lib/image/optimize-thumbnail-image-file.ts
133
+ var THUMBNAIL_MAX_WIDTH = 800;
134
+ var THUMBNAIL_MAX_HEIGHT = 800;
135
+ var THUMBNAIL_OUTPUT_QUALITY = 0.82;
136
+ var optimizeThumbnailImageFile = (file) => optimizeImageFile({
137
+ errorLabel: "thumbnail-optimization",
138
+ file,
139
+ maxHeight: THUMBNAIL_MAX_HEIGHT,
140
+ maxWidth: THUMBNAIL_MAX_WIDTH,
141
+ outputQuality: THUMBNAIL_OUTPUT_QUALITY
142
+ });
143
+
144
+ // src/integrations/default-host/api/upload-editor-image.ts
145
+ var uploadEditorImage = async ({
146
+ contentType,
147
+ file,
148
+ imageKind
149
+ }) => {
150
+ const optimizedFile = imageKind === "thumbnail" ? await optimizeThumbnailImageFile(file) : await optimizeContentImageFile(file);
151
+ const formData = new FormData();
152
+ formData.set("contentType", contentType);
153
+ formData.set("file", optimizedFile);
154
+ formData.set("imageKind", imageKind);
155
+ const response = await fetch("/api/images", {
156
+ body: formData,
157
+ method: "POST"
158
+ });
159
+ let body = {};
160
+ try {
161
+ body = await response.json();
162
+ } catch {
163
+ body = {
164
+ error: response.ok ? "Image response parse failed" : "Image upload failed",
165
+ message: response.statusText || void 0
166
+ };
167
+ }
168
+ if (!response.ok || !body.url) {
169
+ throw new Error(body.error ?? body.message ?? "Image upload failed");
170
+ }
171
+ return body.url;
172
+ };
173
+
174
+ // src/integrations/default-host/api/upload-editor-video.ts
175
+ var createAbortUploadError = () => {
176
+ const error = new Error("Video upload aborted");
177
+ error.name = "AbortError";
178
+ return error;
179
+ };
180
+ var parseUploadResponse = (responseText) => {
181
+ try {
182
+ return JSON.parse(responseText);
183
+ } catch {
184
+ return {};
185
+ }
186
+ };
187
+ var uploadEditorVideo = async ({
188
+ contentType,
189
+ file,
190
+ onProgress,
191
+ signal
192
+ }) => {
193
+ const formData = new FormData();
194
+ formData.set("contentType", contentType);
195
+ formData.set("file", file);
196
+ return await new Promise((resolve, reject) => {
197
+ const xhr = new XMLHttpRequest();
198
+ const cleanup = () => {
199
+ xhr.upload.onprogress = null;
200
+ xhr.onload = null;
201
+ xhr.onerror = null;
202
+ xhr.onabort = null;
203
+ signal?.removeEventListener("abort", handleAbortSignal);
204
+ };
205
+ const handleAbortSignal = () => {
206
+ xhr.abort();
207
+ };
208
+ xhr.open("POST", "/api/videos");
209
+ xhr.upload.onprogress = (event) => {
210
+ if (!event.lengthComputable) return;
211
+ onProgress?.(Math.min(100, Math.round(event.loaded / event.total * 100)));
212
+ };
213
+ xhr.onload = () => {
214
+ cleanup();
215
+ const body = parseUploadResponse(xhr.responseText);
216
+ if (xhr.status < 200 || xhr.status >= 300 || !body.url) {
217
+ reject(new Error(body.error ?? body.message ?? "Video upload failed"));
218
+ return;
219
+ }
220
+ resolve(body.url);
221
+ };
222
+ xhr.onerror = () => {
223
+ cleanup();
224
+ reject(new Error("Video upload failed"));
225
+ };
226
+ xhr.onabort = () => {
227
+ cleanup();
228
+ reject(createAbortUploadError());
229
+ };
230
+ if (signal) {
231
+ if (signal.aborted) {
232
+ xhr.abort();
233
+ return;
234
+ }
235
+ signal.addEventListener("abort", handleAbortSignal, { once: true });
236
+ }
237
+ xhr.send(formData);
238
+ });
239
+ };
240
+
241
+ exports.uploadEditorFile = uploadEditorFile;
242
+ exports.uploadEditorImage = uploadEditorImage;
243
+ exports.uploadEditorVideo = uploadEditorVideo;
@@ -0,0 +1,52 @@
1
+ import { a as EditorContentType, E as EditorAttachment, b as EditorImageUploadKind } from './image-upload-kind-BJqItE_C.mjs';
2
+
3
+ /**
4
+ * Uploads an attachment through the default host HTTP endpoint.
5
+ *
6
+ * @param options Attachment upload options.
7
+ * @param options.contentType Logical content type that scopes the upload target.
8
+ * @param options.file File selected by the user.
9
+ * @returns Uploaded attachment metadata normalized for editor insertion.
10
+ * @throws When the upload fails or the response payload is invalid.
11
+ */
12
+ declare const uploadEditorFile: ({ contentType, file, }: {
13
+ contentType: EditorContentType;
14
+ file: File;
15
+ }) => Promise<EditorAttachment>;
16
+
17
+ /**
18
+ * Uploads an editor image through the default host HTTP endpoint.
19
+ *
20
+ * @param options Image upload options.
21
+ * @param options.contentType Logical content type that scopes the upload target.
22
+ * @param options.file Original file selected by the user.
23
+ * @param options.imageKind Upload intent used to choose the image optimization path.
24
+ * @returns The final public image URL returned by the host.
25
+ * @throws When the response is not successful or does not include a public URL.
26
+ */
27
+ declare const uploadEditorImage: ({ contentType, file, imageKind, }: {
28
+ contentType: EditorContentType;
29
+ file: File;
30
+ imageKind: EditorImageUploadKind;
31
+ }) => Promise<string>;
32
+
33
+ type UploadEditorVideoOptions = {
34
+ contentType: EditorContentType;
35
+ file: File;
36
+ onProgress?: (percentage: number) => void;
37
+ signal?: AbortSignal;
38
+ };
39
+ /**
40
+ * Uploads a video through the default host HTTP endpoint and reports progress through XHR.
41
+ *
42
+ * @param options Video upload options.
43
+ * @param options.contentType Logical content type that scopes the upload target.
44
+ * @param options.file Video file selected by the user.
45
+ * @param options.onProgress Optional upload progress callback that receives a 0-100 percentage.
46
+ * @param options.signal Optional abort signal forwarded to the underlying XHR request.
47
+ * @returns The uploaded public video URL.
48
+ * @throws When the upload fails or does not return a URL.
49
+ */
50
+ declare const uploadEditorVideo: ({ contentType, file, onProgress, signal, }: UploadEditorVideoOptions) => Promise<string>;
51
+
52
+ export { uploadEditorFile, uploadEditorImage, uploadEditorVideo };
@@ -0,0 +1,52 @@
1
+ import { a as EditorContentType, E as EditorAttachment, b as EditorImageUploadKind } from './image-upload-kind-BJqItE_C.js';
2
+
3
+ /**
4
+ * Uploads an attachment through the default host HTTP endpoint.
5
+ *
6
+ * @param options Attachment upload options.
7
+ * @param options.contentType Logical content type that scopes the upload target.
8
+ * @param options.file File selected by the user.
9
+ * @returns Uploaded attachment metadata normalized for editor insertion.
10
+ * @throws When the upload fails or the response payload is invalid.
11
+ */
12
+ declare const uploadEditorFile: ({ contentType, file, }: {
13
+ contentType: EditorContentType;
14
+ file: File;
15
+ }) => Promise<EditorAttachment>;
16
+
17
+ /**
18
+ * Uploads an editor image through the default host HTTP endpoint.
19
+ *
20
+ * @param options Image upload options.
21
+ * @param options.contentType Logical content type that scopes the upload target.
22
+ * @param options.file Original file selected by the user.
23
+ * @param options.imageKind Upload intent used to choose the image optimization path.
24
+ * @returns The final public image URL returned by the host.
25
+ * @throws When the response is not successful or does not include a public URL.
26
+ */
27
+ declare const uploadEditorImage: ({ contentType, file, imageKind, }: {
28
+ contentType: EditorContentType;
29
+ file: File;
30
+ imageKind: EditorImageUploadKind;
31
+ }) => Promise<string>;
32
+
33
+ type UploadEditorVideoOptions = {
34
+ contentType: EditorContentType;
35
+ file: File;
36
+ onProgress?: (percentage: number) => void;
37
+ signal?: AbortSignal;
38
+ };
39
+ /**
40
+ * Uploads a video through the default host HTTP endpoint and reports progress through XHR.
41
+ *
42
+ * @param options Video upload options.
43
+ * @param options.contentType Logical content type that scopes the upload target.
44
+ * @param options.file Video file selected by the user.
45
+ * @param options.onProgress Optional upload progress callback that receives a 0-100 percentage.
46
+ * @param options.signal Optional abort signal forwarded to the underlying XHR request.
47
+ * @returns The uploaded public video URL.
48
+ * @throws When the upload fails or does not return a URL.
49
+ */
50
+ declare const uploadEditorVideo: ({ contentType, file, onProgress, signal, }: UploadEditorVideoOptions) => Promise<string>;
51
+
52
+ export { uploadEditorFile, uploadEditorImage, uploadEditorVideo };
@@ -0,0 +1,239 @@
1
+ // src/integrations/default-host/api/upload-editor-file.ts
2
+ var uploadEditorFile = async ({
3
+ contentType,
4
+ file
5
+ }) => {
6
+ const formData = new FormData();
7
+ formData.set("contentType", contentType);
8
+ formData.set("file", file);
9
+ const response = await fetch("/api/attachments", {
10
+ body: formData,
11
+ method: "POST"
12
+ });
13
+ let body = {};
14
+ try {
15
+ body = await response.json();
16
+ } catch {
17
+ body = {
18
+ error: response.ok ? "Attachment response parse failed" : "Attachment upload failed",
19
+ message: response.statusText || void 0
20
+ };
21
+ }
22
+ if (!response.ok || !body.url || !body.fileName || typeof body.fileSize !== "number" || !body.contentType) {
23
+ throw new Error(body.error ?? body.message ?? "Attachment upload failed");
24
+ }
25
+ return {
26
+ contentType: body.contentType,
27
+ fileName: body.fileName,
28
+ fileSize: body.fileSize,
29
+ url: body.url
30
+ };
31
+ };
32
+
33
+ // src/shared/lib/image/optimize-image-file.ts
34
+ var OUTPUT_TYPE = "image/webp";
35
+ var OPTIMIZABLE_IMAGE_TYPES = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/webp"]);
36
+ var resolveImageOptimizationDimensions = ({
37
+ height,
38
+ maxHeight,
39
+ maxWidth,
40
+ width
41
+ }) => {
42
+ const scale = Math.min(1, maxWidth / width, maxHeight / height);
43
+ return {
44
+ height: Math.max(1, Math.round(height * scale)),
45
+ width: Math.max(1, Math.round(width * scale))
46
+ };
47
+ };
48
+ var resolveOptimizedImageFileName = (fileName) => fileName.replace(/\.[^./]+$/, "") + ".webp";
49
+ var loadImageElement = (file, errorLabel) => new Promise((resolve, reject) => {
50
+ const objectUrl = URL.createObjectURL(file);
51
+ const image = new Image();
52
+ image.onload = () => {
53
+ URL.revokeObjectURL(objectUrl);
54
+ resolve(image);
55
+ };
56
+ image.onerror = () => {
57
+ URL.revokeObjectURL(objectUrl);
58
+ reject(new Error(`[${errorLabel}] Failed to decode the image.`));
59
+ };
60
+ image.src = objectUrl;
61
+ });
62
+ var convertCanvasToBlob = ({
63
+ canvas,
64
+ errorLabel,
65
+ outputQuality
66
+ }) => new Promise((resolve, reject) => {
67
+ canvas.toBlob(
68
+ (blob) => {
69
+ if (!blob) {
70
+ reject(new Error(`[${errorLabel}] Failed to convert the canvas to a blob.`));
71
+ return;
72
+ }
73
+ resolve(blob);
74
+ },
75
+ OUTPUT_TYPE,
76
+ outputQuality
77
+ );
78
+ });
79
+ var optimizeImageFile = async ({
80
+ errorLabel,
81
+ file,
82
+ maxHeight,
83
+ maxWidth,
84
+ outputQuality
85
+ }) => {
86
+ if (!OPTIMIZABLE_IMAGE_TYPES.has(file.type)) {
87
+ return file;
88
+ }
89
+ const image = await loadImageElement(file, errorLabel);
90
+ const { height, width } = resolveImageOptimizationDimensions({
91
+ height: image.naturalHeight,
92
+ maxHeight,
93
+ maxWidth,
94
+ width: image.naturalWidth
95
+ });
96
+ const canvas = document.createElement("canvas");
97
+ const context = canvas.getContext("2d");
98
+ if (!context) {
99
+ throw new Error(`[${errorLabel}] Failed to create a canvas context.`);
100
+ }
101
+ canvas.width = width;
102
+ canvas.height = height;
103
+ context.drawImage(image, 0, 0, width, height);
104
+ const optimizedBlob = await convertCanvasToBlob({
105
+ canvas,
106
+ errorLabel,
107
+ outputQuality
108
+ });
109
+ if (optimizedBlob.size >= file.size) {
110
+ return file;
111
+ }
112
+ return new File([optimizedBlob], resolveOptimizedImageFileName(file.name), {
113
+ lastModified: file.lastModified,
114
+ type: OUTPUT_TYPE
115
+ });
116
+ };
117
+
118
+ // src/shared/lib/image/optimize-content-image-file.ts
119
+ var CONTENT_MAX_WIDTH = 1600;
120
+ var CONTENT_MAX_HEIGHT = 1600;
121
+ var CONTENT_OUTPUT_QUALITY = 0.84;
122
+ var optimizeContentImageFile = (file) => optimizeImageFile({
123
+ errorLabel: "content-image-optimization",
124
+ file,
125
+ maxHeight: CONTENT_MAX_HEIGHT,
126
+ maxWidth: CONTENT_MAX_WIDTH,
127
+ outputQuality: CONTENT_OUTPUT_QUALITY
128
+ });
129
+
130
+ // src/shared/lib/image/optimize-thumbnail-image-file.ts
131
+ var THUMBNAIL_MAX_WIDTH = 800;
132
+ var THUMBNAIL_MAX_HEIGHT = 800;
133
+ var THUMBNAIL_OUTPUT_QUALITY = 0.82;
134
+ var optimizeThumbnailImageFile = (file) => optimizeImageFile({
135
+ errorLabel: "thumbnail-optimization",
136
+ file,
137
+ maxHeight: THUMBNAIL_MAX_HEIGHT,
138
+ maxWidth: THUMBNAIL_MAX_WIDTH,
139
+ outputQuality: THUMBNAIL_OUTPUT_QUALITY
140
+ });
141
+
142
+ // src/integrations/default-host/api/upload-editor-image.ts
143
+ var uploadEditorImage = async ({
144
+ contentType,
145
+ file,
146
+ imageKind
147
+ }) => {
148
+ const optimizedFile = imageKind === "thumbnail" ? await optimizeThumbnailImageFile(file) : await optimizeContentImageFile(file);
149
+ const formData = new FormData();
150
+ formData.set("contentType", contentType);
151
+ formData.set("file", optimizedFile);
152
+ formData.set("imageKind", imageKind);
153
+ const response = await fetch("/api/images", {
154
+ body: formData,
155
+ method: "POST"
156
+ });
157
+ let body = {};
158
+ try {
159
+ body = await response.json();
160
+ } catch {
161
+ body = {
162
+ error: response.ok ? "Image response parse failed" : "Image upload failed",
163
+ message: response.statusText || void 0
164
+ };
165
+ }
166
+ if (!response.ok || !body.url) {
167
+ throw new Error(body.error ?? body.message ?? "Image upload failed");
168
+ }
169
+ return body.url;
170
+ };
171
+
172
+ // src/integrations/default-host/api/upload-editor-video.ts
173
+ var createAbortUploadError = () => {
174
+ const error = new Error("Video upload aborted");
175
+ error.name = "AbortError";
176
+ return error;
177
+ };
178
+ var parseUploadResponse = (responseText) => {
179
+ try {
180
+ return JSON.parse(responseText);
181
+ } catch {
182
+ return {};
183
+ }
184
+ };
185
+ var uploadEditorVideo = async ({
186
+ contentType,
187
+ file,
188
+ onProgress,
189
+ signal
190
+ }) => {
191
+ const formData = new FormData();
192
+ formData.set("contentType", contentType);
193
+ formData.set("file", file);
194
+ return await new Promise((resolve, reject) => {
195
+ const xhr = new XMLHttpRequest();
196
+ const cleanup = () => {
197
+ xhr.upload.onprogress = null;
198
+ xhr.onload = null;
199
+ xhr.onerror = null;
200
+ xhr.onabort = null;
201
+ signal?.removeEventListener("abort", handleAbortSignal);
202
+ };
203
+ const handleAbortSignal = () => {
204
+ xhr.abort();
205
+ };
206
+ xhr.open("POST", "/api/videos");
207
+ xhr.upload.onprogress = (event) => {
208
+ if (!event.lengthComputable) return;
209
+ onProgress?.(Math.min(100, Math.round(event.loaded / event.total * 100)));
210
+ };
211
+ xhr.onload = () => {
212
+ cleanup();
213
+ const body = parseUploadResponse(xhr.responseText);
214
+ if (xhr.status < 200 || xhr.status >= 300 || !body.url) {
215
+ reject(new Error(body.error ?? body.message ?? "Video upload failed"));
216
+ return;
217
+ }
218
+ resolve(body.url);
219
+ };
220
+ xhr.onerror = () => {
221
+ cleanup();
222
+ reject(new Error("Video upload failed"));
223
+ };
224
+ xhr.onabort = () => {
225
+ cleanup();
226
+ reject(createAbortUploadError());
227
+ };
228
+ if (signal) {
229
+ if (signal.aborted) {
230
+ xhr.abort();
231
+ return;
232
+ }
233
+ signal.addEventListener("abort", handleAbortSignal, { once: true });
234
+ }
235
+ xhr.send(formData);
236
+ });
237
+ };
238
+
239
+ export { uploadEditorFile, uploadEditorImage, uploadEditorVideo };
@@ -0,0 +1,12 @@
1
+ import { R as ResolvedMarkdownPrimitiveRegistry } from './markdown-primitive-contract-BXsqbKwY.mjs';
2
+
3
+ /**
4
+ * Returns the package's default primitive registry, currently backed by Panda-based components.
5
+ */
6
+ declare const createDefaultMarkdownPrimitiveRegistry: () => ResolvedMarkdownPrimitiveRegistry;
7
+ /**
8
+ * Returns the currently bundled Panda-backed primitive registry for hosts that want the concrete default shell.
9
+ */
10
+ declare const createPandaMarkdownPrimitiveRegistry: () => ResolvedMarkdownPrimitiveRegistry;
11
+
12
+ export { createPandaMarkdownPrimitiveRegistry as a, createDefaultMarkdownPrimitiveRegistry as c };
@@ -0,0 +1,12 @@
1
+ import { R as ResolvedMarkdownPrimitiveRegistry } from './markdown-primitive-contract-BXsqbKwY.js';
2
+
3
+ /**
4
+ * Returns the package's default primitive registry, currently backed by Panda-based components.
5
+ */
6
+ declare const createDefaultMarkdownPrimitiveRegistry: () => ResolvedMarkdownPrimitiveRegistry;
7
+ /**
8
+ * Returns the currently bundled Panda-backed primitive registry for hosts that want the concrete default shell.
9
+ */
10
+ declare const createPandaMarkdownPrimitiveRegistry: () => ResolvedMarkdownPrimitiveRegistry;
11
+
12
+ export { createPandaMarkdownPrimitiveRegistry as a, createDefaultMarkdownPrimitiveRegistry as c };
@@ -0,0 +1,18 @@
1
+ type EditorContentType = 'article' | 'project' | 'resume';
2
+
3
+ /**
4
+ * Public metadata for an attachment embedded in editor content.
5
+ */
6
+ type EditorAttachment = {
7
+ contentType: string;
8
+ fileName: string;
9
+ fileSize: number;
10
+ url: string;
11
+ };
12
+
13
+ /**
14
+ * Distinguishes the supported image upload intents.
15
+ */
16
+ type EditorImageUploadKind = 'content' | 'thumbnail';
17
+
18
+ export type { EditorAttachment as E, EditorContentType as a, EditorImageUploadKind as b };
@@ -0,0 +1,18 @@
1
+ type EditorContentType = 'article' | 'project' | 'resume';
2
+
3
+ /**
4
+ * Public metadata for an attachment embedded in editor content.
5
+ */
6
+ type EditorAttachment = {
7
+ contentType: string;
8
+ fileName: string;
9
+ fileSize: number;
10
+ url: string;
11
+ };
12
+
13
+ /**
14
+ * Distinguishes the supported image upload intents.
15
+ */
16
+ type EditorImageUploadKind = 'content' | 'thumbnail';
17
+
18
+ export type { EditorAttachment as E, EditorContentType as a, EditorImageUploadKind as b };