@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 { IconStrikethrough } 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 a strikethrough tag (<s>)
|
|
14
|
+
* @param element - The element to check
|
|
15
|
+
*/
|
|
16
|
+
const isStrikethroughTag = (element: Element): boolean => {
|
|
17
|
+
return element.tagName === 'S';
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Strikethrough Tool
|
|
22
|
+
*
|
|
23
|
+
* Inline Toolbar Tool
|
|
24
|
+
*
|
|
25
|
+
* Style selected text with strikethrough
|
|
26
|
+
*/
|
|
27
|
+
export class StrikethroughInlineTool 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 = 'Strikethrough';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Translation key for i18n
|
|
41
|
+
*/
|
|
42
|
+
public static titleKey = 'strikethrough';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sanitizer Rule
|
|
46
|
+
* Leave <s> tags
|
|
47
|
+
* @returns {object}
|
|
48
|
+
*/
|
|
49
|
+
public static get sanitize(): SanitizerConfig {
|
|
50
|
+
return {
|
|
51
|
+
s: {},
|
|
52
|
+
} as SanitizerConfig;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Create button for Inline Toolbar
|
|
57
|
+
*/
|
|
58
|
+
public render(): MenuConfig {
|
|
59
|
+
return {
|
|
60
|
+
icon: IconStrikethrough,
|
|
61
|
+
name: 'strikethrough',
|
|
62
|
+
onActivate: () => {
|
|
63
|
+
this.toggleStrikethrough();
|
|
64
|
+
},
|
|
65
|
+
isActive: () => {
|
|
66
|
+
const selection = window.getSelection();
|
|
67
|
+
|
|
68
|
+
return selection ? this.isSelectionVisuallyStrikethrough(selection) : false;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Shortcut for strikethrough tool
|
|
75
|
+
*/
|
|
76
|
+
public static shortcut = 'CMD+SHIFT+S';
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Apply or remove strikethrough formatting using modern Selection API
|
|
80
|
+
*/
|
|
81
|
+
private toggleStrikethrough(): 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.toggleCollapsedStrikethrough(range, selection);
|
|
92
|
+
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const shouldUnwrap = this.isRangeStrikethrough(range, { ignoreWhitespace: true });
|
|
97
|
+
|
|
98
|
+
if (shouldUnwrap) {
|
|
99
|
+
this.unwrapStrikethroughTags(range);
|
|
100
|
+
} else {
|
|
101
|
+
this.wrapWithStrikethrough(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 toggleCollapsedStrikethrough(range: Range, selection: Selection): void {
|
|
111
|
+
const isStrikethrough = this.isRangeStrikethrough(range, { ignoreWhitespace: true });
|
|
112
|
+
|
|
113
|
+
if (isStrikethrough) {
|
|
114
|
+
const textNode = document.createTextNode('\u200B');
|
|
115
|
+
|
|
116
|
+
range.insertNode(textNode);
|
|
117
|
+
range.selectNode(textNode);
|
|
118
|
+
this.unwrapStrikethroughTags(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 s = document.createElement('s');
|
|
129
|
+
const textNode = document.createTextNode('\u200B');
|
|
130
|
+
|
|
131
|
+
s.appendChild(textNode);
|
|
132
|
+
range.insertNode(s);
|
|
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 a strikethrough tag
|
|
146
|
+
* @param selection - The Selection object to check
|
|
147
|
+
*/
|
|
148
|
+
private isSelectionVisuallyStrikethrough(selection: Selection): boolean {
|
|
149
|
+
if (selection.rangeCount === 0) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const range = selection.getRangeAt(0);
|
|
154
|
+
|
|
155
|
+
return this.isRangeStrikethrough(range, { ignoreWhitespace: true });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if a range contains strikethrough text
|
|
160
|
+
* @param range - The range to check
|
|
161
|
+
* @param options - Options for checking strikethrough status
|
|
162
|
+
*/
|
|
163
|
+
private isRangeStrikethrough(range: Range, options: { ignoreWhitespace: boolean }): boolean {
|
|
164
|
+
return isRangeFormatted(range, isStrikethroughTag, options);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Wrap selection with <s> tag
|
|
169
|
+
* @param range - The Range object containing the selection to wrap
|
|
170
|
+
*/
|
|
171
|
+
private wrapWithStrikethrough(range: Range): void {
|
|
172
|
+
const html = this.getRangeHtmlWithoutStrikethrough(range);
|
|
173
|
+
const insertedRange = this.replaceRangeWithHtml(range, `<s>${html}</s>`);
|
|
174
|
+
const selection = window.getSelection();
|
|
175
|
+
|
|
176
|
+
if (selection && insertedRange) {
|
|
177
|
+
selection.removeAllRanges();
|
|
178
|
+
selection.addRange(insertedRange);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Remove strikethrough tags (<s>) while preserving content
|
|
184
|
+
* @param range - The Range object containing the selection to unwrap
|
|
185
|
+
*/
|
|
186
|
+
private unwrapStrikethroughTags(range: Range): void {
|
|
187
|
+
const strikethroughAncestors = this.collectStrikethroughAncestors(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.removeNestedStrikethrough(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 currentStrikethrough = this.findStrikethroughElement(marker);
|
|
210
|
+
|
|
211
|
+
if (!currentStrikethrough) {
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.moveMarkerOutOfStrikethrough(marker, currentStrikethrough);
|
|
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
|
+
strikethroughAncestors.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 a strikethrough tag
|
|
248
|
+
* @param node - The node to check
|
|
249
|
+
*/
|
|
250
|
+
private hasStrikethroughParent(node: Node | null): boolean {
|
|
251
|
+
return hasFormattingAncestor(node, isStrikethroughTag);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Find a strikethrough element in the parent chain
|
|
256
|
+
* @param node - The node to start searching from
|
|
257
|
+
*/
|
|
258
|
+
private findStrikethroughElement(node: Node | null): HTMLElement | null {
|
|
259
|
+
return findFormattingAncestor(node, isStrikethroughTag);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Collect all strikethrough ancestor elements within a range
|
|
264
|
+
* @param range - The range to search for strikethrough ancestors
|
|
265
|
+
*/
|
|
266
|
+
private collectStrikethroughAncestors(range: Range): HTMLElement[] {
|
|
267
|
+
return collectFormattingAncestors(range, isStrikethroughTag);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get HTML content of a range with strikethrough tags removed
|
|
272
|
+
* @param range - The range to extract HTML from
|
|
273
|
+
*/
|
|
274
|
+
private getRangeHtmlWithoutStrikethrough(range: Range): string {
|
|
275
|
+
const contents = range.cloneContents();
|
|
276
|
+
|
|
277
|
+
this.removeNestedStrikethrough(contents);
|
|
278
|
+
|
|
279
|
+
const container = document.createElement('div');
|
|
280
|
+
|
|
281
|
+
container.appendChild(contents);
|
|
282
|
+
|
|
283
|
+
return container.innerHTML;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Remove nested strikethrough tags from a root node
|
|
288
|
+
* @param root - The root node to process
|
|
289
|
+
*/
|
|
290
|
+
private removeNestedStrikethrough(root: ParentNode): void {
|
|
291
|
+
const strikethroughNodes = root.querySelectorAll('s');
|
|
292
|
+
|
|
293
|
+
strikethroughNodes.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 a strikethrough ancestor while preserving content order
|
|
358
|
+
* @param marker - Marker element wrapping the selection contents
|
|
359
|
+
* @param strikethroughElement - Strikethrough ancestor containing the marker
|
|
360
|
+
*/
|
|
361
|
+
private moveMarkerOutOfStrikethrough(marker: HTMLElement, strikethroughElement: HTMLElement): void {
|
|
362
|
+
const parent = strikethroughElement.parentNode;
|
|
363
|
+
|
|
364
|
+
if (!parent) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Remove empty text nodes to ensure accurate child count
|
|
369
|
+
Array.from(strikethroughElement.childNodes).forEach((node) => {
|
|
370
|
+
if (node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').length === 0) {
|
|
371
|
+
node.remove();
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const isOnlyChild = strikethroughElement.childNodes.length === 1 && strikethroughElement.firstChild === marker;
|
|
376
|
+
|
|
377
|
+
if (isOnlyChild) {
|
|
378
|
+
strikethroughElement.replaceWith(marker);
|
|
379
|
+
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const isFirstChild = strikethroughElement.firstChild === marker;
|
|
384
|
+
|
|
385
|
+
if (isFirstChild) {
|
|
386
|
+
parent.insertBefore(marker, strikethroughElement);
|
|
387
|
+
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const isLastChild = strikethroughElement.lastChild === marker;
|
|
392
|
+
|
|
393
|
+
if (isLastChild) {
|
|
394
|
+
parent.insertBefore(marker, strikethroughElement.nextSibling);
|
|
395
|
+
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const trailingClone = strikethroughElement.cloneNode(false) as HTMLElement;
|
|
400
|
+
|
|
401
|
+
while (marker.nextSibling) {
|
|
402
|
+
trailingClone.appendChild(marker.nextSibling);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
parent.insertBefore(trailingClone, strikethroughElement.nextSibling);
|
|
406
|
+
parent.insertBefore(marker, trailingClone);
|
|
407
|
+
}
|
|
408
|
+
}
|