@jackuait/blok 0.7.3 → 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-BmlbETK7.mjs → blok-CdiMFzDz.mjs} +2143 -2134
- package/dist/chunks/{constants-WhLyFkza.mjs → constants-CjWRVOdm.mjs} +84 -84
- package/dist/chunks/{i18next-loader-CZARkla1.mjs → i18next-loader-p-7ioTwr.mjs} +1 -1
- package/dist/chunks/{lightweight-i18n-BQa0F2X6.mjs → lightweight-i18n-BPeH69Dl.mjs} +5 -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/{messages-CzSLUJQt.mjs → chunks/messages-5thhSeME.mjs} +14 -1
- package/dist/chunks/{messages-hngFJrES2.mjs → messages-8pf7gRQm2.mjs} +14 -1
- package/dist/chunks/{messages-DcPtg90i.mjs → messages-B-i-d1Bc.mjs} +14 -1
- package/dist/chunks/{messages-CRxkRJRN.mjs → messages-B9zocutJ.mjs} +14 -1
- package/dist/chunks/{messages-BUy3odZo.mjs → 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/{messages-C7R0m6oE2.mjs → chunks/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/chunks/{messages-DotEkUpQ.mjs → 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/{messages-B2bHgIcC2.mjs → chunks/messages-B_fFjpX12.mjs} +14 -1
- package/dist/chunks/{messages-CnzaTbel.mjs → 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/chunks/{messages-Dxrg70jo.mjs → 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/chunks/{messages-B_nVGWdk.mjs → messages-CDJLoStb.mjs} +14 -1
- package/dist/chunks/{messages-ClOxDE0y2.mjs → messages-CH_cexo62.mjs} +14 -1
- package/dist/chunks/{messages-DoDbCS02.mjs → messages-CIBuZccC.mjs} +14 -1
- package/dist/{messages-CkmVEyEQ2.mjs → chunks/messages-CIZkNCpW.mjs} +14 -1
- package/dist/{messages-CJYE0_hr2.mjs → chunks/messages-CIugNDDO2.mjs} +14 -1
- package/dist/{messages-DpY9s4Qi2.mjs → chunks/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/{messages-GrVSCmXW.mjs → chunks/messages-Co4WFeQ8.mjs} +14 -1
- package/dist/{messages-voUPclMU.mjs → chunks/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/{messages-m1uf_AMy2.mjs → chunks/messages-DDpgr0B1.mjs} +14 -1
- package/dist/{messages-CB0RKGVM.mjs → chunks/messages-DEGzGmEQ2.mjs} +14 -1
- package/dist/{messages--XEfVx572.mjs → chunks/messages-DKChC8Qu.mjs} +14 -1
- package/dist/{messages-BP8ZuVaD.mjs → chunks/messages-DKCoHa5D.mjs} +14 -1
- package/dist/chunks/{messages-C3AJz_i6.mjs → messages-DPoPrTiZ.mjs} +14 -1
- package/dist/{messages-CaJRIGUu2.mjs → chunks/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/{messages-BlnZ8CkJ2.mjs → chunks/messages-Df69rfTF2.mjs} +15 -2
- package/dist/{messages-BZgGD0zf2.mjs → chunks/messages-DfsHFEWa.mjs} +14 -1
- package/dist/chunks/{messages-yJmwc3zD.mjs → messages-DgZnRQRS.mjs} +14 -1
- package/dist/chunks/{messages-m6bLP64R2.mjs → 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/chunks/{messages-D6SAC8Lc2.mjs → 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-BCb5bMO3.mjs → tools-B5yNeTZh.mjs} +1086 -802
- package/dist/full.mjs +15 -13
- package/dist/locales.mjs +72 -68
- package/dist/{messages-mVFAkdcY.mjs → messages-1_FCq0It.mjs} +14 -1
- package/dist/{messages-DkkrjINb2.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/{messages-pgqtPci-.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/{chunks/messages-DDRCk44J2.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/{messages-B8M4YRFO2.mjs → messages-C5hD5pSd2.mjs} +14 -1
- package/dist/{messages-ruU_e2LK.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/{chunks/messages-DziA-L3p.mjs → messages-CHeucLGl2.mjs} +14 -1
- package/dist/{messages-eCyczLYY.mjs → messages-CIxT1nSh.mjs} +14 -1
- package/dist/{chunks/messages-Cb-x47kY2.mjs → messages-CKX9iXIb2.mjs} +14 -1
- package/dist/{chunks/messages-BjkDJuqh.mjs → messages-CKmmJ9tW.mjs} +14 -1
- package/dist/{chunks/messages-Cn5n0nHe2.mjs → messages-CTFwu5-h2.mjs} +14 -1
- package/dist/{messages-DAssrN5L2.mjs → messages-CTPFrtK92.mjs} +14 -1
- package/dist/{chunks/messages-6EJxSImH.mjs → messages-CWzET_9H2.mjs} +14 -1
- package/dist/{chunks/messages-BZ45xBlV.mjs → messages-CkIRmpfZ2.mjs} +14 -1
- package/dist/{chunks/messages-kHTrX3wo2.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/{chunks/messages-DDr8J4FE.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/{messages-MaHxNgKA.mjs → messages-D8iCBMg7.mjs} +14 -1
- package/dist/{chunks/messages-BtNOlsMj.mjs → messages-DDJOu049.mjs} +14 -1
- package/dist/{messages-BU9luYgO.mjs → messages-DDiP6yex.mjs} +14 -1
- package/dist/{messages-DB9U3VIh.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/{messages-e-KHuxtY2.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/{chunks/messages-IJhiftj5.mjs → messages-EIeWKoc5.mjs} +14 -1
- package/dist/{chunks/messages-CteKp81J.mjs → messages-EwoT2jof.mjs} +14 -1
- package/dist/{messages-C8iAUPzI.mjs → messages-F7cRf-20.mjs} +14 -1
- package/dist/{messages-B9qltgXa.mjs → messages-JZhs_0pf.mjs} +14 -1
- package/dist/{chunks/messages-C232njMF2.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/{chunks/messages-6z-ULVyk.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 +1 -1
- 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 +5 -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 +18 -0
- 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/modules/rectangleSelection.ts +48 -0
- package/src/components/modules/toolbar/index.ts +5 -2
- package/src/components/shared/color-picker.ts +10 -2
- package/src/full.ts +7 -1
- package/src/stories/MarkerColors.stories.ts +13 -34
- package/src/styles/main.css +1 -1
- package/src/tools/header/index.ts +6 -4
- package/src/tools/index.ts +4 -0
- package/src/tools/list/constants.ts +3 -3
- package/src/tools/list/dom-builder.ts +1 -0
- package/src/tools/table/table-cell-blocks.ts +25 -0
- package/src/tools/toggle/constants.ts +12 -5
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import type { InlineTool, SanitizerConfig } from '../../../types';
|
|
2
|
+
import type { MenuConfig } from '../../../types/tools';
|
|
3
|
+
import { IconUnderline } from '../icons';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
isRangeFormatted,
|
|
7
|
+
findFormattingAncestor,
|
|
8
|
+
hasFormattingAncestor,
|
|
9
|
+
collectFormattingAncestors,
|
|
10
|
+
} from './utils/formatting-range-utils';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if an element is an underline tag (<u>)
|
|
14
|
+
* @param element - The element to check
|
|
15
|
+
*/
|
|
16
|
+
const isUnderlineTag = (element: Element): boolean => {
|
|
17
|
+
return element.tagName === 'U';
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Underline Tool
|
|
22
|
+
*
|
|
23
|
+
* Inline Toolbar Tool
|
|
24
|
+
*
|
|
25
|
+
* Style selected text with underline
|
|
26
|
+
*/
|
|
27
|
+
export class UnderlineInlineTool implements InlineTool {
|
|
28
|
+
/**
|
|
29
|
+
* Specifies Tool as Inline Toolbar Tool
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
public static isInline = true;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Title for the Inline Tool
|
|
36
|
+
*/
|
|
37
|
+
public static title = 'Underline';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Translation key for i18n
|
|
41
|
+
*/
|
|
42
|
+
public static titleKey = 'underline';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sanitizer Rule
|
|
46
|
+
* Leave <u> tags
|
|
47
|
+
* @returns {object}
|
|
48
|
+
*/
|
|
49
|
+
public static get sanitize(): SanitizerConfig {
|
|
50
|
+
return {
|
|
51
|
+
u: {},
|
|
52
|
+
} as SanitizerConfig;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create button for Inline Toolbar
|
|
57
|
+
*/
|
|
58
|
+
public render(): MenuConfig {
|
|
59
|
+
return {
|
|
60
|
+
icon: IconUnderline,
|
|
61
|
+
name: 'underline',
|
|
62
|
+
onActivate: () => {
|
|
63
|
+
this.toggleUnderline();
|
|
64
|
+
},
|
|
65
|
+
isActive: () => {
|
|
66
|
+
const selection = window.getSelection();
|
|
67
|
+
|
|
68
|
+
return selection ? this.isSelectionVisuallyUnderline(selection) : false;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Shortcut for underline tool
|
|
75
|
+
*/
|
|
76
|
+
public static shortcut = 'CMD+U';
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Apply or remove underline formatting using modern Selection API
|
|
80
|
+
*/
|
|
81
|
+
private toggleUnderline(): void {
|
|
82
|
+
const selection = window.getSelection();
|
|
83
|
+
|
|
84
|
+
if (!selection || selection.rangeCount === 0) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const range = selection.getRangeAt(0);
|
|
89
|
+
|
|
90
|
+
if (range.collapsed) {
|
|
91
|
+
this.toggleCollapsedUnderline(range, selection);
|
|
92
|
+
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const shouldUnwrap = this.isRangeUnderline(range, { ignoreWhitespace: true });
|
|
97
|
+
|
|
98
|
+
if (shouldUnwrap) {
|
|
99
|
+
this.unwrapUnderlineTags(range);
|
|
100
|
+
} else {
|
|
101
|
+
this.wrapWithUnderline(range);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Handle toggle for collapsed selection (caret)
|
|
107
|
+
* @param range - Current range
|
|
108
|
+
* @param selection - Current selection
|
|
109
|
+
*/
|
|
110
|
+
private toggleCollapsedUnderline(range: Range, selection: Selection): void {
|
|
111
|
+
const isUnderline = this.isRangeUnderline(range, { ignoreWhitespace: true });
|
|
112
|
+
|
|
113
|
+
if (isUnderline) {
|
|
114
|
+
const textNode = document.createTextNode('\u200B');
|
|
115
|
+
|
|
116
|
+
range.insertNode(textNode);
|
|
117
|
+
range.selectNode(textNode);
|
|
118
|
+
this.unwrapUnderlineTags(range);
|
|
119
|
+
|
|
120
|
+
const newRange = document.createRange();
|
|
121
|
+
|
|
122
|
+
newRange.setStart(textNode, 1);
|
|
123
|
+
newRange.setEnd(textNode, 1);
|
|
124
|
+
|
|
125
|
+
selection.removeAllRanges();
|
|
126
|
+
selection.addRange(newRange);
|
|
127
|
+
} else {
|
|
128
|
+
const u = document.createElement('u');
|
|
129
|
+
const textNode = document.createTextNode('\u200B');
|
|
130
|
+
|
|
131
|
+
u.appendChild(textNode);
|
|
132
|
+
range.insertNode(u);
|
|
133
|
+
|
|
134
|
+
const newRange = document.createRange();
|
|
135
|
+
|
|
136
|
+
newRange.setStart(textNode, 1);
|
|
137
|
+
newRange.setEnd(textNode, 1);
|
|
138
|
+
|
|
139
|
+
selection.removeAllRanges();
|
|
140
|
+
selection.addRange(newRange);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Check if current selection is within an underline tag
|
|
146
|
+
* @param selection - The Selection object to check
|
|
147
|
+
*/
|
|
148
|
+
private isSelectionVisuallyUnderline(selection: Selection): boolean {
|
|
149
|
+
if (selection.rangeCount === 0) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const range = selection.getRangeAt(0);
|
|
154
|
+
|
|
155
|
+
return this.isRangeUnderline(range, { ignoreWhitespace: true });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if a range contains underline text
|
|
160
|
+
* @param range - The range to check
|
|
161
|
+
* @param options - Options for checking underline status
|
|
162
|
+
*/
|
|
163
|
+
private isRangeUnderline(range: Range, options: { ignoreWhitespace: boolean }): boolean {
|
|
164
|
+
return isRangeFormatted(range, isUnderlineTag, options);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Wrap selection with <u> tag
|
|
169
|
+
* @param range - The Range object containing the selection to wrap
|
|
170
|
+
*/
|
|
171
|
+
private wrapWithUnderline(range: Range): void {
|
|
172
|
+
const html = this.getRangeHtmlWithoutUnderline(range);
|
|
173
|
+
const insertedRange = this.replaceRangeWithHtml(range, `<u>${html}</u>`);
|
|
174
|
+
const selection = window.getSelection();
|
|
175
|
+
|
|
176
|
+
if (selection && insertedRange) {
|
|
177
|
+
selection.removeAllRanges();
|
|
178
|
+
selection.addRange(insertedRange);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Remove underline tags (<u>) while preserving content
|
|
184
|
+
* @param range - The Range object containing the selection to unwrap
|
|
185
|
+
*/
|
|
186
|
+
private unwrapUnderlineTags(range: Range): void {
|
|
187
|
+
const underlineAncestors = this.collectUnderlineAncestors(range);
|
|
188
|
+
const selection = window.getSelection();
|
|
189
|
+
|
|
190
|
+
if (!selection) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const marker = document.createElement('span');
|
|
195
|
+
const fragment = range.extractContents();
|
|
196
|
+
|
|
197
|
+
marker.appendChild(fragment);
|
|
198
|
+
this.removeNestedUnderline(marker);
|
|
199
|
+
|
|
200
|
+
range.insertNode(marker);
|
|
201
|
+
|
|
202
|
+
const markerRange = document.createRange();
|
|
203
|
+
|
|
204
|
+
markerRange.selectNodeContents(marker);
|
|
205
|
+
selection.removeAllRanges();
|
|
206
|
+
selection.addRange(markerRange);
|
|
207
|
+
|
|
208
|
+
for (; ;) {
|
|
209
|
+
const currentUnderline = this.findUnderlineElement(marker);
|
|
210
|
+
|
|
211
|
+
if (!currentUnderline) {
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.moveMarkerOutOfUnderline(marker, currentUnderline);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const firstChild = marker.firstChild;
|
|
219
|
+
const lastChild = marker.lastChild;
|
|
220
|
+
|
|
221
|
+
this.unwrapElement(marker);
|
|
222
|
+
|
|
223
|
+
const finalRange = firstChild && lastChild ? (() => {
|
|
224
|
+
const newRange = document.createRange();
|
|
225
|
+
|
|
226
|
+
newRange.setStartBefore(firstChild);
|
|
227
|
+
newRange.setEndAfter(lastChild);
|
|
228
|
+
|
|
229
|
+
selection.removeAllRanges();
|
|
230
|
+
selection.addRange(newRange);
|
|
231
|
+
|
|
232
|
+
return newRange;
|
|
233
|
+
})() : undefined;
|
|
234
|
+
|
|
235
|
+
if (!finalRange) {
|
|
236
|
+
selection.removeAllRanges();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
underlineAncestors.forEach((element) => {
|
|
240
|
+
if (element.textContent.length === 0) {
|
|
241
|
+
element.remove();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Check if a node or any of its parents is an underline tag
|
|
248
|
+
* @param node - The node to check
|
|
249
|
+
*/
|
|
250
|
+
private hasUnderlineParent(node: Node | null): boolean {
|
|
251
|
+
return hasFormattingAncestor(node, isUnderlineTag);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Find an underline element in the parent chain
|
|
256
|
+
* @param node - The node to start searching from
|
|
257
|
+
*/
|
|
258
|
+
private findUnderlineElement(node: Node | null): HTMLElement | null {
|
|
259
|
+
return findFormattingAncestor(node, isUnderlineTag);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Collect all underline ancestor elements within a range
|
|
264
|
+
* @param range - The range to search for underline ancestors
|
|
265
|
+
*/
|
|
266
|
+
private collectUnderlineAncestors(range: Range): HTMLElement[] {
|
|
267
|
+
return collectFormattingAncestors(range, isUnderlineTag);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get HTML content of a range with underline tags removed
|
|
272
|
+
* @param range - The range to extract HTML from
|
|
273
|
+
*/
|
|
274
|
+
private getRangeHtmlWithoutUnderline(range: Range): string {
|
|
275
|
+
const contents = range.cloneContents();
|
|
276
|
+
|
|
277
|
+
this.removeNestedUnderline(contents);
|
|
278
|
+
|
|
279
|
+
const container = document.createElement('div');
|
|
280
|
+
|
|
281
|
+
container.appendChild(contents);
|
|
282
|
+
|
|
283
|
+
return container.innerHTML;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Remove nested underline tags from a root node
|
|
288
|
+
* @param root - The root node to process
|
|
289
|
+
*/
|
|
290
|
+
private removeNestedUnderline(root: ParentNode): void {
|
|
291
|
+
const underlineNodes = root.querySelectorAll('u');
|
|
292
|
+
|
|
293
|
+
underlineNodes.forEach((node) => {
|
|
294
|
+
this.unwrapElement(node);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Unwrap an element by moving its children to the parent
|
|
300
|
+
* @param element - The element to unwrap
|
|
301
|
+
*/
|
|
302
|
+
private unwrapElement(element: Element): void {
|
|
303
|
+
const parent = element.parentNode;
|
|
304
|
+
|
|
305
|
+
if (!parent) {
|
|
306
|
+
element.remove();
|
|
307
|
+
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
while (element.firstChild) {
|
|
312
|
+
parent.insertBefore(element.firstChild, element);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
parent.removeChild(element);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Replace the current range contents with provided HTML snippet
|
|
320
|
+
* @param range - Range to replace
|
|
321
|
+
* @param html - HTML string to insert
|
|
322
|
+
*/
|
|
323
|
+
private replaceRangeWithHtml(range: Range, html: string): Range | undefined {
|
|
324
|
+
const fragment = this.createFragmentFromHtml(html);
|
|
325
|
+
const firstInserted = fragment.firstChild ?? null;
|
|
326
|
+
const lastInserted = fragment.lastChild ?? null;
|
|
327
|
+
|
|
328
|
+
range.deleteContents();
|
|
329
|
+
|
|
330
|
+
if (!firstInserted || !lastInserted) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
range.insertNode(fragment);
|
|
335
|
+
|
|
336
|
+
const newRange = document.createRange();
|
|
337
|
+
|
|
338
|
+
newRange.setStartBefore(firstInserted);
|
|
339
|
+
newRange.setEndAfter(lastInserted);
|
|
340
|
+
|
|
341
|
+
return newRange;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Convert an HTML snippet to a document fragment
|
|
346
|
+
* @param html - HTML string to convert
|
|
347
|
+
*/
|
|
348
|
+
private createFragmentFromHtml(html: string): DocumentFragment {
|
|
349
|
+
const template = document.createElement('template');
|
|
350
|
+
|
|
351
|
+
template.innerHTML = html;
|
|
352
|
+
|
|
353
|
+
return template.content;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Move a temporary marker element outside of an underline ancestor while preserving content order
|
|
358
|
+
* @param marker - Marker element wrapping the selection contents
|
|
359
|
+
* @param underlineElement - Underline ancestor containing the marker
|
|
360
|
+
*/
|
|
361
|
+
private moveMarkerOutOfUnderline(marker: HTMLElement, underlineElement: HTMLElement): void {
|
|
362
|
+
const parent = underlineElement.parentNode;
|
|
363
|
+
|
|
364
|
+
if (!parent) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Remove empty text nodes to ensure accurate child count
|
|
369
|
+
Array.from(underlineElement.childNodes).forEach((node) => {
|
|
370
|
+
if (node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').length === 0) {
|
|
371
|
+
node.remove();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const isOnlyChild = underlineElement.childNodes.length === 1 && underlineElement.firstChild === marker;
|
|
376
|
+
|
|
377
|
+
if (isOnlyChild) {
|
|
378
|
+
underlineElement.replaceWith(marker);
|
|
379
|
+
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const isFirstChild = underlineElement.firstChild === marker;
|
|
384
|
+
|
|
385
|
+
if (isFirstChild) {
|
|
386
|
+
parent.insertBefore(marker, underlineElement);
|
|
387
|
+
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const isLastChild = underlineElement.lastChild === marker;
|
|
392
|
+
|
|
393
|
+
if (isLastChild) {
|
|
394
|
+
parent.insertBefore(marker, underlineElement.nextSibling);
|
|
395
|
+
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const trailingClone = underlineElement.cloneNode(false) as HTMLElement;
|
|
400
|
+
|
|
401
|
+
while (marker.nextSibling) {
|
|
402
|
+
trailingClone.appendChild(marker.nextSibling);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
parent.insertBefore(trailingClone, underlineElement.nextSibling);
|
|
406
|
+
parent.insertBefore(marker, trailingClone);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
@@ -65,6 +65,13 @@ export class RectangleSelection extends Module {
|
|
|
65
65
|
*/
|
|
66
66
|
private mousedown = false;
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Set when mousedown starts from a contentEditable element that is within the
|
|
70
|
+
* editor's horizontal content bounds. Prevents the toolbar from re-opening via
|
|
71
|
+
* the BlockHovered event while the user is dragging. Cleared on mouseup.
|
|
72
|
+
*/
|
|
73
|
+
private mouseDownWithinBoundsFromContentEditable = false;
|
|
74
|
+
|
|
68
75
|
/**
|
|
69
76
|
* Is scrolling now
|
|
70
77
|
*/
|
|
@@ -213,6 +220,7 @@ export class RectangleSelection extends Module {
|
|
|
213
220
|
*/
|
|
214
221
|
public endSelection(): void {
|
|
215
222
|
this.mousedown = false;
|
|
223
|
+
this.mouseDownWithinBoundsFromContentEditable = false;
|
|
216
224
|
this.startX = 0;
|
|
217
225
|
this.startY = 0;
|
|
218
226
|
this.anchorBlockIndex = null;
|
|
@@ -229,6 +237,18 @@ export class RectangleSelection extends Module {
|
|
|
229
237
|
return this.isRectSelectionActivated || this.mousedown;
|
|
230
238
|
}
|
|
231
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Returns true when the user pressed down a mouse button within the editor's horizontal
|
|
242
|
+
* content bounds, even if the click originated on a contentEditable element (in which
|
|
243
|
+
* case rubber-band selection is not started but the toolbar is still closed).
|
|
244
|
+
*
|
|
245
|
+
* Used by the Toolbar module to suppress toolbar reopening while the user is dragging
|
|
246
|
+
* inside the editor content area.
|
|
247
|
+
*/
|
|
248
|
+
public get isMouseDownWithinBounds(): boolean {
|
|
249
|
+
return this.mouseDownWithinBoundsFromContentEditable;
|
|
250
|
+
}
|
|
251
|
+
|
|
232
252
|
/**
|
|
233
253
|
* Mark that selection is end
|
|
234
254
|
*/
|
|
@@ -305,6 +325,24 @@ export class RectangleSelection extends Module {
|
|
|
305
325
|
|
|
306
326
|
if (!startedFromContentEditable) {
|
|
307
327
|
this.startSelection(mouseEvent.pageX, mouseEvent.pageY, mouseEvent.shiftKey);
|
|
328
|
+
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* When dragging starts from a contentEditable element, track whether the
|
|
334
|
+
* pointer is within the editor's horizontal content bounds.
|
|
335
|
+
* On the first subsequent mousemove (i.e. when the user actually drags rather
|
|
336
|
+
* than just clicking), the toolbar will be closed and hover-based reopening
|
|
337
|
+
* will be suppressed while the mouse button is held.
|
|
338
|
+
*/
|
|
339
|
+
const scrollLeft = this.getScrollLeft();
|
|
340
|
+
const pointerX = mouseEvent.pageX - scrollLeft;
|
|
341
|
+
const contentRect = this.Blok.UI.contentRect;
|
|
342
|
+
const withinEditorHorizontally = pointerX >= contentRect.left && pointerX <= contentRect.right;
|
|
343
|
+
|
|
344
|
+
if (withinEditorHorizontally) {
|
|
345
|
+
this.mouseDownWithinBoundsFromContentEditable = true;
|
|
308
346
|
}
|
|
309
347
|
}
|
|
310
348
|
|
|
@@ -313,6 +351,16 @@ export class RectangleSelection extends Module {
|
|
|
313
351
|
* @param {MouseEvent} mouseEvent - mouse event payload
|
|
314
352
|
*/
|
|
315
353
|
private processMouseMove(mouseEvent: MouseEvent): void {
|
|
354
|
+
/**
|
|
355
|
+
* When the user clicked inside a contentEditable element within the editor's
|
|
356
|
+
* horizontal bounds and is now dragging, close the toolbar on the first move.
|
|
357
|
+
* We defer this to mousemove (rather than mousedown) so that a plain click
|
|
358
|
+
* does not accidentally close the toolbar.
|
|
359
|
+
*/
|
|
360
|
+
if (this.mouseDownWithinBoundsFromContentEditable) {
|
|
361
|
+
this.Blok.Toolbar.close();
|
|
362
|
+
}
|
|
363
|
+
|
|
316
364
|
this.changingRectangle(mouseEvent);
|
|
317
365
|
this.scrollByZones(mouseEvent.clientY);
|
|
318
366
|
}
|
|
@@ -1009,9 +1009,12 @@ export class Toolbar extends Module<ToolbarNodes> {
|
|
|
1009
1009
|
*/
|
|
1010
1010
|
this.eventsDispatcher.on(BlockHovered, (data) => {
|
|
1011
1011
|
/**
|
|
1012
|
-
* Do not move toolbar during drag
|
|
1012
|
+
* Do not move toolbar during drag, rectangle selection, or when the user
|
|
1013
|
+
* started a mouse-drag from within the editor's content area (even if the
|
|
1014
|
+
* drag originated on a contentEditable element, i.e. rubber-band is not
|
|
1015
|
+
* activated but the toolbar was closed and should stay closed).
|
|
1013
1016
|
*/
|
|
1014
|
-
if (this.Blok.DragManager.isDragging || this.Blok.RectangleSelection.isRectActivated()) {
|
|
1017
|
+
if (this.Blok.DragManager.isDragging || this.Blok.RectangleSelection.isRectActivated() || this.Blok.RectangleSelection.isMouseDownWithinBounds) {
|
|
1015
1018
|
return;
|
|
1016
1019
|
}
|
|
1017
1020
|
|
|
@@ -165,7 +165,11 @@ export function createColorPicker(options: ColorPickerOptions): ColorPickerHandl
|
|
|
165
165
|
defaultSwatch.addEventListener('click', () => {
|
|
166
166
|
onColorSelect(null, mode.key);
|
|
167
167
|
});
|
|
168
|
-
|
|
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' });
|
|
169
173
|
grid.appendChild(defaultSwatch);
|
|
170
174
|
|
|
171
175
|
for (const preset of presets) {
|
|
@@ -193,7 +197,11 @@ export function createColorPicker(options: ColorPickerOptions): ColorPickerHandl
|
|
|
193
197
|
swatch.addEventListener('click', () => {
|
|
194
198
|
onColorSelect(swatchColor, mode.key);
|
|
195
199
|
});
|
|
196
|
-
|
|
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' });
|
|
197
205
|
grid.appendChild(swatch);
|
|
198
206
|
}
|
|
199
207
|
};
|
package/src/full.ts
CHANGED
|
@@ -19,6 +19,8 @@ import { BoldInlineTool as Bold } from './components/inline-tools/inline-tool-bo
|
|
|
19
19
|
import { ItalicInlineTool as Italic } from './components/inline-tools/inline-tool-italic';
|
|
20
20
|
import { LinkInlineTool as Link } from './components/inline-tools/inline-tool-link';
|
|
21
21
|
import { MarkerInlineTool as Marker } from './components/inline-tools/inline-tool-marker';
|
|
22
|
+
import { UnderlineInlineTool as Underline } from './components/inline-tools/inline-tool-underline';
|
|
23
|
+
import { StrikethroughInlineTool as Strikethrough } from './components/inline-tools/inline-tool-strikethrough';
|
|
22
24
|
import { Header } from './tools/header';
|
|
23
25
|
import { ListItem as List } from './tools/list';
|
|
24
26
|
import { Paragraph } from './tools/paragraph';
|
|
@@ -35,6 +37,8 @@ export {
|
|
|
35
37
|
Italic,
|
|
36
38
|
Link,
|
|
37
39
|
Marker,
|
|
40
|
+
Underline,
|
|
41
|
+
Strikethrough,
|
|
38
42
|
defaultBlockTools,
|
|
39
43
|
defaultInlineTools,
|
|
40
44
|
} from './tools';
|
|
@@ -68,6 +72,8 @@ export const allTools = {
|
|
|
68
72
|
...defaultTools,
|
|
69
73
|
bold: { class: Bold },
|
|
70
74
|
italic: { class: Italic },
|
|
71
|
-
link: { class: Link },
|
|
72
75
|
marker: { class: Marker },
|
|
76
|
+
underline: { class: Underline },
|
|
77
|
+
strikethrough: { class: Strikethrough },
|
|
78
|
+
link: { class: Link },
|
|
73
79
|
} as const;
|
|
@@ -93,8 +93,8 @@ const INLINE_TOOLBAR_TESTID = '[data-blok-testid="inline-toolbar"]';
|
|
|
93
93
|
const CONTENTEDITABLE_SELECTOR = '[contenteditable="true"]';
|
|
94
94
|
const MARKER_TOOL_SELECTOR = '[data-blok-item-name="marker"]';
|
|
95
95
|
const MARKER_PICKER_SELECTOR = '[data-blok-testid="marker-picker"]';
|
|
96
|
-
const
|
|
97
|
-
const
|
|
96
|
+
const MARKER_COLOR_SECTION_SELECTOR = '[data-blok-testid="marker-section-color"] button';
|
|
97
|
+
const MARKER_BG_SECTION_SELECTOR = '[data-blok-testid="marker-section-background-color"] button';
|
|
98
98
|
const TIMEOUT_INIT = { timeout: 5000 };
|
|
99
99
|
const TIMEOUT_ACTION = { timeout: 5000 };
|
|
100
100
|
|
|
@@ -411,8 +411,7 @@ export const PickerTextTab: Story = {
|
|
|
411
411
|
|
|
412
412
|
await waitFor(
|
|
413
413
|
() => {
|
|
414
|
-
const
|
|
415
|
-
const swatches = grid?.querySelectorAll('button');
|
|
414
|
+
const swatches = document.querySelectorAll(MARKER_COLOR_SECTION_SELECTOR);
|
|
416
415
|
|
|
417
416
|
expect(swatches?.length).toBe(10);
|
|
418
417
|
},
|
|
@@ -434,24 +433,14 @@ export const PickerBackgroundTab: Story = {
|
|
|
434
433
|
chromatic: { delay: 500 },
|
|
435
434
|
},
|
|
436
435
|
play: async ({ canvasElement, step }) => {
|
|
437
|
-
await step('Open marker picker', async () => {
|
|
436
|
+
await step('Open marker picker and verify background section', async () => {
|
|
438
437
|
await openMarkerPicker(canvasElement);
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
await step('Switch to background tab', async () => {
|
|
442
|
-
const bgTab = document.querySelector(MARKER_TAB_BG_SELECTOR);
|
|
443
|
-
|
|
444
|
-
expect(bgTab).toBeInTheDocument();
|
|
445
|
-
|
|
446
|
-
if (bgTab) {
|
|
447
|
-
simulateClick(bgTab);
|
|
448
|
-
}
|
|
449
438
|
|
|
450
439
|
await waitFor(
|
|
451
440
|
() => {
|
|
452
|
-
const
|
|
441
|
+
const swatches = document.querySelectorAll(MARKER_BG_SECTION_SELECTOR);
|
|
453
442
|
|
|
454
|
-
expect(
|
|
443
|
+
expect(swatches?.length).toBe(10);
|
|
455
444
|
},
|
|
456
445
|
TIMEOUT_ACTION
|
|
457
446
|
);
|
|
@@ -475,7 +464,7 @@ export const PickerDefaultButton: Story = {
|
|
|
475
464
|
|
|
476
465
|
await waitFor(
|
|
477
466
|
() => {
|
|
478
|
-
const defaultBtn = document.querySelector('[data-blok-testid="marker-default
|
|
467
|
+
const defaultBtn = document.querySelector('[data-blok-testid="marker-swatch-color-default"]');
|
|
479
468
|
|
|
480
469
|
expect(defaultBtn).toBeInTheDocument();
|
|
481
470
|
},
|
|
@@ -502,13 +491,12 @@ export const PickerNoActiveSwatch: Story = {
|
|
|
502
491
|
|
|
503
492
|
await waitFor(
|
|
504
493
|
() => {
|
|
505
|
-
const
|
|
506
|
-
const swatches = grid?.querySelectorAll('button');
|
|
494
|
+
const swatches = document.querySelectorAll(MARKER_COLOR_SECTION_SELECTOR);
|
|
507
495
|
|
|
508
496
|
expect(swatches?.length).toBe(10);
|
|
509
497
|
|
|
510
498
|
swatches?.forEach((swatch) => {
|
|
511
|
-
expect(swatch.className).not.toContain('ring-
|
|
499
|
+
expect(swatch.className).not.toContain('ring-swatch-ring-hover');
|
|
512
500
|
});
|
|
513
501
|
},
|
|
514
502
|
TIMEOUT_ACTION
|
|
@@ -581,9 +569,9 @@ export const PickerActiveTextSwatch: Story = {
|
|
|
581
569
|
// Verify the red swatch has the active ring
|
|
582
570
|
await waitFor(
|
|
583
571
|
() => {
|
|
584
|
-
const redSwatch = document.querySelector('[data-blok-testid="marker-swatch-red"]');
|
|
572
|
+
const redSwatch = document.querySelector('[data-blok-testid="marker-swatch-color-red"]');
|
|
585
573
|
|
|
586
|
-
expect(redSwatch?.className).toContain('ring-
|
|
574
|
+
expect(redSwatch?.className).toContain('ring-swatch-ring-hover');
|
|
587
575
|
},
|
|
588
576
|
TIMEOUT_ACTION
|
|
589
577
|
);
|
|
@@ -653,21 +641,12 @@ export const PickerActiveBackgroundSwatch: Story = {
|
|
|
653
641
|
TIMEOUT_ACTION
|
|
654
642
|
);
|
|
655
643
|
|
|
656
|
-
// Switch to background tab
|
|
657
|
-
const bgTab = document.querySelector(MARKER_TAB_BG_SELECTOR);
|
|
658
|
-
|
|
659
|
-
expect(bgTab).toBeInTheDocument();
|
|
660
|
-
|
|
661
|
-
if (bgTab) {
|
|
662
|
-
simulateClick(bgTab);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
644
|
// Verify the orange swatch has the active ring
|
|
666
645
|
await waitFor(
|
|
667
646
|
() => {
|
|
668
|
-
const orangeSwatch = document.querySelector('[data-blok-testid="marker-swatch-orange"]');
|
|
647
|
+
const orangeSwatch = document.querySelector('[data-blok-testid="marker-swatch-background-color-orange"]');
|
|
669
648
|
|
|
670
|
-
expect(orangeSwatch?.className).toContain('ring-
|
|
649
|
+
expect(orangeSwatch?.className).toContain('ring-swatch-ring-hover');
|
|
671
650
|
},
|
|
672
651
|
TIMEOUT_ACTION
|
|
673
652
|
);
|
package/src/styles/main.css
CHANGED
|
@@ -1041,7 +1041,7 @@
|
|
|
1041
1041
|
*/
|
|
1042
1042
|
@utility blok-block {
|
|
1043
1043
|
/* Base Blok styles - applied to block tool wrappers */
|
|
1044
|
-
@apply py-[
|
|
1044
|
+
@apply py-[7px] px-[2px] [&::-webkit-input-placeholder]:leading-normal!;
|
|
1045
1045
|
}
|
|
1046
1046
|
@utility blok-inline-tool-button {
|
|
1047
1047
|
/* Inline Tools styles */
|