bootstrap-vue-next 0.45.5 → 0.45.7
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/{BAccordion-Gz2SpRmq.mjs → BAccordion-D51b9HVD.mjs} +5 -5
- package/dist/{BAccordion-Gz2SpRmq.mjs.map → BAccordion-D51b9HVD.mjs.map} +1 -1
- package/dist/{BAccordion-DgXJMqdG.js → BAccordion-DYmuqZIG.js} +5 -5
- package/dist/{BAccordion-DgXJMqdG.js.map → BAccordion-DYmuqZIG.js.map} +1 -1
- package/dist/{BAlert-BFPBalmr.mjs → BAlert-Ce2uxrJi.mjs} +8 -8
- package/dist/{BAlert-BFPBalmr.mjs.map → BAlert-Ce2uxrJi.mjs.map} +1 -1
- package/dist/{BAlert-Dk3rgEOI.js → BAlert-croEtrQu.js} +8 -8
- package/dist/{BAlert-Dk3rgEOI.js.map → BAlert-croEtrQu.js.map} +1 -1
- package/dist/{BApp-CIu-zI8K.mjs → BApp-B-fUrnpK.mjs} +2 -2
- package/dist/{BApp-CIu-zI8K.mjs.map → BApp-B-fUrnpK.mjs.map} +1 -1
- package/dist/{BApp-cBKQc5Dd.js → BApp-DOvEe1jo.js} +2 -2
- package/dist/{BApp-cBKQc5Dd.js.map → BApp-DOvEe1jo.js.map} +1 -1
- package/dist/{BAspect-BULTO240.js → BAspect-CUIU48Ck.js} +2 -2
- package/dist/{BAspect-BULTO240.js.map → BAspect-CUIU48Ck.js.map} +1 -1
- package/dist/{BAspect-CwokVvvn.mjs → BAspect-wfiXM4KA.mjs} +2 -2
- package/dist/{BAspect-CwokVvvn.mjs.map → BAspect-wfiXM4KA.mjs.map} +1 -1
- package/dist/{BAutocomplete-DRzLhACU.mjs → BAutocomplete-CH-bQzME.mjs} +8 -8
- package/dist/{BAutocomplete-DRzLhACU.mjs.map → BAutocomplete-CH-bQzME.mjs.map} +1 -1
- package/dist/{BAutocomplete-D8Qkcqcy.js → BAutocomplete-DLDFAV5_.js} +8 -8
- package/dist/{BAutocomplete-D8Qkcqcy.js.map → BAutocomplete-DLDFAV5_.js.map} +1 -1
- package/dist/{BAvatar-CZn0MQHY.js → BAvatar-FGK0dK0x.js} +5 -5
- package/dist/{BAvatar-CZn0MQHY.js.map → BAvatar-FGK0dK0x.js.map} +1 -1
- package/dist/{BAvatar-DODGnQMY.mjs → BAvatar-iALHbqVk.mjs} +5 -5
- package/dist/{BAvatar-DODGnQMY.mjs.map → BAvatar-iALHbqVk.mjs.map} +1 -1
- package/dist/{BBadge-CZ219I7a.mjs → BBadge-Cx_CdauK.mjs} +3 -3
- package/dist/{BBadge-CZ219I7a.mjs.map → BBadge-Cx_CdauK.mjs.map} +1 -1
- package/dist/{BBadge-DTJcCo9u.js → BBadge-Db6SEnzy.js} +3 -3
- package/dist/{BBadge-DTJcCo9u.js.map → BBadge-Db6SEnzy.js.map} +1 -1
- package/dist/{BBreadcrumb-DFG2Qxl9.js → BBreadcrumb-B9ra7vg2.js} +3 -3
- package/dist/{BBreadcrumb-DFG2Qxl9.js.map → BBreadcrumb-B9ra7vg2.js.map} +1 -1
- package/dist/{BBreadcrumb-Dk4ia-9c.mjs → BBreadcrumb-BxADbg0O.mjs} +3 -3
- package/dist/{BBreadcrumb-Dk4ia-9c.mjs.map → BBreadcrumb-BxADbg0O.mjs.map} +1 -1
- package/dist/{BButton-C0Ylhonf.mjs → BButton-BSa7LfL5.mjs} +5 -5
- package/dist/{BButton-C0Ylhonf.mjs.map → BButton-BSa7LfL5.mjs.map} +1 -1
- package/dist/{BButton-BZ9eI3ZX.js → BButton-DRRlzkyK.js} +5 -5
- package/dist/{BButton-BZ9eI3ZX.js.map → BButton-DRRlzkyK.js.map} +1 -1
- package/dist/{BButton-D_sCrjpg.mjs → BButton-PY7AANXJ.mjs} +4 -4
- package/dist/{BButton-D_sCrjpg.mjs.map → BButton-PY7AANXJ.mjs.map} +1 -1
- package/dist/{BButton-Dr-RadYQ.js → BButton-aYtMnyHu.js} +4 -4
- package/dist/{BButton-Dr-RadYQ.js.map → BButton-aYtMnyHu.js.map} +1 -1
- package/dist/{BCard-cj8_dIcz.mjs → BCard-BWoruisp.mjs} +3 -3
- package/dist/{BCard-cj8_dIcz.mjs.map → BCard-BWoruisp.mjs.map} +1 -1
- package/dist/{BCard-BjQkY783.js → BCard-Bh8RLMo_.js} +3 -3
- package/dist/{BCard-BjQkY783.js.map → BCard-Bh8RLMo_.js.map} +1 -1
- package/dist/{BCard-TS8DtOwm.mjs → BCard-CHbKv2OR.mjs} +3 -3
- package/dist/{BCard-TS8DtOwm.mjs.map → BCard-CHbKv2OR.mjs.map} +1 -1
- package/dist/{BCard-BkvG5Zzw.js → BCard-DwNYhVmg.js} +3 -3
- package/dist/{BCard-BkvG5Zzw.js.map → BCard-DwNYhVmg.js.map} +1 -1
- package/dist/{BCarousel-D23rApAX.js → BCarousel-2JB21Pcu.js} +5 -5
- package/dist/{BCarousel-D23rApAX.js.map → BCarousel-2JB21Pcu.js.map} +1 -1
- package/dist/{BCarousel-VL1gVXpt.mjs → BCarousel-B6_bgQpl.mjs} +5 -5
- package/dist/{BCarousel-VL1gVXpt.mjs.map → BCarousel-B6_bgQpl.mjs.map} +1 -1
- package/dist/{BCloseButton-CCdRwLDo.mjs → BCloseButton-CKTKr4PS.mjs} +2 -2
- package/dist/{BCloseButton-CCdRwLDo.mjs.map → BCloseButton-CKTKr4PS.mjs.map} +1 -1
- package/dist/{BCloseButton-fw5ONnhr.js → BCloseButton-D42zHRLP.js} +2 -2
- package/dist/{BCloseButton-fw5ONnhr.js.map → BCloseButton-D42zHRLP.js.map} +1 -1
- package/dist/{BCol-VPaTVLsM.mjs → BCol-B3VeEk9z.mjs} +2 -2
- package/dist/{BCol-VPaTVLsM.mjs.map → BCol-B3VeEk9z.mjs.map} +1 -1
- package/dist/{BCol-CArTYHqb.js → BCol-Ck9VydHj.js} +2 -2
- package/dist/{BCol-CArTYHqb.js.map → BCol-Ck9VydHj.js.map} +1 -1
- package/dist/{BCollapse-CZlDVTpI.js → BCollapse-CDLYLSZo.js} +5 -5
- package/dist/{BCollapse-CZlDVTpI.js.map → BCollapse-CDLYLSZo.js.map} +1 -1
- package/dist/{BCollapse-CTvK48kB.mjs → BCollapse-kqhe4AmL.mjs} +5 -5
- package/dist/{BCollapse-CTvK48kB.mjs.map → BCollapse-kqhe4AmL.mjs.map} +1 -1
- package/dist/{BContainer-CeHyMYb_.mjs → BContainer-ATfhaxTc.mjs} +4 -4
- package/dist/{BContainer-CeHyMYb_.mjs.map → BContainer-ATfhaxTc.mjs.map} +1 -1
- package/dist/{BContainer-CNmEk2mi.js → BContainer-CcF6dgtI.js} +4 -4
- package/dist/{BContainer-CNmEk2mi.js.map → BContainer-CcF6dgtI.js.map} +1 -1
- package/dist/{BDateField-gRWIwMnA.mjs → BDateField-CccP3H1R.mjs} +3 -3
- package/dist/{BDateField-gRWIwMnA.mjs.map → BDateField-CccP3H1R.mjs.map} +1 -1
- package/dist/{BDateField-B4yL8Pju.js → BDateField-DzZw5FRX.js} +3 -3
- package/dist/{BDateField-B4yL8Pju.js.map → BDateField-DzZw5FRX.js.map} +1 -1
- package/dist/{BDatePicker-m2drV1fl.js → BDatePicker-BDkzkOcm.js} +3 -3
- package/dist/{BDatePicker-m2drV1fl.js.map → BDatePicker-BDkzkOcm.js.map} +1 -1
- package/dist/{BDatePicker-ZuMpgD91.mjs → BDatePicker-BnwnSkBg.mjs} +3 -3
- package/dist/{BDatePicker-ZuMpgD91.mjs.map → BDatePicker-BnwnSkBg.mjs.map} +1 -1
- package/dist/{BDropdown-D2ep4wKG.mjs → BDropdown-0E8x5kk6.mjs} +5 -5
- package/dist/{BDropdown-D2ep4wKG.mjs.map → BDropdown-0E8x5kk6.mjs.map} +1 -1
- package/dist/{BDropdown-B2vWJ-u0.mjs → BDropdown-B1DbvVzm.mjs} +7 -7
- package/dist/{BDropdown-B2vWJ-u0.mjs.map → BDropdown-B1DbvVzm.mjs.map} +1 -1
- package/dist/{BDropdown-BSCasYDc.js → BDropdown-BPFtkX3p.js} +7 -7
- package/dist/{BDropdown-BSCasYDc.js.map → BDropdown-BPFtkX3p.js.map} +1 -1
- package/dist/{BDropdown-CL-erjq8.js → BDropdown-DKCgBzYS.js} +5 -5
- package/dist/{BDropdown-CL-erjq8.js.map → BDropdown-DKCgBzYS.js.map} +1 -1
- package/dist/{BForm-B0bPQ4kx.js → BForm-6JlWdQMO.js} +9 -6
- package/dist/{BForm-B0bPQ4kx.js.map → BForm-6JlWdQMO.js.map} +1 -1
- package/dist/{BForm-CpNuvbIt.mjs → BForm-BVfW08s5.mjs} +2 -2
- package/dist/{BForm-CpNuvbIt.mjs.map → BForm-BVfW08s5.mjs.map} +1 -1
- package/dist/{BForm-CoQKIJzv.mjs → BForm-DJu2hDV_.mjs} +10 -7
- package/dist/{BForm-CoQKIJzv.mjs.map → BForm-DJu2hDV_.mjs.map} +1 -1
- package/dist/{BForm-K67Ciyza.js → BForm-cnRpggt9.js} +2 -2
- package/dist/{BForm-K67Ciyza.js.map → BForm-cnRpggt9.js.map} +1 -1
- package/dist/{BFormCheckbox-xN7AQw4O.mjs → BFormCheckbox-Baf_9BSc.mjs} +9 -6
- package/dist/BFormCheckbox-Baf_9BSc.mjs.map +1 -0
- package/dist/{BFormCheckbox-g7gtIrhy.js → BFormCheckbox-D5ySHMJ8.js} +9 -6
- package/dist/BFormCheckbox-D5ySHMJ8.js.map +1 -0
- package/dist/{BFormFile-DXdAyYmv.mjs → BFormFile-CZebm0Cp.mjs} +8 -3
- package/dist/BFormFile-CZebm0Cp.mjs.map +1 -0
- package/dist/{BFormFile-DC-x9wQo.js → BFormFile-MISLntyJ.js} +8 -3
- package/dist/BFormFile-MISLntyJ.js.map +1 -0
- package/dist/{BFormGroup-DZTiChgT.js → BFormGroup-Bk1t-D1N.js} +89 -104
- package/dist/BFormGroup-Bk1t-D1N.js.map +1 -0
- package/dist/{BFormGroup-ayltvQts.mjs → BFormGroup-vysRPb99.mjs} +90 -105
- package/dist/BFormGroup-vysRPb99.mjs.map +1 -0
- package/dist/{BFormInput-DNuvqbFQ.js → BFormInput-CBwwDjfC.js} +4 -4
- package/dist/{BFormInput-DNuvqbFQ.js.map → BFormInput-CBwwDjfC.js.map} +1 -1
- package/dist/{BFormInput-NKko58M2.mjs → BFormInput-sEfU3CuN.mjs} +4 -4
- package/dist/{BFormInput-NKko58M2.mjs.map → BFormInput-sEfU3CuN.mjs.map} +1 -1
- package/dist/{BFormOtp-B4al7MJf.mjs → BFormOtp-C8X3u1od.mjs} +4 -4
- package/dist/{BFormOtp-B4al7MJf.mjs.map → BFormOtp-C8X3u1od.mjs.map} +1 -1
- package/dist/{BFormOtp-UcLR9oFd.js → BFormOtp-CLrQJRPe.js} +4 -4
- package/dist/{BFormOtp-UcLR9oFd.js.map → BFormOtp-CLrQJRPe.js.map} +1 -1
- package/dist/{BFormRadio-DX-gM5Rc.js → BFormRadio-B2yu-o2v.js} +9 -6
- package/dist/BFormRadio-B2yu-o2v.js.map +1 -0
- package/dist/{BFormRadio-DHx68AdL.mjs → BFormRadio-COc_IbxC.mjs} +9 -6
- package/dist/BFormRadio-COc_IbxC.mjs.map +1 -0
- package/dist/{BFormRating-BR7RMvZG.mjs → BFormRating-CIgPVsH_.mjs} +4 -4
- package/dist/{BFormRating-BR7RMvZG.mjs.map → BFormRating-CIgPVsH_.mjs.map} +1 -1
- package/dist/{BFormRating-CF-x5qkB.js → BFormRating-CSdRxN5z.js} +4 -4
- package/dist/{BFormRating-CF-x5qkB.js.map → BFormRating-CSdRxN5z.js.map} +1 -1
- package/dist/{BFormSelect-CtcsnTlz.js → BFormSelect-CI92Dv27.js} +7 -6
- package/dist/BFormSelect-CI92Dv27.js.map +1 -0
- package/dist/{BFormSelect-eS-C3M0J.mjs → BFormSelect-P-InkOm-.mjs} +7 -6
- package/dist/BFormSelect-P-InkOm-.mjs.map +1 -0
- package/dist/{BFormSelectOption-B3BO50XB.mjs → BFormSelectOption-DFN4lPRh.mjs} +3 -3
- package/dist/{BFormSelectOption-B3BO50XB.mjs.map → BFormSelectOption-DFN4lPRh.mjs.map} +1 -1
- package/dist/{BFormSelectOption-CQ3j1Q5j.js → BFormSelectOption-DrwJucNf.js} +3 -3
- package/dist/{BFormSelectOption-CQ3j1Q5j.js.map → BFormSelectOption-DrwJucNf.js.map} +1 -1
- package/dist/{BFormSpinbutton-DPCXum9q.js → BFormSpinbutton-1gTz4nTo.js} +4 -4
- package/dist/{BFormSpinbutton-DPCXum9q.js.map → BFormSpinbutton-1gTz4nTo.js.map} +1 -1
- package/dist/{BFormSpinbutton-CPsVUIh9.mjs → BFormSpinbutton-6qkTBF_4.mjs} +4 -4
- package/dist/{BFormSpinbutton-CPsVUIh9.mjs.map → BFormSpinbutton-6qkTBF_4.mjs.map} +1 -1
- package/dist/{BFormTag-Bsy6Znok.js → BFormTag-CeV0MSRC.js} +4 -4
- package/dist/{BFormTag-Bsy6Znok.js.map → BFormTag-CeV0MSRC.js.map} +1 -1
- package/dist/{BFormTag-Cjg1R-Lj.mjs → BFormTag-CnzI39y9.mjs} +4 -4
- package/dist/{BFormTag-Cjg1R-Lj.mjs.map → BFormTag-CnzI39y9.mjs.map} +1 -1
- package/dist/{BFormTags-D2Dk598Q.mjs → BFormTags-BMltSaKL.mjs} +4 -4
- package/dist/{BFormTags-D2Dk598Q.mjs.map → BFormTags-BMltSaKL.mjs.map} +1 -1
- package/dist/{BFormTags-BIZyBseI.js → BFormTags-BhO60uiL.js} +4 -4
- package/dist/{BFormTags-BIZyBseI.js.map → BFormTags-BhO60uiL.js.map} +1 -1
- package/dist/{BFormTextarea-CYh47SxL.js → BFormTextarea-C3Cj0DWj.js} +3 -3
- package/dist/{BFormTextarea-CYh47SxL.js.map → BFormTextarea-C3Cj0DWj.js.map} +1 -1
- package/dist/{BFormTextarea-M21mholw.mjs → BFormTextarea-DN1gAfSo.mjs} +3 -3
- package/dist/{BFormTextarea-M21mholw.mjs.map → BFormTextarea-DN1gAfSo.mjs.map} +1 -1
- package/dist/{BFormValidFeedback-DWkakzVO.mjs → BFormValidFeedback-CBYxQLDz.mjs} +44 -4
- package/dist/BFormValidFeedback-CBYxQLDz.mjs.map +1 -0
- package/dist/{BFormValidFeedback-BhkEhSa0.js → BFormValidFeedback-Kwxh798d.js} +48 -2
- package/dist/BFormValidFeedback-Kwxh798d.js.map +1 -0
- package/dist/{BImg-DFiJSy66.js → BImg-JKJLgYYT.js} +2 -2
- package/dist/{BImg-DFiJSy66.js.map → BImg-JKJLgYYT.js.map} +1 -1
- package/dist/{BImg-UUMOpbK0.mjs → BImg-QBS2ECBc.mjs} +2 -2
- package/dist/{BImg-UUMOpbK0.mjs.map → BImg-QBS2ECBc.mjs.map} +1 -1
- package/dist/{BInputGroup-BAC-B_UM.js → BInputGroup-Bvlfv6VD.js} +3 -3
- package/dist/{BInputGroup-BAC-B_UM.js.map → BInputGroup-Bvlfv6VD.js.map} +1 -1
- package/dist/{BInputGroup-CiKwWBSu.js → BInputGroup-D4fW324B.js} +3 -3
- package/dist/{BInputGroup-CiKwWBSu.js.map → BInputGroup-D4fW324B.js.map} +1 -1
- package/dist/{BInputGroup-CfELrPhK.mjs → BInputGroup-DiTSexkT.mjs} +3 -3
- package/dist/{BInputGroup-CfELrPhK.mjs.map → BInputGroup-DiTSexkT.mjs.map} +1 -1
- package/dist/{BInputGroup-3AVRA3U7.mjs → BInputGroup-X2Z53RJx.mjs} +3 -3
- package/dist/{BInputGroup-3AVRA3U7.mjs.map → BInputGroup-X2Z53RJx.mjs.map} +1 -1
- package/dist/{BLink-CNFWSz0D.mjs → BLink-Dfgte6dQ.mjs} +3 -3
- package/dist/{BLink-CNFWSz0D.mjs.map → BLink-Dfgte6dQ.mjs.map} +1 -1
- package/dist/{BLink-uLjtY3bY.js → BLink-kLEjleB1.js} +3 -3
- package/dist/{BLink-uLjtY3bY.js.map → BLink-kLEjleB1.js.map} +1 -1
- package/dist/{BListGroup-CeXKZio1.js → BListGroup-C8JOzHTz.js} +4 -4
- package/dist/{BListGroup-CeXKZio1.js.map → BListGroup-C8JOzHTz.js.map} +1 -1
- package/dist/{BListGroup-CGxa7ZEu.mjs → BListGroup-DwTLpNiD.mjs} +4 -4
- package/dist/{BListGroup-CGxa7ZEu.mjs.map → BListGroup-DwTLpNiD.mjs.map} +1 -1
- package/dist/{BModal-BEmloby5.mjs → BModal-C-ZCau2E.mjs} +7 -7
- package/dist/{BModal-BEmloby5.mjs.map → BModal-C-ZCau2E.mjs.map} +1 -1
- package/dist/{BModal-6hh-azT8.js → BModal-VstTwEq9.js} +7 -7
- package/dist/{BModal-6hh-azT8.js.map → BModal-VstTwEq9.js.map} +1 -1
- package/dist/{BNav-u9QwSGj3.js → BNav-DCLambmM.js} +5 -5
- package/dist/{BNav-u9QwSGj3.js.map → BNav-DCLambmM.js.map} +1 -1
- package/dist/{BNav-EHHlEg1E.mjs → BNav-DfYvjfRK.mjs} +5 -5
- package/dist/{BNav-EHHlEg1E.mjs.map → BNav-DfYvjfRK.mjs.map} +1 -1
- package/dist/{BNavbar-s8yvmhyz.js → BNavbar-BLWaZJRP.js} +4 -4
- package/dist/{BNavbar-s8yvmhyz.js.map → BNavbar-BLWaZJRP.js.map} +1 -1
- package/dist/{BNavbar-kgHIo_Gr.mjs → BNavbar-xYaikQVY.mjs} +4 -4
- package/dist/{BNavbar-kgHIo_Gr.mjs.map → BNavbar-xYaikQVY.mjs.map} +1 -1
- package/dist/{BOffcanvas-CwH0DqSG.mjs → BOffcanvas-CQb9XNvS.mjs} +6 -6
- package/dist/{BOffcanvas-CwH0DqSG.mjs.map → BOffcanvas-CQb9XNvS.mjs.map} +1 -1
- package/dist/{BOffcanvas-DdiP19Xz.js → BOffcanvas-DTRiZzwN.js} +6 -6
- package/dist/{BOffcanvas-DdiP19Xz.js.map → BOffcanvas-DTRiZzwN.js.map} +1 -1
- package/dist/{BOverlay-DSUoseNJ.mjs → BOverlay-Bh2PIN_q.mjs} +3 -3
- package/dist/{BOverlay-DSUoseNJ.mjs.map → BOverlay-Bh2PIN_q.mjs.map} +1 -1
- package/dist/{BOverlay--gZBEMlX.js → BOverlay-Bh4ldxgt.js} +3 -3
- package/dist/{BOverlay--gZBEMlX.js.map → BOverlay-Bh4ldxgt.js.map} +1 -1
- package/dist/{BPagination-C7MKOk8h.mjs → BPagination-D75q-ZNg.mjs} +2 -2
- package/dist/{BPagination-C7MKOk8h.mjs.map → BPagination-D75q-ZNg.mjs.map} +1 -1
- package/dist/{BPagination-D6W1LdgK.js → BPagination-fbjFAtxu.js} +2 -2
- package/dist/{BPagination-D6W1LdgK.js.map → BPagination-fbjFAtxu.js.map} +1 -1
- package/dist/{BPlaceholder-Ckvq3tMu.js → BPlaceholder-B3rs_39w.js} +4 -4
- package/dist/{BPlaceholder-Ckvq3tMu.js.map → BPlaceholder-B3rs_39w.js.map} +1 -1
- package/dist/{BPlaceholder-D__hNPyQ.mjs → BPlaceholder-DPQ6mCLN.mjs} +4 -4
- package/dist/{BPlaceholder-D__hNPyQ.mjs.map → BPlaceholder-DPQ6mCLN.mjs.map} +1 -1
- package/dist/{BProgress-I1ucNlpA.mjs → BProgress-BZlrPYhA.mjs} +3 -3
- package/dist/{BProgress-I1ucNlpA.mjs.map → BProgress-BZlrPYhA.mjs.map} +1 -1
- package/dist/{BProgress-ySlPjpRn.js → BProgress-th0-eZWo.js} +3 -3
- package/dist/{BProgress-ySlPjpRn.js.map → BProgress-th0-eZWo.js.map} +1 -1
- package/dist/{BRow-CmKiMcMZ.js → BRow-7AOuFiSy.js} +2 -2
- package/dist/{BRow-CmKiMcMZ.js.map → BRow-7AOuFiSy.js.map} +1 -1
- package/dist/{BRow-U3L8AcKV.mjs → BRow-eGSUYGCW.mjs} +2 -2
- package/dist/{BRow-U3L8AcKV.mjs.map → BRow-eGSUYGCW.mjs.map} +1 -1
- package/dist/{BSpinner-CAo-XD04.mjs → BSpinner-CUfGqviV.mjs} +2 -2
- package/dist/{BSpinner-CAo-XD04.mjs.map → BSpinner-CUfGqviV.mjs.map} +1 -1
- package/dist/{BSpinner-C1bm8U4-.js → BSpinner-DbYIp-C7.js} +2 -2
- package/dist/{BSpinner-C1bm8U4-.js.map → BSpinner-DbYIp-C7.js.map} +1 -1
- package/dist/{BTable-Bt75vbNu.mjs → BTable-CzMtFdt5.mjs} +5 -5
- package/dist/{BTable-Bt75vbNu.mjs.map → BTable-CzMtFdt5.mjs.map} +1 -1
- package/dist/{BTable-CXxJl2ps.js → BTable-DOpSWDaC.js} +5 -5
- package/dist/{BTable-CXxJl2ps.js.map → BTable-DOpSWDaC.js.map} +1 -1
- package/dist/{BTableSimple-pyz_6D4s.js → BTableSimple-BkdGAAKb.js} +3 -3
- package/dist/{BTableSimple-pyz_6D4s.js.map → BTableSimple-BkdGAAKb.js.map} +1 -1
- package/dist/{BTableSimple-CThwYBVl.mjs → BTableSimple-C-jn9Nwh.mjs} +3 -3
- package/dist/{BTableSimple-CThwYBVl.mjs.map → BTableSimple-C-jn9Nwh.mjs.map} +1 -1
- package/dist/{BTabs-C8rUY0Lx.js → BTabs-CvecFg5N.js} +4 -4
- package/dist/{BTabs-C8rUY0Lx.js.map → BTabs-CvecFg5N.js.map} +1 -1
- package/dist/{BTabs-Krs_Lv-R.mjs → BTabs-D_vWlBjT.mjs} +4 -4
- package/dist/{BTabs-Krs_Lv-R.mjs.map → BTabs-D_vWlBjT.mjs.map} +1 -1
- package/dist/{BTimeField-DSf4cMpN.mjs → BTimeField-BSDaZogC.mjs} +3 -3
- package/dist/{BTimeField-DSf4cMpN.mjs.map → BTimeField-BSDaZogC.mjs.map} +1 -1
- package/dist/{BTimeField-W2LqGCjB.js → BTimeField-BT5HXecp.js} +3 -3
- package/dist/{BTimeField-W2LqGCjB.js.map → BTimeField-BT5HXecp.js.map} +1 -1
- package/dist/{BToast-DZuxMDbe.js → BToast-DR0pek4W.js} +8 -8
- package/dist/{BToast-DZuxMDbe.js.map → BToast-DR0pek4W.js.map} +1 -1
- package/dist/{BToast-Dcfnqbxt.mjs → BToast-Y8BayxES.mjs} +8 -8
- package/dist/{BToast-Dcfnqbxt.mjs.map → BToast-Y8BayxES.mjs.map} +1 -1
- package/dist/{BTooltip-BWij0hjE.mjs → BTooltip-CVP8HdkU.mjs} +3 -3
- package/dist/{BTooltip-BWij0hjE.mjs.map → BTooltip-CVP8HdkU.mjs.map} +1 -1
- package/dist/{BTooltip-BGTjsV1z.js → BTooltip-DPLYtaL1.js} +3 -3
- package/dist/{BTooltip-BGTjsV1z.js.map → BTooltip-DPLYtaL1.js.map} +1 -1
- package/dist/bootstrap-vue-next.mjs +59 -59
- package/dist/bootstrap-vue-next.umd.js +59 -59
- package/dist/components/BFormFile/BFormFile.vue.d.mts +2 -1
- package/dist/components/BFormFile/BFormFile.vue.d.ts +2 -1
- package/dist/composables/useProvideFormGroupData.d.mts +15 -0
- package/dist/composables/useProvideFormGroupData.d.ts +15 -0
- package/dist/{floatingUi-8xXp54zf.mjs → floatingUi-62aeQtAb.mjs} +4 -4
- package/dist/{floatingUi-8xXp54zf.mjs.map → floatingUi-62aeQtAb.mjs.map} +1 -1
- package/dist/{floatingUi-9SWu8BgZ.js → floatingUi-DQ5bHmy3.js} +4 -4
- package/dist/{floatingUi-9SWu8BgZ.js.map → floatingUi-DQ5bHmy3.js.map} +1 -1
- package/dist/{keys-durSVUrO.js → keys-BMye8nSf.js} +10 -1
- package/dist/{keys-durSVUrO.js.map → keys-BMye8nSf.js.map} +1 -1
- package/dist/{keys-CQKrwmvN.mjs → keys-DU7sQgl3.mjs} +10 -1
- package/dist/{keys-CQKrwmvN.mjs.map → keys-DU7sQgl3.mjs.map} +1 -1
- package/dist/src/components/BAccordion/index.mjs +1 -1
- package/dist/src/components/BAccordion/index.umd.js +1 -1
- package/dist/src/components/BAlert/index.mjs +1 -1
- package/dist/src/components/BAlert/index.umd.js +1 -1
- package/dist/src/components/BApp/index.mjs +1 -1
- package/dist/src/components/BApp/index.umd.js +1 -1
- package/dist/src/components/BAspect/index.mjs +1 -1
- package/dist/src/components/BAspect/index.umd.js +1 -1
- package/dist/src/components/BAutocomplete/index.mjs +1 -1
- package/dist/src/components/BAutocomplete/index.umd.js +1 -1
- package/dist/src/components/BAvatar/index.mjs +1 -1
- package/dist/src/components/BAvatar/index.umd.js +1 -1
- package/dist/src/components/BBadge/index.mjs +1 -1
- package/dist/src/components/BBadge/index.umd.js +1 -1
- package/dist/src/components/BBreadcrumb/index.mjs +1 -1
- package/dist/src/components/BBreadcrumb/index.umd.js +1 -1
- package/dist/src/components/BButton/index.mjs +3 -3
- package/dist/src/components/BButton/index.umd.js +3 -3
- package/dist/src/components/BCard/index.mjs +2 -2
- package/dist/src/components/BCard/index.umd.js +2 -2
- package/dist/src/components/BCarousel/index.mjs +1 -1
- package/dist/src/components/BCarousel/index.umd.js +1 -1
- package/dist/src/components/BCol/index.mjs +1 -1
- package/dist/src/components/BCol/index.umd.js +1 -1
- package/dist/src/components/BCollapse/index.mjs +1 -1
- package/dist/src/components/BCollapse/index.umd.js +1 -1
- package/dist/src/components/BContainer/index.mjs +3 -3
- package/dist/src/components/BContainer/index.umd.js +3 -3
- package/dist/src/components/BDateField/index.mjs +1 -1
- package/dist/src/components/BDateField/index.umd.js +1 -1
- package/dist/src/components/BDatePicker/index.mjs +1 -1
- package/dist/src/components/BDatePicker/index.umd.js +1 -1
- package/dist/src/components/BDropdown/index.mjs +2 -2
- package/dist/src/components/BDropdown/index.umd.js +2 -2
- package/dist/src/components/BForm/index.mjs +3 -3
- package/dist/src/components/BForm/index.umd.js +3 -3
- package/dist/src/components/BFormCheckbox/index.mjs +1 -1
- package/dist/src/components/BFormCheckbox/index.umd.js +1 -1
- package/dist/src/components/BFormFile/index.mjs +1 -1
- package/dist/src/components/BFormFile/index.umd.js +1 -1
- package/dist/src/components/BFormGroup/index.mjs +1 -1
- package/dist/src/components/BFormGroup/index.umd.js +1 -1
- package/dist/src/components/BFormInput/index.mjs +1 -1
- package/dist/src/components/BFormInput/index.umd.js +1 -1
- package/dist/src/components/BFormOtp/index.mjs +1 -1
- package/dist/src/components/BFormOtp/index.umd.js +1 -1
- package/dist/src/components/BFormRadio/index.mjs +1 -1
- package/dist/src/components/BFormRadio/index.umd.js +1 -1
- package/dist/src/components/BFormRating/index.mjs +1 -1
- package/dist/src/components/BFormRating/index.umd.js +1 -1
- package/dist/src/components/BFormSelect/index.mjs +2 -2
- package/dist/src/components/BFormSelect/index.umd.js +2 -2
- package/dist/src/components/BFormSpinbutton/index.mjs +1 -1
- package/dist/src/components/BFormSpinbutton/index.umd.js +1 -1
- package/dist/src/components/BFormTags/index.mjs +2 -2
- package/dist/src/components/BFormTags/index.umd.js +2 -2
- package/dist/src/components/BFormTextarea/index.mjs +1 -1
- package/dist/src/components/BFormTextarea/index.umd.js +1 -1
- package/dist/src/components/BImg/index.mjs +1 -1
- package/dist/src/components/BImg/index.umd.js +1 -1
- package/dist/src/components/BInputGroup/index.mjs +2 -2
- package/dist/src/components/BInputGroup/index.umd.js +2 -2
- package/dist/src/components/BLink/index.mjs +1 -1
- package/dist/src/components/BLink/index.umd.js +1 -1
- package/dist/src/components/BListGroup/index.mjs +1 -1
- package/dist/src/components/BListGroup/index.umd.js +1 -1
- package/dist/src/components/BModal/index.mjs +1 -1
- package/dist/src/components/BModal/index.umd.js +1 -1
- package/dist/src/components/BNav/index.mjs +1 -1
- package/dist/src/components/BNav/index.umd.js +1 -1
- package/dist/src/components/BNavbar/index.mjs +1 -1
- package/dist/src/components/BNavbar/index.umd.js +1 -1
- package/dist/src/components/BOffcanvas/index.mjs +1 -1
- package/dist/src/components/BOffcanvas/index.umd.js +1 -1
- package/dist/src/components/BOverlay/index.mjs +1 -1
- package/dist/src/components/BOverlay/index.umd.js +1 -1
- package/dist/src/components/BPagination/index.mjs +1 -1
- package/dist/src/components/BPagination/index.umd.js +1 -1
- package/dist/src/components/BPlaceholder/index.mjs +1 -1
- package/dist/src/components/BPlaceholder/index.umd.js +1 -1
- package/dist/src/components/BPopover/index.mjs +1 -1
- package/dist/src/components/BPopover/index.umd.js +1 -1
- package/dist/src/components/BProgress/index.mjs +1 -1
- package/dist/src/components/BProgress/index.umd.js +1 -1
- package/dist/src/components/BRow/index.mjs +1 -1
- package/dist/src/components/BRow/index.umd.js +1 -1
- package/dist/src/components/BSpinner/index.mjs +1 -1
- package/dist/src/components/BSpinner/index.umd.js +1 -1
- package/dist/src/components/BTable/index.mjs +2 -2
- package/dist/src/components/BTable/index.umd.js +2 -2
- package/dist/src/components/BTabs/index.mjs +1 -1
- package/dist/src/components/BTabs/index.umd.js +1 -1
- package/dist/src/components/BTimeField/index.mjs +1 -1
- package/dist/src/components/BTimeField/index.umd.js +1 -1
- package/dist/src/components/BToast/index.mjs +1 -1
- package/dist/src/components/BToast/index.umd.js +1 -1
- package/dist/src/components/BTooltip/index.mjs +1 -1
- package/dist/src/components/BTooltip/index.umd.js +1 -1
- package/dist/src/components/index.mjs +59 -59
- package/dist/src/components/index.umd.js +59 -59
- package/dist/src/composables/orchestratorShared/index.mjs +1 -1
- package/dist/src/composables/orchestratorShared/index.umd.js +1 -1
- package/dist/src/composables/useBreadcrumb/index.mjs +1 -1
- package/dist/src/composables/useBreadcrumb/index.umd.js +1 -1
- package/dist/src/composables/useModal/index.mjs +2 -2
- package/dist/src/composables/useModal/index.umd.js +2 -2
- package/dist/src/composables/usePopover/index.mjs +3 -3
- package/dist/src/composables/usePopover/index.umd.js +3 -3
- package/dist/src/composables/useProvideDefaults/index.mjs +1 -1
- package/dist/src/composables/useProvideDefaults/index.umd.js +1 -1
- package/dist/src/composables/useRegistry/index.mjs +1 -1
- package/dist/src/composables/useRegistry/index.umd.js +1 -1
- package/dist/src/composables/useToast/index.mjs +2 -2
- package/dist/src/composables/useToast/index.umd.js +2 -2
- package/dist/src/composables/useToggle/index.mjs +1 -1
- package/dist/src/composables/useToggle/index.umd.js +1 -1
- package/dist/src/directives/BPopover/index.mjs +2 -2
- package/dist/src/directives/BPopover/index.umd.js +2 -2
- package/dist/src/directives/BScrollspy/index.mjs +1 -1
- package/dist/src/directives/BScrollspy/index.umd.js +1 -1
- package/dist/src/directives/BToggle/index.mjs +2 -2
- package/dist/src/directives/BToggle/index.umd.js +2 -2
- package/dist/src/directives/BTooltip/index.mjs +2 -2
- package/dist/src/directives/BTooltip/index.umd.js +2 -2
- package/dist/src/plugins/createBootstrap/index.mjs +1 -1
- package/dist/src/plugins/createBootstrap/index.umd.js +1 -1
- package/dist/src/plugins/orchestrator/index.mjs +1 -1
- package/dist/src/plugins/orchestrator/index.umd.js +1 -1
- package/dist/src/plugins/registry/index.mjs +1 -1
- package/dist/src/plugins/registry/index.umd.js +1 -1
- package/dist/src/plugins/rtl/index.mjs +1 -1
- package/dist/src/plugins/rtl/index.umd.js +1 -1
- package/dist/types/ComponentProps.d.mts +7 -0
- package/dist/types/ComponentProps.d.ts +7 -0
- package/dist/{useDefaults-DsLf4iRY.js → useDefaults-C0CYry78.js} +2 -2
- package/dist/{useDefaults-DsLf4iRY.js.map → useDefaults-C0CYry78.js.map} +1 -1
- package/dist/{useDefaults-BKgBaqOV.mjs → useDefaults-DseelK6y.mjs} +2 -2
- package/dist/{useDefaults-BKgBaqOV.mjs.map → useDefaults-DseelK6y.mjs.map} +1 -1
- package/dist/{useFormInput-CA4FYoV7.mjs → useFormInput-CXl8rpD0.mjs} +5 -4
- package/dist/useFormInput-CXl8rpD0.mjs.map +1 -0
- package/dist/{useFormInput-D31FCDxr.js → useFormInput-ip9hN2AU.js} +5 -4
- package/dist/useFormInput-ip9hN2AU.js.map +1 -0
- package/dist/{useId-DHrBgM7P.js → useId-BkAY2oh6.js} +2 -2
- package/dist/{useId-DHrBgM7P.js.map → useId-BkAY2oh6.js.map} +1 -1
- package/dist/{useId-BKZFSYm8.mjs → useId-D1sqXtwx.mjs} +2 -2
- package/dist/{useId-BKZFSYm8.mjs.map → useId-D1sqXtwx.mjs.map} +1 -1
- package/dist/{useRtl-DDPRnA7g.js → useRtl-BSgvbs5F.js} +2 -2
- package/dist/{useRtl-DDPRnA7g.js.map → useRtl-BSgvbs5F.js.map} +1 -1
- package/dist/{useRtl-VR3M2Txg.mjs → useRtl-CGoXBxNo.mjs} +2 -2
- package/dist/{useRtl-VR3M2Txg.mjs.map → useRtl-CGoXBxNo.mjs.map} +1 -1
- package/dist/{useShowHide-DKdljnpv.mjs → useShowHide-CBFt1_EW.mjs} +2 -2
- package/dist/{useShowHide-DKdljnpv.mjs.map → useShowHide-CBFt1_EW.mjs.map} +1 -1
- package/dist/{useShowHide-BhdrR1wG.js → useShowHide-CHm2uUep.js} +2 -2
- package/dist/{useShowHide-BhdrR1wG.js.map → useShowHide-CHm2uUep.js.map} +1 -1
- package/dist/utils/keys.d.mts +11 -1
- package/dist/utils/keys.d.ts +11 -1
- package/dist/{utils-BbYwYPyP.mjs → utils-CWvndqPg.mjs} +3 -3
- package/dist/{utils-BbYwYPyP.mjs.map → utils-CWvndqPg.mjs.map} +1 -1
- package/dist/{utils-ePxMJ7rd.js → utils-Dk9yAtbs.js} +3 -3
- package/dist/{utils-ePxMJ7rd.js.map → utils-Dk9yAtbs.js.map} +1 -1
- package/package.json +1 -1
- package/dist/BFormCheckbox-g7gtIrhy.js.map +0 -1
- package/dist/BFormCheckbox-xN7AQw4O.mjs.map +0 -1
- package/dist/BFormFile-DC-x9wQo.js.map +0 -1
- package/dist/BFormFile-DXdAyYmv.mjs.map +0 -1
- package/dist/BFormGroup-DZTiChgT.js.map +0 -1
- package/dist/BFormGroup-ayltvQts.mjs.map +0 -1
- package/dist/BFormRadio-DHx68AdL.mjs.map +0 -1
- package/dist/BFormRadio-DX-gM5Rc.js.map +0 -1
- package/dist/BFormSelect-CtcsnTlz.js.map +0 -1
- package/dist/BFormSelect-eS-C3M0J.mjs.map +0 -1
- package/dist/BFormValidFeedback-BhkEhSa0.js.map +0 -1
- package/dist/BFormValidFeedback-DWkakzVO.mjs.map +0 -1
- package/dist/useFormInput-CA4FYoV7.mjs.map +0 -1
- package/dist/useFormInput-D31FCDxr.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require("./chunk-CoQrYLCe.js");
|
|
2
|
-
const require_keys = require("./keys-
|
|
2
|
+
const require_keys = require("./keys-BMye8nSf.js");
|
|
3
3
|
const require_dist = require("./dist-DiXKLh_W.js");
|
|
4
4
|
const require_dom = require("./dom-Bs6DzM72.js");
|
|
5
|
-
const require_useDefaults = require("./useDefaults-
|
|
6
|
-
const require_useId = require("./useId-
|
|
5
|
+
const require_useDefaults = require("./useDefaults-C0CYry78.js");
|
|
6
|
+
const require_useId = require("./useId-BkAY2oh6.js");
|
|
7
7
|
const require_ConditionalWrapper = require("./ConditionalWrapper-DZH_VSwb.js");
|
|
8
8
|
const require_useFormCheck = require("./useFormCheck-DYjLG4WA.js");
|
|
9
9
|
let vue = require("vue");
|
|
@@ -138,7 +138,6 @@ var BFormCheckbox_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
138
138
|
});
|
|
139
139
|
const computedId = require_useId.useId(() => props.id, "form-check");
|
|
140
140
|
const parentData = (0, vue.inject)(require_keys.checkboxGroupKey, null);
|
|
141
|
-
const formGroupData = (0, vue.inject)(require_keys.formGroupKey, null)?.(computedId);
|
|
142
141
|
const input = (0, vue.useTemplateRef)("_input");
|
|
143
142
|
const { focused } = require_dist.useFocus(input, { initialValue: props.autofocus });
|
|
144
143
|
const hasDefaultSlot = (0, vue.computed)(() => !require_dom.isEmptySlot(slots.default));
|
|
@@ -163,6 +162,10 @@ var BFormCheckbox_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
163
162
|
buttonVariant: props.buttonVariant ?? parentData?.buttonVariant.value ?? propDefaults.buttonVariant
|
|
164
163
|
}));
|
|
165
164
|
const resolvedPlain = (0, vue.computed)(() => resolvedProps.value.plain);
|
|
165
|
+
const hasOwnLabel = (0, vue.computed)(() => hasDefaultSlot.value || !resolvedPlain.value);
|
|
166
|
+
const labelTargetId = (0, vue.computed)(() => hasOwnLabel.value ? null : computedId.value);
|
|
167
|
+
const formGroupData = (0, vue.inject)(require_keys.formGroupKey, null)?.();
|
|
168
|
+
formGroupData?.track(labelTargetId);
|
|
166
169
|
const localValue = (0, vue.computed)({
|
|
167
170
|
get: () => parentData ? parentData.modelValue.value : modelValue.value,
|
|
168
171
|
set: (newVal) => {
|
|
@@ -214,7 +217,7 @@ var BFormCheckbox_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
214
217
|
"true-value": (0, vue.unref)(props).value,
|
|
215
218
|
"false-value": (0, vue.unref)(props).uncheckedValue,
|
|
216
219
|
indeterminate: indeterminate.value || void 0
|
|
217
|
-
}, processedAttrs.value.inputAttrs), null, 16, _hoisted_1$1), [[vue.vModelCheckbox, localValue.value]]),
|
|
220
|
+
}, processedAttrs.value.inputAttrs), null, 16, _hoisted_1$1), [[vue.vModelCheckbox, localValue.value]]), hasOwnLabel.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("label", {
|
|
218
221
|
key: 0,
|
|
219
222
|
for: (0, vue.unref)(computedId),
|
|
220
223
|
class: (0, vue.normalizeClass)((0, vue.unref)(labelClasses))
|
|
@@ -483,4 +486,4 @@ Object.defineProperty(exports, "BFormCheckbox_default", {
|
|
|
483
486
|
}
|
|
484
487
|
});
|
|
485
488
|
|
|
486
|
-
//# sourceMappingURL=BFormCheckbox-
|
|
489
|
+
//# sourceMappingURL=BFormCheckbox-D5ySHMJ8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BFormCheckbox-D5ySHMJ8.js","names":[],"sources":["../src/components/BFormCheckbox/BFormCheckbox.vue","../src/components/BFormCheckbox/BFormCheckbox.vue","../src/components/BFormCheckbox/BFormCheckboxGroupBase.vue","../src/components/BFormCheckbox/BFormCheckboxGroupBase.vue","../src/components/BFormCheckbox/BFormCheckboxGroup.vue","../src/components/BFormCheckbox/BFormCheckboxGroup.vue"],"sourcesContent":["<template>\n <ConditionalWrapper\n :skip=\"isButtonGroup\"\n v-bind=\"props.wrapperAttrs\"\n :class=\"computedWrapperClasses\"\n >\n <input\n :id=\"computedId\"\n ref=\"_input\"\n v-model=\"localValue\"\n :class=\"computedInputClasses\"\n type=\"checkbox\"\n :disabled=\"props.disabled || parentData?.disabled.value || formGroupData?.disabled.value\"\n :required=\"computedRequired || undefined\"\n :name=\"props.name || parentData?.name.value\"\n :form=\"props.form || parentData?.form.value\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n :aria-required=\"computedRequired || undefined\"\n :value=\"props.value\"\n :true-value=\"props.value\"\n :false-value=\"props.uncheckedValue\"\n :indeterminate=\"indeterminate || undefined\"\n v-bind=\"processedAttrs.inputAttrs\"\n />\n <label v-if=\"hasOwnLabel\" :for=\"computedId\" :class=\"labelClasses\">\n <slot />\n </label>\n </ConditionalWrapper>\n</template>\n\n<script setup lang=\"ts\">\nimport {useFocus} from '@vueuse/core'\nimport {computed, inject, useAttrs, useTemplateRef} from 'vue'\nimport {getClasses, getInputClasses, getLabelClasses} from '../../composables/useFormCheck'\nimport {checkboxGroupKey, formGroupKey} from '../../utils/keys'\nimport ConditionalWrapper from '../ConditionalWrapper.vue'\nimport {isEmptySlot} from '../../utils/dom'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport type {BFormCheckboxProps, BFormCheckboxSlots, CheckboxValue} from '../../types'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst _props = withDefaults(\n defineProps<Omit<BFormCheckboxProps, 'modelValue' | 'indeterminate'>>(),\n {\n wrapperAttrs: undefined,\n inputClass: undefined,\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n autofocus: false,\n button: undefined,\n buttonGroup: false,\n buttonVariant: undefined,\n disabled: false,\n form: undefined,\n id: undefined,\n inline: undefined,\n name: undefined,\n plain: undefined,\n required: false,\n reverse: undefined,\n size: undefined,\n state: undefined,\n switch: undefined,\n uncheckedValue: false,\n value: true,\n }\n)\nconst props = useDefaults(_props, 'BFormCheckbox')\nconst slots = defineSlots<BFormCheckboxSlots>()\nconst attrs = useAttrs()\n\nconst modelValue = defineModel<BFormCheckboxProps['modelValue']>({\n default: undefined,\n})\nconst indeterminate = defineModel<Exclude<BFormCheckboxProps['indeterminate'], undefined>>(\n 'indeterminate',\n {\n default: false,\n }\n)\n\nconst processedAttrs = computed(() => {\n const {class: wrapperClass, ...inputAttrs} = attrs\n return {wrapperClass, inputAttrs}\n})\n\nconst computedId = useId(() => props.id, 'form-check')\n\nconst parentData = inject(checkboxGroupKey, null)\n\nconst input = useTemplateRef('_input')\n\nconst {focused} = useFocus(input, {\n initialValue: props.autofocus,\n})\n\nconst hasDefaultSlot = computed(() => !isEmptySlot(slots.default))\n\n// True default values for props that are undefined to support inheritance\nconst propDefaults = {\n plain: false,\n button: false,\n inline: false,\n reverse: false,\n switch: false,\n size: undefined,\n buttonVariant: 'secondary' as const,\n state: null,\n}\n\n// Single source of truth for resolved prop values with parent inheritance and defaults\nconst resolvedProps = computed(() => ({\n plain: props.plain ?? parentData?.plain.value ?? propDefaults.plain,\n button: props.button ?? parentData?.buttons.value ?? propDefaults.button,\n inline: props.inline ?? parentData?.inline.value ?? propDefaults.inline,\n reverse: props.reverse ?? parentData?.reverse.value ?? propDefaults.reverse,\n switch: props.switch ?? parentData?.switch.value ?? propDefaults.switch,\n state: props.state ?? parentData?.state.value ?? propDefaults.state,\n size: props.size ?? parentData?.size.value ?? propDefaults.size,\n buttonVariant:\n props.buttonVariant ?? parentData?.buttonVariant.value ?? propDefaults.buttonVariant,\n}))\n\n// Shorthand for template usage\nconst resolvedPlain = computed(() => resolvedProps.value.plain)\nconst hasOwnLabel = computed(() => hasDefaultSlot.value || !resolvedPlain.value)\n\nconst labelTargetId = computed(() => (hasOwnLabel.value ? null : computedId.value))\nconst formGroupData = inject(formGroupKey, null)?.()\nformGroupData?.track(labelTargetId)\n\nconst localValue = computed({\n get: () => (parentData ? parentData.modelValue.value : modelValue.value),\n set: (newVal) => {\n if (newVal === undefined) return\n // Indeterminate is implicitly cleared when the checked state is changed to any value\n // by the user. We reflect that here by setting our indetermiate model to false\n // which will emit the indeterminate event to the parent\n indeterminate.value = false\n if (parentData !== null && Array.isArray(newVal)) {\n // The type cast isn't perfect. Array.isArray detects CheckboxValue.unknown[],\n // but since it's parentData, it should always be CheckboxValue[]\n // It doesn't quite work when props.value is an [], but this is more of a Vue issue\n parentData.modelValue.value = newVal as CheckboxValue[]\n return\n }\n modelValue.value = newVal as CheckboxValue\n },\n})\n\nconst computedRequired = computed(\n () => !!(props.name ?? parentData?.name.value) && (props.required || parentData?.required.value)\n)\n\nconst isButtonGroup = computed(() => props.buttonGroup || (parentData?.buttons.value ?? false))\n\nconst classesObject = computed(() => ({\n ...resolvedProps.value,\n hasDefaultSlot: hasDefaultSlot.value,\n}))\nconst wrapperClasses = getClasses(classesObject)\nconst computedWrapperClasses = computed(() => [\n wrapperClasses.value,\n processedAttrs.value.wrapperClass,\n])\nconst inputClasses = getInputClasses(classesObject)\nconst computedInputClasses = computed(() => [inputClasses.value, props.inputClass])\nconst labelClasses = getLabelClasses(classesObject)\n\ndefineExpose({\n blur: () => {\n focused.value = false\n },\n element: input,\n focus: () => {\n focused.value = true\n },\n})\n</script>\n","<template>\n <ConditionalWrapper\n :skip=\"isButtonGroup\"\n v-bind=\"props.wrapperAttrs\"\n :class=\"computedWrapperClasses\"\n >\n <input\n :id=\"computedId\"\n ref=\"_input\"\n v-model=\"localValue\"\n :class=\"computedInputClasses\"\n type=\"checkbox\"\n :disabled=\"props.disabled || parentData?.disabled.value || formGroupData?.disabled.value\"\n :required=\"computedRequired || undefined\"\n :name=\"props.name || parentData?.name.value\"\n :form=\"props.form || parentData?.form.value\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n :aria-required=\"computedRequired || undefined\"\n :value=\"props.value\"\n :true-value=\"props.value\"\n :false-value=\"props.uncheckedValue\"\n :indeterminate=\"indeterminate || undefined\"\n v-bind=\"processedAttrs.inputAttrs\"\n />\n <label v-if=\"hasOwnLabel\" :for=\"computedId\" :class=\"labelClasses\">\n <slot />\n </label>\n </ConditionalWrapper>\n</template>\n\n<script setup lang=\"ts\">\nimport {useFocus} from '@vueuse/core'\nimport {computed, inject, useAttrs, useTemplateRef} from 'vue'\nimport {getClasses, getInputClasses, getLabelClasses} from '../../composables/useFormCheck'\nimport {checkboxGroupKey, formGroupKey} from '../../utils/keys'\nimport ConditionalWrapper from '../ConditionalWrapper.vue'\nimport {isEmptySlot} from '../../utils/dom'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport type {BFormCheckboxProps, BFormCheckboxSlots, CheckboxValue} from '../../types'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst _props = withDefaults(\n defineProps<Omit<BFormCheckboxProps, 'modelValue' | 'indeterminate'>>(),\n {\n wrapperAttrs: undefined,\n inputClass: undefined,\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n autofocus: false,\n button: undefined,\n buttonGroup: false,\n buttonVariant: undefined,\n disabled: false,\n form: undefined,\n id: undefined,\n inline: undefined,\n name: undefined,\n plain: undefined,\n required: false,\n reverse: undefined,\n size: undefined,\n state: undefined,\n switch: undefined,\n uncheckedValue: false,\n value: true,\n }\n)\nconst props = useDefaults(_props, 'BFormCheckbox')\nconst slots = defineSlots<BFormCheckboxSlots>()\nconst attrs = useAttrs()\n\nconst modelValue = defineModel<BFormCheckboxProps['modelValue']>({\n default: undefined,\n})\nconst indeterminate = defineModel<Exclude<BFormCheckboxProps['indeterminate'], undefined>>(\n 'indeterminate',\n {\n default: false,\n }\n)\n\nconst processedAttrs = computed(() => {\n const {class: wrapperClass, ...inputAttrs} = attrs\n return {wrapperClass, inputAttrs}\n})\n\nconst computedId = useId(() => props.id, 'form-check')\n\nconst parentData = inject(checkboxGroupKey, null)\n\nconst input = useTemplateRef('_input')\n\nconst {focused} = useFocus(input, {\n initialValue: props.autofocus,\n})\n\nconst hasDefaultSlot = computed(() => !isEmptySlot(slots.default))\n\n// True default values for props that are undefined to support inheritance\nconst propDefaults = {\n plain: false,\n button: false,\n inline: false,\n reverse: false,\n switch: false,\n size: undefined,\n buttonVariant: 'secondary' as const,\n state: null,\n}\n\n// Single source of truth for resolved prop values with parent inheritance and defaults\nconst resolvedProps = computed(() => ({\n plain: props.plain ?? parentData?.plain.value ?? propDefaults.plain,\n button: props.button ?? parentData?.buttons.value ?? propDefaults.button,\n inline: props.inline ?? parentData?.inline.value ?? propDefaults.inline,\n reverse: props.reverse ?? parentData?.reverse.value ?? propDefaults.reverse,\n switch: props.switch ?? parentData?.switch.value ?? propDefaults.switch,\n state: props.state ?? parentData?.state.value ?? propDefaults.state,\n size: props.size ?? parentData?.size.value ?? propDefaults.size,\n buttonVariant:\n props.buttonVariant ?? parentData?.buttonVariant.value ?? propDefaults.buttonVariant,\n}))\n\n// Shorthand for template usage\nconst resolvedPlain = computed(() => resolvedProps.value.plain)\nconst hasOwnLabel = computed(() => hasDefaultSlot.value || !resolvedPlain.value)\n\nconst labelTargetId = computed(() => (hasOwnLabel.value ? null : computedId.value))\nconst formGroupData = inject(formGroupKey, null)?.()\nformGroupData?.track(labelTargetId)\n\nconst localValue = computed({\n get: () => (parentData ? parentData.modelValue.value : modelValue.value),\n set: (newVal) => {\n if (newVal === undefined) return\n // Indeterminate is implicitly cleared when the checked state is changed to any value\n // by the user. We reflect that here by setting our indetermiate model to false\n // which will emit the indeterminate event to the parent\n indeterminate.value = false\n if (parentData !== null && Array.isArray(newVal)) {\n // The type cast isn't perfect. Array.isArray detects CheckboxValue.unknown[],\n // but since it's parentData, it should always be CheckboxValue[]\n // It doesn't quite work when props.value is an [], but this is more of a Vue issue\n parentData.modelValue.value = newVal as CheckboxValue[]\n return\n }\n modelValue.value = newVal as CheckboxValue\n },\n})\n\nconst computedRequired = computed(\n () => !!(props.name ?? parentData?.name.value) && (props.required || parentData?.required.value)\n)\n\nconst isButtonGroup = computed(() => props.buttonGroup || (parentData?.buttons.value ?? false))\n\nconst classesObject = computed(() => ({\n ...resolvedProps.value,\n hasDefaultSlot: hasDefaultSlot.value,\n}))\nconst wrapperClasses = getClasses(classesObject)\nconst computedWrapperClasses = computed(() => [\n wrapperClasses.value,\n processedAttrs.value.wrapperClass,\n])\nconst inputClasses = getInputClasses(classesObject)\nconst computedInputClasses = computed(() => [inputClasses.value, props.inputClass])\nconst labelClasses = getLabelClasses(classesObject)\n\ndefineExpose({\n blur: () => {\n focused.value = false\n },\n element: input,\n focus: () => {\n focused.value = true\n },\n})\n</script>\n","<template>\n <div\n v-bind=\"attrs\"\n :id=\"computedId\"\n ref=\"_element\"\n role=\"group\"\n :class=\"classes\"\n class=\"bv-no-focus-ring\"\n tabindex=\"-1\"\n >\n <slot name=\"first\" />\n <BFormCheckbox v-for=\"(item, index) in normalizedOptions\" :key=\"index\" v-bind=\"item\">\n <slot name=\"option\" v-bind=\"item\">\n {{ item.text }}\n </slot>\n </BFormCheckbox>\n <slot />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {computed, provide, toRef, useTemplateRef} from 'vue'\nimport type {BFormCheckboxGroupBaseProps, CheckboxValue} from '../../types'\nimport BFormCheckbox from './BFormCheckbox.vue'\nimport {checkboxGroupKey} from '../../utils/keys'\nimport {getGroupAttr, getGroupClasses} from '../../composables/useFormCheck'\nimport {useFocus} from '@vueuse/core'\nimport {useId} from '../../composables/useId'\nimport {useDefaults} from '../../composables/useDefaults'\n\nconst _props = withDefaults(defineProps<Omit<BFormCheckboxGroupBaseProps, 'modelValue'>>(), {\n ariaInvalid: undefined,\n autofocus: false,\n buttonVariant: 'secondary',\n buttons: false,\n disabled: false,\n form: undefined,\n id: undefined,\n name: undefined,\n options: () => [],\n plain: false,\n required: false,\n reverse: false,\n size: undefined,\n stacked: false,\n state: null,\n switches: false,\n validated: false,\n})\nconst props = useDefaults(_props, 'BFormCheckboxGroup')\n\nconst modelValue = defineModel<CheckboxValue[]>({\n default: () => [],\n})\n\nconst computedId = useId(() => props.id, 'checkbox')\nconst computedName = useId(() => props.name, 'checkbox')\nconst _element = useTemplateRef('_element')\n\nconst {focused} = useFocus(_element, {\n initialValue: props.autofocus,\n})\n\n// Provide context to child checkboxes\nprovide(checkboxGroupKey, {\n modelValue: modelValue as import('vue').Ref<\n readonly import('../../types/CheckboxTypes').CheckboxValue[]\n >,\n switch: toRef(() => props.switches),\n buttonVariant: toRef(() => props.buttonVariant),\n form: toRef(() => props.form),\n name: computedName,\n state: toRef(() => props.state),\n plain: toRef(() => props.plain),\n size: toRef(() => props.size),\n inline: toRef(() => !props.stacked),\n reverse: toRef(() => props.reverse),\n required: toRef(() => props.required),\n buttons: toRef(() => props.buttons),\n disabled: toRef(() => props.disabled),\n})\n\n// Normalize options to always be objects with text/value fields\nconst normalizedOptions = computed<Array<{text: string; value: CheckboxValue; disabled: boolean}>>(\n () =>\n props.options.map((option) => {\n if (typeof option === 'object' && option !== null) {\n // Ensure text and disabled are defined, with group disabled taking precedence\n return {\n ...option,\n text: option.text ?? String(option.value ?? ''),\n value: option.value ?? null,\n disabled: props.disabled ? true : (option.disabled ?? false),\n }\n }\n // Primitive value - normalize to {text, value}, with group disabled taking precedence\n return {\n text: String(option),\n value: option,\n disabled: props.disabled,\n }\n })\n)\n\nconst classesObject = computed(() => ({\n required: props.required,\n ariaInvalid: props.ariaInvalid,\n state: props.state,\n validated: props.validated,\n buttons: props.buttons,\n stacked: props.stacked,\n size: props.size,\n}))\nconst attrs = getGroupAttr(classesObject)\nconst classes = getGroupClasses(classesObject)\n\ndefineExpose({\n blur: () => {\n focused.value = false\n },\n focus: () => {\n focused.value = true\n },\n})\n</script>\n","<template>\n <div\n v-bind=\"attrs\"\n :id=\"computedId\"\n ref=\"_element\"\n role=\"group\"\n :class=\"classes\"\n class=\"bv-no-focus-ring\"\n tabindex=\"-1\"\n >\n <slot name=\"first\" />\n <BFormCheckbox v-for=\"(item, index) in normalizedOptions\" :key=\"index\" v-bind=\"item\">\n <slot name=\"option\" v-bind=\"item\">\n {{ item.text }}\n </slot>\n </BFormCheckbox>\n <slot />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {computed, provide, toRef, useTemplateRef} from 'vue'\nimport type {BFormCheckboxGroupBaseProps, CheckboxValue} from '../../types'\nimport BFormCheckbox from './BFormCheckbox.vue'\nimport {checkboxGroupKey} from '../../utils/keys'\nimport {getGroupAttr, getGroupClasses} from '../../composables/useFormCheck'\nimport {useFocus} from '@vueuse/core'\nimport {useId} from '../../composables/useId'\nimport {useDefaults} from '../../composables/useDefaults'\n\nconst _props = withDefaults(defineProps<Omit<BFormCheckboxGroupBaseProps, 'modelValue'>>(), {\n ariaInvalid: undefined,\n autofocus: false,\n buttonVariant: 'secondary',\n buttons: false,\n disabled: false,\n form: undefined,\n id: undefined,\n name: undefined,\n options: () => [],\n plain: false,\n required: false,\n reverse: false,\n size: undefined,\n stacked: false,\n state: null,\n switches: false,\n validated: false,\n})\nconst props = useDefaults(_props, 'BFormCheckboxGroup')\n\nconst modelValue = defineModel<CheckboxValue[]>({\n default: () => [],\n})\n\nconst computedId = useId(() => props.id, 'checkbox')\nconst computedName = useId(() => props.name, 'checkbox')\nconst _element = useTemplateRef('_element')\n\nconst {focused} = useFocus(_element, {\n initialValue: props.autofocus,\n})\n\n// Provide context to child checkboxes\nprovide(checkboxGroupKey, {\n modelValue: modelValue as import('vue').Ref<\n readonly import('../../types/CheckboxTypes').CheckboxValue[]\n >,\n switch: toRef(() => props.switches),\n buttonVariant: toRef(() => props.buttonVariant),\n form: toRef(() => props.form),\n name: computedName,\n state: toRef(() => props.state),\n plain: toRef(() => props.plain),\n size: toRef(() => props.size),\n inline: toRef(() => !props.stacked),\n reverse: toRef(() => props.reverse),\n required: toRef(() => props.required),\n buttons: toRef(() => props.buttons),\n disabled: toRef(() => props.disabled),\n})\n\n// Normalize options to always be objects with text/value fields\nconst normalizedOptions = computed<Array<{text: string; value: CheckboxValue; disabled: boolean}>>(\n () =>\n props.options.map((option) => {\n if (typeof option === 'object' && option !== null) {\n // Ensure text and disabled are defined, with group disabled taking precedence\n return {\n ...option,\n text: option.text ?? String(option.value ?? ''),\n value: option.value ?? null,\n disabled: props.disabled ? true : (option.disabled ?? false),\n }\n }\n // Primitive value - normalize to {text, value}, with group disabled taking precedence\n return {\n text: String(option),\n value: option,\n disabled: props.disabled,\n }\n })\n)\n\nconst classesObject = computed(() => ({\n required: props.required,\n ariaInvalid: props.ariaInvalid,\n state: props.state,\n validated: props.validated,\n buttons: props.buttons,\n stacked: props.stacked,\n size: props.size,\n}))\nconst attrs = getGroupAttr(classesObject)\nconst classes = getGroupClasses(classesObject)\n\ndefineExpose({\n blur: () => {\n focused.value = false\n },\n focus: () => {\n focused.value = true\n },\n})\n</script>\n","<template>\n <BFormCheckboxGroupBase\n v-bind=\"forwardedProps\"\n v-model=\"modelValue as unknown as CheckboxValue[]\"\n :options=\"normalizedOptions\"\n >\n <!-- Forward all slots -->\n <template #first>\n <slot name=\"first\" />\n </template>\n\n <template #option=\"slotProps\">\n <slot name=\"option\" v-bind=\"slotProps\" />\n </template>\n\n <slot />\n </BFormCheckboxGroupBase>\n</template>\n\n<script\n setup\n lang=\"ts\"\n generic=\"\n Options extends readonly (object | string | number | boolean)[] = readonly (\n | object\n | string\n | number\n | boolean\n )[]\n \"\n>\nimport type {\n BFormCheckboxGroupProps,\n BFormCheckboxGroupSlots,\n CheckboxValue,\n OptionsValues,\n} from '../../types'\nimport {computed} from 'vue'\nimport BFormCheckboxGroupBase from './BFormCheckboxGroupBase.vue'\n\n/**\n * Type-safe wrapper component for BFormCheckboxGroup.\n * Provides generic type safety for options array and strongly-typed modelValue.\n * Uses Options array generic to extract union of all possible values.\n * Supports both complex objects and simple scalar types (string, number, boolean).\n *\n * For strongly-typed modelValue:\n * - Primitive arrays: modelValue is array of those value types\n * - Object arrays with 'value' field: modelValue is array of value field types\n * - Use 'as const' on options for literal type inference\n */\n\n// Generic props - type safety happens here\nconst props = withDefaults(defineProps<Omit<BFormCheckboxGroupProps<Options>, 'modelValue'>>(), {\n ariaInvalid: undefined,\n autofocus: false,\n buttonVariant: 'secondary',\n buttons: false,\n disabled: false,\n disabledField: 'disabled',\n form: undefined,\n id: undefined,\n name: undefined,\n options: () => [] as unknown as Options,\n plain: false,\n required: false,\n reverse: false,\n size: undefined,\n stacked: false,\n state: null,\n switches: false,\n textField: 'text',\n validated: false,\n valueField: 'value',\n})\ndefineSlots<BFormCheckboxGroupSlots>()\n\n// Type-safe model value - extracts union from options, wraps in array.\n// NOTE: OptionsValues assumes a static \"value\" key; custom valueField is not\n// reflected in the type — modelValue falls back to unknown in that case.\nconst modelValue = defineModel<OptionsValues<Options>[] | undefined>({\n default: () => [],\n})\n\n// Type-safe normalization of options\nconst normalizedOptions = computed(() =>\n (props.options ?? []).map(\n (el) =>\n (typeof el === 'string' || typeof el === 'number' || typeof el === 'boolean'\n ? {\n value: el,\n disabled: props.disabled,\n text: el.toString(),\n }\n : {\n value: (el as Record<string, unknown>)[props.valueField as string],\n disabled:\n props.disabled ||\n (((el as Record<string, unknown>)[props.disabledField as string] as\n | boolean\n | undefined) ??\n false),\n text:\n ((el as Record<string, unknown>)[props.textField as string] as string | undefined) ??\n String((el as Record<string, unknown>)[props.valueField as string]),\n }) as {text: string; value: CheckboxValue; disabled: boolean}\n )\n)\n\n// Forward all non-option-related props\nconst forwardedProps = computed(() => ({\n id: props.id,\n name: props.name,\n size: props.size,\n state: props.state,\n buttonVariant: props.buttonVariant,\n buttons: props.buttons,\n stacked: props.stacked,\n disabled: props.disabled,\n required: props.required,\n validated: props.validated,\n autofocus: props.autofocus,\n form: props.form,\n ariaInvalid: props.ariaInvalid,\n plain: props.plain,\n reverse: props.reverse,\n switches: props.switches,\n}))\n</script>\n","<template>\n <BFormCheckboxGroupBase\n v-bind=\"forwardedProps\"\n v-model=\"modelValue as unknown as CheckboxValue[]\"\n :options=\"normalizedOptions\"\n >\n <!-- Forward all slots -->\n <template #first>\n <slot name=\"first\" />\n </template>\n\n <template #option=\"slotProps\">\n <slot name=\"option\" v-bind=\"slotProps\" />\n </template>\n\n <slot />\n </BFormCheckboxGroupBase>\n</template>\n\n<script\n setup\n lang=\"ts\"\n generic=\"\n Options extends readonly (object | string | number | boolean)[] = readonly (\n | object\n | string\n | number\n | boolean\n )[]\n \"\n>\nimport type {\n BFormCheckboxGroupProps,\n BFormCheckboxGroupSlots,\n CheckboxValue,\n OptionsValues,\n} from '../../types'\nimport {computed} from 'vue'\nimport BFormCheckboxGroupBase from './BFormCheckboxGroupBase.vue'\n\n/**\n * Type-safe wrapper component for BFormCheckboxGroup.\n * Provides generic type safety for options array and strongly-typed modelValue.\n * Uses Options array generic to extract union of all possible values.\n * Supports both complex objects and simple scalar types (string, number, boolean).\n *\n * For strongly-typed modelValue:\n * - Primitive arrays: modelValue is array of those value types\n * - Object arrays with 'value' field: modelValue is array of value field types\n * - Use 'as const' on options for literal type inference\n */\n\n// Generic props - type safety happens here\nconst props = withDefaults(defineProps<Omit<BFormCheckboxGroupProps<Options>, 'modelValue'>>(), {\n ariaInvalid: undefined,\n autofocus: false,\n buttonVariant: 'secondary',\n buttons: false,\n disabled: false,\n disabledField: 'disabled',\n form: undefined,\n id: undefined,\n name: undefined,\n options: () => [] as unknown as Options,\n plain: false,\n required: false,\n reverse: false,\n size: undefined,\n stacked: false,\n state: null,\n switches: false,\n textField: 'text',\n validated: false,\n valueField: 'value',\n})\ndefineSlots<BFormCheckboxGroupSlots>()\n\n// Type-safe model value - extracts union from options, wraps in array.\n// NOTE: OptionsValues assumes a static \"value\" key; custom valueField is not\n// reflected in the type — modelValue falls back to unknown in that case.\nconst modelValue = defineModel<OptionsValues<Options>[] | undefined>({\n default: () => [],\n})\n\n// Type-safe normalization of options\nconst normalizedOptions = computed(() =>\n (props.options ?? []).map(\n (el) =>\n (typeof el === 'string' || typeof el === 'number' || typeof el === 'boolean'\n ? {\n value: el,\n disabled: props.disabled,\n text: el.toString(),\n }\n : {\n value: (el as Record<string, unknown>)[props.valueField as string],\n disabled:\n props.disabled ||\n (((el as Record<string, unknown>)[props.disabledField as string] as\n | boolean\n | undefined) ??\n false),\n text:\n ((el as Record<string, unknown>)[props.textField as string] as string | undefined) ??\n String((el as Record<string, unknown>)[props.valueField as string]),\n }) as {text: string; value: CheckboxValue; disabled: boolean}\n )\n)\n\n// Forward all non-option-related props\nconst forwardedProps = computed(() => ({\n id: props.id,\n name: props.name,\n size: props.size,\n state: props.state,\n buttonVariant: props.buttonVariant,\n buttons: props.buttons,\n stacked: props.stacked,\n disabled: props.disabled,\n required: props.required,\n validated: props.validated,\n autofocus: props.autofocus,\n form: props.form,\n ariaInvalid: props.ariaInvalid,\n plain: props.plain,\n reverse: props.reverse,\n switches: props.switches,\n}))\n</script>\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { p as useFileDialog, u as useDropZone } from "./dist-Dk9C_HFS.mjs";
|
|
2
2
|
import { o as isEmptySlot } from "./dom-AhkaSoh8.mjs";
|
|
3
|
-
import { t as useDefaults } from "./useDefaults-
|
|
4
|
-
import { t as useId$1 } from "./useId-
|
|
3
|
+
import { t as useDefaults } from "./useDefaults-DseelK6y.mjs";
|
|
4
|
+
import { t as useId$1 } from "./useId-D1sqXtwx.mjs";
|
|
5
5
|
import { t as useStateClass } from "./useStateClass-DxlL_m2E.mjs";
|
|
6
6
|
import { computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, mergeModels, mergeProps, nextTick, normalizeClass, onMounted, openBlock, ref, renderSlot, toDisplayString, unref, useAttrs, useModel, useSlots, useTemplateRef, watch, withModifiers } from "vue";
|
|
7
7
|
//#region src/components/BFormFile/BFormFile.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -76,6 +76,10 @@ var BFormFile_default = /* @__PURE__ */ defineComponent({
|
|
|
76
76
|
props: /* @__PURE__ */ mergeModels({
|
|
77
77
|
ariaLabel: { default: void 0 },
|
|
78
78
|
ariaLabelledby: { default: void 0 },
|
|
79
|
+
ariaLiveFormatter: {
|
|
80
|
+
type: Function,
|
|
81
|
+
default: void 0
|
|
82
|
+
},
|
|
79
83
|
accept: { default: "" },
|
|
80
84
|
autofocus: {
|
|
81
85
|
type: Boolean,
|
|
@@ -202,6 +206,7 @@ var BFormFile_default = /* @__PURE__ */ defineComponent({
|
|
|
202
206
|
const showExternalDisplay = computed(() => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder));
|
|
203
207
|
const ariaLiveMessage = computed(() => {
|
|
204
208
|
if (!hasFiles.value) return "";
|
|
209
|
+
if (props.ariaLiveFormatter) return props.ariaLiveFormatter(selectedFiles.value);
|
|
205
210
|
const count = selectedFiles.value.length;
|
|
206
211
|
if (count === 1) return `File selected: ${selectedFiles.value[0]?.name}`;
|
|
207
212
|
return `${count} files selected`;
|
|
@@ -409,4 +414,4 @@ var BFormFile_default = /* @__PURE__ */ defineComponent({
|
|
|
409
414
|
//#endregion
|
|
410
415
|
export { BFormFile_default as t };
|
|
411
416
|
|
|
412
|
-
//# sourceMappingURL=BFormFile-
|
|
417
|
+
//# sourceMappingURL=BFormFile-CZebm0Cp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BFormFile-CZebm0Cp.mjs","names":[],"sources":["../src/components/BFormFile/BFormFile.vue","../src/components/BFormFile/BFormFile.vue"],"sourcesContent":["<template>\n <div ref=\"rootRef\" v-bind=\"processedAttrs.rootAttrs\" class=\"b-form-file-root\">\n <!-- Optional label -->\n <label\n v-if=\"hasLabelSlot || props.label\"\n class=\"form-label\"\n :class=\"props.labelClass\"\n :for=\"computedId\"\n >\n <slot name=\"label\">\n {{ props.label }}\n </slot>\n </label>\n\n <!-- Drop zone wrapper -->\n <div\n v-if=\"!props.plain\"\n ref=\"dropZoneRef\"\n v-bind=\"processedAttrs.dropZoneAttrs\"\n class=\"b-form-file-wrapper\"\n :class=\"{\n 'b-form-file-dragging': isOverDropZone && !props.noDrop,\n 'b-form-file-has-files': hasFiles,\n }\"\n >\n <!-- Custom file control (mimics Bootstrap native input) -->\n <div\n class=\"b-form-file-control\"\n :class=\"computedClasses\"\n :aria-disabled=\"props.disabled\"\n @click=\"handleControlClick\"\n >\n <!-- Custom browse button (now on LEFT to match Bootstrap v5) -->\n <button\n v-if=\"!props.noButton\"\n :id=\"computedId\"\n ref=\"browseButtonRef\"\n type=\"button\"\n class=\"b-form-file-button\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n @click.stop=\"openFileDialog\"\n >\n {{ effectiveBrowseText }}\n </button>\n\n <!-- File name display -->\n <div class=\"b-form-file-text\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <span v-if=\"hasFiles\">{{ formattedFileNames }}</span>\n <span v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"text-muted\">\n <slot name=\"placeholder\">{{ props.placeholder }}</slot>\n </span>\n </slot>\n </div>\n </div>\n\n <!-- Drag overlay (only shown when dragging) -->\n <div v-if=\"isOverDropZone && !props.noDrop\" class=\"b-form-file-drag-overlay\">\n <slot name=\"drop-placeholder\">\n <div class=\"b-form-file-drag-text\">\n {{ effectiveDropPlaceholder }}\n </div>\n </slot>\n </div>\n\n <!-- Hidden input for form submission (positioned behind UI with z-index) -->\n <input\n ref=\"customInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :name=\"props.name\"\n :form=\"props.form\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :required=\"props.required\"\n :accept=\"computedAccept || undefined\"\n :capture=\"props.capture\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n style=\"\n position: absolute;\n z-index: -5;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n \"\n />\n </div>\n\n <!-- Plain mode - simple native input -->\n <input\n v-else\n :id=\"computedId\"\n ref=\"plainInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :class=\"computedPlainClasses\"\n :form=\"props.form\"\n :name=\"props.name\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :capture=\"props.capture\"\n :accept=\"computedAccept || undefined\"\n :required=\"props.required || undefined\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n :aria-required=\"props.required || undefined\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n @change=\"onPlainChange\"\n />\n\n <!-- External file display (when showFileNames is true and not plain) -->\n <div v-if=\"showExternalDisplay\" class=\"b-form-file-display mt-2\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <div v-if=\"hasFiles\" class=\"small text-muted\">\n {{ formattedFileNames }}\n </div>\n <div v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"small text-muted\">\n <slot name=\"placeholder\">\n {{ props.placeholder }}\n </slot>\n </div>\n </slot>\n </div>\n\n <!-- ARIA live region for screen reader announcements -->\n <div v-if=\"!props.plain\" class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ ariaLiveMessage }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {useDropZone, useFileDialog} from '@vueuse/core'\nimport {computed, nextTick, onMounted, ref, type Ref, useAttrs, useTemplateRef, watch} from 'vue'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport {useStateClass} from '../../composables/useStateClass'\nimport {isEmptySlot} from '../../utils/dom'\nimport type {BFormFileProps, BFormFileSlots} from '../../types'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst _props = withDefaults(defineProps<Omit<BFormFileProps, 'modelValue'>>(), {\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n accept: '',\n autofocus: false,\n browseText: undefined,\n capture: undefined,\n directory: false,\n disabled: false,\n dropPlaceholder: undefined,\n fileNameFormatter: undefined,\n ariaLiveFormatter: undefined,\n form: undefined,\n id: undefined,\n label: '',\n labelClass: undefined,\n multiple: false,\n name: undefined,\n noButton: false,\n noDrop: false,\n plain: false,\n placeholder: 'No file chosen',\n required: false,\n showFileNames: false,\n size: undefined,\n state: null,\n})\nconst props = useDefaults(_props, 'BFormFile')\nconst slots = defineSlots<BFormFileSlots>()\n\nconst emit = defineEmits<{\n change: [value: Event]\n}>()\n\nconst modelValue = defineModel<Exclude<BFormFileProps['modelValue'], undefined>>({\n default: null,\n})\n\nconst attrs = useAttrs()\n\nconst processedAttrs = computed(() => {\n // In plain mode, pass all attributes to the input element\n if (props.plain) {\n return {\n rootAttrs: {},\n dropZoneAttrs: {},\n inputAttrs: attrs,\n }\n }\n // In custom mode, split attributes:\n // - class/style go to root (for layout/positioning)\n // - title goes to drop zone (for tooltip on interactive element)\n // - everything else goes to hidden input (for form functionality)\n const {class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs} = attrs\n const rootAttrs: Record<string, unknown> = {}\n const dropZoneAttrs: Record<string, unknown> = {}\n if (rootClass !== undefined) rootAttrs.class = rootClass\n if (rootStyle !== undefined) rootAttrs.style = rootStyle\n if (dropZoneTitle !== undefined) dropZoneAttrs.title = dropZoneTitle\n return {\n rootAttrs,\n dropZoneAttrs,\n inputAttrs,\n }\n})\n\nconst computedId = useId(() => props.id)\nconst stateClass = useStateClass(() => props.state)\n\n// Refs\nconst rootRef = useTemplateRef('rootRef')\nconst dropZoneRef = useTemplateRef('dropZoneRef')\nconst browseButtonRef = useTemplateRef('browseButtonRef')\nconst plainInputRef = useTemplateRef<HTMLInputElement>('plainInputRef')\nconst customInputRef = useTemplateRef<HTMLInputElement>('customInputRef')\n\n// Computed accept for file type validation\nconst computedAccept = computed(() =>\n typeof props.accept === 'string' ? props.accept : props.accept.join(',')\n)\n\n// VueUse file dialog (uses our hidden input element)\nconst {\n open,\n reset: resetDialog,\n onChange: onDialogChange,\n} = useFileDialog({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n input: customInputRef as unknown as Ref<HTMLInputElement>,\n})\n\n// VueUse drop zone (replaces manual drag/drop)\n// Note: We don't pass dataTypes because the accept attribute handles validation\n// and there is no reliable way to get MIME types from in all browsers\n// https://github.com/vueuse/vueuse/issues/4523\nconst {isOverDropZone} = useDropZone(dropZoneRef, {\n onDrop: (files) => {\n if (files && !props.noDrop) {\n handleFiles(files)\n }\n },\n multiple: props.multiple || props.directory,\n})\n\n// Computed properties\nconst hasLabelSlot = computed(() => !isEmptySlot(slots.label))\nconst hasPlaceholderSlot = computed(() => !isEmptySlot(slots.placeholder))\n\nconst computedClasses = computed(() => [\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\nconst computedPlainClasses = computed(() => [\n 'form-control',\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\n// Selected files (from dialog or managed state)\nconst internalFiles = ref<readonly File[]>([])\n\nconst selectedFiles = computed<readonly File[]>(() => internalFiles.value)\n\nconst hasFiles = computed(() => selectedFiles.value.length > 0)\n\nconst fileNames = computed(() => selectedFiles.value.map((file) => file.name))\n\nconst formattedFileNames = computed(() => {\n if (!hasFiles.value) return ''\n if (props.fileNameFormatter) {\n return props.fileNameFormatter(selectedFiles.value)\n }\n const names = fileNames.value\n if (names.length === 1) return names[0]\n return `${names.length} files selected`\n})\n\nconst showExternalDisplay = computed(\n () => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)\n)\n\n// ARIA live region message for accessibility\nconst ariaLiveMessage = computed(() => {\n if (!hasFiles.value) return ''\n if (props.ariaLiveFormatter) {\n return props.ariaLiveFormatter(selectedFiles.value)\n }\n const count = selectedFiles.value.length\n if (count === 1) {\n return `File selected: ${selectedFiles.value[0]?.name}`\n }\n return `${count} files selected`\n})\n\nconst effectiveBrowseText = computed(() => props.browseText ?? 'Browse')\nconst effectiveDropPlaceholder = computed(() => props.dropPlaceholder ?? 'Drop files here...')\n\n// Validate file against accept criteria\nconst isFileAccepted = (file: File): boolean => {\n if (!computedAccept.value) return true\n\n const acceptTypes = computedAccept.value.split(',').map((type) => type.trim())\n\n return acceptTypes.some((acceptType) => {\n // Extension match (e.g., .pdf)\n if (acceptType.startsWith('.')) {\n return file.name.toLowerCase().endsWith(acceptType.toLowerCase())\n }\n // Exact MIME type match (e.g., image/png)\n if (!acceptType.includes('*')) {\n return file.type === acceptType\n }\n // Wildcard MIME type match (e.g., image/* or */*)\n const slashIndex = acceptType.indexOf('/')\n if (slashIndex === -1) {\n // Malformed wildcard pattern (no '/'): do not match anything\n return false\n }\n const category = acceptType.slice(0, slashIndex)\n // */* should match any MIME type\n if (category === '*') {\n return true\n }\n return file.type.startsWith(`${category}/`)\n })\n}\n\n// File handling\nconst handleFiles = (files: File[] | FileList, nativeEvent?: Event) => {\n let fileArray: File[] = []\n\n if (nativeEvent) {\n // Plain mode: read from the event target (browser already filtered via accept)\n const input = nativeEvent.target as HTMLInputElement\n fileArray = input.files ? Array.from(input.files) : []\n } else {\n // Custom mode (drag & drop or file dialog): manually filter and set on hidden input\n fileArray = Array.from(files).filter((file) => isFileAccepted(file))\n if (customInputRef.value && typeof DataTransfer !== 'undefined') {\n try {\n const dataTransfer = new DataTransfer()\n fileArray.forEach((file) => dataTransfer.items.add(file))\n customInputRef.value.files = dataTransfer.files\n } catch {\n // In environments where DataTransfer is not fully supported, skip syncing files on the input\n }\n }\n }\n\n // Update internal state\n internalFiles.value = fileArray\n\n // Update model value\n if (fileArray.length === 0) {\n modelValue.value = null\n } else if (props.directory || props.multiple) {\n modelValue.value = fileArray\n } else {\n const [firstFile] = fileArray\n if (firstFile) {\n modelValue.value = firstFile\n }\n }\n\n // Emit change event in nextTick to ensure DOM updates\n // In plain mode: forward the native event (has target.files)\n // In custom mode: create CustomEvent with files in detail\n nextTick(() => {\n if (nativeEvent) {\n // Plain mode: forward native event\n emit('change', nativeEvent)\n } else {\n // Custom mode: create CustomEvent with files\n const changeEvent = new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: {\n files: fileArray,\n target: {files: fileArray},\n },\n })\n // Also attach files directly for easier access\n Object.defineProperty(changeEvent, 'files', {\n value: fileArray,\n enumerable: true,\n })\n emit('change', changeEvent)\n }\n })\n}\n\n// Open file dialog\nconst openFileDialog = () => {\n if (!props.disabled) {\n open({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n })\n }\n}\n\n// Handle click on control wrapper (make entire control clickable like Bootstrap v5)\nconst handleControlClick = () => {\n // Don't trigger if clicking the button itself (button has its own handler with .stop)\n // Don't trigger if disabled\n if (!props.disabled) {\n openFileDialog()\n }\n}\n\n// Plain mode change handler\nconst onPlainChange = (e: Event) => {\n const input = e.target as HTMLInputElement\n if (input.files) {\n handleFiles(input.files, e) // Pass native event\n }\n}\n\n// Watch dialog files from useFileDialog\nonDialogChange((files) => {\n if (files) {\n handleFiles(files)\n }\n})\n\n// Reset method\nconst reset = () => {\n internalFiles.value = []\n modelValue.value = null\n resetDialog() // This resets the hidden input in custom mode\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n}\n\n// Focus management\nconst focus = () => {\n if (props.plain) {\n plainInputRef.value?.focus()\n } else {\n browseButtonRef.value?.focus()\n }\n}\n\nconst blur = () => {\n if (props.plain) {\n plainInputRef.value?.blur()\n } else {\n browseButtonRef.value?.blur()\n }\n}\n\n// Autofocus support - initial focus on mount\nonMounted(() => {\n if (props.autofocus) {\n nextTick(() => {\n focus()\n })\n }\n})\n\n// Autofocus support - runtime prop changes\nwatch(\n () => props.autofocus,\n (autofocus) => {\n if (autofocus) {\n focus()\n }\n }\n)\n\n// Watch modelValue changes from parent\nwatch(modelValue, (newValue) => {\n if (newValue === null) {\n internalFiles.value = []\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n } else if (Array.isArray(newValue)) {\n internalFiles.value = newValue as readonly File[]\n } else {\n internalFiles.value = [newValue] as readonly File[]\n }\n})\n\ndefineExpose({\n blur,\n element: computed(() => (props.plain ? plainInputRef.value : browseButtonRef.value)),\n focus,\n reset,\n})\n</script>\n","<template>\n <div ref=\"rootRef\" v-bind=\"processedAttrs.rootAttrs\" class=\"b-form-file-root\">\n <!-- Optional label -->\n <label\n v-if=\"hasLabelSlot || props.label\"\n class=\"form-label\"\n :class=\"props.labelClass\"\n :for=\"computedId\"\n >\n <slot name=\"label\">\n {{ props.label }}\n </slot>\n </label>\n\n <!-- Drop zone wrapper -->\n <div\n v-if=\"!props.plain\"\n ref=\"dropZoneRef\"\n v-bind=\"processedAttrs.dropZoneAttrs\"\n class=\"b-form-file-wrapper\"\n :class=\"{\n 'b-form-file-dragging': isOverDropZone && !props.noDrop,\n 'b-form-file-has-files': hasFiles,\n }\"\n >\n <!-- Custom file control (mimics Bootstrap native input) -->\n <div\n class=\"b-form-file-control\"\n :class=\"computedClasses\"\n :aria-disabled=\"props.disabled\"\n @click=\"handleControlClick\"\n >\n <!-- Custom browse button (now on LEFT to match Bootstrap v5) -->\n <button\n v-if=\"!props.noButton\"\n :id=\"computedId\"\n ref=\"browseButtonRef\"\n type=\"button\"\n class=\"b-form-file-button\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n @click.stop=\"openFileDialog\"\n >\n {{ effectiveBrowseText }}\n </button>\n\n <!-- File name display -->\n <div class=\"b-form-file-text\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <span v-if=\"hasFiles\">{{ formattedFileNames }}</span>\n <span v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"text-muted\">\n <slot name=\"placeholder\">{{ props.placeholder }}</slot>\n </span>\n </slot>\n </div>\n </div>\n\n <!-- Drag overlay (only shown when dragging) -->\n <div v-if=\"isOverDropZone && !props.noDrop\" class=\"b-form-file-drag-overlay\">\n <slot name=\"drop-placeholder\">\n <div class=\"b-form-file-drag-text\">\n {{ effectiveDropPlaceholder }}\n </div>\n </slot>\n </div>\n\n <!-- Hidden input for form submission (positioned behind UI with z-index) -->\n <input\n ref=\"customInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :name=\"props.name\"\n :form=\"props.form\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :required=\"props.required\"\n :accept=\"computedAccept || undefined\"\n :capture=\"props.capture\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n style=\"\n position: absolute;\n z-index: -5;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n \"\n />\n </div>\n\n <!-- Plain mode - simple native input -->\n <input\n v-else\n :id=\"computedId\"\n ref=\"plainInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :class=\"computedPlainClasses\"\n :form=\"props.form\"\n :name=\"props.name\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :capture=\"props.capture\"\n :accept=\"computedAccept || undefined\"\n :required=\"props.required || undefined\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n :aria-required=\"props.required || undefined\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n @change=\"onPlainChange\"\n />\n\n <!-- External file display (when showFileNames is true and not plain) -->\n <div v-if=\"showExternalDisplay\" class=\"b-form-file-display mt-2\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <div v-if=\"hasFiles\" class=\"small text-muted\">\n {{ formattedFileNames }}\n </div>\n <div v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"small text-muted\">\n <slot name=\"placeholder\">\n {{ props.placeholder }}\n </slot>\n </div>\n </slot>\n </div>\n\n <!-- ARIA live region for screen reader announcements -->\n <div v-if=\"!props.plain\" class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ ariaLiveMessage }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {useDropZone, useFileDialog} from '@vueuse/core'\nimport {computed, nextTick, onMounted, ref, type Ref, useAttrs, useTemplateRef, watch} from 'vue'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport {useStateClass} from '../../composables/useStateClass'\nimport {isEmptySlot} from '../../utils/dom'\nimport type {BFormFileProps, BFormFileSlots} from '../../types'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst _props = withDefaults(defineProps<Omit<BFormFileProps, 'modelValue'>>(), {\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n accept: '',\n autofocus: false,\n browseText: undefined,\n capture: undefined,\n directory: false,\n disabled: false,\n dropPlaceholder: undefined,\n fileNameFormatter: undefined,\n ariaLiveFormatter: undefined,\n form: undefined,\n id: undefined,\n label: '',\n labelClass: undefined,\n multiple: false,\n name: undefined,\n noButton: false,\n noDrop: false,\n plain: false,\n placeholder: 'No file chosen',\n required: false,\n showFileNames: false,\n size: undefined,\n state: null,\n})\nconst props = useDefaults(_props, 'BFormFile')\nconst slots = defineSlots<BFormFileSlots>()\n\nconst emit = defineEmits<{\n change: [value: Event]\n}>()\n\nconst modelValue = defineModel<Exclude<BFormFileProps['modelValue'], undefined>>({\n default: null,\n})\n\nconst attrs = useAttrs()\n\nconst processedAttrs = computed(() => {\n // In plain mode, pass all attributes to the input element\n if (props.plain) {\n return {\n rootAttrs: {},\n dropZoneAttrs: {},\n inputAttrs: attrs,\n }\n }\n // In custom mode, split attributes:\n // - class/style go to root (for layout/positioning)\n // - title goes to drop zone (for tooltip on interactive element)\n // - everything else goes to hidden input (for form functionality)\n const {class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs} = attrs\n const rootAttrs: Record<string, unknown> = {}\n const dropZoneAttrs: Record<string, unknown> = {}\n if (rootClass !== undefined) rootAttrs.class = rootClass\n if (rootStyle !== undefined) rootAttrs.style = rootStyle\n if (dropZoneTitle !== undefined) dropZoneAttrs.title = dropZoneTitle\n return {\n rootAttrs,\n dropZoneAttrs,\n inputAttrs,\n }\n})\n\nconst computedId = useId(() => props.id)\nconst stateClass = useStateClass(() => props.state)\n\n// Refs\nconst rootRef = useTemplateRef('rootRef')\nconst dropZoneRef = useTemplateRef('dropZoneRef')\nconst browseButtonRef = useTemplateRef('browseButtonRef')\nconst plainInputRef = useTemplateRef<HTMLInputElement>('plainInputRef')\nconst customInputRef = useTemplateRef<HTMLInputElement>('customInputRef')\n\n// Computed accept for file type validation\nconst computedAccept = computed(() =>\n typeof props.accept === 'string' ? props.accept : props.accept.join(',')\n)\n\n// VueUse file dialog (uses our hidden input element)\nconst {\n open,\n reset: resetDialog,\n onChange: onDialogChange,\n} = useFileDialog({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n input: customInputRef as unknown as Ref<HTMLInputElement>,\n})\n\n// VueUse drop zone (replaces manual drag/drop)\n// Note: We don't pass dataTypes because the accept attribute handles validation\n// and there is no reliable way to get MIME types from in all browsers\n// https://github.com/vueuse/vueuse/issues/4523\nconst {isOverDropZone} = useDropZone(dropZoneRef, {\n onDrop: (files) => {\n if (files && !props.noDrop) {\n handleFiles(files)\n }\n },\n multiple: props.multiple || props.directory,\n})\n\n// Computed properties\nconst hasLabelSlot = computed(() => !isEmptySlot(slots.label))\nconst hasPlaceholderSlot = computed(() => !isEmptySlot(slots.placeholder))\n\nconst computedClasses = computed(() => [\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\nconst computedPlainClasses = computed(() => [\n 'form-control',\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\n// Selected files (from dialog or managed state)\nconst internalFiles = ref<readonly File[]>([])\n\nconst selectedFiles = computed<readonly File[]>(() => internalFiles.value)\n\nconst hasFiles = computed(() => selectedFiles.value.length > 0)\n\nconst fileNames = computed(() => selectedFiles.value.map((file) => file.name))\n\nconst formattedFileNames = computed(() => {\n if (!hasFiles.value) return ''\n if (props.fileNameFormatter) {\n return props.fileNameFormatter(selectedFiles.value)\n }\n const names = fileNames.value\n if (names.length === 1) return names[0]\n return `${names.length} files selected`\n})\n\nconst showExternalDisplay = computed(\n () => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)\n)\n\n// ARIA live region message for accessibility\nconst ariaLiveMessage = computed(() => {\n if (!hasFiles.value) return ''\n if (props.ariaLiveFormatter) {\n return props.ariaLiveFormatter(selectedFiles.value)\n }\n const count = selectedFiles.value.length\n if (count === 1) {\n return `File selected: ${selectedFiles.value[0]?.name}`\n }\n return `${count} files selected`\n})\n\nconst effectiveBrowseText = computed(() => props.browseText ?? 'Browse')\nconst effectiveDropPlaceholder = computed(() => props.dropPlaceholder ?? 'Drop files here...')\n\n// Validate file against accept criteria\nconst isFileAccepted = (file: File): boolean => {\n if (!computedAccept.value) return true\n\n const acceptTypes = computedAccept.value.split(',').map((type) => type.trim())\n\n return acceptTypes.some((acceptType) => {\n // Extension match (e.g., .pdf)\n if (acceptType.startsWith('.')) {\n return file.name.toLowerCase().endsWith(acceptType.toLowerCase())\n }\n // Exact MIME type match (e.g., image/png)\n if (!acceptType.includes('*')) {\n return file.type === acceptType\n }\n // Wildcard MIME type match (e.g., image/* or */*)\n const slashIndex = acceptType.indexOf('/')\n if (slashIndex === -1) {\n // Malformed wildcard pattern (no '/'): do not match anything\n return false\n }\n const category = acceptType.slice(0, slashIndex)\n // */* should match any MIME type\n if (category === '*') {\n return true\n }\n return file.type.startsWith(`${category}/`)\n })\n}\n\n// File handling\nconst handleFiles = (files: File[] | FileList, nativeEvent?: Event) => {\n let fileArray: File[] = []\n\n if (nativeEvent) {\n // Plain mode: read from the event target (browser already filtered via accept)\n const input = nativeEvent.target as HTMLInputElement\n fileArray = input.files ? Array.from(input.files) : []\n } else {\n // Custom mode (drag & drop or file dialog): manually filter and set on hidden input\n fileArray = Array.from(files).filter((file) => isFileAccepted(file))\n if (customInputRef.value && typeof DataTransfer !== 'undefined') {\n try {\n const dataTransfer = new DataTransfer()\n fileArray.forEach((file) => dataTransfer.items.add(file))\n customInputRef.value.files = dataTransfer.files\n } catch {\n // In environments where DataTransfer is not fully supported, skip syncing files on the input\n }\n }\n }\n\n // Update internal state\n internalFiles.value = fileArray\n\n // Update model value\n if (fileArray.length === 0) {\n modelValue.value = null\n } else if (props.directory || props.multiple) {\n modelValue.value = fileArray\n } else {\n const [firstFile] = fileArray\n if (firstFile) {\n modelValue.value = firstFile\n }\n }\n\n // Emit change event in nextTick to ensure DOM updates\n // In plain mode: forward the native event (has target.files)\n // In custom mode: create CustomEvent with files in detail\n nextTick(() => {\n if (nativeEvent) {\n // Plain mode: forward native event\n emit('change', nativeEvent)\n } else {\n // Custom mode: create CustomEvent with files\n const changeEvent = new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: {\n files: fileArray,\n target: {files: fileArray},\n },\n })\n // Also attach files directly for easier access\n Object.defineProperty(changeEvent, 'files', {\n value: fileArray,\n enumerable: true,\n })\n emit('change', changeEvent)\n }\n })\n}\n\n// Open file dialog\nconst openFileDialog = () => {\n if (!props.disabled) {\n open({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n })\n }\n}\n\n// Handle click on control wrapper (make entire control clickable like Bootstrap v5)\nconst handleControlClick = () => {\n // Don't trigger if clicking the button itself (button has its own handler with .stop)\n // Don't trigger if disabled\n if (!props.disabled) {\n openFileDialog()\n }\n}\n\n// Plain mode change handler\nconst onPlainChange = (e: Event) => {\n const input = e.target as HTMLInputElement\n if (input.files) {\n handleFiles(input.files, e) // Pass native event\n }\n}\n\n// Watch dialog files from useFileDialog\nonDialogChange((files) => {\n if (files) {\n handleFiles(files)\n }\n})\n\n// Reset method\nconst reset = () => {\n internalFiles.value = []\n modelValue.value = null\n resetDialog() // This resets the hidden input in custom mode\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n}\n\n// Focus management\nconst focus = () => {\n if (props.plain) {\n plainInputRef.value?.focus()\n } else {\n browseButtonRef.value?.focus()\n }\n}\n\nconst blur = () => {\n if (props.plain) {\n plainInputRef.value?.blur()\n } else {\n browseButtonRef.value?.blur()\n }\n}\n\n// Autofocus support - initial focus on mount\nonMounted(() => {\n if (props.autofocus) {\n nextTick(() => {\n focus()\n })\n }\n})\n\n// Autofocus support - runtime prop changes\nwatch(\n () => props.autofocus,\n (autofocus) => {\n if (autofocus) {\n focus()\n }\n }\n)\n\n// Watch modelValue changes from parent\nwatch(modelValue, (newValue) => {\n if (newValue === null) {\n internalFiles.value = []\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n } else if (Array.isArray(newValue)) {\n internalFiles.value = newValue as readonly File[]\n } else {\n internalFiles.value = [newValue] as readonly File[]\n }\n})\n\ndefineExpose({\n blur,\n element: computed(() => (props.plain ? plainInputRef.value : browseButtonRef.value)),\n focus,\n reset,\n})\n</script>\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require("./chunk-CoQrYLCe.js");
|
|
2
2
|
const require_dist = require("./dist-DiXKLh_W.js");
|
|
3
3
|
const require_dom = require("./dom-Bs6DzM72.js");
|
|
4
|
-
const require_useDefaults = require("./useDefaults-
|
|
5
|
-
const require_useId = require("./useId-
|
|
4
|
+
const require_useDefaults = require("./useDefaults-C0CYry78.js");
|
|
5
|
+
const require_useId = require("./useId-BkAY2oh6.js");
|
|
6
6
|
const require_useStateClass = require("./useStateClass-CXK3nCg9.js");
|
|
7
7
|
let vue = require("vue");
|
|
8
8
|
//#region src/components/BFormFile/BFormFile.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -77,6 +77,10 @@ var BFormFile_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
77
77
|
props: /* @__PURE__ */ (0, vue.mergeModels)({
|
|
78
78
|
ariaLabel: { default: void 0 },
|
|
79
79
|
ariaLabelledby: { default: void 0 },
|
|
80
|
+
ariaLiveFormatter: {
|
|
81
|
+
type: Function,
|
|
82
|
+
default: void 0
|
|
83
|
+
},
|
|
80
84
|
accept: { default: "" },
|
|
81
85
|
autofocus: {
|
|
82
86
|
type: Boolean,
|
|
@@ -203,6 +207,7 @@ var BFormFile_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
203
207
|
const showExternalDisplay = (0, vue.computed)(() => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder));
|
|
204
208
|
const ariaLiveMessage = (0, vue.computed)(() => {
|
|
205
209
|
if (!hasFiles.value) return "";
|
|
210
|
+
if (props.ariaLiveFormatter) return props.ariaLiveFormatter(selectedFiles.value);
|
|
206
211
|
const count = selectedFiles.value.length;
|
|
207
212
|
if (count === 1) return `File selected: ${selectedFiles.value[0]?.name}`;
|
|
208
213
|
return `${count} files selected`;
|
|
@@ -415,4 +420,4 @@ Object.defineProperty(exports, "BFormFile_default", {
|
|
|
415
420
|
}
|
|
416
421
|
});
|
|
417
422
|
|
|
418
|
-
//# sourceMappingURL=BFormFile-
|
|
423
|
+
//# sourceMappingURL=BFormFile-MISLntyJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BFormFile-MISLntyJ.js","names":[],"sources":["../src/components/BFormFile/BFormFile.vue","../src/components/BFormFile/BFormFile.vue"],"sourcesContent":["<template>\n <div ref=\"rootRef\" v-bind=\"processedAttrs.rootAttrs\" class=\"b-form-file-root\">\n <!-- Optional label -->\n <label\n v-if=\"hasLabelSlot || props.label\"\n class=\"form-label\"\n :class=\"props.labelClass\"\n :for=\"computedId\"\n >\n <slot name=\"label\">\n {{ props.label }}\n </slot>\n </label>\n\n <!-- Drop zone wrapper -->\n <div\n v-if=\"!props.plain\"\n ref=\"dropZoneRef\"\n v-bind=\"processedAttrs.dropZoneAttrs\"\n class=\"b-form-file-wrapper\"\n :class=\"{\n 'b-form-file-dragging': isOverDropZone && !props.noDrop,\n 'b-form-file-has-files': hasFiles,\n }\"\n >\n <!-- Custom file control (mimics Bootstrap native input) -->\n <div\n class=\"b-form-file-control\"\n :class=\"computedClasses\"\n :aria-disabled=\"props.disabled\"\n @click=\"handleControlClick\"\n >\n <!-- Custom browse button (now on LEFT to match Bootstrap v5) -->\n <button\n v-if=\"!props.noButton\"\n :id=\"computedId\"\n ref=\"browseButtonRef\"\n type=\"button\"\n class=\"b-form-file-button\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n @click.stop=\"openFileDialog\"\n >\n {{ effectiveBrowseText }}\n </button>\n\n <!-- File name display -->\n <div class=\"b-form-file-text\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <span v-if=\"hasFiles\">{{ formattedFileNames }}</span>\n <span v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"text-muted\">\n <slot name=\"placeholder\">{{ props.placeholder }}</slot>\n </span>\n </slot>\n </div>\n </div>\n\n <!-- Drag overlay (only shown when dragging) -->\n <div v-if=\"isOverDropZone && !props.noDrop\" class=\"b-form-file-drag-overlay\">\n <slot name=\"drop-placeholder\">\n <div class=\"b-form-file-drag-text\">\n {{ effectiveDropPlaceholder }}\n </div>\n </slot>\n </div>\n\n <!-- Hidden input for form submission (positioned behind UI with z-index) -->\n <input\n ref=\"customInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :name=\"props.name\"\n :form=\"props.form\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :required=\"props.required\"\n :accept=\"computedAccept || undefined\"\n :capture=\"props.capture\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n style=\"\n position: absolute;\n z-index: -5;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n \"\n />\n </div>\n\n <!-- Plain mode - simple native input -->\n <input\n v-else\n :id=\"computedId\"\n ref=\"plainInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :class=\"computedPlainClasses\"\n :form=\"props.form\"\n :name=\"props.name\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :capture=\"props.capture\"\n :accept=\"computedAccept || undefined\"\n :required=\"props.required || undefined\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n :aria-required=\"props.required || undefined\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n @change=\"onPlainChange\"\n />\n\n <!-- External file display (when showFileNames is true and not plain) -->\n <div v-if=\"showExternalDisplay\" class=\"b-form-file-display mt-2\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <div v-if=\"hasFiles\" class=\"small text-muted\">\n {{ formattedFileNames }}\n </div>\n <div v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"small text-muted\">\n <slot name=\"placeholder\">\n {{ props.placeholder }}\n </slot>\n </div>\n </slot>\n </div>\n\n <!-- ARIA live region for screen reader announcements -->\n <div v-if=\"!props.plain\" class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ ariaLiveMessage }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {useDropZone, useFileDialog} from '@vueuse/core'\nimport {computed, nextTick, onMounted, ref, type Ref, useAttrs, useTemplateRef, watch} from 'vue'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport {useStateClass} from '../../composables/useStateClass'\nimport {isEmptySlot} from '../../utils/dom'\nimport type {BFormFileProps, BFormFileSlots} from '../../types'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst _props = withDefaults(defineProps<Omit<BFormFileProps, 'modelValue'>>(), {\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n accept: '',\n autofocus: false,\n browseText: undefined,\n capture: undefined,\n directory: false,\n disabled: false,\n dropPlaceholder: undefined,\n fileNameFormatter: undefined,\n ariaLiveFormatter: undefined,\n form: undefined,\n id: undefined,\n label: '',\n labelClass: undefined,\n multiple: false,\n name: undefined,\n noButton: false,\n noDrop: false,\n plain: false,\n placeholder: 'No file chosen',\n required: false,\n showFileNames: false,\n size: undefined,\n state: null,\n})\nconst props = useDefaults(_props, 'BFormFile')\nconst slots = defineSlots<BFormFileSlots>()\n\nconst emit = defineEmits<{\n change: [value: Event]\n}>()\n\nconst modelValue = defineModel<Exclude<BFormFileProps['modelValue'], undefined>>({\n default: null,\n})\n\nconst attrs = useAttrs()\n\nconst processedAttrs = computed(() => {\n // In plain mode, pass all attributes to the input element\n if (props.plain) {\n return {\n rootAttrs: {},\n dropZoneAttrs: {},\n inputAttrs: attrs,\n }\n }\n // In custom mode, split attributes:\n // - class/style go to root (for layout/positioning)\n // - title goes to drop zone (for tooltip on interactive element)\n // - everything else goes to hidden input (for form functionality)\n const {class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs} = attrs\n const rootAttrs: Record<string, unknown> = {}\n const dropZoneAttrs: Record<string, unknown> = {}\n if (rootClass !== undefined) rootAttrs.class = rootClass\n if (rootStyle !== undefined) rootAttrs.style = rootStyle\n if (dropZoneTitle !== undefined) dropZoneAttrs.title = dropZoneTitle\n return {\n rootAttrs,\n dropZoneAttrs,\n inputAttrs,\n }\n})\n\nconst computedId = useId(() => props.id)\nconst stateClass = useStateClass(() => props.state)\n\n// Refs\nconst rootRef = useTemplateRef('rootRef')\nconst dropZoneRef = useTemplateRef('dropZoneRef')\nconst browseButtonRef = useTemplateRef('browseButtonRef')\nconst plainInputRef = useTemplateRef<HTMLInputElement>('plainInputRef')\nconst customInputRef = useTemplateRef<HTMLInputElement>('customInputRef')\n\n// Computed accept for file type validation\nconst computedAccept = computed(() =>\n typeof props.accept === 'string' ? props.accept : props.accept.join(',')\n)\n\n// VueUse file dialog (uses our hidden input element)\nconst {\n open,\n reset: resetDialog,\n onChange: onDialogChange,\n} = useFileDialog({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n input: customInputRef as unknown as Ref<HTMLInputElement>,\n})\n\n// VueUse drop zone (replaces manual drag/drop)\n// Note: We don't pass dataTypes because the accept attribute handles validation\n// and there is no reliable way to get MIME types from in all browsers\n// https://github.com/vueuse/vueuse/issues/4523\nconst {isOverDropZone} = useDropZone(dropZoneRef, {\n onDrop: (files) => {\n if (files && !props.noDrop) {\n handleFiles(files)\n }\n },\n multiple: props.multiple || props.directory,\n})\n\n// Computed properties\nconst hasLabelSlot = computed(() => !isEmptySlot(slots.label))\nconst hasPlaceholderSlot = computed(() => !isEmptySlot(slots.placeholder))\n\nconst computedClasses = computed(() => [\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\nconst computedPlainClasses = computed(() => [\n 'form-control',\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\n// Selected files (from dialog or managed state)\nconst internalFiles = ref<readonly File[]>([])\n\nconst selectedFiles = computed<readonly File[]>(() => internalFiles.value)\n\nconst hasFiles = computed(() => selectedFiles.value.length > 0)\n\nconst fileNames = computed(() => selectedFiles.value.map((file) => file.name))\n\nconst formattedFileNames = computed(() => {\n if (!hasFiles.value) return ''\n if (props.fileNameFormatter) {\n return props.fileNameFormatter(selectedFiles.value)\n }\n const names = fileNames.value\n if (names.length === 1) return names[0]\n return `${names.length} files selected`\n})\n\nconst showExternalDisplay = computed(\n () => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)\n)\n\n// ARIA live region message for accessibility\nconst ariaLiveMessage = computed(() => {\n if (!hasFiles.value) return ''\n if (props.ariaLiveFormatter) {\n return props.ariaLiveFormatter(selectedFiles.value)\n }\n const count = selectedFiles.value.length\n if (count === 1) {\n return `File selected: ${selectedFiles.value[0]?.name}`\n }\n return `${count} files selected`\n})\n\nconst effectiveBrowseText = computed(() => props.browseText ?? 'Browse')\nconst effectiveDropPlaceholder = computed(() => props.dropPlaceholder ?? 'Drop files here...')\n\n// Validate file against accept criteria\nconst isFileAccepted = (file: File): boolean => {\n if (!computedAccept.value) return true\n\n const acceptTypes = computedAccept.value.split(',').map((type) => type.trim())\n\n return acceptTypes.some((acceptType) => {\n // Extension match (e.g., .pdf)\n if (acceptType.startsWith('.')) {\n return file.name.toLowerCase().endsWith(acceptType.toLowerCase())\n }\n // Exact MIME type match (e.g., image/png)\n if (!acceptType.includes('*')) {\n return file.type === acceptType\n }\n // Wildcard MIME type match (e.g., image/* or */*)\n const slashIndex = acceptType.indexOf('/')\n if (slashIndex === -1) {\n // Malformed wildcard pattern (no '/'): do not match anything\n return false\n }\n const category = acceptType.slice(0, slashIndex)\n // */* should match any MIME type\n if (category === '*') {\n return true\n }\n return file.type.startsWith(`${category}/`)\n })\n}\n\n// File handling\nconst handleFiles = (files: File[] | FileList, nativeEvent?: Event) => {\n let fileArray: File[] = []\n\n if (nativeEvent) {\n // Plain mode: read from the event target (browser already filtered via accept)\n const input = nativeEvent.target as HTMLInputElement\n fileArray = input.files ? Array.from(input.files) : []\n } else {\n // Custom mode (drag & drop or file dialog): manually filter and set on hidden input\n fileArray = Array.from(files).filter((file) => isFileAccepted(file))\n if (customInputRef.value && typeof DataTransfer !== 'undefined') {\n try {\n const dataTransfer = new DataTransfer()\n fileArray.forEach((file) => dataTransfer.items.add(file))\n customInputRef.value.files = dataTransfer.files\n } catch {\n // In environments where DataTransfer is not fully supported, skip syncing files on the input\n }\n }\n }\n\n // Update internal state\n internalFiles.value = fileArray\n\n // Update model value\n if (fileArray.length === 0) {\n modelValue.value = null\n } else if (props.directory || props.multiple) {\n modelValue.value = fileArray\n } else {\n const [firstFile] = fileArray\n if (firstFile) {\n modelValue.value = firstFile\n }\n }\n\n // Emit change event in nextTick to ensure DOM updates\n // In plain mode: forward the native event (has target.files)\n // In custom mode: create CustomEvent with files in detail\n nextTick(() => {\n if (nativeEvent) {\n // Plain mode: forward native event\n emit('change', nativeEvent)\n } else {\n // Custom mode: create CustomEvent with files\n const changeEvent = new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: {\n files: fileArray,\n target: {files: fileArray},\n },\n })\n // Also attach files directly for easier access\n Object.defineProperty(changeEvent, 'files', {\n value: fileArray,\n enumerable: true,\n })\n emit('change', changeEvent)\n }\n })\n}\n\n// Open file dialog\nconst openFileDialog = () => {\n if (!props.disabled) {\n open({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n })\n }\n}\n\n// Handle click on control wrapper (make entire control clickable like Bootstrap v5)\nconst handleControlClick = () => {\n // Don't trigger if clicking the button itself (button has its own handler with .stop)\n // Don't trigger if disabled\n if (!props.disabled) {\n openFileDialog()\n }\n}\n\n// Plain mode change handler\nconst onPlainChange = (e: Event) => {\n const input = e.target as HTMLInputElement\n if (input.files) {\n handleFiles(input.files, e) // Pass native event\n }\n}\n\n// Watch dialog files from useFileDialog\nonDialogChange((files) => {\n if (files) {\n handleFiles(files)\n }\n})\n\n// Reset method\nconst reset = () => {\n internalFiles.value = []\n modelValue.value = null\n resetDialog() // This resets the hidden input in custom mode\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n}\n\n// Focus management\nconst focus = () => {\n if (props.plain) {\n plainInputRef.value?.focus()\n } else {\n browseButtonRef.value?.focus()\n }\n}\n\nconst blur = () => {\n if (props.plain) {\n plainInputRef.value?.blur()\n } else {\n browseButtonRef.value?.blur()\n }\n}\n\n// Autofocus support - initial focus on mount\nonMounted(() => {\n if (props.autofocus) {\n nextTick(() => {\n focus()\n })\n }\n})\n\n// Autofocus support - runtime prop changes\nwatch(\n () => props.autofocus,\n (autofocus) => {\n if (autofocus) {\n focus()\n }\n }\n)\n\n// Watch modelValue changes from parent\nwatch(modelValue, (newValue) => {\n if (newValue === null) {\n internalFiles.value = []\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n } else if (Array.isArray(newValue)) {\n internalFiles.value = newValue as readonly File[]\n } else {\n internalFiles.value = [newValue] as readonly File[]\n }\n})\n\ndefineExpose({\n blur,\n element: computed(() => (props.plain ? plainInputRef.value : browseButtonRef.value)),\n focus,\n reset,\n})\n</script>\n","<template>\n <div ref=\"rootRef\" v-bind=\"processedAttrs.rootAttrs\" class=\"b-form-file-root\">\n <!-- Optional label -->\n <label\n v-if=\"hasLabelSlot || props.label\"\n class=\"form-label\"\n :class=\"props.labelClass\"\n :for=\"computedId\"\n >\n <slot name=\"label\">\n {{ props.label }}\n </slot>\n </label>\n\n <!-- Drop zone wrapper -->\n <div\n v-if=\"!props.plain\"\n ref=\"dropZoneRef\"\n v-bind=\"processedAttrs.dropZoneAttrs\"\n class=\"b-form-file-wrapper\"\n :class=\"{\n 'b-form-file-dragging': isOverDropZone && !props.noDrop,\n 'b-form-file-has-files': hasFiles,\n }\"\n >\n <!-- Custom file control (mimics Bootstrap native input) -->\n <div\n class=\"b-form-file-control\"\n :class=\"computedClasses\"\n :aria-disabled=\"props.disabled\"\n @click=\"handleControlClick\"\n >\n <!-- Custom browse button (now on LEFT to match Bootstrap v5) -->\n <button\n v-if=\"!props.noButton\"\n :id=\"computedId\"\n ref=\"browseButtonRef\"\n type=\"button\"\n class=\"b-form-file-button\"\n :disabled=\"props.disabled\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n @click.stop=\"openFileDialog\"\n >\n {{ effectiveBrowseText }}\n </button>\n\n <!-- File name display -->\n <div class=\"b-form-file-text\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <span v-if=\"hasFiles\">{{ formattedFileNames }}</span>\n <span v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"text-muted\">\n <slot name=\"placeholder\">{{ props.placeholder }}</slot>\n </span>\n </slot>\n </div>\n </div>\n\n <!-- Drag overlay (only shown when dragging) -->\n <div v-if=\"isOverDropZone && !props.noDrop\" class=\"b-form-file-drag-overlay\">\n <slot name=\"drop-placeholder\">\n <div class=\"b-form-file-drag-text\">\n {{ effectiveDropPlaceholder }}\n </div>\n </slot>\n </div>\n\n <!-- Hidden input for form submission (positioned behind UI with z-index) -->\n <input\n ref=\"customInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :name=\"props.name\"\n :form=\"props.form\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :required=\"props.required\"\n :accept=\"computedAccept || undefined\"\n :capture=\"props.capture\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n style=\"\n position: absolute;\n z-index: -5;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n \"\n />\n </div>\n\n <!-- Plain mode - simple native input -->\n <input\n v-else\n :id=\"computedId\"\n ref=\"plainInputRef\"\n v-bind=\"processedAttrs.inputAttrs\"\n type=\"file\"\n :class=\"computedPlainClasses\"\n :form=\"props.form\"\n :name=\"props.name\"\n :multiple=\"props.multiple || props.directory\"\n :disabled=\"props.disabled\"\n :capture=\"props.capture\"\n :accept=\"computedAccept || undefined\"\n :required=\"props.required || undefined\"\n :aria-label=\"props.ariaLabel\"\n :aria-labelledby=\"props.ariaLabelledby\"\n :aria-required=\"props.required || undefined\"\n :directory=\"props.directory || undefined\"\n :webkitdirectory=\"props.directory || undefined\"\n @change=\"onPlainChange\"\n />\n\n <!-- External file display (when showFileNames is true and not plain) -->\n <div v-if=\"showExternalDisplay\" class=\"b-form-file-display mt-2\">\n <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n <div v-if=\"hasFiles\" class=\"small text-muted\">\n {{ formattedFileNames }}\n </div>\n <div v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"small text-muted\">\n <slot name=\"placeholder\">\n {{ props.placeholder }}\n </slot>\n </div>\n </slot>\n </div>\n\n <!-- ARIA live region for screen reader announcements -->\n <div v-if=\"!props.plain\" class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ ariaLiveMessage }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {useDropZone, useFileDialog} from '@vueuse/core'\nimport {computed, nextTick, onMounted, ref, type Ref, useAttrs, useTemplateRef, watch} from 'vue'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport {useStateClass} from '../../composables/useStateClass'\nimport {isEmptySlot} from '../../utils/dom'\nimport type {BFormFileProps, BFormFileSlots} from '../../types'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst _props = withDefaults(defineProps<Omit<BFormFileProps, 'modelValue'>>(), {\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n accept: '',\n autofocus: false,\n browseText: undefined,\n capture: undefined,\n directory: false,\n disabled: false,\n dropPlaceholder: undefined,\n fileNameFormatter: undefined,\n ariaLiveFormatter: undefined,\n form: undefined,\n id: undefined,\n label: '',\n labelClass: undefined,\n multiple: false,\n name: undefined,\n noButton: false,\n noDrop: false,\n plain: false,\n placeholder: 'No file chosen',\n required: false,\n showFileNames: false,\n size: undefined,\n state: null,\n})\nconst props = useDefaults(_props, 'BFormFile')\nconst slots = defineSlots<BFormFileSlots>()\n\nconst emit = defineEmits<{\n change: [value: Event]\n}>()\n\nconst modelValue = defineModel<Exclude<BFormFileProps['modelValue'], undefined>>({\n default: null,\n})\n\nconst attrs = useAttrs()\n\nconst processedAttrs = computed(() => {\n // In plain mode, pass all attributes to the input element\n if (props.plain) {\n return {\n rootAttrs: {},\n dropZoneAttrs: {},\n inputAttrs: attrs,\n }\n }\n // In custom mode, split attributes:\n // - class/style go to root (for layout/positioning)\n // - title goes to drop zone (for tooltip on interactive element)\n // - everything else goes to hidden input (for form functionality)\n const {class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs} = attrs\n const rootAttrs: Record<string, unknown> = {}\n const dropZoneAttrs: Record<string, unknown> = {}\n if (rootClass !== undefined) rootAttrs.class = rootClass\n if (rootStyle !== undefined) rootAttrs.style = rootStyle\n if (dropZoneTitle !== undefined) dropZoneAttrs.title = dropZoneTitle\n return {\n rootAttrs,\n dropZoneAttrs,\n inputAttrs,\n }\n})\n\nconst computedId = useId(() => props.id)\nconst stateClass = useStateClass(() => props.state)\n\n// Refs\nconst rootRef = useTemplateRef('rootRef')\nconst dropZoneRef = useTemplateRef('dropZoneRef')\nconst browseButtonRef = useTemplateRef('browseButtonRef')\nconst plainInputRef = useTemplateRef<HTMLInputElement>('plainInputRef')\nconst customInputRef = useTemplateRef<HTMLInputElement>('customInputRef')\n\n// Computed accept for file type validation\nconst computedAccept = computed(() =>\n typeof props.accept === 'string' ? props.accept : props.accept.join(',')\n)\n\n// VueUse file dialog (uses our hidden input element)\nconst {\n open,\n reset: resetDialog,\n onChange: onDialogChange,\n} = useFileDialog({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n input: customInputRef as unknown as Ref<HTMLInputElement>,\n})\n\n// VueUse drop zone (replaces manual drag/drop)\n// Note: We don't pass dataTypes because the accept attribute handles validation\n// and there is no reliable way to get MIME types from in all browsers\n// https://github.com/vueuse/vueuse/issues/4523\nconst {isOverDropZone} = useDropZone(dropZoneRef, {\n onDrop: (files) => {\n if (files && !props.noDrop) {\n handleFiles(files)\n }\n },\n multiple: props.multiple || props.directory,\n})\n\n// Computed properties\nconst hasLabelSlot = computed(() => !isEmptySlot(slots.label))\nconst hasPlaceholderSlot = computed(() => !isEmptySlot(slots.placeholder))\n\nconst computedClasses = computed(() => [\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\nconst computedPlainClasses = computed(() => [\n 'form-control',\n stateClass.value,\n {\n [`form-control-${props.size}`]: props.size !== undefined,\n },\n])\n\n// Selected files (from dialog or managed state)\nconst internalFiles = ref<readonly File[]>([])\n\nconst selectedFiles = computed<readonly File[]>(() => internalFiles.value)\n\nconst hasFiles = computed(() => selectedFiles.value.length > 0)\n\nconst fileNames = computed(() => selectedFiles.value.map((file) => file.name))\n\nconst formattedFileNames = computed(() => {\n if (!hasFiles.value) return ''\n if (props.fileNameFormatter) {\n return props.fileNameFormatter(selectedFiles.value)\n }\n const names = fileNames.value\n if (names.length === 1) return names[0]\n return `${names.length} files selected`\n})\n\nconst showExternalDisplay = computed(\n () => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)\n)\n\n// ARIA live region message for accessibility\nconst ariaLiveMessage = computed(() => {\n if (!hasFiles.value) return ''\n if (props.ariaLiveFormatter) {\n return props.ariaLiveFormatter(selectedFiles.value)\n }\n const count = selectedFiles.value.length\n if (count === 1) {\n return `File selected: ${selectedFiles.value[0]?.name}`\n }\n return `${count} files selected`\n})\n\nconst effectiveBrowseText = computed(() => props.browseText ?? 'Browse')\nconst effectiveDropPlaceholder = computed(() => props.dropPlaceholder ?? 'Drop files here...')\n\n// Validate file against accept criteria\nconst isFileAccepted = (file: File): boolean => {\n if (!computedAccept.value) return true\n\n const acceptTypes = computedAccept.value.split(',').map((type) => type.trim())\n\n return acceptTypes.some((acceptType) => {\n // Extension match (e.g., .pdf)\n if (acceptType.startsWith('.')) {\n return file.name.toLowerCase().endsWith(acceptType.toLowerCase())\n }\n // Exact MIME type match (e.g., image/png)\n if (!acceptType.includes('*')) {\n return file.type === acceptType\n }\n // Wildcard MIME type match (e.g., image/* or */*)\n const slashIndex = acceptType.indexOf('/')\n if (slashIndex === -1) {\n // Malformed wildcard pattern (no '/'): do not match anything\n return false\n }\n const category = acceptType.slice(0, slashIndex)\n // */* should match any MIME type\n if (category === '*') {\n return true\n }\n return file.type.startsWith(`${category}/`)\n })\n}\n\n// File handling\nconst handleFiles = (files: File[] | FileList, nativeEvent?: Event) => {\n let fileArray: File[] = []\n\n if (nativeEvent) {\n // Plain mode: read from the event target (browser already filtered via accept)\n const input = nativeEvent.target as HTMLInputElement\n fileArray = input.files ? Array.from(input.files) : []\n } else {\n // Custom mode (drag & drop or file dialog): manually filter and set on hidden input\n fileArray = Array.from(files).filter((file) => isFileAccepted(file))\n if (customInputRef.value && typeof DataTransfer !== 'undefined') {\n try {\n const dataTransfer = new DataTransfer()\n fileArray.forEach((file) => dataTransfer.items.add(file))\n customInputRef.value.files = dataTransfer.files\n } catch {\n // In environments where DataTransfer is not fully supported, skip syncing files on the input\n }\n }\n }\n\n // Update internal state\n internalFiles.value = fileArray\n\n // Update model value\n if (fileArray.length === 0) {\n modelValue.value = null\n } else if (props.directory || props.multiple) {\n modelValue.value = fileArray\n } else {\n const [firstFile] = fileArray\n if (firstFile) {\n modelValue.value = firstFile\n }\n }\n\n // Emit change event in nextTick to ensure DOM updates\n // In plain mode: forward the native event (has target.files)\n // In custom mode: create CustomEvent with files in detail\n nextTick(() => {\n if (nativeEvent) {\n // Plain mode: forward native event\n emit('change', nativeEvent)\n } else {\n // Custom mode: create CustomEvent with files\n const changeEvent = new CustomEvent('change', {\n bubbles: true,\n cancelable: false,\n detail: {\n files: fileArray,\n target: {files: fileArray},\n },\n })\n // Also attach files directly for easier access\n Object.defineProperty(changeEvent, 'files', {\n value: fileArray,\n enumerable: true,\n })\n emit('change', changeEvent)\n }\n })\n}\n\n// Open file dialog\nconst openFileDialog = () => {\n if (!props.disabled) {\n open({\n accept: computedAccept.value,\n multiple: props.multiple || props.directory,\n directory: props.directory,\n })\n }\n}\n\n// Handle click on control wrapper (make entire control clickable like Bootstrap v5)\nconst handleControlClick = () => {\n // Don't trigger if clicking the button itself (button has its own handler with .stop)\n // Don't trigger if disabled\n if (!props.disabled) {\n openFileDialog()\n }\n}\n\n// Plain mode change handler\nconst onPlainChange = (e: Event) => {\n const input = e.target as HTMLInputElement\n if (input.files) {\n handleFiles(input.files, e) // Pass native event\n }\n}\n\n// Watch dialog files from useFileDialog\nonDialogChange((files) => {\n if (files) {\n handleFiles(files)\n }\n})\n\n// Reset method\nconst reset = () => {\n internalFiles.value = []\n modelValue.value = null\n resetDialog() // This resets the hidden input in custom mode\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n}\n\n// Focus management\nconst focus = () => {\n if (props.plain) {\n plainInputRef.value?.focus()\n } else {\n browseButtonRef.value?.focus()\n }\n}\n\nconst blur = () => {\n if (props.plain) {\n plainInputRef.value?.blur()\n } else {\n browseButtonRef.value?.blur()\n }\n}\n\n// Autofocus support - initial focus on mount\nonMounted(() => {\n if (props.autofocus) {\n nextTick(() => {\n focus()\n })\n }\n})\n\n// Autofocus support - runtime prop changes\nwatch(\n () => props.autofocus,\n (autofocus) => {\n if (autofocus) {\n focus()\n }\n }\n)\n\n// Watch modelValue changes from parent\nwatch(modelValue, (newValue) => {\n if (newValue === null) {\n internalFiles.value = []\n if (plainInputRef.value) {\n plainInputRef.value.value = ''\n }\n } else if (Array.isArray(newValue)) {\n internalFiles.value = newValue as readonly File[]\n } else {\n internalFiles.value = [newValue] as readonly File[]\n }\n})\n\ndefineExpose({\n blur,\n element: computed(() => (props.plain ? plainInputRef.value : browseButtonRef.value)),\n focus,\n reset,\n})\n</script>\n"],"mappings":"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"}
|