@panneau/editor 5.0.0-alpha.12 → 5.0.0-alpha.14

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../src/Toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAY3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvD,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;CACtC;AAqED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,KAAK,EACL,QAAQ,EACR,MAAM,EAAE,WAAW,EACnB,MAAM,EACN,OAAO,GACV,EAAE,YAAY,+BA+Kd"}
1
+ {"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../src/Toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAY3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvD,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,WAAW,YAAY;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC,MAAM,EAAE,WAAW,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;CACtC;AAqED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,EACpB,MAAM,EACN,KAAK,EACL,QAAQ,EACR,MAAM,EAAE,WAAW,EACnB,MAAM,EACN,OAAO,GACV,EAAE,YAAY,+BAqLd"}
package/dist/Toolbar.js CHANGED
@@ -101,7 +101,7 @@ function Toolbar$1(t0) {
101
101
  }]] : [];
102
102
  })),
103
103
  textStyle: getTextStyle(current),
104
- canSetTextStyle: current.can().setParagraph(),
104
+ canSetTextStyle: current.can().setParagraph() || headings.some((level) => current.can().setHeading({ level })),
105
105
  style: (() => {
106
106
  const active = getActiveStyle(current.state, blockStyles);
107
107
  return active !== null ? blockStyles.indexOf(active) : -1;
@@ -136,16 +136,16 @@ function Toolbar$1(t0) {
136
136
  options: [{
137
137
  value: "paragraph",
138
138
  label: intl.formatMessage(editorMessages.paragraph)
139
- }, ...levels.map((level) => ({
140
- value: `h${String(level)}`,
141
- label: intl.formatMessage(editorMessages.heading, { level })
139
+ }, ...levels.map((level_0) => ({
140
+ value: `h${String(level_0)}`,
141
+ label: intl.formatMessage(editorMessages.heading, { level: level_0 })
142
142
  }))],
143
143
  value: textStyle,
144
144
  onChange: (value) => {
145
145
  if (value === "paragraph") editor.chain().focus().setParagraph().run();
146
146
  else if (typeof value === "string") {
147
- const level_0 = Number(value.slice(1));
148
- if (level_0 >= 1 && level_0 <= 6) editor.chain().focus().setHeading({ level: level_0 }).run();
147
+ const level_1 = Number(value.slice(1));
148
+ if (level_1 >= 1 && level_1 <= 6) editor.chain().focus().setHeading({ level: level_1 }).run();
149
149
  }
150
150
  }
151
151
  }, key);
@@ -1 +1 @@
1
- {"version":3,"file":"Toolbar.js","names":["Editor","useEditorState","Link","useState","Button","AriaButton","Toolbar","AriaToolbar","Separator","ToggleButton","editorMessages","messages","RichTextStyle","IconComponent","Select","Tooltip","usePanneauIntl","LinkDialog","styles","RichTextButton","builtInButtons","NewTabLinks","applyStyle","canApplyStyle","getActiveStyle","ToolbarProps","editor","items","headings","newTab","buttons","SEPARATOR","NO_STYLE","getShownItems","known","name","shown","reduce","result","length","at","push","slice","getTextStyle","$from","state","selection","block","parent","type","String","attrs","level","ToolbarButton","t0","$","_c","label","icon","Icon","isActive","isDisabled","onPress","t1","t2","undefined","button","t3","blockStyles","intl","linkOpen","setLinkOpen","allButtons","Map","map","_temp","has","selector","current","Object","fromEntries","flatMap","name_0","button_0","get","active","disabled","textStyle","canSetTextStyle","can","setParagraph","style","indexOf","applicable","link","canLink","setLink","href","levels","includes","Number","formatMessage","toolbar","name_1","index","key","separator","select","value","paragraph","heading","chain","focus","run","level_0","setHeading","active_0","blockStyle","noStyle","style_0","styleIndex","value_0","style_1","button_1","buttonState","_c","styles","AriaButton","Toolbar","messages","_Fragment","AriaToolbar"],"sources":["../src/Toolbar.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core';\nimport { useEditorState } from '@tiptap/react';\nimport { Link } from 'lucide-react';\nimport { useState } from 'react';\nimport {\n Button as AriaButton,\n Toolbar as AriaToolbar,\n Separator,\n ToggleButton,\n} from 'react-aria-components';\n\nimport { editorMessages as messages } from '@panneau/intl';\nimport type { RichTextStyle } from '@panneau/protocol';\nimport { type IconComponent, Select, Tooltip, usePanneauIntl } from '@panneau/ui';\n\nimport { LinkDialog } from './LinkDialog';\nimport styles from './RichTextField.module.css';\nimport { type RichTextButton, builtInButtons } from './buttons';\nimport type { NewTabLinks } from './settings';\nimport { applyStyle, canApplyStyle, getActiveStyle } from './styles';\n\nexport interface ToolbarProps {\n editor: Editor;\n /** The items, in order: built-in names, names of `buttons`, and `|` between groups. */\n items: readonly string[];\n headings: readonly number[];\n styles: readonly RichTextStyle[];\n newTab: NewTabLinks;\n /** Buttons of plugins. One with the name of a built-in button replaces it. */\n buttons: readonly RichTextButton[];\n}\n\nconst SEPARATOR = '|';\nconst NO_STYLE = 'none';\n\n/** The items that show: known ones, without separators at the ends or next to each other. */\nfunction getShownItems(\n items: readonly string[],\n known: (name: string) => boolean,\n): readonly string[] {\n const shown = items.reduce<string[]>((result, name) => {\n if (name === SEPARATOR ? result.length > 0 && result.at(-1) !== SEPARATOR : known(name)) {\n result.push(name);\n }\n return result;\n }, []);\n return shown.at(-1) === SEPARATOR ? shown.slice(0, -1) : shown;\n}\n\n/** The block of the selection, as the text style select names it: `paragraph`, `h2`. */\nfunction getTextStyle(editor: Editor): string | null {\n const { $from } = editor.state.selection;\n const block = $from.parent;\n if (block.type.name === 'heading') {\n return `h${String(block.attrs.level)}`;\n }\n return block.type.name === 'paragraph' ? 'paragraph' : null;\n}\n\nfunction ToolbarButton({\n label,\n icon: Icon,\n isActive,\n isDisabled,\n onPress,\n}: {\n label: string;\n icon: IconComponent;\n isActive: boolean | undefined;\n isDisabled: boolean;\n onPress: () => void;\n}) {\n const icon = <Icon size={16} aria-hidden />;\n return (\n <Tooltip content={label}>\n {isActive !== undefined ? (\n <ToggleButton\n className={styles.button}\n aria-label={label}\n isSelected={isActive}\n isDisabled={isDisabled}\n onChange={onPress}\n >\n {icon}\n </ToggleButton>\n ) : (\n <AriaButton\n className={styles.button}\n aria-label={label}\n isDisabled={isDisabled}\n onPress={onPress}\n >\n {icon}\n </AriaButton>\n )}\n </Tooltip>\n );\n}\n\n/**\n * The toolbar of the rich text field: the text style (paragraph or a heading level), the block\n * styles, marks, links, lists and the buttons of plugins, as the field's `toolbar` lists them.\n */\nexport function Toolbar({\n editor,\n items,\n headings,\n styles: blockStyles,\n newTab,\n buttons,\n}: ToolbarProps) {\n const intl = usePanneauIntl();\n const [linkOpen, setLinkOpen] = useState(false);\n const allButtons = new Map(\n [...builtInButtons, ...buttons].map((button) => [button.name, button]),\n );\n const known = (name: string) =>\n allButtons.has(name) ||\n name === 'heading' ||\n name === 'link' ||\n (name === 'style' && blockStyles.length > 0);\n const shown = getShownItems(items, known);\n\n // Only what the toolbar shows: it renders again when it changes\n const state = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n buttons: Object.fromEntries(\n shown.flatMap((name) => {\n const button = allButtons.get(name);\n return button !== undefined\n ? [\n [\n name,\n {\n active: button.isActive?.(current),\n disabled: button.isDisabled?.(current) ?? false,\n },\n ],\n ]\n : [];\n }),\n ),\n textStyle: getTextStyle(current),\n canSetTextStyle: current.can().setParagraph(),\n style: (() => {\n const active = getActiveStyle(current.state, blockStyles);\n return active !== null ? blockStyles.indexOf(active) : -1;\n })(),\n applicable: blockStyles.map((style) => canApplyStyle(current.state, style)),\n link: current.isActive('link'),\n canLink: current.can().setLink({ href: '' }),\n }),\n });\n\n const textStyle = state.textStyle;\n const levels =\n textStyle !== null && textStyle !== 'paragraph' && !headings.includes(Number(textStyle[1]))\n ? [...headings, Number(textStyle[1])]\n : headings;\n\n return (\n <>\n <AriaToolbar\n aria-label={intl.formatMessage(messages.toolbar)}\n className={styles.toolbar}\n >\n {shown.map((name, index) => {\n const key = `${name}-${String(index)}`;\n if (name === SEPARATOR) {\n return (\n <Separator\n key={key}\n orientation=\"vertical\"\n className={styles.separator}\n />\n );\n }\n if (name === 'heading') {\n return (\n <Select\n key={key}\n aria-label={intl.formatMessage(messages.textStyle)}\n className={styles.select}\n isDisabled={!state.canSetTextStyle}\n options={[\n {\n value: 'paragraph',\n label: intl.formatMessage(messages.paragraph),\n },\n ...levels.map((level) => ({\n value: `h${String(level)}`,\n label: intl.formatMessage(messages.heading, { level }),\n })),\n ]}\n value={textStyle}\n onChange={(value) => {\n if (value === 'paragraph') {\n editor.chain().focus().setParagraph().run();\n } else if (typeof value === 'string') {\n const level = Number(value.slice(1));\n if (level >= 1 && level <= 6) {\n editor\n .chain()\n .focus()\n .setHeading({\n level: level as 1 | 2 | 3 | 4 | 5 | 6,\n })\n .run();\n }\n }\n }}\n />\n );\n }\n if (name === 'style') {\n const active = state.style;\n return (\n <Select\n key={key}\n aria-label={intl.formatMessage(messages.blockStyle)}\n className={styles.select}\n options={[\n {\n value: NO_STYLE,\n label: intl.formatMessage(messages.noStyle),\n },\n ...blockStyles.map((style, styleIndex) => ({\n value: String(styleIndex),\n label: style.label,\n disabled: state.applicable[styleIndex] !== true,\n })),\n ]}\n value={active >= 0 ? String(active) : NO_STYLE}\n onChange={(value) => {\n const style =\n value === NO_STYLE ? null : blockStyles[Number(value)];\n applyStyle(editor, style ?? null, blockStyles);\n }}\n />\n );\n }\n if (name === 'link') {\n return (\n <ToolbarButton\n key={key}\n label={intl.formatMessage(messages.link)}\n icon={Link}\n isActive={state.link}\n isDisabled={!state.canLink}\n onPress={() => setLinkOpen(true)}\n />\n );\n }\n const button = allButtons.get(name);\n if (button === undefined) {\n return null;\n }\n const buttonState = state.buttons[name];\n return (\n <ToolbarButton\n key={key}\n label={\n typeof button.label === 'string'\n ? button.label\n : intl.formatMessage(button.label)\n }\n icon={button.icon}\n isActive={buttonState?.active}\n isDisabled={buttonState?.disabled === true}\n onPress={() => button.run(editor)}\n />\n );\n })}\n </AriaToolbar>\n {shown.includes('link') ? (\n <LinkDialog\n editor={editor}\n newTab={newTab}\n isOpen={linkOpen}\n onOpenChange={setLinkOpen}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAgCA,IAAM+B,YAAY;AAClB,IAAMC,WAAW;;AAGjB,SAASC,cACLN,OACAO,OACiB;CACjB,MAAME,QAAQT,MAAMU,QAAkBC,QAAQH,SAAS;EACnD,IAAIA,SAASJ,YAAYO,OAAOC,SAAS,KAAKD,OAAOE,GAAG,EAAE,MAAMT,YAAYG,MAAMC,IAAI,GAClFG,OAAOG,KAAKN,IAAI;EAEpB,OAAOG;CACX,GAAG,CAAA,CAAE;CACL,OAAOF,MAAMI,GAAG,EAAE,MAAMT,YAAYK,MAAMM,MAAM,GAAG,EAAE,IAAIN;AAC7D;;AAGA,SAASO,aAAajB,QAA+B;CACjD,MAAM,EAAEkB,UAAUlB,OAAOmB,MAAMC;CAC/B,MAAMC,QAAQH,MAAMI;CACpB,IAAID,MAAME,KAAKd,SAAS,WACpB,OAAO,IAAIe,OAAOH,MAAMI,MAAMC,KAAK;CAEvC,OAAOL,MAAME,KAAKd,SAAS,cAAc,cAAc;AAC3D;AAEA,SAAAkB,cAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAuB,MAAA,EAAAC,OAAAC,MAAAC,MAAAC,UAAAC,YAAAC,YAAAR;CAYtB,IAAAS;CAAA,IAAAR,EAAA,OAAAI,MAAA;EACgBI,KAAA,oBAAC,MAAD;GAAY,MAAA;GAAI,eAAA;EAAW,CAAA;EAAGR,EAAA,KAAAI;EAAAJ,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAA3C,MAAAG,OAAaK;CAA+B,IAAAC;CAAA,IAAAT,EAAA,OAAAG,QAAAH,EAAA,OAAAK,YAAAL,EAAA,OAAAM,cAAAN,EAAA,OAAAE,SAAAF,EAAA,OAAAO,SAAA;EAGnCE,KAAAJ,aAAaK,KAAAA,IACV,oBAAC,cAAD;GACe,WAAA/C,6BAAMgD;GACLT,cAAAA;GACAG,YAAAA;GACAC;GACFC,UAAAA;GAETJ,UAAAA;EAPQ,CAAA,IAUb,oBAACqE,UAAD;GACe,WAAA7G,6BAAMgD;GACLT,cAAAA;GACAI;GACHC;GAERJ,UAAAA;EANM,CAAA;EAQdH,EAAA,KAAAG;EAAAH,EAAA,KAAAK;EAAAL,EAAA,KAAAM;EAAAN,EAAA,KAAAE;EAAAF,EAAA,KAAAO;EAAAP,EAAA,KAAAS;CAAA,OAAAA,KAAAT,EAAA;CAAA,IAAAY;CAAA,IAAAZ,EAAA,OAAAE,SAAAF,EAAA,OAAAS,IAAA;EApBLG,KAAA,oBAAC,SAAD;GAAkBV,SAAAA;GACbO,UAAAA;EADG,CAAA;EAqBET,EAAA,KAAAE;EAAAF,EAAA,KAAAS;EAAAT,EAAA,MAAAY;CAAA,OAAAA,KAAAZ,EAAA;CAAA,OArBVY;AAqBU;;;;;AAQlB,SAAO7D,UAAAgD,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAiB,MAAA,EAAA9B,QAAAC,OAAAC,UAAAV,QAAAkD,aAAAvC,QAAAC,YAAAwB;CAQpB,MAAAe,OAAarD,eAAe;CAC5B,MAAA,CAAAsD,UAAAC,eAAgCpE,SAAS,KAAK;CAC9C,MAAAqE,aAAmB,IAAIC,IACnB,CAAA,GAAIrD,gBAAc,GAAKU,OAAO,CAAC,CAAA4C,IAAKC,KAAiC,CACzE;CACA,MAAAzC,SAAcC,SACVqC,WAAUI,IAAKzC,IACE,KAAjBA,SAAS,aACTA,SAAS,UACRA,SAAS,WAAWiC,YAAW7B,SAAU;CAC9C,MAAAH,QAAcH,cAAcN,OAAOO,KAAK;CAGxC,MAAAW,QAAc5C,eAAe;EAAAyB;EAAAmD,WAEfd,OAAA;GAAC,MAAA,EAAArC,QAAAoD,YAAAf;GAAmB,OAAM;IAAAjC,SACvBiD,OAAMC,YACX5C,MAAK6C,SAASC,WAAA;KACV,MAAAC,WAAeX,WAAUY,IAAKjD,MAAI;KAAE,OAC7B+B,aAAWD,KAAAA,IAAX,CAEG,CACI9B,QACA;MAAAkD,QACYnB,SAAMN,WAAYkB,OAAO;MAACQ,UACxBpB,SAAML,aAAciB,OAAgB,KAApC;KACd,CAAC,CACJ,IARJ,CAAA;IAUC,CACX,CACL;IAACS,WACU5C,aAAamC,OAAO;IAACU,iBACfV,QAAOW,IAAK,CAAC,CAAAC,aAAc;IAACC,cACrC;KACJ,MAAAN,SAAe7D,eAAesD,QAAOjC,OAAQuB,WAAW;KAAE,OACnDiB,WAAW,OAAOjB,YAAWwB,QAASP,MAAW,IAAjD;IAAkD,EAAA,CAC1D;IAACQ,YACQzB,YAAWM,KAAKiB,UAAWpE,cAAcuD,QAAOjC,OAAQ8C,KAAK,CAAC;IAACG,MACrEhB,QAAOlB,SAAU,MAAM;IAACmC,SACrBjB,QAAOW,IAAK,CAAC,CAAAO,QAAS,EAAAC,MAAQ,GAAG,CAAC;GAC/C;EAAC;CACL,CAAC;CAED,MAAAV,YAAkB1C,MAAK0C;CACvB,MAAAW,SACIX,cAAc,QAAQA,cAAc,eAApC,CAAoD3D,SAAQuE,SAAUC,OAAOb,UAAS,EAAG,CAAC,IAA1F,CAAA,GACU3D,UAAUwE,OAAOb,UAAS,EAAG,CAAC,IADxC3D;CAEe,IAAAoC;CAAA,IAAAT,EAAA,OAAAc,MAAA;EAKKL,KAAAK,KAAIgC,cAAe1F,eAAQ2F,OAAQ;EAAC/C,EAAA,KAAAc;EAAAd,EAAA,KAAAS;CAAA,OAAAA,KAAAT,EAAA;CAAA,OAFxD,qBAAA2E,UAAA,EAAA,UAAA,CACI,oBAACC,SAAD;EACgB,cAAAnE;EACD,WAAA9C,6BAAMoF;EAEhBlE,UAAAA,MAAKsC,KAAK6B,QAAAC,UAAA;GACP,MAAAC,MAAY,GAAGtE,OAAI,GAAIe,OAAOsD,KAAK;GACnC,IAAIrE,WAASJ,WAAS,OAEd,oBAAC,WAAD;IAEgB,aAAA;IACD,WAAAb,6BAAMwF;GAAU,GAFtBD,GAEsB;GAIvC,IAAItE,WAAS,WAAS,OAEd,oBAAC,QAAD;IAEgB,cAAAkC,KAAIgC,cAAe1F,eAAQ4E,SAAU;IACtC,WAAArE,6BAAMyF;IACL,YAAA,CAAC9D,MAAK2C;IACT,SAAA,CACL;KAAAoB,OACW;KAAWnD,OACXY,KAAIgC,cAAe1F,eAAQkG,SAAU;IAChD,GAAC,GACEX,OAAMxB,KAAKtB,WAAY;KAAAwD,OACf,IAAI1D,OAAOE,KAAK;KAAGK,OACnBY,KAAIgC,cAAe1F,eAAQmG,SAAU,EAAA1D,MAAQ,CAAC;IACzD,EAAE,CAAC;IAEAmC,OAAAA;IACG,WAAAqB,UAAA;KACN,IAAIA,UAAU,aACVlF,OAAMqF,MAAO,CAAC,CAAAC,MAAO,CAAC,CAAAtB,aAAc,CAAC,CAAAuB,IAAK;UACvC,IAAI,OAAOL,UAAU,UAAQ;MAChC,MAAAM,UAAcd,OAAOQ,MAAKlE,MAAO,CAAC,CAAC;MACnC,IAAIU,WAAS,KAAKA,WAAS,GACvB1B,OAAMqF,MACK,CAAC,CAAAC,MACD,CAAC,CAAAG,WACI,EAAA/D,OACDA,QACX,CAAC,CAAC,CAAA6D,IACG;KACZ;IACJ;GACJ,GA9BIR,GA8BJ;GAIb,IAAItE,WAAS,SAAO;IAChB,MAAAiF,WAAevE,MAAK8C;IAAO,OAEvB,oBAAC,QAAD;KAEgB,cAAAtB,KAAIgC,cAAe1F,eAAQ0G,UAAW;KACvC,WAAAnG,6BAAMyF;KACR,SAAA,CACL;MAAAC,OACW5E;MAAQyB,OACRY,KAAIgC,cAAe1F,eAAQ2G,OAAQ;KAC9C,GAAC,GACElD,YAAWM,KAAK6C,SAAAC,gBAAwB;MAAAZ,OAChC1D,OAAOsE,UAAU;MAAC/D,OAClBkC,QAAKlC;MAAM6B,UACRzC,MAAKgD,WAAY2B,gBAAgB;KAC/C,EAAE,CAAC;KAEA,OAAAnC,YAAU,IAAInC,OAAOmC,QAAiB,IAAtCrD;KACG,WAAAyF,YAAA;MACN,MAAAC,UACId,YAAU5E,WAAV,OAA4BoC,YAAYgC,OAAOQ,OAAK;MACxDtF,WAAWI,QAAQgG,WAAA,MAAetD,WAAW;KAAC;IACjD,GAnBIqC,GAmBJ;GACH;GAGV,IAAItE,WAAS,QAAM,OAEX,oBAAC,eAAD;IAEW,OAAAkC,KAAIgC,cAAe1F,eAAQmF,IAAK;IACjC5F,MAAAA;IACI,UAAA2C,MAAKiD;IACH,YAAA,CAACjD,MAAKkD;IACT,eAAMxB,YAAY,IAAI;GAAC,GAL3BkC,GAK2B;GAI5C,MAAAkB,WAAenD,WAAUY,IAAKjD,MAAI;GAClC,IAAI+B,aAAWD,KAAAA,GAAS,OACb;GAEX,MAAA2D,cAAoB/E,MAAKf,QAASK;GAAM,OAEpC,oBAAC,eAAD;IAGQ,OAAA,OAAO+B,SAAMT,UAAW,WAClBS,SAAMT,QACNY,KAAIgC,cAAenC,SAAMT,KAAM;IAEnC,MAAAS,SAAMR;IACF,UAAAkE,aAAWvC;IACT,YAAAuC,aAAWtC,aAAe;IAC7B,eAAMpB,SAAM+C,IAAKvF,MAAM;GAAC,GAT5B+E,GAS4B;EACnC,CAET;CA9GO,CAAA,GAgHXrE,MAAK+D,SAAU,MAOT,IANH,oBAAC,YAAD;EACYzE;EACAG;EACAyC,QAAAA;EACMC,cAAAA;CAAW,CAAA,IALhC,IAOO,EAAA,CAAA;AACT;AApLJ,SAAAI,MAAAT,QAAA;CAAA,OAWiD,CAACA,OAAM/B,MAAO+B,MAAM;AAAC"}
1
+ {"version":3,"file":"Toolbar.js","names":["Editor","useEditorState","Link","useState","Button","AriaButton","Toolbar","AriaToolbar","Separator","ToggleButton","editorMessages","messages","RichTextStyle","IconComponent","Select","Tooltip","usePanneauIntl","LinkDialog","styles","RichTextButton","builtInButtons","NewTabLinks","applyStyle","canApplyStyle","getActiveStyle","ToolbarProps","editor","items","headings","newTab","buttons","SEPARATOR","NO_STYLE","getShownItems","known","name","shown","reduce","result","length","at","push","slice","getTextStyle","$from","state","selection","block","parent","type","String","attrs","level","ToolbarButton","t0","$","_c","label","icon","Icon","isActive","isDisabled","onPress","t1","t2","undefined","button","t3","blockStyles","intl","linkOpen","setLinkOpen","allButtons","Map","map","_temp","has","selector","current","Object","fromEntries","flatMap","name_0","button_0","get","active","disabled","textStyle","canSetTextStyle","can","setParagraph","some","setHeading","style","indexOf","applicable","link","canLink","setLink","href","levels","includes","Number","formatMessage","toolbar","name_1","index","key","separator","select","value","paragraph","level_0","heading","chain","focus","run","level_1","active_0","blockStyle","noStyle","style_0","styleIndex","value_0","style_1","button_1","buttonState","_c","styles","AriaButton","Toolbar","messages","_Fragment","AriaToolbar"],"sources":["../src/Toolbar.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core';\nimport { useEditorState } from '@tiptap/react';\nimport { Link } from 'lucide-react';\nimport { useState } from 'react';\nimport {\n Button as AriaButton,\n Toolbar as AriaToolbar,\n Separator,\n ToggleButton,\n} from 'react-aria-components';\n\nimport { editorMessages as messages } from '@panneau/intl';\nimport type { RichTextStyle } from '@panneau/protocol';\nimport { type IconComponent, Select, Tooltip, usePanneauIntl } from '@panneau/ui';\n\nimport { LinkDialog } from './LinkDialog';\nimport styles from './RichTextField.module.css';\nimport { type RichTextButton, builtInButtons } from './buttons';\nimport type { NewTabLinks } from './settings';\nimport { applyStyle, canApplyStyle, getActiveStyle } from './styles';\n\nexport interface ToolbarProps {\n editor: Editor;\n /** The items, in order: built-in names, names of `buttons`, and `|` between groups. */\n items: readonly string[];\n headings: readonly number[];\n styles: readonly RichTextStyle[];\n newTab: NewTabLinks;\n /** Buttons of plugins. One with the name of a built-in button replaces it. */\n buttons: readonly RichTextButton[];\n}\n\nconst SEPARATOR = '|';\nconst NO_STYLE = 'none';\n\n/** The items that show: known ones, without separators at the ends or next to each other. */\nfunction getShownItems(\n items: readonly string[],\n known: (name: string) => boolean,\n): readonly string[] {\n const shown = items.reduce<string[]>((result, name) => {\n if (name === SEPARATOR ? result.length > 0 && result.at(-1) !== SEPARATOR : known(name)) {\n result.push(name);\n }\n return result;\n }, []);\n return shown.at(-1) === SEPARATOR ? shown.slice(0, -1) : shown;\n}\n\n/** The block of the selection, as the text style select names it: `paragraph`, `h2`. */\nfunction getTextStyle(editor: Editor): string | null {\n const { $from } = editor.state.selection;\n const block = $from.parent;\n if (block.type.name === 'heading') {\n return `h${String(block.attrs.level)}`;\n }\n return block.type.name === 'paragraph' ? 'paragraph' : null;\n}\n\nfunction ToolbarButton({\n label,\n icon: Icon,\n isActive,\n isDisabled,\n onPress,\n}: {\n label: string;\n icon: IconComponent;\n isActive: boolean | undefined;\n isDisabled: boolean;\n onPress: () => void;\n}) {\n const icon = <Icon size={16} aria-hidden />;\n return (\n <Tooltip content={label}>\n {isActive !== undefined ? (\n <ToggleButton\n className={styles.button}\n aria-label={label}\n isSelected={isActive}\n isDisabled={isDisabled}\n onChange={onPress}\n >\n {icon}\n </ToggleButton>\n ) : (\n <AriaButton\n className={styles.button}\n aria-label={label}\n isDisabled={isDisabled}\n onPress={onPress}\n >\n {icon}\n </AriaButton>\n )}\n </Tooltip>\n );\n}\n\n/**\n * The toolbar of the rich text field: the text style (paragraph or a heading level), the block\n * styles, marks, links, lists and the buttons of plugins, as the field's `toolbar` lists them.\n */\nexport function Toolbar({\n editor,\n items,\n headings,\n styles: blockStyles,\n newTab,\n buttons,\n}: ToolbarProps) {\n const intl = usePanneauIntl();\n const [linkOpen, setLinkOpen] = useState(false);\n const allButtons = new Map(\n [...builtInButtons, ...buttons].map((button) => [button.name, button]),\n );\n const known = (name: string) =>\n allButtons.has(name) ||\n name === 'heading' ||\n name === 'link' ||\n (name === 'style' && blockStyles.length > 0);\n const shown = getShownItems(items, known);\n\n // Only what the toolbar shows: it renders again when it changes\n const state = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n buttons: Object.fromEntries(\n shown.flatMap((name) => {\n const button = allButtons.get(name);\n return button !== undefined\n ? [\n [\n name,\n {\n active: button.isActive?.(current),\n disabled: button.isDisabled?.(current) ?? false,\n },\n ],\n ]\n : [];\n }),\n ),\n textStyle: getTextStyle(current),\n // `setParagraph()` can't run in a paragraph, and `setHeading()` can't run in a heading of\n // the same level: the select is usable when the selection can take any of its styles\n canSetTextStyle:\n current.can().setParagraph() ||\n headings.some((level) =>\n current.can().setHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 }),\n ),\n style: (() => {\n const active = getActiveStyle(current.state, blockStyles);\n return active !== null ? blockStyles.indexOf(active) : -1;\n })(),\n applicable: blockStyles.map((style) => canApplyStyle(current.state, style)),\n link: current.isActive('link'),\n canLink: current.can().setLink({ href: '' }),\n }),\n });\n\n const textStyle = state.textStyle;\n const levels =\n textStyle !== null && textStyle !== 'paragraph' && !headings.includes(Number(textStyle[1]))\n ? [...headings, Number(textStyle[1])]\n : headings;\n\n return (\n <>\n <AriaToolbar\n aria-label={intl.formatMessage(messages.toolbar)}\n className={styles.toolbar}\n >\n {shown.map((name, index) => {\n const key = `${name}-${String(index)}`;\n if (name === SEPARATOR) {\n return (\n <Separator\n key={key}\n orientation=\"vertical\"\n className={styles.separator}\n />\n );\n }\n if (name === 'heading') {\n return (\n <Select\n key={key}\n aria-label={intl.formatMessage(messages.textStyle)}\n className={styles.select}\n isDisabled={!state.canSetTextStyle}\n options={[\n {\n value: 'paragraph',\n label: intl.formatMessage(messages.paragraph),\n },\n ...levels.map((level) => ({\n value: `h${String(level)}`,\n label: intl.formatMessage(messages.heading, { level }),\n })),\n ]}\n value={textStyle}\n onChange={(value) => {\n if (value === 'paragraph') {\n editor.chain().focus().setParagraph().run();\n } else if (typeof value === 'string') {\n const level = Number(value.slice(1));\n if (level >= 1 && level <= 6) {\n editor\n .chain()\n .focus()\n .setHeading({\n level: level as 1 | 2 | 3 | 4 | 5 | 6,\n })\n .run();\n }\n }\n }}\n />\n );\n }\n if (name === 'style') {\n const active = state.style;\n return (\n <Select\n key={key}\n aria-label={intl.formatMessage(messages.blockStyle)}\n className={styles.select}\n options={[\n {\n value: NO_STYLE,\n label: intl.formatMessage(messages.noStyle),\n },\n ...blockStyles.map((style, styleIndex) => ({\n value: String(styleIndex),\n label: style.label,\n disabled: state.applicable[styleIndex] !== true,\n })),\n ]}\n value={active >= 0 ? String(active) : NO_STYLE}\n onChange={(value) => {\n const style =\n value === NO_STYLE ? null : blockStyles[Number(value)];\n applyStyle(editor, style ?? null, blockStyles);\n }}\n />\n );\n }\n if (name === 'link') {\n return (\n <ToolbarButton\n key={key}\n label={intl.formatMessage(messages.link)}\n icon={Link}\n isActive={state.link}\n isDisabled={!state.canLink}\n onPress={() => setLinkOpen(true)}\n />\n );\n }\n const button = allButtons.get(name);\n if (button === undefined) {\n return null;\n }\n const buttonState = state.buttons[name];\n return (\n <ToolbarButton\n key={key}\n label={\n typeof button.label === 'string'\n ? button.label\n : intl.formatMessage(button.label)\n }\n icon={button.icon}\n isActive={buttonState?.active}\n isDisabled={buttonState?.disabled === true}\n onPress={() => button.run(editor)}\n />\n );\n })}\n </AriaToolbar>\n {shown.includes('link') ? (\n <LinkDialog\n editor={editor}\n newTab={newTab}\n isOpen={linkOpen}\n onOpenChange={setLinkOpen}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panneau/editor",
3
- "version": "5.0.0-alpha.12",
3
+ "version": "5.0.0-alpha.14",
4
4
  "description": "The rich text field of Panneau, on TipTap 3: HTML storage, a toolbar and block styles set from the definition, and extensions from plugins.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -41,10 +41,10 @@
41
41
  "react-intl": "^12.0.0"
42
42
  },
43
43
  "dependencies": {
44
- "@panneau/fields": "5.0.0-alpha.12",
45
- "@panneau/intl": "5.0.0-alpha.12",
46
- "@panneau/protocol": "5.0.0-alpha.12",
47
- "@panneau/ui": "5.0.0-alpha.12",
44
+ "@panneau/fields": "5.0.0-alpha.14",
45
+ "@panneau/intl": "5.0.0-alpha.14",
46
+ "@panneau/protocol": "5.0.0-alpha.14",
47
+ "@panneau/ui": "5.0.0-alpha.14",
48
48
  "@tiptap/extension-blockquote": "^3.32.1",
49
49
  "@tiptap/extension-bold": "^3.32.1",
50
50
  "@tiptap/extension-code": "^3.32.1",