@oix1987/yjd 1.0.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 (55) hide show
  1. package/README.md +91 -0
  2. package/index.d.ts +103 -0
  3. package/index.js +221 -0
  4. package/lib/core/editor.js +1175 -0
  5. package/lib/core/format.js +542 -0
  6. package/lib/core/module.js +81 -0
  7. package/lib/core/registry.js +152 -0
  8. package/lib/formats/background.js +212 -0
  9. package/lib/formats/bold.js +67 -0
  10. package/lib/formats/capitalization.js +563 -0
  11. package/lib/formats/color.js +165 -0
  12. package/lib/formats/emoji.js +282 -0
  13. package/lib/formats/font-family.js +547 -0
  14. package/lib/formats/heading.js +502 -0
  15. package/lib/formats/image.js +344 -0
  16. package/lib/formats/import.js +385 -0
  17. package/lib/formats/indent.js +297 -0
  18. package/lib/formats/italic.js +27 -0
  19. package/lib/formats/line-height.js +558 -0
  20. package/lib/formats/link.js +251 -0
  21. package/lib/formats/list.js +635 -0
  22. package/lib/formats/strike.js +31 -0
  23. package/lib/formats/subscript.js +36 -0
  24. package/lib/formats/superscript.js +35 -0
  25. package/lib/formats/table.js +288 -0
  26. package/lib/formats/tag.js +304 -0
  27. package/lib/formats/text-align.js +421 -0
  28. package/lib/formats/text-size.js +497 -0
  29. package/lib/formats/underline.js +30 -0
  30. package/lib/formats/video.js +372 -0
  31. package/lib/modules/block-toolbar.js +628 -0
  32. package/lib/modules/code-view.js +434 -0
  33. package/lib/modules/history.js +410 -0
  34. package/lib/modules/resize-handles.js +677 -0
  35. package/lib/modules/table-toolbar.js +618 -0
  36. package/lib/modules/toolbar.js +424 -0
  37. package/lib/styles-loader.js +144 -0
  38. package/lib/styles.css +2123 -0
  39. package/lib/ui/color-picker.js +296 -0
  40. package/lib/ui/customselect.js +319 -0
  41. package/lib/ui/emoji-picker.js +196 -0
  42. package/lib/ui/icons.js +413 -0
  43. package/lib/ui/image-popup.js +444 -0
  44. package/lib/ui/import-popup.js +288 -0
  45. package/lib/ui/link-popup.js +191 -0
  46. package/lib/ui/list-picker.js +307 -0
  47. package/lib/ui/select-button.js +61 -0
  48. package/lib/ui/table-popup.js +171 -0
  49. package/lib/ui/tag-popup.js +249 -0
  50. package/lib/ui/text-align-picker.js +281 -0
  51. package/lib/ui/video-popup.js +422 -0
  52. package/lib/utils/history-helper.js +50 -0
  53. package/lib/utils/popup-helper.js +219 -0
  54. package/lib/utils/popup-positioning.js +231 -0
  55. package/package.json +26 -0
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Responsive Popup Positioning Utility
3
+ * Handles positioning of popups to ensure they stay within viewport on mobile devices
4
+ */
5
+ export class PopupPositioning {
6
+ /**
7
+ * Calculate optimal position for popup to stay within viewport
8
+ * @param {HTMLElement} anchor - The anchor element
9
+ * @param {HTMLElement} popup - The popup element
10
+ * @param {Object} options - Positioning options
11
+ * @returns {Object} - Calculated position {top, left, transform}
12
+ */
13
+ static calculatePosition(anchor, popup, options = {}) {
14
+ const {
15
+ offsetX = 0,
16
+ offsetY = 5,
17
+ preferredPosition = 'bottom-right', // 'bottom-right', 'bottom-left', 'top-right', 'top-left'
18
+ maxWidth = null,
19
+ maxHeight = null
20
+ } = options;
21
+
22
+ // Get viewport dimensions
23
+ const viewportWidth = window.innerWidth;
24
+ const viewportHeight = window.innerHeight;
25
+ const scrollX = window.scrollX;
26
+ const scrollY = window.scrollY;
27
+
28
+ // Get anchor dimensions
29
+ const anchorRect = anchor.getBoundingClientRect();
30
+
31
+ // Get popup dimensions (measure if not already rendered)
32
+ let popupWidth = popup.offsetWidth;
33
+ let popupHeight = popup.offsetHeight;
34
+
35
+ // If popup is not yet visible, temporarily show it to measure
36
+ let wasVisible = popup.classList.contains('visible');
37
+ if (!wasVisible) {
38
+ popup.style.visibility = 'hidden';
39
+ popup.style.position = 'absolute';
40
+ popup.style.top = '0';
41
+ popup.style.left = '0';
42
+ popup.classList.add('visible');
43
+ }
44
+
45
+ // Measure popup dimensions
46
+ popupWidth = popup.offsetWidth;
47
+ popupHeight = popup.offsetHeight;
48
+
49
+ // Apply max constraints
50
+ if (maxWidth && popupWidth > maxWidth) {
51
+ popupWidth = maxWidth;
52
+ }
53
+ if (maxHeight && popupHeight > maxHeight) {
54
+ popupHeight = maxHeight;
55
+ }
56
+
57
+ // Hide popup if it was hidden before
58
+ if (!wasVisible) {
59
+ popup.classList.remove('visible');
60
+ popup.style.visibility = '';
61
+ }
62
+
63
+ // Calculate base positions for different orientations
64
+ const positions = {
65
+ 'bottom-right': {
66
+ top: anchorRect.bottom + scrollY + offsetY,
67
+ left: anchorRect.left + scrollX + offsetX
68
+ },
69
+ 'bottom-left': {
70
+ top: anchorRect.bottom + scrollY + offsetY,
71
+ left: anchorRect.right + scrollX - popupWidth - offsetX
72
+ },
73
+ 'top-right': {
74
+ top: anchorRect.top + scrollY - popupHeight - offsetY,
75
+ left: anchorRect.left + scrollX + offsetX
76
+ },
77
+ 'top-left': {
78
+ top: anchorRect.top + scrollY - popupHeight - offsetY,
79
+ left: anchorRect.right + scrollX - popupWidth - offsetX
80
+ }
81
+ };
82
+
83
+ // Start with preferred position
84
+ let position = positions[preferredPosition];
85
+ let transform = '';
86
+
87
+ // Check if popup fits in preferred position
88
+ const fitsInPreferred = this.checkFitsInViewport(position, popupWidth, popupHeight, viewportWidth, viewportHeight, scrollX, scrollY);
89
+
90
+ if (!fitsInPreferred) {
91
+ // Try alternative positions
92
+ const alternativePositions = this.getAlternativePositions(preferredPosition);
93
+
94
+ for (const altPosition of alternativePositions) {
95
+ const testPosition = positions[altPosition];
96
+ if (this.checkFitsInViewport(testPosition, popupWidth, popupHeight, viewportWidth, viewportHeight, scrollX, scrollY)) {
97
+ position = testPosition;
98
+ break;
99
+ }
100
+ }
101
+
102
+ // If no position fits, use the best available with adjustments
103
+ if (!this.checkFitsInViewport(position, popupWidth, popupHeight, viewportWidth, viewportHeight, scrollX, scrollY)) {
104
+ position = this.adjustToFitViewport(position, popupWidth, popupHeight, viewportWidth, viewportHeight, scrollX, scrollY);
105
+ }
106
+ }
107
+
108
+ // For mobile devices, add additional constraints
109
+ if (viewportWidth <= 768) {
110
+ position = this.applyMobileConstraints(position, popupWidth, popupHeight, viewportWidth, viewportHeight, scrollX, scrollY);
111
+ }
112
+
113
+ return {
114
+ top: position.top,
115
+ left: position.left,
116
+ transform: transform
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Check if position fits within viewport
122
+ */
123
+ static checkFitsInViewport(position, width, height, viewportWidth, viewportHeight, scrollX, scrollY) {
124
+ const right = position.left + width;
125
+ const bottom = position.top + height;
126
+
127
+ return position.left >= scrollX &&
128
+ position.top >= scrollY &&
129
+ right <= scrollX + viewportWidth &&
130
+ bottom <= scrollY + viewportHeight;
131
+ }
132
+
133
+ /**
134
+ * Get alternative positions to try
135
+ */
136
+ static getAlternativePositions(preferredPosition) {
137
+ const alternatives = {
138
+ 'bottom-right': ['bottom-left', 'top-right', 'top-left'],
139
+ 'bottom-left': ['bottom-right', 'top-left', 'top-right'],
140
+ 'top-right': ['top-left', 'bottom-right', 'bottom-left'],
141
+ 'top-left': ['top-right', 'bottom-left', 'bottom-right']
142
+ };
143
+
144
+ return alternatives[preferredPosition] || ['bottom-right', 'bottom-left', 'top-right', 'top-left'];
145
+ }
146
+
147
+ /**
148
+ * Adjust position to fit within viewport
149
+ */
150
+ static adjustToFitViewport(position, width, height, viewportWidth, viewportHeight, scrollX, scrollY) {
151
+ let { top, left } = position;
152
+
153
+ // Adjust horizontal position
154
+ if (left < scrollX) {
155
+ left = scrollX + 10;
156
+ } else if (left + width > scrollX + viewportWidth) {
157
+ left = scrollX + viewportWidth - width - 10;
158
+ }
159
+
160
+ // Adjust vertical position
161
+ if (top < scrollY) {
162
+ top = scrollY + 10;
163
+ } else if (top + height > scrollY + viewportHeight) {
164
+ top = scrollY + viewportHeight - height - 10;
165
+ }
166
+
167
+ return { top, left };
168
+ }
169
+
170
+ /**
171
+ * Apply mobile-specific constraints
172
+ */
173
+ static applyMobileConstraints(position, width, height, viewportWidth, viewportHeight, scrollX, scrollY) {
174
+ let { top, left } = position;
175
+
176
+ // On mobile, prefer center positioning if popup is too large
177
+ if (width > viewportWidth * 0.9) {
178
+ left = scrollX + (viewportWidth - width) / 2;
179
+ }
180
+
181
+ if (height > viewportHeight * 0.8) {
182
+ top = scrollY + (viewportHeight - height) / 2;
183
+ }
184
+
185
+ // Ensure minimum margins
186
+ const minMargin = 10;
187
+ if (left < scrollX + minMargin) left = scrollX + minMargin;
188
+ if (top < scrollY + minMargin) top = scrollY + minMargin;
189
+ if (left + width > scrollX + viewportWidth - minMargin) {
190
+ left = scrollX + viewportWidth - width - minMargin;
191
+ }
192
+ if (top + height > scrollY + viewportHeight - minMargin) {
193
+ top = scrollY + viewportHeight - height - minMargin;
194
+ }
195
+
196
+ return { top, left };
197
+ }
198
+
199
+ /**
200
+ * Apply calculated position to popup element
201
+ */
202
+ static applyPosition(popup, position) {
203
+ popup.style.position = 'absolute';
204
+ popup.style.top = `${position.top}px`;
205
+ popup.style.left = `${position.left}px`;
206
+
207
+ if (position.transform) {
208
+ popup.style.transform = position.transform;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Check if device is mobile
214
+ */
215
+ static isMobile() {
216
+ return window.innerWidth <= 768;
217
+ }
218
+
219
+ /**
220
+ * Get recommended max dimensions for mobile
221
+ */
222
+ static getMobileMaxDimensions() {
223
+ const viewportWidth = window.innerWidth;
224
+ const viewportHeight = window.innerHeight;
225
+
226
+ return {
227
+ maxWidth: Math.min(viewportWidth * 0.95, 350),
228
+ maxHeight: Math.min(viewportHeight * 0.8, 400)
229
+ };
230
+ }
231
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@oix1987/yjd",
3
+ "version": "1.0.0",
4
+ "description": "A powerful rich text editor with real-time content change tracking for web applications using base javascript",
5
+ "license": "ISC",
6
+ "author": "Oix1987",
7
+ "type": "module",
8
+ "main": "dist/rich-editor.min.js",
9
+ "module": "lib/index.js",
10
+ "types": "index.d.ts",
11
+ "files": [
12
+ "lib",
13
+ "assets",
14
+ "dist",
15
+ "index.js",
16
+ "index.d.ts"
17
+ ],
18
+ "scripts": {
19
+ "test": "echo \"Error: no test specified\" && exit 1",
20
+ "build": "rollup -c"
21
+ },
22
+ "devDependencies": {
23
+ "@rollup/plugin-terser": "^0.4.4",
24
+ "rollup": "^4.46.3"
25
+ }
26
+ }