@pie-lib/editable-html-tip-tap 1.0.0 → 1.0.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/src/index.jsx CHANGED
@@ -27,6 +27,7 @@ import { color } from '@pie-lib/render-ui';
27
27
  import { primary } from './theme';
28
28
  import { PIE_TOOLBAR__CLASS } from './constants';
29
29
  import { DoneButton } from './plugins/toolbar/done-button';
30
+ import { DEFAULT_PLUGINS } from './plugins/index';
30
31
  import Bold from '@material-ui/icons/FormatBold';
31
32
  import Italic from '@material-ui/icons/FormatItalic';
32
33
  import Strikethrough from '@material-ui/icons/FormatStrikethrough';
@@ -40,8 +41,8 @@ import ImageIcon from '@material-ui/icons/Image';
40
41
  import { ToolbarIcon } from './plugins/respArea/icons';
41
42
  import Redo from '@material-ui/icons/Redo';
42
43
  import Undo from '@material-ui/icons/Undo';
43
- import TheatersIcon from "@material-ui/icons/Theaters";
44
- import VolumeUpIcon from "@material-ui/icons/VolumeUp";
44
+ import TheatersIcon from '@material-ui/icons/Theaters';
45
+ import VolumeUpIcon from '@material-ui/icons/VolumeUp';
45
46
  import { characterIcons, spanishConfig, specialConfig } from './plugins/characters/utils';
46
47
  import PropTypes from 'prop-types';
47
48
  import { MathToolbar, PureToolbar } from '@pie-lib/math-toolbar';
@@ -52,7 +53,9 @@ import CSSIcon from './plugins/css/icons';
52
53
 
53
54
  import { ImageUploadNode } from './extensions/image';
54
55
  import { Media } from './extensions/media';
55
- import { CSSMark } from "./extensions/css";
56
+ import { CSSMark } from './extensions/css';
57
+ import { AddColumn, AddRow, RemoveColumn, RemoveRow, RemoveTable } from "./plugins/table/icons";
58
+ import BorderAll from "@material-ui/icons/BorderAll";
56
59
 
57
60
  const CharacterIcon = ({ letter }) => (
58
61
  <div
@@ -248,15 +251,24 @@ const HeadingIcon = () => (
248
251
  );
249
252
 
250
253
  const ExtendedTable = Table.extend({
254
+ addAttributes() {
255
+ return {
256
+ border: { default: '1' },
257
+ };
258
+ },
251
259
  renderHTML(props) {
252
260
  const originalTable = this.parent(props);
261
+ const { border } = props.HTMLAttributes;
253
262
 
254
- originalTable[1].style = `${originalTable[1].style} width: 100%;
263
+ const previousStyle = `${originalTable[1].style}${originalTable[1].style.match(/.*; */) ? '' : ';'}`;
264
+
265
+ originalTable[1].style = `${previousStyle}
266
+ width: 100%;
255
267
  color: var(--pie-text, black);
256
268
  table-layout: fixed;
257
269
  border-collapse: collapse;
258
270
  background-color: var(--pie-background, rgba(255, 255, 255))`;
259
- originalTable[1].border = '1';
271
+ originalTable[1].border = border ? border : '1';
260
272
 
261
273
  return originalTable;
262
274
  },
@@ -353,6 +365,24 @@ const styles = (theme) => ({
353
365
  borderTop: '1px solid var(--gray-2)',
354
366
  margin: '2rem 0',
355
367
  },
368
+
369
+ '& table': {
370
+ tableLayout: 'fixed',
371
+ width: '100%',
372
+ borderCollapse: 'collapse',
373
+ color: color.text(),
374
+ backgroundColor: color.background(),
375
+ },
376
+ '& table:not([border="1"]) tr': {
377
+ borderTop: '1px solid #dfe2e5',
378
+ },
379
+ '& td, th': {
380
+ padding: '.6em 1em',
381
+ textAlign: 'center',
382
+ },
383
+ '& table:not([border="1"]) td, th': {
384
+ border: '1px solid #dfe2e5',
385
+ },
356
386
  },
357
387
  children: {
358
388
  padding: '10px 16px',
@@ -511,6 +541,7 @@ function TiptapContainer(props) {
511
541
  children,
512
542
  disableUnderline,
513
543
  disableScrollbar,
544
+ activePlugins,
514
545
  toolbarOpts,
515
546
  responseAreaProps,
516
547
  autoFocus,
@@ -579,6 +610,7 @@ function TiptapContainer(props) {
579
610
  editor={editor}
580
611
  responseAreaProps={responseAreaProps}
581
612
  toolbarOpts={toolbarOpts}
613
+ activePlugins={activePlugins}
582
614
  onChange={props.onChange}
583
615
  />
584
616
  )}
@@ -588,7 +620,7 @@ function TiptapContainer(props) {
588
620
 
589
621
  const EditorContainer = withStyles(styles)(TiptapContainer);
590
622
 
591
- function MenuBar({ editor, classes, toolbarOpts: toolOpts, responseAreaProps, onChange }) {
623
+ function MenuBar({ editor, classes, activePlugins, toolbarOpts: toolOpts, responseAreaProps, onChange }) {
592
624
  const [showPicker, setShowPicker] = useState(false);
593
625
  const toolbarOpts = toolOpts ?? {};
594
626
  // Read the current editor's state, and re-render the component when it changes
@@ -603,14 +635,14 @@ function MenuBar({ editor, classes, toolbarOpts: toolOpts, responseAreaProps, on
603
635
  currentNode = selection.node; // the selected node
604
636
  }
605
637
 
606
- const customToolbarActive =
638
+ const hideDefaultToolbar =
607
639
  ctx.editor?.isActive('math') ||
608
640
  ctx.editor?.isActive('explicit_constructed_response') ||
609
641
  ctx.editor?.isActive('imageUploadNode');
610
642
 
611
643
  return {
612
644
  currentNode,
613
- customToolbarActive,
645
+ hideDefaultToolbar,
614
646
  isFocused: ctx.editor?.isFocused,
615
647
  isBold: ctx.editor.isActive('bold') ?? false,
616
648
  canBold:
@@ -620,6 +652,7 @@ function MenuBar({ editor, classes, toolbarOpts: toolOpts, responseAreaProps, on
620
652
  .toggleBold()
621
653
  .run() ?? false,
622
654
  isTable: ctx.editor.isActive('table') ?? false,
655
+ tableHasBorder: ctx.editor.getAttributes('table')?.border === '1' ?? false,
623
656
  canTable:
624
657
  ctx.editor
625
658
  .can()
@@ -698,401 +731,315 @@ function MenuBar({ editor, classes, toolbarOpts: toolOpts, responseAreaProps, on
698
731
  const handleMouseDown = (e) => {
699
732
  e.preventDefault();
700
733
  };
734
+ const toolbarButtons = useMemo(
735
+ () => [
736
+ {
737
+ icon: <GridOn />,
738
+ onClick: (editor) =>
739
+ editor.chain().focus().insertTable({ rows: 2, cols: 2, withHeaderRow: false }).run(),
740
+ hidden: (state) => !activePlugins?.includes('table') || state.isTable,
741
+ isActive: (state) => state.isTable,
742
+ isDisabled: (state) => !state.canTable,
743
+ },
744
+ {
745
+ icon: <AddRow />,
746
+ onClick: (editor) =>
747
+ editor
748
+ .chain()
749
+ .focus()
750
+ .addRowAfter()
751
+ .run(),
752
+ hidden: (state) => !state.isTable,
753
+ isActive: (state) => state.isTable,
754
+ isDisabled: (state) => !state.canTable,
755
+ },
756
+ {
757
+ icon: <RemoveRow />,
758
+ onClick: (editor) =>
759
+ editor
760
+ .chain()
761
+ .focus()
762
+ .deleteRow()
763
+ .run(),
764
+ hidden: (state) => !state.isTable,
765
+ isActive: (state) => state.isTable,
766
+ isDisabled: (state) => !state.canTable,
767
+ },
768
+ {
769
+ icon: <AddColumn />,
770
+ onClick: (editor) =>
771
+ editor
772
+ .chain()
773
+ .focus()
774
+ .addColumnAfter()
775
+ .run(),
776
+ hidden: (state) => !state.isTable,
777
+ isActive: (state) => state.isTable,
778
+ isDisabled: (state) => !state.canTable,
779
+ },
780
+ {
781
+ icon: <RemoveColumn />,
782
+ onClick: (editor) =>
783
+ editor
784
+ .chain()
785
+ .focus()
786
+ .deleteColumn()
787
+ .run(),
788
+ hidden: (state) => !state.isTable,
789
+ isActive: (state) => state.isTable,
790
+ isDisabled: (state) => !state.canTable,
791
+ },
792
+ {
793
+ icon: <RemoveTable />,
794
+ onClick: (editor) =>
795
+ editor
796
+ .chain()
797
+ .focus()
798
+ .deleteTable()
799
+ .run(),
800
+ hidden: (state) => !state.isTable,
801
+ isActive: (state) => state.isTable,
802
+ isDisabled: (state) => !state.canTable,
803
+ },
804
+ {
805
+ icon: <BorderAll />,
806
+ onClick: (editor) => {
807
+ const tableAttrs = editor.getAttributes('table');
808
+
809
+ const update = {
810
+ ...tableAttrs,
811
+ border: tableAttrs.border !== '0' ? '0' : '1',
812
+ };
813
+
814
+ editor.commands.updateAttributes('table', update);
815
+ },
816
+ hidden: (state) => !state.isTable,
817
+ isActive: (state) => state.tableHasBorder,
818
+ isDisabled: (state) => !state.canTable,
819
+ },
820
+ {
821
+ icon: <Bold />,
822
+ onClick: (editor) =>
823
+ editor
824
+ .chain()
825
+ .focus()
826
+ .toggleBold()
827
+ .run(),
828
+ hidden: (state) => state.isTable,
829
+ isActive: (state) => state.isBold,
830
+ isDisabled: (state) => !state.canBold,
831
+ },
832
+ {
833
+ icon: <Italic />,
834
+ onClick: (editor) =>
835
+ editor
836
+ .chain()
837
+ .focus()
838
+ .toggleItalic()
839
+ .run(),
840
+ hidden: (state) => state.isTable,
841
+ isActive: (state) => state.isItalic,
842
+ isDisabled: (state) => !state.canItalic,
843
+ },
844
+ {
845
+ icon: <Strikethrough />,
846
+ onClick: (editor) =>
847
+ editor
848
+ .chain()
849
+ .focus()
850
+ .toggleStrike()
851
+ .run(),
852
+ hidden: (state) => state.isTable,
853
+ isActive: (state) => state.isStrike,
854
+ isDisabled: (state) => !state.canStrike,
855
+ },
856
+ {
857
+ icon: <Code />,
858
+ onClick: (editor) =>
859
+ editor
860
+ .chain()
861
+ .focus()
862
+ .toggleCode()
863
+ .run(),
864
+ hidden: (state) => state.isTable,
865
+ isActive: (state) => state.isCode,
866
+ isDisabled: (state) => !state.canCode,
867
+ },
868
+ {
869
+ icon: <Underline />,
870
+ onClick: (editor) =>
871
+ editor
872
+ .chain()
873
+ .focus()
874
+ .toggleUnderline()
875
+ .run(),
876
+ hidden: (state) => state.isTable,
877
+ isActive: (state) => state.isUnderline,
878
+ },
879
+ {
880
+ icon: <SubscriptIcon />,
881
+ onClick: (editor) =>
882
+ editor
883
+ .chain()
884
+ .focus()
885
+ .toggleSubscript()
886
+ .run(),
887
+ hidden: (state) => state.isTable,
888
+ isActive: (state) => state.isSubScript,
889
+ },
890
+ {
891
+ icon: <SuperscriptIcon />,
892
+ onClick: (editor) =>
893
+ editor
894
+ .chain()
895
+ .focus()
896
+ .toggleSuperscript()
897
+ .run(),
898
+ hidden: (state) => state.isTable,
899
+ isActive: (state) => state.isSuperScript,
900
+ },
901
+ {
902
+ icon: <ImageIcon />,
903
+ onClick: (editor) =>
904
+ editor
905
+ .chain()
906
+ .focus()
907
+ .setImageUploadNode()
908
+ .run(),
909
+ },
910
+ {
911
+ icon: <TheatersIcon />,
912
+ hidden: (state) => state.isTable,
913
+ onClick: (editor) =>
914
+ editor
915
+ .chain()
916
+ .focus()
917
+ .insertMedia({ tag: 'video' })
918
+ .run(),
919
+ },
920
+ {
921
+ icon: <VolumeUpIcon />,
922
+ hidden: (state) => state.isTable,
923
+ onClick: (editor) =>
924
+ editor
925
+ .chain()
926
+ .focus()
927
+ .insertMedia({ tag: 'audio' })
928
+ .run(),
929
+ },
930
+ {
931
+ icon: <CSSIcon />,
932
+ hidden: (state) => state.isTable,
933
+ onClick: (editor) => editor.commands.openCSSClassDialog(),
934
+ },
935
+ {
936
+ icon: <HeadingIcon />,
937
+ hidden: (state) => state.isTable,
938
+ onClick: (editor) =>
939
+ editor
940
+ .chain()
941
+ .focus()
942
+ .toggleHeading({ level: 3 })
943
+ .run(),
944
+ isActive: (state) => state.isHeading3,
945
+ },
946
+ {
947
+ icon: <Functions />,
948
+ onClick: (editor) =>
949
+ editor
950
+ .chain()
951
+ .focus()
952
+ .insertMath('')
953
+ .run(),
954
+ },
955
+ {
956
+ icon: <CharacterIcon letter="ñ" />,
957
+ hidden: (state) => state.isTable,
958
+ onClick: () => setShowPicker(spanishConfig),
959
+ },
960
+ {
961
+ icon: <CharacterIcon letter="€" />,
962
+ hidden: (state) => state.isTable,
963
+ onClick: () => setShowPicker(specialConfig),
964
+ },
965
+ {
966
+ icon: <TextAlignIcon editor={editor} />,
967
+ hidden: (state) => state.isTable,
968
+ onClick: () => {},
969
+ },
970
+ {
971
+ icon: <BulletedListIcon />,
972
+ hidden: (state) => state.isTable,
973
+ onClick: (editor) =>
974
+ editor
975
+ .chain()
976
+ .focus()
977
+ .toggleBulletList()
978
+ .run(),
979
+ isActive: (state) => state.isBulletList,
980
+ },
981
+ {
982
+ icon: <NumberedListIcon />,
983
+ hidden: (state) => state.isTable,
984
+ onClick: (editor) =>
985
+ editor
986
+ .chain()
987
+ .focus()
988
+ .toggleOrderedList()
989
+ .run(),
990
+ isActive: (state) => state.isOrderedList,
991
+ },
992
+ {
993
+ icon: <Undo />,
994
+ hidden: (state) => state.isTable,
995
+ onClick: (editor) =>
996
+ editor
997
+ .chain()
998
+ .focus()
999
+ .undo()
1000
+ .run(),
1001
+ isDisabled: (state) => !state.canUndo,
1002
+ },
1003
+ {
1004
+ icon: <Redo />,
1005
+ hidden: (state) => state.isTable,
1006
+ onClick: (editor) =>
1007
+ editor
1008
+ .chain()
1009
+ .focus()
1010
+ .redo()
1011
+ .run(),
1012
+ isDisabled: (state) => !state.canRedo,
1013
+ },
1014
+ ],
1015
+ [activePlugins, editor, spanishConfig, specialConfig, setShowPicker],
1016
+ );
701
1017
 
702
1018
  return (
703
1019
  <div className={names} style={{ ...customStyles }} onMouseDown={handleMouseDown}>
704
- {!editorState.customToolbarActive && (
1020
+ {!editorState.hideDefaultToolbar && (
705
1021
  <div className={classes.defaultToolbar} tabIndex="1">
706
1022
  <div className={classes.buttonsContainer}>
707
- <button
708
- onClick={(e) => {
709
- e.preventDefault();
710
- editor
711
- .chain()
712
- .focus()
713
- .insertTable()
714
- .run();
715
- }}
716
- disabled={!editorState.canTable}
717
- className={classNames(classes.button, { [classes.active]: editorState.isTable })}
718
- >
719
- <GridOn />
720
- </button>
721
- <button
722
- onClick={(e) => {
723
- e.preventDefault();
724
- editor
725
- .chain()
726
- .focus()
727
- .toggleBold()
728
- .run();
729
- }}
730
- disabled={!editorState.canBold}
731
- className={classNames(classes.button, { [classes.active]: editorState.isBold })}
732
- >
733
- <Bold />
734
- </button>
735
- <button
736
- onClick={() =>
737
- editor
738
- .chain()
739
- .focus()
740
- .toggleItalic()
741
- .run()
742
- }
743
- disabled={!editorState.canItalic}
744
- active={editorState.isItalic}
745
- className={classNames(classes.button, { [classes.active]: editorState.isItalic })}
746
- >
747
- <Italic />
748
- </button>
749
- <button
750
- onClick={() =>
751
- editor
752
- .chain()
753
- .focus()
754
- .toggleStrike()
755
- .run()
756
- }
757
- disabled={!editorState.canStrike}
758
- active={editorState.isStrike}
759
- className={classNames(classes.button, { [classes.active]: editorState.isStrike })}
760
- >
761
- <Strikethrough />
762
- </button>
763
- <button
764
- onClick={() =>
765
- editor
766
- .chain()
767
- .focus()
768
- .toggleCode()
769
- .run()
770
- }
771
- disabled={!editorState.canCode}
772
- active={editorState.isCode}
773
- className={classNames(classes.button, { [classes.active]: editorState.isCode })}
774
- >
775
- <Code />
776
- </button>
777
- {/*<button*/}
778
- {/* onClick={() =>*/}
779
- {/* editor*/}
780
- {/* .chain()*/}
781
- {/* .focus()*/}
782
- {/* .unsetAllMarks()*/}
783
- {/* .run()*/}
784
- {/* }*/}
785
- {/*>*/}
786
- {/* Clear marks*/}
787
- {/*</button>*/}
788
- {/*<button*/}
789
- {/* onClick={() =>*/}
790
- {/* editor*/}
791
- {/* .chain()*/}
792
- {/* .focus()*/}
793
- {/* .clearNodes()*/}
794
- {/* .run()*/}
795
- {/* }*/}
796
- {/*>*/}
797
- {/* Clear nodes*/}
798
- {/*</button>*/}
799
- {/*<button*/}
800
- {/* onClick={() =>*/}
801
- {/* editor*/}
802
- {/* .chain()*/}
803
- {/* .focus()*/}
804
- {/* .setParagraph()*/}
805
- {/* .run()*/}
806
- {/* }*/}
807
- {/* className={editorState.isParagraph ? classes.isActive : ''}*/}
808
- {/*>*/}
809
- {/* Paragraph*/}
810
- {/*</button>*/}
811
- {/*<button*/}
812
- {/* onClick={() =>*/}
813
- {/* editor*/}
814
- {/* .chain()*/}
815
- {/* .focus()*/}
816
- {/* .toggleHeading({ level: 1 })*/}
817
- {/* .run()*/}
818
- {/* }*/}
819
- {/* className={editorState.isHeading1 ? classes.isActive : ''}*/}
820
- {/*>*/}
821
- {/* H1*/}
822
- {/*</button>*/}
823
- {/*<button*/}
824
- {/* onClick={() =>*/}
825
- {/* editor*/}
826
- {/* .chain()*/}
827
- {/* .focus()*/}
828
- {/* .toggleHeading({ level: 2 })*/}
829
- {/* .run()*/}
830
- {/* }*/}
831
- {/* className={editorState.isHeading2 ? classes.isActive : ''}*/}
832
- {/*>*/}
833
- {/* H2*/}
834
- {/*</button>*/}
835
- <button
836
- onClick={() =>
837
- editor
838
- .chain()
839
- .focus()
840
- .toggleUnderline()
841
- .run()
842
- }
843
- className={classNames(classes.button, { [classes.active]: editorState.isUnderline })}
844
- >
845
- <Underline />
846
- </button>
847
- <button
848
- onClick={() =>
849
- editor
850
- .chain()
851
- .focus()
852
- .toggleSubscript()
853
- .run()
854
- }
855
- className={classNames(classes.button, { [classes.active]: editorState.isSubScript })}
856
- >
857
- <SubscriptIcon />
858
- </button>
859
- <button
860
- onClick={() =>
861
- editor
862
- .chain()
863
- .focus()
864
- .toggleSuperscript()
865
- .run()
866
- }
867
- className={classNames(classes.button, { [classes.active]: editorState.isSuperScript })}
868
- >
869
- <SuperscriptIcon />
870
- </button>
871
- <button
872
- onClick={() =>
873
- editor
874
- .chain()
875
- .focus()
876
- .setImageUploadNode()
877
- .run()
878
- }
879
- className={classNames(classes.button, { [classes.active]: editorState.isSuperScript })}
880
- >
881
- <ImageIcon />
882
- </button>
883
- <button
884
- onClick={() =>
885
- editor
886
- .chain()
887
- .focus()
888
- .insertMedia({
889
- tag: 'video',
890
- })
891
- .run()
892
- }
893
- className={classNames(classes.button)}
894
- >
895
- <TheatersIcon />
896
- </button>
897
- <button
898
- onClick={() =>
899
- editor
900
- .chain()
901
- .focus()
902
- .insertMedia({
903
- tag: 'audio',
904
- })
905
- .run()
906
- }
907
- className={classNames(classes.button)}
908
- >
909
- <VolumeUpIcon />
910
- </button>
911
- <button
912
- onClick={() =>
913
- editor.commands.openCSSClassDialog()
914
- }
915
- className={classNames(classes.button)}
916
- >
917
- <CSSIcon />
918
- </button>
919
- <button
920
- onClick={() =>
921
- editor
922
- .chain()
923
- .focus()
924
- .toggleHeading({ level: 3 })
925
- .run()
926
- }
927
- className={classNames(classes.button, { [classes.active]: editorState.isHeading3 })}
928
- >
929
- <HeadingIcon />
930
- </button>
931
- {/*<button*/}
932
- {/* onClick={() =>*/}
933
- {/* editor*/}
934
- {/* .chain()*/}
935
- {/* .focus()*/}
936
- {/* .toggleHeading({ level: 3 })*/}
937
- {/* .run()*/}
938
- {/* }*/}
939
- {/* className={classNames(classes.button, { [classes.active]: editorState.isHeading3 })}*/}
940
- {/*>*/}
941
- {/* <Image />*/}
942
- {/*</button>*/}
943
- {/*<button*/}
944
- {/* onClick={() =>*/}
945
- {/* editor*/}
946
- {/* .chain()*/}
947
- {/* .focus()*/}
948
- {/* .toggleHeading({ level: 4 })*/}
949
- {/* .run()*/}
950
- {/* }*/}
951
- {/* className={editorState.isHeading4 ? classes.isActive : ''}*/}
952
- {/*>*/}
953
- {/* H4*/}
954
- {/*</button>*/}
955
- {/*<button*/}
956
- {/* onClick={() =>*/}
957
- {/* editor*/}
958
- {/* .chain()*/}
959
- {/* .focus()*/}
960
- {/* .toggleHeading({ level: 5 })*/}
961
- {/* .run()*/}
962
- {/* }*/}
963
- {/* className={editorState.isHeading5 ? classes.isActive : ''}*/}
964
- {/*>*/}
965
- {/* H5*/}
966
- {/*</button>*/}
967
- {/*<button*/}
968
- {/* onClick={() =>*/}
969
- {/* editor*/}
970
- {/* .chain()*/}
971
- {/* .focus()*/}
972
- {/* .toggleHeading({ level: 6 })*/}
973
- {/* .run()*/}
974
- {/* }*/}
975
- {/* className={editorState.isHeading6 ? classes.isActive : ''}*/}
976
- {/*>*/}
977
- {/* H6*/}
978
- {/*</button>*/}
979
- <button
980
- onClick={() =>
981
- editor
982
- .chain()
983
- .focus()
984
- .insertMath('')
985
- .run()
986
- }
987
- className={classes.button}
988
- >
989
- <Functions />
990
- </button>
991
- <button onClick={() => setShowPicker(spanishConfig)} className={classes.button}>
992
- <CharacterIcon letter="ñ" />
993
- </button>
994
- <button onClick={() => setShowPicker(specialConfig)} className={classes.button}>
995
- <CharacterIcon letter="€" />
996
- </button>
997
- <button onClick={() => {}} className={classes.button}>
998
- <TextAlignIcon editor={editor} />
999
- </button>
1000
- <button
1001
- onClick={() =>
1002
- editor
1003
- .chain()
1004
- .focus()
1005
- .toggleBulletList()
1006
- .run()
1007
- }
1008
- className={classNames(classes.button, { [classes.active]: editorState.isBulletList })}
1009
- >
1010
- <BulletedListIcon />
1011
- </button>
1012
- <button
1013
- onClick={() =>
1014
- editor
1015
- .chain()
1016
- .focus()
1017
- .toggleOrderedList()
1018
- .run()
1019
- }
1020
- className={classNames(classes.button, { [classes.active]: editorState.isOrderedList })}
1021
- >
1022
- <NumberedListIcon />
1023
- </button>
1024
- {/*<button*/}
1025
- {/* onClick={() =>*/}
1026
- {/* editor*/}
1027
- {/* .chain()*/}
1028
- {/* .focus()*/}
1029
- {/* .toggleCodeBlock()*/}
1030
- {/* .run()*/}
1031
- {/* }*/}
1032
- {/* className={classNames(classes.button, { [classes.active]: editorState.isCodeBlock })}*/}
1033
- {/*>*/}
1034
- {/* Code block*/}
1035
- {/*</button>*/}
1036
- {/*<button*/}
1037
- {/* onClick={() =>*/}
1038
- {/* editor*/}
1039
- {/* .chain()*/}
1040
- {/* .focus()*/}
1041
- {/* .toggleBlockquote()*/}
1042
- {/* .run()*/}
1043
- {/* }*/}
1044
- {/* className={classNames(classes.button, { [classes.active]: editorState.isBlockquote })}*/}
1045
- {/*>*/}
1046
- {/* Blockquote*/}
1047
- {/*</button>*/}
1048
- {/*<button*/}
1049
- {/* onClick={() =>*/}
1050
- {/* editor*/}
1051
- {/* .chain()*/}
1052
- {/* .focus()*/}
1053
- {/* .setHorizontalRule()*/}
1054
- {/* .run()*/}
1055
- {/* }*/}
1056
- {/*>*/}
1057
- {/* Horizontal rule*/}
1058
- {/*</button>*/}
1059
- {/*<button*/}
1060
- {/* onClick={() =>*/}
1061
- {/* editor*/}
1062
- {/* .chain()*/}
1063
- {/* .focus()*/}
1064
- {/* .setHardBreak()*/}
1065
- {/* .run()*/}
1066
- {/* }*/}
1067
- {/*>*/}
1068
- {/* Hard break*/}
1069
- {/*</button>*/}
1070
- <button
1071
- onClick={() =>
1072
- editor
1073
- .chain()
1074
- .focus()
1075
- .undo()
1076
- .run()
1077
- }
1078
- disabled={!editorState.canUndo}
1079
- className={classes.button}
1080
- >
1081
- <Undo />
1082
- </button>
1083
- <button
1084
- onClick={() =>
1085
- editor
1086
- .chain()
1087
- .focus()
1088
- .redo()
1089
- .run()
1090
- }
1091
- disabled={!editorState.canRedo}
1092
- className={classes.button}
1093
- >
1094
- <Redo />
1095
- </button>
1023
+ {toolbarButtons
1024
+ .filter((btn) => !btn.hidden?.(editorState))
1025
+ .map((btn, index) => {
1026
+ const disabled = btn.isDisabled?.(editorState);
1027
+ const active = btn.isActive?.(editorState);
1028
+
1029
+ return (
1030
+ <button
1031
+ key={index}
1032
+ disabled={disabled}
1033
+ onClick={(e) => {
1034
+ e.preventDefault();
1035
+ btn.onClick(editor);
1036
+ }}
1037
+ className={classNames(classes.button, { [classes.active]: active })}
1038
+ >
1039
+ {btn.icon}
1040
+ </button>
1041
+ );
1042
+ })}
1096
1043
  </div>
1097
1044
  <button
1098
1045
  onClick={() => {
@@ -1238,6 +1185,7 @@ export const EditableHtml = (props) => {
1238
1185
  ...defaultToolbarOpts,
1239
1186
  ...toolbarOpts,
1240
1187
  };
1188
+ const activePluginsToUse = props.activePlugins || DEFAULT_PLUGINS;
1241
1189
  const extensions = [
1242
1190
  TextStyleKit,
1243
1191
  StarterKit,
@@ -1263,6 +1211,7 @@ export const EditableHtml = (props) => {
1263
1211
  toolbarOpts: toolbarOptsToUse,
1264
1212
  imageHandling: {
1265
1213
  disableImageAlignmentButtons: props.disableImageAlignmentButtons,
1214
+ onDone: () => props.onDone?.(editor.getHTML()),
1266
1215
  onDelete:
1267
1216
  props.imageSupport &&
1268
1217
  props.imageSupport.delete &&
@@ -1326,7 +1275,7 @@ export const EditableHtml = (props) => {
1326
1275
  uploadSoundSupport: props.uploadSoundSupport,
1327
1276
  }),
1328
1277
  CSSMark.configure({
1329
- extraCSSRules: props.extraCSSRules
1278
+ extraCSSRules: props.extraCSSRules,
1330
1279
  }),
1331
1280
  ];
1332
1281
  const editor = useEditor({
@@ -1433,7 +1382,7 @@ export const EditableHtml = (props) => {
1433
1382
  }, [props]);
1434
1383
 
1435
1384
  return (
1436
- <EditorContainer {...{ ...props, toolbarOpts: toolbarOptsToUse }} editorState={editorState} editor={editor}>
1385
+ <EditorContainer {...{ ...props, activePlugins: activePluginsToUse, toolbarOpts: toolbarOptsToUse }} editorState={editorState} editor={editor}>
1437
1386
  {editor && (
1438
1387
  <EditorContent
1439
1388
  style={{