@cgi-learning-hub/ui 1.15.0-dev.1788516152 → 1.15.0-dev.1788530642

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.
@@ -609,7 +609,7 @@ var CODE_BLOCK_SHORTCUT_KEY = "mod+alt+c";
609
609
  /**
610
610
  * Checks if code block can be toggled in the current editor state
611
611
  */
612
- function canToggle$1(editor, turnInto = true) {
612
+ function canToggle$2(editor, turnInto = true) {
613
613
  if (!editor || !editor.isEditable) return false;
614
614
  if (!isNodeInSchema("codeBlock", editor) || isNodeTypeSelected(editor, ["image"])) return false;
615
615
  if (!turnInto) return editor.can().toggleNode("codeBlock", "paragraph");
@@ -629,7 +629,7 @@ function canToggle$1(editor, turnInto = true) {
629
629
  */
630
630
  function toggleCodeBlock(editor) {
631
631
  if (!editor || !editor.isEditable) return false;
632
- if (!canToggle$1(editor)) return false;
632
+ if (!canToggle$2(editor)) return false;
633
633
  try {
634
634
  const view = editor.view;
635
635
  let state = view.state;
@@ -681,7 +681,7 @@ function shouldShowButton$4(props) {
681
681
  if (!hideWhenUnavailable) return true;
682
682
  if (!editor.isEditable) return false;
683
683
  if (!isNodeInSchema("codeBlock", editor)) return false;
684
- if (!editor.isActive("code")) return canToggle$1(editor);
684
+ if (!editor.isActive("code")) return canToggle$2(editor);
685
685
  return true;
686
686
  }
687
687
  /**
@@ -731,7 +731,7 @@ function useCodeBlock(config) {
731
731
  const { editor: providedEditor, hideWhenUnavailable = false, onToggled } = config || {};
732
732
  const { editor } = useTiptapEditor(providedEditor);
733
733
  const [isVisible, setIsVisible] = (0, react.useState)(true);
734
- const canToggleState = canToggle$1(editor);
734
+ const canToggleState = canToggle$2(editor);
735
735
  const isActive = editor?.isActive("codeBlock") || false;
736
736
  (0, react.useEffect)(() => {
737
737
  if (!editor) return;
@@ -897,7 +897,7 @@ var HEADING_SHORTCUT_KEYS = {
897
897
  /**
898
898
  * Checks if heading can be toggled in the current editor state
899
899
  */
900
- function canToggle(editor, level, turnInto = true) {
900
+ function canToggle$1(editor, level, turnInto = true) {
901
901
  if (!editor || !editor.isEditable) return false;
902
902
  if (!isNodeInSchema("heading", editor) || isNodeTypeSelected(editor, ["image"])) return false;
903
903
  if (!turnInto) return level ? editor.can().setNode("heading", { level }) : editor.can().setNode("heading");
@@ -926,7 +926,7 @@ function isHeadingActive(editor, level) {
926
926
  function toggleHeading(editor, level) {
927
927
  if (!editor || !editor.isEditable) return false;
928
928
  const levels = Array.isArray(level) ? level : [level];
929
- const toggleLevel = levels.find((l) => canToggle(editor, l));
929
+ const toggleLevel = levels.find((l) => canToggle$1(editor, l));
930
930
  if (!toggleLevel) return false;
931
931
  try {
932
932
  const view = editor.view;
@@ -973,15 +973,15 @@ function toggleHeading(editor, level) {
973
973
  /**
974
974
  * Determines if the heading menu item should be shown
975
975
  */
976
- function shouldShowItem(props) {
976
+ function shouldShowItem$1(props) {
977
977
  const { editor, level, hideWhenUnavailable } = props;
978
978
  if (!editor) return false;
979
979
  if (!hideWhenUnavailable) return true;
980
980
  if (!editor.isEditable) return false;
981
981
  if (!isNodeInSchema("heading", editor)) return false;
982
982
  if (!editor.isActive("code")) {
983
- if (Array.isArray(level)) return level.some((l) => canToggle(editor, l));
984
- return canToggle(editor, level);
983
+ if (Array.isArray(level)) return level.some((l) => canToggle$1(editor, l));
984
+ return canToggle$1(editor, level);
985
985
  }
986
986
  return true;
987
987
  }
@@ -1035,12 +1035,12 @@ function useHeading(config) {
1035
1035
  const { editor: providedEditor, level, hideWhenUnavailable = false, onToggled } = config;
1036
1036
  const { editor } = useTiptapEditor(providedEditor);
1037
1037
  const [isVisible, setIsVisible] = (0, react.useState)(true);
1038
- const canToggleState = canToggle(editor, level);
1038
+ const canToggleState = canToggle$1(editor, level);
1039
1039
  const isActive = isHeadingActive(editor, level);
1040
1040
  (0, react.useEffect)(() => {
1041
1041
  if (!editor) return;
1042
1042
  const handleSelectionUpdate = () => {
1043
- setIsVisible(shouldShowItem({
1043
+ setIsVisible(shouldShowItem$1({
1044
1044
  editor,
1045
1045
  level,
1046
1046
  hideWhenUnavailable
@@ -1129,6 +1129,169 @@ var HeadingMenuItem = (0, react.forwardRef)(({ editor: providedEditor, level, te
1129
1129
  });
1130
1130
  HeadingMenuItem.displayName = "HeadingMenuItem";
1131
1131
  //#endregion
1132
+ //#region src/tiptap/components/ui/paragraph-menu-item/use-paragraph.ts
1133
+ /**
1134
+ * Checks if paragraph can be toggled in the current editor state
1135
+ */
1136
+ function canToggle(editor, turnInto = true) {
1137
+ if (!editor || !editor.isEditable) return false;
1138
+ if (!isNodeInSchema("paragraph", editor) || isNodeTypeSelected(editor, ["image"])) return false;
1139
+ if (!turnInto) return editor.can().setNode("paragraph");
1140
+ if (!selectionWithinConvertibleTypes(editor, [
1141
+ "paragraph",
1142
+ "heading",
1143
+ "bulletList",
1144
+ "orderedList",
1145
+ "taskList",
1146
+ "blockquote",
1147
+ "codeBlock"
1148
+ ])) return false;
1149
+ return editor.can().setNode("paragraph") || editor.can().clearNodes();
1150
+ }
1151
+ /**
1152
+ * Checks if paragraph is currently active
1153
+ */
1154
+ function isParagraphActive(editor) {
1155
+ if (!editor || !editor.isEditable) return false;
1156
+ return editor.isActive("paragraph");
1157
+ }
1158
+ /**
1159
+ * Toggles paragraph in the editor
1160
+ */
1161
+ function toggleParagraph(editor) {
1162
+ if (!editor || !editor.isEditable || !canToggle(editor)) return false;
1163
+ try {
1164
+ const view = editor.view;
1165
+ let state = view.state;
1166
+ let tr = state.tr;
1167
+ const blocks = getSelectedBlockNodes(editor);
1168
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
1169
+ "paragraph",
1170
+ "heading",
1171
+ "bulletList",
1172
+ "orderedList",
1173
+ "taskList",
1174
+ "blockquote",
1175
+ "codeBlock"
1176
+ ]) && blocks.length === 1;
1177
+ if ((state.selection.empty || state.selection instanceof _tiptap_pm_state.TextSelection) && isPossibleToTurnInto) {
1178
+ const pos = findNodePosition({
1179
+ editor,
1180
+ node: state.selection.$anchor.node(1)
1181
+ })?.pos;
1182
+ if (!isValidPosition(pos)) return false;
1183
+ tr = tr.setSelection(_tiptap_pm_state.NodeSelection.create(state.doc, pos));
1184
+ view.dispatch(tr);
1185
+ state = view.state;
1186
+ }
1187
+ const selection = state.selection;
1188
+ let chain = editor.chain().focus();
1189
+ if (selection instanceof _tiptap_pm_state.NodeSelection) {
1190
+ const firstChild = selection.node.firstChild?.firstChild;
1191
+ const lastChild = selection.node.lastChild?.lastChild;
1192
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
1193
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
1194
+ const resolvedFrom = state.doc.resolve(from);
1195
+ const resolvedTo = state.doc.resolve(to);
1196
+ chain = chain.setTextSelection(_tiptap_pm_state.TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
1197
+ }
1198
+ chain.setNode("paragraph").run();
1199
+ editor.chain().focus().selectTextblockEnd().run();
1200
+ return true;
1201
+ } catch {
1202
+ return false;
1203
+ }
1204
+ }
1205
+ /**
1206
+ * Determines if the paragraph menu item should be shown
1207
+ */
1208
+ function shouldShowItem(props) {
1209
+ const { editor, hideWhenUnavailable } = props;
1210
+ if (!editor) return false;
1211
+ if (!hideWhenUnavailable) return true;
1212
+ if (!editor.isEditable) return false;
1213
+ if (!isNodeInSchema("paragraph", editor)) return false;
1214
+ if (!editor.isActive("code")) return canToggle(editor);
1215
+ return true;
1216
+ }
1217
+ /**
1218
+ * Custom hook that provides paragraph functionality for Tiptap editor
1219
+ */
1220
+ function useParagraph(config) {
1221
+ const { editor: providedEditor, hideWhenUnavailable = false, onToggled } = config;
1222
+ const { editor } = useTiptapEditor(providedEditor);
1223
+ const [isVisible, setIsVisible] = (0, react.useState)(true);
1224
+ const canToggleState = canToggle(editor);
1225
+ const isActive = isParagraphActive(editor);
1226
+ (0, react.useEffect)(() => {
1227
+ if (!editor) return;
1228
+ const handleSelectionUpdate = () => {
1229
+ setIsVisible(shouldShowItem({
1230
+ editor,
1231
+ hideWhenUnavailable
1232
+ }));
1233
+ };
1234
+ handleSelectionUpdate();
1235
+ editor.on("selectionUpdate", handleSelectionUpdate);
1236
+ return () => {
1237
+ editor.off("selectionUpdate", handleSelectionUpdate);
1238
+ };
1239
+ }, [editor, hideWhenUnavailable]);
1240
+ return {
1241
+ isVisible,
1242
+ isActive,
1243
+ handleToggle: (0, react.useCallback)(() => {
1244
+ if (!editor) return false;
1245
+ const success = toggleParagraph(editor);
1246
+ if (success) onToggled?.();
1247
+ return success;
1248
+ }, [editor, onToggled]),
1249
+ canToggle: canToggleState,
1250
+ label: "Paragraphe"
1251
+ };
1252
+ }
1253
+ //#endregion
1254
+ //#region src/tiptap/components/ui/paragraph-menu-item/paragraph-menu-item.tsx
1255
+ /**
1256
+ * Menu item component for toggling paragraph in a Tiptap editor.
1257
+ *
1258
+ * For custom menu item implementations, use the `useParagraph` hook instead.
1259
+ */
1260
+ var ParagraphMenuItem = (0, react.forwardRef)(({ editor: providedEditor, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...menuItemProps }, ref) => {
1261
+ const { editor } = useTiptapEditor(providedEditor);
1262
+ const { isVisible, canToggle, isActive, handleToggle, label } = useParagraph({
1263
+ editor,
1264
+ hideWhenUnavailable,
1265
+ onToggled
1266
+ });
1267
+ const handleClick = (0, react.useCallback)((event) => {
1268
+ onClick?.(event);
1269
+ if (event.defaultPrevented) return;
1270
+ handleToggle();
1271
+ }, [handleToggle, onClick]);
1272
+ if (!isVisible) return null;
1273
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_MenuItem.default, {
1274
+ component: "li",
1275
+ role: "button",
1276
+ tabIndex: -1,
1277
+ disabled: !canToggle,
1278
+ "data-disabled": !canToggle,
1279
+ "aria-label": label,
1280
+ "aria-pressed": isActive,
1281
+ tooltip: label,
1282
+ selected: isActive,
1283
+ onClick: handleClick,
1284
+ ...menuItemProps,
1285
+ ref,
1286
+ children: children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Typography.default, {
1287
+ component: "span",
1288
+ variant: "body2",
1289
+ children: label
1290
+ }), showShortcut && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Badge.default, { children: parseShortcutKeys({ shortcutKeys: "ctrl+alt+p" }) })] })
1291
+ });
1292
+ });
1293
+ ParagraphMenuItem.displayName = "ParagraphMenuItem";
1294
+ //#endregion
1132
1295
  //#region src/tiptap/components/icons/heading-icon.tsx
1133
1296
  var HeadingIcon = (0, _mui_material_utils.createSvgIcon)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1134
1297
  d: "M6 3C6.55228 3 7 3.44772 7 4V11H17V4C17 3.44772 17.4477 3 18 3C18.5523 3 19 3.44772 19 4V20C19 20.5523 18.5523 21 18 21C17.4477 21 17 20.5523 17 20V13H7V20C7 20.5523 6.55228 21 6 21C5.44772 21 5 20.5523 5 20V4C5 3.44772 5.44772 3 6 3Z",
@@ -1202,11 +1365,11 @@ function useHeadingMenu(config) {
1202
1365
  const [isVisible, setIsVisible] = (0, react.useState)(true);
1203
1366
  const activeLevel = getActiveHeadingLevel(editor, levels);
1204
1367
  const isActive = isHeadingActive(editor);
1205
- const canToggleState = canToggle(editor);
1368
+ const canToggleState = canToggle$1(editor);
1206
1369
  (0, react.useEffect)(() => {
1207
1370
  if (!editor) return;
1208
1371
  const handleSelectionUpdate = () => {
1209
- setIsVisible(shouldShowItem({
1372
+ setIsVisible(shouldShowItem$1({
1210
1373
  editor,
1211
1374
  hideWhenUnavailable,
1212
1375
  level: levels
@@ -1286,7 +1449,7 @@ var HeadingMenu = (0, react.forwardRef)(({ editor: providedEditor, levels = [
1286
1449
  ...buttonProps,
1287
1450
  ref,
1288
1451
  children: children ? children : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { fontSize: "small" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExpandMoreRounded_default, { sx: { fontSize: "0.75rem" } })] })
1289
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mui_material_Menu.default, {
1452
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mui_material_Menu.default, {
1290
1453
  id: "heading-menu",
1291
1454
  anchorEl,
1292
1455
  open,
@@ -1295,12 +1458,15 @@ var HeadingMenu = (0, react.forwardRef)(({ editor: providedEditor, levels = [
1295
1458
  "aria-labelledby": "heading-button",
1296
1459
  role: "listbox"
1297
1460
  } },
1298
- children: levels.map((level) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HeadingMenuItem, {
1461
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ParagraphMenuItem, {
1462
+ editor,
1463
+ onClick: handleClose
1464
+ }), levels.map((level) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HeadingMenuItem, {
1299
1465
  editor,
1300
1466
  level,
1301
1467
  text: `Heading ${level}`,
1302
1468
  onClick: handleClose
1303
- }, `heading-${level}`))
1469
+ }, `heading-${level}`))]
1304
1470
  })] });
1305
1471
  });
1306
1472
  HeadingMenu.displayName = "HeadingMenu";
@@ -585,7 +585,7 @@ var CODE_BLOCK_SHORTCUT_KEY = "mod+alt+c";
585
585
  /**
586
586
  * Checks if code block can be toggled in the current editor state
587
587
  */
588
- function canToggle$1(editor, turnInto = true) {
588
+ function canToggle$2(editor, turnInto = true) {
589
589
  if (!editor || !editor.isEditable) return false;
590
590
  if (!isNodeInSchema("codeBlock", editor) || isNodeTypeSelected(editor, ["image"])) return false;
591
591
  if (!turnInto) return editor.can().toggleNode("codeBlock", "paragraph");
@@ -605,7 +605,7 @@ function canToggle$1(editor, turnInto = true) {
605
605
  */
606
606
  function toggleCodeBlock(editor) {
607
607
  if (!editor || !editor.isEditable) return false;
608
- if (!canToggle$1(editor)) return false;
608
+ if (!canToggle$2(editor)) return false;
609
609
  try {
610
610
  const view = editor.view;
611
611
  let state = view.state;
@@ -657,7 +657,7 @@ function shouldShowButton$4(props) {
657
657
  if (!hideWhenUnavailable) return true;
658
658
  if (!editor.isEditable) return false;
659
659
  if (!isNodeInSchema("codeBlock", editor)) return false;
660
- if (!editor.isActive("code")) return canToggle$1(editor);
660
+ if (!editor.isActive("code")) return canToggle$2(editor);
661
661
  return true;
662
662
  }
663
663
  /**
@@ -707,7 +707,7 @@ function useCodeBlock(config) {
707
707
  const { editor: providedEditor, hideWhenUnavailable = false, onToggled } = config || {};
708
708
  const { editor } = useTiptapEditor(providedEditor);
709
709
  const [isVisible, setIsVisible] = useState(true);
710
- const canToggleState = canToggle$1(editor);
710
+ const canToggleState = canToggle$2(editor);
711
711
  const isActive = editor?.isActive("codeBlock") || false;
712
712
  useEffect(() => {
713
713
  if (!editor) return;
@@ -873,7 +873,7 @@ var HEADING_SHORTCUT_KEYS = {
873
873
  /**
874
874
  * Checks if heading can be toggled in the current editor state
875
875
  */
876
- function canToggle(editor, level, turnInto = true) {
876
+ function canToggle$1(editor, level, turnInto = true) {
877
877
  if (!editor || !editor.isEditable) return false;
878
878
  if (!isNodeInSchema("heading", editor) || isNodeTypeSelected(editor, ["image"])) return false;
879
879
  if (!turnInto) return level ? editor.can().setNode("heading", { level }) : editor.can().setNode("heading");
@@ -902,7 +902,7 @@ function isHeadingActive(editor, level) {
902
902
  function toggleHeading(editor, level) {
903
903
  if (!editor || !editor.isEditable) return false;
904
904
  const levels = Array.isArray(level) ? level : [level];
905
- const toggleLevel = levels.find((l) => canToggle(editor, l));
905
+ const toggleLevel = levels.find((l) => canToggle$1(editor, l));
906
906
  if (!toggleLevel) return false;
907
907
  try {
908
908
  const view = editor.view;
@@ -949,15 +949,15 @@ function toggleHeading(editor, level) {
949
949
  /**
950
950
  * Determines if the heading menu item should be shown
951
951
  */
952
- function shouldShowItem(props) {
952
+ function shouldShowItem$1(props) {
953
953
  const { editor, level, hideWhenUnavailable } = props;
954
954
  if (!editor) return false;
955
955
  if (!hideWhenUnavailable) return true;
956
956
  if (!editor.isEditable) return false;
957
957
  if (!isNodeInSchema("heading", editor)) return false;
958
958
  if (!editor.isActive("code")) {
959
- if (Array.isArray(level)) return level.some((l) => canToggle(editor, l));
960
- return canToggle(editor, level);
959
+ if (Array.isArray(level)) return level.some((l) => canToggle$1(editor, l));
960
+ return canToggle$1(editor, level);
961
961
  }
962
962
  return true;
963
963
  }
@@ -1011,12 +1011,12 @@ function useHeading(config) {
1011
1011
  const { editor: providedEditor, level, hideWhenUnavailable = false, onToggled } = config;
1012
1012
  const { editor } = useTiptapEditor(providedEditor);
1013
1013
  const [isVisible, setIsVisible] = useState(true);
1014
- const canToggleState = canToggle(editor, level);
1014
+ const canToggleState = canToggle$1(editor, level);
1015
1015
  const isActive = isHeadingActive(editor, level);
1016
1016
  useEffect(() => {
1017
1017
  if (!editor) return;
1018
1018
  const handleSelectionUpdate = () => {
1019
- setIsVisible(shouldShowItem({
1019
+ setIsVisible(shouldShowItem$1({
1020
1020
  editor,
1021
1021
  level,
1022
1022
  hideWhenUnavailable
@@ -1105,6 +1105,169 @@ var HeadingMenuItem = forwardRef(({ editor: providedEditor, level, text, hideWhe
1105
1105
  });
1106
1106
  HeadingMenuItem.displayName = "HeadingMenuItem";
1107
1107
  //#endregion
1108
+ //#region src/tiptap/components/ui/paragraph-menu-item/use-paragraph.ts
1109
+ /**
1110
+ * Checks if paragraph can be toggled in the current editor state
1111
+ */
1112
+ function canToggle(editor, turnInto = true) {
1113
+ if (!editor || !editor.isEditable) return false;
1114
+ if (!isNodeInSchema("paragraph", editor) || isNodeTypeSelected(editor, ["image"])) return false;
1115
+ if (!turnInto) return editor.can().setNode("paragraph");
1116
+ if (!selectionWithinConvertibleTypes(editor, [
1117
+ "paragraph",
1118
+ "heading",
1119
+ "bulletList",
1120
+ "orderedList",
1121
+ "taskList",
1122
+ "blockquote",
1123
+ "codeBlock"
1124
+ ])) return false;
1125
+ return editor.can().setNode("paragraph") || editor.can().clearNodes();
1126
+ }
1127
+ /**
1128
+ * Checks if paragraph is currently active
1129
+ */
1130
+ function isParagraphActive(editor) {
1131
+ if (!editor || !editor.isEditable) return false;
1132
+ return editor.isActive("paragraph");
1133
+ }
1134
+ /**
1135
+ * Toggles paragraph in the editor
1136
+ */
1137
+ function toggleParagraph(editor) {
1138
+ if (!editor || !editor.isEditable || !canToggle(editor)) return false;
1139
+ try {
1140
+ const view = editor.view;
1141
+ let state = view.state;
1142
+ let tr = state.tr;
1143
+ const blocks = getSelectedBlockNodes(editor);
1144
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
1145
+ "paragraph",
1146
+ "heading",
1147
+ "bulletList",
1148
+ "orderedList",
1149
+ "taskList",
1150
+ "blockquote",
1151
+ "codeBlock"
1152
+ ]) && blocks.length === 1;
1153
+ if ((state.selection.empty || state.selection instanceof TextSelection) && isPossibleToTurnInto) {
1154
+ const pos = findNodePosition({
1155
+ editor,
1156
+ node: state.selection.$anchor.node(1)
1157
+ })?.pos;
1158
+ if (!isValidPosition(pos)) return false;
1159
+ tr = tr.setSelection(NodeSelection.create(state.doc, pos));
1160
+ view.dispatch(tr);
1161
+ state = view.state;
1162
+ }
1163
+ const selection = state.selection;
1164
+ let chain = editor.chain().focus();
1165
+ if (selection instanceof NodeSelection) {
1166
+ const firstChild = selection.node.firstChild?.firstChild;
1167
+ const lastChild = selection.node.lastChild?.lastChild;
1168
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
1169
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
1170
+ const resolvedFrom = state.doc.resolve(from);
1171
+ const resolvedTo = state.doc.resolve(to);
1172
+ chain = chain.setTextSelection(TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
1173
+ }
1174
+ chain.setNode("paragraph").run();
1175
+ editor.chain().focus().selectTextblockEnd().run();
1176
+ return true;
1177
+ } catch {
1178
+ return false;
1179
+ }
1180
+ }
1181
+ /**
1182
+ * Determines if the paragraph menu item should be shown
1183
+ */
1184
+ function shouldShowItem(props) {
1185
+ const { editor, hideWhenUnavailable } = props;
1186
+ if (!editor) return false;
1187
+ if (!hideWhenUnavailable) return true;
1188
+ if (!editor.isEditable) return false;
1189
+ if (!isNodeInSchema("paragraph", editor)) return false;
1190
+ if (!editor.isActive("code")) return canToggle(editor);
1191
+ return true;
1192
+ }
1193
+ /**
1194
+ * Custom hook that provides paragraph functionality for Tiptap editor
1195
+ */
1196
+ function useParagraph(config) {
1197
+ const { editor: providedEditor, hideWhenUnavailable = false, onToggled } = config;
1198
+ const { editor } = useTiptapEditor(providedEditor);
1199
+ const [isVisible, setIsVisible] = useState(true);
1200
+ const canToggleState = canToggle(editor);
1201
+ const isActive = isParagraphActive(editor);
1202
+ useEffect(() => {
1203
+ if (!editor) return;
1204
+ const handleSelectionUpdate = () => {
1205
+ setIsVisible(shouldShowItem({
1206
+ editor,
1207
+ hideWhenUnavailable
1208
+ }));
1209
+ };
1210
+ handleSelectionUpdate();
1211
+ editor.on("selectionUpdate", handleSelectionUpdate);
1212
+ return () => {
1213
+ editor.off("selectionUpdate", handleSelectionUpdate);
1214
+ };
1215
+ }, [editor, hideWhenUnavailable]);
1216
+ return {
1217
+ isVisible,
1218
+ isActive,
1219
+ handleToggle: useCallback(() => {
1220
+ if (!editor) return false;
1221
+ const success = toggleParagraph(editor);
1222
+ if (success) onToggled?.();
1223
+ return success;
1224
+ }, [editor, onToggled]),
1225
+ canToggle: canToggleState,
1226
+ label: "Paragraphe"
1227
+ };
1228
+ }
1229
+ //#endregion
1230
+ //#region src/tiptap/components/ui/paragraph-menu-item/paragraph-menu-item.tsx
1231
+ /**
1232
+ * Menu item component for toggling paragraph in a Tiptap editor.
1233
+ *
1234
+ * For custom menu item implementations, use the `useParagraph` hook instead.
1235
+ */
1236
+ var ParagraphMenuItem = forwardRef(({ editor: providedEditor, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...menuItemProps }, ref) => {
1237
+ const { editor } = useTiptapEditor(providedEditor);
1238
+ const { isVisible, canToggle, isActive, handleToggle, label } = useParagraph({
1239
+ editor,
1240
+ hideWhenUnavailable,
1241
+ onToggled
1242
+ });
1243
+ const handleClick = useCallback((event) => {
1244
+ onClick?.(event);
1245
+ if (event.defaultPrevented) return;
1246
+ handleToggle();
1247
+ }, [handleToggle, onClick]);
1248
+ if (!isVisible) return null;
1249
+ return /* @__PURE__ */ jsx(MenuItem, {
1250
+ component: "li",
1251
+ role: "button",
1252
+ tabIndex: -1,
1253
+ disabled: !canToggle,
1254
+ "data-disabled": !canToggle,
1255
+ "aria-label": label,
1256
+ "aria-pressed": isActive,
1257
+ tooltip: label,
1258
+ selected: isActive,
1259
+ onClick: handleClick,
1260
+ ...menuItemProps,
1261
+ ref,
1262
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [label && /* @__PURE__ */ jsx(Typography, {
1263
+ component: "span",
1264
+ variant: "body2",
1265
+ children: label
1266
+ }), showShortcut && /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys: "ctrl+alt+p" }) })] })
1267
+ });
1268
+ });
1269
+ ParagraphMenuItem.displayName = "ParagraphMenuItem";
1270
+ //#endregion
1108
1271
  //#region src/tiptap/components/icons/heading-icon.tsx
1109
1272
  var HeadingIcon = createSvgIcon(/* @__PURE__ */ jsx("path", {
1110
1273
  d: "M6 3C6.55228 3 7 3.44772 7 4V11H17V4C17 3.44772 17.4477 3 18 3C18.5523 3 19 3.44772 19 4V20C19 20.5523 18.5523 21 18 21C17.4477 21 17 20.5523 17 20V13H7V20C7 20.5523 6.55228 21 6 21C5.44772 21 5 20.5523 5 20V4C5 3.44772 5.44772 3 6 3Z",
@@ -1178,11 +1341,11 @@ function useHeadingMenu(config) {
1178
1341
  const [isVisible, setIsVisible] = useState(true);
1179
1342
  const activeLevel = getActiveHeadingLevel(editor, levels);
1180
1343
  const isActive = isHeadingActive(editor);
1181
- const canToggleState = canToggle(editor);
1344
+ const canToggleState = canToggle$1(editor);
1182
1345
  useEffect(() => {
1183
1346
  if (!editor) return;
1184
1347
  const handleSelectionUpdate = () => {
1185
- setIsVisible(shouldShowItem({
1348
+ setIsVisible(shouldShowItem$1({
1186
1349
  editor,
1187
1350
  hideWhenUnavailable,
1188
1351
  level: levels
@@ -1262,7 +1425,7 @@ var HeadingMenu = forwardRef(({ editor: providedEditor, levels = [
1262
1425
  ...buttonProps,
1263
1426
  ref,
1264
1427
  children: children ? children : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, { fontSize: "small" }), /* @__PURE__ */ jsx(ExpandMoreRounded_default, { sx: { fontSize: "0.75rem" } })] })
1265
- }), /* @__PURE__ */ jsx(Menu, {
1428
+ }), /* @__PURE__ */ jsxs(Menu, {
1266
1429
  id: "heading-menu",
1267
1430
  anchorEl,
1268
1431
  open,
@@ -1271,12 +1434,15 @@ var HeadingMenu = forwardRef(({ editor: providedEditor, levels = [
1271
1434
  "aria-labelledby": "heading-button",
1272
1435
  role: "listbox"
1273
1436
  } },
1274
- children: levels.map((level) => /* @__PURE__ */ jsx(HeadingMenuItem, {
1437
+ children: [/* @__PURE__ */ jsx(ParagraphMenuItem, {
1438
+ editor,
1439
+ onClick: handleClose
1440
+ }), levels.map((level) => /* @__PURE__ */ jsx(HeadingMenuItem, {
1275
1441
  editor,
1276
1442
  level,
1277
1443
  text: `Heading ${level}`,
1278
1444
  onClick: handleClose
1279
- }, `heading-${level}`))
1445
+ }, `heading-${level}`))]
1280
1446
  })] });
1281
1447
  });
1282
1448
  HeadingMenu.displayName = "HeadingMenu";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cgi-learning-hub/ui",
3
- "version": "1.15.0-dev.1788516152",
3
+ "version": "1.15.0-dev.1788530642",
4
4
  "description": "React component library for Hub's design system, built on Material UI with custom and extended components.",
5
5
  "keywords": [
6
6
  "cgi-learning-hub",