@jackuait/blok 0.4.1-beta.4 → 0.4.1-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/README.md +136 -17
- package/codemod/README.md +16 -0
- package/codemod/migrate-editorjs-to-blok.js +868 -92
- package/codemod/test.js +682 -77
- package/dist/blok.mjs +5 -2
- package/dist/chunks/blok-B5qs7C5l.mjs +12838 -0
- package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
- package/dist/chunks/i18next-loader-CTrK3HzG.mjs +43 -0
- package/dist/{index-XWGz4gev.mjs → chunks/index-DDpzQn-0.mjs} +2 -2
- package/dist/chunks/inline-tool-convert-RBcopmCh.mjs +1988 -0
- package/dist/chunks/messages-2434tVOK.mjs +47 -0
- package/dist/chunks/messages-3DcCwXMF.mjs +47 -0
- package/dist/chunks/messages-4kMwVAKY.mjs +47 -0
- package/dist/chunks/messages-57uL5htT.mjs +47 -0
- package/dist/chunks/messages-76-iJV9Q.mjs +47 -0
- package/dist/chunks/messages-8p86Eyf2.mjs +47 -0
- package/dist/chunks/messages-BBX0p0Pi.mjs +47 -0
- package/dist/chunks/messages-BCm2eudQ.mjs +47 -0
- package/dist/chunks/messages-BFiUomgG.mjs +47 -0
- package/dist/chunks/messages-BIPNHHAV.mjs +47 -0
- package/dist/chunks/messages-BUlwu9mo.mjs +47 -0
- package/dist/chunks/messages-BX-DPa-z.mjs +47 -0
- package/dist/chunks/messages-BextV3Qh.mjs +47 -0
- package/dist/chunks/messages-BiPSFlUG.mjs +47 -0
- package/dist/chunks/messages-BiXe9G-O.mjs +47 -0
- package/dist/chunks/messages-Bl5z_Igo.mjs +47 -0
- package/dist/chunks/messages-BnsE97ku.mjs +47 -0
- package/dist/chunks/messages-BoO8gsVD.mjs +47 -0
- package/dist/chunks/messages-BqWaOGMn.mjs +47 -0
- package/dist/chunks/messages-BqkL2_Ro.mjs +47 -0
- package/dist/chunks/messages-BvCkXKX-.mjs +47 -0
- package/dist/chunks/messages-C6tbPLoj.mjs +47 -0
- package/dist/chunks/messages-CA6T3-gQ.mjs +47 -0
- package/dist/chunks/messages-CFFPFdWP.mjs +47 -0
- package/dist/chunks/messages-CFrKE-TN.mjs +47 -0
- package/dist/chunks/messages-CHz8VlG-.mjs +47 -0
- package/dist/chunks/messages-CLixzySl.mjs +47 -0
- package/dist/chunks/messages-CV7OM_qk.mjs +47 -0
- package/dist/chunks/messages-CXHt3eCC.mjs +47 -0
- package/dist/chunks/messages-CbmsBrB0.mjs +47 -0
- package/dist/chunks/messages-Ceo1KtFx.mjs +47 -0
- package/dist/chunks/messages-Cm0LJLtB.mjs +47 -0
- package/dist/chunks/messages-CmymP_Ar.mjs +47 -0
- package/dist/chunks/messages-D0ohMB5H.mjs +47 -0
- package/dist/chunks/messages-D3GrDwXh.mjs +47 -0
- package/dist/chunks/messages-D3vTzIpL.mjs +47 -0
- package/dist/chunks/messages-D5WeksbV.mjs +47 -0
- package/dist/chunks/messages-DGaab4EP.mjs +47 -0
- package/dist/chunks/messages-DKha57ZU.mjs +47 -0
- package/dist/chunks/messages-DOaujgMW.mjs +47 -0
- package/dist/chunks/messages-DVbPLd_0.mjs +47 -0
- package/dist/chunks/messages-D_FCyfW6.mjs +47 -0
- package/dist/chunks/messages-Dd5iZN3c.mjs +47 -0
- package/dist/chunks/messages-DehM7135.mjs +47 -0
- package/dist/chunks/messages-Dg1OHftD.mjs +47 -0
- package/dist/chunks/messages-Di6Flq-b.mjs +47 -0
- package/dist/chunks/messages-Dqhhex6e.mjs +47 -0
- package/dist/chunks/messages-DueVe0F1.mjs +47 -0
- package/dist/chunks/messages-Dx3eFwI0.mjs +47 -0
- package/dist/chunks/messages-FOtiUoKl.mjs +47 -0
- package/dist/chunks/messages-FTOZNhRD.mjs +47 -0
- package/dist/chunks/messages-IQxGfQIV.mjs +47 -0
- package/dist/chunks/messages-JF2fzCkK.mjs +47 -0
- package/dist/chunks/messages-MOGl7I5v.mjs +47 -0
- package/dist/chunks/messages-QgYhPL-3.mjs +47 -0
- package/dist/chunks/messages-WYWIbQwo.mjs +47 -0
- package/dist/chunks/messages-a6A_LgDv.mjs +47 -0
- package/dist/chunks/messages-bSf31LJi.mjs +47 -0
- package/dist/chunks/messages-diGozhTn.mjs +47 -0
- package/dist/chunks/messages-er-kd-VO.mjs +47 -0
- package/dist/chunks/messages-ez3w5NBn.mjs +47 -0
- package/dist/chunks/messages-f3uXjegd.mjs +47 -0
- package/dist/chunks/messages-ohwI1UGv.mjs +47 -0
- package/dist/chunks/messages-p9BZJaFV.mjs +47 -0
- package/dist/chunks/messages-qIQ4L4rw.mjs +47 -0
- package/dist/chunks/messages-qWkXPggi.mjs +47 -0
- package/dist/chunks/messages-w5foGze_.mjs +47 -0
- package/dist/full.mjs +50 -0
- package/dist/locales.mjs +227 -0
- package/dist/messages-2434tVOK.mjs +47 -0
- package/dist/messages-3DcCwXMF.mjs +47 -0
- package/dist/messages-4kMwVAKY.mjs +47 -0
- package/dist/messages-57uL5htT.mjs +47 -0
- package/dist/messages-76-iJV9Q.mjs +47 -0
- package/dist/messages-8p86Eyf2.mjs +47 -0
- package/dist/messages-BBX0p0Pi.mjs +47 -0
- package/dist/messages-BCm2eudQ.mjs +47 -0
- package/dist/messages-BFiUomgG.mjs +47 -0
- package/dist/messages-BIPNHHAV.mjs +47 -0
- package/dist/messages-BUlwu9mo.mjs +47 -0
- package/dist/messages-BX-DPa-z.mjs +47 -0
- package/dist/messages-BextV3Qh.mjs +47 -0
- package/dist/messages-BiPSFlUG.mjs +47 -0
- package/dist/messages-BiXe9G-O.mjs +47 -0
- package/dist/messages-Bl5z_Igo.mjs +47 -0
- package/dist/messages-BnsE97ku.mjs +47 -0
- package/dist/messages-BoO8gsVD.mjs +47 -0
- package/dist/messages-BqWaOGMn.mjs +47 -0
- package/dist/messages-BqkL2_Ro.mjs +47 -0
- package/dist/messages-BvCkXKX-.mjs +47 -0
- package/dist/messages-C6tbPLoj.mjs +47 -0
- package/dist/messages-CA6T3-gQ.mjs +47 -0
- package/dist/messages-CFFPFdWP.mjs +47 -0
- package/dist/messages-CFrKE-TN.mjs +47 -0
- package/dist/messages-CHz8VlG-.mjs +47 -0
- package/dist/messages-CLixzySl.mjs +47 -0
- package/dist/messages-CV7OM_qk.mjs +47 -0
- package/dist/messages-CXHt3eCC.mjs +47 -0
- package/dist/messages-CbmsBrB0.mjs +47 -0
- package/dist/messages-Ceo1KtFx.mjs +47 -0
- package/dist/messages-Cm0LJLtB.mjs +47 -0
- package/dist/messages-CmymP_Ar.mjs +47 -0
- package/dist/messages-D0ohMB5H.mjs +47 -0
- package/dist/messages-D3GrDwXh.mjs +47 -0
- package/dist/messages-D3vTzIpL.mjs +47 -0
- package/dist/messages-D5WeksbV.mjs +47 -0
- package/dist/messages-DGaab4EP.mjs +47 -0
- package/dist/messages-DKha57ZU.mjs +47 -0
- package/dist/messages-DOaujgMW.mjs +47 -0
- package/dist/messages-DVbPLd_0.mjs +47 -0
- package/dist/messages-D_FCyfW6.mjs +47 -0
- package/dist/messages-Dd5iZN3c.mjs +47 -0
- package/dist/messages-DehM7135.mjs +47 -0
- package/dist/messages-Dg1OHftD.mjs +47 -0
- package/dist/messages-Di6Flq-b.mjs +47 -0
- package/dist/messages-Dqhhex6e.mjs +47 -0
- package/dist/messages-DueVe0F1.mjs +47 -0
- package/dist/messages-Dx3eFwI0.mjs +47 -0
- package/dist/messages-FOtiUoKl.mjs +47 -0
- package/dist/messages-FTOZNhRD.mjs +47 -0
- package/dist/messages-IQxGfQIV.mjs +47 -0
- package/dist/messages-JF2fzCkK.mjs +47 -0
- package/dist/messages-MOGl7I5v.mjs +47 -0
- package/dist/messages-QgYhPL-3.mjs +47 -0
- package/dist/messages-WYWIbQwo.mjs +47 -0
- package/dist/messages-a6A_LgDv.mjs +47 -0
- package/dist/messages-bSf31LJi.mjs +47 -0
- package/dist/messages-diGozhTn.mjs +47 -0
- package/dist/messages-er-kd-VO.mjs +47 -0
- package/dist/messages-ez3w5NBn.mjs +47 -0
- package/dist/messages-f3uXjegd.mjs +47 -0
- package/dist/messages-ohwI1UGv.mjs +47 -0
- package/dist/messages-p9BZJaFV.mjs +47 -0
- package/dist/messages-qIQ4L4rw.mjs +47 -0
- package/dist/messages-qWkXPggi.mjs +47 -0
- package/dist/messages-w5foGze_.mjs +47 -0
- package/dist/tools.mjs +3073 -0
- package/dist/vendor.LICENSE.txt +26 -225
- package/package.json +49 -23
- package/src/blok.ts +267 -0
- package/src/components/__module.ts +139 -0
- package/src/components/block/api.ts +155 -0
- package/src/components/block/index.ts +1427 -0
- package/src/components/block-tunes/block-tune-delete.ts +51 -0
- package/src/components/blocks.ts +338 -0
- package/src/components/constants/data-attributes.ts +342 -0
- package/src/components/constants.ts +76 -0
- package/src/components/core.ts +392 -0
- package/src/components/dom.ts +773 -0
- package/src/components/domIterator.ts +189 -0
- package/src/components/errors/critical.ts +5 -0
- package/src/components/events/BlockChanged.ts +16 -0
- package/src/components/events/BlockHovered.ts +21 -0
- package/src/components/events/BlockSettingsClosed.ts +12 -0
- package/src/components/events/BlockSettingsOpened.ts +12 -0
- package/src/components/events/BlokMobileLayoutToggled.ts +15 -0
- package/src/components/events/FakeCursorAboutToBeToggled.ts +17 -0
- package/src/components/events/FakeCursorHaveBeenSet.ts +17 -0
- package/src/components/events/HistoryStateChanged.ts +19 -0
- package/src/components/events/RedactorDomChanged.ts +14 -0
- package/src/components/events/index.ts +46 -0
- package/src/components/flipper.ts +481 -0
- package/src/components/i18n/i18next-loader.ts +84 -0
- package/src/components/i18n/lightweight-i18n.ts +86 -0
- package/src/components/i18n/locales/TRANSLATION_GUIDELINES.md +113 -0
- package/src/components/i18n/locales/am/messages.json +44 -0
- package/src/components/i18n/locales/ar/messages.json +44 -0
- package/src/components/i18n/locales/az/messages.json +44 -0
- package/src/components/i18n/locales/bg/messages.json +44 -0
- package/src/components/i18n/locales/bn/messages.json +44 -0
- package/src/components/i18n/locales/bs/messages.json +44 -0
- package/src/components/i18n/locales/cs/messages.json +44 -0
- package/src/components/i18n/locales/da/messages.json +44 -0
- package/src/components/i18n/locales/de/messages.json +44 -0
- package/src/components/i18n/locales/dv/messages.json +44 -0
- package/src/components/i18n/locales/el/messages.json +44 -0
- package/src/components/i18n/locales/en/messages.json +44 -0
- package/src/components/i18n/locales/es/messages.json +44 -0
- package/src/components/i18n/locales/et/messages.json +44 -0
- package/src/components/i18n/locales/fa/messages.json +44 -0
- package/src/components/i18n/locales/fi/messages.json +44 -0
- package/src/components/i18n/locales/fil/messages.json +44 -0
- package/src/components/i18n/locales/fr/messages.json +44 -0
- package/src/components/i18n/locales/gu/messages.json +44 -0
- package/src/components/i18n/locales/he/messages.json +44 -0
- package/src/components/i18n/locales/hi/messages.json +44 -0
- package/src/components/i18n/locales/hr/messages.json +44 -0
- package/src/components/i18n/locales/hu/messages.json +44 -0
- package/src/components/i18n/locales/hy/messages.json +44 -0
- package/src/components/i18n/locales/id/messages.json +44 -0
- package/src/components/i18n/locales/index.ts +225 -0
- package/src/components/i18n/locales/it/messages.json +44 -0
- package/src/components/i18n/locales/ja/messages.json +44 -0
- package/src/components/i18n/locales/ka/messages.json +44 -0
- package/src/components/i18n/locales/km/messages.json +44 -0
- package/src/components/i18n/locales/kn/messages.json +44 -0
- package/src/components/i18n/locales/ko/messages.json +44 -0
- package/src/components/i18n/locales/ku/messages.json +44 -0
- package/src/components/i18n/locales/lo/messages.json +44 -0
- package/src/components/i18n/locales/lt/messages.json +44 -0
- package/src/components/i18n/locales/lv/messages.json +44 -0
- package/src/components/i18n/locales/mk/messages.json +44 -0
- package/src/components/i18n/locales/ml/messages.json +44 -0
- package/src/components/i18n/locales/mn/messages.json +44 -0
- package/src/components/i18n/locales/mr/messages.json +44 -0
- package/src/components/i18n/locales/ms/messages.json +44 -0
- package/src/components/i18n/locales/my/messages.json +44 -0
- package/src/components/i18n/locales/ne/messages.json +44 -0
- package/src/components/i18n/locales/nl/messages.json +44 -0
- package/src/components/i18n/locales/no/messages.json +44 -0
- package/src/components/i18n/locales/pa/messages.json +44 -0
- package/src/components/i18n/locales/pl/messages.json +44 -0
- package/src/components/i18n/locales/ps/messages.json +44 -0
- package/src/components/i18n/locales/pt/messages.json +44 -0
- package/src/components/i18n/locales/ro/messages.json +44 -0
- package/src/components/i18n/locales/ru/messages.json +44 -0
- package/src/components/i18n/locales/sd/messages.json +44 -0
- package/src/components/i18n/locales/si/messages.json +44 -0
- package/src/components/i18n/locales/sk/messages.json +44 -0
- package/src/components/i18n/locales/sl/messages.json +44 -0
- package/src/components/i18n/locales/sq/messages.json +44 -0
- package/src/components/i18n/locales/sr/messages.json +44 -0
- package/src/components/i18n/locales/sv/messages.json +44 -0
- package/src/components/i18n/locales/sw/messages.json +44 -0
- package/src/components/i18n/locales/ta/messages.json +44 -0
- package/src/components/i18n/locales/te/messages.json +44 -0
- package/src/components/i18n/locales/th/messages.json +44 -0
- package/src/components/i18n/locales/tr/messages.json +44 -0
- package/src/components/i18n/locales/ug/messages.json +44 -0
- package/src/components/i18n/locales/uk/messages.json +44 -0
- package/src/components/i18n/locales/ur/messages.json +44 -0
- package/src/components/i18n/locales/vi/messages.json +44 -0
- package/src/components/i18n/locales/yi/messages.json +44 -0
- package/src/components/i18n/locales/zh/messages.json +44 -0
- package/src/components/icons/index.ts +242 -0
- package/src/components/inline-tools/inline-tool-bold.ts +2213 -0
- package/src/components/inline-tools/inline-tool-convert.ts +141 -0
- package/src/components/inline-tools/inline-tool-italic.ts +500 -0
- package/src/components/inline-tools/inline-tool-link.ts +539 -0
- package/src/components/modules/api/blocks.ts +363 -0
- package/src/components/modules/api/caret.ts +125 -0
- package/src/components/modules/api/events.ts +51 -0
- package/src/components/modules/api/history.ts +73 -0
- package/src/components/modules/api/i18n.ts +33 -0
- package/src/components/modules/api/index.ts +39 -0
- package/src/components/modules/api/inlineToolbar.ts +33 -0
- package/src/components/modules/api/listeners.ts +56 -0
- package/src/components/modules/api/notifier.ts +46 -0
- package/src/components/modules/api/readonly.ts +39 -0
- package/src/components/modules/api/sanitizer.ts +30 -0
- package/src/components/modules/api/saver.ts +52 -0
- package/src/components/modules/api/selection.ts +48 -0
- package/src/components/modules/api/styles.ts +72 -0
- package/src/components/modules/api/toolbar.ts +79 -0
- package/src/components/modules/api/tools.ts +16 -0
- package/src/components/modules/api/tooltip.ts +67 -0
- package/src/components/modules/api/ui.ts +36 -0
- package/src/components/modules/blockEvents.ts +1375 -0
- package/src/components/modules/blockManager.ts +1348 -0
- package/src/components/modules/blockSelection.ts +708 -0
- package/src/components/modules/caret.ts +853 -0
- package/src/components/modules/crossBlockSelection.ts +329 -0
- package/src/components/modules/dragManager.ts +1141 -0
- package/src/components/modules/history.ts +1098 -0
- package/src/components/modules/i18n.ts +325 -0
- package/src/components/modules/index.ts +139 -0
- package/src/components/modules/modificationsObserver.ts +147 -0
- package/src/components/modules/paste.ts +1092 -0
- package/src/components/modules/readonly.ts +136 -0
- package/src/components/modules/rectangleSelection.ts +668 -0
- package/src/components/modules/renderer.ts +155 -0
- package/src/components/modules/saver.ts +283 -0
- package/src/components/modules/toolbar/blockSettings.ts +776 -0
- package/src/components/modules/toolbar/index.ts +1311 -0
- package/src/components/modules/toolbar/inline.ts +956 -0
- package/src/components/modules/tools.ts +589 -0
- package/src/components/modules/ui.ts +1179 -0
- package/src/components/polyfills.ts +113 -0
- package/src/components/selection.ts +1189 -0
- package/src/components/tools/base.ts +274 -0
- package/src/components/tools/block.ts +291 -0
- package/src/components/tools/collection.ts +67 -0
- package/src/components/tools/factory.ts +85 -0
- package/src/components/tools/inline.ts +71 -0
- package/src/components/tools/tune.ts +33 -0
- package/src/components/ui/toolbox.ts +497 -0
- package/src/components/utils/announcer.ts +205 -0
- package/src/components/utils/api.ts +20 -0
- package/src/components/utils/bem.ts +26 -0
- package/src/components/utils/blocks.ts +284 -0
- package/src/components/utils/caret.ts +1067 -0
- package/src/components/utils/data-model-transform.ts +382 -0
- package/src/components/utils/events.ts +117 -0
- package/src/components/utils/keyboard.ts +60 -0
- package/src/components/utils/listeners.ts +296 -0
- package/src/components/utils/mutations.ts +39 -0
- package/src/components/utils/notifier/draw.ts +190 -0
- package/src/components/utils/notifier/index.ts +66 -0
- package/src/components/utils/notifier/types.ts +1 -0
- package/src/components/utils/notifier.ts +77 -0
- package/src/components/utils/placeholder.ts +140 -0
- package/src/components/utils/popover/components/hint/hint.const.ts +10 -0
- package/src/components/utils/popover/components/hint/hint.ts +46 -0
- package/src/components/utils/popover/components/hint/index.ts +6 -0
- package/src/components/utils/popover/components/popover-header/index.ts +2 -0
- package/src/components/utils/popover/components/popover-header/popover-header.const.ts +8 -0
- package/src/components/utils/popover/components/popover-header/popover-header.ts +80 -0
- package/src/components/utils/popover/components/popover-header/popover-header.types.ts +14 -0
- package/src/components/utils/popover/components/popover-item/index.ts +13 -0
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +50 -0
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +666 -0
- package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.const.ts +14 -0
- package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.ts +136 -0
- package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +20 -0
- package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.ts +117 -0
- package/src/components/utils/popover/components/popover-item/popover-item.ts +187 -0
- package/src/components/utils/popover/components/search-input/index.ts +2 -0
- package/src/components/utils/popover/components/search-input/search-input.const.ts +8 -0
- package/src/components/utils/popover/components/search-input/search-input.ts +181 -0
- package/src/components/utils/popover/components/search-input/search-input.types.ts +30 -0
- package/src/components/utils/popover/index.ts +13 -0
- package/src/components/utils/popover/popover-abstract.ts +448 -0
- package/src/components/utils/popover/popover-desktop.ts +643 -0
- package/src/components/utils/popover/popover-inline.ts +338 -0
- package/src/components/utils/popover/popover-mobile.ts +201 -0
- package/src/components/utils/popover/popover.const.ts +81 -0
- package/src/components/utils/popover/utils/popover-states-history.ts +72 -0
- package/src/components/utils/promise-queue.ts +43 -0
- package/src/components/utils/sanitizer.ts +537 -0
- package/src/components/utils/scroll-locker.ts +87 -0
- package/src/components/utils/shortcut.ts +231 -0
- package/src/components/utils/shortcuts.ts +113 -0
- package/src/components/utils/tools.ts +105 -0
- package/src/components/utils/tooltip.ts +642 -0
- package/src/components/utils/tw.ts +241 -0
- package/src/components/utils.ts +1081 -0
- package/src/env.d.ts +13 -0
- package/src/full.ts +69 -0
- package/src/locales.ts +51 -0
- package/src/stories/Block.stories.ts +498 -0
- package/src/stories/EditorModes.stories.ts +505 -0
- package/src/stories/Header.stories.ts +137 -0
- package/src/stories/InlineToolbar.stories.ts +498 -0
- package/src/stories/List.stories.ts +259 -0
- package/src/stories/Notifier.stories.ts +340 -0
- package/src/stories/Paragraph.stories.ts +112 -0
- package/src/stories/Placeholder.stories.ts +319 -0
- package/src/stories/Popover.stories.ts +844 -0
- package/src/stories/Selection.stories.ts +250 -0
- package/src/stories/StubBlock.stories.ts +156 -0
- package/src/stories/Toolbar.stories.ts +223 -0
- package/src/stories/Toolbox.stories.ts +166 -0
- package/src/stories/Tooltip.stories.ts +198 -0
- package/src/stories/helpers.ts +463 -0
- package/src/styles/main.css +123 -0
- package/src/tools/header/index.ts +570 -0
- package/src/tools/index.ts +38 -0
- package/src/tools/list/index.ts +1803 -0
- package/src/tools/paragraph/index.ts +411 -0
- package/src/tools/stub/index.ts +107 -0
- package/src/types-internal/blok-modules.d.ts +87 -0
- package/src/types-internal/html-janitor.d.ts +28 -0
- package/src/types-internal/module-config.d.ts +11 -0
- package/src/variants/all-locales.ts +155 -0
- package/src/variants/blok-maximum.ts +20 -0
- package/src/variants/blok-minimum.ts +243 -0
- package/types/api/blocks.d.ts +1 -1
- package/types/api/i18n.d.ts +5 -3
- package/types/api/selection.d.ts +6 -0
- package/types/api/styles.d.ts +23 -10
- package/types/configs/blok-config.d.ts +29 -0
- package/types/configs/i18n-config.d.ts +52 -2
- package/types/configs/i18n-dictionary.d.ts +16 -90
- package/types/data-attributes.d.ts +169 -0
- package/types/data-formats/output-data.d.ts +15 -0
- package/types/full.d.ts +80 -0
- package/types/index.d.ts +9 -12
- package/types/locales.d.ts +59 -0
- package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
- package/types/tools/block-tool.d.ts +9 -0
- package/types/tools/header.d.ts +18 -0
- package/types/tools/index.d.ts +1 -0
- package/types/tools/list.d.ts +91 -0
- package/types/tools/paragraph.d.ts +71 -0
- package/types/tools/tool-settings.d.ts +16 -2
- package/types/tools/tool.d.ts +6 -0
- package/types/tools-entry.d.ts +49 -0
- package/types/utils/popover/popover-item.d.ts +6 -5
- package/dist/blok-B870U2fw.mjs +0 -25803
- package/dist/blok.umd.js +0 -181
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class allows to make a queue of async jobs and wait until they all will be finished one by one
|
|
3
|
+
* @example const queue = new PromiseQueue();
|
|
4
|
+
* queue.add(async () => { ... });
|
|
5
|
+
* queue.add(async () => { ... });
|
|
6
|
+
* await queue.completed;
|
|
7
|
+
*/
|
|
8
|
+
export class PromiseQueue {
|
|
9
|
+
/**
|
|
10
|
+
* Tail promise representing the queued operations chain
|
|
11
|
+
*/
|
|
12
|
+
private tail: Promise<void> = Promise.resolve();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Stored failure that should be propagated to consumers
|
|
16
|
+
*/
|
|
17
|
+
private failure: unknown;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Expose completion promise that rejects if any queued task failed
|
|
21
|
+
*/
|
|
22
|
+
public get completed(): Promise<void> {
|
|
23
|
+
return this.failure ? Promise.reject(this.failure) : this.tail;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Add new promise to queue
|
|
28
|
+
* @param operation - promise should be added to queue
|
|
29
|
+
*/
|
|
30
|
+
public add(operation: () => void | PromiseLike<void>): Promise<void> {
|
|
31
|
+
if (this.failure) {
|
|
32
|
+
return Promise.reject(this.failure);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const task = this.tail.then(() => operation());
|
|
36
|
+
|
|
37
|
+
this.tail = task.catch((error) => {
|
|
38
|
+
this.failure = error;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return task;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Blok Sanitizer
|
|
4
|
+
*
|
|
5
|
+
* Clears HTML from taint tags
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
* @example
|
|
8
|
+
*
|
|
9
|
+
* clean(yourTaintString, yourConfig);
|
|
10
|
+
*
|
|
11
|
+
* {@link SanitizerConfig}
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { deepMerge, isBoolean, isEmpty, isFunction, isObject, isString } from '../utils';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {object} SanitizerConfig
|
|
18
|
+
* @property {object} tags - define tags restrictions
|
|
19
|
+
* @example
|
|
20
|
+
*
|
|
21
|
+
* tags : {
|
|
22
|
+
* p: true,
|
|
23
|
+
* a: {
|
|
24
|
+
* href: true,
|
|
25
|
+
* rel: "nofollow",
|
|
26
|
+
* target: "_blank"
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import HTMLJanitor from 'html-janitor';
|
|
32
|
+
import type { BlockToolData, SanitizerConfig, SanitizerRule } from '../../../types';
|
|
33
|
+
import type { TagConfig } from '../../../types/configs/sanitizer-config';
|
|
34
|
+
import type { SavedData } from '../../../types/data-formats';
|
|
35
|
+
|
|
36
|
+
type DeepSanitizerRule = SanitizerConfig | SanitizerRule | boolean;
|
|
37
|
+
|
|
38
|
+
const UNSAFE_URL_PROTOCOL_PATTERN = /^\s*(?:javascript\s*:|data\s*:\s*text\s*\/\s*html)/i;
|
|
39
|
+
const UNSAFE_URL_ATTR_FALLBACK_PATTERN =
|
|
40
|
+
/\s*(?:href|src)\s*=\s*(?:"\s*(?:javascript\s*:|data\s*:\s*text\s*\/\s*html)[^"]*"|'\s*(?:javascript\s*:|data\s*:\s*text\s*\/\s*html)[^']*|(?:javascript\s*:|data\s*:\s*text\s*\/\s*html)[^ \t\r\n>]*)/gi;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sanitize Blocks
|
|
44
|
+
*
|
|
45
|
+
* Enumerate blocks and clean data
|
|
46
|
+
* @param blocksData - blocks' data to sanitize
|
|
47
|
+
* @param sanitizeConfig — sanitize config to use or function to get config for Tool
|
|
48
|
+
* @param globalSanitizer — global sanitizer config defined on blok level
|
|
49
|
+
*/
|
|
50
|
+
export const sanitizeBlocks = (
|
|
51
|
+
blocksData: Array<Pick<SavedData, 'data' | 'tool'>>,
|
|
52
|
+
sanitizeConfig: SanitizerConfig | ((toolName: string) => SanitizerConfig | undefined),
|
|
53
|
+
globalSanitizer: SanitizerConfig = {} as SanitizerConfig
|
|
54
|
+
): Array<Pick<SavedData, 'data' | 'tool'>> => {
|
|
55
|
+
return blocksData.map((block) => {
|
|
56
|
+
const toolConfig = isFunction(sanitizeConfig) ? sanitizeConfig(block.tool) : sanitizeConfig;
|
|
57
|
+
const rules: DeepSanitizerRule = (toolConfig ?? {}) as SanitizerConfig;
|
|
58
|
+
|
|
59
|
+
if (isObject(rules) && isEmpty(rules) && isEmpty(globalSanitizer)) {
|
|
60
|
+
return block;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...block,
|
|
65
|
+
data: deepSanitize(block.data, rules, globalSanitizer) as BlockToolData,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Cleans string from unwanted tags
|
|
71
|
+
* Method allows to use default config
|
|
72
|
+
* @param {string} taintString - taint string
|
|
73
|
+
* @param {SanitizerConfig} customConfig - allowed tags
|
|
74
|
+
* @returns {string} clean HTML
|
|
75
|
+
*/
|
|
76
|
+
export const clean = (taintString: string, customConfig: SanitizerConfig = {} as SanitizerConfig): string => {
|
|
77
|
+
const sanitizerConfig = {
|
|
78
|
+
tags: customConfig,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* API client can use custom config to manage sanitize process
|
|
83
|
+
*/
|
|
84
|
+
const sanitizerInstance = new HTMLJanitor(sanitizerConfig);
|
|
85
|
+
|
|
86
|
+
return sanitizerInstance.clean(taintString);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Method recursively reduces Block's data and cleans with passed rules
|
|
91
|
+
* @param {BlockToolData|object|*} dataToSanitize - taint string or object/array that contains taint string
|
|
92
|
+
* @param {SanitizerConfig} rules - object with sanitizer rules
|
|
93
|
+
* @param {SanitizerConfig} globalRules - global sanitizer config
|
|
94
|
+
*/
|
|
95
|
+
const deepSanitize = (
|
|
96
|
+
dataToSanitize: object | string,
|
|
97
|
+
rules: DeepSanitizerRule,
|
|
98
|
+
globalRules: SanitizerConfig
|
|
99
|
+
): object | string => {
|
|
100
|
+
/**
|
|
101
|
+
* BlockData It may contain 3 types:
|
|
102
|
+
* - Array
|
|
103
|
+
* - Object
|
|
104
|
+
* - Primitive
|
|
105
|
+
*/
|
|
106
|
+
if (Array.isArray(dataToSanitize)) {
|
|
107
|
+
/**
|
|
108
|
+
* Array: call sanitize for each item
|
|
109
|
+
*/
|
|
110
|
+
return cleanArray(dataToSanitize, rules, globalRules);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (isObject(dataToSanitize)) {
|
|
114
|
+
/**
|
|
115
|
+
* Objects: just clean object deeper.
|
|
116
|
+
*/
|
|
117
|
+
return cleanObject(dataToSanitize, rules, globalRules);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Primitives (number|string|boolean): clean this item
|
|
122
|
+
*
|
|
123
|
+
* Clean only strings
|
|
124
|
+
*/
|
|
125
|
+
if (isString(dataToSanitize)) {
|
|
126
|
+
return cleanOneItem(dataToSanitize, rules, globalRules);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return dataToSanitize;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Clean array
|
|
134
|
+
* @param {Array} array - [1, 2, {}, []]
|
|
135
|
+
* @param {SanitizerConfig} ruleForItem - sanitizer config for array
|
|
136
|
+
* @param {SanitizerConfig} globalRules - global sanitizer config
|
|
137
|
+
*/
|
|
138
|
+
const cleanArray = (
|
|
139
|
+
array: Array<object | string>,
|
|
140
|
+
ruleForItem: DeepSanitizerRule,
|
|
141
|
+
globalRules: SanitizerConfig
|
|
142
|
+
): Array<object | string> => {
|
|
143
|
+
return array.map((arrayItem) => deepSanitize(arrayItem, ruleForItem, globalRules));
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Clean object
|
|
148
|
+
* @param {object} object - {level: 0, text: 'adada', items: [1,2,3]}}
|
|
149
|
+
* @param {object} rules - { b: true } or true|false
|
|
150
|
+
* @param {SanitizerConfig} globalRules - global sanitizer config
|
|
151
|
+
* @returns {object}
|
|
152
|
+
*/
|
|
153
|
+
const cleanObject = (
|
|
154
|
+
object: object,
|
|
155
|
+
rules: DeepSanitizerRule | Record<string, DeepSanitizerRule>,
|
|
156
|
+
globalRules: SanitizerConfig
|
|
157
|
+
): object => {
|
|
158
|
+
const cleanData: Record<string, unknown> = {};
|
|
159
|
+
const objectRecord = object as Record<string, unknown>;
|
|
160
|
+
|
|
161
|
+
for (const fieldName in object) {
|
|
162
|
+
if (!Object.prototype.hasOwnProperty.call(object, fieldName)) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const currentIterationItem = objectRecord[fieldName];
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Get object from config by field name
|
|
170
|
+
* - if it is a HTML Janitor rule, call with this rule
|
|
171
|
+
* - otherwise, call with parent's config
|
|
172
|
+
*/
|
|
173
|
+
const rulesRecord = isObject(rules) ? (rules as Record<string, DeepSanitizerRule>) : undefined;
|
|
174
|
+
const ruleCandidate = rulesRecord?.[fieldName];
|
|
175
|
+
const ruleForItem = ruleCandidate !== undefined && isRule(ruleCandidate)
|
|
176
|
+
? ruleCandidate
|
|
177
|
+
: rules;
|
|
178
|
+
|
|
179
|
+
cleanData[fieldName] = deepSanitize(currentIterationItem as object | string, ruleForItem as DeepSanitizerRule, globalRules);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return cleanData;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Clean primitive value
|
|
187
|
+
* @param {string} taintString - string to clean
|
|
188
|
+
* @param {SanitizerConfig|boolean} rule - sanitizer rule
|
|
189
|
+
* @param {SanitizerConfig} globalRules - global sanitizer config
|
|
190
|
+
* @returns {string}
|
|
191
|
+
*/
|
|
192
|
+
const cleanOneItem = (
|
|
193
|
+
taintString: string,
|
|
194
|
+
rule: DeepSanitizerRule,
|
|
195
|
+
globalRules: SanitizerConfig
|
|
196
|
+
): string => {
|
|
197
|
+
const effectiveRule = getEffectiveRuleForString(rule, globalRules);
|
|
198
|
+
|
|
199
|
+
if (effectiveRule) {
|
|
200
|
+
const cleaned = clean(taintString, effectiveRule);
|
|
201
|
+
|
|
202
|
+
return stripUnsafeUrls(applyAttributeOverrides(cleaned, effectiveRule));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!isEmpty(globalRules)) {
|
|
206
|
+
const cleaned = clean(taintString, globalRules);
|
|
207
|
+
|
|
208
|
+
return stripUnsafeUrls(applyAttributeOverrides(cleaned, globalRules));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return stripUnsafeUrls(taintString);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Check if passed item is a HTML Janitor rule:
|
|
216
|
+
* { a : true }, {}, false, true, function(){} — correct rules
|
|
217
|
+
* undefined, null, 0, 1, 2 — not a rules
|
|
218
|
+
* @param {SanitizerConfig} config - config to check
|
|
219
|
+
*/
|
|
220
|
+
const isRule = (config: DeepSanitizerRule): boolean => {
|
|
221
|
+
return isObject(config) || isBoolean(config) || isFunction(config);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
*
|
|
226
|
+
* @param {string} value - HTML string to strip unsafe URLs from
|
|
227
|
+
*/
|
|
228
|
+
const hasUnsafeUrlProtocol = (value: string | null): boolean => {
|
|
229
|
+
if (!value) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return UNSAFE_URL_PROTOCOL_PATTERN.test(value);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const stripUnsafeUrls = (value: string): string => {
|
|
237
|
+
if (!value || value.indexOf('<') === -1) {
|
|
238
|
+
return value;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (typeof document !== 'undefined') {
|
|
242
|
+
const template = document.createElement('template');
|
|
243
|
+
|
|
244
|
+
template.innerHTML = value;
|
|
245
|
+
|
|
246
|
+
const elements = template.content.querySelectorAll('[href],[src]');
|
|
247
|
+
|
|
248
|
+
elements.forEach((element) => {
|
|
249
|
+
['href', 'src'].forEach((attribute) => {
|
|
250
|
+
const attrValue = element.getAttribute(attribute);
|
|
251
|
+
|
|
252
|
+
if (hasUnsafeUrlProtocol(attrValue)) {
|
|
253
|
+
element.removeAttribute(attribute);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
return template.innerHTML;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return value.replace(UNSAFE_URL_ATTR_FALLBACK_PATTERN, '');
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
*
|
|
266
|
+
* @param {SanitizerConfig} config - sanitizer config to clone
|
|
267
|
+
*/
|
|
268
|
+
const cloneSanitizerConfig = (config: SanitizerConfig): SanitizerConfig => {
|
|
269
|
+
if (isEmpty(config)) {
|
|
270
|
+
return {} as SanitizerConfig;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const cloned: SanitizerConfig = {} as SanitizerConfig;
|
|
274
|
+
|
|
275
|
+
for (const tag in config) {
|
|
276
|
+
if (!Object.prototype.hasOwnProperty.call(config, tag)) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
cloned[tag] = cloneTagConfig(config[tag]);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return cloned;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
*
|
|
288
|
+
* @param {SanitizerRule} rule - tag rule to clone
|
|
289
|
+
*/
|
|
290
|
+
type SanitizerFunctionRule = (el: Element) => TagConfig;
|
|
291
|
+
|
|
292
|
+
const wrapFunctionRule = (rule: SanitizerFunctionRule): SanitizerFunctionRule => {
|
|
293
|
+
return function wrappedRule(this: unknown, element: Element): TagConfig {
|
|
294
|
+
const result = rule.call(this, element);
|
|
295
|
+
|
|
296
|
+
if (result == null) {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return result;
|
|
301
|
+
};
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const SAFE_ATTRIBUTES = new Set(['class', 'id', 'title', 'role', 'dir', 'lang']);
|
|
305
|
+
|
|
306
|
+
const isSafeAttribute = (attribute: string): boolean => {
|
|
307
|
+
const lowerName = attribute.toLowerCase();
|
|
308
|
+
|
|
309
|
+
return lowerName.startsWith('data-') || lowerName.startsWith('aria-') || SAFE_ATTRIBUTES.has(lowerName);
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const preserveExistingAttributesRule: SanitizerFunctionRule = (element) => {
|
|
313
|
+
const preserved: TagConfig = {};
|
|
314
|
+
|
|
315
|
+
Array.from(element.attributes).forEach((attribute) => {
|
|
316
|
+
if (!isSafeAttribute(attribute.name)) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
preserved[attribute.name] = true;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
return preserved;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const cloneTagConfig = (rule: SanitizerRule): SanitizerRule => {
|
|
327
|
+
if (rule === true) {
|
|
328
|
+
return wrapFunctionRule(preserveExistingAttributesRule);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (rule === false) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (isFunction(rule)) {
|
|
336
|
+
return wrapFunctionRule(rule as SanitizerFunctionRule);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (isString(rule)) {
|
|
340
|
+
return rule;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (isObject(rule)) {
|
|
344
|
+
return deepMerge({}, rule as Record<string, unknown>) as SanitizerRule;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return rule;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
*
|
|
352
|
+
* @param {SanitizerConfig} globalRules - global sanitizer config
|
|
353
|
+
* @param {SanitizerConfig} fieldRules - field-specific sanitizer config
|
|
354
|
+
*/
|
|
355
|
+
const mergeTagRules = (globalRules: SanitizerConfig, fieldRules: SanitizerConfig): SanitizerConfig => {
|
|
356
|
+
if (isEmpty(globalRules)) {
|
|
357
|
+
return cloneSanitizerConfig(fieldRules);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const merged: SanitizerConfig = {} as SanitizerConfig;
|
|
361
|
+
|
|
362
|
+
for (const tag in globalRules) {
|
|
363
|
+
if (!Object.prototype.hasOwnProperty.call(globalRules, tag)) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const globalValue = globalRules[tag];
|
|
368
|
+
const fieldValue = fieldRules ? fieldRules[tag] : undefined;
|
|
369
|
+
|
|
370
|
+
if (isFunction(fieldValue)) {
|
|
371
|
+
merged[tag] = cloneTagConfig(fieldValue as SanitizerRule);
|
|
372
|
+
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (isFunction(globalValue)) {
|
|
377
|
+
merged[tag] = cloneTagConfig(globalValue as SanitizerRule);
|
|
378
|
+
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (isObject(globalValue) && isObject(fieldValue)) {
|
|
383
|
+
merged[tag] = deepMerge({}, fieldValue as SanitizerConfig, globalValue as SanitizerConfig);
|
|
384
|
+
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (fieldValue !== undefined) {
|
|
389
|
+
merged[tag] = cloneTagConfig(fieldValue as SanitizerRule);
|
|
390
|
+
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
merged[tag] = cloneTagConfig(globalValue as SanitizerRule);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return merged;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
*
|
|
402
|
+
* @param {DeepSanitizerRule} rule - sanitizer rule to evaluate
|
|
403
|
+
* @param {SanitizerConfig} globalRules - global sanitizer config
|
|
404
|
+
*/
|
|
405
|
+
const getEffectiveRuleForString = (
|
|
406
|
+
rule: DeepSanitizerRule,
|
|
407
|
+
globalRules: SanitizerConfig
|
|
408
|
+
): SanitizerConfig | null => {
|
|
409
|
+
if (isObject(rule) && !isFunction(rule)) {
|
|
410
|
+
return mergeTagRules(globalRules, rule as SanitizerConfig);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (rule === false) {
|
|
414
|
+
return {} as SanitizerConfig;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (isEmpty(globalRules)) {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return cloneSanitizerConfig(globalRules);
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
*
|
|
426
|
+
* @param {SanitizerConfig} globalConfig - base global sanitizer config
|
|
427
|
+
* @param {...SanitizerConfig[]} configs - additional sanitizer configs to compose
|
|
428
|
+
*/
|
|
429
|
+
export const composeSanitizerConfig = (
|
|
430
|
+
globalConfig: SanitizerConfig,
|
|
431
|
+
...configs: SanitizerConfig[]
|
|
432
|
+
): SanitizerConfig => {
|
|
433
|
+
if (isEmpty(globalConfig)) {
|
|
434
|
+
return Object.assign({}, ...configs) as SanitizerConfig;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const base = cloneSanitizerConfig(globalConfig);
|
|
438
|
+
|
|
439
|
+
configs.forEach((config) => {
|
|
440
|
+
if (!config) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
for (const tag in config) {
|
|
445
|
+
if (!Object.prototype.hasOwnProperty.call(config, tag)) {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const sourceValue = config[tag];
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* If the tag doesn't exist in base, skip it to respect the base config
|
|
453
|
+
*/
|
|
454
|
+
if (!Object.prototype.hasOwnProperty.call(base, tag)) {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const targetValue = base[tag];
|
|
459
|
+
|
|
460
|
+
if (isFunction(sourceValue)) {
|
|
461
|
+
base[tag] = sourceValue;
|
|
462
|
+
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (sourceValue === true && isFunction(targetValue)) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (sourceValue === true) {
|
|
471
|
+
const targetIsPlainObject = isObject(targetValue) && !isFunction(targetValue);
|
|
472
|
+
|
|
473
|
+
base[tag] = targetIsPlainObject
|
|
474
|
+
? deepMerge({}, targetValue as SanitizerConfig)
|
|
475
|
+
: cloneTagConfig(sourceValue as SanitizerRule);
|
|
476
|
+
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (isObject(sourceValue) && isObject(targetValue)) {
|
|
481
|
+
base[tag] = deepMerge({}, targetValue as SanitizerConfig, sourceValue as SanitizerConfig);
|
|
482
|
+
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
base[tag] = cloneTagConfig(sourceValue as SanitizerRule);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
return base;
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
const applyAttributeOverrides = (html: string, rules: SanitizerConfig): string => {
|
|
494
|
+
if (typeof document === 'undefined' || !html || html.indexOf('<') === -1) {
|
|
495
|
+
return html;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const entries = Object.entries(rules).filter(([, value]) => isFunction(value));
|
|
499
|
+
|
|
500
|
+
if (entries.length === 0) {
|
|
501
|
+
return html;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const template = document.createElement('template');
|
|
505
|
+
|
|
506
|
+
template.innerHTML = html;
|
|
507
|
+
|
|
508
|
+
entries.forEach(([tag, rule]) => {
|
|
509
|
+
const elements = template.content.querySelectorAll(tag);
|
|
510
|
+
|
|
511
|
+
elements.forEach((element) => {
|
|
512
|
+
const ruleResult = (rule as (el: Element) => SanitizerRule)(element);
|
|
513
|
+
|
|
514
|
+
if (isBoolean(ruleResult) || isFunction(ruleResult) || ruleResult == null) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
for (const [attr, attrRule] of Object.entries(ruleResult)) {
|
|
519
|
+
if (attrRule === false) {
|
|
520
|
+
element.removeAttribute(attr);
|
|
521
|
+
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (attrRule === true) {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (isString(attrRule)) {
|
|
530
|
+
element.setAttribute(attr, attrRule);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
return template.innerHTML;
|
|
537
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { isIosDevice } from '../utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility allowing to lock body scroll on demand
|
|
5
|
+
*/
|
|
6
|
+
export class ScrollLocker {
|
|
7
|
+
/**
|
|
8
|
+
* Tailwind utility classes for styling
|
|
9
|
+
*/
|
|
10
|
+
private static CSS = {
|
|
11
|
+
overflowHidden: 'overflow-hidden',
|
|
12
|
+
fixed: 'fixed',
|
|
13
|
+
wFull: 'w-full',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Data attributes for state management
|
|
18
|
+
*/
|
|
19
|
+
private static DATA_ATTR = {
|
|
20
|
+
scrollLocked: 'data-blok-scroll-locked',
|
|
21
|
+
scrollLockedHard: 'data-blok-scroll-locked-hard',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Stores scroll position, used for hard scroll lock
|
|
26
|
+
*/
|
|
27
|
+
private scrollPosition: null | number = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Locks body element scroll
|
|
31
|
+
*/
|
|
32
|
+
public lock(): void {
|
|
33
|
+
if (isIosDevice) {
|
|
34
|
+
this.lockHard();
|
|
35
|
+
} else {
|
|
36
|
+
document.body.classList.add(ScrollLocker.CSS.overflowHidden);
|
|
37
|
+
document.body.setAttribute(ScrollLocker.DATA_ATTR.scrollLocked, 'true');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Unlocks body element scroll
|
|
43
|
+
*/
|
|
44
|
+
public unlock(): void {
|
|
45
|
+
if (isIosDevice) {
|
|
46
|
+
this.unlockHard();
|
|
47
|
+
} else {
|
|
48
|
+
document.body.classList.remove(ScrollLocker.CSS.overflowHidden);
|
|
49
|
+
document.body.removeAttribute(ScrollLocker.DATA_ATTR.scrollLocked);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Locks scroll in a hard way (via setting fixed position to body element)
|
|
55
|
+
*/
|
|
56
|
+
private lockHard(): void {
|
|
57
|
+
this.scrollPosition = window.pageYOffset;
|
|
58
|
+
document.documentElement.style.setProperty(
|
|
59
|
+
'--window-scroll-offset',
|
|
60
|
+
`${this.scrollPosition}px`
|
|
61
|
+
);
|
|
62
|
+
document.body.classList.add(
|
|
63
|
+
ScrollLocker.CSS.overflowHidden,
|
|
64
|
+
ScrollLocker.CSS.fixed,
|
|
65
|
+
ScrollLocker.CSS.wFull
|
|
66
|
+
);
|
|
67
|
+
document.body.style.top = `calc(-1 * var(--window-scroll-offset))`;
|
|
68
|
+
document.body.setAttribute(ScrollLocker.DATA_ATTR.scrollLockedHard, 'true');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Unlocks hard scroll lock
|
|
73
|
+
*/
|
|
74
|
+
private unlockHard(): void {
|
|
75
|
+
document.body.classList.remove(
|
|
76
|
+
ScrollLocker.CSS.overflowHidden,
|
|
77
|
+
ScrollLocker.CSS.fixed,
|
|
78
|
+
ScrollLocker.CSS.wFull
|
|
79
|
+
);
|
|
80
|
+
document.body.style.top = '';
|
|
81
|
+
document.body.removeAttribute(ScrollLocker.DATA_ATTR.scrollLockedHard);
|
|
82
|
+
if (this.scrollPosition !== null) {
|
|
83
|
+
window.scrollTo(0, this.scrollPosition);
|
|
84
|
+
}
|
|
85
|
+
this.scrollPosition = null;
|
|
86
|
+
}
|
|
87
|
+
}
|