@quadrats/common 0.7.7 → 1.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/accordion/constants.d.ts +5 -0
- package/accordion/constants.js +10 -0
- package/accordion/createAccordion.d.ts +6 -0
- package/accordion/createAccordion.js +62 -0
- package/accordion/index.cjs.js +76 -0
- package/accordion/index.d.ts +3 -0
- package/accordion/index.js +2 -0
- package/accordion/package.json +7 -0
- package/accordion/typings.d.ts +18 -0
- package/align/constants.d.ts +2 -0
- package/align/constants.js +7 -0
- package/align/createAlign.d.ts +9 -0
- package/align/createAlign.js +39 -0
- package/align/index.cjs.js +46 -0
- package/align/index.d.ts +3 -0
- package/align/index.js +2 -0
- package/align/package.json +7 -0
- package/align/typings.d.ts +1 -0
- package/blockquote/createBlockquote.js +27 -10
- package/blockquote/index.cjs.js +26 -9
- package/card/constants.d.ts +6 -0
- package/card/constants.js +11 -0
- package/card/createCard.d.ts +15 -0
- package/card/createCard.js +147 -0
- package/card/getFilesFromInput.d.ts +4 -0
- package/card/index.cjs.js +163 -0
- package/card/index.d.ts +3 -0
- package/card/index.js +2 -0
- package/card/package.json +7 -0
- package/card/typings.d.ts +73 -0
- package/carousel/_virtual/_tslib.js +33 -0
- package/carousel/constants.d.ts +6 -0
- package/carousel/constants.js +11 -0
- package/carousel/createCarousel.d.ts +16 -0
- package/carousel/createCarousel.js +127 -0
- package/carousel/getFilesFromInput.d.ts +4 -0
- package/carousel/getFilesFromInput.js +30 -0
- package/carousel/index.cjs.js +202 -0
- package/carousel/index.d.ts +3 -0
- package/carousel/index.js +2 -0
- package/carousel/package.json +7 -0
- package/carousel/typings.d.ts +58 -0
- package/embed/constants.d.ts +1 -0
- package/embed/constants.js +2 -1
- package/embed/createEmbed.js +21 -4
- package/embed/index.cjs.js +26 -9
- package/embed/index.js +1 -1
- package/embed/serializeEmbedCode.d.ts +1 -1
- package/embed/serializeEmbedCode.js +5 -7
- package/embed/strategies/podcast-apple/index.cjs.js +1 -1
- package/embed/strategies/podcast-apple/index.js +1 -1
- package/embed/typings.d.ts +16 -1
- package/file-uploader/constants.d.ts +1 -0
- package/file-uploader/constants.js +2 -1
- package/file-uploader/createFileUploader.js +70 -7
- package/file-uploader/getFilesFromInput.js +3 -0
- package/file-uploader/index.cjs.js +73 -5
- package/file-uploader/index.js +1 -1
- package/file-uploader/typings.d.ts +8 -2
- package/heading/typings.d.ts +1 -0
- package/image/createImage.js +12 -11
- package/image/getImageFigureElementCommonProps.d.ts +2 -0
- package/image/getImageFigureElementCommonProps.js +28 -2
- package/image/index.cjs.js +40 -13
- package/image/typings.d.ts +2 -0
- package/list/createList.d.ts +1 -0
- package/list/createList.js +3 -0
- package/list/index.cjs.js +3 -0
- package/list/typings.d.ts +1 -0
- package/package.json +4 -4
- package/paragraph/createParagraph.d.ts +2 -0
- package/paragraph/createParagraph.js +24 -0
- package/paragraph/index.cjs.js +26 -0
- package/paragraph/index.d.ts +2 -0
- package/paragraph/index.js +1 -0
- package/paragraph/package.json +7 -0
- package/paragraph/typings.d.ts +9 -0
- package/table/constants.d.ts +14 -0
- package/table/constants.js +25 -0
- package/table/createTable.d.ts +6 -0
- package/table/createTable.js +429 -0
- package/table/index.cjs.js +714 -0
- package/table/index.d.ts +4 -0
- package/table/index.js +3 -0
- package/table/package.json +7 -0
- package/table/typings.d.ts +70 -0
- package/table/utils.d.ts +68 -0
- package/table/utils.js +243 -0
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var utils = require('@quadrats/utils');
|
|
4
4
|
var core = require('@quadrats/core');
|
|
5
|
+
var table = require('@quadrats/common/table');
|
|
5
6
|
|
|
6
7
|
const FILE_UPLOADER_TYPE = 'file_uploader';
|
|
8
|
+
const FILE_UPLOADER_PLACEHOLDER_TYPE = 'file_uploader_placeholder';
|
|
7
9
|
|
|
8
10
|
function getFilesFromInput(options = {}) {
|
|
9
11
|
const { accept, multiple } = options;
|
|
@@ -14,6 +16,9 @@ function getFilesFromInput(options = {}) {
|
|
|
14
16
|
}
|
|
15
17
|
inputEl.multiple = !!multiple;
|
|
16
18
|
inputEl.type = 'file';
|
|
19
|
+
inputEl.addEventListener('cancel', () => {
|
|
20
|
+
resolve(undefined);
|
|
21
|
+
});
|
|
17
22
|
inputEl.addEventListener('change', () => {
|
|
18
23
|
const { files: fileList } = inputEl;
|
|
19
24
|
if (!fileList || !fileList.length) {
|
|
@@ -63,8 +68,8 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
63
68
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
64
69
|
};
|
|
65
70
|
|
|
66
|
-
const createFileUploaderElementByType = type => (editor, file, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
-
const { createElement, getBody, getHeaders, getUrl, uploader
|
|
71
|
+
const createFileUploaderElementByType = (type) => (editor, file, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
+
const { createElement, getBody, getHeaders, getUrl, uploader } = options;
|
|
68
73
|
const [mime] = file.type.split('/');
|
|
69
74
|
const createByMime = createElement[mime];
|
|
70
75
|
if (!createByMime) {
|
|
@@ -113,16 +118,32 @@ const createFileUploaderElementByType = type => (editor, file, options) => __awa
|
|
|
113
118
|
return fileUploaderElement;
|
|
114
119
|
});
|
|
115
120
|
function insertFileUploaderElement(editor, fileUploaderElement) {
|
|
116
|
-
var _a, _b
|
|
121
|
+
var _a, _b;
|
|
117
122
|
if (fileUploaderElement) {
|
|
123
|
+
// 驗證當前 selection 是否仍然有效
|
|
124
|
+
if (!editor.selection) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
// 嘗試取得當前選取位置的節點,確保路徑仍然有效
|
|
129
|
+
const node = core.Editor.node(editor, editor.selection);
|
|
130
|
+
if (!node) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
// 如果路徑無效(例如 placeholder 已被移除),靜默失敗
|
|
136
|
+
console.warn('Cannot insert file uploader element: invalid selection path', error);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
118
139
|
// Clear empty node
|
|
119
140
|
if (core.isAboveBlockEmpty(editor)) {
|
|
120
141
|
core.Transforms.removeNodes(editor, {
|
|
121
|
-
at:
|
|
142
|
+
at: editor.selection.anchor,
|
|
122
143
|
});
|
|
123
144
|
}
|
|
124
145
|
core.Transforms.insertNodes(editor, [fileUploaderElement, core.createParagraphElement()], {
|
|
125
|
-
at: ((
|
|
146
|
+
at: ((_a = editor.selection) === null || _a === void 0 ? void 0 : _a.anchor.path.length) ? [((_b = editor.selection) === null || _b === void 0 ? void 0 : _b.anchor.path[0]) + 1] : undefined,
|
|
126
147
|
});
|
|
127
148
|
core.Transforms.move(editor);
|
|
128
149
|
}
|
|
@@ -130,12 +151,33 @@ function insertFileUploaderElement(editor, fileUploaderElement) {
|
|
|
130
151
|
function createFileUploader(options = {}) {
|
|
131
152
|
const { type = FILE_UPLOADER_TYPE } = options;
|
|
132
153
|
const createFileUploaderElement = createFileUploaderElementByType(type);
|
|
154
|
+
const removeUploaderPlaceholder = (editor) => {
|
|
155
|
+
core.Transforms.removeNodes(editor, {
|
|
156
|
+
match: (node) => core.Element.isElement(node) && node.type === FILE_UPLOADER_PLACEHOLDER_TYPE,
|
|
157
|
+
});
|
|
158
|
+
};
|
|
133
159
|
const upload = (editor, options) => __awaiter(this, void 0, void 0, function* () {
|
|
160
|
+
// 檢查是否在不允許的元件之中,如果是則不執行上傳
|
|
161
|
+
if (editor.selection) {
|
|
162
|
+
try {
|
|
163
|
+
const invalidEntry = core.Editor.above(editor, {
|
|
164
|
+
at: editor.selection,
|
|
165
|
+
match: (n) => core.Element.isElement(n) && n.type === table.TABLE_CELL_TYPE,
|
|
166
|
+
});
|
|
167
|
+
if (invalidEntry)
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
134
174
|
const { accept, multiple } = options;
|
|
135
175
|
const files = yield getFilesFromInput({ accept, multiple });
|
|
136
176
|
if (!files) {
|
|
177
|
+
removeUploaderPlaceholder(editor);
|
|
137
178
|
return;
|
|
138
179
|
}
|
|
180
|
+
removeUploaderPlaceholder(editor);
|
|
139
181
|
files.reduce((prev, file) => __awaiter(this, void 0, void 0, function* () {
|
|
140
182
|
yield prev;
|
|
141
183
|
return createFileUploaderElement(editor, file, options).then((fileUploaderElement) => {
|
|
@@ -143,16 +185,42 @@ function createFileUploader(options = {}) {
|
|
|
143
185
|
});
|
|
144
186
|
}), Promise.resolve());
|
|
145
187
|
});
|
|
188
|
+
const insertUploaderPlaceholder = (editor) => {
|
|
189
|
+
// 檢查是否在不允許的元件之中,如果是則不插入 placeholder
|
|
190
|
+
if (editor.selection) {
|
|
191
|
+
try {
|
|
192
|
+
const invalidEntry = core.Editor.above(editor, {
|
|
193
|
+
at: editor.selection,
|
|
194
|
+
match: (n) => core.Element.isElement(n) && n.type === table.TABLE_CELL_TYPE,
|
|
195
|
+
});
|
|
196
|
+
if (invalidEntry)
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const uploaderPlaceholderElement = {
|
|
204
|
+
type: FILE_UPLOADER_PLACEHOLDER_TYPE,
|
|
205
|
+
children: [{ text: '' }],
|
|
206
|
+
};
|
|
207
|
+
core.Editor.withoutNormalizing(editor, () => {
|
|
208
|
+
core.Transforms.insertNodes(editor, uploaderPlaceholderElement);
|
|
209
|
+
});
|
|
210
|
+
};
|
|
146
211
|
return {
|
|
147
212
|
type,
|
|
148
213
|
createFileUploaderElement,
|
|
149
214
|
upload,
|
|
215
|
+
insertUploaderPlaceholder,
|
|
216
|
+
removeUploaderPlaceholder,
|
|
150
217
|
with(editor) {
|
|
151
218
|
return editor;
|
|
152
219
|
},
|
|
153
220
|
};
|
|
154
221
|
}
|
|
155
222
|
|
|
223
|
+
exports.FILE_UPLOADER_PLACEHOLDER_TYPE = FILE_UPLOADER_PLACEHOLDER_TYPE;
|
|
156
224
|
exports.FILE_UPLOADER_TYPE = FILE_UPLOADER_TYPE;
|
|
157
225
|
exports.createFileUploader = createFileUploader;
|
|
158
226
|
exports.createFileUploaderElementByType = createFileUploaderElementByType;
|
package/file-uploader/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { FILE_UPLOADER_TYPE } from './constants.js';
|
|
1
|
+
export { FILE_UPLOADER_PLACEHOLDER_TYPE, FILE_UPLOADER_TYPE } from './constants.js';
|
|
2
2
|
export { getFilesFromInput } from './getFilesFromInput.js';
|
|
3
3
|
export { createFileUploader, createFileUploaderElementByType, insertFileUploaderElement } from './createFileUploader.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Editor, QuadratsElement, Path, TransformsInsertNodesOptions, Withable } from '@quadrats/core';
|
|
1
|
+
import { Editor, QuadratsElement, Path, TransformsInsertNodesOptions, Withable, WithElementType, Text } from '@quadrats/core';
|
|
2
2
|
import { GetFilesFromInputOptions } from './getFilesFromInput';
|
|
3
|
+
export type ImageAccept = 'image/jpeg' | 'image/jpg' | 'image/png';
|
|
3
4
|
export interface XHRUploadHeaders {
|
|
4
5
|
[name: string]: string;
|
|
5
6
|
}
|
|
@@ -25,7 +26,7 @@ interface FileUploaderUploadImplementOnProgressArgs {
|
|
|
25
26
|
interface FileUploaderUploadImplement {
|
|
26
27
|
onprogress: ((options: FileUploaderUploadImplementOnProgressArgs) => void) | null;
|
|
27
28
|
}
|
|
28
|
-
interface FileUploaderImplement {
|
|
29
|
+
export interface FileUploaderImplement {
|
|
29
30
|
onload: (() => void) | null;
|
|
30
31
|
open: (method: string, url: string | URL) => void;
|
|
31
32
|
setRequestHeader: (key: string, value: string) => void;
|
|
@@ -34,6 +35,9 @@ interface FileUploaderImplement {
|
|
|
34
35
|
readonly response: any;
|
|
35
36
|
readonly upload: FileUploaderUploadImplement;
|
|
36
37
|
}
|
|
38
|
+
export interface UploaderPlaceholderElement extends QuadratsElement, WithElementType {
|
|
39
|
+
children: [Text];
|
|
40
|
+
}
|
|
37
41
|
export interface FileUploaderCreateFileUploaderElementOptions {
|
|
38
42
|
createElement: {
|
|
39
43
|
[mime in string]?: {
|
|
@@ -51,5 +55,7 @@ export interface FileUploader<T extends Editor = Editor> extends Withable {
|
|
|
51
55
|
type: string;
|
|
52
56
|
createFileUploaderElement(editor: T, file: File, options: FileUploaderCreateFileUploaderElementOptions): Promise<FileUploaderElement | undefined>;
|
|
53
57
|
upload(editor: T, options: FileUploaderUploadOptions): Promise<void>;
|
|
58
|
+
insertUploaderPlaceholder(editor: T): void;
|
|
59
|
+
removeUploaderPlaceholder(editor: T): void;
|
|
54
60
|
}
|
|
55
61
|
export {};
|
package/heading/typings.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Editor, QuadratsElement, GetNodesOptions, Node, NodeEntry, Withable, Wi
|
|
|
2
2
|
export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
3
3
|
export interface HeadingElement extends QuadratsElement, WithElementType {
|
|
4
4
|
level: HeadingLevel;
|
|
5
|
+
align?: 'left' | 'center' | 'right';
|
|
5
6
|
}
|
|
6
7
|
export interface WithEnabledHeadingLevels<L extends HeadingLevel> {
|
|
7
8
|
/**
|
package/image/createImage.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Range, isNodesTypeIn, getAboveByTypes, Editor, Transforms, createParagr
|
|
|
3
3
|
import { IMAGE_TYPES } from './constants.js';
|
|
4
4
|
|
|
5
5
|
function resolveSizeSteps(steps) {
|
|
6
|
-
let sortedSteps = steps.filter(step => step > 0 && step < 100).sort();
|
|
6
|
+
let sortedSteps = steps.filter((step) => step > 0 && step < 100).sort();
|
|
7
7
|
if (!sortedSteps.includes(100)) {
|
|
8
8
|
sortedSteps = [...sortedSteps, 100];
|
|
9
9
|
}
|
|
@@ -16,12 +16,13 @@ function createImage(options = {}) {
|
|
|
16
16
|
const getAboveImageFigure = (editor, options) => getAboveByTypes(editor, [types.figure], options);
|
|
17
17
|
const getAboveImageCaption = (editor, options) => getAboveByTypes(editor, [types.caption], options);
|
|
18
18
|
const isNodesInImage = (editor, options) => isNodesTypeIn(editor, [types.image], options);
|
|
19
|
-
const isSelectionInImage = editor => isNodesInImage(editor);
|
|
20
|
-
const isSelectionInImageCaption = editor => isNodesTypeIn(editor, [types.caption]);
|
|
21
|
-
const isCollapsedOnImage = editor => !!editor.selection && Range.isCollapsed(editor.selection) && isSelectionInImage(editor);
|
|
19
|
+
const isSelectionInImage = (editor) => isNodesInImage(editor);
|
|
20
|
+
const isSelectionInImageCaption = (editor) => isNodesTypeIn(editor, [types.caption]);
|
|
21
|
+
const isCollapsedOnImage = (editor) => !!editor.selection && Range.isCollapsed(editor.selection) && isSelectionInImage(editor);
|
|
22
22
|
const createImageElement = (src, hosting) => {
|
|
23
23
|
const imageElement = {
|
|
24
24
|
type: types.image,
|
|
25
|
+
figureType: types.figure,
|
|
25
26
|
src,
|
|
26
27
|
hosting,
|
|
27
28
|
children: [{ text: '' }],
|
|
@@ -51,7 +52,7 @@ function createImage(options = {}) {
|
|
|
51
52
|
if (!sizeSteps) {
|
|
52
53
|
return percentage;
|
|
53
54
|
}
|
|
54
|
-
const lowerIndex = sizeSteps.findIndex(step => step >= percentage) - 1;
|
|
55
|
+
const lowerIndex = sizeSteps.findIndex((step) => step >= percentage) - 1;
|
|
55
56
|
const upperIndex = lowerIndex + 1;
|
|
56
57
|
if (lowerIndex < 0) {
|
|
57
58
|
return sizeSteps[0];
|
|
@@ -89,7 +90,7 @@ function createImage(options = {}) {
|
|
|
89
90
|
insertImage,
|
|
90
91
|
resizeImage,
|
|
91
92
|
with(editor) {
|
|
92
|
-
const { deleteBackward, deleteForward, insertBreak, isVoid, normalizeNode
|
|
93
|
+
const { deleteBackward, deleteForward, insertBreak, isVoid, normalizeNode } = editor;
|
|
93
94
|
const deleteCollapsed = (origin, isEdgeMethodName) => {
|
|
94
95
|
const { selection } = editor;
|
|
95
96
|
/**
|
|
@@ -97,7 +98,7 @@ function createImage(options = {}) {
|
|
|
97
98
|
*/
|
|
98
99
|
if (selection && Range.isCollapsed(selection)) {
|
|
99
100
|
const [, captionPath] = getAboveImageCaption(editor) || [];
|
|
100
|
-
if (
|
|
101
|
+
if (captionPath && Editor[isEdgeMethodName](editor, selection.focus, captionPath)) {
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
103
104
|
}
|
|
@@ -128,7 +129,7 @@ function createImage(options = {}) {
|
|
|
128
129
|
}
|
|
129
130
|
insertBreak();
|
|
130
131
|
};
|
|
131
|
-
editor.isVoid = element => element.type === types.image || isVoid(element);
|
|
132
|
+
editor.isVoid = (element) => element.type === types.image || isVoid(element);
|
|
132
133
|
editor.normalizeNode = (entry) => {
|
|
133
134
|
const [node, path] = entry;
|
|
134
135
|
if (Element.isElement(node)) {
|
|
@@ -140,9 +141,9 @@ function createImage(options = {}) {
|
|
|
140
141
|
}
|
|
141
142
|
else if (node.type === types.image) {
|
|
142
143
|
const { src, width, hosting } = node;
|
|
143
|
-
if (typeof src !== 'string'
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
if (typeof src !== 'string' ||
|
|
145
|
+
!(width == null || typeof width === 'number') ||
|
|
146
|
+
!(hosting == null || typeof hosting === 'string')) {
|
|
146
147
|
const [, figurePath] = getAboveImageFigure(editor, { at: path }) || [];
|
|
147
148
|
if (figurePath) {
|
|
148
149
|
Transforms.removeNodes(editor, { at: figurePath });
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ImageFigureElement } from './typings';
|
|
2
2
|
export declare function getImageFigureElementCommonProps(element: ImageFigureElement): {
|
|
3
3
|
style?: {
|
|
4
|
+
'--qdr-image-align': 'flex-start' | 'center' | 'flex-end';
|
|
5
|
+
'--qdr-image-caption-align': 'left' | 'center' | 'right';
|
|
4
6
|
width: string;
|
|
5
7
|
};
|
|
6
8
|
};
|
|
@@ -1,7 +1,33 @@
|
|
|
1
1
|
function getImageFigureElementCommonProps(element) {
|
|
2
|
-
const { width } = element;
|
|
2
|
+
const { width, align } = element;
|
|
3
3
|
return {
|
|
4
|
-
style:
|
|
4
|
+
style: {
|
|
5
|
+
width: typeof width === 'number' ? `${width}%` : 'unset',
|
|
6
|
+
'--qdr-image-align': (() => {
|
|
7
|
+
switch (align) {
|
|
8
|
+
case 'start':
|
|
9
|
+
return 'flex-start';
|
|
10
|
+
case 'center':
|
|
11
|
+
return 'center';
|
|
12
|
+
case 'end':
|
|
13
|
+
return 'flex-end';
|
|
14
|
+
default:
|
|
15
|
+
return 'flex-start';
|
|
16
|
+
}
|
|
17
|
+
})(),
|
|
18
|
+
'--qdr-image-caption-align': (() => {
|
|
19
|
+
switch (align) {
|
|
20
|
+
case 'start':
|
|
21
|
+
return 'left';
|
|
22
|
+
case 'center':
|
|
23
|
+
return 'center';
|
|
24
|
+
case 'end':
|
|
25
|
+
return 'right';
|
|
26
|
+
default:
|
|
27
|
+
return 'left';
|
|
28
|
+
}
|
|
29
|
+
})(),
|
|
30
|
+
},
|
|
5
31
|
};
|
|
6
32
|
}
|
|
7
33
|
|
package/image/index.cjs.js
CHANGED
|
@@ -14,9 +14,35 @@ function isHostingNotRequired(src) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function getImageFigureElementCommonProps(element) {
|
|
17
|
-
const { width } = element;
|
|
17
|
+
const { width, align } = element;
|
|
18
18
|
return {
|
|
19
|
-
style:
|
|
19
|
+
style: {
|
|
20
|
+
width: typeof width === 'number' ? `${width}%` : 'unset',
|
|
21
|
+
'--qdr-image-align': (() => {
|
|
22
|
+
switch (align) {
|
|
23
|
+
case 'start':
|
|
24
|
+
return 'flex-start';
|
|
25
|
+
case 'center':
|
|
26
|
+
return 'center';
|
|
27
|
+
case 'end':
|
|
28
|
+
return 'flex-end';
|
|
29
|
+
default:
|
|
30
|
+
return 'flex-start';
|
|
31
|
+
}
|
|
32
|
+
})(),
|
|
33
|
+
'--qdr-image-caption-align': (() => {
|
|
34
|
+
switch (align) {
|
|
35
|
+
case 'start':
|
|
36
|
+
return 'left';
|
|
37
|
+
case 'center':
|
|
38
|
+
return 'center';
|
|
39
|
+
case 'end':
|
|
40
|
+
return 'right';
|
|
41
|
+
default:
|
|
42
|
+
return 'left';
|
|
43
|
+
}
|
|
44
|
+
})(),
|
|
45
|
+
},
|
|
20
46
|
};
|
|
21
47
|
}
|
|
22
48
|
|
|
@@ -29,7 +55,7 @@ function getImageElementCommonProps(element, hostingResolvers) {
|
|
|
29
55
|
}
|
|
30
56
|
|
|
31
57
|
function resolveSizeSteps(steps) {
|
|
32
|
-
let sortedSteps = steps.filter(step => step > 0 && step < 100).sort();
|
|
58
|
+
let sortedSteps = steps.filter((step) => step > 0 && step < 100).sort();
|
|
33
59
|
if (!sortedSteps.includes(100)) {
|
|
34
60
|
sortedSteps = [...sortedSteps, 100];
|
|
35
61
|
}
|
|
@@ -42,12 +68,13 @@ function createImage(options = {}) {
|
|
|
42
68
|
const getAboveImageFigure = (editor, options) => core.getAboveByTypes(editor, [types.figure], options);
|
|
43
69
|
const getAboveImageCaption = (editor, options) => core.getAboveByTypes(editor, [types.caption], options);
|
|
44
70
|
const isNodesInImage = (editor, options) => core.isNodesTypeIn(editor, [types.image], options);
|
|
45
|
-
const isSelectionInImage = editor => isNodesInImage(editor);
|
|
46
|
-
const isSelectionInImageCaption = editor => core.isNodesTypeIn(editor, [types.caption]);
|
|
47
|
-
const isCollapsedOnImage = editor => !!editor.selection && core.Range.isCollapsed(editor.selection) && isSelectionInImage(editor);
|
|
71
|
+
const isSelectionInImage = (editor) => isNodesInImage(editor);
|
|
72
|
+
const isSelectionInImageCaption = (editor) => core.isNodesTypeIn(editor, [types.caption]);
|
|
73
|
+
const isCollapsedOnImage = (editor) => !!editor.selection && core.Range.isCollapsed(editor.selection) && isSelectionInImage(editor);
|
|
48
74
|
const createImageElement = (src, hosting) => {
|
|
49
75
|
const imageElement = {
|
|
50
76
|
type: types.image,
|
|
77
|
+
figureType: types.figure,
|
|
51
78
|
src,
|
|
52
79
|
hosting,
|
|
53
80
|
children: [{ text: '' }],
|
|
@@ -77,7 +104,7 @@ function createImage(options = {}) {
|
|
|
77
104
|
if (!sizeSteps) {
|
|
78
105
|
return percentage;
|
|
79
106
|
}
|
|
80
|
-
const lowerIndex = sizeSteps.findIndex(step => step >= percentage) - 1;
|
|
107
|
+
const lowerIndex = sizeSteps.findIndex((step) => step >= percentage) - 1;
|
|
81
108
|
const upperIndex = lowerIndex + 1;
|
|
82
109
|
if (lowerIndex < 0) {
|
|
83
110
|
return sizeSteps[0];
|
|
@@ -115,7 +142,7 @@ function createImage(options = {}) {
|
|
|
115
142
|
insertImage,
|
|
116
143
|
resizeImage,
|
|
117
144
|
with(editor) {
|
|
118
|
-
const { deleteBackward, deleteForward, insertBreak, isVoid, normalizeNode
|
|
145
|
+
const { deleteBackward, deleteForward, insertBreak, isVoid, normalizeNode } = editor;
|
|
119
146
|
const deleteCollapsed = (origin, isEdgeMethodName) => {
|
|
120
147
|
const { selection } = editor;
|
|
121
148
|
/**
|
|
@@ -123,7 +150,7 @@ function createImage(options = {}) {
|
|
|
123
150
|
*/
|
|
124
151
|
if (selection && core.Range.isCollapsed(selection)) {
|
|
125
152
|
const [, captionPath] = getAboveImageCaption(editor) || [];
|
|
126
|
-
if (
|
|
153
|
+
if (captionPath && core.Editor[isEdgeMethodName](editor, selection.focus, captionPath)) {
|
|
127
154
|
return;
|
|
128
155
|
}
|
|
129
156
|
}
|
|
@@ -154,7 +181,7 @@ function createImage(options = {}) {
|
|
|
154
181
|
}
|
|
155
182
|
insertBreak();
|
|
156
183
|
};
|
|
157
|
-
editor.isVoid = element => element.type === types.image || isVoid(element);
|
|
184
|
+
editor.isVoid = (element) => element.type === types.image || isVoid(element);
|
|
158
185
|
editor.normalizeNode = (entry) => {
|
|
159
186
|
const [node, path] = entry;
|
|
160
187
|
if (core.Element.isElement(node)) {
|
|
@@ -166,9 +193,9 @@ function createImage(options = {}) {
|
|
|
166
193
|
}
|
|
167
194
|
else if (node.type === types.image) {
|
|
168
195
|
const { src, width, hosting } = node;
|
|
169
|
-
if (typeof src !== 'string'
|
|
170
|
-
|
|
171
|
-
|
|
196
|
+
if (typeof src !== 'string' ||
|
|
197
|
+
!(width == null || typeof width === 'number') ||
|
|
198
|
+
!(hosting == null || typeof hosting === 'string')) {
|
|
172
199
|
const [, figurePath] = getAboveImageFigure(editor, { at: path }) || [];
|
|
173
200
|
if (figurePath) {
|
|
174
201
|
core.Transforms.removeNodes(editor, { at: figurePath });
|
package/image/typings.d.ts
CHANGED
|
@@ -4,11 +4,13 @@ export type ImageTypeKey = 'image';
|
|
|
4
4
|
export type ImageCaptionTypeKey = 'caption';
|
|
5
5
|
export type ImageTypes = Record<ImageFigureTypeKey | ImageTypeKey | ImageCaptionTypeKey, string>;
|
|
6
6
|
export interface ImageFigureElement extends QuadratsElement, WithElementType {
|
|
7
|
+
align?: 'start' | 'center' | 'end';
|
|
7
8
|
width?: number;
|
|
8
9
|
}
|
|
9
10
|
export interface ImageElement extends QuadratsElement, WithElementType {
|
|
10
11
|
children: [Text];
|
|
11
12
|
src: string;
|
|
13
|
+
figureType: string;
|
|
12
14
|
/**
|
|
13
15
|
* e.g. The src of image is `8gy9pbaht92y4.jpg` and your static files are hosted by `https://foo.storage`.
|
|
14
16
|
* Then you can make the hosting of element be `foo`.
|
package/list/createList.d.ts
CHANGED
package/list/createList.js
CHANGED
|
@@ -2,6 +2,8 @@ import { PARAGRAPH_TYPE, isNodesTypeIn, Range, isSelectionAtBlockEdge, deleteSel
|
|
|
2
2
|
import { LIST_TYPES } from './constants.js';
|
|
3
3
|
|
|
4
4
|
function createList(options = {}) {
|
|
5
|
+
var _a;
|
|
6
|
+
const labels = (_a = options.labels) !== null && _a !== void 0 ? _a : 4;
|
|
5
7
|
const types = Object.assign(Object.assign({}, LIST_TYPES), options.types);
|
|
6
8
|
const isListElement = (node) => [types.ol, types.ul].includes(node.type);
|
|
7
9
|
const isListItemElement = (node) => node.type === types.li;
|
|
@@ -140,6 +142,7 @@ function createList(options = {}) {
|
|
|
140
142
|
};
|
|
141
143
|
return {
|
|
142
144
|
types,
|
|
145
|
+
labels,
|
|
143
146
|
isListElement,
|
|
144
147
|
isListItemElement,
|
|
145
148
|
isSelectionInList,
|
package/list/index.cjs.js
CHANGED
|
@@ -9,6 +9,8 @@ const LIST_TYPES = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
function createList(options = {}) {
|
|
12
|
+
var _a;
|
|
13
|
+
const labels = (_a = options.labels) !== null && _a !== void 0 ? _a : 4;
|
|
12
14
|
const types = Object.assign(Object.assign({}, LIST_TYPES), options.types);
|
|
13
15
|
const isListElement = (node) => [types.ol, types.ul].includes(node.type);
|
|
14
16
|
const isListItemElement = (node) => node.type === types.li;
|
|
@@ -147,6 +149,7 @@ function createList(options = {}) {
|
|
|
147
149
|
};
|
|
148
150
|
return {
|
|
149
151
|
types,
|
|
152
|
+
labels,
|
|
150
153
|
isListElement,
|
|
151
154
|
isListItemElement,
|
|
152
155
|
isSelectionInList,
|
package/list/typings.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface List<T extends Editor = Editor> extends Withable {
|
|
|
17
17
|
* An object which keys are `ul`, `ol`, `li` and values are the corresponding element types.
|
|
18
18
|
*/
|
|
19
19
|
types: ListTypes;
|
|
20
|
+
labels: number;
|
|
20
21
|
isListElement(node: Node): node is QuadratsElement;
|
|
21
22
|
isListItemElement(node: Node): node is QuadratsElement;
|
|
22
23
|
isSelectionInList(editor: T, listTypeKey: ListRootTypeKey): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quadrats/common",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "Rytass",
|
|
6
6
|
"homepage": "https://github.com/Quadrats/quadrats#readme",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"url": "https://github.com/Quadrats/quadrats/issues"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@quadrats/core": "^
|
|
22
|
-
"@quadrats/locales": "^0.
|
|
23
|
-
"@quadrats/utils": "^0.
|
|
21
|
+
"@quadrats/core": "^1.1.0",
|
|
22
|
+
"@quadrats/locales": "^1.0.0",
|
|
23
|
+
"@quadrats/utils": "^1.0.0"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getNodes, PARAGRAPH_TYPE, Transforms } from '@quadrats/core';
|
|
2
|
+
|
|
3
|
+
function createParagraph() {
|
|
4
|
+
const getParagraphNodes = (editor, options = {}) => getNodes(editor, Object.assign(Object.assign({}, options), { match: (node) => node.type === PARAGRAPH_TYPE }));
|
|
5
|
+
const isSelectionInParagraph = (editor, options = {}) => {
|
|
6
|
+
const [match] = getParagraphNodes(editor, options);
|
|
7
|
+
return !!match;
|
|
8
|
+
};
|
|
9
|
+
const setParagraphNodes = (editor) => {
|
|
10
|
+
const paragraph = { type: PARAGRAPH_TYPE, children: [] };
|
|
11
|
+
Transforms.setNodes(editor, paragraph);
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
type: PARAGRAPH_TYPE,
|
|
15
|
+
getParagraphNodes,
|
|
16
|
+
isSelectionInParagraph,
|
|
17
|
+
setParagraphNodes,
|
|
18
|
+
with(editor) {
|
|
19
|
+
return editor;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { createParagraph };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@quadrats/core');
|
|
4
|
+
|
|
5
|
+
function createParagraph() {
|
|
6
|
+
const getParagraphNodes = (editor, options = {}) => core.getNodes(editor, Object.assign(Object.assign({}, options), { match: (node) => node.type === core.PARAGRAPH_TYPE }));
|
|
7
|
+
const isSelectionInParagraph = (editor, options = {}) => {
|
|
8
|
+
const [match] = getParagraphNodes(editor, options);
|
|
9
|
+
return !!match;
|
|
10
|
+
};
|
|
11
|
+
const setParagraphNodes = (editor) => {
|
|
12
|
+
const paragraph = { type: core.PARAGRAPH_TYPE, children: [] };
|
|
13
|
+
core.Transforms.setNodes(editor, paragraph);
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
type: core.PARAGRAPH_TYPE,
|
|
17
|
+
getParagraphNodes,
|
|
18
|
+
isSelectionInParagraph,
|
|
19
|
+
setParagraphNodes,
|
|
20
|
+
with(editor) {
|
|
21
|
+
return editor;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.createParagraph = createParagraph;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createParagraph } from './createParagraph.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Editor, QuadratsElement, GetNodesOptions, Node, NodeEntry, Withable, WithElementType } from '@quadrats/core';
|
|
2
|
+
export interface ParagraphElement extends QuadratsElement {
|
|
3
|
+
align?: 'left' | 'center' | 'right';
|
|
4
|
+
}
|
|
5
|
+
export interface Paragraph<T extends Editor = Editor> extends WithElementType, Withable {
|
|
6
|
+
getParagraphNodes(editor: T, options?: GetNodesOptions): Generator<NodeEntry<Node>>;
|
|
7
|
+
isSelectionInParagraph(editor: T, options?: GetNodesOptions): boolean;
|
|
8
|
+
setParagraphNodes(editor: T): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TableTypes } from './typings';
|
|
2
|
+
export declare const TABLE_TYPE = "table";
|
|
3
|
+
export declare const TABLE_TITLE_TYPE = "table_title";
|
|
4
|
+
export declare const TABLE_MAIN_TYPE = "table_main";
|
|
5
|
+
export declare const TABLE_HEADER_TYPE = "table_header";
|
|
6
|
+
export declare const TABLE_BODY_TYPE = "table_body";
|
|
7
|
+
export declare const TABLE_ROW_TYPE = "table_row";
|
|
8
|
+
export declare const TABLE_CELL_TYPE = "table_cell";
|
|
9
|
+
export declare const TABLE_TYPES: TableTypes;
|
|
10
|
+
export declare const TABLE_DEFAULT_MAX_COLUMNS = 6;
|
|
11
|
+
export declare const TABLE_DEFAULT_MAX_ROWS = -1;
|
|
12
|
+
export declare const MAX_PINNED_COLUMNS_WIDTH_PERCENTAGE = 40;
|
|
13
|
+
export declare const MIN_COLUMN_WIDTH_PIXEL = 60;
|
|
14
|
+
export declare const MIN_COLUMN_WIDTH_PERCENTAGE = 5;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const TABLE_TYPE = 'table';
|
|
2
|
+
const TABLE_TITLE_TYPE = 'table_title';
|
|
3
|
+
const TABLE_MAIN_TYPE = 'table_main';
|
|
4
|
+
const TABLE_HEADER_TYPE = 'table_header';
|
|
5
|
+
const TABLE_BODY_TYPE = 'table_body';
|
|
6
|
+
const TABLE_ROW_TYPE = 'table_row';
|
|
7
|
+
const TABLE_CELL_TYPE = 'table_cell';
|
|
8
|
+
const TABLE_TYPES = {
|
|
9
|
+
table: TABLE_TYPE,
|
|
10
|
+
table_title: TABLE_TITLE_TYPE,
|
|
11
|
+
table_main: TABLE_MAIN_TYPE,
|
|
12
|
+
table_header: TABLE_HEADER_TYPE,
|
|
13
|
+
table_body: TABLE_BODY_TYPE,
|
|
14
|
+
table_row: TABLE_ROW_TYPE,
|
|
15
|
+
table_cell: TABLE_CELL_TYPE,
|
|
16
|
+
};
|
|
17
|
+
// Table limits
|
|
18
|
+
const TABLE_DEFAULT_MAX_COLUMNS = 6;
|
|
19
|
+
const TABLE_DEFAULT_MAX_ROWS = -1;
|
|
20
|
+
// 釘選欄位的最大總寬度百分比
|
|
21
|
+
const MAX_PINNED_COLUMNS_WIDTH_PERCENTAGE = 40;
|
|
22
|
+
const MIN_COLUMN_WIDTH_PIXEL = 60;
|
|
23
|
+
const MIN_COLUMN_WIDTH_PERCENTAGE = 5;
|
|
24
|
+
|
|
25
|
+
export { MAX_PINNED_COLUMNS_WIDTH_PERCENTAGE, MIN_COLUMN_WIDTH_PERCENTAGE, MIN_COLUMN_WIDTH_PIXEL, TABLE_BODY_TYPE, TABLE_CELL_TYPE, TABLE_DEFAULT_MAX_COLUMNS, TABLE_DEFAULT_MAX_ROWS, TABLE_HEADER_TYPE, TABLE_MAIN_TYPE, TABLE_ROW_TYPE, TABLE_TITLE_TYPE, TABLE_TYPE, TABLE_TYPES };
|