quasar-ui-danx 0.5.0 → 0.5.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 (81) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/dist/danx.es.js +16119 -10641
  3. package/dist/danx.es.js.map +1 -1
  4. package/dist/danx.umd.js +202 -123
  5. package/dist/danx.umd.js.map +1 -1
  6. package/dist/style.css +1 -1
  7. package/package.json +8 -1
  8. package/src/components/Utility/Buttons/ActionButton.vue +15 -5
  9. package/src/components/Utility/Code/CodeViewer.vue +41 -16
  10. package/src/components/Utility/Code/CodeViewerCollapsed.vue +2 -0
  11. package/src/components/Utility/Code/CodeViewerFooter.vue +3 -1
  12. package/src/components/Utility/Code/LanguageBadge.vue +278 -5
  13. package/src/components/Utility/Code/MarkdownContent.vue +31 -163
  14. package/src/components/Utility/Code/index.ts +3 -0
  15. package/src/components/Utility/Markdown/ContextMenu.vue +314 -0
  16. package/src/components/Utility/Markdown/HotkeyHelpPopover.vue +259 -0
  17. package/src/components/Utility/Markdown/LineTypeMenu.vue +226 -0
  18. package/src/components/Utility/Markdown/LinkPopover.vue +331 -0
  19. package/src/components/Utility/Markdown/MarkdownEditor.vue +233 -0
  20. package/src/components/Utility/Markdown/MarkdownEditorContent.vue +296 -0
  21. package/src/components/Utility/Markdown/MarkdownEditorFooter.vue +50 -0
  22. package/src/components/Utility/Markdown/TablePopover.vue +420 -0
  23. package/src/components/Utility/Markdown/index.ts +11 -0
  24. package/src/components/Utility/Markdown/types.ts +27 -0
  25. package/src/components/Utility/Widgets/LabelPillWidget.vue +20 -0
  26. package/src/components/Utility/index.ts +1 -0
  27. package/src/composables/index.ts +1 -0
  28. package/src/composables/markdown/features/useBlockquotes.spec.ts +428 -0
  29. package/src/composables/markdown/features/useBlockquotes.ts +248 -0
  30. package/src/composables/markdown/features/useCodeBlockManager.ts +369 -0
  31. package/src/composables/markdown/features/useCodeBlocks.spec.ts +805 -0
  32. package/src/composables/markdown/features/useCodeBlocks.ts +774 -0
  33. package/src/composables/markdown/features/useContextMenu.ts +444 -0
  34. package/src/composables/markdown/features/useFocusTracking.ts +116 -0
  35. package/src/composables/markdown/features/useHeadings.spec.ts +834 -0
  36. package/src/composables/markdown/features/useHeadings.ts +290 -0
  37. package/src/composables/markdown/features/useInlineFormatting.spec.ts +705 -0
  38. package/src/composables/markdown/features/useInlineFormatting.ts +402 -0
  39. package/src/composables/markdown/features/useLineTypeMenu.ts +285 -0
  40. package/src/composables/markdown/features/useLinks.spec.ts +388 -0
  41. package/src/composables/markdown/features/useLinks.ts +374 -0
  42. package/src/composables/markdown/features/useLists.spec.ts +834 -0
  43. package/src/composables/markdown/features/useLists.ts +747 -0
  44. package/src/composables/markdown/features/usePopoverManager.ts +181 -0
  45. package/src/composables/markdown/features/useTables.spec.ts +1601 -0
  46. package/src/composables/markdown/features/useTables.ts +1107 -0
  47. package/src/composables/markdown/index.ts +16 -0
  48. package/src/composables/markdown/useMarkdownEditor.spec.ts +332 -0
  49. package/src/composables/markdown/useMarkdownEditor.ts +1077 -0
  50. package/src/composables/markdown/useMarkdownHotkeys.spec.ts +791 -0
  51. package/src/composables/markdown/useMarkdownHotkeys.ts +266 -0
  52. package/src/composables/markdown/useMarkdownSelection.ts +219 -0
  53. package/src/composables/markdown/useMarkdownSync.ts +549 -0
  54. package/src/composables/useCodeFormat.ts +17 -10
  55. package/src/composables/useCodeViewerEditor.spec.ts +655 -0
  56. package/src/composables/useCodeViewerEditor.ts +174 -20
  57. package/src/helpers/formats/highlightCSS.ts +236 -0
  58. package/src/helpers/formats/highlightHTML.ts +483 -0
  59. package/src/helpers/formats/highlightJavaScript.ts +346 -0
  60. package/src/helpers/formats/highlightSyntax.ts +15 -4
  61. package/src/helpers/formats/index.ts +3 -0
  62. package/src/helpers/formats/markdown/htmlToMarkdown/convertHeadings.ts +41 -0
  63. package/src/helpers/formats/markdown/htmlToMarkdown/index.spec.ts +489 -0
  64. package/src/helpers/formats/markdown/htmlToMarkdown/index.ts +425 -0
  65. package/src/helpers/formats/markdown/index.ts +7 -0
  66. package/src/helpers/formats/markdown/linePatterns.spec.ts +498 -0
  67. package/src/helpers/formats/markdown/linePatterns.ts +172 -0
  68. package/src/styles/danx.scss +3 -3
  69. package/src/styles/index.scss +5 -5
  70. package/src/styles/themes/danx/code.scss +257 -1
  71. package/src/styles/themes/danx/index.scss +10 -10
  72. package/src/styles/themes/danx/markdown.scss +59 -0
  73. package/src/test/helpers/editorTestUtils.spec.ts +296 -0
  74. package/src/test/helpers/editorTestUtils.ts +253 -0
  75. package/src/test/helpers/index.ts +1 -0
  76. package/src/test/highlighters.test.ts +153 -0
  77. package/src/test/setup.test.ts +12 -0
  78. package/src/test/setup.ts +12 -0
  79. package/src/types/widgets.d.ts +2 -2
  80. package/vite.config.js +5 -1
  81. package/vitest.config.ts +19 -0
@@ -0,0 +1,420 @@
1
+ <template>
2
+ <div
3
+ class="dx-table-popover-overlay"
4
+ @click.self="onCancel"
5
+ @keydown.escape="onCancel"
6
+ >
7
+ <div
8
+ ref="popoverRef"
9
+ class="dx-table-popover"
10
+ :style="popoverStyle"
11
+ >
12
+ <div class="popover-header">
13
+ <h3>Insert Table</h3>
14
+ <button
15
+ class="close-btn"
16
+ type="button"
17
+ aria-label="Close"
18
+ @click="onCancel"
19
+ >
20
+ <CloseIcon class="w-4 h-4" />
21
+ </button>
22
+ </div>
23
+
24
+ <div class="popover-content">
25
+ <!-- Visual Grid Selector -->
26
+ <div class="grid-selector">
27
+ <div
28
+ v-for="row in GRID_SIZE"
29
+ :key="row"
30
+ class="grid-row"
31
+ >
32
+ <div
33
+ v-for="col in GRID_SIZE"
34
+ :key="col"
35
+ class="grid-cell"
36
+ :class="{ selected: row <= hoverRows && col <= hoverCols }"
37
+ @mouseenter="onCellHover(row, col)"
38
+ @click="onCellClick(row, col)"
39
+ />
40
+ </div>
41
+ </div>
42
+
43
+ <!-- Dimension Label -->
44
+ <div class="dimension-label">
45
+ {{ hoverRows }} x {{ hoverCols }}
46
+ </div>
47
+
48
+ <!-- Manual Input Divider -->
49
+ <div class="divider">
50
+ <span>or enter manually</span>
51
+ </div>
52
+
53
+ <!-- Manual Input Fields -->
54
+ <div class="manual-inputs">
55
+ <div class="input-group">
56
+ <label for="table-rows">Rows</label>
57
+ <input
58
+ id="table-rows"
59
+ v-model.number="manualRows"
60
+ type="number"
61
+ min="1"
62
+ :max="MAX_ROWS"
63
+ @keydown.enter.prevent="onSubmit"
64
+ @keydown.escape="onCancel"
65
+ >
66
+ </div>
67
+ <div class="input-group">
68
+ <label for="table-cols">Cols</label>
69
+ <input
70
+ id="table-cols"
71
+ v-model.number="manualCols"
72
+ type="number"
73
+ min="1"
74
+ :max="MAX_COLS"
75
+ @keydown.enter.prevent="onSubmit"
76
+ @keydown.escape="onCancel"
77
+ >
78
+ </div>
79
+ </div>
80
+ </div>
81
+
82
+ <div class="popover-footer">
83
+ <button
84
+ type="button"
85
+ class="btn-cancel"
86
+ @click="onCancel"
87
+ >
88
+ Cancel
89
+ </button>
90
+ <button
91
+ type="button"
92
+ class="btn-insert"
93
+ @click="onSubmit"
94
+ >
95
+ Insert
96
+ </button>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </template>
101
+
102
+ <script setup lang="ts">
103
+ import { FaSolidXmark as CloseIcon } from "danx-icon";
104
+ import { computed, onMounted, onUnmounted, ref } from "vue";
105
+ import type { PopoverPosition } from "@/composables/markdown";
106
+
107
+ export interface TablePopoverProps {
108
+ position: PopoverPosition;
109
+ }
110
+
111
+ const GRID_SIZE = 5;
112
+ const MAX_ROWS = 20;
113
+ const MAX_COLS = 10;
114
+ const DEFAULT_SIZE = 3;
115
+
116
+ const props = defineProps<TablePopoverProps>();
117
+
118
+ const emit = defineEmits<{
119
+ submit: [rows: number, cols: number];
120
+ cancel: [];
121
+ }>();
122
+
123
+ // Refs
124
+ const popoverRef = ref<HTMLElement | null>(null);
125
+
126
+ // State
127
+ const hoverRows = ref(DEFAULT_SIZE);
128
+ const hoverCols = ref(DEFAULT_SIZE);
129
+ const manualRows = ref(DEFAULT_SIZE);
130
+ const manualCols = ref(DEFAULT_SIZE);
131
+
132
+ // Calculate popover position (below cursor by default, above if at bottom of viewport)
133
+ const popoverStyle = computed(() => {
134
+ const popoverHeight = 340; // Approximate height
135
+ const popoverWidth = 280;
136
+ const padding = 10;
137
+
138
+ let top = props.position.y + padding;
139
+ let left = props.position.x - (popoverWidth / 2);
140
+
141
+ // Check if popover would extend below viewport
142
+ if (top + popoverHeight > window.innerHeight - padding) {
143
+ // Position above the cursor
144
+ top = props.position.y - popoverHeight - padding;
145
+ }
146
+
147
+ // Ensure popover doesn't go off left edge
148
+ if (left < padding) {
149
+ left = padding;
150
+ }
151
+
152
+ // Ensure popover doesn't go off right edge
153
+ if (left + popoverWidth > window.innerWidth - padding) {
154
+ left = window.innerWidth - popoverWidth - padding;
155
+ }
156
+
157
+ return {
158
+ top: `${top}px`,
159
+ left: `${left}px`
160
+ };
161
+ });
162
+
163
+ // Methods
164
+ function onCellHover(row: number, col: number): void {
165
+ hoverRows.value = row;
166
+ hoverCols.value = col;
167
+ manualRows.value = row;
168
+ manualCols.value = col;
169
+ }
170
+
171
+ function onCellClick(row: number, col: number): void {
172
+ emit("submit", row, col);
173
+ }
174
+
175
+ function onSubmit(): void {
176
+ const rows = Math.min(Math.max(1, manualRows.value), MAX_ROWS);
177
+ const cols = Math.min(Math.max(1, manualCols.value), MAX_COLS);
178
+ emit("submit", rows, cols);
179
+ }
180
+
181
+ function onCancel(): void {
182
+ emit("cancel");
183
+ }
184
+
185
+ // Handle Escape key at document level
186
+ function handleDocumentKeydown(event: KeyboardEvent): void {
187
+ if (event.key === "Escape") {
188
+ onCancel();
189
+ }
190
+ }
191
+
192
+ onMounted(() => {
193
+ document.addEventListener("keydown", handleDocumentKeydown);
194
+ });
195
+
196
+ onUnmounted(() => {
197
+ document.removeEventListener("keydown", handleDocumentKeydown);
198
+ });
199
+ </script>
200
+
201
+ <style lang="scss">
202
+ .dx-table-popover-overlay {
203
+ position: fixed;
204
+ inset: 0;
205
+ z-index: 1000;
206
+ background: rgba(0, 0, 0, 0.3);
207
+ backdrop-filter: blur(1px);
208
+ }
209
+
210
+ .dx-table-popover {
211
+ position: fixed;
212
+ background: #2d2d2d;
213
+ border: 1px solid #404040;
214
+ border-radius: 0.5rem;
215
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
216
+ width: 280px;
217
+ overflow: hidden;
218
+ display: flex;
219
+ flex-direction: column;
220
+
221
+ .popover-header {
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: space-between;
225
+ padding: 0.875rem 1rem;
226
+ border-bottom: 1px solid #404040;
227
+
228
+ h3 {
229
+ margin: 0;
230
+ font-size: 0.9375rem;
231
+ font-weight: 600;
232
+ color: #f3f4f6;
233
+ }
234
+
235
+ .close-btn {
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ width: 1.5rem;
240
+ height: 1.5rem;
241
+ padding: 0;
242
+ background: transparent;
243
+ border: none;
244
+ border-radius: 0.25rem;
245
+ color: #9ca3af;
246
+ cursor: pointer;
247
+ transition: all 0.15s ease;
248
+
249
+ &:hover {
250
+ background: rgba(255, 255, 255, 0.1);
251
+ color: #f3f4f6;
252
+ }
253
+ }
254
+ }
255
+
256
+ .popover-content {
257
+ padding: 1rem;
258
+ display: flex;
259
+ flex-direction: column;
260
+ align-items: center;
261
+ gap: 0.75rem;
262
+ }
263
+
264
+ .grid-selector {
265
+ display: flex;
266
+ flex-direction: column;
267
+ gap: 3px;
268
+ padding: 0.5rem;
269
+ background: #1e1e1e;
270
+ border-radius: 0.375rem;
271
+ }
272
+
273
+ .grid-row {
274
+ display: flex;
275
+ gap: 3px;
276
+ }
277
+
278
+ .grid-cell {
279
+ width: 28px;
280
+ height: 28px;
281
+ background: #3a3a3a;
282
+ border: 1px solid #4a4a4a;
283
+ border-radius: 3px;
284
+ cursor: pointer;
285
+ transition: all 0.1s ease;
286
+
287
+ &:hover {
288
+ border-color: #60a5fa;
289
+ }
290
+
291
+ &.selected {
292
+ background: #3b82f6;
293
+ border-color: #60a5fa;
294
+ }
295
+ }
296
+
297
+ .dimension-label {
298
+ font-size: 0.875rem;
299
+ font-weight: 600;
300
+ color: #d4d4d4;
301
+ margin-top: 0.25rem;
302
+ }
303
+
304
+ .divider {
305
+ display: flex;
306
+ align-items: center;
307
+ width: 100%;
308
+ margin: 0.5rem 0;
309
+
310
+ &::before,
311
+ &::after {
312
+ content: '';
313
+ flex: 1;
314
+ height: 1px;
315
+ background: #404040;
316
+ }
317
+
318
+ span {
319
+ padding: 0 0.75rem;
320
+ font-size: 0.75rem;
321
+ color: #6b7280;
322
+ white-space: nowrap;
323
+ }
324
+ }
325
+
326
+ .manual-inputs {
327
+ display: flex;
328
+ gap: 1rem;
329
+ width: 100%;
330
+ justify-content: center;
331
+ }
332
+
333
+ .input-group {
334
+ display: flex;
335
+ flex-direction: column;
336
+ gap: 0.25rem;
337
+
338
+ label {
339
+ font-size: 0.75rem;
340
+ font-weight: 500;
341
+ text-transform: uppercase;
342
+ letter-spacing: 0.05em;
343
+ color: #9ca3af;
344
+ }
345
+
346
+ input {
347
+ width: 70px;
348
+ padding: 0.5rem 0.75rem;
349
+ background: #1e1e1e;
350
+ border: 1px solid #404040;
351
+ border-radius: 0.375rem;
352
+ font-size: 0.875rem;
353
+ color: #f3f4f6;
354
+ outline: none;
355
+ text-align: center;
356
+ transition: border-color 0.15s ease;
357
+
358
+ &::placeholder {
359
+ color: #6b7280;
360
+ }
361
+
362
+ &:focus {
363
+ border-color: #60a5fa;
364
+ }
365
+
366
+ /* Hide number input spinners */
367
+ &::-webkit-outer-spin-button,
368
+ &::-webkit-inner-spin-button {
369
+ -webkit-appearance: none;
370
+ margin: 0;
371
+ }
372
+
373
+ /* Firefox */
374
+ &[type=number] {
375
+ -moz-appearance: textfield;
376
+ }
377
+ }
378
+ }
379
+
380
+ .popover-footer {
381
+ display: flex;
382
+ justify-content: flex-end;
383
+ gap: 0.5rem;
384
+ padding: 0.75rem 1rem;
385
+ border-top: 1px solid #404040;
386
+ background: rgba(0, 0, 0, 0.2);
387
+
388
+ button {
389
+ padding: 0.5rem 1rem;
390
+ font-size: 0.875rem;
391
+ font-weight: 500;
392
+ border-radius: 0.375rem;
393
+ cursor: pointer;
394
+ transition: all 0.15s ease;
395
+ }
396
+
397
+ .btn-cancel {
398
+ background: transparent;
399
+ border: 1px solid #404040;
400
+ color: #d4d4d4;
401
+
402
+ &:hover {
403
+ background: rgba(255, 255, 255, 0.05);
404
+ border-color: #525252;
405
+ }
406
+ }
407
+
408
+ .btn-insert {
409
+ background: #3b82f6;
410
+ border: 1px solid #3b82f6;
411
+ color: #ffffff;
412
+
413
+ &:hover {
414
+ background: #2563eb;
415
+ border-color: #2563eb;
416
+ }
417
+ }
418
+ }
419
+ }
420
+ </style>
@@ -0,0 +1,11 @@
1
+ export { default as ContextMenu } from "./ContextMenu.vue";
2
+ export { default as HotkeyHelpPopover } from "./HotkeyHelpPopover.vue";
3
+ export { default as LineTypeMenu } from "./LineTypeMenu.vue";
4
+ export { default as LinkPopover } from "./LinkPopover.vue";
5
+ export { default as MarkdownEditor } from "./MarkdownEditor.vue";
6
+ export { default as MarkdownEditorContent } from "./MarkdownEditorContent.vue";
7
+ export { default as MarkdownEditorFooter } from "./MarkdownEditorFooter.vue";
8
+ export { default as TablePopover } from "./TablePopover.vue";
9
+
10
+ // Re-export types
11
+ export * from "./types";
@@ -0,0 +1,27 @@
1
+ export type LineType = "paragraph" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "ul" | "ol" | "code" | "blockquote";
2
+
3
+ export interface LineTypeOption {
4
+ value: LineType;
5
+ label: string;
6
+ icon: string;
7
+ shortcut: string;
8
+ }
9
+
10
+ export type ContextMenuContext = "table" | "list" | "code" | "text";
11
+
12
+ export interface ContextMenuItem {
13
+ id: string;
14
+ label: string;
15
+ icon?: string;
16
+ shortcut?: string;
17
+ action?: () => void; // Optional - not needed if has children
18
+ disabled?: boolean;
19
+ children?: ContextMenuItem[]; // For nested submenus
20
+ divider?: boolean; // For visual dividers between items
21
+ }
22
+
23
+ export interface ContextMenuGroup {
24
+ id: string;
25
+ label: string;
26
+ items: ContextMenuItem[];
27
+ }
@@ -14,6 +14,7 @@ const props = withDefaults(defineProps<LabelPillWidgetProps>(), {
14
14
  });
15
15
 
16
16
  const colorClasses = {
17
+ // Dark theme colors (dark backgrounds with bright text)
17
18
  sky: "bg-sky-950 text-sky-400",
18
19
  green: "bg-green-950 text-green-400",
19
20
  red: "bg-red-950 text-red-400",
@@ -33,6 +34,25 @@ const colorClasses = {
33
34
  indigo: "bg-indigo-950 text-indigo-400",
34
35
  violet: "bg-violet-950 text-violet-400",
35
36
  fuchsia: "bg-fuchsia-950 text-fuchsia-400",
37
+ // Soft/light theme colors (light backgrounds with darker text)
38
+ "sky-soft": "bg-sky-100 text-sky-700",
39
+ "green-soft": "bg-green-100 text-green-700",
40
+ "red-soft": "bg-red-100 text-red-700",
41
+ "amber-soft": "bg-amber-100 text-amber-700",
42
+ "yellow-soft": "bg-yellow-100 text-yellow-700",
43
+ "blue-soft": "bg-blue-100 text-blue-700",
44
+ "purple-soft": "bg-purple-100 text-purple-700",
45
+ "slate-soft": "bg-slate-100 text-slate-600",
46
+ "gray-soft": "bg-gray-100 text-gray-600",
47
+ "emerald-soft": "bg-emerald-100 text-emerald-700",
48
+ "orange-soft": "bg-orange-100 text-orange-700",
49
+ "lime-soft": "bg-lime-100 text-lime-700",
50
+ "teal-soft": "bg-teal-100 text-teal-700",
51
+ "cyan-soft": "bg-cyan-100 text-cyan-700",
52
+ "rose-soft": "bg-rose-100 text-rose-700",
53
+ "indigo-soft": "bg-indigo-100 text-indigo-700",
54
+ "violet-soft": "bg-violet-100 text-violet-700",
55
+ "fuchsia-soft": "bg-fuchsia-100 text-fuchsia-700",
36
56
  none: ""
37
57
  };
38
58
 
@@ -5,6 +5,7 @@ export * from "./Dialogs";
5
5
  export * from "./Files";
6
6
  export * from "./Formats";
7
7
  export * from "./Layouts";
8
+ export * from "./Markdown";
8
9
  export * from "./Popovers";
9
10
  export * from "./Tabs";
10
11
  export * from "./Tools";
@@ -7,3 +7,4 @@ export * from "./useKeyboardNavigation";
7
7
  export * from "./useThumbnailScroll";
8
8
  export * from "./useTranscodeLoader";
9
9
  export * from "./useVirtualCarousel";
10
+ export * from "./markdown";