@jackuait/blok 0.7.3-beta.4 → 0.8.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 +2 -2
- package/dist/chunks/{blok-CdxHhr5i.mjs → blok-CdiMFzDz.mjs} +2256 -2141
- package/dist/chunks/{constants-C_H9o9Ao.mjs → constants-CjWRVOdm.mjs} +227 -190
- package/dist/chunks/{i18next-loader-D5HxE5ZQ.mjs → i18next-loader-p-7ioTwr.mjs} +1 -1
- package/dist/chunks/{lightweight-i18n-Safdy0ua.mjs → lightweight-i18n-BPeH69Dl.mjs} +14 -1
- package/dist/{messages-BbLCMWln2.mjs → chunks/messages--aM83pib2.mjs} +14 -1
- package/dist/chunks/{messages-ni0ahgYk2.mjs → messages-4OvVdaG52.mjs} +14 -1
- package/dist/chunks/{messages-DnPkoMz1.mjs → messages-5ohIWynJ.mjs} +14 -1
- package/dist/chunks/{messages-BjkDJuqh.mjs → messages-5thhSeME.mjs} +14 -1
- package/dist/chunks/{messages-hngFJrES2.mjs → messages-8pf7gRQm2.mjs} +14 -1
- package/dist/{messages-eCyczLYY.mjs → chunks/messages-B-i-d1Bc.mjs} +14 -1
- package/dist/chunks/{messages-CRxkRJRN.mjs → messages-B9zocutJ.mjs} +14 -1
- package/dist/{messages-pgqtPci-.mjs → chunks/messages-BAC7nLeM.mjs} +14 -1
- package/dist/chunks/{messages-DjOY_EqX.mjs → messages-BARPMN7R.mjs} +14 -1
- package/dist/{messages-Bsz7Qgj_.mjs → chunks/messages-BAgTIgPH.mjs} +15 -2
- package/dist/chunks/{messages-Cb-x47kY2.mjs → messages-BDTgiBJY2.mjs} +14 -1
- package/dist/chunks/{messages-BM1Su_Uy2.mjs → messages-BHf_VcXb2.mjs} +14 -1
- package/dist/{messages-wRvz0vQ3.mjs → chunks/messages-BIrkzbBP.mjs} +14 -1
- package/dist/{messages-DB9U3VIh.mjs → chunks/messages-BKjLgO5d.mjs} +14 -1
- package/dist/{messages-gldjQk7M.mjs → chunks/messages-BMzmli1K.mjs} +14 -1
- package/dist/chunks/{messages-CficsmSH2.mjs → messages-BO_jtRbZ2.mjs} +14 -1
- package/dist/chunks/{messages-kHTrX3wo2.mjs → messages-B_fFjpX12.mjs} +14 -1
- package/dist/{messages-BU9luYgO.mjs → chunks/messages-Bdk5tBNu.mjs} +14 -1
- package/dist/{messages-CRMZ79Xf.mjs → chunks/messages-BgaGPFuy2.mjs} +14 -1
- package/dist/{messages-DCOKudVN.mjs → chunks/messages-BsYzg2le.mjs} +14 -1
- package/dist/{messages-B9qltgXa.mjs → chunks/messages-BtS6JWMT.mjs} +14 -1
- package/dist/{messages-Cgy54529.mjs → chunks/messages-BvlSf_pu.mjs} +14 -1
- package/dist/{messages-oH0ADQ362.mjs → chunks/messages-C03I_oR-2.mjs} +14 -1
- package/dist/{messages-C8iAUPzI.mjs → chunks/messages-CDJLoStb.mjs} +14 -1
- package/dist/chunks/{messages-ClOxDE0y2.mjs → messages-CH_cexo62.mjs} +14 -1
- package/dist/{messages-DkkrjINb2.mjs → chunks/messages-CIBuZccC.mjs} +14 -1
- package/dist/chunks/{messages-BZ45xBlV.mjs → messages-CIZkNCpW.mjs} +14 -1
- package/dist/{messages-CJYE0_hr2.mjs → chunks/messages-CIugNDDO2.mjs} +14 -1
- package/dist/chunks/{messages-Cn5n0nHe2.mjs → messages-COkQfKa72.mjs} +14 -1
- package/dist/{messages-Bw-GC0m5.mjs → chunks/messages-CSpfBhlK2.mjs} +14 -1
- package/dist/chunks/{messages-tBHnC2Rj2.mjs → messages-CWp6-Y8f2.mjs} +14 -1
- package/dist/chunks/{messages-CteKp81J.mjs → messages-Co4WFeQ8.mjs} +14 -1
- package/dist/chunks/{messages-IJhiftj5.mjs → messages-CoRQE_Jc.mjs} +14 -1
- package/dist/{messages-DGZQXeav2.mjs → chunks/messages-CuRN1_ep2.mjs} +14 -1
- package/dist/{messages-BwdowdYD.mjs → chunks/messages-D0IKicWg.mjs} +14 -1
- package/dist/chunks/{messages-1C3OS98e.mjs → messages-D14soBOO.mjs} +14 -1
- package/dist/chunks/{messages-nE9Ko73n2.mjs → messages-D1SqLcxI2.mjs} +14 -1
- package/dist/{messages-COU4L-pL2.mjs → chunks/messages-D2uBlGXR2.mjs} +14 -1
- package/dist/chunks/{messages-DDr8J4FE.mjs → messages-DDpgr0B1.mjs} +14 -1
- package/dist/chunks/{messages-C232njMF2.mjs → messages-DEGzGmEQ2.mjs} +14 -1
- package/dist/chunks/{messages-6z-ULVyk.mjs → messages-DKChC8Qu.mjs} +14 -1
- package/dist/{messages-BP8ZuVaD.mjs → chunks/messages-DKCoHa5D.mjs} +14 -1
- package/dist/{messages-ruU_e2LK.mjs → chunks/messages-DPoPrTiZ.mjs} +14 -1
- package/dist/chunks/{messages-DziA-L3p.mjs → messages-DQOk-dTH.mjs} +14 -1
- package/dist/chunks/{messages-uLIUXFmU.mjs → messages-DUp8NnKT.mjs} +15 -2
- package/dist/chunks/{messages-rJdSnvyi.mjs → messages-DVg69mRj.mjs} +14 -1
- package/dist/chunks/{messages-Cq6wj6FG.mjs → messages-DeLzropc.mjs} +14 -1
- package/dist/chunks/{messages-DDRCk44J2.mjs → messages-Df69rfTF2.mjs} +15 -2
- package/dist/chunks/{messages-6EJxSImH.mjs → messages-DfsHFEWa.mjs} +14 -1
- package/dist/{messages-MaHxNgKA.mjs → chunks/messages-DgZnRQRS.mjs} +14 -1
- package/dist/{messages-B8M4YRFO2.mjs → chunks/messages-DhGHk-Ma2.mjs} +14 -1
- package/dist/{messages-3aRjZXpv.mjs → chunks/messages-Di7mfvB8.mjs} +14 -1
- package/dist/chunks/{messages-C1iQkKu82.mjs → messages-DlM9TmqS2.mjs} +14 -1
- package/dist/chunks/{messages-CejEH4FW2.mjs → messages-DmrsEYQm2.mjs} +14 -1
- package/dist/chunks/{messages-DK6pBwD2.mjs → messages-Dr-Ig3sw.mjs} +14 -1
- package/dist/{messages-BOxe7ewT.mjs → chunks/messages-DrXNb1gu.mjs} +14 -1
- package/dist/chunks/{messages-CvLXClh9.mjs → messages-EDTq4Q52.mjs} +14 -1
- package/dist/{messages-huTzItxA.mjs → chunks/messages-Ehx9YYeb2.mjs} +14 -1
- package/dist/chunks/{messages-CxTq0x772.mjs → messages-FCmAVA792.mjs} +14 -1
- package/dist/{messages-q7HzQPVt.mjs → chunks/messages-LL3Tflph.mjs} +14 -1
- package/dist/chunks/{messages-D9qyilS0.mjs → messages-N72K1hw3.mjs} +14 -1
- package/dist/chunks/{messages-C9XSSqS5.mjs → messages-Nz8C7Znm.mjs} +15 -2
- package/dist/{messages-e-KHuxtY2.mjs → chunks/messages-OIelQDL32.mjs} +14 -1
- package/dist/{messages-BQJzUYP-.mjs → chunks/messages-SsrFJhTN.mjs} +14 -1
- package/dist/{messages-CVBsztOg.mjs → chunks/messages-ohtcmr1w.mjs} +14 -1
- package/dist/chunks/{messages-CVzvKl6U.mjs → messages-stUQR58d.mjs} +14 -1
- package/dist/{messages-DlrZrm3s.mjs → chunks/messages-wUoSWFsJ2.mjs} +14 -1
- package/dist/chunks/{tools-B0YXCZFW.mjs → tools-B5yNeTZh.mjs} +1286 -872
- package/dist/full.mjs +15 -13
- package/dist/locales.mjs +81 -68
- package/dist/{messages-mVFAkdcY.mjs → messages-1_FCq0It.mjs} +14 -1
- package/dist/{chunks/messages-DoDbCS02.mjs → messages-8zo-T-Nx2.mjs} +14 -1
- package/dist/{chunks/messages-DacahKek.mjs → messages-B21zLG6b.mjs} +14 -1
- package/dist/{messages-BBgyeB_N.mjs → messages-B9ythxux.mjs} +14 -1
- package/dist/{messages-C_RPN2GV.mjs → messages-BAZK-8Zb.mjs} +14 -1
- package/dist/{messages-D6Sr5cUE.mjs → messages-BB8umWL1.mjs} +14 -1
- package/dist/{chunks/messages-Dhe8_mnQ.mjs → messages-BD_U2EnE.mjs} +14 -1
- package/dist/{messages-6G0Eia-2.mjs → messages-BRC9E_sp.mjs} +14 -1
- package/dist/{chunks/messages-BUy3odZo.mjs → messages-BSLYh59S.mjs} +14 -1
- package/dist/{messages-K7ROT6ea.mjs → messages-BSwhWcYw.mjs} +14 -1
- package/dist/{messages-BztXgybv2.mjs → messages-BTR3QlIb2.mjs} +14 -1
- package/dist/{messages-C0gyqo4h2.mjs → messages-BZXBdD_S2.mjs} +14 -1
- package/dist/{messages-BlnZ8CkJ2.mjs → messages-Bm8I_Li12.mjs} +15 -2
- package/dist/{chunks/messages-BKtWlK39.mjs → messages-BrcgNZOJ.mjs} +14 -1
- package/dist/{messages-Be1CCcsp2.mjs → messages-BzZ8LahA2.mjs} +14 -1
- package/dist/{chunks/messages-B_90PYaG.mjs → messages-C4HpNHfK.mjs} +14 -1
- package/dist/{chunks/messages-m6bLP64R2.mjs → messages-C5hD5pSd2.mjs} +14 -1
- package/dist/{chunks/messages-C3AJz_i6.mjs → messages-C7Rz00Tp.mjs} +14 -1
- package/dist/{chunks/messages-C1lqY56F2.mjs → messages-C92tAUYT2.mjs} +14 -1
- package/dist/{messages-Kye1BINC.mjs → messages-C9LsEUfG.mjs} +14 -1
- package/dist/{chunks/messages-tg78NAmW.mjs → messages-CHWfj4ik.mjs} +14 -1
- package/dist/{messages-CaJRIGUu2.mjs → messages-CHeucLGl2.mjs} +14 -1
- package/dist/{chunks/messages-DcPtg90i.mjs → messages-CIxT1nSh.mjs} +14 -1
- package/dist/{messages-C7R0m6oE2.mjs → messages-CKX9iXIb2.mjs} +14 -1
- package/dist/{messages-CzSLUJQt.mjs → messages-CKmmJ9tW.mjs} +14 -1
- package/dist/{messages-DpY9s4Qi2.mjs → messages-CTFwu5-h2.mjs} +14 -1
- package/dist/{messages-DAssrN5L2.mjs → messages-CTPFrtK92.mjs} +14 -1
- package/dist/{messages-BZgGD0zf2.mjs → messages-CWzET_9H2.mjs} +14 -1
- package/dist/{messages-CkmVEyEQ2.mjs → messages-CkIRmpfZ2.mjs} +14 -1
- package/dist/{messages-B2bHgIcC2.mjs → messages-CmoTIebG2.mjs} +14 -1
- package/dist/{messages-DZbsds_k2.mjs → messages-Co26RSCV2.mjs} +14 -1
- package/dist/{messages-DrouoDgp.mjs → messages-CqNzlpWi.mjs} +15 -2
- package/dist/{messages-m1uf_AMy2.mjs → messages-CrWsU4Xw2.mjs} +14 -1
- package/dist/{messages-TseLyyoU.mjs → messages-CsmTziC6.mjs} +14 -1
- package/dist/{messages-CAffVeAE2.mjs → messages-CsnglxbV2.mjs} +14 -1
- package/dist/{messages-CE305J0p.mjs → messages-Cu7Lr1wp.mjs} +14 -1
- package/dist/{chunks/messages-Ul43l29K2.mjs → messages-Cy3Ne_M9.mjs} +14 -1
- package/dist/{chunks/messages-CzCqu58X2.mjs → messages-CzZAfGif.mjs} +14 -1
- package/dist/{messages-C_4VGaBC.mjs → messages-D5rnT-BC.mjs} +14 -1
- package/dist/{chunks/messages-yJmwc3zD.mjs → messages-D8iCBMg7.mjs} +14 -1
- package/dist/{chunks/messages-BtNOlsMj.mjs → messages-DDJOu049.mjs} +14 -1
- package/dist/{chunks/messages-CnzaTbel.mjs → messages-DDiP6yex.mjs} +14 -1
- package/dist/{chunks/messages-DotEkUpQ.mjs → messages-DHJ1fZLL.mjs} +14 -1
- package/dist/{chunks/messages-3ePgbbpx2.mjs → messages-DToWAonn2.mjs} +14 -1
- package/dist/{messages-BxQ1gzJF2.mjs → messages-DV29fJMD2.mjs} +14 -1
- package/dist/{chunks/messages-DJWRON2S.mjs → messages-D_-rh8gl.mjs} +14 -1
- package/dist/{chunks/messages-D6SAC8Lc2.mjs → messages-D_cAZ4Ic2.mjs} +14 -1
- package/dist/{chunks/messages-pKUiAqlX2.mjs → messages-Dc7ZzqYN.mjs} +14 -1
- package/dist/{chunks/messages-JRavIeeW.mjs → messages-DiSeSE8p.mjs} +14 -1
- package/dist/{chunks/messages-DbS9Oibb.mjs → messages-Djhu5RJd.mjs} +14 -1
- package/dist/{messages-BdJ1lCo_.mjs → messages-Dr9L1psl.mjs} +15 -2
- package/dist/{messages-voUPclMU.mjs → messages-EIeWKoc5.mjs} +14 -1
- package/dist/{messages-GrVSCmXW.mjs → messages-EwoT2jof.mjs} +14 -1
- package/dist/{chunks/messages-B_nVGWdk.mjs → messages-F7cRf-20.mjs} +14 -1
- package/dist/{chunks/messages-Dxrg70jo.mjs → messages-JZhs_0pf.mjs} +14 -1
- package/dist/{messages-CB0RKGVM.mjs → messages-JwMkLben.mjs} +14 -1
- package/dist/{messages-Cb5JJ8C_2.mjs → messages-LyzjEEIj2.mjs} +14 -1
- package/dist/{chunks/messages-DQ4VyVJf2.mjs → messages-SepwOOcg.mjs} +14 -1
- package/dist/{chunks/messages-DfTU2I8J.mjs → messages-TI0u6Ked.mjs} +14 -1
- package/dist/{chunks/messages-D7aoKTPD.mjs → messages-Tx25QErT.mjs} +14 -1
- package/dist/{chunks/messages-D9nReG4C2.mjs → messages-bRqMCja-2.mjs} +14 -1
- package/dist/{chunks/messages-h474TGR72.mjs → messages-lEyiemqU2.mjs} +14 -1
- package/dist/{messages-BENRci-_2.mjs → messages-mVLfVtQX2.mjs} +14 -1
- package/dist/{messages-CEhkWwqI.mjs → messages-ouO9js8Z.mjs} +14 -1
- package/dist/{messages--XEfVx572.mjs → messages-ouRGTAKo2.mjs} +14 -1
- package/dist/{chunks/messages-DNrK8lCg2.mjs → messages-qV14y_oA2.mjs} +14 -1
- package/dist/{chunks/messages-Yk__PXZQ.mjs → messages-rM6YFLZH.mjs} +15 -2
- package/dist/react.mjs +2 -2
- package/dist/tools.mjs +3 -3
- package/package.json +2 -2
- package/src/components/block/style-manager.ts +1 -1
- package/src/components/blocks.ts +26 -54
- package/src/components/constants/data-attributes.ts +0 -2
- package/src/components/i18n/locales/am/messages.json +14 -1
- package/src/components/i18n/locales/ar/messages.json +14 -1
- package/src/components/i18n/locales/az/messages.json +14 -1
- package/src/components/i18n/locales/bg/messages.json +15 -2
- package/src/components/i18n/locales/bn/messages.json +14 -1
- package/src/components/i18n/locales/bs/messages.json +14 -1
- package/src/components/i18n/locales/cs/messages.json +14 -1
- package/src/components/i18n/locales/da/messages.json +14 -1
- package/src/components/i18n/locales/de/messages.json +14 -1
- package/src/components/i18n/locales/dv/messages.json +14 -1
- package/src/components/i18n/locales/el/messages.json +14 -1
- package/src/components/i18n/locales/en/messages.json +14 -1
- package/src/components/i18n/locales/es/messages.json +14 -1
- package/src/components/i18n/locales/et/messages.json +15 -2
- package/src/components/i18n/locales/fa/messages.json +14 -1
- package/src/components/i18n/locales/fi/messages.json +14 -1
- package/src/components/i18n/locales/fil/messages.json +14 -1
- package/src/components/i18n/locales/fr/messages.json +14 -1
- package/src/components/i18n/locales/gu/messages.json +14 -1
- package/src/components/i18n/locales/he/messages.json +14 -1
- package/src/components/i18n/locales/hi/messages.json +14 -1
- package/src/components/i18n/locales/hr/messages.json +14 -1
- package/src/components/i18n/locales/hu/messages.json +14 -1
- package/src/components/i18n/locales/hy/messages.json +14 -1
- package/src/components/i18n/locales/id/messages.json +14 -1
- package/src/components/i18n/locales/it/messages.json +14 -1
- package/src/components/i18n/locales/ja/messages.json +14 -1
- package/src/components/i18n/locales/ka/messages.json +14 -1
- package/src/components/i18n/locales/km/messages.json +14 -1
- package/src/components/i18n/locales/kn/messages.json +14 -1
- package/src/components/i18n/locales/ko/messages.json +14 -1
- package/src/components/i18n/locales/ku/messages.json +14 -1
- package/src/components/i18n/locales/lo/messages.json +14 -1
- package/src/components/i18n/locales/lt/messages.json +14 -1
- package/src/components/i18n/locales/lv/messages.json +14 -1
- package/src/components/i18n/locales/mk/messages.json +14 -1
- package/src/components/i18n/locales/ml/messages.json +14 -1
- package/src/components/i18n/locales/mn/messages.json +14 -1
- package/src/components/i18n/locales/mr/messages.json +14 -1
- package/src/components/i18n/locales/ms/messages.json +14 -1
- package/src/components/i18n/locales/my/messages.json +14 -1
- package/src/components/i18n/locales/ne/messages.json +14 -1
- package/src/components/i18n/locales/nl/messages.json +14 -1
- package/src/components/i18n/locales/no/messages.json +14 -1
- package/src/components/i18n/locales/pa/messages.json +14 -1
- package/src/components/i18n/locales/pl/messages.json +14 -1
- package/src/components/i18n/locales/ps/messages.json +14 -1
- package/src/components/i18n/locales/pt/messages.json +14 -1
- package/src/components/i18n/locales/ro/messages.json +14 -1
- package/src/components/i18n/locales/ru/messages.json +15 -2
- package/src/components/i18n/locales/sd/messages.json +14 -1
- package/src/components/i18n/locales/si/messages.json +14 -1
- package/src/components/i18n/locales/sk/messages.json +14 -1
- package/src/components/i18n/locales/sl/messages.json +14 -1
- package/src/components/i18n/locales/sq/messages.json +14 -1
- package/src/components/i18n/locales/sr/messages.json +14 -1
- package/src/components/i18n/locales/sv/messages.json +14 -1
- package/src/components/i18n/locales/sw/messages.json +14 -1
- package/src/components/i18n/locales/ta/messages.json +14 -1
- package/src/components/i18n/locales/te/messages.json +14 -1
- package/src/components/i18n/locales/th/messages.json +14 -1
- package/src/components/i18n/locales/tr/messages.json +14 -1
- package/src/components/i18n/locales/ug/messages.json +14 -1
- package/src/components/i18n/locales/uk/messages.json +15 -2
- package/src/components/i18n/locales/ur/messages.json +14 -1
- package/src/components/i18n/locales/vi/messages.json +14 -1
- package/src/components/i18n/locales/yi/messages.json +14 -1
- package/src/components/i18n/locales/zh/messages.json +14 -1
- package/src/components/icons/index.ts +52 -6
- package/src/components/inline-tools/inline-tool-link.ts +202 -5
- package/src/components/inline-tools/inline-tool-marker.ts +166 -23
- package/src/components/inline-tools/inline-tool-strikethrough.ts +408 -0
- package/src/components/inline-tools/inline-tool-underline.ts +408 -0
- package/src/components/inline-tools/utils/formatting-range-utils.ts +10 -1
- package/src/components/modules/blockManager/blockManager.ts +2 -2
- package/src/components/modules/blockManager/operations.ts +2 -2
- package/src/components/modules/blockManager/repository.ts +1 -9
- package/src/components/modules/blockManager/types.ts +1 -1
- package/src/components/modules/drag/operations/DragOperations.ts +45 -6
- package/src/components/modules/paste/google-docs-preprocessor.ts +69 -2
- package/src/components/modules/paste/handlers/blok-data-handler.ts +96 -19
- package/src/components/modules/rectangleSelection.ts +48 -0
- package/src/components/modules/renderer.ts +2 -0
- package/src/components/modules/toolbar/blockSettings.ts +1 -1
- package/src/components/modules/toolbar/index.ts +26 -2
- package/src/components/modules/toolbar/plus-button.ts +15 -5
- package/src/components/selection/fake-background/index.ts +9 -10
- package/src/components/shared/color-picker.ts +116 -95
- package/src/components/shared/color-presets.ts +30 -2
- package/src/components/ui/toolbox.ts +36 -7
- package/src/components/utils/color-mapping.ts +43 -1
- package/src/components/utils/color-migration.ts +37 -0
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +4 -3
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +5 -39
- package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
- package/src/components/utils/popover/components/popover-item/popover-item.ts +11 -0
- package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -3
- package/src/components/utils/popover/components/search-input/search-input.ts +1 -32
- package/src/components/utils/popover/popover-abstract.ts +2 -4
- package/src/components/utils/popover/popover-desktop.ts +1 -16
- package/src/components/utils/popover/popover-inline.ts +1 -2
- package/src/components/utils/popover/popover-mobile.ts +2 -2
- package/src/components/utils/popover/popover.const.ts +1 -1
- package/src/full.ts +7 -1
- package/src/stories/MarkerColors.stories.ts +13 -34
- package/src/stories/Table.stories.ts +15 -9
- package/src/styles/main.css +313 -15
- package/src/tools/header/index.ts +11 -9
- package/src/tools/index.ts +4 -0
- package/src/tools/list/constants.ts +13 -6
- package/src/tools/list/depth-validator.ts +13 -1
- package/src/tools/list/dom-builder.ts +6 -3
- package/src/tools/list/index.ts +3 -2
- package/src/tools/paragraph/index.ts +2 -2
- package/src/tools/table/table-cell-blocks.ts +25 -0
- package/src/tools/table/table-cell-color-picker.ts +1 -1
- package/src/tools/table/table-cell-selection.ts +1 -2
- package/src/tools/table/table-core.ts +2 -2
- package/src/tools/table/table-grip-visuals.ts +13 -5
- package/src/tools/table/table-heading-toggle.ts +15 -9
- package/src/tools/table/table-row-col-controls.ts +17 -11
- package/src/tools/table/table-row-col-drag.ts +26 -3
- package/src/tools/toggle/constants.ts +13 -6
- package/src/tools/toggle/index.ts +1 -1
- package/types/tools/hook-events.d.ts +6 -0
- package/types/utils/popover/popover-item.d.ts +6 -0
- package/CHANGELOG.md +0 -119
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import type { I18n } from '../../../types/api';
|
|
2
2
|
import { parseColor } from '../utils/color-mapping';
|
|
3
|
+
import { onHover } from '../utils/tooltip';
|
|
3
4
|
import { twMerge } from '../utils/tw';
|
|
4
|
-
import { COLOR_PRESETS } from './color-presets';
|
|
5
|
+
import { COLOR_PRESETS, COLOR_PRESETS_DARK } from './color-presets';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns the appropriate preset array for the current theme.
|
|
9
|
+
* Checks the data-blok-theme attribute first (explicit override),
|
|
10
|
+
* then falls back to the prefers-color-scheme media query.
|
|
11
|
+
*/
|
|
12
|
+
function getActivePresets(): typeof COLOR_PRESETS {
|
|
13
|
+
const theme = document.documentElement.getAttribute('data-blok-theme');
|
|
14
|
+
|
|
15
|
+
if (theme === 'dark') return COLOR_PRESETS_DARK;
|
|
16
|
+
if (theme === 'light') return COLOR_PRESETS;
|
|
17
|
+
|
|
18
|
+
if (typeof window !== 'undefined' && window.matchMedia?.('(prefers-color-scheme: dark)').matches) {
|
|
19
|
+
return COLOR_PRESETS_DARK;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return COLOR_PRESETS;
|
|
23
|
+
}
|
|
5
24
|
|
|
6
25
|
/**
|
|
7
26
|
* Compare two CSS color strings for equality by their parsed RGB tuples.
|
|
@@ -23,7 +42,7 @@ function colorsEqual(a: string, b: string): boolean {
|
|
|
23
42
|
}
|
|
24
43
|
|
|
25
44
|
/**
|
|
26
|
-
* Describes one
|
|
45
|
+
* Describes one section in the color picker (e.g. "Text" or "Background")
|
|
27
46
|
*/
|
|
28
47
|
export interface ColorPickerMode {
|
|
29
48
|
key: string;
|
|
@@ -37,7 +56,6 @@ export interface ColorPickerMode {
|
|
|
37
56
|
export interface ColorPickerOptions {
|
|
38
57
|
i18n: I18n;
|
|
39
58
|
modes: [ColorPickerMode, ColorPickerMode];
|
|
40
|
-
defaultModeIndex?: number;
|
|
41
59
|
testIdPrefix: string;
|
|
42
60
|
onColorSelect: (color: string | null, modeKey: string) => void;
|
|
43
61
|
}
|
|
@@ -49,163 +67,166 @@ export interface ColorPickerHandle {
|
|
|
49
67
|
element: HTMLDivElement;
|
|
50
68
|
/**
|
|
51
69
|
* Set the currently active color for visual indication on the matching swatch.
|
|
52
|
-
* Pass null to clear any active indicator.
|
|
70
|
+
* Pass null to clear any active indicator for that section.
|
|
53
71
|
* @param color - CSS color value or null to clear
|
|
54
|
-
* @param modeKey - The mode key (e.g. 'color', 'background-color') to match the correct
|
|
72
|
+
* @param modeKey - The mode key (e.g. 'color', 'background-color') to match the correct section
|
|
55
73
|
*/
|
|
56
74
|
setActiveColor: (color: string | null, modeKey: string) => void;
|
|
57
75
|
/**
|
|
58
|
-
* Reset the picker state (
|
|
59
|
-
* Call this when the picker is reopened to ensure consistent initial state.
|
|
76
|
+
* Reset the picker state back to defaults (clear all active colors).
|
|
60
77
|
*/
|
|
61
78
|
reset: () => void;
|
|
62
79
|
}
|
|
63
80
|
|
|
64
81
|
/**
|
|
65
|
-
*
|
|
82
|
+
* Neutral background for text-mode swatches so they render as visible buttons.
|
|
83
|
+
* Uses a CSS variable so it adapts to dark mode.
|
|
66
84
|
*/
|
|
67
|
-
const
|
|
85
|
+
const SWATCH_NEUTRAL_BG = 'var(--blok-swatch-neutral-bg)';
|
|
68
86
|
|
|
69
87
|
/**
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
const SWATCH_NEUTRAL_BG = '#f7f7f5';
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Creates a color picker element with two tabs (e.g. Text / Background),
|
|
76
|
-
* a 5-column swatch grid, and a "Default" reset button.
|
|
88
|
+
* Creates a color picker element with two always-visible sections (e.g. Text / Background),
|
|
89
|
+
* each containing a 5-column swatch grid with a "Default" reset swatch at position 0.
|
|
77
90
|
*
|
|
78
91
|
* Shared between the marker inline tool and the table cell color popover.
|
|
79
92
|
*/
|
|
80
93
|
export function createColorPicker(options: ColorPickerOptions): ColorPickerHandle {
|
|
81
94
|
const { i18n, modes, testIdPrefix, onColorSelect } = options;
|
|
82
|
-
const
|
|
83
|
-
|
|
95
|
+
const state = {
|
|
96
|
+
activeColors: Object.fromEntries(modes.map((m) => [m.key, null])) as Record<string, string | null>,
|
|
97
|
+
};
|
|
84
98
|
|
|
85
99
|
const wrapper = document.createElement('div');
|
|
86
100
|
|
|
87
101
|
wrapper.setAttribute('data-blok-testid', `${testIdPrefix}-picker`);
|
|
88
|
-
wrapper.className = 'flex flex-col gap-
|
|
102
|
+
wrapper.className = 'flex flex-col gap-3 p-2';
|
|
89
103
|
|
|
90
104
|
/**
|
|
91
|
-
*
|
|
105
|
+
* One grid element per section, stored so we can re-render independently.
|
|
92
106
|
*/
|
|
93
|
-
const
|
|
107
|
+
const sectionGrids: HTMLDivElement[] = [];
|
|
94
108
|
|
|
95
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Build sections once; re-render only the grids on state changes.
|
|
111
|
+
*/
|
|
112
|
+
modes.forEach((mode) => {
|
|
113
|
+
const section = document.createElement('div');
|
|
96
114
|
|
|
97
|
-
|
|
115
|
+
section.setAttribute('data-blok-testid', `${testIdPrefix}-section-${mode.key}`);
|
|
116
|
+
section.className = 'flex flex-col gap-1';
|
|
98
117
|
|
|
99
|
-
|
|
100
|
-
const tab = document.createElement('button');
|
|
118
|
+
const title = document.createElement('div');
|
|
101
119
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
tab.addEventListener('click', () => {
|
|
105
|
-
state.modeIndex = modeIndex;
|
|
106
|
-
updateTabs();
|
|
107
|
-
renderSwatches();
|
|
108
|
-
});
|
|
109
|
-
tabButtons.push(tab);
|
|
110
|
-
tabRow.appendChild(tab);
|
|
111
|
-
});
|
|
120
|
+
title.className = 'text-xs font-medium text-text-primary/60 px-0.5';
|
|
121
|
+
title.textContent = i18n.t(mode.labelKey);
|
|
112
122
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
const grid = document.createElement('div');
|
|
124
|
+
|
|
125
|
+
grid.className = 'grid gap-1';
|
|
126
|
+
grid.style.gridTemplateColumns = 'repeat(5, 2.25rem)';
|
|
127
|
+
sectionGrids.push(grid);
|
|
128
|
+
|
|
129
|
+
section.appendChild(title);
|
|
130
|
+
section.appendChild(grid);
|
|
131
|
+
wrapper.appendChild(section);
|
|
132
|
+
});
|
|
121
133
|
|
|
122
134
|
/**
|
|
123
|
-
*
|
|
135
|
+
* Render the swatches for one section.
|
|
124
136
|
*/
|
|
125
|
-
const
|
|
137
|
+
const renderSection = (modeIndex: number): void => {
|
|
138
|
+
const grid = sectionGrids[modeIndex];
|
|
139
|
+
const mode = modes[modeIndex];
|
|
140
|
+
const presets = getActivePresets();
|
|
126
141
|
|
|
127
|
-
grid.setAttribute('data-blok-testid', `${testIdPrefix}-grid`);
|
|
128
|
-
grid.className = 'grid grid-cols-5 gap-1.5';
|
|
129
|
-
|
|
130
|
-
const renderSwatches = (): void => {
|
|
131
142
|
grid.innerHTML = '';
|
|
132
143
|
|
|
133
|
-
const
|
|
144
|
+
const activeColorForSection = state.activeColors[mode.key];
|
|
145
|
+
|
|
146
|
+
// Default swatch (first position) — clears the active color for this section
|
|
147
|
+
const defaultSwatch = document.createElement('button');
|
|
148
|
+
const isDefaultActive = activeColorForSection === null;
|
|
149
|
+
|
|
150
|
+
defaultSwatch.setAttribute('data-blok-testid', `${testIdPrefix}-swatch-${mode.key}-default`);
|
|
151
|
+
defaultSwatch.className = twMerge(
|
|
152
|
+
'w-9 h-9 rounded-md cursor-pointer border-none outline-hidden',
|
|
153
|
+
'flex items-center justify-center text-sm font-semibold',
|
|
154
|
+
'transition-[box-shadow,transform] ring-inset hover:ring-2 hover:ring-swatch-ring-hover active:scale-90',
|
|
155
|
+
isDefaultActive && 'ring-2 ring-swatch-ring-hover'
|
|
156
|
+
);
|
|
157
|
+
defaultSwatch.textContent = mode.presetField === 'text' ? 'A' : '';
|
|
158
|
+
|
|
159
|
+
if (mode.presetField === 'text') {
|
|
160
|
+
defaultSwatch.style.color = 'var(--blok-text-primary)';
|
|
161
|
+
defaultSwatch.style.backgroundColor = SWATCH_NEUTRAL_BG;
|
|
162
|
+
} else {
|
|
163
|
+
defaultSwatch.style.backgroundColor = SWATCH_NEUTRAL_BG;
|
|
164
|
+
}
|
|
165
|
+
defaultSwatch.addEventListener('click', () => {
|
|
166
|
+
onColorSelect(null, mode.key);
|
|
167
|
+
});
|
|
168
|
+
const defaultLabel = i18n.t('tools.colorPicker.defaultSwatchLabel')
|
|
169
|
+
.replace('{default}', i18n.t('tools.marker.default'))
|
|
170
|
+
.replace('{mode}', i18n.t(mode.labelKey).toLowerCase());
|
|
171
|
+
|
|
172
|
+
onHover(defaultSwatch, defaultLabel.charAt(0).toUpperCase() + defaultLabel.slice(1), { placement: 'top' });
|
|
173
|
+
grid.appendChild(defaultSwatch);
|
|
134
174
|
|
|
135
|
-
for (const preset of
|
|
175
|
+
for (const preset of presets) {
|
|
136
176
|
const swatch = document.createElement('button');
|
|
137
|
-
const swatchColor =
|
|
138
|
-
const isActive =
|
|
177
|
+
const swatchColor = mode.presetField === 'text' ? preset.text : preset.bg;
|
|
178
|
+
const isActive = activeColorForSection !== null && colorsEqual(swatchColor, activeColorForSection);
|
|
139
179
|
|
|
140
|
-
swatch.setAttribute('data-blok-testid', `${testIdPrefix}-swatch-${preset.name}`);
|
|
180
|
+
swatch.setAttribute('data-blok-testid', `${testIdPrefix}-swatch-${mode.key}-${preset.name}`);
|
|
141
181
|
swatch.className = twMerge(
|
|
142
|
-
'w-
|
|
182
|
+
'w-9 h-9 rounded-md cursor-pointer border-none outline-hidden',
|
|
143
183
|
'flex items-center justify-center text-sm font-semibold',
|
|
144
|
-
'transition-shadow ring-inset hover:ring-2 hover:ring-
|
|
145
|
-
isActive && 'ring-2 ring-
|
|
184
|
+
'transition-[box-shadow,transform] ring-inset hover:ring-2 hover:ring-swatch-ring-hover active:scale-90',
|
|
185
|
+
isActive && 'ring-2 ring-swatch-ring-hover'
|
|
146
186
|
);
|
|
147
|
-
swatch.textContent = 'A';
|
|
187
|
+
swatch.textContent = mode.presetField === 'text' ? 'A' : '';
|
|
148
188
|
|
|
149
|
-
if (
|
|
189
|
+
if (mode.presetField === 'text') {
|
|
150
190
|
swatch.style.color = preset.text;
|
|
151
191
|
swatch.style.backgroundColor = SWATCH_NEUTRAL_BG;
|
|
152
192
|
} else {
|
|
153
|
-
swatch.style.color = '';
|
|
193
|
+
swatch.style.color = presets === COLOR_PRESETS_DARK ? preset.text : '#37352f';
|
|
154
194
|
swatch.style.backgroundColor = preset.bg;
|
|
155
195
|
}
|
|
156
196
|
|
|
157
197
|
swatch.addEventListener('click', () => {
|
|
158
|
-
onColorSelect(swatchColor,
|
|
198
|
+
onColorSelect(swatchColor, mode.key);
|
|
159
199
|
});
|
|
200
|
+
const colorLabel = i18n.t('tools.colorPicker.colorSwatchLabel')
|
|
201
|
+
.replace('{color}', i18n.t('tools.colorPicker.color.' + preset.name))
|
|
202
|
+
.replace('{mode}', i18n.t(mode.labelKey).toLowerCase());
|
|
203
|
+
|
|
204
|
+
onHover(swatch, colorLabel.charAt(0).toUpperCase() + colorLabel.slice(1), { placement: 'top' });
|
|
160
205
|
grid.appendChild(swatch);
|
|
161
206
|
}
|
|
162
207
|
};
|
|
163
208
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const defaultBtn = document.createElement('button');
|
|
168
|
-
|
|
169
|
-
defaultBtn.setAttribute('data-blok-testid', `${testIdPrefix}-default-btn`);
|
|
170
|
-
defaultBtn.className = twMerge(
|
|
171
|
-
'w-full py-1.5 text-xs text-center rounded-md cursor-pointer',
|
|
172
|
-
'bg-transparent border-none outline-hidden hover:bg-item-hover-bg',
|
|
173
|
-
'mt-0.5 transition-colors'
|
|
174
|
-
);
|
|
175
|
-
defaultBtn.textContent = i18n.t('tools.marker.default');
|
|
176
|
-
defaultBtn.addEventListener('click', () => {
|
|
177
|
-
onColorSelect(null, modes[state.modeIndex].key);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Assemble
|
|
182
|
-
*/
|
|
183
|
-
updateTabs();
|
|
184
|
-
renderSwatches();
|
|
209
|
+
const renderAll = (): void => {
|
|
210
|
+
modes.forEach((_, i) => renderSection(i));
|
|
211
|
+
};
|
|
185
212
|
|
|
186
|
-
|
|
187
|
-
wrapper.appendChild(grid);
|
|
188
|
-
wrapper.appendChild(defaultBtn);
|
|
213
|
+
renderAll();
|
|
189
214
|
|
|
190
215
|
return {
|
|
191
216
|
element: wrapper,
|
|
192
217
|
setActiveColor: (color: string | null, modeKey: string) => {
|
|
193
|
-
state.activeColor = color;
|
|
194
|
-
|
|
195
218
|
const matchingIndex = modes.findIndex((m) => m.key === modeKey);
|
|
196
219
|
|
|
197
220
|
if (matchingIndex !== -1) {
|
|
198
|
-
state.
|
|
199
|
-
|
|
221
|
+
state.activeColors[modeKey] = color;
|
|
222
|
+
renderSection(matchingIndex);
|
|
200
223
|
}
|
|
201
|
-
|
|
202
|
-
renderSwatches();
|
|
203
224
|
},
|
|
204
225
|
reset: () => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
226
|
+
for (const mode of modes) {
|
|
227
|
+
state.activeColors[mode.key] = null;
|
|
228
|
+
}
|
|
229
|
+
renderAll();
|
|
209
230
|
},
|
|
210
231
|
};
|
|
211
232
|
}
|
|
@@ -8,7 +8,7 @@ export interface ColorPreset {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Ten Notion-style color presets.
|
|
11
|
+
* Ten Notion-style color presets for light mode.
|
|
12
12
|
* `text` is used for foreground (text-color mode), `bg` for background swatches.
|
|
13
13
|
*/
|
|
14
14
|
export const COLOR_PRESETS: ColorPreset[] = [
|
|
@@ -17,9 +17,37 @@ export const COLOR_PRESETS: ColorPreset[] = [
|
|
|
17
17
|
{ name: 'orange', text: '#d9730d', bg: '#fbecdd' },
|
|
18
18
|
{ name: 'yellow', text: '#cb9b00', bg: '#fbf3db' },
|
|
19
19
|
{ name: 'green', text: '#448361', bg: '#edf3ec' },
|
|
20
|
-
{ name: 'teal', text: '#2b9a8f', bg: '#e4f5f3' },
|
|
21
20
|
{ name: 'blue', text: '#337ea9', bg: '#e7f3f8' },
|
|
22
21
|
{ name: 'purple', text: '#9065b0', bg: '#f6f3f9' },
|
|
23
22
|
{ name: 'pink', text: '#c14c8a', bg: '#f9f0f5' },
|
|
24
23
|
{ name: 'red', text: '#d44c47', bg: '#fdebec' },
|
|
25
24
|
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Dark-mode adapted presets. Text colors are lightened for readability on dark
|
|
28
|
+
* swatch backgrounds; background colors are deep/muted to integrate with dark UI.
|
|
29
|
+
* All pairs achieve at least 3.8:1 WCAG contrast. Backgrounds are equalized at
|
|
30
|
+
* ~L19% HSL with increased saturation so each hue family is clearly identifiable.
|
|
31
|
+
*/
|
|
32
|
+
export const COLOR_PRESETS_DARK: ColorPreset[] = [
|
|
33
|
+
{ name: 'gray', text: '#9b9b9b', bg: '#2f2f2f' },
|
|
34
|
+
{ name: 'brown', text: '#c59177', bg: '#452a1c' },
|
|
35
|
+
{ name: 'orange', text: '#dc8c47', bg: '#4d2f14' },
|
|
36
|
+
{ name: 'yellow', text: '#d4ab49', bg: '#544012' },
|
|
37
|
+
{ name: 'green', text: '#5db184', bg: '#1e432f' },
|
|
38
|
+
{ name: 'blue', text: '#5c9fcc', bg: '#123a54' },
|
|
39
|
+
{ name: 'purple', text: '#a67dca', bg: '#341d49' },
|
|
40
|
+
{ name: 'pink', text: '#d45e99', bg: '#4b1b33' },
|
|
41
|
+
{ name: 'red', text: '#dd5e5a', bg: '#4e1a18' },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Construct a CSS custom property reference for a named preset color.
|
|
46
|
+
*
|
|
47
|
+
* @param name - The color preset name (e.g. 'red', 'blue')
|
|
48
|
+
* @param mode - 'text' for foreground, 'bg' for background
|
|
49
|
+
* @returns CSS var reference, e.g. `var(--blok-color-red-text)`
|
|
50
|
+
*/
|
|
51
|
+
export function colorVarName(name: string, mode: 'text' | 'bg'): string {
|
|
52
|
+
return `var(--blok-color-${name}-${mode})`;
|
|
53
|
+
}
|
|
@@ -167,6 +167,13 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
167
167
|
*/
|
|
168
168
|
private isInsideTableCell = false;
|
|
169
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Whether the toolbox was opened in slash-search mode (via "/" key or existing slash paragraph).
|
|
172
|
+
* When false (opened via plus button), the input filter uses the full block text as the query
|
|
173
|
+
* instead of requiring a leading "/" and does not close on missing slash.
|
|
174
|
+
*/
|
|
175
|
+
private openedWithSlash = true;
|
|
176
|
+
|
|
170
177
|
/**
|
|
171
178
|
* Toolbox constructor
|
|
172
179
|
* @param options - available parameters
|
|
@@ -280,8 +287,10 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
280
287
|
|
|
281
288
|
/**
|
|
282
289
|
* Open Toolbox with Tools
|
|
290
|
+
* @param withSlash - When true (default), inline search requires "/" and closes on its removal.
|
|
291
|
+
* When false (plus button), the full block text is used as the filter query.
|
|
283
292
|
*/
|
|
284
|
-
public open(): void {
|
|
293
|
+
public open(withSlash = true): void {
|
|
285
294
|
if (this.isEmpty) {
|
|
286
295
|
return;
|
|
287
296
|
}
|
|
@@ -318,8 +327,20 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
318
327
|
const caretRect = SelectionUtils.rect;
|
|
319
328
|
|
|
320
329
|
this.popover.updatePosition(caretRect);
|
|
330
|
+
} else if (!withSlash && this.popover instanceof PopoverDesktop) {
|
|
331
|
+
/**
|
|
332
|
+
* When opened without slash (via plus button), the trigger element (plus button)
|
|
333
|
+
* is at the top of the block. Position the popover below the block's bottom edge
|
|
334
|
+
* instead, so it doesn't overlap the block's placeholder text.
|
|
335
|
+
*/
|
|
336
|
+
const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex);
|
|
337
|
+
|
|
338
|
+
if (currentBlock) {
|
|
339
|
+
this.popover.updatePosition(currentBlock.holder.getBoundingClientRect());
|
|
340
|
+
}
|
|
321
341
|
}
|
|
322
342
|
|
|
343
|
+
this.openedWithSlash = withSlash;
|
|
323
344
|
this.opened = true;
|
|
324
345
|
this.emit(ToolboxEvent.Opened);
|
|
325
346
|
this.startListeningToBlockInput();
|
|
@@ -725,7 +746,12 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
725
746
|
|
|
726
747
|
/**
|
|
727
748
|
* Handles input events on the block to filter the toolbox.
|
|
728
|
-
*
|
|
749
|
+
*
|
|
750
|
+
* In slash mode (default): extracts text after "/" and filters by it.
|
|
751
|
+
* Closes if "/" is removed.
|
|
752
|
+
*
|
|
753
|
+
* In no-slash mode (opened via plus button): uses full block text as the
|
|
754
|
+
* filter query and does not close on missing "/".
|
|
729
755
|
*/
|
|
730
756
|
private handleBlockInput = (): void => {
|
|
731
757
|
if (this.currentContentEditable === null) {
|
|
@@ -733,15 +759,18 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
733
759
|
}
|
|
734
760
|
|
|
735
761
|
const text = this.currentContentEditable.textContent || '';
|
|
736
|
-
const slashIndex = text.lastIndexOf('/');
|
|
737
762
|
|
|
738
|
-
if (
|
|
739
|
-
|
|
763
|
+
if (this.openedWithSlash) {
|
|
764
|
+
const slashIndex = text.lastIndexOf('/');
|
|
740
765
|
|
|
741
|
-
|
|
766
|
+
if (slashIndex === -1) {
|
|
767
|
+
this.close();
|
|
768
|
+
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
742
771
|
}
|
|
743
772
|
|
|
744
|
-
const query = text.slice(
|
|
773
|
+
const query = this.openedWithSlash ? text.slice(text.lastIndexOf('/') + 1) : text;
|
|
745
774
|
|
|
746
775
|
if (this.currentContentEditable instanceof HTMLElement) {
|
|
747
776
|
this.currentContentEditable.setAttribute(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { COLOR_PRESETS } from '../shared/color-presets';
|
|
1
|
+
import { COLOR_PRESETS, COLOR_PRESETS_DARK } from '../shared/color-presets';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Convert an HSL color (H in degrees, S and L as 0-100 percentages) to an RGB tuple.
|
|
@@ -239,3 +239,45 @@ export function mapToNearestPresetColor(cssColor: string, mode: 'text' | 'bg'):
|
|
|
239
239
|
|
|
240
240
|
return best.color;
|
|
241
241
|
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Map an arbitrary CSS color to the name of the nearest Blok preset color.
|
|
245
|
+
*
|
|
246
|
+
* Searches both light and dark presets to correctly recover the semantic name
|
|
247
|
+
* from hex values that originated in either theme. First match wins on ties.
|
|
248
|
+
*
|
|
249
|
+
* @param cssColor - CSS color string (hex or rgb)
|
|
250
|
+
* @param mode - 'text' for text color presets, 'bg' for background presets
|
|
251
|
+
* @returns the nearest preset name (e.g. 'red'), or null if unparseable
|
|
252
|
+
*/
|
|
253
|
+
export function mapToNearestPresetName(cssColor: string, mode: 'text' | 'bg'): string | null {
|
|
254
|
+
const rgb = parseColor(cssColor);
|
|
255
|
+
|
|
256
|
+
if (rgb === null) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const hsl = rgbToHsl(rgb);
|
|
261
|
+
const allPresets = [...COLOR_PRESETS, ...COLOR_PRESETS_DARK];
|
|
262
|
+
|
|
263
|
+
const best = allPresets.reduce<{ name: string; distance: number } | null>(
|
|
264
|
+
(acc, preset) => {
|
|
265
|
+
const presetRgb = parseColor(preset[mode]);
|
|
266
|
+
|
|
267
|
+
if (presetRgb === null) {
|
|
268
|
+
return acc;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const distance = hslDistance(hsl, rgbToHsl(presetRgb));
|
|
272
|
+
|
|
273
|
+
if (acc === null || distance < acc.distance) {
|
|
274
|
+
return { name: preset.name, distance };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return acc;
|
|
278
|
+
},
|
|
279
|
+
null
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
return best?.name ?? null;
|
|
283
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { colorVarName } from '../shared/color-presets';
|
|
2
|
+
import { mapToNearestPresetName } from './color-mapping';
|
|
3
|
+
|
|
4
|
+
const PROPS = ['color', 'background-color'] as const;
|
|
5
|
+
type Prop = typeof PROPS[number];
|
|
6
|
+
|
|
7
|
+
const PROP_MODE: Record<Prop, 'text' | 'bg'> = {
|
|
8
|
+
'color': 'text',
|
|
9
|
+
'background-color': 'bg',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Scan all <mark> elements inside container and replace raw hex color/background-color
|
|
14
|
+
* inline style values with their corresponding CSS custom property references.
|
|
15
|
+
*
|
|
16
|
+
* Safe to call multiple times — already-migrated var() values and 'transparent' are
|
|
17
|
+
* left unchanged.
|
|
18
|
+
*
|
|
19
|
+
* @param container - Root element to search within (e.g. the editor redactor node)
|
|
20
|
+
*/
|
|
21
|
+
export function migrateMarkColors(container: Element): void {
|
|
22
|
+
container.querySelectorAll<HTMLElement>('mark').forEach((el) => {
|
|
23
|
+
for (const prop of PROPS) {
|
|
24
|
+
const value = el.style.getPropertyValue(prop);
|
|
25
|
+
|
|
26
|
+
if (!value || value === 'transparent' || value.startsWith('var(')) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const name = mapToNearestPresetName(value, PROP_MODE[prop]);
|
|
31
|
+
|
|
32
|
+
if (name !== null) {
|
|
33
|
+
el.style.setProperty(prop, colorVarName(name, PROP_MODE[prop]));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -10,7 +10,7 @@ export const css = {
|
|
|
10
10
|
* Note: noHover state is handled via [data-blok-popover-item-no-hover] which disables hover
|
|
11
11
|
* Priority order: active < hover < focus (focus wins when navigating with keyboard)
|
|
12
12
|
*/
|
|
13
|
-
item: 'flex items-center select-none border-none bg-transparent rounded-lg px-2 py-1 text-text-primary mb-px outline-hidden
|
|
13
|
+
item: 'flex items-center select-none border-none bg-transparent rounded-lg px-2 py-1 text-text-primary mb-px outline-hidden max-h-9 overflow-hidden data-blok-popover-item-active:bg-icon-active-bg data-blok-popover-item-active:text-icon-active-text can-hover:hover:cursor-pointer can-hover:hover:bg-item-hover-bg data-blok-force-hover:cursor-pointer data-blok-force-hover:bg-item-hover-bg data-[blok-focused="true"]:bg-item-focus-bg data-blok-popover-item-no-hover:hover:bg-transparent data-blok-popover-item-no-hover:cursor-default can-hover:data-blok-popover-item-destructive:hover:text-item-destructive-text can-hover:data-blok-popover-item-destructive:hover:bg-item-destructive-hover-bg [&[data-blok-popover-item-destructive][data-blok-force-hover]]:text-item-destructive-text [&[data-blok-popover-item-destructive][data-blok-force-hover]]:bg-item-destructive-hover-bg [&[data-blok-popover-item-destructive][data-blok-focused="true"]]:text-item-destructive-text [&[data-blok-popover-item-destructive][data-blok-focused="true"]]:bg-item-destructive-hover-bg',
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Item disabled state
|
|
@@ -21,7 +21,7 @@ export const css = {
|
|
|
21
21
|
/**
|
|
22
22
|
* Icon container styles
|
|
23
23
|
*/
|
|
24
|
-
icon: 'flex items-center justify-center w-7 h-7 shrink-0 rounded-lg bg-popover-icon-bg
|
|
24
|
+
icon: 'flex items-center justify-center w-7 h-7 shrink-0 rounded-lg bg-popover-icon-bg [&_svg]:w-icon [&_svg]:h-icon',
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Focused state class for DomIterator/Flipper keyboard navigation.
|
|
@@ -37,7 +37,8 @@ export const cssInline = {
|
|
|
37
37
|
/**
|
|
38
38
|
* Item in inline context - more compact styling
|
|
39
39
|
*/
|
|
40
|
-
item: 'rounded p-1',
|
|
40
|
+
item: 'rounded-lg p-1',
|
|
41
|
+
itemIconOnly: 'aspect-square justify-center',
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
/**
|
|
@@ -305,7 +305,7 @@ export class PopoverItemDefault extends PopoverItem {
|
|
|
305
305
|
private createIconElement(icon: string, iconWithGap: boolean, isInline: boolean, isNestedInline: boolean): HTMLElement {
|
|
306
306
|
const iconEl = document.createElement('div');
|
|
307
307
|
|
|
308
|
-
iconEl.className = this.getIconClass(iconWithGap, isInline, isNestedInline
|
|
308
|
+
iconEl.className = this.getIconClass(iconWithGap, isInline, isNestedInline);
|
|
309
309
|
iconEl.setAttribute(DATA_ATTR.popoverItemIcon, '');
|
|
310
310
|
iconEl.setAttribute('data-blok-testid', 'popover-item-icon');
|
|
311
311
|
iconEl.innerHTML = icon;
|
|
@@ -328,6 +328,7 @@ export class PopoverItemDefault extends PopoverItem {
|
|
|
328
328
|
css.item,
|
|
329
329
|
!isInline && !isNestedInline && 'pl-2 pr-3',
|
|
330
330
|
isInline && cssInline.item,
|
|
331
|
+
isInline && this.params.icon && cssInline.itemIconOnly,
|
|
331
332
|
isNestedInline && cssNestedInline.item,
|
|
332
333
|
this.params.isDisabled && css.itemDisabled
|
|
333
334
|
);
|
|
@@ -336,15 +337,14 @@ export class PopoverItemDefault extends PopoverItem {
|
|
|
336
337
|
/**
|
|
337
338
|
* Gets the icon class based on context
|
|
338
339
|
*/
|
|
339
|
-
private getIconClass(iconWithGap: boolean, isInline: boolean, isNestedInline: boolean
|
|
340
|
+
private getIconClass(iconWithGap: boolean, isInline: boolean, isNestedInline: boolean): string {
|
|
340
341
|
return twMerge(
|
|
341
342
|
css.icon,
|
|
342
343
|
isInline && 'w-auto h-auto bg-transparent [&_svg]:w-icon [&_svg]:h-icon mobile:[&_svg]:w-icon-mobile mobile:[&_svg]:h-icon-mobile',
|
|
343
344
|
isNestedInline && 'w-toolbox-btn h-toolbox-btn',
|
|
344
345
|
iconWithGap && 'mr-3',
|
|
345
346
|
iconWithGap && isInline && 'shadow-none mr-0!',
|
|
346
|
-
iconWithGap && isNestedInline && 'mr-2!'
|
|
347
|
-
isWobbling && 'animate-wobble'
|
|
347
|
+
iconWithGap && isNestedInline && 'mr-2!'
|
|
348
348
|
);
|
|
349
349
|
}
|
|
350
350
|
|
|
@@ -639,47 +639,13 @@ export class PopoverItemDefault extends PopoverItem {
|
|
|
639
639
|
item.onActivate?.(item);
|
|
640
640
|
this.disableConfirmationMode();
|
|
641
641
|
} catch {
|
|
642
|
-
|
|
642
|
+
// onActivate threw an error
|
|
643
643
|
}
|
|
644
644
|
} else {
|
|
645
645
|
this.enableConfirmationMode(item.confirmation);
|
|
646
646
|
}
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
/**
|
|
650
|
-
* Animates item which symbolizes that error occurred while executing 'onActivate()' callback
|
|
651
|
-
*/
|
|
652
|
-
private animateError(): void {
|
|
653
|
-
this.triggerWobble();
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
/**
|
|
657
|
-
* Triggers wobble animation on the icon
|
|
658
|
-
*/
|
|
659
|
-
private triggerWobble(): void {
|
|
660
|
-
if (!this.nodes.icon) {
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
const isInline = this.renderParams?.isInline ?? false;
|
|
665
|
-
const isNestedInline = this.renderParams?.isNestedInline ?? false;
|
|
666
|
-
const iconWithGap = this.renderParams?.iconWithGap ?? true;
|
|
667
|
-
|
|
668
|
-
// Add wobble class
|
|
669
|
-
this.nodes.icon.setAttribute(DATA_ATTR.popoverItemWobble, 'true');
|
|
670
|
-
this.nodes.icon.className = this.getIconClass(iconWithGap, isInline, isNestedInline, true);
|
|
671
|
-
|
|
672
|
-
// Remove wobble after animation ends
|
|
673
|
-
const handleAnimationEnd = (): void => {
|
|
674
|
-
if (this.nodes.icon) {
|
|
675
|
-
this.nodes.icon.removeAttribute(DATA_ATTR.popoverItemWobble);
|
|
676
|
-
this.nodes.icon.className = this.getIconClass(iconWithGap, isInline, isNestedInline, false);
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
|
|
680
|
-
this.nodes.icon.addEventListener('animationend', handleAnimationEnd, { once: true });
|
|
681
|
-
}
|
|
682
|
-
|
|
683
649
|
/**
|
|
684
650
|
* Gets reference to the icon element
|
|
685
651
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tailwind CSS classes for popover separator component
|
|
3
3
|
*/
|
|
4
4
|
export const css = {
|
|
5
|
-
container: 'py-1.5 px-2
|
|
5
|
+
container: 'py-1.5 px-2 max-h-5 overflow-hidden',
|
|
6
6
|
containerHidden: 'opacity-0 max-h-0! py-0!',
|
|
7
7
|
line: 'h-px w-full bg-popover-border/60',
|
|
8
8
|
};
|
|
@@ -12,7 +12,7 @@ export const css = {
|
|
|
12
12
|
*/
|
|
13
13
|
export const cssInline = {
|
|
14
14
|
// Inline context: horizontal separator
|
|
15
|
-
container: 'px-1 py-0',
|
|
15
|
+
container: 'px-1 py-0 max-h-none',
|
|
16
16
|
line: 'h-full w-px',
|
|
17
17
|
// Nested inline context: back to vertical separator
|
|
18
18
|
nestedContainer: 'py-1 px-[3px]',
|