@mihcm/ui 0.14.1 → 0.15.1
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.
- package/dist/CheckboxGrid.native.d.ts.map +1 -1
- package/dist/CheckboxGrid.native.js +2 -1
- package/dist/CheckboxGrid.native.js.map +1 -1
- package/dist/Combobox.native.d.ts.map +1 -1
- package/dist/Combobox.native.js +2 -1
- package/dist/Combobox.native.js.map +1 -1
- package/dist/DataTable/column-filter.d.ts +8 -0
- package/dist/DataTable/column-filter.d.ts.map +1 -0
- package/dist/DataTable/column-filter.js +67 -0
- package/dist/DataTable/column-filter.js.map +1 -0
- package/dist/DataTable/column-header.d.ts +16 -0
- package/dist/DataTable/column-header.d.ts.map +1 -0
- package/dist/DataTable/column-header.js +11 -0
- package/dist/DataTable/column-header.js.map +1 -0
- package/dist/DataTable/column-visibility.d.ts +7 -0
- package/dist/DataTable/column-visibility.d.ts.map +1 -0
- package/dist/DataTable/column-visibility.js +35 -0
- package/dist/DataTable/column-visibility.js.map +1 -0
- package/dist/DataTable/index.d.ts +5 -0
- package/dist/DataTable/index.d.ts.map +1 -0
- package/dist/DataTable/index.js +5 -0
- package/dist/DataTable/index.js.map +1 -0
- package/dist/DataTable/pinning.d.ts +13 -0
- package/dist/DataTable/pinning.d.ts.map +1 -0
- package/dist/DataTable/pinning.js +29 -0
- package/dist/DataTable/pinning.js.map +1 -0
- package/dist/DataTable.d.ts +3 -7
- package/dist/DataTable.d.ts.map +1 -1
- package/dist/DataTable.js +7 -126
- package/dist/DataTable.js.map +1 -1
- package/dist/Dialog.native.d.ts +3 -1
- package/dist/Dialog.native.d.ts.map +1 -1
- package/dist/Dialog.native.js +2 -2
- package/dist/Dialog.native.js.map +1 -1
- package/dist/Form/building-blocks.d.ts +26 -0
- package/dist/Form/building-blocks.d.ts.map +1 -0
- package/dist/Form/building-blocks.js +29 -0
- package/dist/Form/building-blocks.js.map +1 -0
- package/dist/Form/fields-choice.d.ts +72 -0
- package/dist/Form/fields-choice.d.ts.map +1 -0
- package/dist/Form/fields-choice.js +69 -0
- package/dist/Form/fields-choice.js.map +1 -0
- package/dist/Form/fields-complex.d.ts +28 -0
- package/dist/Form/fields-complex.d.ts.map +1 -0
- package/dist/Form/fields-complex.js +38 -0
- package/dist/Form/fields-complex.js.map +1 -0
- package/dist/Form/fields-date.d.ts +46 -0
- package/dist/Form/fields-date.d.ts.map +1 -0
- package/dist/Form/fields-date.js +41 -0
- package/dist/Form/fields-date.js.map +1 -0
- package/dist/Form/fields-text.d.ts +47 -0
- package/dist/Form/fields-text.d.ts.map +1 -0
- package/dist/Form/fields-text.js +46 -0
- package/dist/Form/fields-text.js.map +1 -0
- package/dist/Form/fields-toggle.d.ts +24 -0
- package/dist/Form/fields-toggle.d.ts.map +1 -0
- package/dist/Form/fields-toggle.js +32 -0
- package/dist/Form/fields-toggle.js.map +1 -0
- package/dist/Form/helpers.d.ts +66 -0
- package/dist/Form/helpers.d.ts.map +1 -0
- package/dist/Form/helpers.js +44 -0
- package/dist/Form/helpers.js.map +1 -0
- package/dist/Form/types.d.ts +25 -0
- package/dist/Form/types.d.ts.map +1 -0
- package/dist/Form/types.js +8 -0
- package/dist/Form/types.js.map +1 -0
- package/dist/Form.d.ts +24 -298
- package/dist/Form.d.ts.map +1 -1
- package/dist/Form.js +30 -246
- package/dist/Form.js.map +1 -1
- package/dist/IconSidebar.d.ts +6 -46
- package/dist/IconSidebar.d.ts.map +1 -1
- package/dist/IconSidebar.js +6 -116
- package/dist/IconSidebar.js.map +1 -1
- package/dist/MainSidebar/back-button.d.ts +14 -0
- package/dist/MainSidebar/back-button.d.ts.map +1 -0
- package/dist/MainSidebar/back-button.js +14 -0
- package/dist/MainSidebar/back-button.js.map +1 -0
- package/dist/MainSidebar/breadcrumb.d.ts +10 -0
- package/dist/MainSidebar/breadcrumb.d.ts.map +1 -0
- package/dist/MainSidebar/breadcrumb.js +24 -0
- package/dist/MainSidebar/breadcrumb.js.map +1 -0
- package/dist/MainSidebar/columns.d.ts +3 -0
- package/dist/MainSidebar/columns.d.ts.map +1 -0
- package/dist/MainSidebar/columns.js +198 -0
- package/dist/MainSidebar/columns.js.map +1 -0
- package/dist/MainSidebar/command.d.ts +3 -0
- package/dist/MainSidebar/command.d.ts.map +1 -0
- package/dist/MainSidebar/command.js +193 -0
- package/dist/MainSidebar/command.js.map +1 -0
- package/dist/MainSidebar/drilldown.d.ts +3 -0
- package/dist/MainSidebar/drilldown.d.ts.map +1 -0
- package/dist/MainSidebar/drilldown.js +154 -0
- package/dist/MainSidebar/drilldown.js.map +1 -0
- package/dist/MainSidebar/expanded.d.ts +7 -0
- package/dist/MainSidebar/expanded.d.ts.map +1 -0
- package/dist/MainSidebar/expanded.js +102 -0
- package/dist/MainSidebar/expanded.js.map +1 -0
- package/dist/MainSidebar/floating.d.ts +3 -0
- package/dist/MainSidebar/floating.d.ts.map +1 -0
- package/dist/MainSidebar/floating.js +116 -0
- package/dist/MainSidebar/floating.js.map +1 -0
- package/dist/MainSidebar/helpers.d.ts +50 -0
- package/dist/MainSidebar/helpers.d.ts.map +1 -0
- package/dist/MainSidebar/helpers.js +150 -0
- package/dist/MainSidebar/helpers.js.map +1 -0
- package/dist/MainSidebar/hover.d.ts +3 -0
- package/dist/MainSidebar/hover.d.ts.map +1 -0
- package/dist/MainSidebar/hover.js +177 -0
- package/dist/MainSidebar/hover.js.map +1 -0
- package/dist/MainSidebar/index.d.ts +6 -0
- package/dist/MainSidebar/index.d.ts.map +1 -0
- package/dist/MainSidebar/index.js +108 -0
- package/dist/MainSidebar/index.js.map +1 -0
- package/dist/MainSidebar/mobile.d.ts +29 -0
- package/dist/MainSidebar/mobile.d.ts.map +1 -0
- package/dist/MainSidebar/mobile.js +38 -0
- package/dist/MainSidebar/mobile.js.map +1 -0
- package/dist/MainSidebar/motion.d.ts +23 -0
- package/dist/MainSidebar/motion.d.ts.map +1 -0
- package/dist/MainSidebar/motion.js +40 -0
- package/dist/MainSidebar/motion.js.map +1 -0
- package/dist/MainSidebar/rail.d.ts +24 -0
- package/dist/MainSidebar/rail.d.ts.map +1 -0
- package/dist/MainSidebar/rail.js +29 -0
- package/dist/MainSidebar/rail.js.map +1 -0
- package/dist/MainSidebar/search.d.ts +19 -0
- package/dist/MainSidebar/search.d.ts.map +1 -0
- package/dist/MainSidebar/search.js +33 -0
- package/dist/MainSidebar/search.js.map +1 -0
- package/dist/MainSidebar/types.d.ts +161 -0
- package/dist/MainSidebar/types.d.ts.map +1 -0
- package/dist/MainSidebar/types.js +2 -0
- package/dist/MainSidebar/types.js.map +1 -0
- package/dist/MainSidebar.d.ts +6 -1
- package/dist/MainSidebar.d.ts.map +1 -1
- package/dist/MainSidebar.js +6 -1
- package/dist/MainSidebar.js.map +1 -1
- package/dist/NavigationMenu.js +1 -1
- package/dist/NavigationMenu.js.map +1 -1
- package/dist/RichTextEditor/theme.d.ts +44 -0
- package/dist/RichTextEditor/theme.d.ts.map +1 -0
- package/dist/RichTextEditor/theme.js +41 -0
- package/dist/RichTextEditor/theme.js.map +1 -0
- package/dist/RichTextEditor/toolbar-icons.d.ts +21 -0
- package/dist/RichTextEditor/toolbar-icons.d.ts.map +1 -0
- package/dist/RichTextEditor/toolbar-icons.js +21 -0
- package/dist/RichTextEditor/toolbar-icons.js.map +1 -0
- package/dist/RichTextEditor/toolbar.d.ts +5 -0
- package/dist/RichTextEditor/toolbar.d.ts.map +1 -0
- package/dist/RichTextEditor/toolbar.js +116 -0
- package/dist/RichTextEditor/toolbar.js.map +1 -0
- package/dist/RichTextEditor.d.ts +16 -9
- package/dist/RichTextEditor.d.ts.map +1 -1
- package/dist/RichTextEditor.js +18 -164
- package/dist/RichTextEditor.js.map +1 -1
- package/dist/Select/content.d.ts +9 -0
- package/dist/Select/content.d.ts.map +1 -0
- package/dist/Select/content.js +80 -0
- package/dist/Select/content.js.map +1 -0
- package/dist/Select/context.d.ts +27 -0
- package/dist/Select/context.d.ts.map +1 -0
- package/dist/Select/context.js +35 -0
- package/dist/Select/context.js.map +1 -0
- package/dist/Select/item.d.ts +13 -0
- package/dist/Select/item.d.ts.map +1 -0
- package/dist/Select/item.js +39 -0
- package/dist/Select/item.js.map +1 -0
- package/dist/Select/parts.d.ts +14 -0
- package/dist/Select/parts.d.ts.map +1 -0
- package/dist/Select/parts.js +17 -0
- package/dist/Select/parts.js.map +1 -0
- package/dist/Select/react-select.d.ts +25 -0
- package/dist/Select/react-select.d.ts.map +1 -0
- package/dist/Select/react-select.js +66 -0
- package/dist/Select/react-select.js.map +1 -0
- package/dist/Select/root.d.ts +15 -0
- package/dist/Select/root.d.ts.map +1 -0
- package/dist/Select/root.js +41 -0
- package/dist/Select/root.js.map +1 -0
- package/dist/Select/trigger.d.ts +15 -0
- package/dist/Select/trigger.d.ts.map +1 -0
- package/dist/Select/trigger.js +61 -0
- package/dist/Select/trigger.js.map +1 -0
- package/dist/Select.d.ts +14 -62
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +14 -293
- package/dist/Select.js.map +1 -1
- package/dist/Sidebar/context.d.ts +28 -0
- package/dist/Sidebar/context.d.ts.map +1 -0
- package/dist/Sidebar/context.js +37 -0
- package/dist/Sidebar/context.js.map +1 -0
- package/dist/Sidebar/group.d.ts +13 -0
- package/dist/Sidebar/group.d.ts.map +1 -0
- package/dist/Sidebar/group.js +20 -0
- package/dist/Sidebar/group.js.map +1 -0
- package/dist/Sidebar/icons.d.ts +7 -0
- package/dist/Sidebar/icons.d.ts.map +1 -0
- package/dist/Sidebar/icons.js +12 -0
- package/dist/Sidebar/icons.js.map +1 -0
- package/dist/Sidebar/layout.d.ts +9 -0
- package/dist/Sidebar/layout.d.ts.map +1 -0
- package/dist/Sidebar/layout.js +21 -0
- package/dist/Sidebar/layout.js.map +1 -0
- package/dist/Sidebar/menu.d.ts +29 -0
- package/dist/Sidebar/menu.d.ts.map +1 -0
- package/dist/Sidebar/menu.js +55 -0
- package/dist/Sidebar/menu.js.map +1 -0
- package/dist/Sidebar/provider.d.ts +33 -0
- package/dist/Sidebar/provider.d.ts.map +1 -0
- package/dist/Sidebar/provider.js +110 -0
- package/dist/Sidebar/provider.js.map +1 -0
- package/dist/Sidebar/sidebar.d.ts +17 -0
- package/dist/Sidebar/sidebar.d.ts.map +1 -0
- package/dist/Sidebar/sidebar.js +51 -0
- package/dist/Sidebar/sidebar.js.map +1 -0
- package/dist/Sidebar/submenu.d.ts +13 -0
- package/dist/Sidebar/submenu.d.ts.map +1 -0
- package/dist/Sidebar/submenu.js +17 -0
- package/dist/Sidebar/submenu.js.map +1 -0
- package/dist/Sidebar/trigger.d.ts +9 -0
- package/dist/Sidebar/trigger.d.ts.map +1 -0
- package/dist/Sidebar/trigger.js +33 -0
- package/dist/Sidebar/trigger.js.map +1 -0
- package/dist/Sidebar.d.ts +14 -104
- package/dist/Sidebar.d.ts.map +1 -1
- package/dist/Sidebar.js +14 -300
- package/dist/Sidebar.js.map +1 -1
- package/dist/StatCard.d.ts +67 -9
- package/dist/StatCard.d.ts.map +1 -1
- package/dist/StatCard.js +111 -9
- package/dist/StatCard.js.map +1 -1
- package/dist/TransferList.native.d.ts.map +1 -1
- package/dist/TransferList.native.js +2 -1
- package/dist/TransferList.native.js.map +1 -1
- package/package.json +2 -2
- package/src/CheckboxGrid.native.tsx +2 -1
- package/src/Combobox.native.tsx +2 -1
- package/src/DataTable/column-filter.tsx +134 -0
- package/src/DataTable/column-header.tsx +67 -0
- package/src/DataTable/column-visibility.tsx +87 -0
- package/src/DataTable/index.ts +4 -0
- package/src/DataTable/pinning.ts +40 -0
- package/src/DataTable.tsx +14 -297
- package/src/Dialog.native.tsx +4 -2
- package/src/Form/building-blocks.tsx +97 -0
- package/src/Form/fields-choice.tsx +312 -0
- package/src/Form/fields-complex.tsx +195 -0
- package/src/Form/fields-date.tsx +195 -0
- package/src/Form/fields-text.tsx +218 -0
- package/src/Form/fields-toggle.tsx +123 -0
- package/src/Form/helpers.tsx +189 -0
- package/src/Form/types.ts +26 -0
- package/src/Form.tsx +91 -1308
- package/src/IconSidebar.tsx +20 -442
- package/src/MainSidebar/back-button.tsx +58 -0
- package/src/MainSidebar/breadcrumb.tsx +53 -0
- package/src/MainSidebar/columns.tsx +350 -0
- package/src/MainSidebar/command.tsx +404 -0
- package/src/MainSidebar/drilldown.tsx +373 -0
- package/src/MainSidebar/expanded.tsx +414 -0
- package/src/MainSidebar/floating.tsx +268 -0
- package/src/MainSidebar/helpers.ts +166 -0
- package/src/MainSidebar/hover.tsx +334 -0
- package/src/MainSidebar/index.tsx +191 -0
- package/src/MainSidebar/mobile.tsx +117 -0
- package/src/MainSidebar/motion.ts +64 -0
- package/src/MainSidebar/rail.tsx +137 -0
- package/src/MainSidebar/search.tsx +99 -0
- package/src/MainSidebar/types.ts +208 -0
- package/src/MainSidebar.tsx +15 -4
- package/src/NavigationMenu.tsx +1 -1
- package/src/RichTextEditor/theme.ts +43 -0
- package/src/RichTextEditor/toolbar-icons.tsx +40 -0
- package/src/RichTextEditor/toolbar.tsx +271 -0
- package/src/RichTextEditor.tsx +23 -371
- package/src/Select/content.tsx +111 -0
- package/src/Select/context.tsx +66 -0
- package/src/Select/item.tsx +97 -0
- package/src/Select/parts.tsx +43 -0
- package/src/Select/react-select.tsx +216 -0
- package/src/Select/root.tsx +75 -0
- package/src/Select/trigger.tsx +122 -0
- package/src/Select.tsx +34 -692
- package/src/Sidebar/context.tsx +72 -0
- package/src/Sidebar/group.tsx +69 -0
- package/src/Sidebar/icons.tsx +42 -0
- package/src/Sidebar/layout.tsx +64 -0
- package/src/Sidebar/menu.tsx +171 -0
- package/src/Sidebar/provider.tsx +224 -0
- package/src/Sidebar/sidebar.tsx +178 -0
- package/src/Sidebar/submenu.tsx +58 -0
- package/src/Sidebar/trigger.tsx +104 -0
- package/src/Sidebar.tsx +44 -927
- package/src/StatCard.tsx +365 -20
- package/src/TransferList.native.tsx +2 -1
- package/dist/TiptapEditor.d.ts +0 -24
- package/dist/TiptapEditor.d.ts.map +0 -1
- package/dist/TiptapEditor.js +0 -84
- package/dist/TiptapEditor.js.map +0 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme + variant config for RichTextEditor.
|
|
3
|
+
*
|
|
4
|
+
* `editorTheme` maps Lexical's internal class names to MiHCM Tailwind tokens
|
|
5
|
+
* so the editor body matches the rest of the design system in light/dark.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type RichTextEditorVariant = 'minimal' | 'default' | 'semi' | 'full';
|
|
9
|
+
|
|
10
|
+
export const editorTheme = {
|
|
11
|
+
paragraph: 'mb-2 last:mb-0',
|
|
12
|
+
heading: {
|
|
13
|
+
h1: 'text-2xl font-bold mb-3 text-foreground',
|
|
14
|
+
h2: 'text-xl font-semibold mb-2 text-foreground',
|
|
15
|
+
h3: 'text-lg font-medium mb-2 text-foreground',
|
|
16
|
+
},
|
|
17
|
+
text: {
|
|
18
|
+
bold: 'font-bold',
|
|
19
|
+
italic: 'italic',
|
|
20
|
+
underline: 'underline',
|
|
21
|
+
strikethrough: 'line-through',
|
|
22
|
+
underlineStrikethrough: 'underline line-through',
|
|
23
|
+
code: 'font-mono text-sm bg-muted px-1.5 py-0.5 rounded',
|
|
24
|
+
subscript: 'align-sub',
|
|
25
|
+
superscript: 'align-super',
|
|
26
|
+
},
|
|
27
|
+
list: {
|
|
28
|
+
ul: 'list-disc ml-6 mb-2',
|
|
29
|
+
ol: 'list-decimal ml-6 mb-2',
|
|
30
|
+
listitem: 'mb-0.5',
|
|
31
|
+
listitemChecked: 'line-through opacity-60 relative ml-2 list-none outline-none',
|
|
32
|
+
listitemUnchecked: 'relative ml-2 list-none outline-none',
|
|
33
|
+
nested: { listitem: 'list-none' },
|
|
34
|
+
checklist: 'list-none ml-0',
|
|
35
|
+
},
|
|
36
|
+
link: 'text-primary underline cursor-pointer hover:text-primary/80',
|
|
37
|
+
quote: 'border-l-4 border-primary-200 dark:border-primary-800 pl-4 italic text-muted-foreground mb-2',
|
|
38
|
+
code: 'font-mono text-sm bg-muted p-3 rounded-md mb-2 block overflow-x-auto',
|
|
39
|
+
horizontalRule: 'my-4 border-t border-border',
|
|
40
|
+
table: 'border-collapse border border-border w-full mb-2',
|
|
41
|
+
tableCell: 'border border-border px-2 py-1.5 text-sm min-w-[75px]',
|
|
42
|
+
tableCellHeader: 'border border-border px-2 py-1.5 text-sm font-semibold bg-muted/50',
|
|
43
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tiny presentational primitives for the RichTextEditor toolbar — kept local
|
|
5
|
+
* so the editor doesn't pull in a full icon set for ~30 glyphs.
|
|
6
|
+
*/
|
|
7
|
+
import { type ReactNode } from 'react';
|
|
8
|
+
import { cn } from '../internal/cn.js';
|
|
9
|
+
|
|
10
|
+
export function TbIcon({ d, className }: { d: string; className?: string }) {
|
|
11
|
+
return (
|
|
12
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={cn('size-3.5', className)}>
|
|
13
|
+
<path d={d} />
|
|
14
|
+
</svg>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function TbMultiIcon({ paths, className }: { paths: string[]; className?: string }) {
|
|
19
|
+
return (
|
|
20
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={cn('size-3.5', className)}>
|
|
21
|
+
{paths.map((d, i) => <path key={i} d={d} />)}
|
|
22
|
+
</svg>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function TbBtn({ active, onClick, title, children }: { active?: boolean; onClick: () => void; title: string; children: ReactNode }) {
|
|
27
|
+
return (
|
|
28
|
+
<button type="button" onClick={onClick} title={title} aria-label={title} aria-pressed={active} className={cn(
|
|
29
|
+
'flex items-center justify-center size-7 rounded transition-colors duration-150 cursor-pointer',
|
|
30
|
+
'hover:bg-muted focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
31
|
+
active && 'border border-primary bg-primary text-primary-foreground shadow-mi-card',
|
|
32
|
+
)}>
|
|
33
|
+
{children}
|
|
34
|
+
</button>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function TbSep() {
|
|
39
|
+
return <span className="w-px h-4 bg-border mx-0.5" aria-hidden="true" />;
|
|
40
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Toolbar plugin for the RichTextEditor — registers selection-driven format
|
|
5
|
+
* state and dispatches Lexical commands when toolbar buttons are pressed.
|
|
6
|
+
*
|
|
7
|
+
* Visible button set is gated by the editor's `variant` prop.
|
|
8
|
+
*/
|
|
9
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
10
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js';
|
|
11
|
+
import {
|
|
12
|
+
$isRangeSelection,
|
|
13
|
+
$getSelection,
|
|
14
|
+
$createParagraphNode,
|
|
15
|
+
FORMAT_TEXT_COMMAND,
|
|
16
|
+
FORMAT_ELEMENT_COMMAND,
|
|
17
|
+
INDENT_CONTENT_COMMAND,
|
|
18
|
+
OUTDENT_CONTENT_COMMAND,
|
|
19
|
+
UNDO_COMMAND,
|
|
20
|
+
REDO_COMMAND,
|
|
21
|
+
} from 'lexical';
|
|
22
|
+
import { $createHeadingNode, $createQuoteNode, type HeadingTagType } from '@lexical/rich-text';
|
|
23
|
+
import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, INSERT_CHECK_LIST_COMMAND } from '@lexical/list';
|
|
24
|
+
import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
|
|
25
|
+
import { $setBlocksType } from '@lexical/selection';
|
|
26
|
+
import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode.js';
|
|
27
|
+
import { $createTableNodeWithDimensions } from '@lexical/table';
|
|
28
|
+
import { TbBtn, TbIcon, TbMultiIcon, TbSep } from './toolbar-icons.js';
|
|
29
|
+
import type { RichTextEditorVariant } from './theme.js';
|
|
30
|
+
|
|
31
|
+
export function ToolbarPlugin({ variant }: { variant: RichTextEditorVariant }) {
|
|
32
|
+
const [editor] = useLexicalComposerContext();
|
|
33
|
+
const [isBold, setIsBold] = useState(false);
|
|
34
|
+
const [isItalic, setIsItalic] = useState(false);
|
|
35
|
+
const [isUnderline, setIsUnderline] = useState(false);
|
|
36
|
+
const [isStrikethrough, setIsStrikethrough] = useState(false);
|
|
37
|
+
const [isCode, setIsCode] = useState(false);
|
|
38
|
+
const [isSuperscript, setIsSuperscript] = useState(false);
|
|
39
|
+
const [isSubscript, setIsSubscript] = useState(false);
|
|
40
|
+
const [isLink, setIsLink] = useState(false);
|
|
41
|
+
|
|
42
|
+
const updateToolbar = useCallback(() => {
|
|
43
|
+
const selection = $getSelection();
|
|
44
|
+
if ($isRangeSelection(selection)) {
|
|
45
|
+
setIsBold(selection.hasFormat('bold'));
|
|
46
|
+
setIsItalic(selection.hasFormat('italic'));
|
|
47
|
+
setIsUnderline(selection.hasFormat('underline'));
|
|
48
|
+
setIsStrikethrough(selection.hasFormat('strikethrough'));
|
|
49
|
+
setIsCode(selection.hasFormat('code'));
|
|
50
|
+
setIsSuperscript(selection.hasFormat('superscript'));
|
|
51
|
+
setIsSubscript(selection.hasFormat('subscript'));
|
|
52
|
+
const node = selection.anchor.getNode();
|
|
53
|
+
const parent = node.getParent();
|
|
54
|
+
setIsLink($isLinkNode(parent) || $isLinkNode(node));
|
|
55
|
+
}
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
return editor.registerUpdateListener(({ editorState }) => {
|
|
60
|
+
editorState.read(() => updateToolbar());
|
|
61
|
+
});
|
|
62
|
+
}, [editor, updateToolbar]);
|
|
63
|
+
|
|
64
|
+
const formatHeading = (tag: HeadingTagType) => {
|
|
65
|
+
editor.update(() => {
|
|
66
|
+
const selection = $getSelection();
|
|
67
|
+
if ($isRangeSelection(selection)) $setBlocksType(selection, () => $createHeadingNode(tag));
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const formatParagraph = () => {
|
|
72
|
+
editor.update(() => {
|
|
73
|
+
const selection = $getSelection();
|
|
74
|
+
if ($isRangeSelection(selection)) $setBlocksType(selection, () => $createParagraphNode());
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const formatBlockQuote = () => {
|
|
79
|
+
editor.update(() => {
|
|
80
|
+
const selection = $getSelection();
|
|
81
|
+
if ($isRangeSelection(selection)) $setBlocksType(selection, () => $createQuoteNode());
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const insertLink = () => {
|
|
86
|
+
if (isLink) {
|
|
87
|
+
editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
|
|
88
|
+
} else {
|
|
89
|
+
const url = prompt('Enter URL:');
|
|
90
|
+
if (url) editor.dispatchCommand(TOGGLE_LINK_COMMAND, url);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const insertTable = () => {
|
|
95
|
+
editor.update(() => {
|
|
96
|
+
const table = $createTableNodeWithDimensions(3, 3, false);
|
|
97
|
+
const selection = $getSelection();
|
|
98
|
+
if ($isRangeSelection(selection)) {
|
|
99
|
+
const anchor = selection.anchor.getNode();
|
|
100
|
+
const parent = anchor.getTopLevelElementOrThrow();
|
|
101
|
+
parent.insertAfter(table);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const clearFormatting = () => {
|
|
107
|
+
editor.update(() => {
|
|
108
|
+
const selection = $getSelection();
|
|
109
|
+
if ($isRangeSelection(selection)) {
|
|
110
|
+
for (const format of ['bold', 'italic', 'underline', 'strikethrough', 'code', 'superscript', 'subscript'] as const) {
|
|
111
|
+
if (selection.hasFormat(format)) {
|
|
112
|
+
editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const showHistory = variant === 'semi' || variant === 'full';
|
|
120
|
+
const showHeadings = variant === 'semi' || variant === 'full';
|
|
121
|
+
const showUnderlineStrike = variant !== 'minimal';
|
|
122
|
+
const showLists = variant !== 'minimal';
|
|
123
|
+
const showCode = variant === 'semi' || variant === 'full';
|
|
124
|
+
const showLink = variant === 'semi' || variant === 'full';
|
|
125
|
+
const showIndent = variant === 'semi' || variant === 'full';
|
|
126
|
+
const showAlignment = variant === 'full';
|
|
127
|
+
const showSuperSub = variant === 'full';
|
|
128
|
+
const showCheckList = variant === 'full';
|
|
129
|
+
const showExtras = variant === 'full';
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div className="flex items-center gap-0.5 px-2 py-1.5 border-b border-border bg-muted/50 rounded-t-lg flex-wrap">
|
|
133
|
+
{showHistory && (
|
|
134
|
+
<>
|
|
135
|
+
<TbBtn title="Undo (Ctrl+Z)" onClick={() => editor.dispatchCommand(UNDO_COMMAND, undefined)}>
|
|
136
|
+
<TbIcon d="M3 7v6h6M3 13a9 9 0 1 0 3-7.7" />
|
|
137
|
+
</TbBtn>
|
|
138
|
+
<TbBtn title="Redo (Ctrl+Shift+Z)" onClick={() => editor.dispatchCommand(REDO_COMMAND, undefined)}>
|
|
139
|
+
<TbIcon d="M21 7v6h-6M21 13a9 9 0 1 1-3-7.7" />
|
|
140
|
+
</TbBtn>
|
|
141
|
+
<TbSep />
|
|
142
|
+
</>
|
|
143
|
+
)}
|
|
144
|
+
|
|
145
|
+
{showHeadings && (
|
|
146
|
+
<>
|
|
147
|
+
<TbBtn title="Heading 1" onClick={() => formatHeading('h1')}>
|
|
148
|
+
<span className="text-xs font-bold leading-none">H1</span>
|
|
149
|
+
</TbBtn>
|
|
150
|
+
<TbBtn title="Heading 2" onClick={() => formatHeading('h2')}>
|
|
151
|
+
<span className="text-xs font-bold leading-none">H2</span>
|
|
152
|
+
</TbBtn>
|
|
153
|
+
<TbBtn title="Heading 3" onClick={() => formatHeading('h3')}>
|
|
154
|
+
<span className="text-xs font-bold leading-none">H3</span>
|
|
155
|
+
</TbBtn>
|
|
156
|
+
<TbBtn title="Paragraph" onClick={formatParagraph}>
|
|
157
|
+
<span className="text-xs font-medium leading-none">¶</span>
|
|
158
|
+
</TbBtn>
|
|
159
|
+
<TbSep />
|
|
160
|
+
</>
|
|
161
|
+
)}
|
|
162
|
+
|
|
163
|
+
<TbBtn title="Bold (Ctrl+B)" active={isBold} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')}>
|
|
164
|
+
<span className="text-xs font-bold">B</span>
|
|
165
|
+
</TbBtn>
|
|
166
|
+
<TbBtn title="Italic (Ctrl+I)" active={isItalic} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')}>
|
|
167
|
+
<span className="text-xs italic">I</span>
|
|
168
|
+
</TbBtn>
|
|
169
|
+
{showUnderlineStrike && (
|
|
170
|
+
<>
|
|
171
|
+
<TbBtn title="Underline (Ctrl+U)" active={isUnderline} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline')}>
|
|
172
|
+
<span className="text-xs underline">U</span>
|
|
173
|
+
</TbBtn>
|
|
174
|
+
<TbBtn title="Strikethrough" active={isStrikethrough} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough')}>
|
|
175
|
+
<span className="text-xs line-through">S</span>
|
|
176
|
+
</TbBtn>
|
|
177
|
+
</>
|
|
178
|
+
)}
|
|
179
|
+
|
|
180
|
+
{showCode && (
|
|
181
|
+
<TbBtn title="Inline code" active={isCode} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'code')}>
|
|
182
|
+
<TbMultiIcon paths={['M16 18l6-6-6-6', 'M8 6l-6 6 6 6']} />
|
|
183
|
+
</TbBtn>
|
|
184
|
+
)}
|
|
185
|
+
|
|
186
|
+
{showSuperSub && (
|
|
187
|
+
<>
|
|
188
|
+
<TbBtn title="Superscript" active={isSuperscript} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'superscript')}>
|
|
189
|
+
<span className="text-xs leading-none">X<sup>2</sup></span>
|
|
190
|
+
</TbBtn>
|
|
191
|
+
<TbBtn title="Subscript" active={isSubscript} onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'subscript')}>
|
|
192
|
+
<span className="text-xs leading-none">X<sub>2</sub></span>
|
|
193
|
+
</TbBtn>
|
|
194
|
+
</>
|
|
195
|
+
)}
|
|
196
|
+
|
|
197
|
+
{(showLists || showLink) && <TbSep />}
|
|
198
|
+
|
|
199
|
+
{showLists && (
|
|
200
|
+
<>
|
|
201
|
+
<TbBtn title="Bullet list" onClick={() => editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined)}>
|
|
202
|
+
<TbIcon d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" />
|
|
203
|
+
</TbBtn>
|
|
204
|
+
<TbBtn title="Numbered list" onClick={() => editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined)}>
|
|
205
|
+
<TbIcon d="M10 6h11M10 12h11M10 18h11M3 5l2 1V4M3 11h2l-1 2h2M3 17l2 1-2 1" />
|
|
206
|
+
</TbBtn>
|
|
207
|
+
</>
|
|
208
|
+
)}
|
|
209
|
+
|
|
210
|
+
{showCheckList && (
|
|
211
|
+
<TbBtn title="Check list" onClick={() => editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND, undefined)}>
|
|
212
|
+
<TbMultiIcon paths={['M9 11l3 3L22 4', 'M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11']} />
|
|
213
|
+
</TbBtn>
|
|
214
|
+
)}
|
|
215
|
+
|
|
216
|
+
{showLink && (
|
|
217
|
+
<TbBtn title="Insert link" active={isLink} onClick={insertLink}>
|
|
218
|
+
<TbMultiIcon paths={['M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71', 'M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71']} />
|
|
219
|
+
</TbBtn>
|
|
220
|
+
)}
|
|
221
|
+
|
|
222
|
+
{showIndent && (
|
|
223
|
+
<>
|
|
224
|
+
<TbSep />
|
|
225
|
+
<TbBtn title="Indent" onClick={() => editor.dispatchCommand(INDENT_CONTENT_COMMAND, undefined)}>
|
|
226
|
+
<TbMultiIcon paths={['M3 8l4 4-4 4', 'M11 6h10', 'M11 12h10', 'M11 18h10']} />
|
|
227
|
+
</TbBtn>
|
|
228
|
+
<TbBtn title="Outdent" onClick={() => editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, undefined)}>
|
|
229
|
+
<TbMultiIcon paths={['M7 8l-4 4 4 4', 'M11 6h10', 'M11 12h10', 'M11 18h10']} />
|
|
230
|
+
</TbBtn>
|
|
231
|
+
</>
|
|
232
|
+
)}
|
|
233
|
+
|
|
234
|
+
{showAlignment && (
|
|
235
|
+
<>
|
|
236
|
+
<TbSep />
|
|
237
|
+
<TbBtn title="Align left" onClick={() => editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'left')}>
|
|
238
|
+
<TbIcon d="M17 10H3M21 6H3M21 14H3M17 18H3" />
|
|
239
|
+
</TbBtn>
|
|
240
|
+
<TbBtn title="Align center" onClick={() => editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'center')}>
|
|
241
|
+
<TbIcon d="M18 10H6M21 6H3M21 14H3M18 18H6" />
|
|
242
|
+
</TbBtn>
|
|
243
|
+
<TbBtn title="Align right" onClick={() => editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'right')}>
|
|
244
|
+
<TbIcon d="M21 10H7M21 6H3M21 14H3M21 18H7" />
|
|
245
|
+
</TbBtn>
|
|
246
|
+
<TbBtn title="Justify" onClick={() => editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, 'justify')}>
|
|
247
|
+
<TbIcon d="M3 6h18M3 12h18M3 18h18" />
|
|
248
|
+
</TbBtn>
|
|
249
|
+
</>
|
|
250
|
+
)}
|
|
251
|
+
|
|
252
|
+
{showExtras && (
|
|
253
|
+
<>
|
|
254
|
+
<TbSep />
|
|
255
|
+
<TbBtn title="Insert table (3×3)" onClick={insertTable}>
|
|
256
|
+
<TbMultiIcon paths={['M3 3h18v18H3V3z', 'M3 9h18', 'M3 15h18', 'M9 3v18', 'M15 3v18']} />
|
|
257
|
+
</TbBtn>
|
|
258
|
+
<TbBtn title="Block quote" onClick={formatBlockQuote}>
|
|
259
|
+
<TbMultiIcon paths={['M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1', 'M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1']} />
|
|
260
|
+
</TbBtn>
|
|
261
|
+
<TbBtn title="Horizontal rule" onClick={() => editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined)}>
|
|
262
|
+
<TbIcon d="M3 12h18" />
|
|
263
|
+
</TbBtn>
|
|
264
|
+
<TbBtn title="Clear formatting" onClick={clearFormatting}>
|
|
265
|
+
<TbMultiIcon paths={['M4 7h7l-2 9h7', 'M16 4l4 4-4 4', 'M7 20l5-5']} />
|
|
266
|
+
</TbBtn>
|
|
267
|
+
</>
|
|
268
|
+
)}
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
}
|