@notum-cz/strapi-plugin-tiptap-editor 1.0.1 → 1.0.2

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 (80) hide show
  1. package/README.md +85 -55
  2. package/dist/_chunks/{RichTextInput-BZQ2iVqa.mjs → RichTextInput-COGVRWOW.mjs} +786 -596
  3. package/dist/_chunks/RichTextInput-COGVRWOW.mjs.map +1 -0
  4. package/dist/_chunks/{RichTextInput-BlxoJMa2.js → RichTextInput-Wc2q__HY.js} +785 -595
  5. package/dist/_chunks/RichTextInput-Wc2q__HY.js.map +1 -0
  6. package/dist/admin/index.js +23 -1
  7. package/dist/admin/index.js.map +1 -1
  8. package/dist/admin/index.mjs +23 -1
  9. package/dist/admin/index.mjs.map +1 -1
  10. package/dist/admin/src/components/BaseTiptapInput.d.ts +1 -0
  11. package/dist/admin/src/components/EditorErrorBoundary.d.ts +23 -0
  12. package/dist/admin/src/components/FeatureGuard.d.ts +15 -0
  13. package/dist/admin/src/components/PresetSelect.d.ts +7 -0
  14. package/dist/admin/src/extensions/Heading.d.ts +1 -0
  15. package/dist/admin/src/fields/richTextField.d.ts +18 -0
  16. package/dist/admin/src/hooks/usePresetConfig.d.ts +6 -0
  17. package/dist/admin/src/utils/buildExtensions.d.ts +3 -0
  18. package/dist/server/index.js +154 -6
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server/index.mjs +153 -6
  21. package/dist/server/index.mjs.map +1 -1
  22. package/dist/server/src/config/index.d.ts +7 -4
  23. package/dist/server/src/controllers/index.d.ts +8 -1
  24. package/dist/server/src/controllers/preset.d.ts +8 -0
  25. package/dist/server/src/index.d.ts +43 -5
  26. package/dist/server/src/routes/index.d.ts +15 -1
  27. package/dist/server/src/services/index.d.ts +9 -1
  28. package/dist/server/src/services/preset.d.ts +10 -0
  29. package/dist/shared/types.d.ts +54 -0
  30. package/package.json +11 -3
  31. package/dist/_chunks/AccentCursive-CpAPpH9C.mjs +0 -3383
  32. package/dist/_chunks/AccentCursive-CpAPpH9C.mjs.map +0 -1
  33. package/dist/_chunks/AccentCursive-D6sTlhub.js +0 -3384
  34. package/dist/_chunks/AccentCursive-D6sTlhub.js.map +0 -1
  35. package/dist/_chunks/FormattedHeadingInput-DycgfIze.mjs +0 -101
  36. package/dist/_chunks/FormattedHeadingInput-DycgfIze.mjs.map +0 -1
  37. package/dist/_chunks/FormattedHeadingInput-FFjiRSEJ.js +0 -101
  38. package/dist/_chunks/FormattedHeadingInput-FFjiRSEJ.js.map +0 -1
  39. package/dist/_chunks/RichTextInput-BZQ2iVqa.mjs.map +0 -1
  40. package/dist/_chunks/RichTextInput-BbbQxPc-.js +0 -4414
  41. package/dist/_chunks/RichTextInput-BbbQxPc-.js.map +0 -1
  42. package/dist/_chunks/RichTextInput-BjLR2pi0.js +0 -4416
  43. package/dist/_chunks/RichTextInput-BjLR2pi0.js.map +0 -1
  44. package/dist/_chunks/RichTextInput-BlxoJMa2.js.map +0 -1
  45. package/dist/_chunks/RichTextInput-Bm3X8fR2.mjs +0 -4400
  46. package/dist/_chunks/RichTextInput-Bm3X8fR2.mjs.map +0 -1
  47. package/dist/_chunks/RichTextInput-Bms-gSvK.js +0 -4407
  48. package/dist/_chunks/RichTextInput-Bms-gSvK.js.map +0 -1
  49. package/dist/_chunks/RichTextInput-BtNjPJRN.mjs +0 -4400
  50. package/dist/_chunks/RichTextInput-BtNjPJRN.mjs.map +0 -1
  51. package/dist/_chunks/RichTextInput-Bw3tcXfp.js +0 -4407
  52. package/dist/_chunks/RichTextInput-Bw3tcXfp.js.map +0 -1
  53. package/dist/_chunks/RichTextInput-CsgNpoxq.mjs +0 -4409
  54. package/dist/_chunks/RichTextInput-CsgNpoxq.mjs.map +0 -1
  55. package/dist/_chunks/RichTextInput-CwTvEMda.js +0 -4407
  56. package/dist/_chunks/RichTextInput-CwTvEMda.js.map +0 -1
  57. package/dist/_chunks/RichTextInput-DG-36krM.js +0 -1181
  58. package/dist/_chunks/RichTextInput-DG-36krM.js.map +0 -1
  59. package/dist/_chunks/RichTextInput-DLac-zNQ.mjs +0 -4400
  60. package/dist/_chunks/RichTextInput-DLac-zNQ.mjs.map +0 -1
  61. package/dist/_chunks/RichTextInput-DSXttrvi.js +0 -4407
  62. package/dist/_chunks/RichTextInput-DSXttrvi.js.map +0 -1
  63. package/dist/_chunks/RichTextInput-DeJ6Exto.mjs +0 -4400
  64. package/dist/_chunks/RichTextInput-DeJ6Exto.mjs.map +0 -1
  65. package/dist/_chunks/RichTextInput-DgT88AkO.mjs +0 -1175
  66. package/dist/_chunks/RichTextInput-DgT88AkO.mjs.map +0 -1
  67. package/dist/_chunks/RichTextInput-DlMaDJQF.mjs +0 -4400
  68. package/dist/_chunks/RichTextInput-DlMaDJQF.mjs.map +0 -1
  69. package/dist/_chunks/RichTextInput-DtaYdjCs.mjs +0 -4400
  70. package/dist/_chunks/RichTextInput-DtaYdjCs.mjs.map +0 -1
  71. package/dist/_chunks/RichTextInput-YTKXo5oq.js +0 -4407
  72. package/dist/_chunks/RichTextInput-YTKXo5oq.js.map +0 -1
  73. package/dist/_chunks/RichTextInput-tmg-oMJk.mjs +0 -4407
  74. package/dist/_chunks/RichTextInput-tmg-oMJk.mjs.map +0 -1
  75. package/dist/_chunks/RichTextInput-umhMsI5o.js +0 -4407
  76. package/dist/_chunks/RichTextInput-umhMsI5o.js.map +0 -1
  77. package/dist/admin/src/components/FormattedHeadingInput.d.ts +0 -4
  78. package/dist/admin/src/extensions/AccentCursive.d.ts +0 -18
  79. package/dist/admin/src/fields/formattedHeadingField.d.ts +0 -20
  80. package/dist/admin/src/pluginId.d.ts +0 -1
@@ -41,7 +41,29 @@ const richTextField = {
41
41
  icon: icons.Paragraph,
42
42
  // cast to any to avoid some weird non-exported type issue during build
43
43
  components: {
44
- Input: async () => Promise.resolve().then(() => require("../_chunks/RichTextInput-BlxoJMa2.js")).then((m) => ({ default: m.default }))
44
+ Input: async () => Promise.resolve().then(() => require("../_chunks/RichTextInput-Wc2q__HY.js")).then((m) => ({ default: m.default }))
45
+ },
46
+ options: {
47
+ advanced: [
48
+ {
49
+ sectionTitle: null,
50
+ items: [
51
+ {
52
+ name: "options.preset",
53
+ type: "select",
54
+ intlLabel: {
55
+ id: "tiptap-editor.preset.label",
56
+ defaultMessage: "Editor Preset"
57
+ },
58
+ description: {
59
+ id: "tiptap-editor.preset.description",
60
+ defaultMessage: "Select the preset that configures available editing tools."
61
+ },
62
+ options: []
63
+ }
64
+ ]
65
+ }
66
+ ]
45
67
  }
46
68
  };
47
69
  const index = {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../shared/pluginId.ts","../../admin/src/components/Initializer.tsx","../../shared/fields.ts","../../admin/src/fields/richTextField.ts","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'tiptap-editor';\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../../../shared/pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","export const RICH_TEXT_FIELD_NAME = 'RichText';\n","import { PLUGIN_ID } from '../../../shared/pluginId';\nimport { Paragraph } from '@strapi/icons';\nimport { ComponentType } from 'react';\nimport { RICH_TEXT_FIELD_NAME } from '../../../shared/fields';\n\nexport const richTextField = {\n name: RICH_TEXT_FIELD_NAME,\n pluginId: PLUGIN_ID,\n type: 'string',\n intlLabel: {\n id: 'tiptap-editor.richText.label',\n defaultMessage: 'Rich Text (Tiptap)',\n },\n intlDescription: {\n id: 'tiptap-editor.richText.description',\n defaultMessage: 'Use this field to create formatted text via Tiptap editor.',\n },\n icon: Paragraph as ComponentType<any>, // cast to any to avoid some weird non-exported type issue during build\n components: {\n Input: async () => import('../components/RichTextInput').then((m) => ({ default: m.default })),\n },\n};\n","import { PLUGIN_ID } from '../../shared/pluginId';\nimport { Initializer } from './components/Initializer';\n\nimport { richTextField } from './fields/richTextField';\n\nexport default {\n register(app: any) {\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n\n app.customFields.register(richTextField);\n },\n\n async registerTrads({ locales }: { locales: string[] }) {\n return Promise.all(\n locales.map(async (locale) => {\n try {\n const { default: data } = await import(`./translations/${locale}.json`);\n\n return { data, locale };\n } catch {\n return { data: {}, locale };\n }\n })\n );\n },\n};\n"],"names":["useRef","useEffect","Paragraph"],"mappings":";;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACQzB,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACvD,QAAM,MAAMA,MAAAA,OAAO,SAAS;AAE5BC,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AChBO,MAAM,uBAAuB;ACK7B,MAAM,gBAAgB;AAAA,EAC3B,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,MAAMC,MAAAA;AAAAA;AAAAA,EACN,YAAY;AAAA,IACV,OAAO,YAAY,qCAAO,sCAA6B,CAAA,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU;AAAA,EAAA;AAEjG;AChBA,MAAA,QAAe;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAED,QAAI,aAAa,SAAS,aAAa;AAAA,EACzC;AAAA,EAEA,MAAM,cAAc,EAAE,WAAkC;AACtD,WAAO,QAAQ;AAAA,MACb,QAAQ,IAAI,OAAO,WAAW;AAC5B,YAAI;AACF,gBAAM,EAAE,SAAS,KAAA,IAAS,MAAM,qCAAA,uBAAA,OAAA,EAAA,0BAAA,MAAA,QAAA,QAAA,EAAA,KAAA,MAAA,QAAA,2BAAA,CAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA;AAEhC,iBAAO,EAAE,MAAM,OAAA;AAAA,QACjB,QAAQ;AACN,iBAAO,EAAE,MAAM,CAAA,GAAI,OAAA;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IAAA;AAAA,EAEL;AACF;;"}
1
+ {"version":3,"file":"index.js","sources":["../../shared/pluginId.ts","../../admin/src/components/Initializer.tsx","../../shared/fields.ts","../../admin/src/fields/richTextField.ts","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'tiptap-editor';\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../../../shared/pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","export const RICH_TEXT_FIELD_NAME = 'RichText';\n","import { PLUGIN_ID } from '../../../shared/pluginId';\nimport { Paragraph } from '@strapi/icons';\nimport { ComponentType } from 'react';\nimport { RICH_TEXT_FIELD_NAME } from '../../../shared/fields';\n\nexport const richTextField = {\n name: RICH_TEXT_FIELD_NAME,\n pluginId: PLUGIN_ID,\n type: 'string',\n intlLabel: {\n id: 'tiptap-editor.richText.label',\n defaultMessage: 'Rich Text (Tiptap)',\n },\n intlDescription: {\n id: 'tiptap-editor.richText.description',\n defaultMessage: 'Use this field to create formatted text via Tiptap editor.',\n },\n icon: Paragraph as ComponentType<any>, // cast to any to avoid some weird non-exported type issue during build\n components: {\n Input: async () => import('../components/RichTextInput').then((m) => ({ default: m.default })),\n },\n options: {\n advanced: [\n {\n sectionTitle: null,\n items: [\n {\n name: 'options.preset',\n type: 'select',\n intlLabel: {\n id: 'tiptap-editor.preset.label',\n defaultMessage: 'Editor Preset',\n },\n description: {\n id: 'tiptap-editor.preset.description',\n defaultMessage: 'Select the preset that configures available editing tools.',\n },\n options: [],\n },\n ],\n },\n ],\n },\n};\n","import { PLUGIN_ID } from '../../shared/pluginId';\nimport { Initializer } from './components/Initializer';\n\nimport { richTextField } from './fields/richTextField';\n\nexport default {\n register(app: any) {\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n\n app.customFields.register(richTextField);\n },\n\n async registerTrads({ locales }: { locales: string[] }) {\n return Promise.all(\n locales.map(async (locale) => {\n try {\n const { default: data } = await import(`./translations/${locale}.json`);\n\n return { data, locale };\n } catch {\n return { data: {}, locale };\n }\n })\n );\n },\n};\n"],"names":["useRef","useEffect","Paragraph"],"mappings":";;;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACQzB,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACvD,QAAM,MAAMA,MAAAA,OAAO,SAAS;AAE5BC,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AChBO,MAAM,uBAAuB;ACK7B,MAAM,gBAAgB;AAAA,EAC3B,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,MAAMC,MAAAA;AAAAA;AAAAA,EACN,YAAY;AAAA,IACV,OAAO,YAAY,qCAAO,sCAA6B,CAAA,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU;AAAA,EAAA;AAAA,EAE/F,SAAS;AAAA,IACP,UAAU;AAAA,MACR;AAAA,QACE,cAAc;AAAA,QACd,OAAO;AAAA,UACL;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,YACN,WAAW;AAAA,cACT,IAAI;AAAA,cACJ,gBAAgB;AAAA,YAAA;AAAA,YAElB,aAAa;AAAA,cACX,IAAI;AAAA,cACJ,gBAAgB;AAAA,YAAA;AAAA,YAElB,SAAS,CAAA;AAAA,UAAC;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEJ;ACtCA,MAAA,QAAe;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAED,QAAI,aAAa,SAAS,aAAa;AAAA,EACzC;AAAA,EAEA,MAAM,cAAc,EAAE,WAAkC;AACtD,WAAO,QAAQ;AAAA,MACb,QAAQ,IAAI,OAAO,WAAW;AAC5B,YAAI;AACF,gBAAM,EAAE,SAAS,KAAA,IAAS,MAAM,qCAAA,uBAAA,OAAA,EAAA,0BAAA,MAAA,QAAA,QAAA,EAAA,KAAA,MAAA,QAAA,2BAAA,CAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA;AAEhC,iBAAO,EAAE,MAAM,OAAA;AAAA,QACjB,QAAQ;AACN,iBAAO,EAAE,MAAM,CAAA,GAAI,OAAA;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IAAA;AAAA,EAEL;AACF;;"}
@@ -40,7 +40,29 @@ const richTextField = {
40
40
  icon: Paragraph,
41
41
  // cast to any to avoid some weird non-exported type issue during build
42
42
  components: {
43
- Input: async () => import("../_chunks/RichTextInput-BZQ2iVqa.mjs").then((m) => ({ default: m.default }))
43
+ Input: async () => import("../_chunks/RichTextInput-COGVRWOW.mjs").then((m) => ({ default: m.default }))
44
+ },
45
+ options: {
46
+ advanced: [
47
+ {
48
+ sectionTitle: null,
49
+ items: [
50
+ {
51
+ name: "options.preset",
52
+ type: "select",
53
+ intlLabel: {
54
+ id: "tiptap-editor.preset.label",
55
+ defaultMessage: "Editor Preset"
56
+ },
57
+ description: {
58
+ id: "tiptap-editor.preset.description",
59
+ defaultMessage: "Select the preset that configures available editing tools."
60
+ },
61
+ options: []
62
+ }
63
+ ]
64
+ }
65
+ ]
44
66
  }
45
67
  };
46
68
  const index = {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../shared/pluginId.ts","../../admin/src/components/Initializer.tsx","../../shared/fields.ts","../../admin/src/fields/richTextField.ts","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'tiptap-editor';\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../../../shared/pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","export const RICH_TEXT_FIELD_NAME = 'RichText';\n","import { PLUGIN_ID } from '../../../shared/pluginId';\nimport { Paragraph } from '@strapi/icons';\nimport { ComponentType } from 'react';\nimport { RICH_TEXT_FIELD_NAME } from '../../../shared/fields';\n\nexport const richTextField = {\n name: RICH_TEXT_FIELD_NAME,\n pluginId: PLUGIN_ID,\n type: 'string',\n intlLabel: {\n id: 'tiptap-editor.richText.label',\n defaultMessage: 'Rich Text (Tiptap)',\n },\n intlDescription: {\n id: 'tiptap-editor.richText.description',\n defaultMessage: 'Use this field to create formatted text via Tiptap editor.',\n },\n icon: Paragraph as ComponentType<any>, // cast to any to avoid some weird non-exported type issue during build\n components: {\n Input: async () => import('../components/RichTextInput').then((m) => ({ default: m.default })),\n },\n};\n","import { PLUGIN_ID } from '../../shared/pluginId';\nimport { Initializer } from './components/Initializer';\n\nimport { richTextField } from './fields/richTextField';\n\nexport default {\n register(app: any) {\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n\n app.customFields.register(richTextField);\n },\n\n async registerTrads({ locales }: { locales: string[] }) {\n return Promise.all(\n locales.map(async (locale) => {\n try {\n const { default: data } = await import(`./translations/${locale}.json`);\n\n return { data, locale };\n } catch {\n return { data: {}, locale };\n }\n })\n );\n },\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACQzB,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACvD,QAAM,MAAM,OAAO,SAAS;AAE5B,YAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AChBO,MAAM,uBAAuB;ACK7B,MAAM,gBAAgB;AAAA,EAC3B,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,MAAM;AAAA;AAAA,EACN,YAAY;AAAA,IACV,OAAO,YAAY,OAAO,uCAA6B,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU;AAAA,EAAA;AAEjG;AChBA,MAAA,QAAe;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAED,QAAI,aAAa,SAAS,aAAa;AAAA,EACzC;AAAA,EAEA,MAAM,cAAc,EAAE,WAAkC;AACtD,WAAO,QAAQ;AAAA,MACb,QAAQ,IAAI,OAAO,WAAW;AAC5B,YAAI;AACF,gBAAM,EAAE,SAAS,KAAA,IAAS,MAAM,qCAAA,uBAAA,OAAA,EAAA,0BAAA,MAAA,OAAA,4BAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA;AAEhC,iBAAO,EAAE,MAAM,OAAA;AAAA,QACjB,QAAQ;AACN,iBAAO,EAAE,MAAM,CAAA,GAAI,OAAA;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IAAA;AAAA,EAEL;AACF;"}
1
+ {"version":3,"file":"index.mjs","sources":["../../shared/pluginId.ts","../../admin/src/components/Initializer.tsx","../../shared/fields.ts","../../admin/src/fields/richTextField.ts","../../admin/src/index.ts"],"sourcesContent":["export const PLUGIN_ID = 'tiptap-editor';\n","import { useEffect, useRef } from 'react';\n\nimport { PLUGIN_ID } from '../../../shared/pluginId';\n\ntype InitializerProps = {\n setPlugin: (id: string) => void;\n};\n\nconst Initializer = ({ setPlugin }: InitializerProps) => {\n const ref = useRef(setPlugin);\n\n useEffect(() => {\n ref.current(PLUGIN_ID);\n }, []);\n\n return null;\n};\n\nexport { Initializer };\n","export const RICH_TEXT_FIELD_NAME = 'RichText';\n","import { PLUGIN_ID } from '../../../shared/pluginId';\nimport { Paragraph } from '@strapi/icons';\nimport { ComponentType } from 'react';\nimport { RICH_TEXT_FIELD_NAME } from '../../../shared/fields';\n\nexport const richTextField = {\n name: RICH_TEXT_FIELD_NAME,\n pluginId: PLUGIN_ID,\n type: 'string',\n intlLabel: {\n id: 'tiptap-editor.richText.label',\n defaultMessage: 'Rich Text (Tiptap)',\n },\n intlDescription: {\n id: 'tiptap-editor.richText.description',\n defaultMessage: 'Use this field to create formatted text via Tiptap editor.',\n },\n icon: Paragraph as ComponentType<any>, // cast to any to avoid some weird non-exported type issue during build\n components: {\n Input: async () => import('../components/RichTextInput').then((m) => ({ default: m.default })),\n },\n options: {\n advanced: [\n {\n sectionTitle: null,\n items: [\n {\n name: 'options.preset',\n type: 'select',\n intlLabel: {\n id: 'tiptap-editor.preset.label',\n defaultMessage: 'Editor Preset',\n },\n description: {\n id: 'tiptap-editor.preset.description',\n defaultMessage: 'Select the preset that configures available editing tools.',\n },\n options: [],\n },\n ],\n },\n ],\n },\n};\n","import { PLUGIN_ID } from '../../shared/pluginId';\nimport { Initializer } from './components/Initializer';\n\nimport { richTextField } from './fields/richTextField';\n\nexport default {\n register(app: any) {\n app.registerPlugin({\n id: PLUGIN_ID,\n initializer: Initializer,\n isReady: false,\n name: PLUGIN_ID,\n });\n\n app.customFields.register(richTextField);\n },\n\n async registerTrads({ locales }: { locales: string[] }) {\n return Promise.all(\n locales.map(async (locale) => {\n try {\n const { default: data } = await import(`./translations/${locale}.json`);\n\n return { data, locale };\n } catch {\n return { data: {}, locale };\n }\n })\n );\n },\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAO,MAAM,YAAY;ACQzB,MAAM,cAAc,CAAC,EAAE,gBAAkC;AACvD,QAAM,MAAM,OAAO,SAAS;AAE5B,YAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AAAA,EACvB,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;AChBO,MAAM,uBAAuB;ACK7B,MAAM,gBAAgB;AAAA,EAC3B,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,WAAW;AAAA,IACT,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,iBAAiB;AAAA,IACf,IAAI;AAAA,IACJ,gBAAgB;AAAA,EAAA;AAAA,EAElB,MAAM;AAAA;AAAA,EACN,YAAY;AAAA,IACV,OAAO,YAAY,OAAO,uCAA6B,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU;AAAA,EAAA;AAAA,EAE/F,SAAS;AAAA,IACP,UAAU;AAAA,MACR;AAAA,QACE,cAAc;AAAA,QACd,OAAO;AAAA,UACL;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,YACN,WAAW;AAAA,cACT,IAAI;AAAA,cACJ,gBAAgB;AAAA,YAAA;AAAA,YAElB,aAAa;AAAA,cACX,IAAI;AAAA,cACJ,gBAAgB;AAAA,YAAA;AAAA,YAElB,SAAS,CAAA;AAAA,UAAC;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEJ;ACtCA,MAAA,QAAe;AAAA,EACb,SAAS,KAAU;AACjB,QAAI,eAAe;AAAA,MACjB,IAAI;AAAA,MACJ,aAAa;AAAA,MACb,SAAS;AAAA,MACT,MAAM;AAAA,IAAA,CACP;AAED,QAAI,aAAa,SAAS,aAAa;AAAA,EACzC;AAAA,EAEA,MAAM,cAAc,EAAE,WAAkC;AACtD,WAAO,QAAQ;AAAA,MACb,QAAQ,IAAI,OAAO,WAAW;AAC5B,YAAI;AACF,gBAAM,EAAE,SAAS,KAAA,IAAS,MAAM,qCAAA,uBAAA,OAAA,EAAA,0BAAA,MAAA,OAAA,4BAAA,EAAA,CAAA,GAAA,kBAAA,MAAA,SAAA,CAAA;AAEhC,iBAAO,EAAE,MAAM,OAAA;AAAA,QACjB,QAAQ;AACN,iBAAO,EAAE,MAAM,CAAA,GAAI,OAAA;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IAAA;AAAA,EAEL;AACF;"}
@@ -7,6 +7,7 @@ type TiptapInputProps = InputProps & {
7
7
  editor: Editor;
8
8
  field: FieldValue;
9
9
  children?: React.ReactNode;
10
+ noPresetConfigured?: boolean;
10
11
  };
11
12
  declare const BaseTiptapInput: import("react").ForwardRefExoticComponent<TiptapInputProps & import("react").RefAttributes<HTMLDivElement>>;
12
13
  export default BaseTiptapInput;
@@ -0,0 +1,23 @@
1
+ import { Component, ErrorInfo, ReactNode } from 'react';
2
+ interface Props {
3
+ children: ReactNode;
4
+ }
5
+ interface State {
6
+ hasError: boolean;
7
+ error: Error | null;
8
+ }
9
+ /**
10
+ * Error boundary that wraps the editor content area.
11
+ * Catches render errors in children and displays a fallback UI with a retry button.
12
+ * Logs errors with [TiptapEditor] prefix for debugging.
13
+ *
14
+ * Created in Phase 2 but wired into RichTextInput in Phase 3.
15
+ */
16
+ export declare class EditorErrorBoundary extends Component<Props, State> {
17
+ state: State;
18
+ static getDerivedStateFromError(error: Error): Partial<State>;
19
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
20
+ handleRetry: () => void;
21
+ render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
22
+ }
23
+ export {};
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ import { TiptapPresetConfig } from '../../../shared/types';
3
+ interface FeatureGuardProps {
4
+ /** The feature config value from TiptapPresetConfig (e.g., config.bold, config.heading) */
5
+ featureValue: TiptapPresetConfig[keyof TiptapPresetConfig];
6
+ children: ReactNode;
7
+ }
8
+ /**
9
+ * Conditionally renders children based on whether a feature is enabled in the preset config.
10
+ * When disabled, returns null — children never mount, so any hooks inside are never called.
11
+ * This is the primary mechanism for HOOKS-01/HOOKS-02: hooks don't need internal config gating
12
+ * because FeatureGuard prevents them from being called entirely.
13
+ */
14
+ export declare function FeatureGuard({ featureValue, children }: FeatureGuardProps): ReactNode;
15
+ export {};
@@ -0,0 +1,7 @@
1
+ interface PresetSelectProps {
2
+ value?: string;
3
+ onChange: (value: string) => void;
4
+ name?: string;
5
+ }
6
+ export declare function PresetSelect({ value, onChange, name }: PresetSelectProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { Editor } from '@tiptap/core';
2
+ export declare const BaseHeadingWithSEOTag: import("@tiptap/core").Node<import("@tiptap/extension-heading").HeadingOptions, any>;
2
3
  export declare const HeadingWithSEOTag: import("@tiptap/core").Node<import("@tiptap/extension-heading").HeadingOptions, any>;
3
4
  export declare function useHeading(editor: Editor, props?: {
4
5
  disabled?: boolean;
@@ -17,4 +17,22 @@ export declare const richTextField: {
17
17
  default: import("react").ForwardRefExoticComponent<import("../utils/tiptapUtils").TiptapInputProps & import("react").RefAttributes<HTMLDivElement>>;
18
18
  }>;
19
19
  };
20
+ options: {
21
+ advanced: {
22
+ sectionTitle: null;
23
+ items: {
24
+ name: string;
25
+ type: string;
26
+ intlLabel: {
27
+ id: string;
28
+ defaultMessage: string;
29
+ };
30
+ description: {
31
+ id: string;
32
+ defaultMessage: string;
33
+ };
34
+ options: never[];
35
+ }[];
36
+ }[];
37
+ };
20
38
  };
@@ -0,0 +1,6 @@
1
+ import { TiptapPresetConfig } from '../../../shared/types';
2
+ export type PresetConfigResult = {
3
+ config: TiptapPresetConfig | null;
4
+ isLoading: boolean;
5
+ };
6
+ export declare function usePresetConfig(presetName?: string): PresetConfigResult;
@@ -0,0 +1,3 @@
1
+ import { Extensions } from '@tiptap/core';
2
+ import { TiptapPresetConfig } from '../../../shared/types';
3
+ export declare function buildExtensions(config: TiptapPresetConfig): Extensions;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
2
3
  const bootstrap = ({ strapi }) => {
3
4
  };
4
5
  const destroy = ({ strapi }) => {
@@ -17,17 +18,160 @@ const richTextField = {
17
18
  const register = ({ strapi }) => {
18
19
  strapi.customFields.register(richTextField);
19
20
  };
21
+ const PRESET_FEATURE_KEYS = [
22
+ "bold",
23
+ "italic",
24
+ "strike",
25
+ "code",
26
+ "codeBlock",
27
+ "blockquote",
28
+ "bulletList",
29
+ "orderedList",
30
+ "hardBreak",
31
+ "horizontalRule",
32
+ "history",
33
+ "heading",
34
+ "link",
35
+ "table",
36
+ "textAlign",
37
+ "superscript",
38
+ "subscript"
39
+ ];
40
+ const MINIMAL_PRESET_CONFIG = {
41
+ bold: true,
42
+ italic: true
43
+ };
44
+ const isPlainObject$1 = (value) => {
45
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
46
+ const prototype = Object.getPrototypeOf(value);
47
+ return prototype === Object.prototype || prototype === null;
48
+ };
49
+ const isFeatureEnabled = (value) => {
50
+ if (value === void 0) {
51
+ return true;
52
+ }
53
+ if (typeof value === "boolean") {
54
+ return value;
55
+ }
56
+ if (!isPlainObject$1(value)) {
57
+ return false;
58
+ }
59
+ const obj = value;
60
+ if (typeof obj.enabled === "boolean") {
61
+ return obj.enabled;
62
+ }
63
+ if (typeof obj.disabled === "boolean") {
64
+ return !obj.disabled;
65
+ }
66
+ return true;
67
+ };
68
+ const getFeatureOptions = (value, defaults) => {
69
+ if (value === false) {
70
+ return null;
71
+ }
72
+ if (!isPlainObject$1(value)) {
73
+ return defaults;
74
+ }
75
+ const { enabled: _e, disabled: _d, ...rest } = value;
76
+ return { ...defaults, ...rest };
77
+ };
78
+ const isPlainObject = (value) => {
79
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
80
+ const prototype = Object.getPrototypeOf(value);
81
+ return prototype === Object.prototype || prototype === null;
82
+ };
83
+ const FEATURE_KEYS = new Set(PRESET_FEATURE_KEYS);
84
+ const getInvalidKeys = (presetConfig) => {
85
+ if (!isPlainObject(presetConfig)) return [];
86
+ return Object.keys(presetConfig).filter(
87
+ (key) => !FEATURE_KEYS.has(key)
88
+ );
89
+ };
20
90
  const config = {
21
- default: {},
22
- validator() {
91
+ default: {
92
+ presets: {}
93
+ },
94
+ validator(pluginConfig) {
95
+ if (!isPlainObject(pluginConfig)) {
96
+ throw new Error("tiptap-editor plugin config must be a plain object");
97
+ }
98
+ const typedConfig = pluginConfig;
99
+ const { presets } = typedConfig;
100
+ if (presets === void 0) {
101
+ return;
102
+ }
103
+ if (!isPlainObject(presets)) {
104
+ throw new Error("tiptap-editor config.presets must be a plain object");
105
+ }
106
+ const allInvalidKeys = [];
107
+ for (const [presetName, presetConfig] of Object.entries(
108
+ presets
109
+ )) {
110
+ const invalidKeys = getInvalidKeys(presetConfig);
111
+ if (invalidKeys.length > 0) {
112
+ allInvalidKeys.push(...invalidKeys);
113
+ }
114
+ }
115
+ if (allInvalidKeys.length > 0) {
116
+ throw new Error(
117
+ `tiptap-editor config.presets contains invalid feature keys: ${allInvalidKeys.join(", ")}. Allowed keys: ${PRESET_FEATURE_KEYS.join(", ")}`
118
+ );
119
+ }
23
120
  }
24
121
  };
25
122
  const contentTypes = {};
26
- const controllers = {};
123
+ const createPresetController = ({ strapi }) => ({
124
+ async find(ctx) {
125
+ const presetService = strapi.plugin("tiptap-editor").service("preset");
126
+ ctx.body = { presets: presetService.listPresetNames() };
127
+ },
128
+ async findOne(ctx) {
129
+ const presetService = strapi.plugin("tiptap-editor").service("preset");
130
+ const presetName = ctx.params?.name;
131
+ const preset = presetService.getPreset(presetName);
132
+ ctx.body = preset ?? MINIMAL_PRESET_CONFIG;
133
+ }
134
+ });
135
+ const controllers = {
136
+ preset: createPresetController
137
+ };
27
138
  const middlewares = {};
28
139
  const policies = {};
29
- const routes = {};
30
- const services = {};
140
+ const routes = {
141
+ "preset-routes": {
142
+ type: "admin",
143
+ routes: [
144
+ {
145
+ method: "GET",
146
+ path: "/presets",
147
+ handler: "preset.find",
148
+ config: { auth: false, policies: [], middlewares: [] }
149
+ },
150
+ {
151
+ method: "GET",
152
+ path: "/presets/:name",
153
+ handler: "preset.findOne",
154
+ config: { auth: false, policies: [], middlewares: [] }
155
+ }
156
+ ]
157
+ }
158
+ };
159
+ const DEFAULT_CONFIG = { presets: {} };
160
+ const createPresetService = ({ strapi }) => ({
161
+ getConfig() {
162
+ return strapi.config.get("plugin::tiptap-editor", DEFAULT_CONFIG);
163
+ },
164
+ listPresetNames() {
165
+ return Object.keys(this.getConfig().presets || {});
166
+ },
167
+ getPreset(name) {
168
+ const presets = this.getConfig().presets || {};
169
+ return presets[name] ?? null;
170
+ }
171
+ });
172
+ const services = {
173
+ preset: createPresetService
174
+ };
31
175
  const index = {
32
176
  register,
33
177
  bootstrap,
@@ -40,5 +184,9 @@ const index = {
40
184
  policies,
41
185
  middlewares
42
186
  };
43
- module.exports = index;
187
+ exports.MINIMAL_PRESET_CONFIG = MINIMAL_PRESET_CONFIG;
188
+ exports.PRESET_FEATURE_KEYS = PRESET_FEATURE_KEYS;
189
+ exports.default = index;
190
+ exports.getFeatureOptions = getFeatureOptions;
191
+ exports.isFeatureEnabled = isFeatureEnabled;
44
192
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../shared/pluginId.ts","../../shared/fields.ts","../../server/src/fields/richTextField.ts","../../server/src/register.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/index.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","export const PLUGIN_ID = 'tiptap-editor';\n","export const RICH_TEXT_FIELD_NAME = 'RichText';\n","import { PLUGIN_ID } from '../../../shared/pluginId';\nimport { RICH_TEXT_FIELD_NAME } from '../../../shared/fields';\nimport { CustomFieldServerOptions } from '@strapi/types/dist/modules/custom-fields';\n\nexport const richTextField: CustomFieldServerOptions = {\n name: RICH_TEXT_FIELD_NAME,\n plugin: PLUGIN_ID,\n type: 'text',\n inputSize: {\n default: 12,\n isResizable: true,\n },\n};\n","import type { Core } from '@strapi/strapi';\n\nimport { richTextField } from './fields/richTextField';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.customFields.register(richTextField);\n};\n\nexport default register;\n","export default {\n default: {},\n validator() {},\n};\n","export default {};\n","export default {};\n","export default {};\n","export default {};\n","export default {};\n","export default {};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n} as const; // Type Assertion necessary due to the error below\n\n/**\n * [ERROR] server/src/index.ts:19:1 - TS2742: The inferred type of 'default' cannot be named without a reference to '@strapi/core/node_modules/@strapi/types/dist/core'. This is likely not portable. A type annotation is necessary.\n */\n"],"names":[],"mappings":";AAEA,MAAM,YAAY,CAAC,EAAE,aAAsC;AAE3D;ACFA,MAAM,UAAU,CAAC,EAAE,aAAsC;AAEzD;ACJO,MAAM,YAAY;ACAlB,MAAM,uBAAuB;ACI7B,MAAM,gBAA0C;AAAA,EACrD,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,WAAW;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,EAAA;AAEjB;ACRA,MAAM,WAAW,CAAC,EAAE,aAAsC;AACxD,SAAO,aAAa,SAAS,aAAa;AAC5C;ACNA,MAAA,SAAe;AAAA,EACb,SAAS,CAAA;AAAA,EACT,YAAY;AAAA,EAAC;AACf;ACHA,MAAA,eAAe,CAAA;ACAf,MAAA,cAAe,CAAA;ACAf,MAAA,cAAe,CAAA;ACAf,MAAA,WAAe,CAAA;ACAf,MAAA,SAAe,CAAA;ACAf,MAAA,WAAe,CAAA;ACkBf,MAAA,QAAe;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;"}
1
+ {"version":3,"file":"index.js","sources":["../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../shared/pluginId.ts","../../shared/fields.ts","../../server/src/fields/richTextField.ts","../../server/src/register.ts","../../shared/types.ts","../../server/src/config/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/preset.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/index.ts","../../server/src/services/preset.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["import type { Core } from '@strapi/strapi';\n\nconst bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {\n // bootstrap phase\n};\n\nexport default bootstrap;\n","import type { Core } from '@strapi/strapi';\n\nconst destroy = ({ strapi }: { strapi: Core.Strapi }) => {\n // destroy phase\n};\n\nexport default destroy;\n","export const PLUGIN_ID = 'tiptap-editor';\n","export const RICH_TEXT_FIELD_NAME = 'RichText';\n","import { PLUGIN_ID } from '../../../shared/pluginId';\nimport { RICH_TEXT_FIELD_NAME } from '../../../shared/fields';\nimport { CustomFieldServerOptions } from '@strapi/types/dist/modules/custom-fields';\n\nexport const richTextField: CustomFieldServerOptions = {\n name: RICH_TEXT_FIELD_NAME,\n plugin: PLUGIN_ID,\n type: 'text',\n inputSize: {\n default: 12,\n isResizable: true,\n },\n};\n","import type { Core } from '@strapi/strapi';\n\nimport { richTextField } from './fields/richTextField';\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n strapi.customFields.register(richTextField);\n};\n\nexport default register;\n","// shared/types.ts\n\n// ─── Option types ───────────────────────────────────────────────────────────\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;\n\nexport type LinkConfig = {\n openOnClick?: boolean;\n HTMLAttributes?: Record<string, string>;\n};\n\nexport type TableConfig = {\n resizable?: boolean;\n};\n\nexport type TextAlignConfig = {\n types?: string[];\n alignments?: Array<'left' | 'center' | 'right' | 'justify'>;\n};\n\nexport type HeadingConfig = {\n levels?: HeadingLevel[];\n};\n\n// ─── Core types ──────────────────────────────────────────────────────────────\n\nexport interface TiptapPresetConfig {\n bold?: boolean | Record<string, unknown>;\n italic?: boolean | Record<string, unknown>;\n strike?: boolean | Record<string, unknown>;\n code?: boolean | Record<string, unknown>;\n codeBlock?: boolean | Record<string, unknown>;\n blockquote?: boolean | Record<string, unknown>;\n bulletList?: boolean | Record<string, unknown>;\n orderedList?: boolean | Record<string, unknown>;\n hardBreak?: boolean | Record<string, unknown>;\n horizontalRule?: boolean | Record<string, unknown>;\n history?: boolean | Record<string, unknown>;\n heading?: boolean | HeadingConfig;\n link?: boolean | LinkConfig;\n table?: boolean | TableConfig;\n textAlign?: boolean | TextAlignConfig;\n superscript?: boolean | Record<string, unknown>;\n subscript?: boolean | Record<string, unknown>;\n}\n\nexport interface TiptapPluginConfig {\n presets: Record<string, TiptapPresetConfig>;\n}\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\nexport const PRESET_FEATURE_KEYS: Array<keyof TiptapPresetConfig> = [\n 'bold', 'italic', 'strike', 'code', 'codeBlock', 'blockquote',\n 'bulletList', 'orderedList', 'hardBreak', 'horizontalRule', 'history',\n 'heading', 'link', 'table', 'textAlign', 'superscript', 'subscript',\n];\n\n// Fallback for unconfigured fields — deliberately minimal to prompt developers to configure\nexport const MINIMAL_PRESET_CONFIG: TiptapPresetConfig = {\n bold: true,\n italic: true,\n};\n\n// ─── Internal helpers ────────────────────────────────────────────────────────\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\n// ─── Utility functions ───────────────────────────────────────────────────────\n\n/**\n * Returns true when a preset feature value is enabled.\n * NOTE: undefined (absent key) returns true — absent key = feature enabled by default.\n * This DIVERGES from dist where undefined returns false.\n */\nexport const isFeatureEnabled = (\n value: TiptapPresetConfig[keyof TiptapPresetConfig]\n): boolean => {\n if (value === undefined) {\n return true; // TYPES-04: absent key = enabled\n }\n if (typeof value === 'boolean') {\n return value;\n }\n if (!isPlainObject(value)) {\n return false;\n }\n const obj = value as Record<string, unknown>;\n if (typeof obj.enabled === 'boolean') {\n return obj.enabled;\n }\n if (typeof obj.disabled === 'boolean') {\n return !obj.disabled;\n }\n return true;\n};\n\n/**\n * Returns the effective options for a feature.\n * - false → null (feature explicitly disabled, no options)\n * - true | undefined → defaults (feature enabled with default options)\n * - object → merged with defaults (feature enabled with custom options)\n *\n * NOTE: false returns null — DIVERGES from dist where false returns defaults.\n */\nexport const getFeatureOptions = <T extends Record<string, unknown>>(\n value: boolean | T | undefined,\n defaults: T\n): T | null => {\n if (value === false) {\n return null; // TYPES-05: explicitly disabled\n }\n if (!isPlainObject(value)) {\n return defaults; // true or undefined: return defaults\n }\n const { enabled: _e, disabled: _d, ...rest } = value as Record<string, unknown>;\n return { ...defaults, ...rest } as T;\n};\n","import {\n PRESET_FEATURE_KEYS,\n TiptapPluginConfig,\n TiptapPresetConfig,\n} from '../../../shared/types';\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\nconst FEATURE_KEYS = new Set(PRESET_FEATURE_KEYS);\n\nconst getInvalidKeys = (presetConfig: unknown): string[] => {\n if (!isPlainObject(presetConfig)) return [];\n return Object.keys(presetConfig).filter(\n (key) => !FEATURE_KEYS.has(key as keyof TiptapPresetConfig)\n );\n};\n\nconst config = {\n default: {\n presets: {} as Record<string, TiptapPresetConfig>,\n },\n validator(pluginConfig: unknown): void {\n if (!isPlainObject(pluginConfig)) {\n throw new Error('tiptap-editor plugin config must be a plain object');\n }\n\n const typedConfig = pluginConfig as { presets?: unknown };\n const { presets } = typedConfig;\n\n if (presets === undefined) {\n return; // presets key is optional\n }\n\n if (!isPlainObject(presets)) {\n throw new Error('tiptap-editor config.presets must be a plain object');\n }\n\n const allInvalidKeys: string[] = [];\n for (const [presetName, presetConfig] of Object.entries(\n presets as Record<string, unknown>\n )) {\n const invalidKeys = getInvalidKeys(presetConfig);\n if (invalidKeys.length > 0) {\n allInvalidKeys.push(...invalidKeys);\n }\n }\n\n if (allInvalidKeys.length > 0) {\n throw new Error(\n `tiptap-editor config.presets contains invalid feature keys: ${allInvalidKeys.join(', ')}. ` +\n `Allowed keys: ${PRESET_FEATURE_KEYS.join(', ')}`\n );\n }\n },\n} satisfies { default: TiptapPluginConfig; validator: (config: unknown) => void };\n\nexport default config;\n","export default {};\n","import type { Core } from '@strapi/strapi';\nimport { MINIMAL_PRESET_CONFIG } from '../../../shared/types';\n\nconst createPresetController = ({ strapi }: { strapi: Core.Strapi }) => ({\n async find(ctx: any): Promise<void> {\n const presetService = strapi.plugin('tiptap-editor').service('preset') as any;\n ctx.body = { presets: presetService.listPresetNames() };\n },\n\n async findOne(ctx: any): Promise<void> {\n const presetService = strapi.plugin('tiptap-editor').service('preset') as any;\n const presetName: string = ctx.params?.name;\n const preset = presetService.getPreset(presetName);\n // Return MINIMAL_PRESET_CONFIG for unknown presets (never 404) — SERVER-03\n ctx.body = preset ?? MINIMAL_PRESET_CONFIG;\n },\n});\n\nexport default createPresetController;\n","import createPresetController from './preset';\n\nexport default {\n preset: createPresetController,\n};\n","export default {};\n","export default {};\n","export default {\n 'preset-routes': {\n type: 'admin' as const,\n routes: [\n {\n method: 'GET',\n path: '/presets',\n handler: 'preset.find',\n config: { auth: false, policies: [], middlewares: [] },\n },\n {\n method: 'GET',\n path: '/presets/:name',\n handler: 'preset.findOne',\n config: { auth: false, policies: [], middlewares: [] },\n },\n ],\n },\n};\n","import type { Core } from '@strapi/strapi';\nimport {\n TiptapPluginConfig,\n TiptapPresetConfig,\n} from '../../../shared/types';\n\nconst DEFAULT_CONFIG: TiptapPluginConfig = { presets: {} };\n\nconst createPresetService = ({ strapi }: { strapi: Core.Strapi }) => ({\n getConfig(): TiptapPluginConfig {\n return strapi.config.get('plugin::tiptap-editor', DEFAULT_CONFIG) as TiptapPluginConfig;\n },\n\n listPresetNames(): string[] {\n return Object.keys(this.getConfig().presets || {});\n },\n\n getPreset(name: string): TiptapPresetConfig | null {\n const presets = this.getConfig().presets || {};\n return presets[name] ?? null;\n },\n});\n\nexport default createPresetService;\n","import createPresetService from './preset';\n\nexport default {\n preset: createPresetService,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n} as const; // Type Assertion necessary due to the error below\n\n/**\n * [ERROR] server/src/index.ts:19:1 - TS2742: The inferred type of 'default' cannot be named without a reference to '@strapi/core/node_modules/@strapi/types/dist/core'. This is likely not portable. A type annotation is necessary.\n */\n\n// Re-export shared types for host app developer access via the ./strapi-server entry point\nexport type { TiptapPresetConfig, TiptapPluginConfig } from '../../shared/types';\nexport {\n PRESET_FEATURE_KEYS,\n MINIMAL_PRESET_CONFIG,\n isFeatureEnabled,\n getFeatureOptions,\n} from '../../shared/types';\n"],"names":["isPlainObject"],"mappings":"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"}
@@ -16,17 +16,160 @@ const richTextField = {
16
16
  const register = ({ strapi }) => {
17
17
  strapi.customFields.register(richTextField);
18
18
  };
19
+ const PRESET_FEATURE_KEYS = [
20
+ "bold",
21
+ "italic",
22
+ "strike",
23
+ "code",
24
+ "codeBlock",
25
+ "blockquote",
26
+ "bulletList",
27
+ "orderedList",
28
+ "hardBreak",
29
+ "horizontalRule",
30
+ "history",
31
+ "heading",
32
+ "link",
33
+ "table",
34
+ "textAlign",
35
+ "superscript",
36
+ "subscript"
37
+ ];
38
+ const MINIMAL_PRESET_CONFIG = {
39
+ bold: true,
40
+ italic: true
41
+ };
42
+ const isPlainObject$1 = (value) => {
43
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
44
+ const prototype = Object.getPrototypeOf(value);
45
+ return prototype === Object.prototype || prototype === null;
46
+ };
47
+ const isFeatureEnabled = (value) => {
48
+ if (value === void 0) {
49
+ return true;
50
+ }
51
+ if (typeof value === "boolean") {
52
+ return value;
53
+ }
54
+ if (!isPlainObject$1(value)) {
55
+ return false;
56
+ }
57
+ const obj = value;
58
+ if (typeof obj.enabled === "boolean") {
59
+ return obj.enabled;
60
+ }
61
+ if (typeof obj.disabled === "boolean") {
62
+ return !obj.disabled;
63
+ }
64
+ return true;
65
+ };
66
+ const getFeatureOptions = (value, defaults) => {
67
+ if (value === false) {
68
+ return null;
69
+ }
70
+ if (!isPlainObject$1(value)) {
71
+ return defaults;
72
+ }
73
+ const { enabled: _e, disabled: _d, ...rest } = value;
74
+ return { ...defaults, ...rest };
75
+ };
76
+ const isPlainObject = (value) => {
77
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
78
+ const prototype = Object.getPrototypeOf(value);
79
+ return prototype === Object.prototype || prototype === null;
80
+ };
81
+ const FEATURE_KEYS = new Set(PRESET_FEATURE_KEYS);
82
+ const getInvalidKeys = (presetConfig) => {
83
+ if (!isPlainObject(presetConfig)) return [];
84
+ return Object.keys(presetConfig).filter(
85
+ (key) => !FEATURE_KEYS.has(key)
86
+ );
87
+ };
19
88
  const config = {
20
- default: {},
21
- validator() {
89
+ default: {
90
+ presets: {}
91
+ },
92
+ validator(pluginConfig) {
93
+ if (!isPlainObject(pluginConfig)) {
94
+ throw new Error("tiptap-editor plugin config must be a plain object");
95
+ }
96
+ const typedConfig = pluginConfig;
97
+ const { presets } = typedConfig;
98
+ if (presets === void 0) {
99
+ return;
100
+ }
101
+ if (!isPlainObject(presets)) {
102
+ throw new Error("tiptap-editor config.presets must be a plain object");
103
+ }
104
+ const allInvalidKeys = [];
105
+ for (const [presetName, presetConfig] of Object.entries(
106
+ presets
107
+ )) {
108
+ const invalidKeys = getInvalidKeys(presetConfig);
109
+ if (invalidKeys.length > 0) {
110
+ allInvalidKeys.push(...invalidKeys);
111
+ }
112
+ }
113
+ if (allInvalidKeys.length > 0) {
114
+ throw new Error(
115
+ `tiptap-editor config.presets contains invalid feature keys: ${allInvalidKeys.join(", ")}. Allowed keys: ${PRESET_FEATURE_KEYS.join(", ")}`
116
+ );
117
+ }
22
118
  }
23
119
  };
24
120
  const contentTypes = {};
25
- const controllers = {};
121
+ const createPresetController = ({ strapi }) => ({
122
+ async find(ctx) {
123
+ const presetService = strapi.plugin("tiptap-editor").service("preset");
124
+ ctx.body = { presets: presetService.listPresetNames() };
125
+ },
126
+ async findOne(ctx) {
127
+ const presetService = strapi.plugin("tiptap-editor").service("preset");
128
+ const presetName = ctx.params?.name;
129
+ const preset = presetService.getPreset(presetName);
130
+ ctx.body = preset ?? MINIMAL_PRESET_CONFIG;
131
+ }
132
+ });
133
+ const controllers = {
134
+ preset: createPresetController
135
+ };
26
136
  const middlewares = {};
27
137
  const policies = {};
28
- const routes = {};
29
- const services = {};
138
+ const routes = {
139
+ "preset-routes": {
140
+ type: "admin",
141
+ routes: [
142
+ {
143
+ method: "GET",
144
+ path: "/presets",
145
+ handler: "preset.find",
146
+ config: { auth: false, policies: [], middlewares: [] }
147
+ },
148
+ {
149
+ method: "GET",
150
+ path: "/presets/:name",
151
+ handler: "preset.findOne",
152
+ config: { auth: false, policies: [], middlewares: [] }
153
+ }
154
+ ]
155
+ }
156
+ };
157
+ const DEFAULT_CONFIG = { presets: {} };
158
+ const createPresetService = ({ strapi }) => ({
159
+ getConfig() {
160
+ return strapi.config.get("plugin::tiptap-editor", DEFAULT_CONFIG);
161
+ },
162
+ listPresetNames() {
163
+ return Object.keys(this.getConfig().presets || {});
164
+ },
165
+ getPreset(name) {
166
+ const presets = this.getConfig().presets || {};
167
+ return presets[name] ?? null;
168
+ }
169
+ });
170
+ const services = {
171
+ preset: createPresetService
172
+ };
30
173
  const index = {
31
174
  register,
32
175
  bootstrap,
@@ -40,6 +183,10 @@ const index = {
40
183
  middlewares
41
184
  };
42
185
  export {
43
- index as default
186
+ MINIMAL_PRESET_CONFIG,
187
+ PRESET_FEATURE_KEYS,
188
+ index as default,
189
+ getFeatureOptions,
190
+ isFeatureEnabled
44
191
  };
45
192
  //# sourceMappingURL=index.mjs.map