toolbar.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <script setup lang="ts">
  2. import type { ToolbarMode } from "@enesis/editor"
  3. import { Editor, EditorToolbar } from "@enesis/editor"
  4. import { ref } from "vue"
  5. const content =
  6. ref(`* **Bold**, *italic*, \`code\`, ~~strikethrough~~, ^^highlight^^, and $math$ work inline
  7. * ## Heading 2
  8. * TODO This task can be toggled from the toolbar
  9. * [[Page refs]] and #tags are supported inline`)
  10. const mode = ref<ToolbarMode | undefined>("fixed")
  11. </script>
  12. <template>
  13. <UPage>
  14. <UPageHeader
  15. title="EditorToolbar"
  16. description="Formatting toolbar with active state tracking, undo/redo, and three layout modes."
  17. />
  18. <UPageBody>
  19. <div class="space-y-8">
  20. <section class="space-y-4">
  21. <p class="text-sm text-muted leading-relaxed">
  22. The toolbar is rendered via the <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">#toolbar</code> slot on <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">Editor</code>.
  23. It receives <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">handlers</code>, <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">canUndo</code>/<code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">canRedo</code>, and <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">undo</code>/<code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">redo</code> from the focused block.
  24. The <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">mode</code> prop controls the toolbar layout:
  25. <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">fixed</code> (default, sticky to editor top),
  26. <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">bubble</code> (appears on text selection), or
  27. <code class="text-xs font-mono px-1 py-0.5 rounded bg-elevated border border-default">floating</code> (appears on empty lines).
  28. </p>
  29. <div class="rounded-lg border border-default dark:bg-neutral-950/50 p-4 sm:p-8 rounded-t-md">
  30. <div class="flex items-center gap-2 mb-4">
  31. <span class="text-sm text-muted">Mode:</span>
  32. <UButton
  33. v-for="m in (['fixed', 'bubble', 'floating'] as const)"
  34. :key="m"
  35. size="xs"
  36. :variant="(mode === m) ? 'solid' : 'outline'"
  37. :color="(mode === m) ? 'primary' : 'neutral'"
  38. @click="mode = mode === m ? undefined : m"
  39. >
  40. {{ m }}
  41. </UButton>
  42. </div>
  43. <Editor v-model:content="content" :focused="true" marker-mode="always-visible">
  44. <template #toolbar="{ handlers, selectionVersion, canUndo, canRedo, undo, redo }">
  45. <EditorToolbar
  46. :mode="mode"
  47. :handlers="handlers"
  48. :selection-version="selectionVersion"
  49. :can-undo="canUndo"
  50. :can-redo="canRedo"
  51. :undo="undo"
  52. :redo="redo"
  53. />
  54. </template>
  55. </Editor>
  56. </div>
  57. </section>
  58. <section class="space-y-4">
  59. <h2 class="text-lg font-semibold text-highlighted">Props</h2>
  60. <div class="rounded-lg border border-default overflow-hidden">
  61. <table class="w-full border-separate border-spacing-0 rounded-md text-sm">
  62. <thead class="bg-muted">
  63. <tr>
  64. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Prop</th>
  65. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Type</th>
  66. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Default</th>
  67. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Description</th>
  68. </tr>
  69. </thead>
  70. <tbody>
  71. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">mode</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">'fixed' | 'bubble' | 'floating'</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">'fixed'</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Toolbar layout mode</td></tr>
  72. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">handlers</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">FormattingHandlers</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">—</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Handlers from focused block</td></tr>
  73. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">selectionVersion</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">number</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">—</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Re-compute active states on cursor move</td></tr>
  74. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">canUndo / canRedo</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">boolean</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">—</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Enable undo/redo buttons</td></tr>
  75. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">undo / redo</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">() => void</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">—</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Undo/redo callbacks</td></tr>
  76. </tbody>
  77. </table>
  78. </div>
  79. </section>
  80. <section class="space-y-4">
  81. <h2 class="text-lg font-semibold text-highlighted">Button Groups</h2>
  82. <div class="rounded-lg border border-default overflow-hidden">
  83. <table class="w-full border-separate border-spacing-0 rounded-md text-sm">
  84. <thead class="bg-muted">
  85. <tr>
  86. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Group</th>
  87. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Buttons</th>
  88. <th class="py-3 px-4 font-semibold text-sm border-e border-b first:border-s border-t border-muted text-left">Description</th>
  89. </tr>
  90. </thead>
  91. <tbody>
  92. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">History</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">Undo, Redo</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Undo/redo stack</td></tr>
  93. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">Block</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">Heading, Task</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Heading level dropdown, task toggle</td></tr>
  94. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">Inline</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">Bold, Italic, Code, Strike, Highlight</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Inline formatting toggles</td></tr>
  95. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">Insert</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">Link, Inline Math, Block Math</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Insert markdown syntax</td></tr>
  96. <tr><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left"><code class="md-code">References</code></td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left">Page Ref, Block Ref, Tag</td><td class="py-3 px-4 text-sm align-top border-e border-b first:border-s border-muted text-left text-muted">Prompt-based insertion</td></tr>
  97. </tbody>
  98. </table>
  99. </div>
  100. </section>
  101. </div>
  102. </UPageBody>
  103. </UPage>
  104. </template>