betterstart-cli 0.0.95 → 0.0.97

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 (162) hide show
  1. package/dist/assets/adapters/next/integrations/_shared/actions/object-key.ts +16 -0
  2. package/dist/assets/adapters/next/integrations/r2/actions/r2.ts +6 -14
  3. package/dist/assets/adapters/next/integrations/r2/integration.ts +4 -0
  4. package/dist/assets/adapters/next/integrations/railway-bucket/actions/railway-bucket.ts +7 -15
  5. package/dist/assets/adapters/next/integrations/railway-bucket/integration.ts +4 -0
  6. package/dist/assets/adapters/next/integrations/vercel-blob/actions/vercel-blob.ts +2 -10
  7. package/dist/assets/adapters/next/integrations/vercel-blob/integration.ts +4 -0
  8. package/dist/assets/adapters/next/templates/init/api/upload-route.ts +37 -13
  9. package/dist/assets/adapters/next/templates/init/components/layouts/admin-header.tsx +6 -6
  10. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-branding-skeleton.tsx +2 -2
  11. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu-skeleton.tsx +1 -1
  12. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu.tsx +8 -8
  13. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar.tsx +4 -4
  14. package/dist/assets/adapters/next/templates/init/components/layouts/content-skeleton.tsx +4 -4
  15. package/dist/assets/adapters/next/templates/init/components/layouts/sidebar-branding.tsx +4 -4
  16. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid.tsx +1 -1
  17. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table-pagination.tsx +3 -3
  18. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +1 -1
  19. package/dist/assets/adapters/next/templates/init/components/shared/delete-dialog.tsx +1 -1
  20. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx +5 -5
  21. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/plain-code-fallback.tsx +1 -1
  22. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +1 -1
  23. package/dist/assets/adapters/next/templates/init/components/shared/entity-filters-bar.tsx +5 -5
  24. package/dist/assets/adapters/next/templates/init/components/shared/entity-metadata.tsx +2 -2
  25. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-item.tsx +1 -1
  26. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-current-row.tsx +1 -1
  27. package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog-content.tsx +3 -3
  28. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx +1 -1
  29. package/dist/assets/adapters/next/templates/init/components/shared/media/media-filters-bar.tsx +2 -2
  30. package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +2 -2
  31. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-item.tsx +3 -3
  32. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-pagination.tsx +4 -4
  33. package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +3 -3
  34. package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +3 -3
  35. package/dist/assets/adapters/next/templates/init/components/shared/page-header.tsx +4 -4
  36. package/dist/assets/adapters/next/templates/init/components/shared/search-input.tsx +5 -5
  37. package/dist/assets/adapters/next/templates/init/components/shared/sort-indicator.tsx +1 -1
  38. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-dialog.tsx +1 -1
  39. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-drag-overlay-item.tsx +1 -1
  40. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-item.tsx +2 -2
  41. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-color-highlight.ts +10 -64
  42. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-source-mode.tsx +11 -4
  43. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-heading-dropdown-menu.ts +0 -1
  44. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list-dropdown-menu.ts +0 -1
  45. package/dist/assets/adapters/next/templates/init/lib/actions/audit/get-audit-logs.ts +5 -10
  46. package/dist/assets/adapters/next/templates/init/lib/actions/forms/index.ts +1 -5
  47. package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +6 -6
  48. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media.ts +4 -1
  49. package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +5 -5
  50. package/dist/assets/adapters/next/templates/init/lib/actions/profile/index.ts +1 -5
  51. package/dist/assets/adapters/next/templates/init/lib/actions/upload/index.ts +1 -5
  52. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhook-deliveries.ts +1 -10
  53. package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhooks.ts +1 -10
  54. package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +4 -1
  55. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +1 -1
  56. package/dist/assets/adapters/next/templates/init/pages/admin-layout.tsx +1 -1
  57. package/dist/assets/adapters/next/templates/init/pages/auth-gate-rsc.tsx +1 -1
  58. package/dist/assets/adapters/next/templates/init/pages/dashboard-page.tsx +6 -6
  59. package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +4 -4
  60. package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +3 -3
  61. package/dist/assets/adapters/next/templates/init/pages/media/media-page-content.tsx +3 -3
  62. package/dist/assets/adapters/next/templates/init/pages/media/media-page-skeleton.tsx +1 -1
  63. package/dist/assets/adapters/next/templates/init/pages/minimal-account-shell.tsx +2 -2
  64. package/dist/assets/adapters/next/templates/init/pages/profile/profile-page.tsx +1 -1
  65. package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +3 -3
  66. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-columns.tsx +1 -1
  67. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-drawer.tsx +1 -1
  68. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-row.tsx +2 -2
  69. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-page-content.tsx +1 -1
  70. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-page-skeleton.tsx +1 -1
  71. package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +2 -2
  72. package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-content.tsx +1 -1
  73. package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-skeleton.tsx +1 -1
  74. package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-table.tsx +1 -1
  75. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-endpoint-dialog.tsx +3 -3
  76. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-columns.tsx +6 -6
  77. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-columns.tsx +7 -7
  78. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-page-content.tsx +1 -1
  79. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-table.tsx +2 -2
  80. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page-content.tsx +1 -1
  81. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page-skeleton.tsx +1 -1
  82. package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +2 -2
  83. package/dist/assets/adapters/next/templates/init/pages/users/columns.tsx +4 -4
  84. package/dist/assets/adapters/next/templates/init/pages/users/users-page-content.tsx +1 -1
  85. package/dist/assets/adapters/next/templates/init/pages/users/users-page-skeleton.tsx +1 -1
  86. package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +5 -5
  87. package/dist/assets/adapters/next/templates/init/types/table-meta.ts +1 -1
  88. package/dist/assets/adapters/next/templates/init/utils/date/date.ts +15 -0
  89. package/dist/assets/adapters/next/templates/init/utils/editor/content-editor.ts +98 -25
  90. package/dist/assets/adapters/next/templates/init/utils/editor/markdown.ts +5 -2
  91. package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +1 -1
  92. package/dist/assets/shared-assets/react-admin/custom/content-editor/index.tsx +2 -2
  93. package/dist/assets/shared-assets/react-admin/custom/content-editor/main-toolbar-content.tsx +4 -4
  94. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-bubble-menu.tsx +1 -1
  95. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-editor-controls.tsx +1 -1
  96. package/dist/assets/shared-assets/react-admin/custom/content-editor/mobile-toolbar-content.tsx +1 -1
  97. package/dist/assets/shared-assets/react-admin/custom/content-editor/remove-table-part-icon.tsx +1 -1
  98. package/dist/assets/shared-assets/react-admin/custom/content-editor/selection-bubble-menu.tsx +5 -5
  99. package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +6 -6
  100. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +11 -9
  101. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-add-controls.tsx +3 -3
  102. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-bubble-menu.tsx +2 -2
  103. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +1 -1
  104. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/blockquote-button.tsx +1 -2
  105. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/code-block-button.tsx +1 -2
  106. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-button/color-highlight-button.tsx +2 -3
  107. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-content.tsx +4 -2
  108. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +3 -2
  109. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/source-color-highlight-popover.tsx +5 -3
  110. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +2 -1
  111. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-main.tsx +2 -2
  112. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-popover.tsx +1 -2
  113. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/mark-button.tsx +1 -2
  114. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/undo-redo-button.tsx +1 -2
  115. package/dist/assets/shared-assets/react-admin/custom/date-picker.tsx +2 -2
  116. package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +6 -6
  117. package/dist/assets/shared-assets/react-admin/custom/icon-picker.tsx +10 -8
  118. package/dist/assets/shared-assets/react-admin/custom/icons-column-skeleton.tsx +2 -2
  119. package/dist/assets/shared-assets/react-admin/custom/media-field-empty-state.tsx +5 -5
  120. package/dist/assets/shared-assets/react-admin/custom/media-field.tsx +7 -7
  121. package/dist/assets/shared-assets/react-admin/custom/nested-object-list-field.tsx +2 -2
  122. package/dist/assets/shared-assets/react-admin/custom/placeholder-card.tsx +1 -1
  123. package/dist/assets/shared-assets/react-admin/custom/placeholder.tsx +1 -1
  124. package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +1 -1
  125. package/dist/assets/shared-assets/react-admin/custom/sortable-gallery-item.tsx +3 -3
  126. package/dist/assets/shared-assets/react-admin/custom/upload-dropzone.tsx +6 -6
  127. package/dist/assets/shared-assets/react-admin/schema.json +1143 -876
  128. package/dist/assets/shared-assets/react-admin/ui/accordion.tsx +1 -1
  129. package/dist/assets/shared-assets/react-admin/ui/alert-dialog.tsx +4 -4
  130. package/dist/assets/shared-assets/react-admin/ui/badge.tsx +1 -1
  131. package/dist/assets/shared-assets/react-admin/ui/button-group.tsx +1 -1
  132. package/dist/assets/shared-assets/react-admin/ui/button.tsx +6 -6
  133. package/dist/assets/shared-assets/react-admin/ui/card.tsx +5 -5
  134. package/dist/assets/shared-assets/react-admin/ui/checkbox.tsx +1 -1
  135. package/dist/assets/shared-assets/react-admin/ui/combobox.tsx +1 -1
  136. package/dist/assets/shared-assets/react-admin/ui/command.tsx +0 -1
  137. package/dist/assets/shared-assets/react-admin/ui/context-menu.tsx +2 -2
  138. package/dist/assets/shared-assets/react-admin/ui/dialog.tsx +3 -3
  139. package/dist/assets/shared-assets/react-admin/ui/drawer.tsx +1 -1
  140. package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +3 -3
  141. package/dist/assets/shared-assets/react-admin/ui/field.tsx +0 -1
  142. package/dist/assets/shared-assets/react-admin/ui/input-group.tsx +2 -2
  143. package/dist/assets/shared-assets/react-admin/ui/input.tsx +1 -1
  144. package/dist/assets/shared-assets/react-admin/ui/menubar.tsx +2 -2
  145. package/dist/assets/shared-assets/react-admin/ui/pagination.tsx +0 -1
  146. package/dist/assets/shared-assets/react-admin/ui/scroll-area.tsx +1 -1
  147. package/dist/assets/shared-assets/react-admin/ui/select.tsx +2 -2
  148. package/dist/assets/shared-assets/react-admin/ui/sidebar.tsx +4 -4
  149. package/dist/assets/shared-assets/react-admin/ui/table.tsx +1 -1
  150. package/dist/assets/shared-assets/react-admin/ui/tabs.tsx +2 -2
  151. package/dist/assets/shared-assets/react-admin/ui/textarea.tsx +1 -1
  152. package/dist/assets/shared-assets/react-admin/ui/tooltip.tsx +1 -1
  153. package/dist/{chunk-3CLINNJL.js → chunk-MJWUGEMK.js} +32 -8
  154. package/dist/chunk-MJWUGEMK.js.map +1 -0
  155. package/dist/cli.js +8554 -9062
  156. package/dist/cli.js.map +1 -1
  157. package/dist/index.d.ts +1 -1
  158. package/dist/index.js.map +1 -1
  159. package/dist/{template-reader-PVN53GS7.js → template-reader-R2JIWUNK.js} +2 -2
  160. package/package.json +3 -3
  161. package/dist/chunk-3CLINNJL.js.map +0 -1
  162. /package/dist/{template-reader-PVN53GS7.js.map → template-reader-R2JIWUNK.js.map} +0 -0
@@ -25,7 +25,7 @@ export const columns: ColumnDef<User>[] = [
25
25
  <Button
26
26
  variant="ghost"
27
27
  onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
28
- className="w-full min-w-0 justify-start overflow-hidden px-0! border-none rounded-none bg-transparent! scale-100! group"
28
+ className="group w-full min-w-0 scale-100! justify-start overflow-hidden rounded-none border-none bg-transparent! px-0!"
29
29
  >
30
30
  <span className="truncate">User</span>
31
31
  <SortIndicator direction={sortDirection} />
@@ -42,7 +42,7 @@ export const columns: ColumnDef<User>[] = [
42
42
  </Avatar>
43
43
  <div className="flex flex-col">
44
44
  <div className="font-medium">{name || 'N/A'}</div>
45
- <div className="text-muted-foreground text-sm">{email}</div>
45
+ <div className="text-sm text-muted-foreground">{email}</div>
46
46
  </div>
47
47
  </div>
48
48
  )
@@ -92,7 +92,7 @@ export const columns: ColumnDef<User>[] = [
92
92
  currentRole={row.original.role}
93
93
  userName={row.original.name}
94
94
  >
95
- <Badge variant="outline" className="capitalize cursor-pointer">
95
+ <Badge variant="outline" className="cursor-pointer capitalize">
96
96
  <span className="flex items-center gap-1">
97
97
  {role}
98
98
  <Edit className="size-3" />
@@ -111,7 +111,7 @@ export const columns: ColumnDef<User>[] = [
111
111
  <Button
112
112
  variant="ghost"
113
113
  onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}
114
- className="w-full min-w-0 justify-start overflow-hidden px-0! border-none rounded-none bg-transparent! scale-100! group"
114
+ className="group w-full min-w-0 scale-100! justify-start overflow-hidden rounded-none border-none bg-transparent! px-0!"
115
115
  >
116
116
  <span className="truncate">Joined</span>
117
117
  <SortIndicator direction={sortDirection} />
@@ -98,7 +98,7 @@ export function UsersPageContent() {
98
98
  isPending={isSearchFetching}
99
99
  onSearch={handleSearch}
100
100
  />
101
- <main className="space-y-4 px-4 pb-4 flex-1">
101
+ <main className="flex-1 space-y-4 px-4 pb-4">
102
102
  <UsersTable columns={columns} search={search} status={status} role={role} />
103
103
  </main>
104
104
  </React.Fragment>
@@ -1,6 +1,6 @@
1
1
  export function UsersPageSkeleton() {
2
2
  return (
3
- <div className="flex items-center justify-center h-48">
3
+ <div className="flex h-48 items-center justify-center">
4
4
  <div className="text-muted-foreground">Loading Users…</div>
5
5
  </div>
6
6
  )
@@ -137,7 +137,7 @@ export function UsersTable<TValue>({
137
137
  .join(' ')
138
138
 
139
139
  return (
140
- <div className={cn('flex flex-col gap-6 pt-px pb-2 h-full', className)}>
140
+ <div className={cn('flex h-full flex-col gap-6 pt-px pb-2', className)}>
141
141
  <DataGrid
142
142
  containerClassName="min-h-0 flex-1"
143
143
  containerRef={tableContainerRef}
@@ -174,7 +174,7 @@ export function UsersTable<TValue>({
174
174
  <button
175
175
  type="button"
176
176
  aria-label={`Resize ${resizeLabel} column`}
177
- className="group/resize-handle absolute right-0 top-0 z-10 flex h-full w-5 cursor-col-resize touch-none select-none items-center justify-center text-muted-foreground opacity-0 transition-opacity hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none group-focus-within/resize-header:opacity-100 data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
177
+ className="group/resize-handle absolute top-0 right-0 z-10 flex h-full w-5 cursor-col-resize touch-none items-center justify-center text-muted-foreground opacity-0 transition-opacity select-none group-focus-within/resize-header:opacity-100 hover:text-foreground focus-visible:text-foreground focus-visible:opacity-100 focus-visible:outline-none data-[column-hovered=true]:opacity-100 data-[resizing=true]:opacity-100"
178
178
  data-resize-handle
179
179
  data-column-hovered={
180
180
  hoveredColumnId === header.column.id ? 'true' : 'false'
@@ -202,7 +202,7 @@ export function UsersTable<TValue>({
202
202
  {isPending ? (
203
203
  <DataGridRow>
204
204
  <DataGridCell
205
- className="flex h-24 items-center justify-center text-center px-4"
205
+ className="flex h-24 items-center justify-center px-4 text-center"
206
206
  style={{ gridColumn: '1 / -1' }}
207
207
  >
208
208
  <div className="text-muted-foreground">Loading users…</div>
@@ -211,7 +211,7 @@ export function UsersTable<TValue>({
211
211
  ) : error ? (
212
212
  <DataGridRow>
213
213
  <DataGridCell
214
- className="flex h-24 items-center justify-center text-center px-4"
214
+ className="flex h-24 items-center justify-center px-4 text-center"
215
215
  style={{ gridColumn: '1 / -1' }}
216
216
  >
217
217
  <div className="text-destructive">Error: {error.message}</div>
@@ -238,7 +238,7 @@ export function UsersTable<TValue>({
238
238
  ) : (
239
239
  <DataGridRow>
240
240
  <DataGridCell
241
- className="flex h-24 items-center justify-center text-center px-4"
241
+ className="flex h-24 items-center justify-center px-4 text-center"
242
242
  style={{ gridColumn: '1 / -1' }}
243
243
  >
244
244
  No users found.
@@ -1,7 +1,7 @@
1
1
  import type { RowData } from '@tanstack/react-table'
2
2
 
3
3
  declare module '@tanstack/react-table' {
4
- // biome-ignore lint/correctness/noUnusedVariables: augmenting module
4
+ // oxlint-disable-next-line no-unused-vars -- augmenting module
5
5
  interface TableMeta<TData extends RowData> {
6
6
  currentUser?: {
7
7
  id: string
@@ -8,6 +8,21 @@ const DATE_RANGE_TIME_PATTERN = /^([01]\d|2[0-3]):([0-5]\d)$/
8
8
  export const DATE_RANGE_START_TIME = '00:00'
9
9
  export const DATE_RANGE_END_TIME = '23:59'
10
10
 
11
+ /**
12
+ * Turn an inclusive `YYYY-MM-DD` "to date" filter into the exclusive upper bound
13
+ * that follows it. The input is always read as UTC so the same filter selects the
14
+ * same rows regardless of the viewer's timezone.
15
+ */
16
+ export function getExclusiveDateUpperBound(value?: string): string | null {
17
+ if (!value) return null
18
+
19
+ const date = new Date(`${value}T00:00:00.000Z`)
20
+ if (Number.isNaN(date.getTime())) return null
21
+
22
+ date.setUTCDate(date.getUTCDate() + 1)
23
+ return date.toISOString().slice(0, 10)
24
+ }
25
+
11
26
  export function parseDateInputValue(value?: string): Date | undefined {
12
27
  if (!value) return undefined
13
28
 
@@ -9,6 +9,7 @@ export interface ContentEditorSelectionRequest {
9
9
  }
10
10
 
11
11
  export const CONTENT_EDITOR_HIGHLIGHT_COLORS = [
12
+ 'default',
12
13
  'gray',
13
14
  'brown',
14
15
  'orange',
@@ -22,20 +23,92 @@ export const CONTENT_EDITOR_HIGHLIGHT_COLORS = [
22
23
 
23
24
  export type ContentEditorHighlightColor = (typeof CONTENT_EDITOR_HIGHLIGHT_COLORS)[number]
24
25
 
25
- export const CONTENT_EDITOR_HIGHLIGHT_COLOR_VALUES: Record<ContentEditorHighlightColor, string> = {
26
- gray: 'var(--tt-color-highlight-gray)',
27
- brown: 'var(--tt-color-highlight-brown)',
28
- orange: 'var(--tt-color-highlight-orange)',
29
- yellow: 'var(--tt-color-highlight-yellow)',
30
- green: 'var(--tt-color-highlight-green)',
31
- blue: 'var(--tt-color-highlight-blue)',
32
- purple: 'var(--tt-color-highlight-purple)',
33
- pink: 'var(--tt-color-highlight-pink)',
34
- red: 'var(--tt-color-highlight-red)'
26
+ export interface ContentEditorHighlightColorOption {
27
+ label: string
28
+ value: string
29
+ colorValue: string
30
+ border: string
35
31
  }
36
32
 
37
- const HIGHLIGHT_VALUE_NAMES = new Map(
38
- Object.entries(CONTENT_EDITOR_HIGHLIGHT_COLOR_VALUES).map(([name, value]) => [value, name])
33
+ export const CONTENT_EDITOR_HIGHLIGHT_COLOR_OPTIONS: Record<
34
+ ContentEditorHighlightColor,
35
+ ContentEditorHighlightColorOption
36
+ > = {
37
+ default: {
38
+ label: 'Default background',
39
+ value: 'var(--tt-bg-color)',
40
+ colorValue: '#ffffff',
41
+ border: 'var(--tt-bg-color-contrast)'
42
+ },
43
+ gray: {
44
+ label: 'Gray background',
45
+ value: 'var(--tt-color-highlight-gray)',
46
+ colorValue: '#f8f8f7',
47
+ border: 'var(--tt-color-highlight-gray-contrast)'
48
+ },
49
+ brown: {
50
+ label: 'Brown background',
51
+ value: 'var(--tt-color-highlight-brown)',
52
+ colorValue: '#f4eeee',
53
+ border: 'var(--tt-color-highlight-brown-contrast)'
54
+ },
55
+ orange: {
56
+ label: 'Orange background',
57
+ value: 'var(--tt-color-highlight-orange)',
58
+ colorValue: '#fbecdd',
59
+ border: 'var(--tt-color-highlight-orange-contrast)'
60
+ },
61
+ yellow: {
62
+ label: 'Yellow background',
63
+ value: 'var(--tt-color-highlight-yellow)',
64
+ colorValue: '#fef9c3',
65
+ border: 'var(--tt-color-highlight-yellow-contrast)'
66
+ },
67
+ green: {
68
+ label: 'Green background',
69
+ value: 'var(--tt-color-highlight-green)',
70
+ colorValue: '#dcfce7',
71
+ border: 'var(--tt-color-highlight-green-contrast)'
72
+ },
73
+ blue: {
74
+ label: 'Blue background',
75
+ value: 'var(--tt-color-highlight-blue)',
76
+ colorValue: '#e0f2fe',
77
+ border: 'var(--tt-color-highlight-blue-contrast)'
78
+ },
79
+ purple: {
80
+ label: 'Purple background',
81
+ value: 'var(--tt-color-highlight-purple)',
82
+ colorValue: '#f3e8ff',
83
+ border: 'var(--tt-color-highlight-purple-contrast)'
84
+ },
85
+ pink: {
86
+ label: 'Pink background',
87
+ value: 'var(--tt-color-highlight-pink)',
88
+ colorValue: '#fcf1f6',
89
+ border: 'var(--tt-color-highlight-pink-contrast)'
90
+ },
91
+ red: {
92
+ label: 'Red background',
93
+ value: 'var(--tt-color-highlight-red)',
94
+ colorValue: '#ffe4e6',
95
+ border: 'var(--tt-color-highlight-red-contrast)'
96
+ }
97
+ }
98
+
99
+ export const CONTENT_EDITOR_HIGHLIGHT_COLOR_NAME_PATTERN = CONTENT_EDITOR_HIGHLIGHT_COLORS.join('|')
100
+
101
+ const HIGHLIGHT_NAMES_BY_VALUE = new Map(
102
+ CONTENT_EDITOR_HIGHLIGHT_COLORS.map(
103
+ (name) => [CONTENT_EDITOR_HIGHLIGHT_COLOR_OPTIONS[name].value, name] as const
104
+ )
105
+ )
106
+
107
+ const HIGHLIGHT_NAMES_BY_CSS_VARIABLE = new Map(
108
+ CONTENT_EDITOR_HIGHLIGHT_COLORS.map(
109
+ (name) =>
110
+ [CONTENT_EDITOR_HIGHLIGHT_COLOR_OPTIONS[name].value.slice('var('.length, -1), name] as const
111
+ )
39
112
  )
40
113
 
41
114
  export function getContentEditorHighlightColorName(
@@ -44,19 +117,16 @@ export function getContentEditorHighlightColorName(
44
117
  if (!value) return 'yellow'
45
118
 
46
119
  const normalized = value.trim()
47
- const variableMatch = normalized.match(/var\((--tt-color-highlight-[^)]+)\)/)
48
- const variableName = variableMatch ? `var(${variableMatch[1]})` : normalized
49
- const mapped = HIGHLIGHT_VALUE_NAMES.get(variableName)
120
+ const mapped = HIGHLIGHT_NAMES_BY_VALUE.get(normalized)
50
121
 
51
- if (mapped && isContentEditorHighlightColor(mapped)) {
122
+ if (mapped) {
52
123
  return mapped
53
124
  }
54
125
 
55
- const cssVariableMatch = normalized.match(
56
- /--tt-color-highlight-(gray|brown|orange|yellow|green|blue|purple|pink|red)/
57
- )
58
- if (cssVariableMatch && isContentEditorHighlightColor(cssVariableMatch[1])) {
59
- return cssVariableMatch[1]
126
+ for (const [cssVariable, name] of HIGHLIGHT_NAMES_BY_CSS_VARIABLE) {
127
+ if (normalized.includes(cssVariable)) {
128
+ return name
129
+ }
60
130
  }
61
131
 
62
132
  if (isContentEditorHighlightColor(normalized)) {
@@ -67,7 +137,7 @@ export function getContentEditorHighlightColorName(
67
137
  }
68
138
 
69
139
  export function getContentEditorHighlightColorValue(color: ContentEditorHighlightColor): string {
70
- return CONTENT_EDITOR_HIGHLIGHT_COLOR_VALUES[color]
140
+ return CONTENT_EDITOR_HIGHLIGHT_COLOR_OPTIONS[color].value
71
141
  }
72
142
 
73
143
  export function isContentEditorHighlightColor(value: string): value is ContentEditorHighlightColor {
@@ -295,13 +365,16 @@ function matchMarkdownMarkSyntax(markdown: string, index: number): number | null
295
365
  return null
296
366
  }
297
367
 
368
+ const HIGHLIGHT_SPAN_OPEN_PATTERN = new RegExp(
369
+ `^<span\\s+data-highlight-color="(?:${CONTENT_EDITOR_HIGHLIGHT_COLOR_NAME_PATTERN})">`,
370
+ 'i'
371
+ )
372
+
298
373
  function matchHtmlMarkSyntax(markdown: string, index: number): number | null {
299
374
  const remaining = markdown.slice(index)
300
375
  const match =
301
376
  /^<\/?(?:u|sub|sup|kbd)>/i.exec(remaining) ??
302
- /^<span\s+data-highlight-color="(?:gray|brown|orange|yellow|green|blue|purple|pink|red)">/i.exec(
303
- remaining
304
- ) ??
377
+ HIGHLIGHT_SPAN_OPEN_PATTERN.exec(remaining) ??
305
378
  /^<\/span>/i.exec(remaining)
306
379
 
307
380
  return match ? index + match[0].length : null
@@ -1,3 +1,4 @@
1
+ import { CONTENT_EDITOR_HIGHLIGHT_COLOR_NAME_PATTERN } from '@admin/utils/editor/content-editor'
1
2
  import type { EditorView } from '@codemirror/view'
2
3
 
3
4
  interface InsertResult {
@@ -22,8 +23,10 @@ export interface ContentEditorMathValue {
22
23
  raw: string
23
24
  }
24
25
 
25
- const HIGHLIGHT_SPAN_PATTERN =
26
- /<span\s+data-highlight-color="(?:gray|brown|orange|yellow|green|blue|purple|pink|red)">([\s\S]*?)<\/span>/g
26
+ const HIGHLIGHT_SPAN_PATTERN = new RegExp(
27
+ `<span\\s+data-highlight-color="(?:${CONTENT_EDITOR_HIGHLIGHT_COLOR_NAME_PATTERN})">([\\s\\S]*?)<\\/span>`,
28
+ 'g'
29
+ )
27
30
  const MARKDOWN_LINK_PATTERN = /\[([^\]\n]*)\]\(([^)\n]*)\)/g
28
31
  const BLOCK_MATH_ENVIRONMENT_NAMES = new Set([
29
32
  'align',
@@ -15,7 +15,7 @@ export function EditorToolbar({
15
15
  role="toolbar"
16
16
  aria-label={ariaLabel}
17
17
  className={cn(
18
- 'flex items-center gap-1 overflow-x-auto border-border bg-card sticky top-0 z-10 min-h-12 w-full overscroll-x-contain border-b px-2 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden max-[480px]:absolute max-[480px]:top-auto max-[480px]:h-[calc(2.75rem+env(safe-area-inset-bottom,0px))] max-[480px]:flex-nowrap max-[480px]:justify-start max-[480px]:border-t max-[480px]:border-b-0 max-[480px]:pb-[env(safe-area-inset-bottom,0px)]',
18
+ 'sticky top-0 z-10 flex min-h-12 w-full items-center gap-1 overflow-x-auto overscroll-x-contain border-b border-border bg-card px-2 [scrollbar-width:none] max-[480px]:absolute max-[480px]:top-auto max-[480px]:h-[calc(2.75rem+env(safe-area-inset-bottom,0px))] max-[480px]:flex-nowrap max-[480px]:justify-start max-[480px]:border-t max-[480px]:border-b-0 max-[480px]:pb-[env(safe-area-inset-bottom,0px)] [&::-webkit-scrollbar]:hidden',
19
19
  className
20
20
  )}
21
21
  >
@@ -88,7 +88,7 @@ export function ContentEditor({
88
88
  toolbarEnd={
89
89
  <ModeToggleButton isSourceMode={isSourceMode} onClick={handleModeChange} />
90
90
  }
91
- className="min-h-0 flex-1 max-h-none resize-none rounded-none border-0"
91
+ className="max-h-none min-h-0 flex-1 resize-none rounded-none border-0"
92
92
  />
93
93
  ) : (
94
94
  <>
@@ -136,7 +136,7 @@ export function ContentEditor({
136
136
  <EditorContent
137
137
  editor={editor}
138
138
  role="presentation"
139
- className="simple-editor-content min-h-0 flex-1 cursor-text p-10 overflow-y-auto bg-input [&_.ProseMirror]:min-h-full"
139
+ className="simple-editor-content min-h-0 flex-1 cursor-text overflow-y-auto bg-input p-10 [&_.ProseMirror]:min-h-full"
140
140
  />
141
141
  </div>
142
142
  </>
@@ -43,13 +43,13 @@ export function MainToolbarContent({
43
43
 
44
44
  return (
45
45
  <>
46
- <div className="flex min-w-0 h-full flex-1 items-center overflow-x-auto">
46
+ <div className="flex h-full min-w-0 flex-1 items-center overflow-x-auto">
47
47
  <div className="flex items-center gap-0.5">
48
48
  <UndoRedoButton action="undo" />
49
49
  <UndoRedoButton action="redo" />
50
50
  </div>
51
51
 
52
- <Separator orientation="vertical" decorative className="my-auto h-[65%] mx-1 self-center" />
52
+ <Separator orientation="vertical" decorative className="mx-1 my-auto h-[65%] self-center" />
53
53
 
54
54
  <div className="flex items-center gap-0.5">
55
55
  <HeadingDropdownMenu />
@@ -59,7 +59,7 @@ export function MainToolbarContent({
59
59
  <HorizontalRuleButton editor={editor} />
60
60
  </div>
61
61
 
62
- <Separator orientation="vertical" decorative className="my-auto h-[65%] mx-1 self-center" />
62
+ <Separator orientation="vertical" decorative className="mx-1 my-auto h-[65%] self-center" />
63
63
 
64
64
  <div className="flex items-center gap-0.5">
65
65
  <MarkButton type="bold" />
@@ -75,7 +75,7 @@ export function MainToolbarContent({
75
75
  {!isMobile ? <LinkPopover /> : <LinkButton onClick={onLinkClick} />}
76
76
  </div>
77
77
 
78
- <Separator orientation="vertical" decorative className="my-auto h-[65%] mx-1 self-center" />
78
+ <Separator orientation="vertical" decorative className="mx-1 my-auto h-[65%] self-center" />
79
79
 
80
80
  <div className="flex items-center">
81
81
  <TableButton editor={editor} />
@@ -63,7 +63,7 @@ export function MathBubbleMenu({ editor }: { editor: Editor }) {
63
63
  role="toolbar"
64
64
  aria-label="Math formatting toolbar"
65
65
  className={cn(
66
- 'flex items-center gap-1 overflow-x-auto border-border rounded-sm border bg-popover p-0 text-popover-foreground shadow-menu [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
66
+ 'flex items-center gap-1 overflow-x-auto rounded-sm border border-border bg-popover p-0 text-popover-foreground shadow-menu [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
67
67
  'relative z-50'
68
68
  )}
69
69
  >
@@ -73,7 +73,7 @@ export function MathEditorControls({
73
73
  className="min-h-24 resize-y rounded-md text-sm"
74
74
  />
75
75
 
76
- <div className="flex items-center flex-wrap gap-1">
76
+ <div className="flex flex-wrap items-center gap-1">
77
77
  {onRemove ? (
78
78
  <Button
79
79
  type="button"
@@ -38,7 +38,7 @@ export function MobileToolbarContent({
38
38
  </Button>
39
39
  </div>
40
40
 
41
- <Separator orientation="vertical" decorative className="my-auto h-[65%] mx-1 self-center" />
41
+ <Separator orientation="vertical" decorative className="mx-1 my-auto h-[65%] self-center" />
42
42
 
43
43
  {type === 'highlighter' ? (
44
44
  <ColorHighlightPopoverContent />
@@ -11,7 +11,7 @@ export function RemoveTablePartIcon({
11
11
  return (
12
12
  <span className="tiptap-button-icon relative inline-flex size-4 items-center justify-center">
13
13
  <Icon className="size-4" />
14
- <MinusIcon className="-right-1 -bottom-0.5 border border-border absolute size-3 rounded-sm bg-card stroke-3" />
14
+ <MinusIcon className="absolute -right-1 -bottom-0.5 size-3 rounded-sm border border-border bg-card stroke-3" />
15
15
  </span>
16
16
  )
17
17
  }
@@ -72,8 +72,8 @@ export function SelectionBubbleMenu({ editor }: { editor: Editor }) {
72
72
  role="toolbar"
73
73
  aria-label="Link formatting toolbar"
74
74
  className={cn(
75
- 'flex items-center gap-1 overflow-x-auto border-border border bg-popover p-4 text-foreground shadow-2xl [scrollbar-width:none] [&::-webkit-scrollbar]:hidden rounded-sm',
76
- 'relative z-10'
75
+ 'flex items-center gap-1 overflow-x-auto rounded-sm border border-border bg-popover p-4 text-foreground shadow-2xl [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
76
+ 'relative z-50'
77
77
  )}
78
78
  >
79
79
  <LinkContent editor={editor} />
@@ -101,8 +101,8 @@ export function SelectionBubbleMenu({ editor }: { editor: Editor }) {
101
101
  aria-label="Selection formatting toolbar"
102
102
  onPointerDownCapture={handleSelectionMenuPointerDown}
103
103
  className={cn(
104
- 'flex items-center gap-1 overflow-x-auto border-border rounded-sm border bg-popover p-1 text-popover-foreground shadow-menu [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
105
- 'relative z-10'
104
+ 'flex items-center gap-1 overflow-x-auto rounded-sm border border-border bg-popover p-1 text-popover-foreground shadow-menu [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
105
+ 'relative z-50'
106
106
  )}
107
107
  >
108
108
  <div className="flex items-center gap-0.5">
@@ -120,7 +120,7 @@ export function SelectionBubbleMenu({ editor }: { editor: Editor }) {
120
120
  <Separator
121
121
  orientation="vertical"
122
122
  decorative
123
- className="my-auto h-[65%] mx-1 self-center"
123
+ className="mx-1 my-auto h-[65%] self-center"
124
124
  />
125
125
 
126
126
  <div className="flex items-center gap-0.5">
@@ -130,7 +130,7 @@ export function SlashCommandMenu({
130
130
  <ComboboxContent
131
131
  anchor={slashAnchor}
132
132
  align="start"
133
- className="w-72 min-w-72 max-w-[calc(100vw-2rem)] p-2 gap-2 flex flex-col"
133
+ className="flex w-72 max-w-[calc(100vw-2rem)] min-w-72 flex-col gap-2 p-2"
134
134
  collisionPadding={8}
135
135
  finalFocus={false}
136
136
  initialFocus={false}
@@ -166,17 +166,17 @@ export function SlashCommandMenu({
166
166
  onMouseEnter={() => onActiveIndexChange(index)}
167
167
  value={command}
168
168
  className={cn(
169
- 'border border-transparent p-2 data-highlighted:bg-card! data-highlighted:border-border!',
169
+ 'border border-transparent p-2 data-highlighted:border-border! data-highlighted:bg-card!',
170
170
  {
171
- 'bg-card border-border shadow-input text-foreground': isActive
171
+ 'border-border bg-card text-foreground shadow-input': isActive
172
172
  }
173
173
  )}
174
174
  >
175
- <span className="flex size-8 shrink-0 items-center justify-center rounded-sm bg-card border border-border shadow-input">
175
+ <span className="flex size-8 shrink-0 items-center justify-center rounded-sm border border-border bg-card shadow-input">
176
176
  <Icon />
177
177
  </span>
178
- <span className="min-w-0 space-y-1 flex flex-col w-full">
179
- <span className="font-medium leading-none">{command.title}</span>
178
+ <span className="flex w-full min-w-0 flex-col space-y-1">
179
+ <span className="leading-none font-medium">{command.title}</span>
180
180
  <span className="truncate text-xs text-muted-foreground">
181
181
  {command.description}
182
182
  </span>
@@ -92,6 +92,8 @@ export function SourceMode({
92
92
  applyList,
93
93
  applyStrike,
94
94
  applyUnderline,
95
+ canRedoMarkdownChange,
96
+ canUndoMarkdownChange,
95
97
  codeMirrorExtensions,
96
98
  editorRef,
97
99
  editorTheme,
@@ -122,20 +124,20 @@ export function SourceMode({
122
124
  return (
123
125
  <div
124
126
  className={cn(
125
- 'content-editor-wrapper relative flex min-h-[240px] max-h-[90vh] flex-col overflow-hidden resize-y rounded-md border bg-background',
127
+ 'content-editor-wrapper relative flex max-h-[90vh] min-h-[240px] resize-y flex-col overflow-hidden rounded-md border bg-background',
126
128
  { 'opacity-50': disabled },
127
129
  className
128
130
  )}
129
131
  >
130
132
  <EditorToolbar ariaLabel="Markdown editor toolbar" className="shrink-0">
131
- <div className="flex min-w-0 h-full flex-1 items-center overflow-x-auto">
133
+ <div className="flex h-full min-w-0 flex-1 items-center overflow-x-auto">
132
134
  <div className="flex items-center gap-0.5">
133
135
  <Button
134
136
  type="button"
135
137
  variant="ghost"
136
138
  size="icon-sm"
137
139
  onClick={undoMarkdownChange}
138
- disabled={disabled}
140
+ disabled={disabled || !canUndoMarkdownChange}
139
141
  aria-label="Undo"
140
142
  title="Undo"
141
143
  >
@@ -146,7 +148,7 @@ export function SourceMode({
146
148
  variant="ghost"
147
149
  size="icon-sm"
148
150
  onClick={redoMarkdownChange}
149
- disabled={disabled}
151
+ disabled={disabled || !canRedoMarkdownChange}
150
152
  aria-label="Redo"
151
153
  title="Redo"
152
154
  >
@@ -157,7 +159,7 @@ export function SourceMode({
157
159
  <Separator
158
160
  orientation="vertical"
159
161
  decorative
160
- className="my-auto h-[65%] mx-1 self-center"
162
+ className="mx-1 my-auto h-[65%] self-center"
161
163
  />
162
164
 
163
165
  <div className="flex items-center gap-0.5">
@@ -239,7 +241,7 @@ export function SourceMode({
239
241
  <Separator
240
242
  orientation="vertical"
241
243
  decorative
242
- className="my-auto h-[65%] mx-1 self-center"
244
+ className="mx-1 my-auto h-[65%] self-center"
243
245
  />
244
246
 
245
247
  <div className="flex items-center gap-0.5">
@@ -305,7 +307,7 @@ export function SourceMode({
305
307
  <Separator
306
308
  orientation="vertical"
307
309
  decorative
308
- className="my-auto h-[65%] mx-1 self-center"
310
+ className="mx-1 my-auto h-[65%] self-center"
309
311
  />
310
312
 
311
313
  <div className="flex items-center">
@@ -346,9 +348,9 @@ export function SourceMode({
346
348
  highlightActiveLineGutter: false
347
349
  }}
348
350
  className={cn(
349
- 'flex min-h-0 flex-1 flex-col overflow-hidden font-mono text-sm font-normal leading-6 [&_.cm-content]:!bg-transparent [&_.cm-editor]:!bg-input [&_.cm-gutters]:!bg-input [&_.cm-scroller]:!bg-input',
351
+ 'flex min-h-0 flex-1 flex-col overflow-hidden font-mono text-sm leading-6 font-normal [&_.cm-content]:!bg-transparent [&_.cm-editor]:!bg-input [&_.cm-gutters]:!bg-input [&_.cm-scroller]:!bg-input',
350
352
  {
351
- 'opacity-50 cursor-not-allowed': disabled
353
+ 'cursor-not-allowed opacity-50': disabled
352
354
  }
353
355
  )}
354
356
  />
@@ -13,10 +13,10 @@ export function TableAddControls({ controls }: TableAddControlsProps) {
13
13
  if (!controls) return null
14
14
 
15
15
  return createPortal(
16
- <div className="contents not-prose" contentEditable={false}>
16
+ <div className="not-prose contents" contentEditable={false}>
17
17
  <Button
18
18
  aria-label="Add table column"
19
- className="group absolute top-0 right-0 bottom-6 z-[1] inline-flex h-auto w-4 shrink-0 cursor-pointer items-center justify-center rounded-none border border-border bg-muted/80 p-0 whitespace-nowrap outline-none transition-colors select-none hover:bg-muted focus-visible:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/50"
19
+ className="group absolute top-0 right-0 bottom-6 z-[1] inline-flex h-auto w-4 shrink-0 cursor-pointer items-center justify-center rounded-none border border-border bg-muted/80 p-0 whitespace-nowrap transition-colors outline-none select-none hover:bg-muted focus-visible:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/50"
20
20
  onClick={controls.addColumn}
21
21
  onPointerDown={(event) => event.preventDefault()}
22
22
  title="Add table column"
@@ -29,7 +29,7 @@ export function TableAddControls({ controls }: TableAddControlsProps) {
29
29
  </Button>
30
30
  <Button
31
31
  aria-label="Add table row"
32
- className="group absolute right-6 bottom-0 left-0 z-[1] inline-flex h-4 w-auto shrink-0 cursor-pointer items-center justify-center rounded-none border border-border bg-muted/80 p-0 whitespace-nowrap outline-none transition-colors select-none hover:bg-muted focus-visible:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/50"
32
+ className="group absolute right-6 bottom-0 left-0 z-[1] inline-flex h-4 w-auto shrink-0 cursor-pointer items-center justify-center rounded-none border border-border bg-muted/80 p-0 whitespace-nowrap transition-colors outline-none select-none hover:bg-muted focus-visible:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/50"
33
33
  onClick={controls.addRow}
34
34
  onPointerDown={(event) => event.preventDefault()}
35
35
  title="Add table row"
@@ -202,7 +202,7 @@ export function TableBubbleMenu({ editor }: { editor: Editor }) {
202
202
  role="toolbar"
203
203
  aria-label="Table formatting toolbar"
204
204
  className={cn(
205
- 'flex items-center gap-1 overflow-x-auto border-border rounded-sm border bg-popover p-1 text-popover-foreground shadow-menu [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
205
+ 'flex items-center gap-1 overflow-x-auto rounded-sm border border-border bg-popover p-1 text-popover-foreground shadow-menu [scrollbar-width:none] [&::-webkit-scrollbar]:hidden',
206
206
  'relative z-50'
207
207
  )}
208
208
  >
@@ -235,7 +235,7 @@ export function TableBubbleMenu({ editor }: { editor: Editor }) {
235
235
  <Separator
236
236
  orientation="vertical"
237
237
  decorative
238
- className="my-auto h-5 w-px mx-1 self-center bg-border opacity-100"
238
+ className="mx-1 my-auto h-5 w-px self-center bg-border opacity-100"
239
239
  />
240
240
  <div className="flex items-center gap-0.5">
241
241
  <Button
@@ -126,7 +126,7 @@ export const RemovableImageNode: React.FC<NodeViewProps> = (props) => {
126
126
  <div
127
127
  data-content-editor-image-controls-overlay=""
128
128
  className={cn(
129
- 'pointer-events-none rounded-md absolute inset-0 flex items-center justify-center gap-1 bg-black/10 backdrop-blur-xs transition-opacity duration-200 ease-out',
129
+ 'pointer-events-none absolute inset-0 flex items-center justify-center gap-1 rounded-md bg-black/10 backdrop-blur-xs transition-opacity duration-200 ease-out',
130
130
  {
131
131
  'opacity-100': isControlsVisible,
132
132
  'opacity-0': !isControlsVisible
@@ -26,8 +26,7 @@ type EditorButtonProps = React.ComponentProps<typeof Button> & {
26
26
  }
27
27
 
28
28
  export interface BlockquoteButtonProps
29
- extends Omit<EditorButtonProps, 'type'>,
30
- Omit<UseBlockquoteConfig, 'hideWhenUnavailable'> {
29
+ extends Omit<EditorButtonProps, 'type'>, Omit<UseBlockquoteConfig, 'hideWhenUnavailable'> {
31
30
  availability?: ControlAvailability
32
31
  /**
33
32
  * Optional text to display alongside the icon.
@@ -26,8 +26,7 @@ type EditorButtonProps = React.ComponentProps<typeof Button> & {
26
26
  }
27
27
 
28
28
  export interface CodeBlockButtonProps
29
- extends Omit<EditorButtonProps, 'type'>,
30
- Omit<UseCodeBlockConfig, 'hideWhenUnavailable'> {
29
+ extends Omit<EditorButtonProps, 'type'>, Omit<UseCodeBlockConfig, 'hideWhenUnavailable'> {
31
30
  availability?: ControlAvailability
32
31
  /**
33
32
  * Optional text to display alongside the icon.