@jackuait/blok 0.10.0-beta.4 → 0.10.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blok.mjs +3 -3
- package/dist/chunks/{blok-D_0qAdUd.mjs → blok-BdlR_lX6.mjs} +2073 -2034
- package/dist/chunks/chunk-Byubey_H.mjs +20 -0
- package/dist/chunks/{constants-DxSXr7kd.mjs → constants-Cp8O0UfP.mjs} +524 -550
- package/dist/chunks/default-DIfXCS2E.mjs +4 -0
- package/dist/chunks/{i18next-G6FKbZqA.mjs → i18next-KNC_XV5x.mjs} +1 -1
- package/dist/chunks/{i18next-loader-CwNimni3.mjs → i18next-loader-oDO9ZKUV.mjs} +2 -2
- package/dist/chunks/katex-NjLaA6AJ.mjs +22026 -0
- package/dist/chunks/{lightweight-i18n-DWCdzAw0.mjs → lightweight-i18n-DTySD6f6.mjs} +16 -18
- package/dist/chunks/mdast-util-math-yS0EygZV.mjs +151 -0
- package/dist/{messages-DVQNjdPk.mjs → chunks/messages-5ArOv8cj.mjs} +3 -17
- package/dist/chunks/{messages-Czny5pPT2.mjs → messages-876bKyUj2.mjs} +3 -17
- package/dist/{messages-JhoVMjfX2.mjs → chunks/messages-9l49jauY.mjs} +3 -17
- package/dist/{messages-D3cAcyzj.mjs → chunks/messages-B5aAzExz.mjs} +3 -17
- package/dist/chunks/{messages-CmrMwBv3.mjs → messages-B5fKJXd6.mjs} +3 -17
- package/dist/chunks/{messages-DBpXyvRe2.mjs → messages-B9N__q552.mjs} +3 -17
- package/dist/{messages-CVcQD-9u.mjs → chunks/messages-BAP2OAQk.mjs} +3 -17
- package/dist/chunks/{messages-R2W_rGOo2.mjs → messages-BDXl53cy2.mjs} +3 -17
- package/dist/{messages-CM5fsPo02.mjs → chunks/messages-BGCQCeWd.mjs} +3 -17
- package/dist/{messages-DtrSrdfE2.mjs → chunks/messages-BHhbHLoq.mjs} +3 -17
- package/dist/{messages-C6Y4Jv2N.mjs → chunks/messages-BMq9k_lI.mjs} +3 -17
- package/dist/{messages-DjJQoYvP2.mjs → chunks/messages-BXSXk3oS2.mjs} +3 -17
- package/dist/{messages-pgPcitDH.mjs → chunks/messages-BXn9Vzbx2.mjs} +3 -17
- package/dist/chunks/{messages-DR09nkcZ.mjs → messages-BaoJwsEZ.mjs} +3 -17
- package/dist/{messages-CdlsTFB1.mjs → chunks/messages-BbfLRqLh2.mjs} +3 -17
- package/dist/{messages-BvgTQLf72.mjs → chunks/messages-BhcYsC_M2.mjs} +3 -17
- package/dist/chunks/{messages-Cdx4QMR1.mjs → messages-BlO_37l_.mjs} +3 -17
- package/dist/{messages--S8_taOd2.mjs → chunks/messages-BlcRm2I3.mjs} +3 -17
- package/dist/{messages-DbxbxUiK2.mjs → chunks/messages-Btr121zI2.mjs} +3 -17
- package/dist/chunks/{messages-p4byLfvR.mjs → messages-BxBID_0B.mjs} +3 -17
- package/dist/chunks/{messages-Cs9XBt4T.mjs → messages-ByAqzAhB.mjs} +3 -17
- package/dist/chunks/{messages-JQKFJo7C.mjs → messages-C-jA6Rf7.mjs} +3 -17
- package/dist/{messages-BAcH6PtT2.mjs → chunks/messages-C5aCWL7B.mjs} +3 -17
- package/dist/{messages-BCG_evLg.mjs → chunks/messages-CF_PfacZ.mjs} +3 -17
- package/dist/{messages-B-4fku2H2.mjs → chunks/messages-CKRJDX0K2.mjs} +3 -17
- package/dist/chunks/{messages-CrMfiGu5.mjs → messages-CL3mCbi6.mjs} +3 -17
- package/dist/chunks/{messages-BnznaKEP2.mjs → messages-CNEJxD8q2.mjs} +3 -17
- package/dist/{messages-hTpeKUaW.mjs → chunks/messages-CZ5Sbf8U.mjs} +3 -17
- package/dist/chunks/{messages-CljStrYi.mjs → messages-CcyIKgGU.mjs} +3 -17
- package/dist/{messages-Dcyrzdxa2.mjs → chunks/messages-CdzF0Hvl.mjs} +3 -17
- package/dist/chunks/{messages-IDEUsFhQ2.mjs → messages-CgedvWCf.mjs} +3 -17
- package/dist/chunks/{messages-CmXADeab2.mjs → messages-CjVPwkVy.mjs} +3 -17
- package/dist/chunks/{messages-wLSVQbsA2.mjs → messages-CnQydQJd2.mjs} +3 -17
- package/dist/chunks/{messages-BS1nOvZ-.mjs → messages-CqgEz7C5.mjs} +3 -17
- package/dist/{messages-BCuTVHBV.mjs → chunks/messages-CvlMT1e62.mjs} +3 -17
- package/dist/{messages-CYX48nfg.mjs → chunks/messages-CyxDkx8a.mjs} +3 -17
- package/dist/chunks/{messages-ClRHDxzh.mjs → messages-D7n_wJK7.mjs} +3 -17
- package/dist/chunks/{messages-Dplnp19q.mjs → messages-D8-N0FmU.mjs} +3 -17
- package/dist/chunks/{messages-DAVsuDWh2.mjs → messages-D8dKkyII2.mjs} +3 -17
- package/dist/chunks/{messages-B3s2vra72.mjs → messages-DGD6BiGd.mjs} +3 -17
- package/dist/chunks/{messages-DHCVA7XQ.mjs → messages-DJO0ERQT.mjs} +3 -17
- package/dist/chunks/{messages-B7MIRzCa2.mjs → messages-DMyRdafk2.mjs} +3 -17
- package/dist/chunks/{messages-C-b6tPad2.mjs → messages-DN-194c32.mjs} +3 -17
- package/dist/chunks/{messages-BW_7lfqG2.mjs → messages-DQ5ng0_t2.mjs} +3 -17
- package/dist/{messages-DUBHHfEt.mjs → chunks/messages-DRv4g-IA.mjs} +3 -17
- package/dist/chunks/{messages-xfjdrZmx.mjs → messages-DSO2U-ul.mjs} +3 -17
- package/dist/{messages-CgzbJ8_l2.mjs → chunks/messages-DUGEqDEG.mjs} +3 -17
- package/dist/{messages-DA-o8X3A.mjs → chunks/messages-DVKifYlq.mjs} +3 -17
- package/dist/{messages-tsHpMdDT2.mjs → chunks/messages-DWD0ry9x.mjs} +3 -17
- package/dist/{messages-Dddxv8-f2.mjs → chunks/messages-DYizZHT2.mjs} +3 -17
- package/dist/chunks/{messages-Csvm4mtA.mjs → messages-DZwCufSb.mjs} +3 -17
- package/dist/{messages-BJ7BuFZi.mjs → chunks/messages-DdmWzF5M.mjs} +3 -17
- package/dist/{messages-Bo_FUvVH.mjs → chunks/messages-DgEGJECT.mjs} +3 -17
- package/dist/chunks/{messages-Bpda_3PM2.mjs → messages-Dgng6KN8.mjs} +3 -17
- package/dist/{messages-CBzd_x7H.mjs → chunks/messages-DkTxBa1V.mjs} +3 -17
- package/dist/{messages-Bio7KYsr2.mjs → chunks/messages-DnJHflSh.mjs} +3 -17
- package/dist/{messages-CjmSrt1D.mjs → chunks/messages-DopbvJlg.mjs} +3 -17
- package/dist/{messages-DIRha_gg2.mjs → chunks/messages-Dux1S0-D2.mjs} +3 -17
- package/dist/chunks/{messages-1Raf1IK82.mjs → messages-Dw2rmKMi2.mjs} +3 -17
- package/dist/chunks/{messages-D5IgUbBD2.mjs → messages-Dz3UhEco2.mjs} +3 -17
- package/dist/{messages-C6OJvnJg2.mjs → chunks/messages-FYl9woii2.mjs} +3 -17
- package/dist/{messages-BBvDbp62.mjs → chunks/messages-Jps5Tc77.mjs} +3 -17
- package/dist/chunks/{messages-Dfpi8pDY.mjs → messages-NJsvFwJj.mjs} +3 -17
- package/dist/chunks/{messages-DPykxECP2.mjs → messages-SSDr5fGF2.mjs} +3 -17
- package/dist/{messages-BXI3qIos.mjs → chunks/messages-bmwto4UV.mjs} +3 -17
- package/dist/{messages-CBdQ3XP9.mjs → chunks/messages-vN4T4r67.mjs} +3 -17
- package/dist/{messages-tK67CBqn.mjs → chunks/messages-yszqJukE.mjs} +3 -17
- package/dist/chunks/micromark-extension-math-CCEGWpdz.mjs +169 -0
- package/dist/chunks/micromark-factory-space-WwmyBO_J.mjs +36 -0
- package/dist/chunks/{notifier-Butv4Dvo.mjs → notifier-BOwxj_Ok.mjs} +1 -1
- package/dist/chunks/{objectSpread2-BY4mgzrQ.mjs → objectSpread2-CWwMYL_U.mjs} +1 -1
- package/dist/chunks/{tools-DVZ3zU40.mjs → tools-DGOsJbHH.mjs} +1816 -2916
- package/dist/full.mjs +14 -14
- package/dist/locales.mjs +82 -84
- package/dist/markdown.mjs +3962 -0
- package/dist/{messages-DqyqEw1_.mjs → messages--cUQf9JX.mjs} +3 -17
- package/dist/{messages-BtxaN-xx.mjs → messages-12_eyAo-.mjs} +3 -17
- package/dist/{chunks/messages-LxumrNue2.mjs → messages-B3Yhiycb2.mjs} +3 -17
- package/dist/{chunks/messages-Cqc-6rfh2.mjs → messages-B4lhNMKm2.mjs} +3 -17
- package/dist/{chunks/messages-B0ffBqzr.mjs → messages-BOE2mzCj2.mjs} +3 -17
- package/dist/{chunks/messages-BaPZuLjN.mjs → messages-BPL7riv-.mjs} +3 -17
- package/dist/{messages-DD5pW0zJ.mjs → messages-BYQ769S5.mjs} +3 -17
- package/dist/{chunks/messages-C11byid72.mjs → messages-B_sKqaeK.mjs} +3 -17
- package/dist/{messages-BmNaAyKS.mjs → messages-Bdk4ocMI.mjs} +3 -17
- package/dist/{chunks/messages-6mikOS4D2.mjs → messages-BeI2HORe2.mjs} +3 -17
- package/dist/{chunks/messages-u2yxkNTE2.mjs → messages-Bug6Du35.mjs} +3 -17
- package/dist/{messages-eTourT12.mjs → messages-C2veeQpU.mjs} +3 -17
- package/dist/{messages-BokEflKa.mjs → messages-C5Uufygq.mjs} +3 -17
- package/dist/{chunks/messages-BPog17132.mjs → messages-C8f1I5EQ2.mjs} +3 -17
- package/dist/{chunks/messages-ID1PHnMv.mjs → messages-CBPiFbEf2.mjs} +3 -17
- package/dist/{messages-DZEcrbmH.mjs → messages-CByBLxWk.mjs} +3 -17
- package/dist/{chunks/messages-BgVEGd4c.mjs → messages-CD8K1g_t2.mjs} +3 -17
- package/dist/{messages-Dkg99bfr2.mjs → messages-CEEzfqMO2.mjs} +3 -17
- package/dist/{messages-DV9e1DW7.mjs → messages-CNNcKuGH.mjs} +3 -17
- package/dist/{messages-C30Vz-UZ2.mjs → messages-CSl0Wla62.mjs} +3 -17
- package/dist/{messages-fLi0P2dP.mjs → messages-CUzBNjnc.mjs} +3 -17
- package/dist/{chunks/messages-DJA6fb_P2.mjs → messages-CWEL1WDy2.mjs} +3 -17
- package/dist/{messages-BcFQFcJ92.mjs → messages-C_HmWyXc2.mjs} +3 -17
- package/dist/{chunks/messages-CpzO7KRA.mjs → messages-Cb3wXGnc.mjs} +3 -17
- package/dist/{messages-C5XPUD9T2.mjs → messages-Cd23UgLV2.mjs} +3 -17
- package/dist/{chunks/messages-DSjXen8E.mjs → messages-Cg1CF4pw.mjs} +3 -17
- package/dist/{messages-i4S6q64n2.mjs → messages-CgEDVri-2.mjs} +3 -17
- package/dist/{messages-CHJ5SOZI.mjs → messages-ChTWmxS8.mjs} +3 -17
- package/dist/{messages-BVKZK-3t.mjs → messages-Cho2VTAX.mjs} +3 -17
- package/dist/{chunks/messages-d0Ky6QjR.mjs → messages-CkySRhtd2.mjs} +3 -17
- package/dist/{chunks/messages-C1OqT_nL.mjs → messages-Clsh86WQ.mjs} +3 -17
- package/dist/{chunks/messages-BrFl5773.mjs → messages-CsiGzUSP2.mjs} +3 -17
- package/dist/{messages-BKjqW08U.mjs → messages-Cv-DKlZd.mjs} +3 -17
- package/dist/{messages-BGsDZTQp2.mjs → messages-CvvbLyTy2.mjs} +3 -17
- package/dist/{chunks/messages-DA7Zk-Cy.mjs → messages-CwCEcbWG.mjs} +3 -17
- package/dist/{chunks/messages-DQ5AyNCU.mjs → messages-D38h5XlF.mjs} +3 -17
- package/dist/{chunks/messages-DC7TX-YT.mjs → messages-D7juvhHp.mjs} +3 -17
- package/dist/{chunks/messages-BdnSVKOw.mjs → messages-D8WvwU42.mjs} +3 -17
- package/dist/{chunks/messages-Df87zXXG.mjs → messages-DACg1XAu.mjs} +3 -17
- package/dist/{messages-BBq0M604.mjs → messages-DIKCwGog.mjs} +3 -17
- package/dist/{messages-Ccd587Yn.mjs → messages-DJU4YLij.mjs} +3 -17
- package/dist/{chunks/messages-Dm4YVlrm.mjs → messages-DQN1y6E9.mjs} +3 -17
- package/dist/{messages-CqkRG9mH.mjs → messages-DRU_IgoW.mjs} +3 -17
- package/dist/{chunks/messages-DT7fRpCy.mjs → messages-DbZsJAff.mjs} +3 -17
- package/dist/{messages-upqrRZQH2.mjs → messages-Dg2CDXZi2.mjs} +3 -17
- package/dist/{messages-DJKLtW7u.mjs → messages-Dj79y02X.mjs} +3 -17
- package/dist/{chunks/messages-Ct7AMBS82.mjs → messages-DjWfVYHS2.mjs} +3 -17
- package/dist/{chunks/messages-B2pW6jO_.mjs → messages-DkvQ-6HC2.mjs} +3 -17
- package/dist/{chunks/messages-ZJ0b1C3a.mjs → messages-DnhEzmXJ2.mjs} +3 -17
- package/dist/{chunks/messages-BgsPQXfP.mjs → messages-DqJTZbwt.mjs} +3 -17
- package/dist/{chunks/messages-DUDgFEEe2.mjs → messages-Dq_v7slw2.mjs} +3 -17
- package/dist/{chunks/messages-CyNsByCY.mjs → messages-En8LDjUB.mjs} +3 -17
- package/dist/{chunks/messages-FHrCEJmY2.mjs → messages-JK9Okzsy2.mjs} +3 -17
- package/dist/{messages-DnatBKPm.mjs → messages-KSxF8eib.mjs} +3 -17
- package/dist/{chunks/messages-DD7BI6BK.mjs → messages-KbYSpNrE.mjs} +3 -17
- package/dist/{messages-BvgXeMSL2.mjs → messages-KqWQKmIu2.mjs} +3 -17
- package/dist/{messages-BSe3QDnQ.mjs → messages-PvMdmlxI.mjs} +3 -17
- package/dist/{chunks/messages-DJkIeapn.mjs → messages-So3SHdIc2.mjs} +3 -17
- package/dist/{messages-BywbKcPC.mjs → messages-X80Nh0ib.mjs} +3 -17
- package/dist/{messages-DOTJ2NvJ.mjs → messages-hrSlVSHp.mjs} +3 -17
- package/dist/{messages-DJT4Bt_02.mjs → messages-mipkPgwQ2.mjs} +3 -17
- package/dist/{messages-xEI8gEDK.mjs → messages-nOe1gJYu.mjs} +3 -17
- package/dist/{messages-Bk984gRE2.mjs → messages-rbox5gSb2.mjs} +3 -17
- package/dist/{chunks/messages-CgRvtOEY.mjs → messages-uCsQjz7M.mjs} +3 -17
- package/dist/{chunks/messages-BbdNugdi.mjs → messages-vcoib5Ga.mjs} +3 -17
- package/dist/{chunks/messages-CvfKofOP.mjs → messages-vptt-pVF.mjs} +3 -17
- package/dist/{chunks/messages-BkCjgGxc.mjs → messages-x353UCBI.mjs} +3 -17
- package/dist/react.mjs +3 -3
- package/dist/tools.mjs +3 -3
- package/dist/vendor.LICENSE.txt +1622 -182
- package/package.json +15 -2
- package/src/components/blocks.ts +26 -1
- package/src/components/i18n/locales/am/messages.json +3 -17
- package/src/components/i18n/locales/ar/messages.json +3 -17
- package/src/components/i18n/locales/az/messages.json +3 -17
- package/src/components/i18n/locales/bg/messages.json +3 -17
- package/src/components/i18n/locales/bn/messages.json +3 -17
- package/src/components/i18n/locales/bs/messages.json +3 -17
- package/src/components/i18n/locales/cs/messages.json +3 -17
- package/src/components/i18n/locales/da/messages.json +3 -17
- package/src/components/i18n/locales/de/messages.json +3 -17
- package/src/components/i18n/locales/dv/messages.json +3 -17
- package/src/components/i18n/locales/el/messages.json +3 -17
- package/src/components/i18n/locales/en/messages.json +15 -17
- package/src/components/i18n/locales/es/messages.json +3 -17
- package/src/components/i18n/locales/et/messages.json +3 -17
- package/src/components/i18n/locales/fa/messages.json +3 -17
- package/src/components/i18n/locales/fi/messages.json +3 -17
- package/src/components/i18n/locales/fil/messages.json +3 -17
- package/src/components/i18n/locales/fr/messages.json +3 -17
- package/src/components/i18n/locales/gu/messages.json +3 -17
- package/src/components/i18n/locales/he/messages.json +3 -17
- package/src/components/i18n/locales/hi/messages.json +3 -17
- package/src/components/i18n/locales/hr/messages.json +3 -17
- package/src/components/i18n/locales/hu/messages.json +3 -17
- package/src/components/i18n/locales/hy/messages.json +3 -17
- package/src/components/i18n/locales/id/messages.json +3 -17
- package/src/components/i18n/locales/it/messages.json +3 -17
- package/src/components/i18n/locales/ja/messages.json +3 -17
- package/src/components/i18n/locales/ka/messages.json +3 -17
- package/src/components/i18n/locales/km/messages.json +3 -17
- package/src/components/i18n/locales/kn/messages.json +3 -17
- package/src/components/i18n/locales/ko/messages.json +3 -17
- package/src/components/i18n/locales/ku/messages.json +3 -17
- package/src/components/i18n/locales/lo/messages.json +3 -17
- package/src/components/i18n/locales/lt/messages.json +3 -17
- package/src/components/i18n/locales/lv/messages.json +3 -17
- package/src/components/i18n/locales/mk/messages.json +3 -17
- package/src/components/i18n/locales/ml/messages.json +3 -17
- package/src/components/i18n/locales/mn/messages.json +3 -17
- package/src/components/i18n/locales/mr/messages.json +3 -17
- package/src/components/i18n/locales/ms/messages.json +3 -17
- package/src/components/i18n/locales/my/messages.json +3 -17
- package/src/components/i18n/locales/ne/messages.json +3 -17
- package/src/components/i18n/locales/nl/messages.json +3 -17
- package/src/components/i18n/locales/no/messages.json +3 -17
- package/src/components/i18n/locales/pa/messages.json +3 -17
- package/src/components/i18n/locales/pl/messages.json +3 -17
- package/src/components/i18n/locales/ps/messages.json +3 -17
- package/src/components/i18n/locales/pt/messages.json +3 -17
- package/src/components/i18n/locales/ro/messages.json +3 -17
- package/src/components/i18n/locales/ru/messages.json +3 -17
- package/src/components/i18n/locales/sd/messages.json +3 -17
- package/src/components/i18n/locales/si/messages.json +3 -17
- package/src/components/i18n/locales/sk/messages.json +3 -17
- package/src/components/i18n/locales/sl/messages.json +3 -17
- package/src/components/i18n/locales/sq/messages.json +3 -17
- package/src/components/i18n/locales/sr/messages.json +3 -17
- package/src/components/i18n/locales/sv/messages.json +3 -17
- package/src/components/i18n/locales/sw/messages.json +3 -17
- package/src/components/i18n/locales/ta/messages.json +3 -17
- package/src/components/i18n/locales/te/messages.json +3 -17
- package/src/components/i18n/locales/th/messages.json +3 -17
- package/src/components/i18n/locales/tr/messages.json +3 -17
- package/src/components/i18n/locales/ug/messages.json +3 -17
- package/src/components/i18n/locales/uk/messages.json +3 -17
- package/src/components/i18n/locales/ur/messages.json +3 -17
- package/src/components/i18n/locales/vi/messages.json +3 -17
- package/src/components/i18n/locales/yi/messages.json +3 -17
- package/src/components/i18n/locales/zh/messages.json +3 -17
- package/src/components/icons/index.ts +30 -56
- package/src/components/inline-tools/inline-tool-code.ts +399 -0
- package/src/components/modules/api/blocks.ts +17 -0
- package/src/components/modules/api/tools.ts +0 -19
- package/src/components/modules/blockEvents/composers/blockSelectionKeys.ts +20 -3
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +5 -5
- package/src/components/modules/blockManager/blockManager.ts +0 -11
- package/src/components/modules/blockManager/event-binder.ts +1 -12
- package/src/components/modules/paste/handlers/html-handler.ts +13 -10
- package/src/components/modules/paste/handlers/index.ts +1 -0
- package/src/components/modules/paste/index.ts +6 -0
- package/src/components/modules/themeManager.ts +1 -3
- package/src/components/modules/toolbar/blockSettings.ts +1 -0
- package/src/components/modules/toolbar/inline/index.ts +3 -0
- package/src/components/modules/uiControllers/controllers/keyboard.ts +0 -29
- package/src/components/modules/uiControllers/controllers/selection.ts +2 -14
- package/src/components/ui/toolbox.ts +1 -0
- package/src/components/utils/popover/popover-position.ts +2 -4
- package/src/markdown/index.ts +63 -0
- package/src/markdown/markdown-handler.ts +110 -0
- package/src/markdown/mdast-to-blocks.ts +418 -0
- package/src/markdown/phrasing-to-html.ts +60 -0
- package/src/markdown/types.ts +42 -0
- package/src/styles/main.css +0 -1139
- package/src/tools/callout/index.ts +24 -0
- package/src/tools/code/code-keyboard.ts +135 -0
- package/src/tools/code/constants.ts +73 -0
- package/src/tools/code/dom-builder.ts +146 -0
- package/src/tools/code/index.ts +322 -0
- package/src/tools/code/katex-loader.ts +50 -0
- package/src/tools/code/language-picker.ts +241 -0
- package/src/tools/divider/index.ts +9 -1
- package/src/tools/index.ts +4 -2
- package/src/tools/list/block-operations.ts +3 -1
- package/src/tools/list/depth-validator.ts +4 -7
- package/src/tools/list/dom-builder.ts +5 -3
- package/src/tools/list/index.ts +21 -3
- package/src/tools/list/list-helpers.ts +9 -2
- package/src/tools/list/list-keyboard.ts +56 -14
- package/src/tools/list/list-lifecycle.ts +3 -1
- package/src/tools/list/marker-calculator.ts +37 -0
- package/src/tools/list/ordered-marker-manager.ts +4 -2
- package/src/tools/table/index.ts +2 -2
- package/src/tools/table/table-cell-clipboard.ts +1 -1
- package/types/api/tools.d.ts +0 -18
- package/types/markdown.d.ts +2 -0
- package/types/tools/code.d.ts +11 -0
- package/src/tools/database/database-backend-sync.ts +0 -101
- package/src/tools/database/database-board-view.ts +0 -301
- package/src/tools/database/database-card-drag.ts +0 -306
- package/src/tools/database/database-card-drawer.ts +0 -546
- package/src/tools/database/database-column-controls.ts +0 -46
- package/src/tools/database/database-column-drag.ts +0 -262
- package/src/tools/database/database-keyboard.ts +0 -35
- package/src/tools/database/database-list-row-drag.ts +0 -245
- package/src/tools/database/database-list-view.ts +0 -333
- package/src/tools/database/database-model.ts +0 -246
- package/src/tools/database/database-property-type-popover.ts +0 -108
- package/src/tools/database/database-tab-bar.ts +0 -532
- package/src/tools/database/database-view-popover.ts +0 -109
- package/src/tools/database/database-view-renderer.ts +0 -25
- package/src/tools/database/index.ts +0 -948
- package/src/tools/database/types.ts +0 -144
- /package/dist/chunks/{am-CHDDMHkd.mjs → am-CS-JjQ0N.mjs} +0 -0
- /package/dist/chunks/{ar-DoqfNqut.mjs → ar-Dt4XzR5U.mjs} +0 -0
- /package/dist/chunks/{az-C34P9iEa.mjs → az-CaDTXby8.mjs} +0 -0
- /package/dist/chunks/{bg-jroXLY8Y.mjs → bg-D1pLog-R.mjs} +0 -0
- /package/dist/chunks/{bn-BRI-WqxY.mjs → bn-Db_ae60m.mjs} +0 -0
- /package/dist/chunks/{bs-CCGUpNHu.mjs → bs-DJTg1R9e.mjs} +0 -0
- /package/dist/chunks/{cs-D5qZOGuc.mjs → cs-_Gc21gSL.mjs} +0 -0
- /package/dist/chunks/{da-DrJ7W37K.mjs → da-xDB8uhCd.mjs} +0 -0
- /package/dist/chunks/{de-BW6-kp2c.mjs → de-B6gVjh1Z.mjs} +0 -0
- /package/dist/chunks/{el-C-Vc_Otu.mjs → el-ClbRSnOs.mjs} +0 -0
- /package/dist/chunks/{es-B6fI5K9i.mjs → es-CuY9rnLK.mjs} +0 -0
- /package/dist/chunks/{et-BhVlZ-Yz.mjs → et-BLu5lDVc.mjs} +0 -0
- /package/dist/chunks/{fa-D55Ijdqa.mjs → fa-P3gnrZH8.mjs} +0 -0
- /package/dist/chunks/{fi-jNLjhKUQ.mjs → fi-B8PVHLjq.mjs} +0 -0
- /package/dist/chunks/{fil-DYd0T5aX.mjs → fil-B9JII5iF.mjs} +0 -0
- /package/dist/chunks/{fr-yxy5xWw_.mjs → fr-BWLDZdcc.mjs} +0 -0
- /package/dist/chunks/{gu-CcY_LJe7.mjs → gu-BH3R_s4c.mjs} +0 -0
- /package/dist/chunks/{he-DL9s7wNw.mjs → he-CCmeCVR_.mjs} +0 -0
- /package/dist/chunks/{hi-C8eGXgw5.mjs → hi-BBav00DN.mjs} +0 -0
- /package/dist/chunks/{hr-DLpybOhU.mjs → hr-B5ZX0r9G.mjs} +0 -0
- /package/dist/chunks/{hu-BkT0gT00.mjs → hu-1jgDa3YU.mjs} +0 -0
- /package/dist/chunks/{hy-CVFDCp2S.mjs → hy-LX4Kp2PE.mjs} +0 -0
- /package/dist/chunks/{id-0P4W9Az0.mjs → id-CcG40D1H.mjs} +0 -0
- /package/dist/chunks/{it-mLY6_uoW.mjs → it-Cb8_K72W.mjs} +0 -0
- /package/dist/chunks/{ja-7RkeRNWG.mjs → ja-ipCH91mv.mjs} +0 -0
- /package/dist/chunks/{ka-C7Lx-Qsh.mjs → ka-BRvREIgq.mjs} +0 -0
- /package/dist/chunks/{km-Q8udaraH.mjs → km-BJwVw7Fg.mjs} +0 -0
- /package/dist/chunks/{kn-BiETM-iq.mjs → kn-BPgUazCC.mjs} +0 -0
- /package/dist/chunks/{ko-tiB80pF1.mjs → ko-CQLzxe7k.mjs} +0 -0
- /package/dist/chunks/{ku-CY-OABkR.mjs → ku-BHhHu8Iz.mjs} +0 -0
- /package/dist/chunks/{lo-CTBhEnyk.mjs → lo-DsTgYblY.mjs} +0 -0
- /package/dist/chunks/{lt-BHKHEtqK.mjs → lt-CDzHJm71.mjs} +0 -0
- /package/dist/chunks/{lv-DWxgtfUg.mjs → lv-MLLIAnIX.mjs} +0 -0
- /package/dist/chunks/{mk-BjookGdx.mjs → mk-DQdmUquZ.mjs} +0 -0
- /package/dist/chunks/{ml-L-NnZcp9.mjs → ml-DqehZnra.mjs} +0 -0
- /package/dist/chunks/{mn-OMWi7Hl_.mjs → mn-4cFkKFjW.mjs} +0 -0
- /package/dist/chunks/{mr-B6JPzITo.mjs → mr-DWiztOP4.mjs} +0 -0
- /package/dist/chunks/{ms-CG3S-sPB.mjs → ms-BSz-iSnc.mjs} +0 -0
- /package/dist/chunks/{my-BLAmGfhT.mjs → my-DbtbM1MW.mjs} +0 -0
- /package/dist/chunks/{native-BPcABu9z.mjs → native-CzYG0YgY.mjs} +0 -0
- /package/dist/chunks/{ne-D1JHLfYw.mjs → ne-CqALWw_f.mjs} +0 -0
- /package/dist/chunks/{nl-Ca7Q8FnY.mjs → nl-D_ra6RvH.mjs} +0 -0
- /package/dist/chunks/{no-Coxcohcz.mjs → no-Cg_kz_jl.mjs} +0 -0
- /package/dist/chunks/{pa-CCaXqpaI.mjs → pa-NLAsNqwY.mjs} +0 -0
- /package/dist/chunks/{pl-Cl_fAZ84.mjs → pl-NHKp4YDg.mjs} +0 -0
- /package/dist/chunks/{ps-WD5qGAWy.mjs → ps-D1zEqNeg.mjs} +0 -0
- /package/dist/chunks/{pt-C4zvLfvq.mjs → pt-DBtqbUEB.mjs} +0 -0
- /package/dist/chunks/{ro-DbefHcmM.mjs → ro-lqr63ai5.mjs} +0 -0
- /package/dist/chunks/{ru-uU1J14jd.mjs → ru-BycNnDyN.mjs} +0 -0
- /package/dist/chunks/{sd-DKu368Ip.mjs → sd-DpHpIN9Z.mjs} +0 -0
- /package/dist/chunks/{si-BsJCiPkZ.mjs → si-BwiwaC7N.mjs} +0 -0
- /package/dist/chunks/{sk-CD-a3SN6.mjs → sk-CqRHT2Gp.mjs} +0 -0
- /package/dist/chunks/{sl-CXhrPJe_.mjs → sl-DA348uQ_.mjs} +0 -0
- /package/dist/chunks/{sq-CTctCoFQ.mjs → sq-D7JNgve1.mjs} +0 -0
- /package/dist/chunks/{sr-BZkhBwXj.mjs → sr-D8RK6Kwp.mjs} +0 -0
- /package/dist/chunks/{sv-NmRZb_xi.mjs → sv-dwgT67ZG.mjs} +0 -0
- /package/dist/chunks/{sw-Be5ik3H6.mjs → sw-ZRRJnkem.mjs} +0 -0
- /package/dist/chunks/{ta-DsXh6neL.mjs → ta-5x4L5Krl.mjs} +0 -0
- /package/dist/chunks/{te-CwpCbM8M.mjs → te-BZpEimwA.mjs} +0 -0
- /package/dist/chunks/{th-CcZ15OLk.mjs → th-Bhr-33kv.mjs} +0 -0
- /package/dist/chunks/{tr-q3bTgvhW.mjs → tr-6tSNKGNB.mjs} +0 -0
- /package/dist/chunks/{tw-DmW6-pCY.mjs → tw-CqxBf-1Y.mjs} +0 -0
- /package/dist/chunks/{ug-919EhLsL.mjs → ug-_e-jvr2b.mjs} +0 -0
- /package/dist/chunks/{uk-aNMEzd0Y.mjs → uk-DooSc2Ja.mjs} +0 -0
- /package/dist/chunks/{ur-BwQI77sh.mjs → ur-rb-krkIO.mjs} +0 -0
- /package/dist/chunks/{vi-Dxq806-F.mjs → vi-CQkLn2AQ.mjs} +0 -0
- /package/dist/chunks/{zh-BcHuy1Ti.mjs → zh-CXQ40Q2_.mjs} +0 -0
|
@@ -78,21 +78,6 @@ export class KeyboardController extends Controller {
|
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const target = event.target;
|
|
82
|
-
|
|
83
|
-
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Skip events from nested editors
|
|
88
|
-
if (target instanceof Element) {
|
|
89
|
-
const closestEditor = target.closest('[data-blok-testid="blok-editor"]');
|
|
90
|
-
|
|
91
|
-
if (closestEditor !== null && closestEditor !== this.Blok.UI.nodes.wrapper) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
81
|
if (KEYS_REQUIRING_CARET_CAPTURE.has(event.key)) {
|
|
97
82
|
this.Blok.YjsManager.markCaretBeforeChange();
|
|
98
83
|
}
|
|
@@ -104,20 +89,6 @@ export class KeyboardController extends Controller {
|
|
|
104
89
|
* @param event - keyboard event
|
|
105
90
|
*/
|
|
106
91
|
private handleKeydown(event: KeyboardEvent): void {
|
|
107
|
-
const target = event.target;
|
|
108
|
-
|
|
109
|
-
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (target instanceof Element) {
|
|
114
|
-
const closestEditor = target.closest('[data-blok-testid="blok-editor"]');
|
|
115
|
-
|
|
116
|
-
if (closestEditor !== null && closestEditor !== this.Blok.UI.nodes.wrapper) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
92
|
const key = event.key ?? '';
|
|
122
93
|
|
|
123
94
|
switch (key) {
|
|
@@ -167,22 +167,10 @@ export class SelectionController extends Controller {
|
|
|
167
167
|
* @returns true if current block should be updated
|
|
168
168
|
*/
|
|
169
169
|
private shouldUpdateCurrentBlock(): boolean {
|
|
170
|
-
const focusedElement = Selection.anchorElement;
|
|
171
|
-
|
|
172
|
-
if (!focusedElement || !this.wrapperElement) {
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
170
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
171
|
+
* Always update current block when focus moves to a different block.
|
|
172
|
+
* This handles Tab key navigation, programmatic focus, and accessibility tools.
|
|
179
173
|
*/
|
|
180
|
-
const closestEditor = focusedElement.closest('[data-blok-testid="blok-editor"]');
|
|
181
|
-
|
|
182
|
-
if (closestEditor !== null && closestEditor !== this.wrapperElement) {
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
174
|
return true;
|
|
187
175
|
}
|
|
188
176
|
}
|
|
@@ -411,6 +411,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
411
411
|
const PopoverClass = isMobileScreen() ? PopoverMobile : PopoverDesktop;
|
|
412
412
|
|
|
413
413
|
this.popover = new PopoverClass({
|
|
414
|
+
scopeElement: this.api.ui.nodes.redactor,
|
|
414
415
|
trigger: this.triggerElement || this.nodes.toolbox,
|
|
415
416
|
leftAlignElement: this.leftAlignElement,
|
|
416
417
|
messages: {
|
|
@@ -32,9 +32,7 @@ export interface ResolvedPosition {
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Determines whether the popover should flip to the alternate side.
|
|
35
|
-
* Returns true
|
|
36
|
-
* When neither side fits, stays on the preferred side so the popover remains adjacent
|
|
37
|
-
* to the anchor instead of getting clamped to a distant boundary edge.
|
|
35
|
+
* Returns true when the popover doesn't fit on the preferred side and the alternate side has more (or equal) space.
|
|
38
36
|
*/
|
|
39
37
|
function shouldFlip(popoverDimension: number, spaceOnPreferred: number, spaceOnAlternate: number): boolean {
|
|
40
38
|
if (popoverDimension <= spaceOnPreferred) {
|
|
@@ -45,7 +43,7 @@ function shouldFlip(popoverDimension: number, spaceOnPreferred: number, spaceOnA
|
|
|
45
43
|
return true;
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
return
|
|
46
|
+
return spaceOnAlternate > spaceOnPreferred;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
/**
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
2
|
+
import type { Extension as MdastExtension } from 'mdast-util-from-markdown';
|
|
3
|
+
import { gfm } from 'micromark-extension-gfm';
|
|
4
|
+
import { gfmFromMarkdown } from 'mdast-util-gfm';
|
|
5
|
+
import type { Extension as MicromarkExtension } from 'micromark-util-types';
|
|
6
|
+
import type { OutputBlockData } from '../../types/data-formats/output-data';
|
|
7
|
+
import type { MarkdownImportConfig } from './types';
|
|
8
|
+
import { mdastToBlocks } from './mdast-to-blocks';
|
|
9
|
+
|
|
10
|
+
export type { MarkdownImportConfig, ToolMapEntry } from './types';
|
|
11
|
+
|
|
12
|
+
const MATH_SIGNAL = /\$\$[\s\S]+?\$\$|(?<!\$)\$(?!\$)(?=\S)[^$]+(?<=\S)\$(?!\$)/;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Lazily load math micromark/mdast extensions only when needed.
|
|
16
|
+
*/
|
|
17
|
+
async function loadMathExtensions(): Promise<{
|
|
18
|
+
mathSyntax: MicromarkExtension;
|
|
19
|
+
mathFromMarkdown: MdastExtension;
|
|
20
|
+
}> {
|
|
21
|
+
const [{ math }, { mathFromMarkdown }] = await Promise.all([
|
|
22
|
+
import('micromark-extension-math'),
|
|
23
|
+
import('mdast-util-math'),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
return { mathSyntax: math(), mathFromMarkdown: mathFromMarkdown() };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Convert a Markdown string to an array of Blok OutputBlockData.
|
|
31
|
+
*
|
|
32
|
+
* @param md - Markdown source string
|
|
33
|
+
* @param config - Optional configuration for tool mapping, GFM, and extensions
|
|
34
|
+
* @returns Array of OutputBlockData ready for `blok.blocks.render()` or `blok.blocks.insertMany()`
|
|
35
|
+
*/
|
|
36
|
+
export async function markdownToBlocks(md: string, config: MarkdownImportConfig = {}): Promise<OutputBlockData[]> {
|
|
37
|
+
const enableGfm = config.gfm !== false;
|
|
38
|
+
const hasMath = MATH_SIGNAL.test(md);
|
|
39
|
+
|
|
40
|
+
const extensions = [
|
|
41
|
+
...(enableGfm ? [gfm()] : []),
|
|
42
|
+
...(config.extensions ?? []),
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const mdastExtensions = [
|
|
46
|
+
...(enableGfm ? [gfmFromMarkdown()] : []),
|
|
47
|
+
...(config.mdastExtensions ?? []),
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
if (hasMath) {
|
|
51
|
+
const { mathSyntax, mathFromMarkdown } = await loadMathExtensions();
|
|
52
|
+
|
|
53
|
+
extensions.push(mathSyntax);
|
|
54
|
+
mdastExtensions.push(mathFromMarkdown);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const tree = fromMarkdown(md, {
|
|
58
|
+
extensions,
|
|
59
|
+
mdastExtensions,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return mdastToBlocks(tree, config);
|
|
63
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { BlockToolData } from '../../types';
|
|
2
|
+
import type { BlokModules } from '../types-internal/blok-modules';
|
|
3
|
+
import type { SanitizerConfigBuilder } from '../components/modules/paste/sanitizer-config';
|
|
4
|
+
import type { ToolRegistry } from '../components/modules/paste/tool-registry';
|
|
5
|
+
import type { HandlerContext } from '../components/modules/paste/types';
|
|
6
|
+
import type { PasteHandler } from '../components/modules/paste/handlers/base';
|
|
7
|
+
import { BasePasteHandler } from '../components/modules/paste/handlers/base';
|
|
8
|
+
import { Block } from '../components/block';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Patterns that indicate text is likely Markdown rather than plain text.
|
|
12
|
+
* Each must be unlikely to appear in normal prose.
|
|
13
|
+
*/
|
|
14
|
+
const MARKDOWN_SIGNALS: RegExp[] = [
|
|
15
|
+
/^#{1,6}\s/m, // ATX headings: # Heading
|
|
16
|
+
/^```/m, // Fenced code blocks
|
|
17
|
+
/\|\s*---/, // GFM table separator: | --- |
|
|
18
|
+
/^- \[[ x]\]/m, // Task list items: - [ ] or - [x]
|
|
19
|
+
/\[.+?\]\(.+?\)/, // Markdown links: [text](url)
|
|
20
|
+
/\*\*.+?\*\*/, // Bold: **text**
|
|
21
|
+
/!\[/, // Image: ![
|
|
22
|
+
/\$\$[\s\S]+?\$\$/, // Block math: $$...$$
|
|
23
|
+
/(?<!\$)\$(?!\$)(?=\S)[^$]+(?<=\S)\$(?!\$)/, // Inline math: $...$
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if a plain-text string contains strong Markdown signals.
|
|
28
|
+
*/
|
|
29
|
+
export function hasMarkdownSignals(text: string): boolean {
|
|
30
|
+
if (!text) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return MARKDOWN_SIGNALS.some((pattern) => pattern.test(text));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Paste handler that detects and converts Markdown text.
|
|
39
|
+
* Priority 30: between TextHandler (10) and HtmlHandler (40).
|
|
40
|
+
* Lazy-loads the converter on first use.
|
|
41
|
+
*
|
|
42
|
+
* Uses BlockManager.insertMany() to insert converted blocks directly,
|
|
43
|
+
* preserving all block data (list depth, table cells, etc.) that
|
|
44
|
+
* would be lost if mapped through the DOM-based paste pipeline.
|
|
45
|
+
*/
|
|
46
|
+
export class MarkdownHandler extends BasePasteHandler implements PasteHandler {
|
|
47
|
+
constructor(
|
|
48
|
+
Blok: BlokModules,
|
|
49
|
+
toolRegistry: ToolRegistry,
|
|
50
|
+
sanitizerBuilder: SanitizerConfigBuilder
|
|
51
|
+
) {
|
|
52
|
+
super(Blok, toolRegistry, sanitizerBuilder);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
canHandle(data: unknown): number {
|
|
56
|
+
if (typeof data !== 'string' || !data.trim()) {
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return hasMarkdownSignals(data) ? 30 : 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async handle(data: unknown, context: HandlerContext): Promise<boolean> {
|
|
64
|
+
if (typeof data !== 'string') {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { markdownToBlocks } = await import('./index');
|
|
69
|
+
const outputBlocks = await markdownToBlocks(data);
|
|
70
|
+
|
|
71
|
+
if (!outputBlocks.length) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { BlockManager, Caret } = this.Blok;
|
|
76
|
+
|
|
77
|
+
// Replace empty default block if present
|
|
78
|
+
const currentBlock = BlockManager.currentBlock;
|
|
79
|
+
const shouldReplace = context.canReplaceCurrentBlock && currentBlock !== undefined && currentBlock.isEmpty;
|
|
80
|
+
const insertIndex = shouldReplace
|
|
81
|
+
? BlockManager.currentBlockIndex
|
|
82
|
+
: BlockManager.currentBlockIndex + 1;
|
|
83
|
+
|
|
84
|
+
// Compose Block instances from OutputBlockData
|
|
85
|
+
const blocksToInsert = outputBlocks.map(({ id, type, data: blockData, parent }) =>
|
|
86
|
+
BlockManager.composeBlock({
|
|
87
|
+
id,
|
|
88
|
+
tool: type,
|
|
89
|
+
data: blockData as BlockToolData,
|
|
90
|
+
parentId: parent,
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
BlockManager.insertMany(blocksToInsert, insertIndex);
|
|
95
|
+
|
|
96
|
+
// Remove the replaced empty block
|
|
97
|
+
if (shouldReplace && currentBlock !== undefined) {
|
|
98
|
+
await BlockManager.removeBlock(currentBlock, false);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Set caret to end of last inserted block
|
|
102
|
+
const lastBlock = blocksToInsert[blocksToInsert.length - 1];
|
|
103
|
+
|
|
104
|
+
if (lastBlock instanceof Block) {
|
|
105
|
+
Caret.setToBlock(lastBlock, Caret.positions.END);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import type { Root, Nodes, List, ListItem, PhrasingContent, Table, Blockquote, RootContent } from 'mdast';
|
|
2
|
+
import type { OutputBlockData } from '../../types/data-formats/output-data';
|
|
3
|
+
import type { MarkdownImportConfig } from './types';
|
|
4
|
+
import { phrasingToHtml } from './phrasing-to-html';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates a scoped ID generator. Each call to mdastToBlocks gets a fresh generator.
|
|
8
|
+
*/
|
|
9
|
+
function createIdGenerator(): () => string {
|
|
10
|
+
const prefix = `md-${Date.now().toString(36)}`;
|
|
11
|
+
const state = { counter: 0 };
|
|
12
|
+
|
|
13
|
+
return () => `${prefix}-${(state.counter++).toString(36)}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Convert an mdast tree to an array of Blok OutputBlockData.
|
|
18
|
+
*/
|
|
19
|
+
export function mdastToBlocks(tree: Root, config: MarkdownImportConfig = {}): OutputBlockData[] {
|
|
20
|
+
const generateId = createIdGenerator();
|
|
21
|
+
|
|
22
|
+
return convertNodes(tree.children, config, 0, generateId);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function convertNodes(
|
|
26
|
+
nodes: RootContent[],
|
|
27
|
+
config: MarkdownImportConfig,
|
|
28
|
+
listDepth: number,
|
|
29
|
+
generateId: () => string,
|
|
30
|
+
): OutputBlockData[] {
|
|
31
|
+
const blocks: OutputBlockData[] = [];
|
|
32
|
+
|
|
33
|
+
for (const node of nodes) {
|
|
34
|
+
const result = convertNode(node, config, listDepth, generateId);
|
|
35
|
+
|
|
36
|
+
if (result) {
|
|
37
|
+
blocks.push(...result);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return blocks;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function convertNode(
|
|
45
|
+
node: RootContent,
|
|
46
|
+
config: MarkdownImportConfig,
|
|
47
|
+
listDepth: number,
|
|
48
|
+
generateId: () => string,
|
|
49
|
+
): OutputBlockData[] | null {
|
|
50
|
+
// 1. Check toolMap first
|
|
51
|
+
if (config.toolMap?.[node.type]) {
|
|
52
|
+
return handleToolMap(node, config, generateId);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. Built-in handlers
|
|
56
|
+
const builtInResult = handleBuiltInNode(node, config, listDepth, generateId);
|
|
57
|
+
|
|
58
|
+
if (builtInResult !== undefined) {
|
|
59
|
+
return builtInResult;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 3. onUnknownNode hook
|
|
63
|
+
if (config.onUnknownNode) {
|
|
64
|
+
return tryOnUnknownNode(config.onUnknownNode, node);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 4. Fallback: extract any text content as paragraph
|
|
68
|
+
if ('value' in node && typeof node.value === 'string') {
|
|
69
|
+
return [makeParagraph(escapeHtml(node.value), generateId)];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Handle built-in node types. Returns undefined if node type is not built-in.
|
|
77
|
+
*/
|
|
78
|
+
function handleBuiltInNode(
|
|
79
|
+
node: RootContent,
|
|
80
|
+
config: MarkdownImportConfig,
|
|
81
|
+
listDepth: number,
|
|
82
|
+
generateId: () => string,
|
|
83
|
+
): OutputBlockData[] | null | undefined {
|
|
84
|
+
if (node.type === 'paragraph') {
|
|
85
|
+
return handleParagraph(node.children as Array<{ type: string; value?: string; children?: unknown[] }>, generateId);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (node.type === 'heading') {
|
|
89
|
+
return [makeBlock('header', { text: phrasingToHtml(node.children), level: node.depth }, generateId)];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (node.type === 'thematicBreak') {
|
|
93
|
+
return [makeBlock('divider', {}, generateId)];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (node.type === 'list') {
|
|
97
|
+
return handleList(node, config, listDepth, generateId);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (node.type === 'blockquote') {
|
|
101
|
+
return handleBlockquote(node, generateId);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (node.type === 'table') {
|
|
105
|
+
return handleTable(node, generateId);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (node.type === 'code') {
|
|
109
|
+
return [makeBlock('code', {
|
|
110
|
+
code: node.value,
|
|
111
|
+
language: node.lang ?? 'plain text',
|
|
112
|
+
}, generateId)];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (node.type === 'math') {
|
|
116
|
+
return [makeBlock('code', { code: node.value, language: 'latex' }, generateId)];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (node.type === 'html') {
|
|
120
|
+
return handleFallback(node, config, escapeHtml(node.value), generateId);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
type ParagraphChild = { type: string; value?: string; children?: unknown[] };
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Convert a paragraph's phrasing children to blocks.
|
|
130
|
+
* Splits on inlineMath nodes, emitting each as a latex code block.
|
|
131
|
+
*/
|
|
132
|
+
function handleParagraph(children: ParagraphChild[], generateId: () => string): OutputBlockData[] {
|
|
133
|
+
const hasInlineMath = children.some(c => c.type === 'inlineMath');
|
|
134
|
+
|
|
135
|
+
if (!hasInlineMath) {
|
|
136
|
+
return [makeParagraph(phrasingToHtml(children as PhrasingContent[]), generateId)];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return splitOnInlineMath(children, generateId);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function splitOnInlineMath(children: ParagraphChild[], generateId: () => string): OutputBlockData[] {
|
|
143
|
+
const blocks: OutputBlockData[] = [];
|
|
144
|
+
const segments = groupByInlineMath(children);
|
|
145
|
+
|
|
146
|
+
for (const segment of segments) {
|
|
147
|
+
if (segment.type === 'math') {
|
|
148
|
+
blocks.push(makeBlock('code', { code: segment.value, language: 'latex' }, generateId));
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const text = phrasingToHtml(segment.nodes as PhrasingContent[]).trim();
|
|
153
|
+
|
|
154
|
+
if (text) {
|
|
155
|
+
blocks.push(makeParagraph(text, generateId));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return blocks;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
type MathSegment = { type: 'math'; value: string } | { type: 'text'; nodes: ParagraphChild[] };
|
|
163
|
+
|
|
164
|
+
function groupByInlineMath(children: ParagraphChild[]): MathSegment[] {
|
|
165
|
+
const segments: MathSegment[] = [];
|
|
166
|
+
const textNodes: ParagraphChild[] = [];
|
|
167
|
+
|
|
168
|
+
for (const child of children) {
|
|
169
|
+
if (child.type !== 'inlineMath') {
|
|
170
|
+
textNodes.push(child);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (textNodes.length > 0) {
|
|
175
|
+
segments.push({ type: 'text', nodes: [...textNodes] });
|
|
176
|
+
textNodes.length = 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
segments.push({ type: 'math', value: child.value ?? '' });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (textNodes.length > 0) {
|
|
183
|
+
segments.push({ type: 'text', nodes: textNodes });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return segments;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function tryOnUnknownNode(
|
|
190
|
+
onUnknownNode: (node: Nodes) => OutputBlockData[] | null,
|
|
191
|
+
node: RootContent,
|
|
192
|
+
): OutputBlockData[] | null {
|
|
193
|
+
try {
|
|
194
|
+
return onUnknownNode(node as Nodes);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
console.warn(`markdownToBlocks: onUnknownNode threw for node type "${node.type}"`, e);
|
|
197
|
+
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function handleToolMap(
|
|
203
|
+
node: RootContent,
|
|
204
|
+
config: MarkdownImportConfig,
|
|
205
|
+
generateId: () => string,
|
|
206
|
+
): OutputBlockData[] {
|
|
207
|
+
const toolMap = config.toolMap;
|
|
208
|
+
|
|
209
|
+
if (!toolMap) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const entry = toolMap[node.type];
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const block: OutputBlockData = {
|
|
217
|
+
id: generateId(),
|
|
218
|
+
type: entry.tool,
|
|
219
|
+
data: entry.data(node as Nodes),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
if (entry.children) {
|
|
223
|
+
const childBlocks = entry.children(
|
|
224
|
+
node as Nodes,
|
|
225
|
+
(childNodes) => convertNodes(childNodes as RootContent[], config, 0, generateId),
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return [block, ...childBlocks];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return [block];
|
|
232
|
+
} catch (e) {
|
|
233
|
+
console.warn(`markdownToBlocks: toolMap handler threw for node type "${node.type}"`, e);
|
|
234
|
+
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function handleList(
|
|
240
|
+
list: List,
|
|
241
|
+
config: MarkdownImportConfig,
|
|
242
|
+
depth: number,
|
|
243
|
+
generateId: () => string,
|
|
244
|
+
): OutputBlockData[] {
|
|
245
|
+
const blocks: OutputBlockData[] = [];
|
|
246
|
+
|
|
247
|
+
for (const [index, item] of list.children.entries()) {
|
|
248
|
+
blocks.push(...handleListItem(item, list, config, depth, index, generateId));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return blocks;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function resolveListStyle(isChecklist: boolean, ordered: boolean | null | undefined): string {
|
|
255
|
+
if (isChecklist) {
|
|
256
|
+
return 'checklist';
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return ordered ? 'ordered' : 'unordered';
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function handleListItem(
|
|
263
|
+
item: ListItem,
|
|
264
|
+
list: List,
|
|
265
|
+
config: MarkdownImportConfig,
|
|
266
|
+
depth: number,
|
|
267
|
+
index: number,
|
|
268
|
+
generateId: () => string,
|
|
269
|
+
): OutputBlockData[] {
|
|
270
|
+
const blocks: OutputBlockData[] = [];
|
|
271
|
+
const isChecklist = item.checked !== null && item.checked !== undefined;
|
|
272
|
+
const style = resolveListStyle(isChecklist, list.ordered);
|
|
273
|
+
|
|
274
|
+
// Extract text from the first paragraph child
|
|
275
|
+
const paragraphChild = item.children.find(
|
|
276
|
+
(c): c is Extract<typeof c, { type: 'paragraph' }> => c.type === 'paragraph',
|
|
277
|
+
);
|
|
278
|
+
const text = paragraphChild ? phrasingToHtml(paragraphChild.children) : '';
|
|
279
|
+
|
|
280
|
+
const data: Record<string, unknown> = { text, style, depth };
|
|
281
|
+
|
|
282
|
+
if (isChecklist) {
|
|
283
|
+
data.checked = item.checked;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (list.ordered && index === 0 && list.start !== null && list.start !== undefined && list.start !== 1) {
|
|
287
|
+
data.start = list.start;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
blocks.push(makeBlock('list', data, generateId));
|
|
291
|
+
|
|
292
|
+
// Process nested lists (increase depth)
|
|
293
|
+
for (const child of item.children) {
|
|
294
|
+
if (child.type === 'list') {
|
|
295
|
+
blocks.push(...handleList(child, config, depth + 1, generateId));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return blocks;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function handleBlockquote(bq: Blockquote, generateId: () => string): OutputBlockData[] {
|
|
303
|
+
const parts: string[] = [];
|
|
304
|
+
|
|
305
|
+
for (const child of bq.children) {
|
|
306
|
+
if (child.type === 'paragraph') {
|
|
307
|
+
parts.push(phrasingToHtml(child.children));
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!('children' in child) || !Array.isArray(child.children)) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// For non-paragraph flow content, extract text
|
|
316
|
+
const innerPhrasing = child.children.filter(
|
|
317
|
+
(c): c is PhrasingContent => 'value' in c || 'children' in c,
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
if (innerPhrasing.length > 0) {
|
|
321
|
+
parts.push(phrasingToHtml(innerPhrasing));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return [makeBlock('quote', { text: parts.join('<br>'), size: 'default' }, generateId)];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function handleTable(table: Table, generateId: () => string): OutputBlockData[] {
|
|
329
|
+
const blocks: OutputBlockData[] = [];
|
|
330
|
+
const tableId = generateId();
|
|
331
|
+
const content: Array<Array<{ blocks: string[] }>> = [];
|
|
332
|
+
|
|
333
|
+
for (const row of table.children) {
|
|
334
|
+
const rowContent = processTableRow(row.children, tableId, blocks, generateId);
|
|
335
|
+
|
|
336
|
+
content.push(rowContent);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const tableBlock: OutputBlockData = {
|
|
340
|
+
id: tableId,
|
|
341
|
+
type: 'table',
|
|
342
|
+
data: {
|
|
343
|
+
withHeadings: table.children.length > 1,
|
|
344
|
+
withHeadingColumn: false,
|
|
345
|
+
content,
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Table block first, then cell blocks
|
|
350
|
+
return [tableBlock, ...blocks];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function processTableRow(
|
|
354
|
+
cells: Table['children'][number]['children'],
|
|
355
|
+
tableId: string,
|
|
356
|
+
blocks: OutputBlockData[],
|
|
357
|
+
generateId: () => string,
|
|
358
|
+
): Array<{ blocks: string[] }> {
|
|
359
|
+
const rowContent: Array<{ blocks: string[] }> = [];
|
|
360
|
+
|
|
361
|
+
for (const cell of cells) {
|
|
362
|
+
const cellText = phrasingToHtml(cell.children);
|
|
363
|
+
const cellBlockId = generateId();
|
|
364
|
+
|
|
365
|
+
blocks.push({
|
|
366
|
+
id: cellBlockId,
|
|
367
|
+
type: 'paragraph',
|
|
368
|
+
data: { text: cellText },
|
|
369
|
+
parent: tableId,
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
rowContent.push({ blocks: [cellBlockId] });
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return rowContent;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function handleFallback(
|
|
379
|
+
node: RootContent,
|
|
380
|
+
config: MarkdownImportConfig,
|
|
381
|
+
fallbackText: string,
|
|
382
|
+
generateId: () => string,
|
|
383
|
+
): OutputBlockData[] | null {
|
|
384
|
+
// Try onUnknownNode first for unmapped block types
|
|
385
|
+
if (config.onUnknownNode) {
|
|
386
|
+
const result = tryOnUnknownNode(config.onUnknownNode, node);
|
|
387
|
+
|
|
388
|
+
// null means "skip this node" — respect the caller's decision
|
|
389
|
+
// non-null means the hook handled it
|
|
390
|
+
if (result === null) {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return [makeParagraph(fallbackText, generateId)];
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function makeParagraph(text: string, generateId: () => string): OutputBlockData {
|
|
401
|
+
return makeBlock('paragraph', { text }, generateId);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function makeBlock(type: string, data: Record<string, unknown>, generateId: () => string): OutputBlockData {
|
|
405
|
+
return {
|
|
406
|
+
id: generateId(),
|
|
407
|
+
type,
|
|
408
|
+
data,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function escapeHtml(text: string): string {
|
|
413
|
+
return text
|
|
414
|
+
.replace(/&/g, '&')
|
|
415
|
+
.replace(/</g, '<')
|
|
416
|
+
.replace(/>/g, '>')
|
|
417
|
+
.replace(/"/g, '"');
|
|
418
|
+
}
|