@oix1987/yjd 1.0.0 → 1.0.2

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 (58) hide show
  1. package/README.md +73 -22
  2. package/dist/rich-editor.esm.js +2 -0
  3. package/dist/rich-editor.esm.js.map +1 -0
  4. package/dist/rich-editor.min.js +2 -0
  5. package/dist/rich-editor.min.js.map +1 -0
  6. package/package.json +12 -7
  7. package/index.js +0 -221
  8. package/lib/core/editor.js +0 -1175
  9. package/lib/core/format.js +0 -542
  10. package/lib/core/module.js +0 -81
  11. package/lib/core/registry.js +0 -152
  12. package/lib/formats/background.js +0 -212
  13. package/lib/formats/bold.js +0 -67
  14. package/lib/formats/capitalization.js +0 -563
  15. package/lib/formats/color.js +0 -165
  16. package/lib/formats/emoji.js +0 -282
  17. package/lib/formats/font-family.js +0 -547
  18. package/lib/formats/heading.js +0 -502
  19. package/lib/formats/image.js +0 -344
  20. package/lib/formats/import.js +0 -385
  21. package/lib/formats/indent.js +0 -297
  22. package/lib/formats/italic.js +0 -27
  23. package/lib/formats/line-height.js +0 -558
  24. package/lib/formats/link.js +0 -251
  25. package/lib/formats/list.js +0 -635
  26. package/lib/formats/strike.js +0 -31
  27. package/lib/formats/subscript.js +0 -36
  28. package/lib/formats/superscript.js +0 -35
  29. package/lib/formats/table.js +0 -288
  30. package/lib/formats/tag.js +0 -304
  31. package/lib/formats/text-align.js +0 -421
  32. package/lib/formats/text-size.js +0 -497
  33. package/lib/formats/underline.js +0 -30
  34. package/lib/formats/video.js +0 -372
  35. package/lib/modules/block-toolbar.js +0 -628
  36. package/lib/modules/code-view.js +0 -434
  37. package/lib/modules/history.js +0 -410
  38. package/lib/modules/resize-handles.js +0 -677
  39. package/lib/modules/table-toolbar.js +0 -618
  40. package/lib/modules/toolbar.js +0 -424
  41. package/lib/styles-loader.js +0 -144
  42. package/lib/styles.css +0 -2123
  43. package/lib/ui/color-picker.js +0 -296
  44. package/lib/ui/customselect.js +0 -319
  45. package/lib/ui/emoji-picker.js +0 -196
  46. package/lib/ui/icons.js +0 -413
  47. package/lib/ui/image-popup.js +0 -444
  48. package/lib/ui/import-popup.js +0 -288
  49. package/lib/ui/link-popup.js +0 -191
  50. package/lib/ui/list-picker.js +0 -307
  51. package/lib/ui/select-button.js +0 -61
  52. package/lib/ui/table-popup.js +0 -171
  53. package/lib/ui/tag-popup.js +0 -249
  54. package/lib/ui/text-align-picker.js +0 -281
  55. package/lib/ui/video-popup.js +0 -422
  56. package/lib/utils/history-helper.js +0 -50
  57. package/lib/utils/popup-helper.js +0 -219
  58. package/lib/utils/popup-positioning.js +0 -231
@@ -1,296 +0,0 @@
1
- /**
2
- * Color Picker Component - Simple color picker with popup
3
- */
4
- import IconUtils from './icons.js';
5
- import { appendPopup, calculatePopupPosition, setPopupPosition } from '../utils/popup-helper.js';
6
-
7
- class ColorPicker {
8
- constructor(options = {}) {
9
- this.options = {
10
- colors: [
11
- '#000000', '#333333', '#666666', '#999999', '#cccccc', '#eeeeee',
12
- '#ff0000', '#ff6600', '#ffcc00', '#ffff00', '#99ff00', '#00ff00',
13
- '#00ffcc', '#00ccff', '#0066ff', '#0000ff', '#6600ff', '#cc00ff',
14
- '#ff00cc', '#ff0066', '#800000', '#ff8000', '#808000', '#008000',
15
- '#008080', '#0080ff', '#004080', '#800080', '#804080', '#ff0080'
16
- ],
17
- customColorEnabled: true,
18
- onColorSelect: null,
19
- editor: null,
20
- ...options
21
- };
22
-
23
- this.popup = null;
24
- this.isVisible = false;
25
- this.currentColor = '#000000';
26
- this.clickOutsideHandler = null;
27
-
28
- this.createColorPicker();
29
- }
30
-
31
- /**
32
- * Create color picker popup
33
- */
34
- createColorPicker() {
35
- // Create popup
36
- this.popup = document.createElement('div');
37
- this.popup.className = 'color-picker-popup';
38
-
39
- // Create color grid
40
- this.createColorGrid();
41
-
42
- // Create custom color input if enabled
43
- if (this.options.customColorEnabled) {
44
- this.createCustomColorInput();
45
- }
46
-
47
- // Add popup to container
48
- appendPopup(this.popup);
49
-
50
- // Prevent focus loss when clicking on popup
51
- if (this.options.editor && typeof this.options.editor.preventFocusLoss === 'function') {
52
- this.options.editor.preventFocusLoss(this.popup);
53
- }
54
- }
55
-
56
- /**
57
- * Create color grid
58
- */
59
- createColorGrid() {
60
- const grid = document.createElement('div');
61
- grid.className = 'color-grid';
62
-
63
- this.options.colors.forEach(color => {
64
- const colorButton = document.createElement('button');
65
- colorButton.type = 'button';
66
- colorButton.className = 'color-button';
67
- colorButton.style.backgroundColor = color;
68
- colorButton.dataset.color = color;
69
- colorButton.title = color;
70
-
71
- colorButton.addEventListener('click', (e) => {
72
- e.preventDefault();
73
- e.stopPropagation();
74
- this.selectColor(color);
75
- // Maintain editor focus after color selection
76
- if (this.options.editor) {
77
- setTimeout(() => this.options.editor.focus(), 0);
78
- }
79
- });
80
-
81
- grid.appendChild(colorButton);
82
- });
83
-
84
- this.popup.appendChild(grid);
85
- }
86
-
87
- /**
88
- * Create custom color input
89
- */
90
- createCustomColorInput() {
91
- const customContainer = document.createElement('div');
92
- customContainer.className = 'custom-color-container';
93
-
94
- // No color button
95
- const noColorButton = document.createElement('button');
96
- noColorButton.type = 'button';
97
- noColorButton.className = 'color-button no-color-button';
98
- noColorButton.title = 'No Color';
99
- noColorButton.style.backgroundColor = 'transparent';
100
-
101
- // Add icon to button
102
- const noColorIcon = IconUtils.createIconElement('no-color', {
103
- width: '24',
104
- height: '24'
105
- });
106
- noColorButton.appendChild(noColorIcon);
107
-
108
- noColorButton.addEventListener('click', (e) => {
109
- e.preventDefault();
110
- e.stopPropagation();
111
- this.selectColor('transparent');
112
- // Maintain editor focus after color selection
113
- if (this.options.editor) {
114
- setTimeout(() => this.options.editor.focus(), 0);
115
- }
116
- });
117
-
118
- // White button
119
- const whiteButton = document.createElement('button');
120
- whiteButton.type = 'button';
121
- whiteButton.className = 'color-button white-button';
122
- whiteButton.style.backgroundColor = '#ffffff';
123
- whiteButton.style.border = '1px solid #ccc';
124
- whiteButton.title = 'White';
125
-
126
- whiteButton.addEventListener('click', (e) => {
127
- e.preventDefault();
128
- e.stopPropagation();
129
- this.selectColor('#ffffff');
130
- // Maintain editor focus after color selection
131
- if (this.options.editor) {
132
- setTimeout(() => this.options.editor.focus(), 0);
133
- }
134
- });
135
-
136
- // Black button
137
- const blackButton = document.createElement('button');
138
- blackButton.type = 'button';
139
- blackButton.className = 'color-button black-button';
140
- blackButton.style.backgroundColor = '#000000';
141
- blackButton.title = 'Black';
142
-
143
- blackButton.addEventListener('click', (e) => {
144
- e.preventDefault();
145
- e.stopPropagation();
146
- this.selectColor('#000000');
147
- // Maintain editor focus after color selection
148
- if (this.options.editor) {
149
- setTimeout(() => this.options.editor.focus(), 0);
150
- }
151
- });
152
-
153
- // Custom color button with hidden input
154
- const customColorButton = document.createElement('button');
155
- customColorButton.type = 'button';
156
- customColorButton.className = 'color-button custom-color-button';
157
- customColorButton.title = 'Custom Color';
158
- customColorButton.style.backgroundColor = 'transparent';
159
- customColorButton.style.border = '1px solid #ccc';
160
- customColorButton.style.font = 'none !important';
161
- // Add icon to button
162
- const iconElement = IconUtils.createIconElement('custom-color', {
163
- width: '16px',
164
- height: '16px'
165
- });
166
- customColorButton.appendChild(iconElement);
167
-
168
- const customInput = document.createElement('input');
169
- customInput.type = 'color';
170
- customInput.className = 'custom-color-input';
171
- customInput.value = this.currentColor;
172
- customInput.style.visibility = 'hidden';
173
- customInput.style.pointerEvents = 'none'; // ngăn không cho click
174
- customInput.style.opacity = '0'; // ẩn hẳn về mặt thị giác
175
- customColorButton.addEventListener('click', (e) => {
176
- customInput.style.visibility = 'visible';
177
- customInput.style.pointerEvents = 'auto';
178
- customInput.style.opacity = '1';
179
- e.preventDefault();
180
- e.stopPropagation();
181
- customInput.click();
182
-
183
- });
184
-
185
- customInput.addEventListener('change', (e) => {
186
- customInput.style.visibility = 'hidden';
187
- customInput.style.pointerEvents = 'none'; // ngăn không cho click
188
- customInput.style.opacity = '0'; // ẩn hẳn về mặt thị giác
189
- this.selectColor(e.target.value);
190
- // Maintain editor focus after color selection
191
- if (this.options.editor) {
192
- setTimeout(() => this.options.editor.focus(), 0);
193
- }
194
- });
195
-
196
- customContainer.appendChild(noColorButton);
197
- customContainer.appendChild(whiteButton);
198
- customContainer.appendChild(blackButton);
199
- customContainer.appendChild(customColorButton);
200
- customContainer.appendChild(customInput);
201
-
202
- this.popup.appendChild(customContainer);
203
- }
204
-
205
- /**
206
- * Setup click outside handler
207
- */
208
- setupClickOutside() {
209
- if (this.clickOutsideHandler) {
210
- document.removeEventListener('click', this.clickOutsideHandler);
211
- }
212
-
213
- this.clickOutsideHandler = (e) => {
214
- if (!this.popup.contains(e.target)) {
215
- this.hide();
216
- }
217
- };
218
-
219
- // Add slight delay to avoid immediate close
220
- setTimeout(() => {
221
- document.addEventListener('click', this.clickOutsideHandler);
222
- }, 100);
223
- }
224
-
225
- /**
226
- * Remove click outside handler
227
- */
228
- removeClickOutside() {
229
- if (this.clickOutsideHandler) {
230
- document.removeEventListener('click', this.clickOutsideHandler);
231
- this.clickOutsideHandler = null;
232
- }
233
- }
234
-
235
- /**
236
- * Show color picker popup
237
- * @param {HTMLElement} anchor - Element to position popup relative to
238
- */
239
- show(anchor) {
240
- if (!anchor) return;
241
-
242
- // Ensure popup is in DOM
243
- if (!document.body.contains(this.popup)) {
244
- appendPopup(this.popup);
245
- }
246
-
247
- // Calculate and set popup position
248
- const position = calculatePopupPosition(anchor, this.popup, {
249
- offsetY: 5,
250
- offsetX: 0
251
- });
252
- setPopupPosition(this.popup, position);
253
-
254
- // Show popup by adding visible class
255
- this.popup.classList.add('visible');
256
- this.isVisible = true;
257
-
258
- // Setup click outside handler
259
- this.setupClickOutside();
260
- }
261
-
262
- /**
263
- * Hide color picker popup
264
- */
265
- hide() {
266
- this.popup.classList.remove('visible');
267
- this.isVisible = false;
268
- this.removeClickOutside();
269
- }
270
-
271
- /**
272
- * Select color and trigger callback
273
- * @param {string} color - Selected color
274
- */
275
- selectColor(color) {
276
- this.currentColor = color;
277
-
278
- if (this.options.onColorSelect) {
279
- this.options.onColorSelect(color);
280
- }
281
-
282
- this.hide();
283
- }
284
-
285
- /**
286
- * Destroy color picker
287
- */
288
- destroy() {
289
- this.removeClickOutside();
290
- if (this.popup && this.popup.parentNode) {
291
- this.popup.parentNode.removeChild(this.popup);
292
- }
293
- }
294
- }
295
-
296
- export default ColorPicker;
@@ -1,319 +0,0 @@
1
- import IconUtils from './icons.js';
2
- import { appendPopup, calculatePopupPosition, setPopupPosition } from '../utils/popup-helper.js';
3
-
4
- /**
5
- * Custom Select Component - Reusable dropdown/popup select component
6
- */
7
- class CustomSelect {
8
- constructor(options = {}) {
9
- this.options = {
10
- items: [], // Array of items to display
11
- onItemSelect: null, // Callback when item is selected
12
- displayProperty: 'label', // Property to display as text
13
- valueProperty: 'value', // Property to use as value
14
- className: 'custom-select', // CSS class for the popup
15
- width: 200, // Popup width
16
- height: 280, // Popup height
17
- ...options
18
- };
19
-
20
- this.popup = null;
21
- this.isVisible = false;
22
- this.currentValue = null;
23
- this.clickOutsideHandler = null;
24
- this.initialized = false;
25
-
26
- this.createSelect();
27
- }
28
-
29
- /**
30
- * Create select popup
31
- */
32
- createSelect() {
33
- // Create popup
34
- this.popup = document.createElement('div');
35
- this.popup.className = `${this.options.className}-popup`;
36
-
37
- // Add popup to container
38
- appendPopup(this.popup);
39
-
40
- // Initialize async
41
- this.init();
42
- }
43
-
44
- /**
45
- * Initialize component with async operations
46
- */
47
- async init() {
48
- // Create item list
49
- await this.createItemList();
50
- this.initialized = true;
51
- }
52
-
53
- /**
54
- * Create item list
55
- */
56
- async createItemList() {
57
- const list = document.createElement('div');
58
- list.className = 'item-list';
59
-
60
- // Get check icon
61
- const checkIconSvg = IconUtils.getIcon('check');
62
-
63
- this.options.items.forEach(item => {
64
- const itemButton = document.createElement('button');
65
- itemButton.type = 'button';
66
- itemButton.className = 'custom-select-item-button';
67
- itemButton.dataset.value = this.getItemValue(item);
68
-
69
- // Create item content with text and checkmark
70
- const itemText = document.createElement('div');
71
- itemText.className = 'item-text';
72
- itemText.innerHTML = this.getItemDisplay(item);
73
-
74
- const checkmark = document.createElement('span');
75
- checkmark.className = 'item-checkmark';
76
- checkmark.innerHTML = checkIconSvg || '';
77
-
78
- itemButton.appendChild(itemText);
79
- itemButton.appendChild(checkmark);
80
-
81
- itemButton.addEventListener('click', (e) => {
82
- e.preventDefault();
83
- e.stopPropagation();
84
- this.selectItem(item);
85
- });
86
-
87
- list.appendChild(itemButton);
88
- });
89
-
90
- this.popup.appendChild(list);
91
- }
92
-
93
- /**
94
- * Get display text for item
95
- */
96
- getItemDisplay(item) {
97
- return item[this.options.displayProperty] || item.toString();
98
- }
99
-
100
- /**
101
- * Get value for item
102
- */
103
- getItemValue(item) {
104
- return item[this.options.valueProperty] || item[this.options.displayProperty] || item;
105
- }
106
-
107
- /**
108
- * Update items in the select
109
- */
110
- async updateItems(items) {
111
- this.options.items = items;
112
-
113
- // Remove existing list
114
- const existingList = this.popup.querySelector('.item-list');
115
- if (existingList) {
116
- existingList.remove();
117
- }
118
-
119
- // Create new list
120
- await this.createItemList();
121
- }
122
-
123
- /**
124
- * Setup click outside handler
125
- */
126
- setupClickOutside() {
127
- if (this.clickOutsideHandler) {
128
- document.removeEventListener('click', this.clickOutsideHandler);
129
- }
130
-
131
- this.clickOutsideHandler = (e) => {
132
- // Don't hide if clicking on block toolbar or its buttons
133
- if (e.target.closest('.block-toolbar')) {
134
- return;
135
- }
136
-
137
- if (!this.popup.contains(e.target)) {
138
- this.hide();
139
- }
140
- };
141
-
142
- // Add slight delay to avoid immediate close
143
- setTimeout(() => {
144
- document.addEventListener('click', this.clickOutsideHandler);
145
- }, 100);
146
- }
147
-
148
- /**
149
- * Remove click outside handler
150
- */
151
- removeClickOutside() {
152
- if (this.clickOutsideHandler) {
153
- document.removeEventListener('click', this.clickOutsideHandler);
154
- this.clickOutsideHandler = null;
155
- }
156
- }
157
-
158
- /**
159
- * Setup scroll handler to update popup position
160
- */
161
- setupScrollHandler() {
162
- if (this.scrollHandler) {
163
- window.removeEventListener('scroll', this.scrollHandler);
164
- }
165
-
166
- this.scrollHandler = () => {
167
- if (this.isVisible) {
168
- this.updatePosition();
169
- }
170
- };
171
-
172
- window.addEventListener('scroll', this.scrollHandler);
173
- }
174
-
175
- /**
176
- * Remove scroll handler
177
- */
178
- removeScrollHandler() {
179
- if (this.scrollHandler) {
180
- window.removeEventListener('scroll', this.scrollHandler);
181
- this.scrollHandler = null;
182
- }
183
- }
184
-
185
- /**
186
- * Show select popup
187
- */
188
- async show(anchor) {
189
- if (!anchor) return;
190
-
191
- // Wait for initialization if not ready
192
- if (!this.initialized) {
193
- await new Promise(resolve => {
194
- const checkInit = () => {
195
- if (this.initialized) {
196
- resolve();
197
- } else {
198
- setTimeout(checkInit, 10);
199
- }
200
- };
201
- checkInit();
202
- });
203
- }
204
-
205
- // Ensure popup is in DOM
206
- if (!document.body.contains(this.popup)) {
207
- appendPopup(this.popup);
208
- }
209
-
210
- // Update current selection highlight
211
- this.highlightCurrentItem(this.currentValue);
212
-
213
- // Calculate and set popup position
214
- const position = calculatePopupPosition(anchor, this.popup, {
215
- offsetY: 5,
216
- offsetX: 0
217
- });
218
- setPopupPosition(this.popup, position);
219
-
220
- // Show popup by adding visible class
221
- this.popup.classList.add('visible');
222
- this.isVisible = true;
223
-
224
- // Setup click outside handler
225
- this.setupClickOutside();
226
-
227
- // Setup scroll handler to update position
228
- this.setupScrollHandler();
229
-
230
- // Store reference to anchor for potential repositioning
231
- this.currentAnchor = anchor;
232
- }
233
-
234
- /**
235
- * Hide select popup
236
- */
237
- hide() {
238
- this.popup.classList.remove('visible');
239
- this.isVisible = false;
240
- this.removeClickOutside();
241
- this.currentAnchor = null;
242
- }
243
-
244
- /**
245
- * Update popup position based on current anchor
246
- */
247
- updatePosition() {
248
- if (this.isVisible && this.currentAnchor) {
249
- // Calculate and set popup position
250
- const position = calculatePopupPosition(this.currentAnchor, this.popup, {
251
- offsetY: 5,
252
- offsetX: 0
253
- });
254
- setPopupPosition(this.popup, position);
255
- }
256
- }
257
-
258
- /**
259
- * Set current value
260
- */
261
- setCurrentValue(value) {
262
- this.currentValue = value;
263
- this.highlightCurrentItem(value);
264
- }
265
-
266
- /**
267
- * Highlight current item in the list
268
- */
269
- highlightCurrentItem(value) {
270
- // Remove previous highlights
271
- this.popup.querySelectorAll('.custom-select-item-button.current').forEach(btn => {
272
- btn.classList.remove('current');
273
- });
274
-
275
- // Highlight current item - find by comparing dataset.value directly
276
- if (value != null) {
277
- const buttons = this.popup.querySelectorAll('.custom-select-item-button');
278
- for (const button of buttons) {
279
- if (button.dataset.value === value.toString()) {
280
- button.classList.add('current');
281
- break;
282
- }
283
- }
284
- }
285
- }
286
-
287
- /**
288
- * Select item and trigger callback
289
- */
290
- selectItem(item) {
291
- const value = this.getItemValue(item);
292
- this.currentValue = value;
293
-
294
- if (this.options.onItemSelect) {
295
- this.options.onItemSelect(value, item);
296
- }
297
-
298
- this.hide();
299
- }
300
-
301
- /**
302
- * Get current selected value
303
- */
304
- getCurrentValue() {
305
- return this.currentValue;
306
- }
307
-
308
- /**
309
- * Destroy select component
310
- */
311
- destroy() {
312
- this.removeClickOutside();
313
- if (this.popup && this.popup.parentNode) {
314
- this.popup.parentNode.removeChild(this.popup);
315
- }
316
- }
317
- }
318
-
319
- export default CustomSelect;