@jackuait/blok 0.7.0-beta.3 → 0.7.0
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 -7
- package/dist/chunks/blok-Ufr5cPq-.mjs +12435 -0
- package/dist/chunks/constants-DT17zmu_.mjs +2934 -0
- package/dist/chunks/i18next-DymC16cN.mjs +1146 -0
- package/dist/chunks/i18next-loader-qjweOJ-t.mjs +35 -0
- package/dist/chunks/lightweight-i18n-vbtPx5C4.mjs +105 -0
- package/dist/chunks/messages-3bOAVT3X2.mjs +80 -0
- package/dist/chunks/messages-43N0Vfg42.mjs +80 -0
- package/dist/chunks/messages-B0cg-ThO2.mjs +80 -0
- package/dist/chunks/messages-B3StvafX.mjs +80 -0
- package/dist/chunks/messages-B7LU-b6n2.mjs +80 -0
- package/dist/chunks/messages-B87-89os.mjs +80 -0
- package/dist/chunks/messages-BFiMCfDX2.mjs +80 -0
- package/dist/chunks/messages-BLxyso1L.mjs +80 -0
- package/dist/chunks/messages-BQZtOYxr2.mjs +80 -0
- package/dist/chunks/messages-BRrtoRdw2.mjs +80 -0
- package/dist/chunks/messages-BU_YdaAf.mjs +80 -0
- package/dist/chunks/messages-BWbZYIs12.mjs +80 -0
- package/dist/chunks/messages-B_Qcy8kr2.mjs +80 -0
- package/dist/chunks/messages-B_uTiuQ-.mjs +80 -0
- package/dist/chunks/messages-BdWTM73p.mjs +80 -0
- package/dist/chunks/messages-BhZcNoIQ.mjs +80 -0
- package/dist/chunks/messages-Bn6LwI4B.mjs +80 -0
- package/dist/chunks/messages-BoTtYEct2.mjs +80 -0
- package/dist/chunks/messages-BrvAiuWT.mjs +80 -0
- package/dist/chunks/messages-Byp0YFMg.mjs +80 -0
- package/dist/chunks/messages-C0ZWDShx2.mjs +80 -0
- package/dist/chunks/messages-CA-jms9R.mjs +80 -0
- package/dist/chunks/messages-CFr0Ha6p2.mjs +80 -0
- package/dist/chunks/messages-CG2xl0IV.mjs +80 -0
- package/dist/chunks/messages-CIGX0FfW.mjs +80 -0
- package/dist/chunks/messages-CRMdL0jG.mjs +80 -0
- package/dist/chunks/messages-CRdl14uE.mjs +80 -0
- package/dist/chunks/messages-Cimsel4e.mjs +80 -0
- package/dist/chunks/messages-CjcSWeud.mjs +80 -0
- package/dist/chunks/messages-ClDJuy8K2.mjs +80 -0
- package/dist/chunks/messages-Cn1AC0Qk.mjs +80 -0
- package/dist/chunks/messages-CpnXbVOK2.mjs +80 -0
- package/dist/chunks/messages-CqsES1wk2.mjs +80 -0
- package/dist/chunks/messages-Csq7JatN.mjs +80 -0
- package/dist/chunks/messages-CtufKbaD.mjs +80 -0
- package/dist/chunks/messages-Cuk0QaLM.mjs +80 -0
- package/dist/chunks/messages-CvamFN6x.mjs +80 -0
- package/dist/chunks/messages-CwRhVVui.mjs +80 -0
- package/dist/chunks/messages-CzCezryo.mjs +80 -0
- package/dist/chunks/messages-D0v0Xa_i2.mjs +80 -0
- package/dist/chunks/messages-D3JVx_CH2.mjs +80 -0
- package/dist/chunks/messages-D4jR5Oc-.mjs +80 -0
- package/dist/chunks/messages-D7fI9Pj52.mjs +80 -0
- package/dist/chunks/messages-DGodJU2R.mjs +80 -0
- package/dist/chunks/messages-DLrmLkco2.mjs +80 -0
- package/dist/chunks/messages-DPe7kW6J.mjs +80 -0
- package/dist/chunks/messages-DRYKKPk8.mjs +80 -0
- package/dist/chunks/messages-DV5c_ZRQ.mjs +80 -0
- package/dist/chunks/messages-Dg6kSnxq.mjs +80 -0
- package/dist/chunks/messages-Dgfbmyf-.mjs +80 -0
- package/dist/chunks/messages-DihczS7L.mjs +80 -0
- package/dist/chunks/messages-DkSwQvmi2.mjs +80 -0
- package/dist/chunks/messages-Doxcj7Qy.mjs +80 -0
- package/dist/chunks/messages-DqGQvcXv2.mjs +80 -0
- package/dist/chunks/messages-Dr7yA3xM.mjs +80 -0
- package/dist/chunks/messages-DriB5lEF.mjs +80 -0
- package/dist/chunks/messages-FB_MePlt.mjs +80 -0
- package/dist/chunks/messages-JyZvGvrN.mjs +80 -0
- package/dist/chunks/messages-KdvbGwLH.mjs +80 -0
- package/dist/chunks/messages-M0HT-kBW.mjs +80 -0
- package/dist/chunks/messages-M8noQ6Kp2.mjs +80 -0
- package/dist/chunks/messages-elZUbCrN.mjs +80 -0
- package/dist/chunks/messages-iWMOMK822.mjs +80 -0
- package/dist/chunks/messages-kC92TJI72.mjs +80 -0
- package/dist/chunks/messages-tfyq1JIh2.mjs +80 -0
- package/dist/chunks/messages-v1HkA3kF2.mjs +80 -0
- package/dist/chunks/messages-yuqArCc6.mjs +80 -0
- package/dist/chunks/notifier-BqYxvxnV.mjs +96 -0
- package/dist/chunks/objectSpread2-CyPxu8-u.mjs +62 -0
- package/dist/chunks/tools-CJIETS-H.mjs +6004 -0
- package/dist/chunks/tw-DmW6-pCY.mjs +237 -0
- package/dist/cli.mjs +36 -49
- package/dist/full.mjs +26 -52
- package/dist/locales.mjs +181 -254
- package/dist/messages-2iHnlF0U.mjs +80 -0
- package/dist/messages-49ZJ_ISf.mjs +80 -0
- package/dist/messages-B8jjwMLK.mjs +80 -0
- package/dist/messages-BEDVb3ZX.mjs +80 -0
- package/dist/messages-BEEr6Vh82.mjs +80 -0
- package/dist/messages-BFT0F9pw.mjs +80 -0
- package/dist/messages-BHOI7R4K.mjs +80 -0
- package/dist/messages-BRPH_a6a.mjs +80 -0
- package/dist/messages-BSlQrYwp.mjs +80 -0
- package/dist/messages-BTNuOkhL.mjs +80 -0
- package/dist/messages-BX2KVzJp2.mjs +80 -0
- package/dist/messages-BaGwIHPb2.mjs +80 -0
- package/dist/messages-BdA_xvxj.mjs +80 -0
- package/dist/messages-BeJaje7e2.mjs +80 -0
- package/dist/messages-BfgHOkAy.mjs +80 -0
- package/dist/messages-BflWzIcP2.mjs +80 -0
- package/dist/messages-BigRnQS92.mjs +80 -0
- package/dist/messages-BjnJajTO2.mjs +80 -0
- package/dist/messages-BpA30dPf.mjs +80 -0
- package/dist/messages-BrPEPj382.mjs +80 -0
- package/dist/messages-Bt_9ptDu.mjs +80 -0
- package/dist/messages-C0cXOCHN2.mjs +80 -0
- package/dist/messages-C3tLCwJp2.mjs +80 -0
- package/dist/messages-C45IBZtA2.mjs +80 -0
- package/dist/messages-CA0hwajz.mjs +80 -0
- package/dist/messages-CCKZS2f4.mjs +80 -0
- package/dist/messages-CCm71gq3.mjs +80 -0
- package/dist/messages-CERs9LC9.mjs +80 -0
- package/dist/messages-CLQvtc_8.mjs +80 -0
- package/dist/messages-CPx1R-PH.mjs +80 -0
- package/dist/messages-CYFdbooL2.mjs +80 -0
- package/dist/messages-CYLYnOV82.mjs +80 -0
- package/dist/messages-CYZVFnaF.mjs +80 -0
- package/dist/messages-CaAdEXoh2.mjs +80 -0
- package/dist/messages-CicggErN2.mjs +80 -0
- package/dist/messages-CkAWTSc4.mjs +80 -0
- package/dist/messages-CkVfziK_2.mjs +80 -0
- package/dist/messages-CsM2iz1H2.mjs +80 -0
- package/dist/messages-D-12TeCM2.mjs +80 -0
- package/dist/messages-D0i5Vdyy2.mjs +80 -0
- package/dist/messages-D5KmRsUV2.mjs +80 -0
- package/dist/messages-DBwaWI0X.mjs +80 -0
- package/dist/messages-DDGzypb4.mjs +80 -0
- package/dist/messages-DQGzw4IC.mjs +80 -0
- package/dist/messages-DWZyaZNA.mjs +80 -0
- package/dist/messages-DYlxQEIv.mjs +80 -0
- package/dist/messages-DZo0x7Bd.mjs +80 -0
- package/dist/messages-Dc1yFFBM.mjs +80 -0
- package/dist/messages-DdUpYaJ1.mjs +80 -0
- package/dist/messages-DgstU8GH.mjs +80 -0
- package/dist/messages-DhdWq5oQ2.mjs +80 -0
- package/dist/messages-DmX52AQr.mjs +80 -0
- package/dist/messages-Dr-YJYIK2.mjs +80 -0
- package/dist/messages-DuubRyFf.mjs +80 -0
- package/dist/messages-DvTVsLOK2.mjs +80 -0
- package/dist/messages-DwPfgL_u.mjs +80 -0
- package/dist/messages-DxKIxLKw.mjs +80 -0
- package/dist/messages-DzhR8Klk.mjs +80 -0
- package/dist/messages-MBBSKGjJ2.mjs +80 -0
- package/dist/messages-RNusm48G2.mjs +80 -0
- package/dist/messages-XwPD18Kk.mjs +80 -0
- package/dist/messages-YfjdnhUF.mjs +80 -0
- package/dist/messages-aNMLsF8T2.mjs +80 -0
- package/dist/messages-cOqXp22e.mjs +80 -0
- package/dist/messages-g58itYPI.mjs +80 -0
- package/dist/messages-vfkwiKQo.mjs +80 -0
- package/dist/messages-vssmW7KO.mjs +80 -0
- package/dist/react.mjs +108 -0
- package/dist/tools.mjs +3 -7462
- package/dist/vendor.LICENSE.txt +86 -86
- package/package.json +56 -29
- package/src/blok.ts +52 -2
- package/src/components/block/api.ts +8 -0
- package/src/components/block/mutation-handler.ts +29 -4
- package/src/components/block/style-manager.ts +1 -1
- package/src/components/block-tunes/block-tune-width.ts +39 -0
- package/src/components/blocks.ts +56 -2
- package/src/components/core.ts +1 -0
- package/src/components/i18n/locales/am/messages.json +6 -1
- package/src/components/i18n/locales/ar/messages.json +6 -1
- package/src/components/i18n/locales/az/messages.json +6 -1
- package/src/components/i18n/locales/bg/messages.json +8 -3
- package/src/components/i18n/locales/bn/messages.json +6 -1
- package/src/components/i18n/locales/bs/messages.json +6 -1
- package/src/components/i18n/locales/cs/messages.json +6 -1
- package/src/components/i18n/locales/da/messages.json +6 -1
- package/src/components/i18n/locales/de/messages.json +8 -3
- package/src/components/i18n/locales/dv/messages.json +6 -1
- package/src/components/i18n/locales/el/messages.json +8 -3
- package/src/components/i18n/locales/en/messages.json +5 -0
- package/src/components/i18n/locales/es/messages.json +6 -1
- package/src/components/i18n/locales/et/messages.json +6 -1
- package/src/components/i18n/locales/fa/messages.json +8 -3
- package/src/components/i18n/locales/fi/messages.json +6 -1
- package/src/components/i18n/locales/fil/messages.json +21 -16
- package/src/components/i18n/locales/fr/messages.json +6 -1
- package/src/components/i18n/locales/gu/messages.json +6 -1
- package/src/components/i18n/locales/he/messages.json +6 -1
- package/src/components/i18n/locales/hi/messages.json +6 -1
- package/src/components/i18n/locales/hr/messages.json +6 -1
- package/src/components/i18n/locales/hu/messages.json +6 -1
- package/src/components/i18n/locales/hy/messages.json +8 -3
- package/src/components/i18n/locales/id/messages.json +12 -7
- package/src/components/i18n/locales/it/messages.json +6 -1
- package/src/components/i18n/locales/ja/messages.json +6 -1
- package/src/components/i18n/locales/ka/messages.json +6 -1
- package/src/components/i18n/locales/km/messages.json +6 -1
- package/src/components/i18n/locales/kn/messages.json +6 -1
- package/src/components/i18n/locales/ko/messages.json +6 -1
- package/src/components/i18n/locales/ku/messages.json +7 -2
- package/src/components/i18n/locales/lo/messages.json +7 -2
- package/src/components/i18n/locales/lt/messages.json +6 -1
- package/src/components/i18n/locales/lv/messages.json +6 -1
- package/src/components/i18n/locales/mk/messages.json +6 -1
- package/src/components/i18n/locales/ml/messages.json +6 -1
- package/src/components/i18n/locales/mn/messages.json +6 -1
- package/src/components/i18n/locales/mr/messages.json +6 -1
- package/src/components/i18n/locales/ms/messages.json +6 -1
- package/src/components/i18n/locales/my/messages.json +6 -1
- package/src/components/i18n/locales/ne/messages.json +9 -4
- package/src/components/i18n/locales/nl/messages.json +6 -1
- package/src/components/i18n/locales/no/messages.json +6 -1
- package/src/components/i18n/locales/pa/messages.json +6 -1
- package/src/components/i18n/locales/pl/messages.json +6 -1
- package/src/components/i18n/locales/ps/messages.json +8 -3
- package/src/components/i18n/locales/pt/messages.json +6 -1
- package/src/components/i18n/locales/ro/messages.json +6 -1
- package/src/components/i18n/locales/ru/messages.json +10 -5
- package/src/components/i18n/locales/sd/messages.json +6 -1
- package/src/components/i18n/locales/si/messages.json +6 -1
- package/src/components/i18n/locales/sk/messages.json +6 -1
- package/src/components/i18n/locales/sl/messages.json +6 -1
- package/src/components/i18n/locales/sq/messages.json +6 -1
- package/src/components/i18n/locales/sr/messages.json +6 -1
- package/src/components/i18n/locales/sv/messages.json +6 -1
- package/src/components/i18n/locales/sw/messages.json +6 -1
- package/src/components/i18n/locales/ta/messages.json +6 -1
- package/src/components/i18n/locales/te/messages.json +9 -4
- package/src/components/i18n/locales/th/messages.json +6 -1
- package/src/components/i18n/locales/tr/messages.json +6 -1
- package/src/components/i18n/locales/ug/messages.json +7 -2
- package/src/components/i18n/locales/uk/messages.json +6 -1
- package/src/components/i18n/locales/ur/messages.json +6 -1
- package/src/components/i18n/locales/vi/messages.json +6 -1
- package/src/components/i18n/locales/yi/messages.json +7 -2
- package/src/components/i18n/locales/zh/messages.json +6 -1
- package/src/components/icons/index.ts +16 -0
- package/src/components/inline-tools/inline-tool-link.ts +1 -1
- package/src/components/modules/api/blocks.ts +45 -2
- package/src/components/modules/api/index.ts +1 -0
- package/src/components/modules/api/width.ts +17 -0
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +99 -0
- package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +109 -2
- package/src/components/modules/blockEvents/constants.ts +7 -0
- package/src/components/modules/blockManager/blockManager.ts +113 -9
- package/src/components/modules/blockManager/hierarchy.ts +61 -0
- package/src/components/modules/blockManager/operations.ts +161 -16
- package/src/components/modules/blockManager/yjs-sync.ts +112 -4
- package/src/components/modules/blockSelection.ts +36 -2
- package/src/components/modules/crossBlockSelection.ts +22 -2
- package/src/components/modules/drag/DragController.ts +178 -4
- package/src/components/modules/drag/operations/DragOperations.ts +48 -9
- package/src/components/modules/drag/preview/DragPreview.ts +21 -1
- package/src/components/modules/drag/state/DragStateMachine.ts +6 -1
- package/src/components/modules/drag/target/DropTargetDetector.ts +80 -4
- package/src/components/modules/drag/utils/ToggleSpringLoader.ts +71 -0
- package/src/components/modules/index.ts +7 -1
- package/src/components/modules/modificationsObserver.ts +19 -0
- package/src/components/modules/paste/constants.ts +2 -0
- package/src/components/modules/paste/handlers/base.ts +33 -1
- package/src/components/modules/paste/handlers/html-handler.ts +121 -54
- package/src/components/modules/paste/index.ts +5 -0
- package/src/components/modules/paste/types.ts +5 -0
- package/src/components/modules/rectangleSelection.ts +74 -81
- package/src/components/modules/toolbar/blockSettings.ts +25 -7
- package/src/components/modules/toolbar/index.ts +9 -7
- package/src/components/modules/toolbar/inline/index.ts +6 -1
- package/src/components/modules/toolbar/plus-button.ts +2 -6
- package/src/components/modules/toolbar/positioning.ts +10 -1
- package/src/components/modules/toolbar/settings-toggler.ts +1 -1
- package/src/components/modules/toolbar/styles.ts +3 -7
- package/src/components/modules/ui.ts +59 -5
- package/src/components/modules/uiControllers/handlers/click.ts +3 -2
- package/src/components/modules/widthManager.ts +69 -0
- package/src/components/modules/yjs/document-store.ts +11 -0
- package/src/components/modules/yjs/index.ts +11 -0
- package/src/components/shared/color-picker.ts +3 -3
- package/src/components/tools/block.ts +1 -11
- package/src/components/ui/toolbox.ts +52 -8
- package/src/components/utils/blocks.ts +37 -7
- package/src/components/utils/mutations.ts +2 -2
- package/src/components/utils/notifier/draw.ts +1 -1
- package/src/components/utils/placeholder.ts +5 -6
- package/src/components/utils/popover/components/popover-header/popover-header.const.ts +1 -1
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +4 -4
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +6 -6
- package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
- package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
- package/src/components/utils/popover/components/search-input/search-input.ts +7 -11
- package/src/components/utils/popover/components/search-input/search-input.types.ts +149 -10
- package/src/components/utils/popover/popover-abstract.ts +3 -2
- package/src/components/utils/popover/popover-desktop.ts +133 -11
- package/src/components/utils/popover/popover-inline.ts +1 -1
- package/src/components/utils/popover/popover.const.ts +3 -3
- package/src/components/utils/shortcut.ts +2 -0
- package/src/components/utils/tooltip.ts +11 -1
- package/src/react/BlokContent.tsx +46 -0
- package/src/react/holder-map.ts +17 -0
- package/src/react/index.ts +3 -0
- package/src/react/types.ts +16 -0
- package/src/react/useBlok.ts +173 -0
- package/src/stories/Placeholder.stories.ts +0 -59
- package/src/styles/main.css +663 -52
- package/src/tools/header/header-toggle-keyboard.ts +115 -0
- package/src/tools/header/index.ts +382 -187
- package/src/tools/list/block-operations.ts +1 -1
- package/src/tools/list/caret-manager.ts +9 -12
- package/src/tools/list/index.ts +2 -6
- package/src/tools/list/list-keyboard.ts +2 -2
- package/src/tools/paragraph/index.ts +1 -1
- package/src/tools/table/index.ts +75 -3
- package/src/tools/table/table-add-controls.ts +97 -8
- package/src/tools/table/table-cell-blocks.ts +17 -8
- package/src/tools/table/table-cell-clipboard.ts +1 -1
- package/src/tools/table/table-cell-selection.ts +27 -2
- package/src/tools/table/table-operations.ts +3 -2
- package/src/tools/toggle/block-operations.ts +4 -2
- package/src/tools/toggle/constants.ts +26 -2
- package/src/tools/toggle/dom-builder.ts +90 -25
- package/src/tools/toggle/index.ts +112 -9
- package/src/tools/toggle/toggle-keyboard.ts +5 -3
- package/src/tools/toggle/toggle-lifecycle.ts +79 -7
- package/src/tools/toggle/toggle-shortcuts.ts +214 -20
- package/src/tools/toggle/types.ts +2 -0
- package/src/types-internal/blok-modules.d.ts +4 -0
- package/types/api/block.d.ts +5 -0
- package/types/api/blocks.d.ts +29 -0
- package/types/api/index.d.ts +1 -0
- package/types/api/width.d.ts +19 -0
- package/types/configs/blok-config.d.ts +33 -0
- package/types/index.d.ts +4 -0
- package/types/react.d.ts +58 -0
- package/types/utils/popover/popover.d.ts +7 -0
- package/dist/chunks/blok-BlyYiZTm.mjs +0 -20098
- package/dist/chunks/constants-DEy4jBO5.mjs +0 -5123
- package/dist/chunks/i18next-B47TKgbU.mjs +0 -1303
- package/dist/chunks/i18next-loader-Cfbv-x6v.mjs +0 -43
- package/dist/chunks/index-Cu1w-sLZ.mjs +0 -130
- package/dist/chunks/messages-0Pxnqd4N.mjs +0 -75
- package/dist/chunks/messages-0ZXYUq7S.mjs +0 -75
- package/dist/chunks/messages-2OD2uUDS.mjs +0 -75
- package/dist/chunks/messages-7cEMfYzh.mjs +0 -75
- package/dist/chunks/messages-8mwfda1Q.mjs +0 -75
- package/dist/chunks/messages-B-FqWsBM.mjs +0 -75
- package/dist/chunks/messages-B1jzqWiQ.mjs +0 -75
- package/dist/chunks/messages-B5wk4Ezz.mjs +0 -75
- package/dist/chunks/messages-BAZ5Ld8x.mjs +0 -75
- package/dist/chunks/messages-BBhGp198.mjs +0 -75
- package/dist/chunks/messages-BC9IjIb7.mjs +0 -75
- package/dist/chunks/messages-BFEmpeV-.mjs +0 -75
- package/dist/chunks/messages-BGqzTZy0.mjs +0 -75
- package/dist/chunks/messages-BICs1abK.mjs +0 -75
- package/dist/chunks/messages-BJX6rOnd.mjs +0 -75
- package/dist/chunks/messages-BL2bXRhN.mjs +0 -75
- package/dist/chunks/messages-BMs5qdlH.mjs +0 -75
- package/dist/chunks/messages-BRsjUNwB.mjs +0 -75
- package/dist/chunks/messages-BSqV8OUR.mjs +0 -75
- package/dist/chunks/messages-BTqu3DfG.mjs +0 -75
- package/dist/chunks/messages-BXnDEsur.mjs +0 -75
- package/dist/chunks/messages-BYcre4-6.mjs +0 -75
- package/dist/chunks/messages-BZ9LRJf-.mjs +0 -75
- package/dist/chunks/messages-BgypBy7y.mjs +0 -75
- package/dist/chunks/messages-BsuGf70G.mjs +0 -75
- package/dist/chunks/messages-BwaoF4lQ.mjs +0 -75
- package/dist/chunks/messages-C1l8_7-y.mjs +0 -75
- package/dist/chunks/messages-C5NA_r9v.mjs +0 -75
- package/dist/chunks/messages-C6zgZ5pA.mjs +0 -75
- package/dist/chunks/messages-CAo5ghFI.mjs +0 -75
- package/dist/chunks/messages-CH9qlJ9I.mjs +0 -75
- package/dist/chunks/messages-CI0HqAeS.mjs +0 -75
- package/dist/chunks/messages-CJJtms9k.mjs +0 -75
- package/dist/chunks/messages-CM2hJqk6.mjs +0 -75
- package/dist/chunks/messages-CRMiDPIQ.mjs +0 -75
- package/dist/chunks/messages-CWsZuBj1.mjs +0 -75
- package/dist/chunks/messages-C_gLHo6A.mjs +0 -75
- package/dist/chunks/messages-Cbu-NUDn.mjs +0 -75
- package/dist/chunks/messages-Cjb_MCeh.mjs +0 -75
- package/dist/chunks/messages-ClXYO9Wn.mjs +0 -75
- package/dist/chunks/messages-CsH20vhP.mjs +0 -75
- package/dist/chunks/messages-CsjAGhzA.mjs +0 -75
- package/dist/chunks/messages-Cx7VKFOE.mjs +0 -75
- package/dist/chunks/messages-D3JeBwxo.mjs +0 -75
- package/dist/chunks/messages-D541fieJ.mjs +0 -75
- package/dist/chunks/messages-D7XPdglc.mjs +0 -75
- package/dist/chunks/messages-DBhylfvt.mjs +0 -75
- package/dist/chunks/messages-DCA120lW.mjs +0 -75
- package/dist/chunks/messages-DCf_xZMN.mjs +0 -75
- package/dist/chunks/messages-DDwXKCpe.mjs +0 -75
- package/dist/chunks/messages-DNKDlxcy.mjs +0 -75
- package/dist/chunks/messages-DPvEjrGK.mjs +0 -75
- package/dist/chunks/messages-DQ-AkNxA.mjs +0 -75
- package/dist/chunks/messages-DVuvkNap.mjs +0 -75
- package/dist/chunks/messages-DaglyqUT.mjs +0 -75
- package/dist/chunks/messages-Di0bAfwA.mjs +0 -75
- package/dist/chunks/messages-DuLct0Yr.mjs +0 -75
- package/dist/chunks/messages-DzEYYhZh.mjs +0 -75
- package/dist/chunks/messages-DznNGAB2.mjs +0 -75
- package/dist/chunks/messages-DzoIzyu8.mjs +0 -75
- package/dist/chunks/messages-QYOGmket.mjs +0 -75
- package/dist/chunks/messages-cEjGDAgI.mjs +0 -75
- package/dist/chunks/messages-ddhvrdpE.mjs +0 -75
- package/dist/chunks/messages-mwfNK5nZ.mjs +0 -75
- package/dist/chunks/messages-nG_vNDte.mjs +0 -75
- package/dist/chunks/messages-tDq3Owh7.mjs +0 -75
- package/dist/chunks/messages-x6VJVZKx.mjs +0 -75
- package/dist/messages-0Pxnqd4N.mjs +0 -75
- package/dist/messages-0ZXYUq7S.mjs +0 -75
- package/dist/messages-2OD2uUDS.mjs +0 -75
- package/dist/messages-7cEMfYzh.mjs +0 -75
- package/dist/messages-8mwfda1Q.mjs +0 -75
- package/dist/messages-B-FqWsBM.mjs +0 -75
- package/dist/messages-B1jzqWiQ.mjs +0 -75
- package/dist/messages-B5wk4Ezz.mjs +0 -75
- package/dist/messages-BAZ5Ld8x.mjs +0 -75
- package/dist/messages-BBhGp198.mjs +0 -75
- package/dist/messages-BC9IjIb7.mjs +0 -75
- package/dist/messages-BFEmpeV-.mjs +0 -75
- package/dist/messages-BGqzTZy0.mjs +0 -75
- package/dist/messages-BICs1abK.mjs +0 -75
- package/dist/messages-BJX6rOnd.mjs +0 -75
- package/dist/messages-BL2bXRhN.mjs +0 -75
- package/dist/messages-BMs5qdlH.mjs +0 -75
- package/dist/messages-BRsjUNwB.mjs +0 -75
- package/dist/messages-BSqV8OUR.mjs +0 -75
- package/dist/messages-BTqu3DfG.mjs +0 -75
- package/dist/messages-BXnDEsur.mjs +0 -75
- package/dist/messages-BYcre4-6.mjs +0 -75
- package/dist/messages-BZ9LRJf-.mjs +0 -75
- package/dist/messages-BgypBy7y.mjs +0 -75
- package/dist/messages-BsuGf70G.mjs +0 -75
- package/dist/messages-BwaoF4lQ.mjs +0 -75
- package/dist/messages-C1l8_7-y.mjs +0 -75
- package/dist/messages-C5NA_r9v.mjs +0 -75
- package/dist/messages-C6zgZ5pA.mjs +0 -75
- package/dist/messages-CAo5ghFI.mjs +0 -75
- package/dist/messages-CH9qlJ9I.mjs +0 -75
- package/dist/messages-CI0HqAeS.mjs +0 -75
- package/dist/messages-CJJtms9k.mjs +0 -75
- package/dist/messages-CM2hJqk6.mjs +0 -75
- package/dist/messages-CRMiDPIQ.mjs +0 -75
- package/dist/messages-CWsZuBj1.mjs +0 -75
- package/dist/messages-C_gLHo6A.mjs +0 -75
- package/dist/messages-Cbu-NUDn.mjs +0 -75
- package/dist/messages-Cjb_MCeh.mjs +0 -75
- package/dist/messages-ClXYO9Wn.mjs +0 -75
- package/dist/messages-CsH20vhP.mjs +0 -75
- package/dist/messages-CsjAGhzA.mjs +0 -75
- package/dist/messages-Cx7VKFOE.mjs +0 -75
- package/dist/messages-D3JeBwxo.mjs +0 -75
- package/dist/messages-D541fieJ.mjs +0 -75
- package/dist/messages-D7XPdglc.mjs +0 -75
- package/dist/messages-DBhylfvt.mjs +0 -75
- package/dist/messages-DCA120lW.mjs +0 -75
- package/dist/messages-DCf_xZMN.mjs +0 -75
- package/dist/messages-DDwXKCpe.mjs +0 -75
- package/dist/messages-DNKDlxcy.mjs +0 -75
- package/dist/messages-DPvEjrGK.mjs +0 -75
- package/dist/messages-DQ-AkNxA.mjs +0 -75
- package/dist/messages-DVuvkNap.mjs +0 -75
- package/dist/messages-DaglyqUT.mjs +0 -75
- package/dist/messages-Di0bAfwA.mjs +0 -75
- package/dist/messages-DuLct0Yr.mjs +0 -75
- package/dist/messages-DzEYYhZh.mjs +0 -75
- package/dist/messages-DznNGAB2.mjs +0 -75
- package/dist/messages-DzoIzyu8.mjs +0 -75
- package/dist/messages-QYOGmket.mjs +0 -75
- package/dist/messages-cEjGDAgI.mjs +0 -75
- package/dist/messages-ddhvrdpE.mjs +0 -75
- package/dist/messages-mwfNK5nZ.mjs +0 -75
- package/dist/messages-nG_vNDte.mjs +0 -75
- package/dist/messages-tDq3Owh7.mjs +0 -75
- package/dist/messages-x6VJVZKx.mjs +0 -75
|
@@ -6,9 +6,10 @@ import type { PopoverItem, PopoverItemRenderParamsMap } from './components/popov
|
|
|
6
6
|
import { PopoverItemSeparator, css as popoverItemCls , PopoverItemDefault } from './components/popover-item';
|
|
7
7
|
import { PopoverItemHtml } from './components/popover-item/popover-item-html/popover-item-html';
|
|
8
8
|
import type { SearchableItem } from './components/search-input';
|
|
9
|
-
import { SearchInput, SearchInputEvent,
|
|
9
|
+
import { SearchInput, SearchInputEvent, scoreSearchMatch } from './components/search-input';
|
|
10
10
|
import { PopoverAbstract } from './popover-abstract';
|
|
11
|
-
import { CSSVariables } from './popover.const';
|
|
11
|
+
import { CSSVariables, css as popoverCss } from './popover.const';
|
|
12
|
+
import { twMerge } from '../tw';
|
|
12
13
|
|
|
13
14
|
import type { PopoverParams } from '@/types/utils/popover/popover';
|
|
14
15
|
import { PopoverEvent } from '@/types/utils/popover/popover-event';
|
|
@@ -71,6 +72,12 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
71
72
|
*/
|
|
72
73
|
private _size: { height: number; width: number } | undefined;
|
|
73
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Original order of item elements in the popover container.
|
|
77
|
+
* Cached on first search so we can restore order when query is cleared.
|
|
78
|
+
*/
|
|
79
|
+
private originalItemOrder: Element[] | undefined;
|
|
80
|
+
|
|
74
81
|
/**
|
|
75
82
|
* Construct the instance
|
|
76
83
|
* @param params - popover params
|
|
@@ -102,6 +109,7 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
102
109
|
|
|
103
110
|
if (this.nodes.popoverContainer !== null) {
|
|
104
111
|
this.listeners.on(this.nodes.popoverContainer, 'mouseover', (event: Event) => this.handleHover(event));
|
|
112
|
+
this.listeners.on(this.nodes.popoverContainer, 'mouseleave', (event: Event) => this.handleMouseLeave(event));
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
if (params.searchable) {
|
|
@@ -225,15 +233,16 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
225
233
|
this.flipper?.activate(this.flippableElements);
|
|
226
234
|
|
|
227
235
|
// Focus the first item: search field if present, otherwise first menu item
|
|
228
|
-
|
|
236
|
+
queueMicrotask(() => {
|
|
229
237
|
this.focusInitialElement();
|
|
230
238
|
});
|
|
231
239
|
}
|
|
232
240
|
|
|
233
241
|
/**
|
|
234
242
|
* Focuses the initial element when popover is shown.
|
|
235
|
-
*
|
|
236
|
-
*
|
|
243
|
+
* When a search field is present, it receives focus so the user can type immediately.
|
|
244
|
+
* When autoFocusFirstItem is false, no item is pre-focused — focus only appears
|
|
245
|
+
* after the user begins keyboard navigation.
|
|
237
246
|
*/
|
|
238
247
|
private focusInitialElement(): void {
|
|
239
248
|
if (this.search) {
|
|
@@ -242,6 +251,10 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
242
251
|
return;
|
|
243
252
|
}
|
|
244
253
|
|
|
254
|
+
if (this.params.autoFocusFirstItem === false) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
245
258
|
this.flipper?.focusItem(0, { skipNextTab: true });
|
|
246
259
|
}
|
|
247
260
|
|
|
@@ -363,7 +376,20 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
363
376
|
return;
|
|
364
377
|
}
|
|
365
378
|
|
|
366
|
-
|
|
379
|
+
/**
|
|
380
|
+
* If the pointer moved into the nested popover (e.g. user is about to click
|
|
381
|
+
* an item in the sub-menu), do not destroy it.
|
|
382
|
+
*/
|
|
383
|
+
if (
|
|
384
|
+
this.nestedPopover !== undefined &&
|
|
385
|
+
this.nestedPopover !== null &&
|
|
386
|
+
event.target instanceof Node &&
|
|
387
|
+
this.nestedPopover.hasNode(event.target)
|
|
388
|
+
) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
this.destroyNestedPopoverIfExists(false);
|
|
367
393
|
|
|
368
394
|
this.previouslyHoveredItem = item;
|
|
369
395
|
|
|
@@ -374,6 +400,28 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
374
400
|
this.showNestedPopoverForItem(item);
|
|
375
401
|
}
|
|
376
402
|
|
|
403
|
+
/**
|
|
404
|
+
* Handles mouse leaving the popover container.
|
|
405
|
+
* Destroys nested popover unless the mouse moved into it.
|
|
406
|
+
* @param event - mouseleave event
|
|
407
|
+
*/
|
|
408
|
+
private handleMouseLeave(event: Event): void {
|
|
409
|
+
const mouseEvent = event as MouseEvent;
|
|
410
|
+
const relatedTarget = mouseEvent.relatedTarget;
|
|
411
|
+
|
|
412
|
+
if (
|
|
413
|
+
relatedTarget instanceof Node &&
|
|
414
|
+
this.nestedPopover !== undefined &&
|
|
415
|
+
this.nestedPopover !== null &&
|
|
416
|
+
this.nestedPopover.hasNode(relatedTarget)
|
|
417
|
+
) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
this.destroyNestedPopoverIfExists(false);
|
|
422
|
+
this.previouslyHoveredItem = null;
|
|
423
|
+
}
|
|
424
|
+
|
|
377
425
|
/**
|
|
378
426
|
* Sets CSS variable with position of item near which nested popover should be displayed.
|
|
379
427
|
* Is used for correct positioning of the nested popover
|
|
@@ -393,8 +441,11 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
393
441
|
|
|
394
442
|
/**
|
|
395
443
|
* Destroys existing nested popover
|
|
444
|
+
* @param restoreFocus - whether to restore keyboard focus to the trigger item after closing.
|
|
445
|
+
* Should be true for keyboard-driven closes (e.g. ArrowLeft/Escape), false for mouse-driven closes
|
|
446
|
+
* to avoid leaving a stale focus highlight on the trigger item.
|
|
396
447
|
*/
|
|
397
|
-
protected destroyNestedPopoverIfExists(): void {
|
|
448
|
+
protected destroyNestedPopoverIfExists(restoreFocus = true): void {
|
|
398
449
|
if (this.nestedPopover === undefined || this.nestedPopover === null) {
|
|
399
450
|
return;
|
|
400
451
|
}
|
|
@@ -408,8 +459,11 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
408
459
|
elementToRemove.remove();
|
|
409
460
|
this.nestedPopover = null;
|
|
410
461
|
this.flipper?.activate(this.flippableElements);
|
|
411
|
-
|
|
412
|
-
|
|
462
|
+
|
|
463
|
+
if (restoreFocus) {
|
|
464
|
+
// Focus the trigger item synchronously to ensure keyboard events work immediately
|
|
465
|
+
this.focusAfterNestedPopoverClose(triggerItemElement);
|
|
466
|
+
}
|
|
413
467
|
|
|
414
468
|
this.nestedPopoverTriggerItem?.onChildrenClose();
|
|
415
469
|
// Reset trigger item so clicking the same item again will open the nested popover
|
|
@@ -457,6 +511,7 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
457
511
|
onNavigateBack: this.destroyNestedPopoverIfExists.bind(this),
|
|
458
512
|
width: item.childrenWidth,
|
|
459
513
|
handleContentEditableNavigation: handleContentEditable,
|
|
514
|
+
autoFocusFirstItem: this.params.autoFocusFirstItem,
|
|
460
515
|
});
|
|
461
516
|
|
|
462
517
|
item.onChildrenOpen();
|
|
@@ -608,10 +663,13 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
608
663
|
|
|
609
664
|
popoverClone.setAttribute(DATA_ATTR.popoverOpened, 'true');
|
|
610
665
|
popoverClone.querySelector(`[${DATA_ATTR.nested}]`)?.remove();
|
|
611
|
-
document.body.appendChild(popoverClone);
|
|
612
666
|
|
|
613
667
|
const container = popoverClone.querySelector(`[${DATA_ATTR.popoverContainer}]`) as HTMLElement;
|
|
614
668
|
|
|
669
|
+
container.className = twMerge(container.className, popoverCss.popoverContainerOpened);
|
|
670
|
+
|
|
671
|
+
document.body.appendChild(popoverClone);
|
|
672
|
+
|
|
615
673
|
size.height = container.offsetHeight;
|
|
616
674
|
size.width = container.offsetWidth;
|
|
617
675
|
popoverClone.remove();
|
|
@@ -690,7 +748,21 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
690
748
|
* @param query - search query text
|
|
691
749
|
*/
|
|
692
750
|
public override filterItems(query: string): void {
|
|
693
|
-
|
|
751
|
+
if (query === '') {
|
|
752
|
+
this.onSearch({
|
|
753
|
+
query,
|
|
754
|
+
items: this.itemsDefault as unknown as SearchableItem[],
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const scoredItems = this.itemsDefault
|
|
761
|
+
.map(item => ({ item, score: scoreSearchMatch(item, query) }))
|
|
762
|
+
.filter(({ score }) => score > 0)
|
|
763
|
+
.sort((a, b) => b.score - a.score);
|
|
764
|
+
|
|
765
|
+
const matchingItems = scoredItems.map(({ item }) => item);
|
|
694
766
|
|
|
695
767
|
this.onSearch({
|
|
696
768
|
query,
|
|
@@ -742,6 +814,13 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
742
814
|
});
|
|
743
815
|
}
|
|
744
816
|
|
|
817
|
+
// Reorder DOM elements to reflect ranking
|
|
818
|
+
if (!isEmptyQuery && matchingItems.length > 0) {
|
|
819
|
+
this.reorderItemsByRank(matchingItems);
|
|
820
|
+
} else if (isEmptyQuery && this.originalItemOrder !== undefined) {
|
|
821
|
+
this.restoreOriginalItemOrder();
|
|
822
|
+
}
|
|
823
|
+
|
|
745
824
|
this.toggleNothingFoundMessage(isNothingFound);
|
|
746
825
|
|
|
747
826
|
/** List of elements available for keyboard navigation considering search query applied */
|
|
@@ -767,4 +846,47 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
767
846
|
this.flipper.focusItem(0, { skipNextTab: true });
|
|
768
847
|
}
|
|
769
848
|
};
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Reorders DOM children of the items container to match the ranked order.
|
|
852
|
+
* Caches the original order on first call so it can be restored later.
|
|
853
|
+
* @param rankedItems - items sorted by search relevance (best first)
|
|
854
|
+
*/
|
|
855
|
+
private reorderItemsByRank(rankedItems: PopoverItemDefault[]): void {
|
|
856
|
+
if (this.originalItemOrder === undefined && this.nodes.items !== null) {
|
|
857
|
+
this.originalItemOrder = Array.from(this.nodes.items.children);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const itemsContainer = this.nodes.items;
|
|
861
|
+
|
|
862
|
+
if (itemsContainer === null) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
for (const item of rankedItems) {
|
|
867
|
+
const el = item.getElement();
|
|
868
|
+
|
|
869
|
+
if (el !== null) {
|
|
870
|
+
itemsContainer.appendChild(el);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/**
|
|
876
|
+
* Restores the original DOM order of items container children.
|
|
877
|
+
* Called when the search query is cleared.
|
|
878
|
+
*/
|
|
879
|
+
private restoreOriginalItemOrder(): void {
|
|
880
|
+
const itemsContainer = this.nodes.items;
|
|
881
|
+
|
|
882
|
+
if (itemsContainer === null || this.originalItemOrder === undefined) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
for (const el of this.originalItemOrder) {
|
|
887
|
+
itemsContainer.appendChild(el);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
this.originalItemOrder = undefined;
|
|
891
|
+
}
|
|
770
892
|
}
|
|
@@ -226,7 +226,7 @@ export class PopoverInline extends PopoverDesktop {
|
|
|
226
226
|
this.nodes.popover.style.height = heightPx;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
queueMicrotask(() => {
|
|
230
230
|
this.flipper?.deactivate();
|
|
231
231
|
this.flipper?.activate(this.flippableElements);
|
|
232
232
|
});
|
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export const css = {
|
|
7
7
|
// Popover container - base styles
|
|
8
|
-
popoverContainer: 'absolute flex flex-col overflow-hidden box-border opacity-0 pointer-events-none p-0 border-none z-4 max-h-0 min-w-(--width) w-(--width) rounded-xl
|
|
8
|
+
popoverContainer: 'absolute flex flex-col overflow-hidden box-border opacity-0 pointer-events-none p-0 border-none z-4 max-h-0 min-w-(--width) w-(--width) rounded-xl text-sm left-(--popover-left) top-(--popover-top) bg-popover-bg',
|
|
9
9
|
|
|
10
10
|
// Popover container - mobile styles (applied conditionally)
|
|
11
11
|
// Reset left/top from base class since inset shorthand may not properly override them in twMerge
|
|
12
12
|
popoverContainerMobile: 'fixed max-w-none rounded-[10px] min-w-[calc(100%-var(--offset)*2)] left-auto top-auto inset-[auto_var(--offset)_calc(var(--offset)+env(safe-area-inset-bottom))_var(--offset)]',
|
|
13
13
|
|
|
14
14
|
// Popover container - opened state
|
|
15
|
-
popoverContainerOpened: 'opacity-100 pointer-events-auto p-1.5 max-h-(--max-height) border
|
|
15
|
+
popoverContainerOpened: 'opacity-100 pointer-events-auto p-1.5 max-h-(--max-height) border-none animate-panel-showing',
|
|
16
16
|
|
|
17
17
|
// Popover overlay
|
|
18
18
|
popoverOverlay: 'hidden bg-dark',
|
|
19
19
|
|
|
20
|
-
items: 'overflow-y-auto overscroll-contain
|
|
20
|
+
items: 'overflow-y-auto overscroll-contain',
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -360,7 +360,17 @@ class Tooltip {
|
|
|
360
360
|
const shownClass = Array.isArray(this.CSS.tooltipShown) ? this.CSS.tooltipShown[0] : this.CSS.tooltipShown;
|
|
361
361
|
const isShown = this.nodes.wrapper.classList.contains(shownClass);
|
|
362
362
|
|
|
363
|
-
|
|
363
|
+
/**
|
|
364
|
+
* Use `!important` priority when hiding so the inline style wins over the
|
|
365
|
+
* author stylesheet's `all: initial !important` rule (which sets visibility
|
|
366
|
+
* to `visible`). Inline `!important` > author `!important` in the cascade.
|
|
367
|
+
* When showing, normal priority is sufficient (no competing rule sets visible).
|
|
368
|
+
*/
|
|
369
|
+
this.nodes.wrapper.style.setProperty(
|
|
370
|
+
VISIBILITY_PROPERTY,
|
|
371
|
+
isShown ? VISIBILITY_VISIBLE : VISIBILITY_HIDDEN,
|
|
372
|
+
isShown ? '' : 'important'
|
|
373
|
+
);
|
|
364
374
|
this.nodes.wrapper.setAttribute(ARIA_HIDDEN_ATTRIBUTE, isShown ? ARIA_HIDDEN_FALSE : ARIA_HIDDEN_TRUE);
|
|
365
375
|
this.nodes.wrapper.setAttribute('data-blok-shown', isShown ? 'true' : 'false');
|
|
366
376
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useEffect, useRef, forwardRef } from 'react';
|
|
2
|
+
import { getHolder } from './holder-map';
|
|
3
|
+
import type { BlokContentProps } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Component that provides the DOM mount point for a Blok editor.
|
|
7
|
+
* Renders a <div> and adopts the editor's detached holder DOM into it.
|
|
8
|
+
* When editor is null, renders an empty div (for layout stability).
|
|
9
|
+
* Passes through all standard HTML div attributes (className, style, etc.).
|
|
10
|
+
*/
|
|
11
|
+
export const BlokContent = forwardRef<HTMLDivElement, BlokContentProps>(
|
|
12
|
+
function BlokContent({ editor, ...divProps }, ref) {
|
|
13
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
14
|
+
|
|
15
|
+
const setRefs = (node: HTMLDivElement | null): void => {
|
|
16
|
+
containerRef.current = node;
|
|
17
|
+
if (typeof ref === 'function') {
|
|
18
|
+
ref(node);
|
|
19
|
+
} else if (ref !== null && ref !== undefined) {
|
|
20
|
+
const mutableRef = ref;
|
|
21
|
+
|
|
22
|
+
mutableRef.current = node;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (editor === null || containerRef.current === null) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const holder = getHolder(editor);
|
|
32
|
+
|
|
33
|
+
if (holder === undefined) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
containerRef.current.appendChild(holder);
|
|
38
|
+
|
|
39
|
+
return (): void => {
|
|
40
|
+
holder.remove();
|
|
41
|
+
};
|
|
42
|
+
}, [editor]);
|
|
43
|
+
|
|
44
|
+
return <div ref={setRefs} {...divProps} />;
|
|
45
|
+
}
|
|
46
|
+
);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level WeakMap associating editor instances with their detached holder divs.
|
|
3
|
+
* WeakMap ensures no memory leaks — when the editor is garbage collected, the holder reference is released.
|
|
4
|
+
*/
|
|
5
|
+
const holders = new WeakMap<WeakKey, HTMLDivElement>();
|
|
6
|
+
|
|
7
|
+
export function setHolder(editor: WeakKey, holder: HTMLDivElement): void {
|
|
8
|
+
holders.set(editor, holder);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getHolder(editor: WeakKey): HTMLDivElement | undefined {
|
|
12
|
+
return holders.get(editor);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function removeHolder(editor: WeakKey): void {
|
|
16
|
+
holders.delete(editor);
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BlokConfig, Blok } from '@/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for useBlok hook.
|
|
5
|
+
* Same as BlokConfig but without `holder` — the holder is managed by BlokContent.
|
|
6
|
+
*/
|
|
7
|
+
export interface UseBlokConfig extends Omit<BlokConfig, 'holder'> {}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Props for the BlokContent component.
|
|
11
|
+
* Extends standard div HTML attributes so className, style, id, etc. pass through.
|
|
12
|
+
*/
|
|
13
|
+
export interface BlokContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
14
|
+
/** The Blok editor instance returned by useBlok. Pass null if editor is not ready yet. */
|
|
15
|
+
editor: Blok | null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { useState, useEffect, useRef, useMemo, type DependencyList } from 'react';
|
|
2
|
+
import { Blok as BlokRuntime } from '../blok';
|
|
3
|
+
import { setHolder, removeHolder } from './holder-map';
|
|
4
|
+
import type { Blok } from '@/types';
|
|
5
|
+
import type { UseBlokConfig } from './types';
|
|
6
|
+
|
|
7
|
+
interface EditorInstanceState {
|
|
8
|
+
editor: Blok | null;
|
|
9
|
+
holder: HTMLDivElement | null;
|
|
10
|
+
destroyTimeout: ReturnType<typeof setTimeout> | null;
|
|
11
|
+
isDestroyed: boolean;
|
|
12
|
+
/** Opaque token identifying which deps cycle created this editor */
|
|
13
|
+
depsToken: Record<string, unknown> | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* React hook that manages a Blok editor instance lifecycle.
|
|
18
|
+
*
|
|
19
|
+
* Creates a detached holder div, instantiates Blok, and returns the instance
|
|
20
|
+
* once `isReady` resolves. Handles StrictMode double-mount by deferring
|
|
21
|
+
* destroy via `setTimeout(0)` and cancelling on remount.
|
|
22
|
+
*
|
|
23
|
+
* @param config - Blok configuration without `holder` (managed internally)
|
|
24
|
+
* @param deps - Optional dependency array; when values change, the editor is recreated
|
|
25
|
+
* @returns The Blok instance once ready, or null during initialization / SSR
|
|
26
|
+
*/
|
|
27
|
+
export function useBlok(config: UseBlokConfig, deps?: DependencyList): Blok | null {
|
|
28
|
+
const [editor, setEditor] = useState<Blok | null>(null);
|
|
29
|
+
const configRef = useRef(config);
|
|
30
|
+
configRef.current = config;
|
|
31
|
+
|
|
32
|
+
const stateRef = useRef<EditorInstanceState>({
|
|
33
|
+
editor: null,
|
|
34
|
+
holder: null,
|
|
35
|
+
destroyTimeout: null,
|
|
36
|
+
isDestroyed: false,
|
|
37
|
+
depsToken: null,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// A new token is created only when deps change (useMemo compares deps).
|
|
41
|
+
// StrictMode re-runs see the SAME token. Deps changes produce a NEW token.
|
|
42
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
43
|
+
const depsToken = useMemo(() => ({}), deps ?? []);
|
|
44
|
+
|
|
45
|
+
// Main lifecycle effect
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (typeof window === 'undefined') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const state = stateRef.current;
|
|
52
|
+
|
|
53
|
+
// Cancel pending deferred destroy (StrictMode remount)
|
|
54
|
+
if (state.destroyTimeout !== null) {
|
|
55
|
+
clearTimeout(state.destroyTimeout);
|
|
56
|
+
state.destroyTimeout = null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Reuse editor on StrictMode remount (same deps cycle)
|
|
60
|
+
if (state.editor !== null && !state.isDestroyed && state.depsToken === depsToken) {
|
|
61
|
+
setEditor(state.editor);
|
|
62
|
+
|
|
63
|
+
return (): void => {
|
|
64
|
+
deferDestroy(state, setEditor);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Destroy leftover editor from a previous deps cycle
|
|
69
|
+
if (state.editor !== null && !state.isDestroyed) {
|
|
70
|
+
removeHolder(state.editor);
|
|
71
|
+
try {
|
|
72
|
+
state.editor.destroy();
|
|
73
|
+
} catch {
|
|
74
|
+
// destroy may throw — still clean up state
|
|
75
|
+
}
|
|
76
|
+
state.editor = null;
|
|
77
|
+
state.holder = null;
|
|
78
|
+
state.isDestroyed = true;
|
|
79
|
+
setEditor(null);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Create detached holder
|
|
83
|
+
const holder = document.createElement('div');
|
|
84
|
+
state.holder = holder;
|
|
85
|
+
state.isDestroyed = false;
|
|
86
|
+
state.depsToken = depsToken;
|
|
87
|
+
|
|
88
|
+
// Wrap callbacks via ref so they never go stale
|
|
89
|
+
const currentConfig = configRef.current;
|
|
90
|
+
const blokConfig = {
|
|
91
|
+
...currentConfig,
|
|
92
|
+
holder,
|
|
93
|
+
onReady: (): void => {
|
|
94
|
+
configRef.current.onReady?.();
|
|
95
|
+
},
|
|
96
|
+
onChange: (...args: Parameters<NonNullable<UseBlokConfig['onChange']>>): void => {
|
|
97
|
+
configRef.current.onChange?.(...args);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const blok = new BlokRuntime(blokConfig) as unknown as Blok;
|
|
102
|
+
state.editor = blok;
|
|
103
|
+
setHolder(blok, holder);
|
|
104
|
+
|
|
105
|
+
void blok.isReady
|
|
106
|
+
.then(() => {
|
|
107
|
+
if (state.editor === blok && !state.isDestroyed) {
|
|
108
|
+
setEditor(blok);
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
.catch(() => {
|
|
112
|
+
if (state.editor === blok && !state.isDestroyed) {
|
|
113
|
+
removeHolder(blok);
|
|
114
|
+
try {
|
|
115
|
+
blok.destroy();
|
|
116
|
+
} catch {
|
|
117
|
+
// destroy may also throw — still clean up state
|
|
118
|
+
}
|
|
119
|
+
state.editor = null;
|
|
120
|
+
state.holder = null;
|
|
121
|
+
state.isDestroyed = true;
|
|
122
|
+
setEditor(null);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return (): void => {
|
|
127
|
+
deferDestroy(state, setEditor);
|
|
128
|
+
};
|
|
129
|
+
}, [depsToken]);
|
|
130
|
+
|
|
131
|
+
// Reactive: readOnly
|
|
132
|
+
const { readOnly } = config;
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (editor === null) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
void editor.readOnly.set(readOnly ?? false);
|
|
138
|
+
}, [editor, readOnly]);
|
|
139
|
+
|
|
140
|
+
// Reactive: autofocus
|
|
141
|
+
const { autofocus } = config;
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (editor === null || !autofocus) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
editor.focus();
|
|
147
|
+
}, [editor, autofocus]);
|
|
148
|
+
|
|
149
|
+
return editor;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function deferDestroy(
|
|
153
|
+
state: EditorInstanceState,
|
|
154
|
+
setEditorState: React.Dispatch<React.SetStateAction<Blok | null>>
|
|
155
|
+
): void {
|
|
156
|
+
/* eslint-disable no-param-reassign -- intentional mutation of shared state ref */
|
|
157
|
+
state.destroyTimeout = setTimeout(() => {
|
|
158
|
+
if (state.editor !== null) {
|
|
159
|
+
removeHolder(state.editor);
|
|
160
|
+
try {
|
|
161
|
+
state.editor.destroy();
|
|
162
|
+
} catch {
|
|
163
|
+
// destroy may throw — still clean up state
|
|
164
|
+
}
|
|
165
|
+
state.editor = null;
|
|
166
|
+
state.holder = null;
|
|
167
|
+
state.isDestroyed = true;
|
|
168
|
+
state.destroyTimeout = null;
|
|
169
|
+
setEditorState(null);
|
|
170
|
+
}
|
|
171
|
+
}, 0);
|
|
172
|
+
/* eslint-enable no-param-reassign */
|
|
173
|
+
}
|
|
@@ -148,65 +148,6 @@ export const PlaceholderHiddenWithContent: Story = {
|
|
|
148
148
|
},
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
-
/**
|
|
152
|
-
* Typing hides placeholder, clearing restores it.
|
|
153
|
-
*/
|
|
154
|
-
export const TypeAndClearPlaceholder: Story = {
|
|
155
|
-
args: {
|
|
156
|
-
placeholder: DEFAULT_PLACEHOLDER,
|
|
157
|
-
data: undefined,
|
|
158
|
-
},
|
|
159
|
-
parameters: {
|
|
160
|
-
chromatic: { delay: 500 },
|
|
161
|
-
},
|
|
162
|
-
play: async ({ canvasElement, step }) => {
|
|
163
|
-
await step('Wait for editor to initialize', async () => {
|
|
164
|
-
await waitFor(
|
|
165
|
-
() => {
|
|
166
|
-
const block = canvasElement.querySelector(BLOCK_TESTID);
|
|
167
|
-
|
|
168
|
-
expect(block).toBeInTheDocument();
|
|
169
|
-
},
|
|
170
|
-
TIMEOUT_INIT
|
|
171
|
-
);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
await step('Focus and type to hide placeholder', async () => {
|
|
175
|
-
const block = canvasElement.querySelector(BLOCK_TESTID);
|
|
176
|
-
const contentEditable = block?.querySelector(CONTENTEDITABLE_SELECTOR);
|
|
177
|
-
|
|
178
|
-
if (contentEditable) {
|
|
179
|
-
await userEvent.click(contentEditable);
|
|
180
|
-
await userEvent.keyboard('Hello world');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
await waitFor(
|
|
184
|
-
() => {
|
|
185
|
-
expect(contentEditable?.textContent).toContain('Hello world');
|
|
186
|
-
},
|
|
187
|
-
TIMEOUT_ACTION
|
|
188
|
-
);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
await step('Clear content to restore placeholder', async () => {
|
|
192
|
-
const block = canvasElement.querySelector(BLOCK_TESTID);
|
|
193
|
-
const contentEditable = block?.querySelector(CONTENTEDITABLE_SELECTOR);
|
|
194
|
-
|
|
195
|
-
if (contentEditable) {
|
|
196
|
-
await userEvent.tripleClick(contentEditable);
|
|
197
|
-
await userEvent.keyboard('{Backspace}');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
await waitFor(
|
|
201
|
-
() => {
|
|
202
|
-
expect(contentEditable?.textContent?.trim()).toBe('');
|
|
203
|
-
},
|
|
204
|
-
TIMEOUT_ACTION
|
|
205
|
-
);
|
|
206
|
-
});
|
|
207
|
-
},
|
|
208
|
-
};
|
|
209
|
-
|
|
210
151
|
/**
|
|
211
152
|
* Multiple blocks - only first empty block shows placeholder.
|
|
212
153
|
*/
|