@jackuait/blok 0.16.1 → 0.17.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.cjs +1 -1
- package/dist/blok.iife.js +4 -4
- package/dist/blok.mjs +2 -2
- package/dist/blok.umd.js +4 -4
- package/dist/chunks/{blok-DEVVs3xk.cjs → blok-BPd65xOj.cjs} +11 -11
- package/dist/chunks/{blok-D1e9swtF.mjs → blok-D4ApwnD7.mjs} +776 -780
- package/dist/chunks/constants-C3wBsvmH.cjs +606 -0
- package/dist/chunks/{constants-DfGAwzgk.mjs → constants-DObdf8NU.mjs} +274 -274
- package/dist/chunks/{i18next-loader-BH_a6G9t.mjs → i18next-loader-BMhspWFn.mjs} +1 -1
- package/dist/chunks/{i18next-loader-BID4jAFG.cjs → i18next-loader-CNLosgId.cjs} +1 -1
- package/dist/chunks/{lightweight-i18n-Clk37huC.cjs → lightweight-i18n-ByswFbdt.cjs} +1 -1
- package/dist/chunks/{lightweight-i18n-B0VO8Rft.mjs → lightweight-i18n-Ck1HlVxq.mjs} +32 -0
- package/dist/chunks/{messages-BGoPxZ5n.mjs → messages--uPFKcl3.mjs} +33 -1
- package/dist/{messages-BmKhZE7I.mjs → chunks/messages-0ZOxg81Y.mjs} +33 -1
- package/dist/chunks/{messages-BxhJFFrR.mjs → messages-1H2SY5H1.mjs} +33 -1
- package/dist/chunks/{messages-px_8gpHT.cjs → messages-1bAMgAsO.cjs} +1 -1
- package/dist/chunks/{messages-CO_hj1x6.cjs → messages-3B44ZmLZ.cjs} +1 -1
- package/dist/chunks/{messages-5tb-mSXS.cjs → messages-3iZ6jJ6e.cjs} +1 -1
- package/dist/chunks/{messages-BVuodJIJ.cjs → messages-5Rp1xyL4.cjs} +1 -1
- package/dist/chunks/{messages-CgGwGZs22.cjs → messages-5Vbzn-DL2.cjs} +1 -1
- package/dist/chunks/{messages-De0Fkl0K.mjs → messages-61uWTg1y.mjs} +33 -1
- package/dist/chunks/messages-6lqZ4lhc2.cjs +1 -0
- package/dist/chunks/messages-795D2ldP2.cjs +1 -0
- package/dist/chunks/{messages-CUxk6xrQ.cjs → messages-79WWudxY.cjs} +1 -1
- package/dist/chunks/{messages-B-3_M44j.cjs → messages-8uD5ctYP.cjs} +1 -1
- package/dist/{messages-Z8HMjhe9.mjs → chunks/messages-9gvi5jul.mjs} +33 -1
- package/dist/chunks/{messages-BDNdC6-X.cjs → messages-B0o3rVBB.cjs} +1 -1
- package/dist/chunks/messages-B1h0nDQW.cjs +1 -0
- package/dist/chunks/{messages-BPYQEADI.cjs → messages-B37vUkBi.cjs} +1 -1
- package/dist/{messages-BrkXHD2D2.mjs → chunks/messages-B4BvJtlu.mjs} +33 -1
- package/dist/{messages-CsHwUgSZ.mjs → chunks/messages-BChCPw99.mjs} +33 -1
- package/dist/chunks/{messages-DkINYHo4.cjs → messages-BDs_gdD_.cjs} +1 -1
- package/dist/chunks/{messages-Cz7AbEFm.cjs → messages-BE6rW2R-.cjs} +1 -1
- package/dist/{messages-DFKu1WGX2.mjs → chunks/messages-BFGgLdIA2.mjs} +33 -1
- package/dist/{messages-D1jUHOKr.mjs → chunks/messages-BFcq7wsx.mjs} +33 -1
- package/dist/{messages-BbFJ2r9p.mjs → chunks/messages-BGaAuDRS.mjs} +33 -1
- package/dist/chunks/{messages-Dml6u25s2.cjs → messages-BGoJHXUk2.cjs} +1 -1
- package/dist/chunks/{messages-DDnB1EFE2.mjs → messages-BIHeeP7X2.mjs} +33 -1
- package/dist/{messages-6RcfJ59a.mjs → chunks/messages-BIQ2VT8X2.mjs} +33 -1
- package/dist/chunks/{messages-Bnm45Rmp.mjs → messages-BK32XCpH.mjs} +33 -1
- package/dist/{messages-BkNVOuvO2.mjs → chunks/messages-BKSDnjOs.mjs} +33 -1
- package/dist/chunks/{messages-CdOX6JHb2.mjs → messages-BMNmXaC8.mjs} +33 -1
- package/dist/{messages-Cg3w36Bc.mjs → chunks/messages-BNuGVAEy.mjs} +33 -1
- package/dist/chunks/{messages-C62iC79d2.mjs → messages-BQEh67Mi2.mjs} +33 -1
- package/dist/chunks/{messages-BG1Tn41d.cjs → messages-BQOx3XGd.cjs} +1 -1
- package/dist/{messages-DaoTSrJW.mjs → chunks/messages-BQUzqXIO.mjs} +33 -1
- package/dist/chunks/{messages-DuOkV5T_.mjs → messages-BTKPcoLu.mjs} +33 -1
- package/dist/chunks/messages-BXgTHDIw.cjs +1 -0
- package/dist/chunks/{messages-BItPVbHx.cjs → messages-BXvKhyQH.cjs} +1 -1
- package/dist/chunks/{messages-98gouyMa.cjs → messages-BYW-U0iT.cjs} +1 -1
- package/dist/chunks/{messages-Bs9JOJDc.cjs → messages-B_lkWkPQ.cjs} +1 -1
- package/dist/chunks/{messages-Bq7pLz_h2.mjs → messages-BaWaLwcn2.mjs} +33 -1
- package/dist/chunks/{messages-DsWTIuli2.cjs → messages-BeTQxvmX2.cjs} +1 -1
- package/dist/chunks/{messages-BSyXBvUi2.cjs → messages-BfWGa4V82.cjs} +1 -1
- package/dist/{messages-GUgmAfdB.mjs → chunks/messages-Bgzyr5Lh.mjs} +33 -1
- package/dist/chunks/{messages-UoKgx7_8.cjs → messages-BjFB8sow.cjs} +1 -1
- package/dist/chunks/messages-Bjmg_8lv2.cjs +1 -0
- package/dist/chunks/{messages-CVHSfosB.cjs → messages-BlOVJtaj.cjs} +1 -1
- package/dist/{messages-CSVEbRhT.mjs → chunks/messages-BnW_Fwro.mjs} +33 -1
- package/dist/chunks/{messages-BdjiMHzU2.cjs → messages-Bpvja9xW2.cjs} +1 -1
- package/dist/chunks/{messages-BSxgqWqe.cjs → messages-BtMQ6v_L.cjs} +1 -1
- package/dist/chunks/{messages-Cx1kdFH_2.cjs → messages-BvChjyuU2.cjs} +1 -1
- package/dist/chunks/{messages-BSstxb1m2.mjs → messages-Bvge__AJ2.mjs} +33 -1
- package/dist/chunks/{messages-BhTV7PCN.mjs → messages-BwxzN2q3.mjs} +33 -1
- package/dist/chunks/{messages-DubJ63UL.mjs → messages-Byntrl2c.mjs} +33 -1
- package/dist/{messages-BfGAGIg-2.mjs → chunks/messages-C3B8l3Hy.mjs} +33 -1
- package/dist/chunks/{messages-CZQuqbNz2.cjs → messages-C3fAHxfE2.cjs} +1 -1
- package/dist/{messages-BOEP2ly_.mjs → chunks/messages-C56BTPcC.mjs} +33 -1
- package/dist/chunks/{messages-BXmg4Rer2.mjs → messages-C6vijVZv2.mjs} +33 -1
- package/dist/{messages-zoHZbvbe.mjs → chunks/messages-C79Ef9MU.mjs} +33 -1
- package/dist/{messages-CzabNeP5.mjs → chunks/messages-C93gDUHr.mjs} +33 -1
- package/dist/chunks/messages-CAix8jdZ.cjs +1 -0
- package/dist/chunks/{messages-BHE1mg5A2.mjs → messages-CEUDK26P2.mjs} +33 -1
- package/dist/chunks/{messages-D2nTfhRa2.cjs → messages-CEZ528TO2.cjs} +1 -1
- package/dist/chunks/{messages-Ced9OY9X.mjs → messages-CHx6m_Bo.mjs} +33 -1
- package/dist/chunks/{messages-Ck6jEhXV.cjs → messages-CKiWXTe1.cjs} +1 -1
- package/dist/{messages-DfnSbN512.mjs → chunks/messages-CMFcaa9C.mjs} +33 -1
- package/dist/chunks/{messages-jAgR8EPP.cjs → messages-CO4J7Nns.cjs} +1 -1
- package/dist/chunks/messages-COTP4ZJ_2.cjs +1 -0
- package/dist/{messages-TfPmsrxh.mjs → chunks/messages-CV3U2Vsm.mjs} +33 -1
- package/dist/chunks/{messages-BClegbPD.mjs → messages-CYOersvL.mjs} +33 -1
- package/dist/chunks/{messages-B3xnntgx2.mjs → messages-C_s-wv1r2.mjs} +33 -1
- package/dist/{messages-DSmNNjPb.mjs → chunks/messages-CbdaJSfC2.mjs} +33 -1
- package/dist/chunks/{messages-CxVi9cnz.mjs → messages-Ccng4hJ2.mjs} +33 -1
- package/dist/chunks/{messages-CpJW0LBR.cjs → messages-Cgph4q9d.cjs} +1 -1
- package/dist/chunks/{messages-DNYtMplL2.cjs → messages-Cp7wFDrY2.cjs} +1 -1
- package/dist/chunks/{messages-Bttb4o0k.cjs → messages-CpZneXUI.cjs} +1 -1
- package/dist/chunks/{messages-C2-v6HdR.cjs → messages-CpbireNX.cjs} +1 -1
- package/dist/{messages-C5sc4wjR.mjs → chunks/messages-CpcZgGYg.mjs} +33 -1
- package/dist/chunks/{messages-Cd-FaIr_2.mjs → messages-CqhQuuRo2.mjs} +33 -1
- package/dist/{messages-B8BXCJBA.mjs → chunks/messages-CrFIbrXr2.mjs} +33 -1
- package/dist/chunks/{messages-DB6z9ybS.cjs → messages-CrwZs1Gq.cjs} +1 -1
- package/dist/chunks/{messages-DQb9YRoO2.mjs → messages-D0_Mxuh62.mjs} +33 -1
- package/dist/{messages-2jeEK-EB.mjs → chunks/messages-D1q601Wg.mjs} +33 -1
- package/dist/{messages-BCGyLzFB2.mjs → chunks/messages-D3kC7iDa2.mjs} +33 -1
- package/dist/chunks/{messages-DwU7qOBO2.mjs → messages-D4UnR6e52.mjs} +33 -1
- package/dist/chunks/{messages-f1NcMMTR2.cjs → messages-D5CeQW1e2.cjs} +1 -1
- package/dist/chunks/messages-D8UH8jc6.cjs +1 -0
- package/dist/chunks/{messages-BJ7clJXu2.cjs → messages-DAmOTPVW2.cjs} +1 -1
- package/dist/{messages-DPZsygzY.mjs → chunks/messages-DBPkzBZO2.mjs} +33 -1
- package/dist/chunks/{messages-o3omNKfH.cjs → messages-DEduQerF.cjs} +1 -1
- package/dist/chunks/{messages-Beh905t72.mjs → messages-DFA5OVrs2.mjs} +33 -1
- package/dist/chunks/{messages-poLdFEEs2.cjs → messages-DHah-frn.cjs} +1 -1
- package/dist/chunks/messages-DI1ZLPxM.cjs +1 -0
- package/dist/chunks/{messages-BqM6l_JM2.mjs → messages-DKJ5CX9h2.mjs} +33 -1
- package/dist/chunks/{messages-s9I-JHCa.cjs → messages-DKjhx7Y3.cjs} +1 -1
- package/dist/chunks/{messages-GXQbRrHa2.mjs → messages-DR5DyRRY2.mjs} +33 -1
- package/dist/chunks/{messages-B94JmzMj.mjs → messages-DWjHAdb3.mjs} +33 -1
- package/dist/chunks/{messages-Cn0B5LU1.mjs → messages-DYsO5SIA.mjs} +33 -1
- package/dist/chunks/{messages-M2lNlKhI2.mjs → messages-DZwozMZD2.mjs} +33 -1
- package/dist/{messages-DGwIRpOH2.mjs → chunks/messages-Db_L5RNl.mjs} +33 -1
- package/dist/chunks/{messages-Bi3snvmH2.cjs → messages-DeXUZcFn2.cjs} +1 -1
- package/dist/chunks/messages-Dgp7Wk4H.cjs +1 -0
- package/dist/chunks/{messages-Cg6qicee.cjs → messages-DhnCZQEY.cjs} +1 -1
- package/dist/chunks/{messages-Ckej-nnJ.cjs → messages-DjU1jbKf.cjs} +1 -1
- package/dist/{messages-CJsMZvUv.mjs → chunks/messages-DkqiXPS7.mjs} +33 -1
- package/dist/chunks/{messages-p5w1kuc5.cjs → messages-Dl6VC9Q9.cjs} +1 -1
- package/dist/chunks/{messages-DG8Lmqf52.cjs → messages-Dlc1DdZ22.cjs} +1 -1
- package/dist/chunks/{messages-D8qYNZ_T.mjs → messages-Dna-8bQq.mjs} +33 -1
- package/dist/chunks/{messages-DgSRzW-Y.mjs → messages-DtTgOx9a.mjs} +33 -1
- package/dist/chunks/{messages-h43rfIyt2.mjs → messages-Duj8jpve2.mjs} +33 -1
- package/dist/chunks/{messages-XM0y9kXy2.cjs → messages-DvxZjb5g2.cjs} +1 -1
- package/dist/chunks/{messages-DWeyV2N3.cjs → messages-Dz8AmvFq.cjs} +1 -1
- package/dist/chunks/messages-DzarYc1J2.cjs +1 -0
- package/dist/{messages-BXs-Zwhx.mjs → chunks/messages-FIgYAomz2.mjs} +33 -1
- package/dist/chunks/{messages-04T5j1ww2.cjs → messages-FM0KHIkQ2.cjs} +1 -1
- package/dist/chunks/{messages-BtEDKVO7.cjs → messages-JsmKjXPZ.cjs} +1 -1
- package/dist/{messages-DvSC5JGC2.mjs → chunks/messages-LW9Kd-vn.mjs} +33 -1
- package/dist/chunks/{messages-LWyC-1ol.mjs → messages-R2RH1RLt.mjs} +33 -1
- package/dist/chunks/{messages-0OyEWZDW.cjs → messages-RWVOHsZu.cjs} +1 -1
- package/dist/chunks/{messages-DwAl9zoh2.mjs → messages-X90YfYzG2.mjs} +33 -1
- package/dist/chunks/{messages-BxRX_hY12.cjs → messages-YhmR1nl02.cjs} +1 -1
- package/dist/chunks/{messages-CT025FgD2.cjs → messages-Ywb6VdfO2.cjs} +1 -1
- package/dist/{messages-qjir1Zx9.mjs → chunks/messages-ZPOc6IQC.mjs} +33 -1
- package/dist/chunks/{messages-C-N1XBvh2.cjs → messages-_ECIn1VC2.cjs} +1 -1
- package/dist/chunks/{messages-Cf5mu1AT.cjs → messages-cYjlWqco.cjs} +1 -1
- package/dist/{messages-CS6vG53A.mjs → chunks/messages-dp4NwDVM.mjs} +33 -1
- package/dist/chunks/{messages-Bz_fTG46.mjs → messages-hhT3Vii-.mjs} +33 -1
- package/dist/chunks/messages-iwzDjgrP.cjs +1 -0
- package/dist/chunks/{messages-B5eo-pGw.mjs → messages-k4Do3gkF.mjs} +33 -1
- package/dist/chunks/{messages-BfYWRC3o.cjs → messages-l0nKmGOV.cjs} +1 -1
- package/dist/chunks/{messages-BtevAuQS2.cjs → messages-l7DqwqOu2.cjs} +1 -1
- package/dist/{messages-C9XTx39w2.mjs → chunks/messages-oLqnmqJf2.mjs} +33 -1
- package/dist/chunks/{messages-Vbqmvxs1.cjs → messages-sLVwrcar.cjs} +1 -1
- package/dist/chunks/{messages-DFUn1PHK2.mjs → messages-yGQn67fw2.mjs} +33 -1
- package/dist/chunks/{messages-CXlSU8cQ2.cjs → messages-zkunMjZf2.cjs} +1 -1
- package/dist/chunks/{tools-vX3wCW3a.mjs → tools-CM6aPuR4.mjs} +3442 -2226
- package/dist/chunks/tools-kfoXLTzY.cjs +208 -0
- package/dist/chunks/webm-muxer-CC98PYSV.cjs +5 -0
- package/dist/chunks/webm-muxer-CUUz719e.mjs +864 -0
- package/dist/full.cjs +1 -1
- package/dist/full.mjs +13 -13
- package/dist/locales.mjs +99 -67
- package/dist/{messages-iJKNW8hW2.mjs → messages-1ZSVxDYN2.mjs} +33 -1
- package/dist/{chunks/messages-dZdV8VYV.mjs → messages-AK_9q2yu.mjs} +33 -1
- package/dist/{messages-eFz25q1T.mjs → messages-B0Gc0lBw.mjs} +33 -1
- package/dist/{messages-ChivLKDg2.mjs → messages-B5THTOwb2.mjs} +33 -1
- package/dist/{messages-Bd2Q-tnQ.mjs → messages-B5xy5hCa.mjs} +33 -1
- package/dist/{chunks/messages-CSc7Lh_3.mjs → messages-B6J8l1aF.mjs} +33 -1
- package/dist/{messages-tcfLP2b2.mjs → messages-B7E1zFAv.mjs} +33 -1
- package/dist/{messages-gJWgJtGo.mjs → messages-B87GXoqt.mjs} +33 -1
- package/dist/{chunks/messages-8vGF8iWb.mjs → messages-B95smO_C.mjs} +33 -1
- package/dist/{messages-Dw7P8bMa2.mjs → messages-B9h-mKVO2.mjs} +33 -1
- package/dist/{chunks/messages-D1gz17wt.mjs → messages-BBb_hXxm.mjs} +33 -1
- package/dist/{messages-kb2GSl-V.mjs → messages-BDJfFuXR.mjs} +33 -1
- package/dist/{messages-C1d7I7f_2.mjs → messages-BH5AKf_i2.mjs} +33 -1
- package/dist/{chunks/messages-CZ4Jcn6y.mjs → messages-BLslMhf-.mjs} +33 -1
- package/dist/{chunks/messages-PtDEkfSR2.mjs → messages-BPsdJnwT.mjs} +33 -1
- package/dist/{chunks/messages-BQKWm9xB.mjs → messages-BTrok9K8.mjs} +33 -1
- package/dist/{messages-B0n-WDK72.mjs → messages-BctWdAZP2.mjs} +33 -1
- package/dist/{messages-CX2ioEBc2.mjs → messages-BhGHyHKC2.mjs} +33 -1
- package/dist/{messages-CWdh59uz2.mjs → messages-BlInN8XP2.mjs} +33 -1
- package/dist/{chunks/messages-xMrks-Gg.mjs → messages-Bn19MGza.mjs} +33 -1
- package/dist/{chunks/messages-Cc56SxY7.mjs → messages-BqFRlEJE2.mjs} +33 -1
- package/dist/{messages-DMH0zRig2.mjs → messages-Bt5Sbl952.mjs} +33 -1
- package/dist/{chunks/messages-CHizzxUv.mjs → messages-Bumbqs6s.mjs} +33 -1
- package/dist/{messages-BytEaMMs.mjs → messages-BvwVDbII.mjs} +33 -1
- package/dist/{chunks/messages-DzZZDveu.mjs → messages-Bwese2OQ.mjs} +33 -1
- package/dist/{chunks/messages-Vdmc6CaN.mjs → messages-Bx5KWmyJ.mjs} +33 -1
- package/dist/{chunks/messages-BzC8TVYC.mjs → messages-ByntluqZ.mjs} +33 -1
- package/dist/{messages-C2pz0mJs2.mjs → messages-C-8BMvSp2.mjs} +33 -1
- package/dist/{messages-BInBVzW42.mjs → messages-C-ytN6Dz2.mjs} +33 -1
- package/dist/{messages-CUsdyCrN2.mjs → messages-C8QB980F2.mjs} +33 -1
- package/dist/{chunks/messages-ID7kZQyc.mjs → messages-CCdDP2DE.mjs} +33 -1
- package/dist/{chunks/messages-Cx_kyYnf2.mjs → messages-CCgDqF-e.mjs} +33 -1
- package/dist/{chunks/messages-DyuKfskv.mjs → messages-CLkbvdRh2.mjs} +33 -1
- package/dist/{messages-DPzZM5FG.mjs → messages-CQ6A0zI9.mjs} +33 -1
- package/dist/{chunks/messages-DjSuzS2m2.mjs → messages-CQnz6pXD2.mjs} +33 -1
- package/dist/{messages-CWWIbebM2.mjs → messages-CQotju8u2.mjs} +33 -1
- package/dist/{chunks/messages-C4Wacagz.mjs → messages-CRL2ecWR.mjs} +33 -1
- package/dist/{chunks/messages-CkRbSW3z2.mjs → messages-CRhhyqEy2.mjs} +33 -1
- package/dist/{chunks/messages-CZfG1cmA2.mjs → messages-CSf1g9n_.mjs} +33 -1
- package/dist/{messages-Ck7HWiG_.mjs → messages-CYuTyoK6.mjs} +33 -1
- package/dist/{messages-BEnINcno2.mjs → messages-Co2GV7rA2.mjs} +33 -1
- package/dist/{chunks/messages-CpC5Cv_s.mjs → messages-CqtZ_gtb.mjs} +33 -1
- package/dist/{chunks/messages-Dp5C7vWz.mjs → messages-CxK_Vgra.mjs} +33 -1
- package/dist/{messages-2pXizYBd.mjs → messages-D08TSj5Q.mjs} +33 -1
- package/dist/{chunks/messages-n1T_9w-Z.mjs → messages-DFDw0nkI.mjs} +33 -1
- package/dist/{messages-S8uz2_bw2.mjs → messages-DKoeDmZV2.mjs} +33 -1
- package/dist/{chunks/messages-EI0ZLMIG.mjs → messages-DLKTwtBI.mjs} +33 -1
- package/dist/{chunks/messages-CcvcAZOt.mjs → messages-DQaDNQat2.mjs} +33 -1
- package/dist/{messages-B4cc5O5K.mjs → messages-DZlYqaxx.mjs} +33 -1
- package/dist/{messages-CdmaH2dA2.mjs → messages-D_ql7LL-2.mjs} +33 -1
- package/dist/{messages-CoSj68Ef2.mjs → messages-Da09byG42.mjs} +33 -1
- package/dist/{messages-BXgGBpmY.mjs → messages-DaKjx7Gh.mjs} +33 -1
- package/dist/{messages-C-XKbE2c.mjs → messages-Dc1aAz5V.mjs} +33 -1
- package/dist/{chunks/messages-CEslBsO62.mjs → messages-DlxBkSUv.mjs} +33 -1
- package/dist/{messages-BYyRYlTQ2.mjs → messages-DoahmNMI2.mjs} +33 -1
- package/dist/{messages-CGZPFOEr.mjs → messages-DpbHfnge.mjs} +33 -1
- package/dist/{chunks/messages-m_zk_AR3.mjs → messages-DrjZz7u9.mjs} +33 -1
- package/dist/{chunks/messages-DaqNOQ8p.mjs → messages-DrwEVbKk2.mjs} +33 -1
- package/dist/{messages-B_XoP1A3.mjs → messages-DvIPbDsq.mjs} +33 -1
- package/dist/{messages-BWzRZ5Un.mjs → messages-Dy3mYP_n.mjs} +33 -1
- package/dist/{chunks/messages-Dp5SW9D-.mjs → messages-STUXoPH72.mjs} +33 -1
- package/dist/{messages-BCeeFrNO.mjs → messages-Vfl9lWod.mjs} +33 -1
- package/dist/{messages-Nbssq1-N.mjs → messages-YPF71WjJ.mjs} +33 -1
- package/dist/{chunks/messages-14GzwdH92.mjs → messages-aPBlKHzr.mjs} +33 -1
- package/dist/{messages-Bj8K6_bv.mjs → messages-bCZW7LiC.mjs} +33 -1
- package/dist/{chunks/messages-Bh3E53-f2.mjs → messages-kjO2WeG-2.mjs} +33 -1
- package/dist/{chunks/messages-S_Bmo_Qc.mjs → messages-un7M6YZC2.mjs} +33 -1
- package/dist/react.cjs +1 -1
- package/dist/react.mjs +1 -1
- package/dist/tools.cjs +1 -1
- package/dist/tools.mjs +3 -3
- package/dist/vendor.LICENSE.txt +35 -0
- package/package.json +2 -1
- package/src/components/i18n/locales/am/messages.json +33 -1
- package/src/components/i18n/locales/ar/messages.json +33 -1
- package/src/components/i18n/locales/az/messages.json +33 -1
- package/src/components/i18n/locales/bg/messages.json +33 -1
- package/src/components/i18n/locales/bn/messages.json +33 -1
- package/src/components/i18n/locales/bs/messages.json +33 -1
- package/src/components/i18n/locales/cs/messages.json +33 -1
- package/src/components/i18n/locales/da/messages.json +33 -1
- package/src/components/i18n/locales/de/messages.json +33 -1
- package/src/components/i18n/locales/dv/messages.json +33 -1
- package/src/components/i18n/locales/el/messages.json +33 -1
- package/src/components/i18n/locales/en/messages.json +32 -0
- package/src/components/i18n/locales/es/messages.json +33 -1
- package/src/components/i18n/locales/et/messages.json +33 -1
- package/src/components/i18n/locales/fa/messages.json +33 -1
- package/src/components/i18n/locales/fi/messages.json +33 -1
- package/src/components/i18n/locales/fil/messages.json +33 -1
- package/src/components/i18n/locales/fr/messages.json +33 -1
- package/src/components/i18n/locales/gu/messages.json +33 -1
- package/src/components/i18n/locales/he/messages.json +33 -1
- package/src/components/i18n/locales/hi/messages.json +33 -1
- package/src/components/i18n/locales/hr/messages.json +33 -1
- package/src/components/i18n/locales/hu/messages.json +33 -1
- package/src/components/i18n/locales/hy/messages.json +33 -1
- package/src/components/i18n/locales/id/messages.json +33 -1
- package/src/components/i18n/locales/it/messages.json +33 -1
- package/src/components/i18n/locales/ja/messages.json +33 -1
- package/src/components/i18n/locales/ka/messages.json +33 -1
- package/src/components/i18n/locales/km/messages.json +33 -1
- package/src/components/i18n/locales/kn/messages.json +33 -1
- package/src/components/i18n/locales/ko/messages.json +33 -1
- package/src/components/i18n/locales/ku/messages.json +33 -1
- package/src/components/i18n/locales/lo/messages.json +33 -1
- package/src/components/i18n/locales/lt/messages.json +33 -1
- package/src/components/i18n/locales/lv/messages.json +33 -1
- package/src/components/i18n/locales/mk/messages.json +33 -1
- package/src/components/i18n/locales/ml/messages.json +33 -1
- package/src/components/i18n/locales/mn/messages.json +33 -1
- package/src/components/i18n/locales/mr/messages.json +33 -1
- package/src/components/i18n/locales/ms/messages.json +33 -1
- package/src/components/i18n/locales/my/messages.json +33 -1
- package/src/components/i18n/locales/ne/messages.json +33 -1
- package/src/components/i18n/locales/nl/messages.json +33 -1
- package/src/components/i18n/locales/no/messages.json +33 -1
- package/src/components/i18n/locales/pa/messages.json +33 -1
- package/src/components/i18n/locales/pl/messages.json +33 -1
- package/src/components/i18n/locales/ps/messages.json +33 -1
- package/src/components/i18n/locales/pt/messages.json +33 -1
- package/src/components/i18n/locales/ro/messages.json +33 -1
- package/src/components/i18n/locales/ru/messages.json +33 -1
- package/src/components/i18n/locales/sd/messages.json +33 -1
- package/src/components/i18n/locales/si/messages.json +33 -1
- package/src/components/i18n/locales/sk/messages.json +33 -1
- package/src/components/i18n/locales/sl/messages.json +33 -1
- package/src/components/i18n/locales/sq/messages.json +33 -1
- package/src/components/i18n/locales/sr/messages.json +33 -1
- package/src/components/i18n/locales/sv/messages.json +33 -1
- package/src/components/i18n/locales/sw/messages.json +33 -1
- package/src/components/i18n/locales/ta/messages.json +33 -1
- package/src/components/i18n/locales/te/messages.json +33 -1
- package/src/components/i18n/locales/th/messages.json +33 -1
- package/src/components/i18n/locales/tr/messages.json +33 -1
- package/src/components/i18n/locales/ug/messages.json +33 -1
- package/src/components/i18n/locales/uk/messages.json +33 -1
- package/src/components/i18n/locales/ur/messages.json +33 -1
- package/src/components/i18n/locales/vi/messages.json +33 -1
- package/src/components/i18n/locales/yi/messages.json +33 -1
- package/src/components/i18n/locales/zh/messages.json +33 -1
- package/src/components/icons/index.ts +106 -0
- package/src/components/modules/paste/handlers/pattern-handler.ts +4 -7
- package/src/components/utils/format-bytes.ts +15 -0
- package/src/components/utils/max-size.ts +36 -0
- package/src/components/utils/media-empty-state.ts +1 -11
- package/src/components/utils/upload-error-message.ts +43 -0
- package/src/styles/colors.css +31 -0
- package/src/styles/keyframes.css +8 -0
- package/src/styles/main.css +2 -0
- package/src/styles/resize-cue.css +26 -0
- package/src/styles/video.css +1221 -0
- package/src/tools/file/constants.ts +3 -0
- package/src/tools/file/index.ts +45 -4
- package/src/tools/file/uploader.ts +5 -2
- package/src/tools/image/constants.ts +1 -1
- package/src/tools/image/converted-uploader.ts +30 -0
- package/src/tools/image/gif-to-webm.ts +170 -0
- package/src/tools/image/index.ts +125 -3
- package/src/tools/image/resizer.ts +39 -6
- package/src/tools/image/uploader.ts +2 -1
- package/src/tools/image/uploading-state.ts +2 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/video/constants.ts +22 -0
- package/src/tools/video/controls.ts +1448 -0
- package/src/tools/video/empty-state.ts +45 -0
- package/src/tools/video/i18n.ts +13 -0
- package/src/tools/video/index.ts +521 -0
- package/src/tools/video/ui.ts +83 -0
- package/src/tools/video/uploader.ts +75 -0
- package/types/configs/blok-config.d.ts +2 -9
- package/types/tools/file.d.ts +9 -3
- package/types/tools/image.d.ts +11 -2
- package/types/tools/max-size.d.ts +12 -0
- package/types/tools/video.d.ts +72 -0
- package/dist/chunks/constants-B2Lcd7Kk.cjs +0 -539
- package/dist/chunks/messages-3iHkF7Vy.cjs +0 -1
- package/dist/chunks/messages-BAgSlZpS.cjs +0 -1
- package/dist/chunks/messages-Br3ERe172.cjs +0 -1
- package/dist/chunks/messages-C6Xc3L-B2.cjs +0 -1
- package/dist/chunks/messages-CEquPedm.cjs +0 -1
- package/dist/chunks/messages-CFo-pG-t2.cjs +0 -1
- package/dist/chunks/messages-Cf8u0aln2.cjs +0 -1
- package/dist/chunks/messages-Cgg1HHSo.cjs +0 -1
- package/dist/chunks/messages-DOBcfgRF.cjs +0 -1
- package/dist/chunks/messages-JLj0J5so.cjs +0 -1
- package/dist/chunks/messages-p-1X5oFM2.cjs +0 -1
- package/dist/chunks/messages-vdupz5T0.cjs +0 -1
- package/dist/chunks/tools-DiTb45BS.cjs +0 -208
- /package/dist/chunks/{am-B37aLxvu.cjs → am-BA02TqF9.cjs} +0 -0
- /package/dist/chunks/{am-D7yfVqJS.mjs → am-C9_6r8HY.mjs} +0 -0
- /package/dist/chunks/{ar-D00SixXA.mjs → ar-BM96nSXF.mjs} +0 -0
- /package/dist/chunks/{ar-ySo_KDqd.cjs → ar-CB4IsGCa.cjs} +0 -0
- /package/dist/chunks/{az-BmIwKcoq.mjs → az-DnZSY5ok.mjs} +0 -0
- /package/dist/chunks/{az-nCoWuGBd.cjs → az-FykE_aDi.cjs} +0 -0
- /package/dist/chunks/{bg-BTZaB21W.mjs → bg-BplUvPeX.mjs} +0 -0
- /package/dist/chunks/{bg-BKB8_J3v.cjs → bg-D6r90gqH.cjs} +0 -0
- /package/dist/chunks/{bn-BQiBKtpR.cjs → bn-B7w2dbK4.cjs} +0 -0
- /package/dist/chunks/{bn-BVpf0XL6.mjs → bn-CdP9lnfr.mjs} +0 -0
- /package/dist/chunks/{bs-BSz4cPth.mjs → bs-BtX-qLsk.mjs} +0 -0
- /package/dist/chunks/{bs-D_lekdEb.cjs → bs-DztHHorM.cjs} +0 -0
- /package/dist/chunks/{cs-Dv8Jg_Fa.cjs → cs-CLMsCdIt.cjs} +0 -0
- /package/dist/chunks/{cs-p5s4GudH.mjs → cs-NcDYS-aU.mjs} +0 -0
- /package/dist/chunks/{da-BqJa8BMd.mjs → da-ANg6gK3-.mjs} +0 -0
- /package/dist/chunks/{da-D33rjz-t.cjs → da-sJ7EsHcO.cjs} +0 -0
- /package/dist/chunks/{de-BDDktkfI.mjs → de-CTxvRxuE.mjs} +0 -0
- /package/dist/chunks/{de-I8YFq0Ej.cjs → de-CxMqLKhy.cjs} +0 -0
- /package/dist/chunks/{el-BInM0nQo.cjs → el-Bg6QXLt5.cjs} +0 -0
- /package/dist/chunks/{el-R63G08P0.mjs → el-CgOoJaXB.mjs} +0 -0
- /package/dist/chunks/{es-Cj_AHhb9.cjs → es-7zUbslPJ.cjs} +0 -0
- /package/dist/chunks/{es-BleH_dHg.mjs → es-D5YDFRu-.mjs} +0 -0
- /package/dist/chunks/{et-BuISCVFl.mjs → et-57a7ees8.mjs} +0 -0
- /package/dist/chunks/{et-BkMzN_qG.cjs → et-D_rhRdDD.cjs} +0 -0
- /package/dist/chunks/{fa-CI9f3My0.mjs → fa-Dp_BXnBP.mjs} +0 -0
- /package/dist/chunks/{fa-C3VQIfEJ.cjs → fa-JBr2zsfI.cjs} +0 -0
- /package/dist/chunks/{fi-p8xxtchQ.cjs → fi-DjbYN6MA.cjs} +0 -0
- /package/dist/chunks/{fi-C0_Jyps9.mjs → fi-at45xjOS.mjs} +0 -0
- /package/dist/chunks/{fil-BZsJ4YZG.mjs → fil-D_HT2vGt.mjs} +0 -0
- /package/dist/chunks/{fil-DC8VTmfd.cjs → fil-dcVBIQoi.cjs} +0 -0
- /package/dist/chunks/{fr-BjeioA2N.mjs → fr-ByR9PLTE.mjs} +0 -0
- /package/dist/chunks/{fr-Cbstr5ii.cjs → fr-Ch4zj1rM.cjs} +0 -0
- /package/dist/chunks/{gu-DpPoUPem.cjs → gu-CoLW5Saq.cjs} +0 -0
- /package/dist/chunks/{gu-CNi9WnhQ.mjs → gu-CvfPvH3Y.mjs} +0 -0
- /package/dist/chunks/{he-Rlv-PVKK.cjs → he-2wS2DK0D.cjs} +0 -0
- /package/dist/chunks/{he-bU_Id5XQ.mjs → he-Bmqypvkq.mjs} +0 -0
- /package/dist/chunks/{hi-CYYjJgoQ.mjs → hi-DbcN0x64.mjs} +0 -0
- /package/dist/chunks/{hi-CfLaLKZL.cjs → hi-f4gshON3.cjs} +0 -0
- /package/dist/chunks/{hr-CerKCstu.mjs → hr-D5mydeyn.mjs} +0 -0
- /package/dist/chunks/{hr-B6eFd_4M.cjs → hr-DMExeWwd.cjs} +0 -0
- /package/dist/chunks/{hu-DQcisouf.cjs → hu-COmlHkse.cjs} +0 -0
- /package/dist/chunks/{hu-DNYoHMic.mjs → hu-DVCPn8un.mjs} +0 -0
- /package/dist/chunks/{hy-x9QOWTT6.cjs → hy-BoBSSiJc.cjs} +0 -0
- /package/dist/chunks/{hy-N0XBqVv_.mjs → hy-CP6oqcK_.mjs} +0 -0
- /package/dist/chunks/{id-dmUIQB07.mjs → id-COwan-Bb.mjs} +0 -0
- /package/dist/chunks/{id-G7ASv812.cjs → id-Dk2AQ6-R.cjs} +0 -0
- /package/dist/chunks/{it-DXDwm7Aj.cjs → it-BCmU3zOg.cjs} +0 -0
- /package/dist/chunks/{it-G9Rg2LaN.mjs → it-DJqN-zLs.mjs} +0 -0
- /package/dist/chunks/{ja-C1Nou_k5.mjs → ja-CvoLNAXS.mjs} +0 -0
- /package/dist/chunks/{ja-DHMurrnk.cjs → ja-DcMqJvnV.cjs} +0 -0
- /package/dist/chunks/{ka-P0_q1_oW.cjs → ka-BdyjQFkv.cjs} +0 -0
- /package/dist/chunks/{ka-9rtmTdhq.mjs → ka-BsqbDXqr.mjs} +0 -0
- /package/dist/chunks/{km-DedsOdPY.cjs → km-BShH0mB9.cjs} +0 -0
- /package/dist/chunks/{km-T8J0lGcC.mjs → km-C9FxSKv0.mjs} +0 -0
- /package/dist/chunks/{kn-CMb5Cv2d.mjs → kn-BKTm-E-A.mjs} +0 -0
- /package/dist/chunks/{kn-CAGP6H3x.cjs → kn-bNx6e6NK.cjs} +0 -0
- /package/dist/chunks/{ko-DulVmkjC.mjs → ko-BLEDr4t_.mjs} +0 -0
- /package/dist/chunks/{ko-3D0kPtnu.cjs → ko-LmGjEODJ.cjs} +0 -0
- /package/dist/chunks/{ku-BYzD3GnU.cjs → ku-BekLwcHQ.cjs} +0 -0
- /package/dist/chunks/{ku-C5mlSVfC.mjs → ku-DGpIv9vX.mjs} +0 -0
- /package/dist/chunks/{lo-Cw2hfj84.mjs → lo-C3wsS73b.mjs} +0 -0
- /package/dist/chunks/{lo-D9ixPNJD.cjs → lo-YgZPFD63.cjs} +0 -0
- /package/dist/chunks/{lt-CzfEJdVd.cjs → lt-CIvBJk2h.cjs} +0 -0
- /package/dist/chunks/{lt-Ceg9NAdI.mjs → lt-DWWjfR4Z.mjs} +0 -0
- /package/dist/chunks/{lv-DWyBbTHI.cjs → lv-B6Djmvjl.cjs} +0 -0
- /package/dist/chunks/{lv-3CXzQoic.mjs → lv-D4nb-9oK.mjs} +0 -0
- /package/dist/chunks/{mk-CEbNT0Oe.mjs → mk-BPUvDORf.mjs} +0 -0
- /package/dist/chunks/{mk-Anl5AUSU.cjs → mk-Ck56Emvp.cjs} +0 -0
- /package/dist/chunks/{ml-B1QmnbTX.cjs → ml-DsibsgSA.cjs} +0 -0
- /package/dist/chunks/{ml-DaF_zn1h.mjs → ml-qo0n1JHs.mjs} +0 -0
- /package/dist/chunks/{mn-DLpgZmIl.mjs → mn-BAQnLAOv.mjs} +0 -0
- /package/dist/chunks/{mn-DM3AWPQI.cjs → mn-Db0fVNYE.cjs} +0 -0
- /package/dist/chunks/{mr-CPCMiBsx.cjs → mr-BTz5VL4u.cjs} +0 -0
- /package/dist/chunks/{mr-C-d3CWSD.mjs → mr-CFEPrQYy.mjs} +0 -0
- /package/dist/chunks/{ms-D3Zil5Dz.mjs → ms-C9p2_6EB.mjs} +0 -0
- /package/dist/chunks/{ms-BKg5zJ6g.cjs → ms-ItzWfmiu.cjs} +0 -0
- /package/dist/chunks/{my-HzQdQq6H.mjs → my-BQhcHK_d.mjs} +0 -0
- /package/dist/chunks/{my-BhrbZPAE.cjs → my-Bq1EPoFX.cjs} +0 -0
- /package/dist/chunks/{ne-Dw6kUPkS.mjs → ne-Cf4GpHyI.mjs} +0 -0
- /package/dist/chunks/{ne-BsEUv3Vp.cjs → ne-Mog3kAWt.cjs} +0 -0
- /package/dist/chunks/{nl-D8QQ6wmJ.mjs → nl-7DE7AKK5.mjs} +0 -0
- /package/dist/chunks/{nl-C1jFx32v.cjs → nl-Do9Y1u3F.cjs} +0 -0
- /package/dist/chunks/{no-BWEOGeAo.cjs → no-DNuo9wW6.cjs} +0 -0
- /package/dist/chunks/{no-Rg2uuKdV.mjs → no-J4jj2fW7.mjs} +0 -0
- /package/dist/chunks/{notifier-CEnelp-K.mjs → notifier-BDNwSr07.mjs} +0 -0
- /package/dist/chunks/{notifier-BOB8o7IG.cjs → notifier-BW5H3Ctc.cjs} +0 -0
- /package/dist/chunks/{pa-BitCteAA.cjs → pa-BVCDv2EV.cjs} +0 -0
- /package/dist/chunks/{pa-BSwIZvA0.mjs → pa-DMuUOUxa.mjs} +0 -0
- /package/dist/chunks/{pl-CbCrHaA6.cjs → pl-Ct8v4d8V.cjs} +0 -0
- /package/dist/chunks/{pl-FhXomIGp.mjs → pl-DIZm5XzV.mjs} +0 -0
- /package/dist/chunks/{ps-4sPZuv3g.cjs → ps-DT4DAHOy.cjs} +0 -0
- /package/dist/chunks/{ps-BoBtbrB6.mjs → ps-X3--6pS3.mjs} +0 -0
- /package/dist/chunks/{pt-BYA5NOw_.mjs → pt-BMT2BIpj.mjs} +0 -0
- /package/dist/chunks/{pt-CSzjho-V.cjs → pt-Dwe6Dinw.cjs} +0 -0
- /package/dist/chunks/{ro-C9tN3AFF.cjs → ro-CoHEUo3b.cjs} +0 -0
- /package/dist/chunks/{ro-mtobtMpD.mjs → ro-Ndh2J4Fv.mjs} +0 -0
- /package/dist/chunks/{ru-B791LPq3.mjs → ru-DEoON4H0.mjs} +0 -0
- /package/dist/chunks/{ru-BYPO5wNO.cjs → ru-Pmgo28Kt.cjs} +0 -0
- /package/dist/chunks/{sd-C8ngG92I.mjs → sd-B46KwBlt.mjs} +0 -0
- /package/dist/chunks/{sd-BWuglgs_.cjs → sd-DxSmw84d.cjs} +0 -0
- /package/dist/chunks/{si-C_q8DxVt.mjs → si-CEX6-_X4.mjs} +0 -0
- /package/dist/chunks/{si-IX2P_DGB.cjs → si-attpuQg-.cjs} +0 -0
- /package/dist/chunks/{sk-HJJlM9uq.mjs → sk-Crsvi9aQ.mjs} +0 -0
- /package/dist/chunks/{sk-CxtyIOlr.cjs → sk-CvkpO0ti.cjs} +0 -0
- /package/dist/chunks/{sl-CPjYG80u.cjs → sl-BT19lhkA.cjs} +0 -0
- /package/dist/chunks/{sl-kB1f5rPn.mjs → sl-Cqe1IKhE.mjs} +0 -0
- /package/dist/chunks/{sq-CD0W0D6z.mjs → sq-BOQb1hx9.mjs} +0 -0
- /package/dist/chunks/{sq-Do6UyHn9.cjs → sq-rY2-arjV.cjs} +0 -0
- /package/dist/chunks/{sr-lLJu9TsT.mjs → sr-WVqhi-MV.mjs} +0 -0
- /package/dist/chunks/{sr-BcyT-MWS.cjs → sr-jnkxoHkR.cjs} +0 -0
- /package/dist/chunks/{sv-Bsz7ersx.cjs → sv-BiWSYdw7.cjs} +0 -0
- /package/dist/chunks/{sv-C3GL-a0k.mjs → sv-cjssSK3x.mjs} +0 -0
- /package/dist/chunks/{sw-D6-DZ14-.mjs → sw-BNNAgQNn.mjs} +0 -0
- /package/dist/chunks/{sw-CUElHZxL.cjs → sw-DFyk62c4.cjs} +0 -0
- /package/dist/chunks/{ta-D0DQba-y.cjs → ta-DowDx1bh.cjs} +0 -0
- /package/dist/chunks/{ta-BZy78kBk.mjs → ta-jg4mBsL9.mjs} +0 -0
- /package/dist/chunks/{te-vigCVKdg.mjs → te-BiLupA2T.mjs} +0 -0
- /package/dist/chunks/{te-DPMvJyXg.cjs → te-G0buJU1V.cjs} +0 -0
- /package/dist/chunks/{th-DtcrIt9J.cjs → th-DsjA6OWh.cjs} +0 -0
- /package/dist/chunks/{th-CGc0RLWB.mjs → th-Dtb_u833.mjs} +0 -0
- /package/dist/chunks/{tr-Cgkf5aJo.mjs → tr-01MbT9-l.mjs} +0 -0
- /package/dist/chunks/{tr-BrEFaVNA.cjs → tr-DN1xdxQn.cjs} +0 -0
- /package/dist/chunks/{ug-BVK7qBs4.mjs → ug-BFlA2VRZ.mjs} +0 -0
- /package/dist/chunks/{ug-CqZXfhXi.cjs → ug-DEJ9cNGH.cjs} +0 -0
- /package/dist/chunks/{uk-DgReWEge.cjs → uk-Bv6aB1Nd.cjs} +0 -0
- /package/dist/chunks/{uk-CSPaCalw.mjs → uk-DY7rBPyo.mjs} +0 -0
- /package/dist/chunks/{ur-ByrwJnY1.cjs → ur-C3CFfx9s.cjs} +0 -0
- /package/dist/chunks/{ur-VpFFsATs.mjs → ur-DHfULZeF.mjs} +0 -0
- /package/dist/chunks/{vi-CWQtvATS.mjs → vi-BFuaq2Tk.mjs} +0 -0
- /package/dist/chunks/{vi-lUD3w7gP.cjs → vi-DQrrRkmq.cjs} +0 -0
- /package/dist/chunks/{zh-fSp1qOne.cjs → zh-5rdSdLkR.cjs} +0 -0
- /package/dist/chunks/{zh-akJj2cdF.mjs → zh-BGpl7x7W.mjs} +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DEFAULT_MIME_TYPES } from './constants';
|
|
2
|
+
import { tr } from './i18n';
|
|
3
|
+
import {
|
|
4
|
+
renderMediaEmptyState,
|
|
5
|
+
type MediaEmptyStateElement,
|
|
6
|
+
} from '../../components/utils/media-empty-state';
|
|
7
|
+
import type { I18nInstance } from '../../components/utils/tools';
|
|
8
|
+
|
|
9
|
+
export interface EmptyStateOptions {
|
|
10
|
+
onFile(file: File): void;
|
|
11
|
+
onUrl(url: string): void;
|
|
12
|
+
/** MIME types to accept on file picker + show in the formats hint. */
|
|
13
|
+
acceptTypes?: string[];
|
|
14
|
+
/** Max file size in bytes — surfaced in the formats hint when set. */
|
|
15
|
+
maxSize?: number;
|
|
16
|
+
i18n?: I18nInstance;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type EmptyStateElement = MediaEmptyStateElement;
|
|
20
|
+
|
|
21
|
+
export function renderEmptyState(opts: EmptyStateOptions): EmptyStateElement {
|
|
22
|
+
const i18n = opts.i18n;
|
|
23
|
+
return renderMediaEmptyState({
|
|
24
|
+
acceptTypes: opts.acceptTypes ?? [...DEFAULT_MIME_TYPES],
|
|
25
|
+
maxSize: opts.maxSize,
|
|
26
|
+
onFile: opts.onFile,
|
|
27
|
+
onUrl: opts.onUrl,
|
|
28
|
+
labels: {
|
|
29
|
+
add: tr(i18n, 'tools.video.emptyAddVideo', 'Add a video'),
|
|
30
|
+
upload: tr(i18n, 'tools.video.emptyUpload', 'Upload'),
|
|
31
|
+
embed: tr(i18n, 'tools.video.emptyLink', 'Link'),
|
|
32
|
+
chooseFile: tr(i18n, 'tools.video.emptyChooseFile', 'Choose file'),
|
|
33
|
+
orDropHere: tr(i18n, 'tools.video.emptyOrDropHere', 'or drop a video here'),
|
|
34
|
+
dropToUpload: tr(i18n, 'tools.video.emptyDropToUpload', 'Drop to upload'),
|
|
35
|
+
urlPlaceholder: tr(i18n, 'tools.video.emptyUrlPlaceholder', 'Paste a video URL…'),
|
|
36
|
+
urlAria: tr(i18n, 'tools.video.emptyUrlAria', 'Video URL'),
|
|
37
|
+
submit: tr(i18n, 'tools.video.emptyInsert', 'Insert'),
|
|
38
|
+
sourceAria: tr(i18n, 'tools.video.emptySourceAria', 'Video source'),
|
|
39
|
+
maxSize: (size) =>
|
|
40
|
+
i18n?.has('tools.video.emptyMaxSize')
|
|
41
|
+
? i18n.t('tools.video.emptyMaxSize', { size })
|
|
42
|
+
: `max ${size}`,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { I18nInstance } from '../../components/utils/tools';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a translation key, falling back to an inline English string when the
|
|
5
|
+
* host editor has not registered the key. Keeps the video tool usable before
|
|
6
|
+
* locale messages are wired and gives the i18n regression scan a single place
|
|
7
|
+
* to find the source copy.
|
|
8
|
+
*/
|
|
9
|
+
export function tr(i18n: I18nInstance | undefined, key: string, fallback: string): string {
|
|
10
|
+
if (i18n?.has(key)) return i18n.t(key);
|
|
11
|
+
|
|
12
|
+
return fallback;
|
|
13
|
+
}
|
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
API,
|
|
3
|
+
BlockAPI,
|
|
4
|
+
BlockTool,
|
|
5
|
+
BlockToolConstructorOptions,
|
|
6
|
+
FilePasteEvent,
|
|
7
|
+
PasteConfig,
|
|
8
|
+
PasteEvent,
|
|
9
|
+
PatternPasteEvent,
|
|
10
|
+
ToolboxConfig,
|
|
11
|
+
} from '../../../types';
|
|
12
|
+
import type { MenuConfig } from '../../../types/tools/menu-config';
|
|
13
|
+
import type { VideoAlignment, VideoConfig, VideoData } from '../../../types/tools/video';
|
|
14
|
+
import {
|
|
15
|
+
IconAlignCenter,
|
|
16
|
+
IconAlignLeft,
|
|
17
|
+
IconAlignRight,
|
|
18
|
+
IconCaption,
|
|
19
|
+
IconCopy,
|
|
20
|
+
IconDownload,
|
|
21
|
+
IconPlayerLoop,
|
|
22
|
+
IconPlayerPlay,
|
|
23
|
+
IconPlayerSettings,
|
|
24
|
+
IconReplace,
|
|
25
|
+
IconVideo,
|
|
26
|
+
} from '../../components/icons';
|
|
27
|
+
import { attachResizeHandle, type ResizeEdge } from '../image/resizer';
|
|
28
|
+
import { renderUploadingState, type UploadingStateElement } from '../image/uploading-state';
|
|
29
|
+
import { DEFAULT_CAPTION_PLACEHOLDER, MIN_WIDTH_PX, URL_PATTERN } from './constants';
|
|
30
|
+
import { renderEmptyState, type EmptyStateElement } from './empty-state';
|
|
31
|
+
import { tr } from './i18n';
|
|
32
|
+
import { renderCaptionRow, renderVideo } from './ui';
|
|
33
|
+
import { attachControls, type ControlsHandle } from './controls';
|
|
34
|
+
import { Uploader, VideoUploadError, type UploadResult } from './uploader';
|
|
35
|
+
import { uploadErrorMessage } from '../../components/utils/upload-error-message';
|
|
36
|
+
import { pickDisplayMaxSize } from '../../components/utils/max-size';
|
|
37
|
+
|
|
38
|
+
type ToolState = 'EMPTY' | 'LOADING' | 'RENDERED' | 'ERROR';
|
|
39
|
+
|
|
40
|
+
export class VideoTool implements BlockTool {
|
|
41
|
+
private readonly api: API;
|
|
42
|
+
private readonly block: BlockAPI;
|
|
43
|
+
private readonly config: VideoConfig;
|
|
44
|
+
private readonly uploader: Uploader;
|
|
45
|
+
private data: VideoData;
|
|
46
|
+
private readOnly: boolean;
|
|
47
|
+
private root: HTMLElement | null = null;
|
|
48
|
+
private state: ToolState;
|
|
49
|
+
private uploadingEl: UploadingStateElement | null = null;
|
|
50
|
+
private lastFileName: string | null = null;
|
|
51
|
+
private errorMessage: string | null = null;
|
|
52
|
+
private lastSource: { kind: 'file'; file: File } | { kind: 'url'; url: string } | null = null;
|
|
53
|
+
private resizeDetach: (() => void)[] = [];
|
|
54
|
+
private controlsHandle: ControlsHandle | null = null;
|
|
55
|
+
// Ephemeral theater (cinema-width) state — presentation only, never saved.
|
|
56
|
+
private theater = false;
|
|
57
|
+
|
|
58
|
+
constructor(options: BlockToolConstructorOptions<VideoData, VideoConfig>) {
|
|
59
|
+
this.api = options.api;
|
|
60
|
+
this.block = options.block;
|
|
61
|
+
this.config = options.config ?? {};
|
|
62
|
+
this.readOnly = options.readOnly;
|
|
63
|
+
this.data = { ...options.data, url: options.data?.url ?? '' };
|
|
64
|
+
this.state = this.data.url ? 'RENDERED' : 'EMPTY';
|
|
65
|
+
this.uploader = new Uploader(this.config);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public render(): HTMLElement {
|
|
69
|
+
const root = document.createElement('div');
|
|
70
|
+
root.setAttribute('data-blok-tool', 'video');
|
|
71
|
+
this.root = root;
|
|
72
|
+
this.renderState();
|
|
73
|
+
return root;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public save(_block?: HTMLElement): VideoData {
|
|
77
|
+
const out: VideoData = { url: this.data.url };
|
|
78
|
+
if (this.data.caption !== undefined) out.caption = this.data.caption;
|
|
79
|
+
if (this.data.captionVisible !== undefined) out.captionVisible = this.data.captionVisible;
|
|
80
|
+
if (this.data.width !== undefined) out.width = this.data.width;
|
|
81
|
+
if (this.data.alignment !== undefined) out.alignment = this.data.alignment;
|
|
82
|
+
if (this.data.autoplay) out.autoplay = true;
|
|
83
|
+
if (this.data.loop) out.loop = true;
|
|
84
|
+
if (this.data.hideControls) out.hideControls = true;
|
|
85
|
+
if (this.data.fileName !== undefined) out.fileName = this.data.fileName;
|
|
86
|
+
if (this.data.mimeType !== undefined) out.mimeType = this.data.mimeType;
|
|
87
|
+
if (this.data.aspectRatio !== undefined) out.aspectRatio = this.data.aspectRatio;
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public validate(data: VideoData): boolean {
|
|
92
|
+
return typeof data.url === 'string' && data.url.length > 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public static get toolbox(): ToolboxConfig {
|
|
96
|
+
return {
|
|
97
|
+
icon: IconVideo,
|
|
98
|
+
titleKey: 'video',
|
|
99
|
+
searchTerms: ['video', 'movie', 'clip', 'player', 'mp4', 'media'],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public static get isReadOnlySupported(): boolean {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public static get pasteConfig(): PasteConfig {
|
|
108
|
+
return {
|
|
109
|
+
patterns: { video: URL_PATTERN },
|
|
110
|
+
files: { mimeTypes: ['video/*'] },
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public onPaste(event: PasteEvent): void {
|
|
115
|
+
if (event.type === 'pattern') {
|
|
116
|
+
this.applyResult({ url: (event as PatternPasteEvent).detail.data });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (event.type === 'file') {
|
|
120
|
+
this.startUpload((event as FilePasteEvent).detail.file);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public getToolbarAnchorElement(): HTMLElement | undefined {
|
|
125
|
+
return this.root?.querySelector<HTMLElement>('[data-role="video-figure"]') ?? undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public getContentOffset(_hoveredElement: Element): { left: number } | undefined {
|
|
129
|
+
const root = this.root;
|
|
130
|
+
const figure = root?.querySelector<HTMLElement>('[data-role="video-figure"]');
|
|
131
|
+
if (!root || !figure) return undefined;
|
|
132
|
+
const delta = figure.getBoundingClientRect().left - root.getBoundingClientRect().left;
|
|
133
|
+
return delta > 0 ? { left: delta } : undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public setReadOnly(state: boolean): void {
|
|
137
|
+
this.readOnly = state;
|
|
138
|
+
this.renderState();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public renderSettings(): MenuConfig {
|
|
142
|
+
const i18n = this.api.i18n;
|
|
143
|
+
const current: VideoAlignment = this.data.alignment ?? 'center';
|
|
144
|
+
const captionVisible = this.data.captionVisible !== false;
|
|
145
|
+
const alignments: { value: VideoAlignment; title: string; icon: string }[] = [
|
|
146
|
+
{ value: 'left', title: tr(i18n, 'tools.video.alignmentLeft', 'Align left'), icon: IconAlignLeft },
|
|
147
|
+
{ value: 'center', title: tr(i18n, 'tools.video.alignmentCenter', 'Align center'), icon: IconAlignCenter },
|
|
148
|
+
{ value: 'right', title: tr(i18n, 'tools.video.alignmentRight', 'Align right'), icon: IconAlignRight },
|
|
149
|
+
];
|
|
150
|
+
const alignIcon = alignments.find((a) => a.value === current)?.icon ?? alignments[1].icon;
|
|
151
|
+
|
|
152
|
+
return [
|
|
153
|
+
{
|
|
154
|
+
icon: alignIcon,
|
|
155
|
+
title: tr(i18n, 'tools.video.alignment', 'Alignment'),
|
|
156
|
+
name: 'video-alignment',
|
|
157
|
+
children: {
|
|
158
|
+
items: alignments.map((a) => ({
|
|
159
|
+
icon: a.icon,
|
|
160
|
+
title: a.title,
|
|
161
|
+
name: `video-alignment-${a.value}`,
|
|
162
|
+
isActive: current === a.value,
|
|
163
|
+
closeOnActivate: true,
|
|
164
|
+
onActivate: (): void => this.setAlignment(a.value),
|
|
165
|
+
})),
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
icon: IconCaption,
|
|
170
|
+
title: tr(i18n, 'tools.video.caption', 'Caption'),
|
|
171
|
+
name: 'video-caption',
|
|
172
|
+
isActive: captionVisible,
|
|
173
|
+
closeOnActivate: true,
|
|
174
|
+
onActivate: (): void => this.toggleCaption(),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
icon: IconPlayerPlay,
|
|
178
|
+
title: tr(i18n, 'tools.video.autoplay', 'Autoplay'),
|
|
179
|
+
name: 'video-autoplay',
|
|
180
|
+
isActive: this.data.autoplay === true,
|
|
181
|
+
closeOnActivate: true,
|
|
182
|
+
onActivate: (): void => this.toggleAutoplay(),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
icon: IconPlayerLoop,
|
|
186
|
+
title: tr(i18n, 'tools.video.loop', 'Loop'),
|
|
187
|
+
name: 'video-loop',
|
|
188
|
+
isActive: this.data.loop === true,
|
|
189
|
+
closeOnActivate: true,
|
|
190
|
+
onActivate: (): void => this.toggleLoop(),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
icon: IconPlayerSettings,
|
|
194
|
+
title: tr(i18n, 'tools.video.hideControls', 'Hide controls'),
|
|
195
|
+
name: 'video-hide-controls',
|
|
196
|
+
isActive: this.data.hideControls === true,
|
|
197
|
+
closeOnActivate: true,
|
|
198
|
+
onActivate: (): void => this.toggleHideControls(),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
icon: IconReplace,
|
|
202
|
+
title: tr(i18n, 'tools.video.replace', 'Replace video'),
|
|
203
|
+
name: 'video-replace',
|
|
204
|
+
closeOnActivate: true,
|
|
205
|
+
onActivate: (): void => this.transitionToEmpty(),
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
icon: IconDownload,
|
|
209
|
+
title: tr(i18n, 'tools.video.download', 'Download'),
|
|
210
|
+
name: 'video-download',
|
|
211
|
+
closeOnActivate: true,
|
|
212
|
+
onActivate: (): void => this.download(),
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
icon: IconCopy,
|
|
216
|
+
title: tr(i18n, 'tools.video.copyUrl', 'Copy URL'),
|
|
217
|
+
name: 'video-copy-url',
|
|
218
|
+
closeOnActivate: true,
|
|
219
|
+
onActivate: (): void => this.copyUrl(),
|
|
220
|
+
},
|
|
221
|
+
];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
public removed(): void {
|
|
225
|
+
this.detachResize();
|
|
226
|
+
this.controlsHandle?.destroy();
|
|
227
|
+
this.controlsHandle = null;
|
|
228
|
+
if (this.data.url.startsWith('blob:')) {
|
|
229
|
+
URL.revokeObjectURL(this.data.url);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private startUpload(file: File): void {
|
|
234
|
+
this.lastFileName = file.name;
|
|
235
|
+
this.lastSource = { kind: 'file', file };
|
|
236
|
+
this.state = 'LOADING';
|
|
237
|
+
this.renderState();
|
|
238
|
+
void this.uploader
|
|
239
|
+
.handleFile(file, { onProgress: (p) => this.uploadingEl?.setProgress(p) })
|
|
240
|
+
.then((result) => this.applyResult(result, file.type))
|
|
241
|
+
.catch((err) => this.applyError(err));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private startUrl(url: string): void {
|
|
245
|
+
this.lastFileName = null;
|
|
246
|
+
this.lastSource = { kind: 'url', url };
|
|
247
|
+
this.state = 'LOADING';
|
|
248
|
+
this.renderState();
|
|
249
|
+
void this.uploader
|
|
250
|
+
.handleUrl(url, { onProgress: (p) => this.uploadingEl?.setProgress(p) })
|
|
251
|
+
.then((result) => this.applyResult(result))
|
|
252
|
+
.catch((err) => this.applyError(err));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private applyResult(result: UploadResult, mimeType?: string): void {
|
|
256
|
+
this.data = {
|
|
257
|
+
...this.data,
|
|
258
|
+
url: result.url,
|
|
259
|
+
fileName: result.fileName ?? this.lastFileName ?? this.data.fileName,
|
|
260
|
+
mimeType: mimeType || this.data.mimeType,
|
|
261
|
+
};
|
|
262
|
+
this.errorMessage = null;
|
|
263
|
+
this.state = 'RENDERED';
|
|
264
|
+
this.renderState();
|
|
265
|
+
this.block.dispatchChange();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private applyError(err?: unknown): void {
|
|
269
|
+
this.errorMessage = err instanceof VideoUploadError
|
|
270
|
+
? uploadErrorMessage(err, (key) => this.api.i18n.t(key), {
|
|
271
|
+
tooLarge: 'tools.video.errorFileTooLarge',
|
|
272
|
+
generic: 'tools.video.errorUploadFailed',
|
|
273
|
+
})
|
|
274
|
+
: null;
|
|
275
|
+
this.state = 'ERROR';
|
|
276
|
+
this.renderState();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private detachResize(): void {
|
|
280
|
+
while (this.resizeDetach.length > 0) {
|
|
281
|
+
this.resizeDetach.pop()?.();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private syncRootAttributes(): void {
|
|
286
|
+
if (!this.root) return;
|
|
287
|
+
const r = this.root;
|
|
288
|
+
r.setAttribute('data-state', this.state.toLowerCase());
|
|
289
|
+
r.setAttribute('data-align', this.data.alignment ?? 'center');
|
|
290
|
+
r.setAttribute('data-caption', this.data.captionVisible === false ? 'off' : 'on');
|
|
291
|
+
r.setAttribute('data-controls', this.data.hideControls === true ? 'off' : 'on');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private renderState(): void {
|
|
295
|
+
if (!this.root) return;
|
|
296
|
+
this.detachResize();
|
|
297
|
+
this.controlsHandle?.destroy();
|
|
298
|
+
this.controlsHandle = null;
|
|
299
|
+
this.root.replaceChildren();
|
|
300
|
+
this.uploadingEl = null;
|
|
301
|
+
this.syncRootAttributes();
|
|
302
|
+
|
|
303
|
+
if (this.state === 'EMPTY') {
|
|
304
|
+
this.renderEmpty();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (this.state === 'LOADING') {
|
|
308
|
+
this.renderLoading();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (this.state === 'ERROR') {
|
|
312
|
+
this.renderError();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
this.renderRendered();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private renderEmpty(): void {
|
|
319
|
+
if (!this.root) return;
|
|
320
|
+
const el: EmptyStateElement = renderEmptyState({
|
|
321
|
+
onFile: (file) => this.startUpload(file),
|
|
322
|
+
onUrl: (url) => this.startUrl(url),
|
|
323
|
+
acceptTypes: this.config.types,
|
|
324
|
+
maxSize: pickDisplayMaxSize(this.config.maxSize),
|
|
325
|
+
i18n: this.api.i18n,
|
|
326
|
+
});
|
|
327
|
+
this.root.appendChild(el);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private renderLoading(): void {
|
|
331
|
+
if (!this.root) return;
|
|
332
|
+
this.uploadingEl = renderUploadingState({
|
|
333
|
+
fileName: this.lastFileName ?? tr(this.api.i18n, 'tools.video.uploading', 'Uploading…'),
|
|
334
|
+
onCancel: () => this.transitionToEmpty(),
|
|
335
|
+
i18n: this.api.i18n,
|
|
336
|
+
});
|
|
337
|
+
this.root.appendChild(this.uploadingEl);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
private renderError(): void {
|
|
341
|
+
if (!this.root) return;
|
|
342
|
+
const wrap = document.createElement('div');
|
|
343
|
+
wrap.className = 'blok-video-error-state';
|
|
344
|
+
wrap.setAttribute('data-role', 'video-error');
|
|
345
|
+
|
|
346
|
+
const message = document.createElement('span');
|
|
347
|
+
message.textContent = this.errorMessage ?? tr(this.api.i18n, 'tools.video.errorUploadFailed', 'Upload failed');
|
|
348
|
+
|
|
349
|
+
const retry = document.createElement('button');
|
|
350
|
+
retry.type = 'button';
|
|
351
|
+
retry.className = 'blok-video-retry';
|
|
352
|
+
retry.setAttribute('data-action', 'replace');
|
|
353
|
+
retry.textContent = tr(this.api.i18n, 'tools.video.errorReplace', 'Replace');
|
|
354
|
+
retry.addEventListener('click', () => this.transitionToEmpty());
|
|
355
|
+
|
|
356
|
+
wrap.append(message, retry);
|
|
357
|
+
this.root.appendChild(wrap);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private renderRendered(): void {
|
|
361
|
+
if (!this.root) return;
|
|
362
|
+
const figure = renderVideo(this.data);
|
|
363
|
+
const media = figure.querySelector<HTMLElement>('[data-role="video-media"]') ?? figure;
|
|
364
|
+
|
|
365
|
+
// Custom playback controls replace the native chrome — available to
|
|
366
|
+
// viewers too, so they attach regardless of read-only.
|
|
367
|
+
const video = media.querySelector('video');
|
|
368
|
+
if (video) {
|
|
369
|
+
// Loop is content — honour it in both modes. Autoplay is a read-only viewer
|
|
370
|
+
// affordance: muted + autoplay + loop turns the block into a gif. Browsers
|
|
371
|
+
// only honour autoplay when muted, so we mute here; editing never autoplays.
|
|
372
|
+
video.loop = this.data.loop === true;
|
|
373
|
+
if (this.readOnly && this.data.autoplay === true) {
|
|
374
|
+
video.muted = true;
|
|
375
|
+
video.setAttribute('muted', '');
|
|
376
|
+
video.setAttribute('autoplay', '');
|
|
377
|
+
}
|
|
378
|
+
// "Hide controls" tune renders a clean, control-free frame — the custom
|
|
379
|
+
// chrome is skipped entirely (native controls were never attached). Loop
|
|
380
|
+
// and autoplay above still apply: they are content/viewer affordances.
|
|
381
|
+
if (this.data.hideControls !== true) {
|
|
382
|
+
this.controlsHandle = attachControls({
|
|
383
|
+
video,
|
|
384
|
+
figure,
|
|
385
|
+
glow: this.config.glow ?? 'minimal',
|
|
386
|
+
loop: this.data.loop === true,
|
|
387
|
+
});
|
|
388
|
+
media.appendChild(this.controlsHandle.element);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// When metadata arrives, update the media wrapper's aspect ratio so it
|
|
392
|
+
// matches the video's intrinsic dimensions. If the ratio differs from
|
|
393
|
+
// the default 16 : 9 (or a previously stored value) we persist it so
|
|
394
|
+
// subsequent renders skip the layout pop.
|
|
395
|
+
video.addEventListener('loadedmetadata', () => {
|
|
396
|
+
if (video.videoWidth > 0 && video.videoHeight > 0) {
|
|
397
|
+
const ratio = `${video.videoWidth} / ${video.videoHeight}`;
|
|
398
|
+
if (ratio !== this.data.aspectRatio) {
|
|
399
|
+
this.data.aspectRatio = ratio;
|
|
400
|
+
media.style.aspectRatio = ratio;
|
|
401
|
+
this.block.dispatchChange();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}, { once: true });
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Theater is an ephemeral view mode: observe the player's toggle to keep our
|
|
408
|
+
// copy, and re-apply it after a re-render so alignment/caption changes don't
|
|
409
|
+
// eject the viewer. Never written to save() — presentation, not content.
|
|
410
|
+
figure.addEventListener('blok-video-theater', (event) => {
|
|
411
|
+
this.theater = (event as CustomEvent<{ on: boolean }>).detail.on;
|
|
412
|
+
});
|
|
413
|
+
if (this.theater) this.controlsHandle?.setTheater(true);
|
|
414
|
+
|
|
415
|
+
const placeholder = this.config.captionPlaceholder ?? DEFAULT_CAPTION_PLACEHOLDER;
|
|
416
|
+
const captionVisible = this.data.captionVisible !== false;
|
|
417
|
+
if (captionVisible || !this.readOnly) {
|
|
418
|
+
figure.appendChild(renderCaptionRow({
|
|
419
|
+
value: this.data.caption ?? '',
|
|
420
|
+
placeholder,
|
|
421
|
+
readOnly: this.readOnly,
|
|
422
|
+
onChange: (next) => {
|
|
423
|
+
if (next !== this.data.caption) {
|
|
424
|
+
this.data.caption = next;
|
|
425
|
+
this.block.dispatchChange();
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
}));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
this.root.appendChild(figure);
|
|
432
|
+
|
|
433
|
+
if (!this.readOnly) {
|
|
434
|
+
this.attachResizeHandles(figure);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private attachResizeHandles(figure: HTMLElement): void {
|
|
439
|
+
const edges: ResizeEdge[] = ['left', 'right'];
|
|
440
|
+
for (const edge of edges) {
|
|
441
|
+
const handle = document.createElement('div');
|
|
442
|
+
handle.setAttribute('data-role', 'resize-handle');
|
|
443
|
+
handle.setAttribute('data-edge', edge);
|
|
444
|
+
figure.appendChild(handle);
|
|
445
|
+
const detach = attachResizeHandle({
|
|
446
|
+
handle,
|
|
447
|
+
figure,
|
|
448
|
+
container: figure.parentElement ?? figure,
|
|
449
|
+
edge,
|
|
450
|
+
alignment: this.data.alignment ?? 'center',
|
|
451
|
+
minWidthPx: MIN_WIDTH_PX,
|
|
452
|
+
onPreview: (percent) => {
|
|
453
|
+
figure.style.setProperty('width', `${percent}%`);
|
|
454
|
+
},
|
|
455
|
+
onCommit: (percent) => {
|
|
456
|
+
this.data.width = percent;
|
|
457
|
+
this.block.dispatchChange();
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
this.resizeDetach.push(detach);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private setAlignment(next: VideoAlignment): void {
|
|
465
|
+
if (this.data.alignment === next) return;
|
|
466
|
+
this.data.alignment = next;
|
|
467
|
+
this.block.dispatchChange();
|
|
468
|
+
this.renderState();
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private toggleCaption(): void {
|
|
472
|
+
this.data.captionVisible = this.data.captionVisible === false;
|
|
473
|
+
this.block.dispatchChange();
|
|
474
|
+
this.renderState();
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private toggleAutoplay(): void {
|
|
478
|
+
this.data.autoplay = this.data.autoplay !== true ? true : undefined;
|
|
479
|
+
this.block.dispatchChange();
|
|
480
|
+
this.renderState();
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
private toggleLoop(): void {
|
|
484
|
+
this.data.loop = this.data.loop !== true ? true : undefined;
|
|
485
|
+
this.block.dispatchChange();
|
|
486
|
+
this.renderState();
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
private toggleHideControls(): void {
|
|
490
|
+
this.data.hideControls = this.data.hideControls !== true ? true : undefined;
|
|
491
|
+
this.block.dispatchChange();
|
|
492
|
+
this.renderState();
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
private transitionToEmpty(): void {
|
|
496
|
+
this.data = { ...this.data, url: '' };
|
|
497
|
+
this.state = 'EMPTY';
|
|
498
|
+
this.lastSource = null;
|
|
499
|
+
this.lastFileName = null;
|
|
500
|
+
this.renderState();
|
|
501
|
+
this.block.dispatchChange();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private download(): void {
|
|
505
|
+
const a = document.createElement('a');
|
|
506
|
+
a.href = this.data.url;
|
|
507
|
+
a.download = this.data.fileName ?? '';
|
|
508
|
+
a.target = '_blank';
|
|
509
|
+
a.rel = 'noopener';
|
|
510
|
+
document.body.appendChild(a);
|
|
511
|
+
a.click();
|
|
512
|
+
a.remove();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private copyUrl(): void {
|
|
516
|
+
const clip = navigator.clipboard;
|
|
517
|
+
if (clip && typeof clip.writeText === 'function') {
|
|
518
|
+
void clip.writeText(this.data.url);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { VideoAlignment, VideoData } from '../../../types/tools/video';
|
|
2
|
+
|
|
3
|
+
const ALIGN_TO_TEXT_ALIGN: Record<VideoAlignment, string> = {
|
|
4
|
+
left: 'left',
|
|
5
|
+
center: 'center',
|
|
6
|
+
right: 'right',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function renderVideo(data: Partial<VideoData> & { url: string }): HTMLElement {
|
|
10
|
+
const alignment = data.alignment ?? 'center';
|
|
11
|
+
const figure = document.createElement('figure');
|
|
12
|
+
figure.className = 'blok-video-inner';
|
|
13
|
+
figure.setAttribute('data-role', 'video-figure');
|
|
14
|
+
figure.style.margin = '0';
|
|
15
|
+
figure.style.textAlign = ALIGN_TO_TEXT_ALIGN[alignment];
|
|
16
|
+
figure.style.position = 'relative';
|
|
17
|
+
if (data.width !== undefined) {
|
|
18
|
+
figure.style.width = `${data.width}%`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// The media wrapper hugs the player pixels and anchors the overlaid chrome
|
|
22
|
+
// (custom controls, edit toolbar, resize handles) so they sit over the video
|
|
23
|
+
// only — never over the caption row below.
|
|
24
|
+
const media = document.createElement('div');
|
|
25
|
+
media.className = 'blok-video-media';
|
|
26
|
+
media.setAttribute('data-role', 'video-media');
|
|
27
|
+
media.style.position = 'relative';
|
|
28
|
+
// Reserve space before loadedmetadata fires — without this the <video>
|
|
29
|
+
// collapses to zero height then "pops" when the browser learns the
|
|
30
|
+
// intrinsic ratio (the "squeeze" visual glitch on load).
|
|
31
|
+
media.style.aspectRatio = data.aspectRatio ?? '16 / 9';
|
|
32
|
+
|
|
33
|
+
// No native `controls` — a custom Airbnb-style control surface is attached
|
|
34
|
+
// separately (see controls.ts) and fully replaces the browser chrome.
|
|
35
|
+
const video = document.createElement('video');
|
|
36
|
+
video.setAttribute('data-blok-testid', 'video-player');
|
|
37
|
+
video.setAttribute('playsinline', '');
|
|
38
|
+
video.setAttribute('preload', 'metadata');
|
|
39
|
+
// Focusable so the player can field keyboard control (seek, volume, speed,
|
|
40
|
+
// play/pause, mute, fullscreen) à la a native player.
|
|
41
|
+
video.setAttribute('tabindex', '0');
|
|
42
|
+
video.setAttribute(
|
|
43
|
+
'aria-keyshortcuts',
|
|
44
|
+
'Space k j l ArrowLeft ArrowRight ArrowUp ArrowDown m f Home End',
|
|
45
|
+
);
|
|
46
|
+
video.setAttribute('src', data.url);
|
|
47
|
+
video.style.width = '100%';
|
|
48
|
+
video.style.display = 'block';
|
|
49
|
+
media.appendChild(video);
|
|
50
|
+
figure.appendChild(media);
|
|
51
|
+
|
|
52
|
+
return figure;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CaptionRowOptions {
|
|
56
|
+
value: string;
|
|
57
|
+
placeholder: string;
|
|
58
|
+
readOnly: boolean;
|
|
59
|
+
onChange(next: string): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function renderCaptionRow(opts: CaptionRowOptions): HTMLElement {
|
|
63
|
+
const row = document.createElement('div');
|
|
64
|
+
row.className = 'blok-video-caption-row';
|
|
65
|
+
row.setAttribute('data-role', 'video-caption-row');
|
|
66
|
+
|
|
67
|
+
const caption = document.createElement('div');
|
|
68
|
+
caption.className = 'blok-video-caption';
|
|
69
|
+
caption.setAttribute('data-role', 'video-caption');
|
|
70
|
+
caption.setAttribute('role', 'textbox');
|
|
71
|
+
caption.setAttribute('contenteditable', opts.readOnly ? 'false' : 'true');
|
|
72
|
+
caption.setAttribute('data-placeholder', opts.placeholder);
|
|
73
|
+
caption.textContent = opts.value;
|
|
74
|
+
caption.style.outline = 'none';
|
|
75
|
+
caption.style.textAlign = 'left';
|
|
76
|
+
|
|
77
|
+
if (!opts.readOnly) {
|
|
78
|
+
caption.addEventListener('blur', () => opts.onChange(caption.textContent ?? ''));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
row.appendChild(caption);
|
|
82
|
+
return row;
|
|
83
|
+
}
|