@7pmlabs/design-system 1.0.10 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -6
- package/dist/design-system.css +1 -1
- package/dist/design-system.js +66 -60
- package/dist/design-system100.js +4 -5
- package/dist/design-system100.js.map +1 -1
- package/dist/design-system101.js +53 -506
- package/dist/design-system101.js.map +1 -1
- package/dist/{design-system93.js → design-system102.js} +1 -1
- package/dist/design-system102.js.map +1 -0
- package/dist/design-system103.js +13 -5
- package/dist/design-system103.js.map +1 -1
- package/dist/design-system104.js +109 -7
- package/dist/design-system104.js.map +1 -1
- package/dist/design-system106.js +9 -0
- package/dist/design-system106.js.map +1 -0
- package/dist/design-system107.js +206 -6
- package/dist/design-system107.js.map +1 -1
- package/dist/design-system109.js +9 -0
- package/dist/design-system109.js.map +1 -0
- package/dist/design-system110.js +507 -6
- package/dist/design-system110.js.map +1 -1
- package/dist/design-system112.js +8 -0
- package/dist/design-system112.js.map +1 -0
- package/dist/design-system113.js +7 -5
- package/dist/design-system113.js.map +1 -1
- package/dist/design-system114.js +209 -9
- package/dist/design-system114.js.map +1 -1
- package/dist/design-system116.js +9 -0
- package/dist/design-system116.js.map +1 -0
- package/dist/design-system117.js +224 -6
- package/dist/design-system117.js.map +1 -1
- package/dist/design-system119.js +9 -0
- package/dist/design-system119.js.map +1 -0
- package/dist/design-system12.js.map +1 -1
- package/dist/design-system120.js +163 -5
- package/dist/design-system120.js.map +1 -1
- package/dist/design-system122.js +5 -90
- package/dist/design-system122.js.map +1 -1
- package/dist/design-system123.js +12 -0
- package/dist/design-system123.js.map +1 -0
- package/dist/design-system124.js +274 -5
- package/dist/design-system124.js.map +1 -1
- package/dist/design-system126.js +9 -0
- package/dist/design-system126.js.map +1 -0
- package/dist/design-system127.js +16 -5
- package/dist/design-system127.js.map +1 -1
- package/dist/design-system129.js +8 -0
- package/dist/design-system129.js.map +1 -0
- package/dist/design-system130.js +12 -5
- package/dist/design-system130.js.map +1 -1
- package/dist/design-system131.js +76 -137
- package/dist/design-system131.js.map +1 -1
- package/dist/design-system133.js +1 -1
- package/dist/design-system133.js.map +1 -1
- package/dist/design-system134.js +37 -90
- package/dist/design-system134.js.map +1 -1
- package/dist/design-system136.js +1 -1
- package/dist/design-system136.js.map +1 -1
- package/dist/design-system137.js +226 -20
- package/dist/design-system137.js.map +1 -1
- package/dist/design-system139.js +4 -5
- package/dist/design-system139.js.map +1 -1
- package/dist/design-system140.js +151 -9
- package/dist/design-system140.js.map +1 -1
- package/dist/design-system142.js +3 -2
- package/dist/design-system142.js.map +1 -1
- package/dist/design-system143.js +93 -19
- package/dist/design-system143.js.map +1 -1
- package/dist/design-system145.js +5 -158
- package/dist/design-system145.js.map +1 -1
- package/dist/design-system146.js +12 -0
- package/dist/design-system146.js.map +1 -0
- package/dist/design-system147.js +37 -5
- package/dist/design-system147.js.map +1 -1
- package/dist/design-system148.js +4 -307
- package/dist/design-system148.js.map +1 -1
- package/dist/design-system149.js +24 -0
- package/dist/{design-system144.js.map → design-system149.js.map} +1 -1
- package/dist/design-system150.js +2 -3
- package/dist/design-system150.js.map +1 -1
- package/dist/design-system151.js +131 -213
- package/dist/design-system151.js.map +1 -1
- package/dist/design-system153.js +1 -1
- package/dist/design-system153.js.map +1 -1
- package/dist/design-system154.js +278 -160
- package/dist/design-system154.js.map +1 -1
- package/dist/design-system156.js +1 -1
- package/dist/design-system156.js.map +1 -1
- package/dist/design-system157.js +240 -3
- package/dist/design-system157.js.map +1 -1
- package/dist/design-system159.js +8 -0
- package/dist/design-system159.js.map +1 -0
- package/dist/design-system16.js.map +1 -1
- package/dist/design-system160.js +189 -6
- package/dist/design-system160.js.map +1 -1
- package/dist/design-system162.js +8 -0
- package/dist/design-system162.js.map +1 -0
- package/dist/design-system163.js +3 -6
- package/dist/design-system163.js.map +1 -1
- package/dist/design-system164.js +46 -57
- package/dist/design-system164.js.map +1 -1
- package/dist/design-system166.js +2 -2
- package/dist/design-system166.js.map +1 -1
- package/dist/design-system167.js +44 -170
- package/dist/design-system167.js.map +1 -1
- package/dist/design-system169.js +2 -2
- package/dist/design-system169.js.map +1 -1
- package/dist/design-system170.js +55 -101
- package/dist/design-system170.js.map +1 -1
- package/dist/design-system172.js +5 -4
- package/dist/design-system172.js.map +1 -1
- package/dist/design-system173.js +182 -11
- package/dist/design-system173.js.map +1 -1
- package/dist/design-system175.js +9 -0
- package/dist/design-system175.js.map +1 -0
- package/dist/design-system176.js +115 -6
- package/dist/design-system176.js.map +1 -1
- package/dist/design-system178.js +8 -0
- package/dist/design-system178.js.map +1 -0
- package/dist/design-system179.js +11 -5
- package/dist/design-system179.js.map +1 -1
- package/dist/design-system180.js +444 -70
- package/dist/design-system180.js.map +1 -1
- package/dist/design-system182.js +5 -4
- package/dist/design-system182.js.map +1 -1
- package/dist/design-system183.js +21 -21
- package/dist/design-system183.js.map +1 -1
- package/dist/design-system185.js +1 -1
- package/dist/design-system185.js.map +1 -1
- package/dist/design-system186.js +85 -25
- package/dist/design-system186.js.map +1 -1
- package/dist/design-system188.js +1 -1
- package/dist/design-system188.js.map +1 -1
- package/dist/design-system189.js +7 -5
- package/dist/design-system189.js.map +1 -1
- package/dist/design-system19.js.map +1 -1
- package/dist/design-system191.js +1 -1
- package/dist/design-system191.js.map +1 -1
- package/dist/design-system192.js +20 -23
- package/dist/design-system192.js.map +1 -1
- package/dist/design-system194.js +1 -1
- package/dist/design-system194.js.map +1 -1
- package/dist/design-system195.js +24 -323
- package/dist/design-system195.js.map +1 -1
- package/dist/design-system197.js +1 -1
- package/dist/design-system197.js.map +1 -1
- package/dist/design-system198.js +19 -88
- package/dist/design-system198.js.map +1 -1
- package/dist/design-system200.js +1 -1
- package/dist/design-system200.js.map +1 -1
- package/dist/design-system201.js +330 -17
- package/dist/design-system201.js.map +1 -1
- package/dist/design-system203.js +5 -3
- package/dist/design-system203.js.map +1 -1
- package/dist/design-system204.js +88 -407
- package/dist/design-system204.js.map +1 -1
- package/dist/design-system206.js +1 -1
- package/dist/design-system206.js.map +1 -1
- package/dist/design-system207.js +17 -106
- package/dist/design-system207.js.map +1 -1
- package/dist/{design-system202.js → design-system208.js} +2 -2
- package/dist/{design-system202.js.map → design-system208.js.map} +1 -1
- package/dist/design-system209.js +3 -6
- package/dist/design-system209.js.map +1 -1
- package/dist/design-system210.js +403 -90
- package/dist/design-system210.js.map +1 -1
- package/dist/design-system212.js +4 -5
- package/dist/design-system212.js.map +1 -1
- package/dist/design-system213.js +45 -723
- package/dist/design-system213.js.map +1 -1
- package/dist/design-system215.js +1 -1
- package/dist/design-system215.js.map +1 -1
- package/dist/design-system216.js +88 -11
- package/dist/design-system216.js.map +1 -1
- package/dist/design-system217.js +4 -525
- package/dist/design-system217.js.map +1 -1
- package/dist/design-system218.js +111 -0
- package/dist/design-system218.js.map +1 -0
- package/dist/design-system22.js.map +1 -1
- package/dist/design-system220.js +6 -3
- package/dist/design-system220.js.map +1 -1
- package/dist/design-system221.js +103 -43
- package/dist/design-system221.js.map +1 -1
- package/dist/design-system223.js +6 -283
- package/dist/design-system223.js.map +1 -1
- package/dist/design-system224.js +740 -0
- package/dist/design-system224.js.map +1 -0
- package/dist/design-system226.js +5 -119
- package/dist/design-system226.js.map +1 -1
- package/dist/{design-system60.js → design-system227.js} +6 -8
- package/dist/design-system227.js.map +1 -0
- package/dist/design-system228.js +525 -5
- package/dist/design-system228.js.map +1 -1
- package/dist/{design-system219.js → design-system230.js} +2 -2
- package/dist/{design-system219.js.map → design-system230.js.map} +1 -1
- package/dist/design-system231.js +3 -5
- package/dist/design-system231.js.map +1 -1
- package/dist/design-system232.js +42 -50
- package/dist/design-system232.js.map +1 -1
- package/dist/design-system233.js +1 -1
- package/dist/design-system233.js.map +1 -1
- package/dist/design-system234.js +254 -141
- package/dist/design-system234.js.map +1 -1
- package/dist/design-system236.js +1 -1
- package/dist/design-system236.js.map +1 -1
- package/dist/design-system237.js +119 -7
- package/dist/design-system237.js.map +1 -1
- package/dist/design-system239.js +8 -0
- package/dist/design-system239.js.map +1 -0
- package/dist/design-system240.js +112 -5
- package/dist/design-system240.js.map +1 -1
- package/dist/design-system242.js +8 -0
- package/dist/design-system242.js.map +1 -0
- package/dist/design-system243.js +54 -6
- package/dist/design-system243.js.map +1 -1
- package/dist/design-system244.js +4 -7
- package/dist/design-system244.js.map +1 -1
- package/dist/design-system245.js +139 -343
- package/dist/design-system245.js.map +1 -1
- package/dist/design-system247.js +4 -5
- package/dist/design-system247.js.map +1 -1
- package/dist/design-system248.js +10 -0
- package/dist/design-system248.js.map +1 -0
- package/dist/{design-system238.js → design-system249.js} +2 -2
- package/dist/design-system249.js.map +1 -0
- package/dist/design-system25.js.map +1 -1
- package/dist/design-system251.js +8 -0
- package/dist/design-system251.js.map +1 -0
- package/dist/{design-system241.js → design-system252.js} +1 -1
- package/dist/design-system252.js.map +1 -0
- package/dist/design-system254.js +9 -0
- package/dist/design-system254.js.map +1 -0
- package/dist/design-system255.js +12 -0
- package/dist/design-system255.js.map +1 -0
- package/dist/design-system256.js +769 -0
- package/dist/design-system256.js.map +1 -0
- package/dist/design-system258.js +9 -0
- package/dist/design-system258.js.map +1 -0
- package/dist/design-system259.js +10 -0
- package/dist/design-system259.js.map +1 -0
- package/dist/design-system260.js +377 -0
- package/dist/design-system260.js.map +1 -0
- package/dist/design-system262.js +9 -0
- package/dist/design-system262.js.map +1 -0
- package/dist/design-system28.js.map +1 -1
- package/dist/design-system3.js.map +1 -1
- package/dist/design-system30.js +21 -138
- package/dist/design-system30.js.map +1 -1
- package/dist/design-system32.js +5 -4
- package/dist/design-system32.js.map +1 -1
- package/dist/design-system33.js +488 -14
- package/dist/design-system33.js.map +1 -1
- package/dist/design-system35.js +1 -1
- package/dist/design-system35.js.map +1 -1
- package/dist/design-system36.js +135 -17
- package/dist/design-system36.js.map +1 -1
- package/dist/design-system38.js +1 -1
- package/dist/design-system38.js.map +1 -1
- package/dist/design-system39.js +16 -11
- package/dist/design-system39.js.map +1 -1
- package/dist/design-system4.js.map +1 -1
- package/dist/design-system41.js +8 -0
- package/dist/design-system41.js.map +1 -0
- package/dist/design-system42.js +26 -5
- package/dist/design-system42.js.map +1 -1
- package/dist/design-system44.js +5 -71
- package/dist/design-system44.js.map +1 -1
- package/dist/design-system45.js +353 -0
- package/dist/design-system45.js.map +1 -0
- package/dist/design-system47.js +5 -50
- package/dist/design-system47.js.map +1 -1
- package/dist/design-system48.js +11 -4
- package/dist/design-system48.js.map +1 -1
- package/dist/design-system49.js +476 -3
- package/dist/design-system49.js.map +1 -1
- package/dist/design-system51.js +8 -0
- package/dist/design-system51.js.map +1 -0
- package/dist/design-system52.js +3 -5
- package/dist/design-system52.js.map +1 -1
- package/dist/design-system53.js +56 -83
- package/dist/design-system53.js.map +1 -1
- package/dist/design-system55.js +5 -4
- package/dist/design-system55.js.map +1 -1
- package/dist/design-system56.js +50 -11
- package/dist/design-system56.js.map +1 -1
- package/dist/design-system57.js +4 -591
- package/dist/design-system57.js.map +1 -1
- package/dist/design-system58.js +6 -0
- package/dist/design-system58.js.map +1 -0
- package/dist/design-system59.js +64 -5
- package/dist/design-system59.js.map +1 -1
- package/dist/design-system61.js +5 -696
- package/dist/design-system61.js.map +1 -1
- package/dist/design-system62.js +101 -0
- package/dist/design-system62.js.map +1 -0
- package/dist/design-system64.js +5 -158
- package/dist/design-system64.js.map +1 -1
- package/dist/design-system65.js +14 -0
- package/dist/design-system65.js.map +1 -0
- package/dist/design-system66.js +591 -5
- package/dist/design-system66.js.map +1 -1
- package/dist/design-system68.js +3 -2
- package/dist/design-system68.js.map +1 -1
- package/dist/design-system69.js +13 -49
- package/dist/design-system69.js.map +1 -1
- package/dist/design-system7.js.map +1 -1
- package/dist/design-system70.js +699 -0
- package/dist/{design-system63.js.map → design-system70.js.map} +1 -1
- package/dist/design-system72.js +5 -199
- package/dist/design-system72.js.map +1 -1
- package/dist/design-system73.js +161 -0
- package/dist/design-system73.js.map +1 -0
- package/dist/design-system75.js +5 -7
- package/dist/design-system75.js.map +1 -1
- package/dist/design-system76.js +25 -269
- package/dist/design-system76.js.map +1 -1
- package/dist/design-system77.js +7 -0
- package/dist/design-system77.js.map +1 -0
- package/dist/design-system78.js +49 -5
- package/dist/design-system78.js.map +1 -1
- package/dist/{design-system71.js → design-system80.js} +2 -2
- package/dist/{design-system71.js.map → design-system80.js.map} +1 -1
- package/dist/design-system81.js +199 -5
- package/dist/design-system81.js.map +1 -1
- package/dist/design-system83.js +5 -99
- package/dist/design-system83.js.map +1 -1
- package/dist/design-system84.js +10 -0
- package/dist/design-system84.js.map +1 -0
- package/dist/design-system85.js +273 -5
- package/dist/design-system85.js.map +1 -1
- package/dist/design-system87.js +8 -0
- package/dist/design-system87.js.map +1 -0
- package/dist/design-system88.js +57 -5
- package/dist/design-system88.js.map +1 -1
- package/dist/design-system90.js +8 -0
- package/dist/design-system90.js.map +1 -0
- package/dist/design-system91.js +11 -5
- package/dist/design-system91.js.map +1 -1
- package/dist/design-system92.js +98 -53
- package/dist/design-system92.js.map +1 -1
- package/dist/design-system94.js +5 -13
- package/dist/design-system94.js.map +1 -1
- package/dist/design-system95.js +61 -104
- package/dist/design-system95.js.map +1 -1
- package/dist/design-system97.js +4 -5
- package/dist/design-system97.js.map +1 -1
- package/dist/design-system98.js +80 -198
- package/dist/design-system98.js.map +1 -1
- package/dist/types/components/BCalendar/BCalendar.spec.d.ts +1 -0
- package/dist/types/components/BCalendar/BCalendar.vue.d.ts +114 -0
- package/dist/types/components/BCalendar/index.d.ts +2 -0
- package/dist/types/components/BCalendar/types.d.ts +54 -0
- package/dist/types/components/BCarousel/BCarousel.spec.d.ts +1 -0
- package/dist/types/components/BCarousel/BCarousel.vue.d.ts +133 -0
- package/dist/types/components/BCarousel/index.d.ts +2 -0
- package/dist/types/components/BCarousel/types.d.ts +15 -0
- package/dist/types/components/BDivider/types.d.ts +2 -2
- package/dist/types/components/BMasonry/types.d.ts +2 -2
- package/dist/types/components/BPagination/BPagination.vue.d.ts +1 -1
- package/dist/types/components/BStatistic/BStatistic.spec.d.ts +1 -0
- package/dist/types/components/BStatistic/BStatistic.vue.d.ts +44 -0
- package/dist/types/components/BStatistic/BStatisticTimer.vue.d.ts +50 -0
- package/dist/types/components/BStatistic/index.d.ts +3 -0
- package/dist/types/components/BStatistic/types.d.ts +6 -0
- package/dist/types/components/BTreeSelect/BTreeSelect.spec.d.ts +1 -0
- package/dist/types/components/BTreeSelect/BTreeSelect.vue.d.ts +143 -0
- package/dist/types/components/BTreeSelect/index.d.ts +2 -0
- package/dist/types/components/BTreeSelect/types.d.ts +77 -0
- package/dist/types/components/index.d.ts +4 -0
- package/dist/types/types.d.ts +3 -0
- package/package.json +18 -15
- package/dist/design-system105.js +0 -212
- package/dist/design-system105.js.map +0 -1
- package/dist/design-system108.js +0 -227
- package/dist/design-system108.js.map +0 -1
- package/dist/design-system111.js +0 -166
- package/dist/design-system111.js.map +0 -1
- package/dist/design-system115.js +0 -277
- package/dist/design-system115.js.map +0 -1
- package/dist/design-system118.js +0 -19
- package/dist/design-system118.js.map +0 -1
- package/dist/design-system121.js +0 -15
- package/dist/design-system121.js.map +0 -1
- package/dist/design-system125.js +0 -45
- package/dist/design-system125.js.map +0 -1
- package/dist/design-system128.js +0 -236
- package/dist/design-system128.js.map +0 -1
- package/dist/design-system141.js +0 -40
- package/dist/design-system141.js.map +0 -1
- package/dist/design-system144.js +0 -7
- package/dist/design-system158.js +0 -61
- package/dist/design-system158.js.map +0 -1
- package/dist/design-system161.js +0 -59
- package/dist/design-system161.js.map +0 -1
- package/dist/design-system174.js +0 -465
- package/dist/design-system174.js.map +0 -1
- package/dist/design-system177.js +0 -38
- package/dist/design-system177.js.map +0 -1
- package/dist/design-system222.js +0 -7
- package/dist/design-system222.js.map +0 -1
- package/dist/design-system225.js +0 -8
- package/dist/design-system225.js.map +0 -1
- package/dist/design-system229.js +0 -115
- package/dist/design-system229.js.map +0 -1
- package/dist/design-system238.js.map +0 -1
- package/dist/design-system241.js.map +0 -1
- package/dist/design-system40.js +0 -479
- package/dist/design-system40.js.map +0 -1
- package/dist/design-system43.js +0 -6
- package/dist/design-system43.js.map +0 -1
- package/dist/design-system46.js +0 -9
- package/dist/design-system46.js.map +0 -1
- package/dist/design-system50.js +0 -67
- package/dist/design-system50.js.map +0 -1
- package/dist/design-system60.js.map +0 -1
- package/dist/design-system63.js +0 -8
- package/dist/design-system67.js +0 -32
- package/dist/design-system67.js.map +0 -1
- package/dist/design-system74.js +0 -8
- package/dist/design-system74.js.map +0 -1
- package/dist/design-system79.js +0 -60
- package/dist/design-system79.js.map +0 -1
- package/dist/design-system82.js +0 -14
- package/dist/design-system82.js.map +0 -1
- package/dist/design-system86.js +0 -69
- package/dist/design-system86.js.map +0 -1
- package/dist/design-system89.js +0 -91
- package/dist/design-system89.js.map +0 -1
- package/dist/design-system93.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-system110.js","names":[],"sources":["../src/components/BInputNumber/BInputNumber.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { BInputStatus, BInputVariant } from '@/components/BInput/types.ts';\nimport { useComponentId } from '@/composables/useComponentId.ts';\nimport { BCommonSize } from '@/types.ts';\nimport { computed, ref, useSlots, watch } from 'vue';\nimport type { BInputNumberFocusOptions, BInputNumberStepInfo } from './types.ts';\n\ndefineOptions({ inheritAttrs: false });\n\nconst slots = useSlots();\n\nconst {\n size = BCommonSize.Medium,\n variant = BInputVariant.Outlined,\n min = Number.MIN_SAFE_INTEGER,\n max = Number.MAX_SAFE_INTEGER,\n step = 1,\n disabled = false,\n readOnly = false,\n controls = true,\n keyboard = true,\n changeOnBlur = true,\n changeOnWheel = false,\n placeholder,\n id,\n precision,\n formatter,\n parser,\n decimalSeparator,\n stringMode = false,\n status,\n} = defineProps<{\n /** The size of the input number. */\n size?: `${BCommonSize}`;\n /** Visual variant of the input number. */\n variant?: `${BInputVariant}`;\n /** Validation status. */\n status?: `${BInputStatus}`;\n /** Minimum value allowed. */\n min?: number;\n /** Maximum value allowed. */\n max?: number;\n /** Increment/decrement step amount. */\n step?: number;\n /** Whether the input number is disabled. */\n disabled?: boolean;\n /** Whether the input number is read-only. */\n readOnly?: boolean;\n /** Whether to show +/- controls. */\n controls?: boolean;\n /** Whether keyboard up/down changes value. */\n keyboard?: boolean;\n /** Whether to trigger change on blur (e.g. reset out-of-range). */\n changeOnBlur?: boolean;\n /** Whether mouse wheel changes value. */\n changeOnWheel?: boolean;\n /** Placeholder text. */\n placeholder?: string;\n /** HTML id attribute. */\n id?: string;\n /** Decimal precision for display. */\n precision?: number;\n /** Format the displayed value. */\n formatter?: (value: string | number) => string;\n /** Parse the formatted value back to a number. */\n parser?: (displayValue: string) => string;\n /** Custom decimal separator character. */\n decimalSeparator?: string;\n /** Use string mode for high-precision decimals. */\n stringMode?: boolean;\n}>();\n\nconst emit = defineEmits<{\n /** Fired when value changes. */\n change: [value: number | null];\n /** Fired when Enter key is pressed. */\n pressEnter: [event: KeyboardEvent];\n /** Fired on step (button, keyboard, or wheel). */\n step: [value: number | null, info: BInputNumberStepInfo];\n /** Fired on input focus. */\n focus: [event: FocusEvent];\n /** Fired on input blur. */\n blur: [event: FocusEvent];\n}>();\n\nconst model = defineModel<number | null>({ default: null });\n\nconst { componentUID } = useComponentId();\nconst inputId = computed(() => id ?? `b-input-number-${componentUID.value}`);\n\nconst inputRef = ref<HTMLInputElement | null>(null);\nconst isFocused = ref(false);\nconst displayValue = ref('');\n\nconst hasPrefix = computed(() => !!slots.prefix);\nconst hasSuffix = computed(() => !!slots.suffix);\n\nconst isUpDisabled = computed(() => {\n if (disabled || readOnly) return true;\n if (model.value === null) return false;\n return model.value >= max;\n});\n\nconst isDownDisabled = computed(() => {\n if (disabled || readOnly) return true;\n if (model.value === null) return false;\n return model.value <= min;\n});\n\nfunction toFixedPrecision(val: number): number {\n if (precision !== undefined) {\n return parseFloat(val.toFixed(precision));\n }\n const stepStr = String(step);\n const stepDecimals = stepStr.includes('.') ? stepStr.split('.')[1].length : 0;\n if (stepDecimals > 0) {\n return parseFloat(val.toFixed(stepDecimals));\n }\n return val;\n}\n\nfunction clamp(val: number): number {\n return Math.min(max, Math.max(min, val));\n}\n\nfunction formatValue(val: number | null): string {\n if (val === null) return '';\n let str: string;\n if (precision !== undefined) {\n str = val.toFixed(precision);\n } else {\n str = String(val);\n }\n if (decimalSeparator) {\n str = str.replace('.', decimalSeparator);\n }\n if (formatter) {\n return formatter(stringMode ? str : val);\n }\n return str;\n}\n\nfunction parseInput(input: string): number | null {\n if (!input.trim()) return null;\n let parsed = input;\n if (parser) {\n parsed = parser(input);\n } else if (decimalSeparator) {\n parsed = parsed.replace(decimalSeparator, '.');\n }\n const num = Number(parsed);\n if (isNaN(num)) return model.value;\n return num;\n}\n\nfunction syncDisplay() {\n displayValue.value = formatValue(model.value);\n}\n\nfunction updateValue(newVal: number | null, triggerChange = true) {\n if (newVal !== null) {\n newVal = toFixedPrecision(clamp(newVal));\n }\n const changed = newVal !== model.value;\n model.value = newVal;\n syncDisplay();\n if (changed && triggerChange) {\n emit('change', newVal);\n }\n}\n\nfunction stepValue(direction: 'up' | 'down') {\n if (disabled || readOnly) return;\n const current = model.value ?? 0;\n const offset = direction === 'up' ? step : -step;\n const next = toFixedPrecision(current + offset);\n const clamped = clamp(next);\n updateValue(clamped);\n emit('step', clamped, { offset: step, type: direction });\n}\n\nconst handleInput = (e: Event) => {\n const target = e.target as HTMLInputElement;\n displayValue.value = target.value;\n};\n\nconst handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n commitValue();\n emit('pressEnter', e);\n }\n if (!keyboard) return;\n if (e.key === 'ArrowUp') {\n e.preventDefault();\n stepValue('up');\n } else if (e.key === 'ArrowDown') {\n e.preventDefault();\n stepValue('down');\n }\n};\n\nconst handleFocus = (e: FocusEvent) => {\n isFocused.value = true;\n emit('focus', e);\n};\n\nconst handleBlur = (e: FocusEvent) => {\n isFocused.value = false;\n if (changeOnBlur) {\n commitValue();\n }\n emit('blur', e);\n};\n\nconst handleWheel = (e: WheelEvent) => {\n if (!changeOnWheel || disabled || readOnly || !isFocused.value) return;\n e.preventDefault();\n if (e.deltaY < 0) {\n stepValue('up');\n } else if (e.deltaY > 0) {\n stepValue('down');\n }\n};\n\nfunction commitValue() {\n const parsed = parseInput(displayValue.value);\n if (parsed === null) {\n updateValue(null);\n } else {\n updateValue(parsed);\n }\n}\n\nconst focus = (options?: BInputNumberFocusOptions) => {\n inputRef.value?.focus({ preventScroll: options?.preventScroll });\n if (options?.cursor && inputRef.value) {\n const len = inputRef.value.value.length;\n switch (options.cursor) {\n case 'start':\n inputRef.value.setSelectionRange(0, 0);\n break;\n case 'end':\n inputRef.value.setSelectionRange(len, len);\n break;\n case 'all':\n inputRef.value.setSelectionRange(0, len);\n break;\n }\n }\n};\n\nconst blur = () => {\n inputRef.value?.blur();\n};\n\nwatch(\n () => model.value,\n () => {\n if (!isFocused.value) {\n syncDisplay();\n }\n },\n { immediate: true },\n);\n\ndefineExpose({ focus, blur });\n</script>\n\n<template>\n <span\n class=\"b-input-number\"\n :class=\"[\n `b-input-number--${size}`,\n `b-input-number--${variant}`,\n {\n 'b-input-number--focused': isFocused,\n 'b-input-number--disabled': disabled,\n 'b-input-number--readonly': readOnly,\n 'b-input-number--error': status === BInputStatus.Error,\n 'b-input-number--warning': status === BInputStatus.Warning,\n 'b-input-number--has-controls': controls,\n },\n ]\"\n >\n <span class=\"b-input-number__wrapper\">\n <span v-if=\"hasPrefix\" class=\"b-input-number__prefix\" aria-hidden=\"true\">\n <slot name=\"prefix\" />\n </span>\n\n <input\n :id=\"inputId\"\n ref=\"inputRef\"\n :value=\"displayValue\"\n type=\"text\"\n inputmode=\"decimal\"\n role=\"spinbutton\"\n :aria-valuenow=\"model ?? undefined\"\n :aria-valuemin=\"min !== Number.MIN_SAFE_INTEGER ? min : undefined\"\n :aria-valuemax=\"max !== Number.MAX_SAFE_INTEGER ? max : undefined\"\n :aria-invalid=\"status === BInputStatus.Error ? true : undefined\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readOnly\"\n class=\"b-input-number__input\"\n @input=\"handleInput\"\n @keydown=\"handleKeyDown\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n @wheel=\"handleWheel\"\n />\n\n <span v-if=\"hasSuffix\" class=\"b-input-number__suffix\" aria-hidden=\"true\">\n <slot name=\"suffix\" />\n </span>\n\n <span v-if=\"controls\" class=\"b-input-number__handler-wrap\" aria-hidden=\"true\">\n <span\n class=\"b-input-number__handler b-input-number__handler--up\"\n :class=\"{ 'b-input-number__handler--disabled': isUpDisabled }\"\n role=\"button\"\n tabindex=\"-1\"\n aria-label=\"Increase value\"\n :aria-disabled=\"isUpDisabled\"\n @mousedown.prevent=\"!isUpDisabled && stepValue('up')\"\n >\n <svg\n viewBox=\"0 0 1024 1024\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h286c2.1 0 4.2-.8 5.7-2.3l70.3-70.3 70.3 70.3c1.5 1.5 3.5 2.3 5.7 2.3h286c6.5 0 10.3-7.4 6.5-12.7z\"\n />\n </svg>\n </span>\n <span\n class=\"b-input-number__handler b-input-number__handler--down\"\n :class=\"{ 'b-input-number__handler--disabled': isDownDisabled }\"\n role=\"button\"\n tabindex=\"-1\"\n aria-label=\"Decrease value\"\n :aria-disabled=\"isDownDisabled\"\n @mousedown.prevent=\"!isDownDisabled && stepValue('down')\"\n >\n <svg\n viewBox=\"0 0 1024 1024\"\n width=\"1em\"\n height=\"1em\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z\"\n />\n </svg>\n </span>\n </span>\n </span>\n </span>\n</template>\n\n<style scoped>\n.b-input-number {\n --b-input-number-active-bg: #ffffff;\n --b-input-number-active-border-color: #1677ff;\n --b-input-number-active-shadow: 0 0 0 2px rgba(5, 145, 255, 0.1);\n --b-input-number-addon-bg: rgba(0, 0, 0, 0.02);\n --b-input-number-control-width: 90px;\n --b-input-number-error-active-shadow: 0 0 0 2px rgba(255, 38, 5, 0.06);\n --b-input-number-filled-handle-bg: #f0f0f0;\n --b-input-number-handle-active-bg: rgba(0, 0, 0, 0.02);\n --b-input-number-handle-bg: #ffffff;\n --b-input-number-handle-border-color: #d9d9d9;\n --b-input-number-handle-font-size: 7px;\n --b-input-number-handle-hover-color: #1677ff;\n --b-input-number-handle-width: 22px;\n --b-input-number-hover-bg: #ffffff;\n --b-input-number-hover-border-color: #4096ff;\n --b-input-number-font-size: 14px;\n --b-input-number-font-size-lg: 16px;\n --b-input-number-font-size-sm: 14px;\n --b-input-number-padding-block: 4px;\n --b-input-number-padding-block-lg: 7px;\n --b-input-number-padding-block-sm: 0px;\n --b-input-number-padding-inline: 11px;\n --b-input-number-padding-inline-lg: 11px;\n --b-input-number-padding-inline-sm: 7px;\n --b-input-number-warning-active-shadow: 0 0 0 2px rgba(255, 215, 5, 0.1);\n --b-input-number-border-color: #d9d9d9;\n --b-input-number-bg: #ffffff;\n --b-input-number-color: rgba(0, 0, 0, 0.88);\n --b-input-number-placeholder-color: rgba(0, 0, 0, 0.25);\n --b-input-number-border-radius: 6px;\n --b-input-number-disabled-bg: rgba(0, 0, 0, 0.04);\n --b-input-number-disabled-color: rgba(0, 0, 0, 0.25);\n --b-input-number-error-border-color: #ff4d4f;\n --b-input-number-error-hover-border-color: #ff7875;\n --b-input-number-warning-border-color: #faad14;\n --b-input-number-warning-hover-border-color: #ffc53d;\n --b-input-number-filled-bg: rgba(0, 0, 0, 0.04);\n --b-input-number-filled-hover-bg: rgba(0, 0, 0, 0.04);\n\n display: inline-flex;\n align-items: stretch;\n width: var(--b-input-number-control-width);\n font-size: var(--b-input-number-font-size);\n color: var(--b-input-number-color);\n line-height: 1.5714;\n}\n\n.b-input-number--lg {\n font-size: var(--b-input-number-font-size-lg);\n}\n\n.b-input-number--sm {\n font-size: var(--b-input-number-font-size-sm);\n}\n\n.b-input-number__wrapper {\n display: inline-flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n position: relative;\n transition: all 0.2s;\n}\n\n/* Outlined */\n.b-input-number--outlined .b-input-number__wrapper {\n background: var(--b-input-number-bg);\n border: 1px solid var(--b-input-number-border-color);\n border-radius: var(--b-input-number-border-radius);\n}\n\n.b-input-number--outlined:not(.b-input-number--disabled):hover .b-input-number__wrapper {\n border-color: var(--b-input-number-hover-border-color);\n background: var(--b-input-number-hover-bg);\n}\n\n.b-input-number--outlined.b-input-number--focused .b-input-number__wrapper {\n border-color: var(--b-input-number-active-border-color);\n background: var(--b-input-number-active-bg);\n box-shadow: var(--b-input-number-active-shadow);\n}\n\n/* Filled */\n.b-input-number--filled .b-input-number__wrapper {\n background: var(--b-input-number-filled-bg);\n border: 1px solid transparent;\n border-radius: var(--b-input-number-border-radius);\n}\n\n.b-input-number--filled:not(.b-input-number--disabled):hover .b-input-number__wrapper {\n background: var(--b-input-number-filled-hover-bg);\n}\n\n.b-input-number--filled.b-input-number--focused .b-input-number__wrapper {\n background: var(--b-input-number-active-bg);\n border-color: var(--b-input-number-active-border-color);\n box-shadow: var(--b-input-number-active-shadow);\n}\n\n/* Borderless */\n.b-input-number--borderless .b-input-number__wrapper {\n background: transparent;\n border: 1px solid transparent;\n border-radius: var(--b-input-number-border-radius);\n}\n\n/* Underlined */\n.b-input-number--underlined .b-input-number__wrapper {\n background: transparent;\n border: none;\n border-bottom: 1px solid var(--b-input-number-border-color);\n border-radius: 0;\n}\n\n.b-input-number--underlined:not(.b-input-number--disabled):hover .b-input-number__wrapper {\n border-bottom-color: var(--b-input-number-hover-border-color);\n}\n\n.b-input-number--underlined.b-input-number--focused .b-input-number__wrapper {\n border-bottom-color: var(--b-input-number-active-border-color);\n box-shadow: 0 1px 0 0 var(--b-input-number-active-border-color);\n}\n\n/* Error */\n.b-input-number--error.b-input-number--outlined .b-input-number__wrapper {\n border-color: var(--b-input-number-error-border-color);\n}\n\n.b-input-number--error.b-input-number--outlined:not(.b-input-number--disabled):hover\n .b-input-number__wrapper {\n border-color: var(--b-input-number-error-hover-border-color);\n}\n\n.b-input-number--error.b-input-number--outlined.b-input-number--focused .b-input-number__wrapper,\n.b-input-number--error.b-input-number--filled.b-input-number--focused .b-input-number__wrapper {\n border-color: var(--b-input-number-error-border-color);\n box-shadow: var(--b-input-number-error-active-shadow);\n}\n\n.b-input-number--error.b-input-number--underlined .b-input-number__wrapper {\n border-bottom-color: var(--b-input-number-error-border-color);\n}\n\n.b-input-number--error.b-input-number--underlined.b-input-number--focused .b-input-number__wrapper {\n border-bottom-color: var(--b-input-number-error-border-color);\n box-shadow: 0 1px 0 0 var(--b-input-number-error-border-color);\n}\n\n/* Warning */\n.b-input-number--warning.b-input-number--outlined .b-input-number__wrapper {\n border-color: var(--b-input-number-warning-border-color);\n}\n\n.b-input-number--warning.b-input-number--outlined:not(.b-input-number--disabled):hover\n .b-input-number__wrapper {\n border-color: var(--b-input-number-warning-hover-border-color);\n}\n\n.b-input-number--warning.b-input-number--outlined.b-input-number--focused .b-input-number__wrapper,\n.b-input-number--warning.b-input-number--filled.b-input-number--focused .b-input-number__wrapper {\n border-color: var(--b-input-number-warning-border-color);\n box-shadow: var(--b-input-number-warning-active-shadow);\n}\n\n.b-input-number--warning.b-input-number--underlined .b-input-number__wrapper {\n border-bottom-color: var(--b-input-number-warning-border-color);\n}\n\n.b-input-number--warning.b-input-number--underlined.b-input-number--focused\n .b-input-number__wrapper {\n border-bottom-color: var(--b-input-number-warning-border-color);\n box-shadow: 0 1px 0 0 var(--b-input-number-warning-border-color);\n}\n\n/* Disabled */\n.b-input-number--disabled .b-input-number__wrapper {\n background: var(--b-input-number-disabled-bg);\n cursor: not-allowed;\n}\n\n.b-input-number--disabled .b-input-number__input {\n color: var(--b-input-number-disabled-color);\n cursor: not-allowed;\n}\n\n/* Input element */\n.b-input-number__input {\n flex: 1;\n min-width: 0;\n width: 100%;\n border: none;\n outline: none;\n background: transparent;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n text-align: left;\n}\n\n.b-input-number--md .b-input-number__input {\n padding: var(--b-input-number-padding-block) var(--b-input-number-padding-inline);\n}\n\n.b-input-number--lg .b-input-number__input {\n padding: var(--b-input-number-padding-block-lg) var(--b-input-number-padding-inline-lg);\n}\n\n.b-input-number--sm .b-input-number__input {\n padding: var(--b-input-number-padding-block-sm) var(--b-input-number-padding-inline-sm);\n}\n\n.b-input-number--has-controls .b-input-number__input {\n padding-right: calc(var(--b-input-number-handle-width) + 2px);\n}\n\n.b-input-number__input::placeholder {\n color: var(--b-input-number-placeholder-color);\n}\n\n/* Prefix & Suffix */\n.b-input-number__prefix,\n.b-input-number__suffix {\n display: inline-flex;\n align-items: center;\n color: var(--b-input-number-color);\n flex-shrink: 0;\n}\n\n.b-input-number__prefix {\n margin-left: var(--b-input-number-padding-inline);\n}\n\n.b-input-number__suffix {\n margin-right: var(--b-input-number-padding-inline);\n}\n\n.b-input-number__prefix ~ .b-input-number__input {\n padding-left: 4px;\n}\n\n/* Handler (step buttons) */\n.b-input-number__handler-wrap {\n position: absolute;\n top: 0;\n right: 0;\n display: flex;\n flex-direction: column;\n height: 100%;\n width: var(--b-input-number-handle-width);\n border-left: 1px solid var(--b-input-number-handle-border-color);\n border-radius: 0 var(--b-input-number-border-radius) var(--b-input-number-border-radius) 0;\n overflow: hidden;\n opacity: 0;\n transition: opacity 0.2s;\n}\n\n.b-input-number:hover .b-input-number__handler-wrap,\n.b-input-number--focused .b-input-number__handler-wrap {\n opacity: 1;\n}\n\n.b-input-number__handler {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n cursor: pointer;\n background: var(--b-input-number-handle-bg);\n font-size: var(--b-input-number-handle-font-size);\n color: rgba(0, 0, 0, 0.45);\n user-select: none;\n transition:\n color 0.2s,\n background 0.2s;\n}\n\n.b-input-number__handler:hover {\n color: var(--b-input-number-handle-hover-color);\n background: var(--b-input-number-handle-active-bg);\n}\n\n.b-input-number__handler--up {\n border-bottom: 1px solid var(--b-input-number-handle-border-color);\n}\n\n.b-input-number__handler--disabled {\n cursor: not-allowed;\n opacity: 0.4;\n pointer-events: none;\n}\n\n.b-input-number__handler svg {\n width: 0.5em;\n height: 0.5em;\n}\n\n/* Filled variant handler */\n.b-input-number--filled .b-input-number__handler {\n background: var(--b-input-number-filled-handle-bg);\n}\n\n/* Borderless / underlined: hide handler border */\n.b-input-number--borderless .b-input-number__handler-wrap,\n.b-input-number--underlined .b-input-number__handler-wrap {\n border-left-color: transparent;\n}\n\n/* Dark mode */\n[data-prefers-color='dark'] .b-input-number {\n --b-input-number-active-bg: #141414;\n --b-input-number-active-border-color: #1668dc;\n --b-input-number-active-shadow: 0 0 0 2px rgba(22, 104, 220, 0.15);\n --b-input-number-addon-bg: rgba(255, 255, 255, 0.04);\n --b-input-number-error-active-shadow: 0 0 0 2px rgba(220, 56, 56, 0.1);\n --b-input-number-filled-handle-bg: rgba(255, 255, 255, 0.12);\n --b-input-number-handle-active-bg: rgba(255, 255, 255, 0.04);\n --b-input-number-handle-bg: #1f1f1f;\n --b-input-number-handle-border-color: #424242;\n --b-input-number-handle-hover-color: #3c89e8;\n --b-input-number-hover-bg: #141414;\n --b-input-number-hover-border-color: #3c89e8;\n --b-input-number-warning-active-shadow: 0 0 0 2px rgba(209, 163, 0, 0.1);\n --b-input-number-border-color: #424242;\n --b-input-number-bg: #141414;\n --b-input-number-color: rgba(255, 255, 255, 0.88);\n --b-input-number-placeholder-color: rgba(255, 255, 255, 0.25);\n --b-input-number-disabled-bg: rgba(255, 255, 255, 0.08);\n --b-input-number-disabled-color: rgba(255, 255, 255, 0.25);\n --b-input-number-error-border-color: #dc3838;\n --b-input-number-error-hover-border-color: #e86e6e;\n --b-input-number-warning-border-color: #d1a300;\n --b-input-number-warning-hover-border-color: #e8c631;\n --b-input-number-filled-bg: rgba(255, 255, 255, 0.08);\n --b-input-number-filled-hover-bg: rgba(255, 255, 255, 0.12);\n}\n\n@media (prefers-color-scheme: dark) {\n [data-prefers-color='system'] .b-input-number {\n --b-input-number-active-bg: #141414;\n --b-input-number-active-border-color: #1668dc;\n --b-input-number-active-shadow: 0 0 0 2px rgba(22, 104, 220, 0.15);\n --b-input-number-addon-bg: rgba(255, 255, 255, 0.04);\n --b-input-number-error-active-shadow: 0 0 0 2px rgba(220, 56, 56, 0.1);\n --b-input-number-filled-handle-bg: rgba(255, 255, 255, 0.12);\n --b-input-number-handle-active-bg: rgba(255, 255, 255, 0.04);\n --b-input-number-handle-bg: #1f1f1f;\n --b-input-number-handle-border-color: #424242;\n --b-input-number-handle-hover-color: #3c89e8;\n --b-input-number-hover-bg: #141414;\n --b-input-number-hover-border-color: #3c89e8;\n --b-input-number-warning-active-shadow: 0 0 0 2px rgba(209, 163, 0, 0.1);\n --b-input-number-border-color: #424242;\n --b-input-number-bg: #141414;\n --b-input-number-color: rgba(255, 255, 255, 0.88);\n --b-input-number-placeholder-color: rgba(255, 255, 255, 0.25);\n --b-input-number-disabled-bg: rgba(255, 255, 255, 0.08);\n --b-input-number-disabled-color: rgba(255, 255, 255, 0.25);\n --b-input-number-error-border-color: #dc3838;\n --b-input-number-error-hover-border-color: #e86e6e;\n --b-input-number-warning-border-color: #d1a300;\n --b-input-number-warning-hover-border-color: #e8c631;\n --b-input-number-filled-bg: rgba(255, 255, 255, 0.08);\n --b-input-number-filled-hover-bg: rgba(255, 255, 255, 0.12);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .b-input-number__wrapper,\n .b-input-number__handler-wrap,\n .b-input-number__handler {\n transition: none;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"design-system110.js","names":["$slots"],"sources":["../src/components/BImage/BImage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';\n\n// ─────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────\nexport type BImageTransformAction =\n | 'flipX'\n | 'flipY'\n | 'rotateLeft'\n | 'rotateRight'\n | 'zoomIn'\n | 'zoomOut'\n | 'reset'\n | 'wheel'\n | 'dragStart'\n | 'dragEnd';\n\nexport interface BImageTransform {\n scale: number;\n rotate: number;\n flipX: boolean;\n flipY: boolean;\n x: number;\n y: number;\n}\n\n// ─────────────────────────────────────────────\n// Props\n// ─────────────────────────────────────────────\nconst props = withDefaults(\n defineProps<{\n /** Image source URL. */\n src?: string;\n /** Alt text for the image. */\n alt?: string;\n /** Image width (px or CSS value). */\n width?: string | number;\n /** Image height (px or CSS value). */\n height?: string | number;\n /** Fallback source when loading fails. */\n fallback?: string;\n /**\n * Show loading placeholder. Set to `true` for built-in shimmer,\n * or use the `placeholder` slot for custom content.\n */\n placeholder?: boolean;\n /**\n * Low-resolution source for progressive loading.\n * Shown blurred while the full image loads.\n */\n placeholderSrc?: string;\n /** Enable image preview on click. */\n preview?: boolean;\n /** Show the hover mask overlay over the image. Set `false` to hide the mask entirely while keeping preview on click. */\n mask?: boolean;\n /** Custom source for preview (defaults to `src`). */\n previewSrc?: string;\n /** Controlled preview visibility (v-model:previewVisible). */\n previewVisible?: boolean;\n /** Zoom scale step for preview controls. */\n scaleStep?: number;\n /** Min zoom scale. */\n minScale?: number;\n /** Max zoom scale. */\n maxScale?: number;\n /** Allow dragging/panning the image inside the preview. */\n movable?: boolean;\n /** Native `loading` attribute - `'lazy'` for below-the-fold images. */\n loading?: 'lazy' | 'eager';\n /** CORS setting for the image. */\n crossOrigin?: '' | 'anonymous' | 'use-credentials';\n /** Decoding hint for the browser. */\n decoding?: 'async' | 'auto' | 'sync';\n /** Referrer policy for the image request. */\n referrerPolicy?:\n | ''\n | 'no-referrer'\n | 'no-referrer-when-downgrade'\n | 'origin'\n | 'origin-when-cross-origin'\n | 'same-origin'\n | 'strict-origin'\n | 'strict-origin-when-cross-origin'\n | 'unsafe-url';\n }>(),\n {\n src: undefined,\n alt: '',\n width: undefined,\n height: undefined,\n fallback: undefined,\n placeholder: false,\n placeholderSrc: undefined,\n preview: true,\n mask: true,\n previewSrc: undefined,\n previewVisible: undefined,\n scaleStep: 0.5,\n minScale: 1,\n maxScale: 50,\n movable: true,\n loading: undefined,\n crossOrigin: undefined,\n decoding: undefined,\n referrerPolicy: undefined,\n },\n);\n\n// ─────────────────────────────────────────────\n// Emits\n// ─────────────────────────────────────────────\nconst emit = defineEmits<{\n /** Fires when the <img> fails to load. */\n (e: 'error', event: Event): void;\n /** Fires when controlled preview visibility changes. */\n (e: 'update:previewVisible', visible: boolean): void;\n /** Fires on every preview transform change (zoom, rotate, flip, drag). */\n (e: 'transform', payload: { transform: BImageTransform; action: BImageTransformAction }): void;\n}>();\n\n// ─────────────────────────────────────────────\n// Slots\n// ─────────────────────────────────────────────\ndefineSlots<{\n /** Custom loading placeholder content. */\n placeholder?(): unknown;\n /** Custom preview mask overlay. */\n 'preview-mask'?(): unknown;\n}>();\n\n// ─────────────────────────────────────────────\n// Image loading state\n// ─────────────────────────────────────────────\nconst loadStatus = ref<'loading' | 'loaded' | 'error'>('loading');\nconst useFallback = ref(false);\n\nfunction handleLoad() {\n loadStatus.value = 'loaded';\n}\n\nfunction handleError(event: Event) {\n if (props.fallback && !useFallback.value) {\n useFallback.value = true;\n loadStatus.value = 'loading';\n } else {\n loadStatus.value = 'error';\n }\n emit('error', event);\n}\n\nconst displaySrc = computed(() => {\n if (useFallback.value && props.fallback) return props.fallback;\n return props.src;\n});\n\n// Reset state when src changes\nwatch(\n () => props.src,\n () => {\n loadStatus.value = 'loading';\n useFallback.value = false;\n },\n);\n\n// ─────────────────────────────────────────────\n// Progressive loading (low-res blurry placeholder)\n// ─────────────────────────────────────────────\nconst showProgressivePlaceholder = computed(\n () => props.placeholderSrc && loadStatus.value === 'loading',\n);\n\n// ─────────────────────────────────────────────\n// Dimension helpers\n// ─────────────────────────────────────────────\nconst dimensionStyle = computed(() => {\n const s: Record<string, string> = {};\n if (props.width != null) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width;\n }\n if (props.height != null) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height;\n }\n return s;\n});\n\n// ─────────────────────────────────────────────\n// Show mask logic\n// ─────────────────────────────────────────────\nconst showMask = computed(() => props.preview && props.mask && loadStatus.value === 'loaded');\n\n// ─────────────────────────────────────────────\n// Preview overlay\n// ─────────────────────────────────────────────\nconst internalPreviewOpen = ref(false);\nconst isControlled = computed(() => props.previewVisible !== undefined);\n\nconst previewOpen = computed(() =>\n isControlled.value ? props.previewVisible : internalPreviewOpen.value,\n);\n\nfunction openPreview() {\n if (!props.preview) return;\n if (isControlled.value) {\n emit('update:previewVisible', true);\n } else {\n internalPreviewOpen.value = true;\n }\n nextTick(() => {\n trapFocusInPreview();\n });\n}\n\nfunction closePreview() {\n if (isControlled.value) {\n emit('update:previewVisible', false);\n } else {\n internalPreviewOpen.value = false;\n }\n // Return focus to trigger\n nextTick(() => {\n triggerRef.value?.focus();\n });\n}\n\n// ─────────────────────────────────────────────\n// Preview transform state\n// ─────────────────────────────────────────────\nconst scale = ref(1);\nconst rotate = ref(0);\nconst flipX = ref(false);\nconst flipY = ref(false);\nconst dragX = ref(0);\nconst dragY = ref(0);\n\nfunction currentTransform(): BImageTransform {\n return {\n scale: scale.value,\n rotate: rotate.value,\n flipX: flipX.value,\n flipY: flipY.value,\n x: dragX.value,\n y: dragY.value,\n };\n}\n\nfunction emitTransform(action: BImageTransformAction) {\n emit('transform', { transform: currentTransform(), action });\n}\n\nfunction resetTransform() {\n scale.value = 1;\n rotate.value = 0;\n flipX.value = false;\n flipY.value = false;\n dragX.value = 0;\n dragY.value = 0;\n}\n\nfunction doResetTransform() {\n resetTransform();\n emitTransform('reset');\n}\n\nfunction zoomIn() {\n const next = scale.value + props.scaleStep;\n scale.value = Math.min(next, props.maxScale);\n emitTransform('zoomIn');\n}\n\nfunction zoomOut() {\n const next = scale.value - props.scaleStep;\n scale.value = Math.max(next, props.minScale);\n emitTransform('zoomOut');\n}\n\nfunction rotateLeft() {\n rotate.value -= 90;\n emitTransform('rotateLeft');\n}\n\nfunction rotateRight() {\n rotate.value += 90;\n emitTransform('rotateRight');\n}\n\nfunction toggleFlipX() {\n flipX.value = !flipX.value;\n emitTransform('flipX');\n}\n\nfunction toggleFlipY() {\n flipY.value = !flipY.value;\n emitTransform('flipY');\n}\n\nconst previewTransform = computed(() => {\n const parts: string[] = [];\n parts.push(`translate(${dragX.value}px, ${dragY.value}px)`);\n parts.push(`scale(${flipX.value ? -1 : 1}, ${flipY.value ? -1 : 1})`);\n parts.push(`scale(${scale.value})`);\n parts.push(`rotate(${rotate.value}deg)`);\n return parts.join(' ');\n});\n\n// Reset transform when preview is opened\nwatch(previewOpen, (open) => {\n if (open) {\n resetTransform();\n }\n});\n\nconst previewImageSrc = computed(() => props.previewSrc || props.src);\n\n// ─────────────────────────────────────────────\n// Drag-to-pan (movable)\n// ─────────────────────────────────────────────\nconst isDragging = ref(false);\nconst dragStartX = ref(0);\nconst dragStartY = ref(0);\nconst dragStartTranslateX = ref(0);\nconst dragStartTranslateY = ref(0);\n\nfunction handlePreviewPointerDown(event: PointerEvent) {\n if (!props.movable) return;\n // Only initiate drag on the image body (not toolbar/close)\n const target = event.target as HTMLElement;\n if (target.closest('.b-image-preview__toolbar') || target.closest('.b-image-preview__close')) {\n return;\n }\n\n isDragging.value = true;\n dragStartX.value = event.clientX;\n dragStartY.value = event.clientY;\n dragStartTranslateX.value = dragX.value;\n dragStartTranslateY.value = dragY.value;\n\n (event.currentTarget as HTMLElement)?.setPointerCapture(event.pointerId);\n emitTransform('dragStart');\n}\n\nfunction handlePreviewPointerMove(event: PointerEvent) {\n if (!isDragging.value) return;\n const dx = event.clientX - dragStartX.value;\n const dy = event.clientY - dragStartY.value;\n dragX.value = dragStartTranslateX.value + dx;\n dragY.value = dragStartTranslateY.value + dy;\n}\n\nfunction handlePreviewPointerUp() {\n if (!isDragging.value) return;\n isDragging.value = false;\n emitTransform('dragEnd');\n}\n\n// ─────────────────────────────────────────────\n// Focus management\n// ─────────────────────────────────────────────\nconst triggerRef = ref<HTMLElement | null>(null);\nconst overlayRef = ref<HTMLElement | null>(null);\n\nfunction trapFocusInPreview() {\n nextTick(() => {\n if (!overlayRef.value) return;\n const focusable = overlayRef.value.querySelectorAll<HTMLElement>(\n 'button, [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length > 0) {\n focusable[0].focus();\n }\n });\n}\n\nfunction handleOverlayKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n event.stopPropagation();\n closePreview();\n return;\n }\n\n if (event.key === 'Tab' && overlayRef.value) {\n const focusable = Array.from(\n overlayRef.value.querySelectorAll<HTMLElement>('button, [tabindex]:not([tabindex=\"-1\"])'),\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }\n}\n\nfunction handleTriggerKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n openPreview();\n }\n}\n\n// ─────────────────────────────────────────────\n// Body scroll lock\n// ─────────────────────────────────────────────\nwatch(previewOpen, (open) => {\n if (typeof document === 'undefined') return;\n if (open) {\n document.body.style.overflow = 'hidden';\n } else {\n document.body.style.overflow = '';\n }\n});\n\nonBeforeUnmount(() => {\n if (typeof document !== 'undefined') {\n document.body.style.overflow = '';\n }\n});\n\n// ─────────────────────────────────────────────\n// Zoom with mouse wheel in preview\n// ─────────────────────────────────────────────\nfunction handlePreviewWheel(event: WheelEvent) {\n event.preventDefault();\n if (event.deltaY < 0) {\n const next = scale.value + props.scaleStep;\n scale.value = Math.min(next, props.maxScale);\n } else {\n const next = scale.value - props.scaleStep;\n scale.value = Math.max(next, props.minScale);\n }\n emitTransform('wheel');\n}\n\n// ─────────────────────────────────────────────\n// Toolbar keyboard support\n// ─────────────────────────────────────────────\nfunction handleToolbarKeydown(event: KeyboardEvent) {\n const target = event.target as HTMLElement;\n if (target.tagName !== 'BUTTON') return;\n\n const toolbar = target.closest('.b-image-preview__toolbar');\n if (!toolbar) return;\n const buttons = Array.from(toolbar.querySelectorAll<HTMLElement>('button:not(:disabled)'));\n const index = buttons.indexOf(target);\n\n let nextIndex = -1;\n if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n event.preventDefault();\n nextIndex = (index + 1) % buttons.length;\n } else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n event.preventDefault();\n nextIndex = (index - 1 + buttons.length) % buttons.length;\n } else if (event.key === 'Home') {\n event.preventDefault();\n nextIndex = 0;\n } else if (event.key === 'End') {\n event.preventDefault();\n nextIndex = buttons.length - 1;\n }\n\n if (nextIndex >= 0) {\n buttons[nextIndex].focus();\n }\n}\n</script>\n\n<template>\n <div\n class=\"b-image\"\n :class=\"{\n 'b-image--error': loadStatus === 'error' && !fallback,\n 'b-image--preview': preview,\n }\"\n :style=\"dimensionStyle\"\n >\n <!-- Progressive placeholder (blurred low-res image) -->\n <img\n v-if=\"showProgressivePlaceholder\"\n class=\"b-image__progressive-placeholder\"\n :src=\"placeholderSrc\"\n :alt=\"alt\"\n aria-hidden=\"true\"\n />\n\n <!-- Placeholder (shimmer or slot) -->\n <div\n v-if=\"(placeholder || $slots.placeholder) && loadStatus === 'loading' && !placeholderSrc\"\n class=\"b-image__placeholder\"\n aria-hidden=\"true\"\n >\n <slot name=\"placeholder\">\n <div class=\"b-image__placeholder-shimmer\" />\n </slot>\n </div>\n\n <!-- Image -->\n <img\n v-show=\"loadStatus !== 'loading' || (!placeholder && !$slots.placeholder && !placeholderSrc)\"\n class=\"b-image__img\"\n :src=\"displaySrc\"\n :alt=\"alt\"\n :width=\"typeof width === 'number' ? width : undefined\"\n :height=\"typeof height === 'number' ? height : undefined\"\n :loading=\"loading\"\n :crossorigin=\"crossOrigin\"\n :decoding=\"decoding\"\n :referrerpolicy=\"referrerPolicy\"\n @load=\"handleLoad\"\n @error=\"handleError\"\n />\n\n <!-- Preview mask overlay (clickable) -->\n <div\n v-if=\"showMask\"\n ref=\"triggerRef\"\n class=\"b-image__mask\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"`Preview image${alt ? ': ' + alt : ''}`\"\n @click=\"openPreview\"\n @keydown=\"handleTriggerKeydown\"\n >\n <slot name=\"preview-mask\">\n <span class=\"b-image__mask-text\" aria-hidden=\"true\">\n <!-- Eye icon -->\n <svg\n class=\"b-image__mask-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n Preview\n </span>\n </slot>\n </div>\n\n <!-- Invisible click target when mask is hidden but preview is enabled -->\n <div\n v-else-if=\"preview && !mask && loadStatus === 'loaded'\"\n ref=\"triggerRef\"\n class=\"b-image__click-target\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"`Preview image${alt ? ': ' + alt : ''}`\"\n @click=\"openPreview\"\n @keydown=\"handleTriggerKeydown\"\n />\n\n <!-- Preview overlay (teleported to body) -->\n <Teleport to=\"body\">\n <Transition name=\"b-image-preview\">\n <div\n v-if=\"previewOpen\"\n ref=\"overlayRef\"\n class=\"b-image-preview\"\n :class=\"{ 'b-image-preview--dragging': isDragging }\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"`Image preview${alt ? ': ' + alt : ''}`\"\n @keydown=\"handleOverlayKeydown\"\n @wheel.prevent=\"handlePreviewWheel\"\n @pointerdown=\"handlePreviewPointerDown\"\n @pointermove=\"handlePreviewPointerMove\"\n @pointerup=\"handlePreviewPointerUp\"\n @pointercancel=\"handlePreviewPointerUp\"\n >\n <!-- Backdrop -->\n <div class=\"b-image-preview__backdrop\" @click=\"closePreview\" />\n\n <!-- Close button -->\n <button\n class=\"b-image-preview__close\"\n type=\"button\"\n aria-label=\"Close preview\"\n @click=\"closePreview\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n\n <!-- Preview image -->\n <div class=\"b-image-preview__body\">\n <img\n class=\"b-image-preview__img\"\n :src=\"previewImageSrc\"\n :alt=\"alt\"\n :style=\"{ transform: previewTransform }\"\n draggable=\"false\"\n />\n </div>\n\n <!-- Toolbar -->\n <div\n class=\"b-image-preview__toolbar\"\n role=\"toolbar\"\n aria-label=\"Image preview controls\"\n @keydown=\"handleToolbarKeydown\"\n >\n <!-- Flip Horizontal -->\n <button\n type=\"button\"\n aria-label=\"Flip horizontal\"\n :aria-pressed=\"flipX\"\n @click=\"toggleFlipX\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M8 3H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h3\" />\n <path d=\"M16 3h3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-3\" />\n <line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"23\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n\n <!-- Flip Vertical -->\n <button\n type=\"button\"\n aria-label=\"Flip vertical\"\n :aria-pressed=\"flipY\"\n @click=\"toggleFlipY\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M3 8V5a2 2 0 0 1 2-2h14c1.1 0 2 .9 2 2v3\" />\n <path d=\"M3 16v3a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-3\" />\n <line x1=\"1\" y1=\"12\" x2=\"23\" y2=\"12\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n\n <!-- Rotate Left -->\n <button type=\"button\" aria-label=\"Rotate left\" @click=\"rotateLeft\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <polyline points=\"1 4 1 10 7 10\" />\n <path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\" />\n </svg>\n </button>\n\n <!-- Rotate Right -->\n <button type=\"button\" aria-label=\"Rotate right\" @click=\"rotateRight\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <polyline points=\"23 4 23 10 17 10\" />\n <path d=\"M20.49 15a9 9 0 1 1-2.13-9.36L23 10\" />\n </svg>\n </button>\n\n <!-- Zoom Out -->\n <button\n type=\"button\"\n aria-label=\"Zoom out\"\n :disabled=\"scale <= minScale\"\n @click=\"zoomOut\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </button>\n\n <!-- Scale indicator -->\n <span class=\"b-image-preview__scale\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ Math.round(scale * 100) }}%\n </span>\n\n <!-- Zoom In -->\n <button\n type=\"button\"\n aria-label=\"Zoom in\"\n :disabled=\"scale >= maxScale\"\n @click=\"zoomIn\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </button>\n\n <!-- Reset (1:1) -->\n <button type=\"button\" aria-label=\"Reset to original size\" @click=\"doResetTransform\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <text\n x=\"12\"\n y=\"16\"\n text-anchor=\"middle\"\n fill=\"currentColor\"\n stroke=\"none\"\n font-size=\"10\"\n font-weight=\"600\"\n font-family=\"system-ui\"\n >\n 1:1\n </text>\n </svg>\n </button>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<style>\n/* ────────────────────────────────────────────\n CSS Custom Properties (tokens)\n ──────────────────────────────────────────── */\n.b-image {\n /* Layout */\n --b-image-border-radius: 8px;\n --b-image-bg: oklch(95% 0.003 260);\n --b-image-object-fit: cover;\n\n /* Placeholder */\n --b-image-placeholder-bg: oklch(93% 0.005 260);\n --b-image-placeholder-shimmer: linear-gradient(\n 90deg,\n oklch(93% 0.005 260) 25%,\n oklch(96% 0.003 260) 50%,\n oklch(93% 0.005 260) 75%\n );\n --b-image-progressive-blur: 20px;\n\n /* Mask */\n --b-image-mask-bg: oklch(0% 0 0 / 50%);\n --b-image-mask-color: oklch(100% 0 0);\n --b-image-mask-font-size: 14px;\n --b-image-mask-icon-size: 20px;\n\n /* Error */\n --b-image-error-bg: oklch(95% 0.003 260);\n --b-image-error-color: oklch(55% 0.01 260);\n --b-image-error-icon-size: 32px;\n\n /* Animation */\n --b-image-transition-duration: 200ms;\n\n /* Focus */\n --b-image-focus-ring: 2px solid oklch(54.6% 0.245 262.881);\n --b-image-focus-ring-offset: 2px;\n}\n\n/* Preview overlay tokens */\n.b-image-preview {\n --b-image-preview-backdrop-bg: oklch(0% 0 0 / 65%);\n --b-image-preview-toolbar-bg: oklch(15% 0.005 260 / 85%);\n --b-image-preview-toolbar-color: oklch(95% 0.005 260);\n --b-image-preview-toolbar-btn-size: 40px;\n --b-image-preview-toolbar-icon-size: 20px;\n --b-image-preview-toolbar-gap: 8px;\n --b-image-preview-toolbar-radius: 24px;\n --b-image-preview-toolbar-padding: 4px 16px;\n --b-image-preview-close-size: 40px;\n --b-image-preview-close-color: oklch(90% 0.005 260);\n --b-image-preview-close-hover-bg: oklch(100% 0 0 / 12%);\n --b-image-preview-transition-duration: 250ms;\n --b-image-preview-scale-font-size: 13px;\n --b-image-preview-scale-min-width: 52px;\n}\n\n/* ── Dark mode ─────────────────────────────── */\n[data-prefers-color='dark'] .b-image {\n --b-image-bg: oklch(22% 0.005 260);\n --b-image-placeholder-bg: oklch(25% 0.005 260);\n --b-image-placeholder-shimmer: linear-gradient(\n 90deg,\n oklch(25% 0.005 260) 25%,\n oklch(30% 0.003 260) 50%,\n oklch(25% 0.005 260) 75%\n );\n --b-image-error-bg: oklch(22% 0.005 260);\n --b-image-error-color: oklch(70% 0.01 260);\n}\n\n[data-prefers-color='dark'] .b-image-preview {\n --b-image-preview-backdrop-bg: oklch(0% 0 0 / 80%);\n --b-image-preview-toolbar-bg: oklch(10% 0.005 260 / 90%);\n}\n\n@media (prefers-color-scheme: dark) {\n [data-prefers-color='system'] .b-image {\n --b-image-bg: oklch(22% 0.005 260);\n --b-image-placeholder-bg: oklch(25% 0.005 260);\n --b-image-placeholder-shimmer: linear-gradient(\n 90deg,\n oklch(25% 0.005 260) 25%,\n oklch(30% 0.003 260) 50%,\n oklch(25% 0.005 260) 75%\n );\n --b-image-error-bg: oklch(22% 0.005 260);\n --b-image-error-color: oklch(70% 0.01 260);\n }\n [data-prefers-color='system'] .b-image-preview {\n --b-image-preview-backdrop-bg: oklch(0% 0 0 / 80%);\n --b-image-preview-toolbar-bg: oklch(10% 0.005 260 / 90%);\n }\n}\n\n/* ─────────────────────────────────────────────\n Base layout\n ───────────────────────────────────────────── */\n.b-image {\n position: relative;\n display: inline-block;\n overflow: hidden;\n border-radius: var(--b-image-border-radius);\n background-color: var(--b-image-bg);\n line-height: 0;\n box-sizing: border-box;\n}\n\n.b-image__img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: var(--b-image-object-fit);\n border-radius: var(--b-image-border-radius);\n}\n\n/* ─────────────────────────────────────────────\n Progressive placeholder (blurred low-res)\n ───────────────────────────────────────────── */\n.b-image__progressive-placeholder {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: var(--b-image-object-fit);\n border-radius: var(--b-image-border-radius);\n filter: blur(var(--b-image-progressive-blur));\n transform: scale(1.1);\n z-index: 1;\n}\n\n/* ─────────────────────────────────────────────\n Placeholder\n ───────────────────────────────────────────── */\n.b-image__placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--b-image-placeholder-bg);\n border-radius: var(--b-image-border-radius);\n z-index: 1;\n}\n\n.b-image__placeholder-shimmer {\n width: 100%;\n height: 100%;\n background: var(--b-image-placeholder-shimmer);\n background-size: 200% 100%;\n animation: b-image-shimmer 1.5s infinite;\n border-radius: var(--b-image-border-radius);\n}\n\n@keyframes b-image-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n}\n\n/* ─────────────────────────────────────────────\n Preview mask\n ───────────────────────────────────────────── */\n.b-image__mask {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--b-image-mask-bg);\n color: var(--b-image-mask-color);\n font-size: var(--b-image-mask-font-size);\n border-radius: var(--b-image-border-radius);\n opacity: 0;\n cursor: pointer;\n transition: opacity var(--b-image-transition-duration) ease;\n z-index: 2;\n outline: none;\n}\n\n.b-image--preview:hover .b-image__mask,\n.b-image__mask:focus-visible {\n opacity: 1;\n}\n\n.b-image__mask:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n.b-image__mask-text {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n user-select: none;\n}\n\n.b-image__mask-icon {\n width: var(--b-image-mask-icon-size);\n height: var(--b-image-mask-icon-size);\n}\n\n/* Invisible click target (mask=false, preview=true) */\n.b-image__click-target {\n position: absolute;\n inset: 0;\n z-index: 2;\n cursor: pointer;\n outline: none;\n}\n\n.b-image__click-target:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n/* ─────────────────────────────────────────────\n Error state\n ───────────────────────────────────────────── */\n.b-image--error {\n background-color: var(--b-image-error-bg);\n}\n\n/* ─────────────────────────────────────────────\n Preview overlay\n ───────────────────────────────────────────── */\n.b-image-preview {\n position: fixed;\n inset: 0;\n z-index: 1080;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: none;\n}\n\n.b-image-preview--dragging {\n cursor: grabbing;\n}\n\n.b-image-preview__backdrop {\n position: absolute;\n inset: 0;\n background-color: var(--b-image-preview-backdrop-bg);\n}\n\n.b-image-preview__close {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--b-image-preview-close-size);\n height: var(--b-image-preview-close-size);\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--b-image-preview-close-color);\n cursor: pointer;\n padding: 0;\n transition: background-color var(--b-image-preview-transition-duration) ease;\n}\n\n.b-image-preview__close:hover,\n.b-image-preview__close:focus-visible {\n background-color: var(--b-image-preview-close-hover-bg);\n}\n\n.b-image-preview__close:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n.b-image-preview__close svg {\n width: 20px;\n height: 20px;\n}\n\n.b-image-preview__body {\n position: relative;\n z-index: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n max-width: 100%;\n max-height: 100%;\n padding: 40px;\n box-sizing: border-box;\n cursor: grab;\n}\n\n.b-image-preview--dragging .b-image-preview__body {\n cursor: grabbing;\n}\n\n.b-image-preview__img {\n max-width: 100%;\n max-height: calc(100vh - 120px);\n object-fit: contain;\n transition: transform var(--b-image-preview-transition-duration) ease;\n user-select: none;\n -webkit-user-drag: none;\n pointer-events: none;\n}\n\n.b-image-preview--dragging .b-image-preview__img {\n transition: none;\n}\n\n/* ─────────────────────────────────────────────\n Toolbar\n ───────────────────────────────────────────── */\n.b-image-preview__toolbar {\n position: absolute;\n bottom: 24px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 1;\n display: flex;\n align-items: center;\n gap: var(--b-image-preview-toolbar-gap);\n padding: var(--b-image-preview-toolbar-padding);\n background-color: var(--b-image-preview-toolbar-bg);\n color: var(--b-image-preview-toolbar-color);\n border-radius: var(--b-image-preview-toolbar-radius);\n backdrop-filter: blur(8px);\n}\n\n.b-image-preview__toolbar button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--b-image-preview-toolbar-btn-size);\n height: var(--b-image-preview-toolbar-btn-size);\n border: none;\n border-radius: 50%;\n background: transparent;\n color: inherit;\n cursor: pointer;\n padding: 0;\n transition: background-color var(--b-image-preview-transition-duration) ease;\n}\n\n.b-image-preview__toolbar button:hover:not(:disabled),\n.b-image-preview__toolbar button:focus-visible {\n background-color: var(--b-image-preview-close-hover-bg);\n}\n\n.b-image-preview__toolbar button:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n.b-image-preview__toolbar button:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.b-image-preview__toolbar button svg {\n width: var(--b-image-preview-toolbar-icon-size);\n height: var(--b-image-preview-toolbar-icon-size);\n}\n\n.b-image-preview__scale {\n font-size: var(--b-image-preview-scale-font-size);\n min-width: var(--b-image-preview-scale-min-width);\n text-align: center;\n font-variant-numeric: tabular-nums;\n user-select: none;\n}\n\n/* ─────────────────────────────────────────────\n Preview transitions\n ───────────────────────────────────────────── */\n.b-image-preview-enter-active,\n.b-image-preview-leave-active {\n transition: opacity var(--b-image-preview-transition-duration) ease;\n}\n\n.b-image-preview-enter-from,\n.b-image-preview-leave-to {\n opacity: 0;\n}\n\n/* ─────────────────────────────────────────────\n Reduced motion\n ───────────────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .b-image {\n --b-image-transition-duration: 0ms;\n }\n\n .b-image-preview {\n --b-image-preview-transition-duration: 0ms;\n }\n\n .b-image__placeholder-shimmer {\n animation: none;\n }\n\n .b-image-preview-enter-active,\n .b-image-preview-leave-active {\n transition-duration: 0ms;\n }\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-system112.js","names":[],"sources":["../src/components/BImage/BImage.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';\n\n// ─────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────\nexport type BImageTransformAction =\n | 'flipX'\n | 'flipY'\n | 'rotateLeft'\n | 'rotateRight'\n | 'zoomIn'\n | 'zoomOut'\n | 'reset'\n | 'wheel'\n | 'dragStart'\n | 'dragEnd';\n\nexport interface BImageTransform {\n scale: number;\n rotate: number;\n flipX: boolean;\n flipY: boolean;\n x: number;\n y: number;\n}\n\n// ─────────────────────────────────────────────\n// Props\n// ─────────────────────────────────────────────\nconst props = withDefaults(\n defineProps<{\n /** Image source URL. */\n src?: string;\n /** Alt text for the image. */\n alt?: string;\n /** Image width (px or CSS value). */\n width?: string | number;\n /** Image height (px or CSS value). */\n height?: string | number;\n /** Fallback source when loading fails. */\n fallback?: string;\n /**\n * Show loading placeholder. Set to `true` for built-in shimmer,\n * or use the `placeholder` slot for custom content.\n */\n placeholder?: boolean;\n /**\n * Low-resolution source for progressive loading.\n * Shown blurred while the full image loads.\n */\n placeholderSrc?: string;\n /** Enable image preview on click. */\n preview?: boolean;\n /** Show the hover mask overlay over the image. Set `false` to hide the mask entirely while keeping preview on click. */\n mask?: boolean;\n /** Custom source for preview (defaults to `src`). */\n previewSrc?: string;\n /** Controlled preview visibility (v-model:previewVisible). */\n previewVisible?: boolean;\n /** Zoom scale step for preview controls. */\n scaleStep?: number;\n /** Min zoom scale. */\n minScale?: number;\n /** Max zoom scale. */\n maxScale?: number;\n /** Allow dragging/panning the image inside the preview. */\n movable?: boolean;\n /** Native `loading` attribute - `'lazy'` for below-the-fold images. */\n loading?: 'lazy' | 'eager';\n /** CORS setting for the image. */\n crossOrigin?: '' | 'anonymous' | 'use-credentials';\n /** Decoding hint for the browser. */\n decoding?: 'async' | 'auto' | 'sync';\n /** Referrer policy for the image request. */\n referrerPolicy?:\n | ''\n | 'no-referrer'\n | 'no-referrer-when-downgrade'\n | 'origin'\n | 'origin-when-cross-origin'\n | 'same-origin'\n | 'strict-origin'\n | 'strict-origin-when-cross-origin'\n | 'unsafe-url';\n }>(),\n {\n src: undefined,\n alt: '',\n width: undefined,\n height: undefined,\n fallback: undefined,\n placeholder: false,\n placeholderSrc: undefined,\n preview: true,\n mask: true,\n previewSrc: undefined,\n previewVisible: undefined,\n scaleStep: 0.5,\n minScale: 1,\n maxScale: 50,\n movable: true,\n loading: undefined,\n crossOrigin: undefined,\n decoding: undefined,\n referrerPolicy: undefined,\n },\n);\n\n// ─────────────────────────────────────────────\n// Emits\n// ─────────────────────────────────────────────\nconst emit = defineEmits<{\n /** Fires when the <img> fails to load. */\n (e: 'error', event: Event): void;\n /** Fires when controlled preview visibility changes. */\n (e: 'update:previewVisible', visible: boolean): void;\n /** Fires on every preview transform change (zoom, rotate, flip, drag). */\n (e: 'transform', payload: { transform: BImageTransform; action: BImageTransformAction }): void;\n}>();\n\n// ─────────────────────────────────────────────\n// Slots\n// ─────────────────────────────────────────────\ndefineSlots<{\n /** Custom loading placeholder content. */\n placeholder?(): unknown;\n /** Custom preview mask overlay. */\n 'preview-mask'?(): unknown;\n}>();\n\n// ─────────────────────────────────────────────\n// Image loading state\n// ─────────────────────────────────────────────\nconst loadStatus = ref<'loading' | 'loaded' | 'error'>('loading');\nconst useFallback = ref(false);\n\nfunction handleLoad() {\n loadStatus.value = 'loaded';\n}\n\nfunction handleError(event: Event) {\n if (props.fallback && !useFallback.value) {\n useFallback.value = true;\n loadStatus.value = 'loading';\n } else {\n loadStatus.value = 'error';\n }\n emit('error', event);\n}\n\nconst displaySrc = computed(() => {\n if (useFallback.value && props.fallback) return props.fallback;\n return props.src;\n});\n\n// Reset state when src changes\nwatch(\n () => props.src,\n () => {\n loadStatus.value = 'loading';\n useFallback.value = false;\n },\n);\n\n// ─────────────────────────────────────────────\n// Progressive loading (low-res blurry placeholder)\n// ─────────────────────────────────────────────\nconst showProgressivePlaceholder = computed(\n () => props.placeholderSrc && loadStatus.value === 'loading',\n);\n\n// ─────────────────────────────────────────────\n// Dimension helpers\n// ─────────────────────────────────────────────\nconst dimensionStyle = computed(() => {\n const s: Record<string, string> = {};\n if (props.width != null) {\n s.width = typeof props.width === 'number' ? `${props.width}px` : props.width;\n }\n if (props.height != null) {\n s.height = typeof props.height === 'number' ? `${props.height}px` : props.height;\n }\n return s;\n});\n\n// ─────────────────────────────────────────────\n// Show mask logic\n// ─────────────────────────────────────────────\nconst showMask = computed(() => props.preview && props.mask && loadStatus.value === 'loaded');\n\n// ─────────────────────────────────────────────\n// Preview overlay\n// ─────────────────────────────────────────────\nconst internalPreviewOpen = ref(false);\nconst isControlled = computed(() => props.previewVisible !== undefined);\n\nconst previewOpen = computed(() =>\n isControlled.value ? props.previewVisible : internalPreviewOpen.value,\n);\n\nfunction openPreview() {\n if (!props.preview) return;\n if (isControlled.value) {\n emit('update:previewVisible', true);\n } else {\n internalPreviewOpen.value = true;\n }\n nextTick(() => {\n trapFocusInPreview();\n });\n}\n\nfunction closePreview() {\n if (isControlled.value) {\n emit('update:previewVisible', false);\n } else {\n internalPreviewOpen.value = false;\n }\n // Return focus to trigger\n nextTick(() => {\n triggerRef.value?.focus();\n });\n}\n\n// ─────────────────────────────────────────────\n// Preview transform state\n// ─────────────────────────────────────────────\nconst scale = ref(1);\nconst rotate = ref(0);\nconst flipX = ref(false);\nconst flipY = ref(false);\nconst dragX = ref(0);\nconst dragY = ref(0);\n\nfunction currentTransform(): BImageTransform {\n return {\n scale: scale.value,\n rotate: rotate.value,\n flipX: flipX.value,\n flipY: flipY.value,\n x: dragX.value,\n y: dragY.value,\n };\n}\n\nfunction emitTransform(action: BImageTransformAction) {\n emit('transform', { transform: currentTransform(), action });\n}\n\nfunction resetTransform() {\n scale.value = 1;\n rotate.value = 0;\n flipX.value = false;\n flipY.value = false;\n dragX.value = 0;\n dragY.value = 0;\n}\n\nfunction doResetTransform() {\n resetTransform();\n emitTransform('reset');\n}\n\nfunction zoomIn() {\n const next = scale.value + props.scaleStep;\n scale.value = Math.min(next, props.maxScale);\n emitTransform('zoomIn');\n}\n\nfunction zoomOut() {\n const next = scale.value - props.scaleStep;\n scale.value = Math.max(next, props.minScale);\n emitTransform('zoomOut');\n}\n\nfunction rotateLeft() {\n rotate.value -= 90;\n emitTransform('rotateLeft');\n}\n\nfunction rotateRight() {\n rotate.value += 90;\n emitTransform('rotateRight');\n}\n\nfunction toggleFlipX() {\n flipX.value = !flipX.value;\n emitTransform('flipX');\n}\n\nfunction toggleFlipY() {\n flipY.value = !flipY.value;\n emitTransform('flipY');\n}\n\nconst previewTransform = computed(() => {\n const parts: string[] = [];\n parts.push(`translate(${dragX.value}px, ${dragY.value}px)`);\n parts.push(`scale(${flipX.value ? -1 : 1}, ${flipY.value ? -1 : 1})`);\n parts.push(`scale(${scale.value})`);\n parts.push(`rotate(${rotate.value}deg)`);\n return parts.join(' ');\n});\n\n// Reset transform when preview is opened\nwatch(previewOpen, (open) => {\n if (open) {\n resetTransform();\n }\n});\n\nconst previewImageSrc = computed(() => props.previewSrc || props.src);\n\n// ─────────────────────────────────────────────\n// Drag-to-pan (movable)\n// ─────────────────────────────────────────────\nconst isDragging = ref(false);\nconst dragStartX = ref(0);\nconst dragStartY = ref(0);\nconst dragStartTranslateX = ref(0);\nconst dragStartTranslateY = ref(0);\n\nfunction handlePreviewPointerDown(event: PointerEvent) {\n if (!props.movable) return;\n // Only initiate drag on the image body (not toolbar/close)\n const target = event.target as HTMLElement;\n if (target.closest('.b-image-preview__toolbar') || target.closest('.b-image-preview__close')) {\n return;\n }\n\n isDragging.value = true;\n dragStartX.value = event.clientX;\n dragStartY.value = event.clientY;\n dragStartTranslateX.value = dragX.value;\n dragStartTranslateY.value = dragY.value;\n\n (event.currentTarget as HTMLElement)?.setPointerCapture(event.pointerId);\n emitTransform('dragStart');\n}\n\nfunction handlePreviewPointerMove(event: PointerEvent) {\n if (!isDragging.value) return;\n const dx = event.clientX - dragStartX.value;\n const dy = event.clientY - dragStartY.value;\n dragX.value = dragStartTranslateX.value + dx;\n dragY.value = dragStartTranslateY.value + dy;\n}\n\nfunction handlePreviewPointerUp() {\n if (!isDragging.value) return;\n isDragging.value = false;\n emitTransform('dragEnd');\n}\n\n// ─────────────────────────────────────────────\n// Focus management\n// ─────────────────────────────────────────────\nconst triggerRef = ref<HTMLElement | null>(null);\nconst overlayRef = ref<HTMLElement | null>(null);\n\nfunction trapFocusInPreview() {\n nextTick(() => {\n if (!overlayRef.value) return;\n const focusable = overlayRef.value.querySelectorAll<HTMLElement>(\n 'button, [tabindex]:not([tabindex=\"-1\"])',\n );\n if (focusable.length > 0) {\n focusable[0].focus();\n }\n });\n}\n\nfunction handleOverlayKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n event.stopPropagation();\n closePreview();\n return;\n }\n\n if (event.key === 'Tab' && overlayRef.value) {\n const focusable = Array.from(\n overlayRef.value.querySelectorAll<HTMLElement>('button, [tabindex]:not([tabindex=\"-1\"])'),\n );\n if (focusable.length === 0) return;\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n }\n}\n\nfunction handleTriggerKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n openPreview();\n }\n}\n\n// ─────────────────────────────────────────────\n// Body scroll lock\n// ─────────────────────────────────────────────\nwatch(previewOpen, (open) => {\n if (typeof document === 'undefined') return;\n if (open) {\n document.body.style.overflow = 'hidden';\n } else {\n document.body.style.overflow = '';\n }\n});\n\nonBeforeUnmount(() => {\n if (typeof document !== 'undefined') {\n document.body.style.overflow = '';\n }\n});\n\n// ─────────────────────────────────────────────\n// Zoom with mouse wheel in preview\n// ─────────────────────────────────────────────\nfunction handlePreviewWheel(event: WheelEvent) {\n event.preventDefault();\n if (event.deltaY < 0) {\n const next = scale.value + props.scaleStep;\n scale.value = Math.min(next, props.maxScale);\n } else {\n const next = scale.value - props.scaleStep;\n scale.value = Math.max(next, props.minScale);\n }\n emitTransform('wheel');\n}\n\n// ─────────────────────────────────────────────\n// Toolbar keyboard support\n// ─────────────────────────────────────────────\nfunction handleToolbarKeydown(event: KeyboardEvent) {\n const target = event.target as HTMLElement;\n if (target.tagName !== 'BUTTON') return;\n\n const toolbar = target.closest('.b-image-preview__toolbar');\n if (!toolbar) return;\n const buttons = Array.from(toolbar.querySelectorAll<HTMLElement>('button:not(:disabled)'));\n const index = buttons.indexOf(target);\n\n let nextIndex = -1;\n if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n event.preventDefault();\n nextIndex = (index + 1) % buttons.length;\n } else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n event.preventDefault();\n nextIndex = (index - 1 + buttons.length) % buttons.length;\n } else if (event.key === 'Home') {\n event.preventDefault();\n nextIndex = 0;\n } else if (event.key === 'End') {\n event.preventDefault();\n nextIndex = buttons.length - 1;\n }\n\n if (nextIndex >= 0) {\n buttons[nextIndex].focus();\n }\n}\n</script>\n\n<template>\n <div\n class=\"b-image\"\n :class=\"{\n 'b-image--error': loadStatus === 'error' && !fallback,\n 'b-image--preview': preview,\n }\"\n :style=\"dimensionStyle\"\n >\n <!-- Progressive placeholder (blurred low-res image) -->\n <img\n v-if=\"showProgressivePlaceholder\"\n class=\"b-image__progressive-placeholder\"\n :src=\"placeholderSrc\"\n :alt=\"alt\"\n aria-hidden=\"true\"\n />\n\n <!-- Placeholder (shimmer or slot) -->\n <div\n v-if=\"(placeholder || $slots.placeholder) && loadStatus === 'loading' && !placeholderSrc\"\n class=\"b-image__placeholder\"\n aria-hidden=\"true\"\n >\n <slot name=\"placeholder\">\n <div class=\"b-image__placeholder-shimmer\" />\n </slot>\n </div>\n\n <!-- Image -->\n <img\n v-show=\"loadStatus !== 'loading' || (!placeholder && !$slots.placeholder && !placeholderSrc)\"\n class=\"b-image__img\"\n :src=\"displaySrc\"\n :alt=\"alt\"\n :width=\"typeof width === 'number' ? width : undefined\"\n :height=\"typeof height === 'number' ? height : undefined\"\n :loading=\"loading\"\n :crossorigin=\"crossOrigin\"\n :decoding=\"decoding\"\n :referrerpolicy=\"referrerPolicy\"\n @load=\"handleLoad\"\n @error=\"handleError\"\n />\n\n <!-- Preview mask overlay (clickable) -->\n <div\n v-if=\"showMask\"\n ref=\"triggerRef\"\n class=\"b-image__mask\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"`Preview image${alt ? ': ' + alt : ''}`\"\n @click=\"openPreview\"\n @keydown=\"handleTriggerKeydown\"\n >\n <slot name=\"preview-mask\">\n <span class=\"b-image__mask-text\" aria-hidden=\"true\">\n <!-- Eye icon -->\n <svg\n class=\"b-image__mask-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n Preview\n </span>\n </slot>\n </div>\n\n <!-- Invisible click target when mask is hidden but preview is enabled -->\n <div\n v-else-if=\"preview && !mask && loadStatus === 'loaded'\"\n ref=\"triggerRef\"\n class=\"b-image__click-target\"\n role=\"button\"\n tabindex=\"0\"\n :aria-label=\"`Preview image${alt ? ': ' + alt : ''}`\"\n @click=\"openPreview\"\n @keydown=\"handleTriggerKeydown\"\n />\n\n <!-- Preview overlay (teleported to body) -->\n <Teleport to=\"body\">\n <Transition name=\"b-image-preview\">\n <div\n v-if=\"previewOpen\"\n ref=\"overlayRef\"\n class=\"b-image-preview\"\n :class=\"{ 'b-image-preview--dragging': isDragging }\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-label=\"`Image preview${alt ? ': ' + alt : ''}`\"\n @keydown=\"handleOverlayKeydown\"\n @wheel.prevent=\"handlePreviewWheel\"\n @pointerdown=\"handlePreviewPointerDown\"\n @pointermove=\"handlePreviewPointerMove\"\n @pointerup=\"handlePreviewPointerUp\"\n @pointercancel=\"handlePreviewPointerUp\"\n >\n <!-- Backdrop -->\n <div class=\"b-image-preview__backdrop\" @click=\"closePreview\" />\n\n <!-- Close button -->\n <button\n class=\"b-image-preview__close\"\n type=\"button\"\n aria-label=\"Close preview\"\n @click=\"closePreview\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n\n <!-- Preview image -->\n <div class=\"b-image-preview__body\">\n <img\n class=\"b-image-preview__img\"\n :src=\"previewImageSrc\"\n :alt=\"alt\"\n :style=\"{ transform: previewTransform }\"\n draggable=\"false\"\n />\n </div>\n\n <!-- Toolbar -->\n <div\n class=\"b-image-preview__toolbar\"\n role=\"toolbar\"\n aria-label=\"Image preview controls\"\n @keydown=\"handleToolbarKeydown\"\n >\n <!-- Flip Horizontal -->\n <button\n type=\"button\"\n aria-label=\"Flip horizontal\"\n :aria-pressed=\"flipX\"\n @click=\"toggleFlipX\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M8 3H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h3\" />\n <path d=\"M16 3h3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-3\" />\n <line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"23\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n\n <!-- Flip Vertical -->\n <button\n type=\"button\"\n aria-label=\"Flip vertical\"\n :aria-pressed=\"flipY\"\n @click=\"toggleFlipY\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M3 8V5a2 2 0 0 1 2-2h14c1.1 0 2 .9 2 2v3\" />\n <path d=\"M3 16v3a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-3\" />\n <line x1=\"1\" y1=\"12\" x2=\"23\" y2=\"12\" stroke-dasharray=\"2 2\" />\n </svg>\n </button>\n\n <!-- Rotate Left -->\n <button type=\"button\" aria-label=\"Rotate left\" @click=\"rotateLeft\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <polyline points=\"1 4 1 10 7 10\" />\n <path d=\"M3.51 15a9 9 0 1 0 2.13-9.36L1 10\" />\n </svg>\n </button>\n\n <!-- Rotate Right -->\n <button type=\"button\" aria-label=\"Rotate right\" @click=\"rotateRight\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <polyline points=\"23 4 23 10 17 10\" />\n <path d=\"M20.49 15a9 9 0 1 1-2.13-9.36L23 10\" />\n </svg>\n </button>\n\n <!-- Zoom Out -->\n <button\n type=\"button\"\n aria-label=\"Zoom out\"\n :disabled=\"scale <= minScale\"\n @click=\"zoomOut\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </button>\n\n <!-- Scale indicator -->\n <span class=\"b-image-preview__scale\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ Math.round(scale * 100) }}%\n </span>\n\n <!-- Zoom In -->\n <button\n type=\"button\"\n aria-label=\"Zoom in\"\n :disabled=\"scale >= maxScale\"\n @click=\"zoomIn\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </svg>\n </button>\n\n <!-- Reset (1:1) -->\n <button type=\"button\" aria-label=\"Reset to original size\" @click=\"doResetTransform\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <text\n x=\"12\"\n y=\"16\"\n text-anchor=\"middle\"\n fill=\"currentColor\"\n stroke=\"none\"\n font-size=\"10\"\n font-weight=\"600\"\n font-family=\"system-ui\"\n >\n 1:1\n </text>\n </svg>\n </button>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<style>\n/* ────────────────────────────────────────────\n CSS Custom Properties (tokens)\n ──────────────────────────────────────────── */\n.b-image {\n /* Layout */\n --b-image-border-radius: 8px;\n --b-image-bg: oklch(95% 0.003 260);\n --b-image-object-fit: cover;\n\n /* Placeholder */\n --b-image-placeholder-bg: oklch(93% 0.005 260);\n --b-image-placeholder-shimmer: linear-gradient(\n 90deg,\n oklch(93% 0.005 260) 25%,\n oklch(96% 0.003 260) 50%,\n oklch(93% 0.005 260) 75%\n );\n --b-image-progressive-blur: 20px;\n\n /* Mask */\n --b-image-mask-bg: oklch(0% 0 0 / 50%);\n --b-image-mask-color: oklch(100% 0 0);\n --b-image-mask-font-size: 14px;\n --b-image-mask-icon-size: 20px;\n\n /* Error */\n --b-image-error-bg: oklch(95% 0.003 260);\n --b-image-error-color: oklch(55% 0.01 260);\n --b-image-error-icon-size: 32px;\n\n /* Animation */\n --b-image-transition-duration: 200ms;\n\n /* Focus */\n --b-image-focus-ring: 2px solid oklch(54.6% 0.245 262.881);\n --b-image-focus-ring-offset: 2px;\n}\n\n/* Preview overlay tokens */\n.b-image-preview {\n --b-image-preview-backdrop-bg: oklch(0% 0 0 / 65%);\n --b-image-preview-toolbar-bg: oklch(15% 0.005 260 / 85%);\n --b-image-preview-toolbar-color: oklch(95% 0.005 260);\n --b-image-preview-toolbar-btn-size: 40px;\n --b-image-preview-toolbar-icon-size: 20px;\n --b-image-preview-toolbar-gap: 8px;\n --b-image-preview-toolbar-radius: 24px;\n --b-image-preview-toolbar-padding: 4px 16px;\n --b-image-preview-close-size: 40px;\n --b-image-preview-close-color: oklch(90% 0.005 260);\n --b-image-preview-close-hover-bg: oklch(100% 0 0 / 12%);\n --b-image-preview-transition-duration: 250ms;\n --b-image-preview-scale-font-size: 13px;\n --b-image-preview-scale-min-width: 52px;\n}\n\n/* ── Dark mode ─────────────────────────────── */\n[data-prefers-color='dark'] .b-image {\n --b-image-bg: oklch(22% 0.005 260);\n --b-image-placeholder-bg: oklch(25% 0.005 260);\n --b-image-placeholder-shimmer: linear-gradient(\n 90deg,\n oklch(25% 0.005 260) 25%,\n oklch(30% 0.003 260) 50%,\n oklch(25% 0.005 260) 75%\n );\n --b-image-error-bg: oklch(22% 0.005 260);\n --b-image-error-color: oklch(70% 0.01 260);\n}\n\n[data-prefers-color='dark'] .b-image-preview {\n --b-image-preview-backdrop-bg: oklch(0% 0 0 / 80%);\n --b-image-preview-toolbar-bg: oklch(10% 0.005 260 / 90%);\n}\n\n@media (prefers-color-scheme: dark) {\n [data-prefers-color='system'] .b-image {\n --b-image-bg: oklch(22% 0.005 260);\n --b-image-placeholder-bg: oklch(25% 0.005 260);\n --b-image-placeholder-shimmer: linear-gradient(\n 90deg,\n oklch(25% 0.005 260) 25%,\n oklch(30% 0.003 260) 50%,\n oklch(25% 0.005 260) 75%\n );\n --b-image-error-bg: oklch(22% 0.005 260);\n --b-image-error-color: oklch(70% 0.01 260);\n }\n [data-prefers-color='system'] .b-image-preview {\n --b-image-preview-backdrop-bg: oklch(0% 0 0 / 80%);\n --b-image-preview-toolbar-bg: oklch(10% 0.005 260 / 90%);\n }\n}\n\n/* ─────────────────────────────────────────────\n Base layout\n ───────────────────────────────────────────── */\n.b-image {\n position: relative;\n display: inline-block;\n overflow: hidden;\n border-radius: var(--b-image-border-radius);\n background-color: var(--b-image-bg);\n line-height: 0;\n box-sizing: border-box;\n}\n\n.b-image__img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: var(--b-image-object-fit);\n border-radius: var(--b-image-border-radius);\n}\n\n/* ─────────────────────────────────────────────\n Progressive placeholder (blurred low-res)\n ───────────────────────────────────────────── */\n.b-image__progressive-placeholder {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: var(--b-image-object-fit);\n border-radius: var(--b-image-border-radius);\n filter: blur(var(--b-image-progressive-blur));\n transform: scale(1.1);\n z-index: 1;\n}\n\n/* ─────────────────────────────────────────────\n Placeholder\n ───────────────────────────────────────────── */\n.b-image__placeholder {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--b-image-placeholder-bg);\n border-radius: var(--b-image-border-radius);\n z-index: 1;\n}\n\n.b-image__placeholder-shimmer {\n width: 100%;\n height: 100%;\n background: var(--b-image-placeholder-shimmer);\n background-size: 200% 100%;\n animation: b-image-shimmer 1.5s infinite;\n border-radius: var(--b-image-border-radius);\n}\n\n@keyframes b-image-shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n}\n\n/* ─────────────────────────────────────────────\n Preview mask\n ───────────────────────────────────────────── */\n.b-image__mask {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--b-image-mask-bg);\n color: var(--b-image-mask-color);\n font-size: var(--b-image-mask-font-size);\n border-radius: var(--b-image-border-radius);\n opacity: 0;\n cursor: pointer;\n transition: opacity var(--b-image-transition-duration) ease;\n z-index: 2;\n outline: none;\n}\n\n.b-image--preview:hover .b-image__mask,\n.b-image__mask:focus-visible {\n opacity: 1;\n}\n\n.b-image__mask:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n.b-image__mask-text {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 500;\n user-select: none;\n}\n\n.b-image__mask-icon {\n width: var(--b-image-mask-icon-size);\n height: var(--b-image-mask-icon-size);\n}\n\n/* Invisible click target (mask=false, preview=true) */\n.b-image__click-target {\n position: absolute;\n inset: 0;\n z-index: 2;\n cursor: pointer;\n outline: none;\n}\n\n.b-image__click-target:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n/* ─────────────────────────────────────────────\n Error state\n ───────────────────────────────────────────── */\n.b-image--error {\n background-color: var(--b-image-error-bg);\n}\n\n/* ─────────────────────────────────────────────\n Preview overlay\n ───────────────────────────────────────────── */\n.b-image-preview {\n position: fixed;\n inset: 0;\n z-index: 1080;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: none;\n}\n\n.b-image-preview--dragging {\n cursor: grabbing;\n}\n\n.b-image-preview__backdrop {\n position: absolute;\n inset: 0;\n background-color: var(--b-image-preview-backdrop-bg);\n}\n\n.b-image-preview__close {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--b-image-preview-close-size);\n height: var(--b-image-preview-close-size);\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--b-image-preview-close-color);\n cursor: pointer;\n padding: 0;\n transition: background-color var(--b-image-preview-transition-duration) ease;\n}\n\n.b-image-preview__close:hover,\n.b-image-preview__close:focus-visible {\n background-color: var(--b-image-preview-close-hover-bg);\n}\n\n.b-image-preview__close:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n.b-image-preview__close svg {\n width: 20px;\n height: 20px;\n}\n\n.b-image-preview__body {\n position: relative;\n z-index: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n max-width: 100%;\n max-height: 100%;\n padding: 40px;\n box-sizing: border-box;\n cursor: grab;\n}\n\n.b-image-preview--dragging .b-image-preview__body {\n cursor: grabbing;\n}\n\n.b-image-preview__img {\n max-width: 100%;\n max-height: calc(100vh - 120px);\n object-fit: contain;\n transition: transform var(--b-image-preview-transition-duration) ease;\n user-select: none;\n -webkit-user-drag: none;\n pointer-events: none;\n}\n\n.b-image-preview--dragging .b-image-preview__img {\n transition: none;\n}\n\n/* ─────────────────────────────────────────────\n Toolbar\n ───────────────────────────────────────────── */\n.b-image-preview__toolbar {\n position: absolute;\n bottom: 24px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 1;\n display: flex;\n align-items: center;\n gap: var(--b-image-preview-toolbar-gap);\n padding: var(--b-image-preview-toolbar-padding);\n background-color: var(--b-image-preview-toolbar-bg);\n color: var(--b-image-preview-toolbar-color);\n border-radius: var(--b-image-preview-toolbar-radius);\n backdrop-filter: blur(8px);\n}\n\n.b-image-preview__toolbar button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--b-image-preview-toolbar-btn-size);\n height: var(--b-image-preview-toolbar-btn-size);\n border: none;\n border-radius: 50%;\n background: transparent;\n color: inherit;\n cursor: pointer;\n padding: 0;\n transition: background-color var(--b-image-preview-transition-duration) ease;\n}\n\n.b-image-preview__toolbar button:hover:not(:disabled),\n.b-image-preview__toolbar button:focus-visible {\n background-color: var(--b-image-preview-close-hover-bg);\n}\n\n.b-image-preview__toolbar button:focus-visible {\n outline: var(--b-image-focus-ring);\n outline-offset: var(--b-image-focus-ring-offset);\n}\n\n.b-image-preview__toolbar button:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.b-image-preview__toolbar button svg {\n width: var(--b-image-preview-toolbar-icon-size);\n height: var(--b-image-preview-toolbar-icon-size);\n}\n\n.b-image-preview__scale {\n font-size: var(--b-image-preview-scale-font-size);\n min-width: var(--b-image-preview-scale-min-width);\n text-align: center;\n font-variant-numeric: tabular-nums;\n user-select: none;\n}\n\n/* ─────────────────────────────────────────────\n Preview transitions\n ───────────────────────────────────────────── */\n.b-image-preview-enter-active,\n.b-image-preview-leave-active {\n transition: opacity var(--b-image-preview-transition-duration) ease;\n}\n\n.b-image-preview-enter-from,\n.b-image-preview-leave-to {\n opacity: 0;\n}\n\n/* ─────────────────────────────────────────────\n Reduced motion\n ───────────────────────────────────────────── */\n@media (prefers-reduced-motion: reduce) {\n .b-image {\n --b-image-transition-duration: 0ms;\n }\n\n .b-image-preview {\n --b-image-preview-transition-duration: 0ms;\n }\n\n .b-image__placeholder-shimmer {\n animation: none;\n }\n\n .b-image-preview-enter-active,\n .b-image-preview-leave-active {\n transition-duration: 0ms;\n }\n}\n</style>\n"],"mappings":""}
|
package/dist/design-system113.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
/*
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
//#region src/components/BInput/types.ts
|
|
2
|
+
var e = /* @__PURE__ */ function(e) {
|
|
3
|
+
return e.Outlined = "outlined", e.Filled = "filled", e.Borderless = "borderless", e.Underlined = "underlined", e;
|
|
4
|
+
}({}), t = /* @__PURE__ */ function(e) {
|
|
5
|
+
return e.Error = "error", e.Warning = "warning", e;
|
|
6
|
+
}({});
|
|
5
7
|
//#endregion
|
|
6
|
-
export { t as
|
|
8
|
+
export { t as BInputStatus, e as BInputVariant };
|
|
7
9
|
|
|
8
10
|
//# sourceMappingURL=design-system113.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"design-system113.js","names":[],"sources":["../src/components/BMasonry/BMasonry.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport type {\n BMasonryBreakpoint,\n BMasonryClassNames,\n BMasonryItem,\n BMasonryLayoutChangePayload,\n BMasonryResponsive,\n BMasonryStyles,\n} from './types';\n\n// ─── Props ────────────────────────────────────────────────────────────────────\n\nconst {\n columns = 3,\n // eslint-disable-next-line vue/require-valid-default-prop\n gutter = 0,\n items = [],\n fresh = false,\n classNames,\n styles,\n} = defineProps<{\n /**\n * Number of columns. Accepts a fixed number or a breakpoint map.\n * @example 3\n * @example { xs: 1, sm: 2, md: 3, lg: 4 }\n * @default 3\n */\n columns?: BMasonryResponsive;\n\n /**\n * Gap between items in pixels. Accepts a fixed value, a [colGap, rowGap] tuple,\n * or a breakpoint map for responsive gaps.\n * @example 16\n * @example [16, 8]\n * @example { xs: 8, md: 16 }\n * @default 0\n */\n gutter?: BMasonryResponsive | [BMasonryResponsive, BMasonryResponsive];\n\n /**\n * Array of masonry items to render.\n * @default []\n */\n items?: BMasonryItem[];\n\n /**\n * When true, observe every item's size so the layout re-flows when children resize.\n * Requires ResizeObserver support; degrades gracefully when unavailable.\n * @default false\n */\n fresh?: boolean;\n\n /**\n * Customize CSS classes on semantic DOM elements (`root`, `column`, `item`).\n * Can be a plain object or a per-item function `(item, columnIndex) => classes`.\n */\n classNames?: BMasonryClassNames;\n\n /**\n * Customize inline styles on semantic DOM elements (`root`, `column`, `item`).\n * Can be a plain object or a per-item function `(item, columnIndex) => styles`.\n */\n styles?: BMasonryStyles;\n}>();\n\n// ─── Emits ────────────────────────────────────────────────────────────────────\n\nconst emit = defineEmits<{\n /**\n * Fires after each layout recalculation with the resolved column count and\n * the column assignment map (item key → 0-based column index).\n */\n layoutChange: [payload: BMasonryLayoutChangePayload];\n}>();\n\n// ─── Slots ────────────────────────────────────────────────────────────────────\n\ndefineSlots<{\n /**\n * Custom rendering for each item. Receives `{ item: BMasonryItem, index: number, column: number }`.\n */\n item?: (props: { item: BMasonryItem; index: number; column: number }) => unknown;\n\n /**\n * Default slot used when no `items` prop is provided — raw child nodes are\n * distributed across columns automatically.\n */\n default?: (props: Record<string, never>) => unknown;\n}>();\n\n// ─── Responsive helpers ───────────────────────────────────────────────────────\n\nconst BREAKPOINTS: Record<BMasonryBreakpoint, number> = {\n xs: 0,\n sm: 576,\n md: 768,\n lg: 992,\n xl: 1200,\n xxl: 1600,\n};\n\nfunction resolveResponsive(value: BMasonryResponsive, width: number): number {\n if (typeof value === 'number') return Math.max(1, value);\n\n // Breakpoint map — pick the largest breakpoint that still fits\n const keys = (Object.keys(BREAKPOINTS) as BMasonryBreakpoint[]).sort(\n (a, b) => BREAKPOINTS[b] - BREAKPOINTS[a],\n );\n\n for (const bp of keys) {\n if (width >= BREAKPOINTS[bp] && value[bp] !== undefined) {\n return Math.max(1, value[bp]!);\n }\n }\n // Fallback to smallest defined value\n const smallest = (Object.keys(value) as BMasonryBreakpoint[]).sort(\n (a, b) => BREAKPOINTS[a] - BREAKPOINTS[b],\n )[0];\n return smallest ? Math.max(1, value[smallest]!) : 1;\n}\n\n// ─── Container width tracking ─────────────────────────────────────────────────\n\nconst rootEl = ref<HTMLElement | null>(null);\nconst containerWidth = ref(0);\n\nlet containerObserver: ResizeObserver | null = null;\n\nfunction updateWidth() {\n if (rootEl.value) {\n containerWidth.value = rootEl.value.offsetWidth;\n }\n}\n\n// ─── Item height tracking (fresh mode) ────────────────────────────────────────\n\nconst itemHeights = ref<Record<string | number, number>>({});\nlet itemObserver: ResizeObserver | null = null;\nconst itemEls = ref<Map<string | number, Element>>(new Map());\n\nfunction registerItemEl(key: string | number, el: Element | null) {\n if (el) {\n itemEls.value.set(key, el);\n if (fresh && itemObserver) {\n itemObserver.observe(el);\n }\n } else {\n const old = itemEls.value.get(key);\n if (old && itemObserver) itemObserver.unobserve(old);\n itemEls.value.delete(key);\n const next = { ...itemHeights.value };\n delete next[key];\n itemHeights.value = next;\n }\n}\n\nfunction setupItemObserver() {\n if (!fresh || typeof ResizeObserver === 'undefined') return;\n itemObserver = new ResizeObserver((entries) => {\n let changed = false;\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const key = el.dataset.masonryKey;\n if (key !== undefined) {\n const h = entry.contentRect.height;\n if (itemHeights.value[key] !== h) {\n itemHeights.value = { ...itemHeights.value, [key]: h };\n changed = true;\n }\n }\n }\n if (changed) {\n // trigger layout recompute (handled reactively via computed)\n }\n });\n // Observe any already-mounted elements\n itemEls.value.forEach((el) => itemObserver!.observe(el));\n}\n\n// ─── Core layout algorithm ────────────────────────────────────────────────────\n\nconst resolvedColumns = computed(() => resolveResponsive(columns, containerWidth.value));\n\nconst resolvedGutter = computed<[number, number]>(() => {\n const g = gutter;\n if (Array.isArray(g)) {\n const colGap = resolveResponsive(g[0] as BMasonryResponsive, containerWidth.value);\n const rowGap = resolveResponsive(g[1] as BMasonryResponsive, containerWidth.value);\n return [colGap, rowGap];\n }\n const v = resolveResponsive(g as BMasonryResponsive, containerWidth.value);\n return [v, v];\n});\n\n/** Distribute items across columns using the \"shortest column first\" strategy. */\nconst columnBuckets = computed<{ item: BMasonryItem; originalIndex: number }[][]>(() => {\n const cols = resolvedColumns.value;\n const buckets: { item: BMasonryItem; originalIndex: number }[][] = Array.from(\n { length: cols },\n () => [],\n );\n const heights = Array<number>(cols).fill(0);\n const [, rowGap] = resolvedGutter.value;\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n let targetCol: number;\n\n if (item.column !== undefined) {\n // Pinned column (1-based → 0-based, clamped)\n targetCol = Math.max(0, Math.min(cols - 1, item.column - 1));\n } else {\n // Shortest column\n targetCol = heights.indexOf(Math.min(...heights));\n }\n\n buckets[targetCol].push({ item, originalIndex: i });\n const h = itemHeights.value[item.key] ?? item.height ?? 0;\n heights[targetCol] += h + (buckets[targetCol].length > 1 ? rowGap : 0);\n }\n\n return buckets;\n});\n\nconst layoutColumnMap = computed(() => {\n const cols = resolvedColumns.value;\n const map: Record<string | number, number> = {};\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const bucket = columnBuckets.value.findIndex((b) =>\n b.some((entry) => entry.item.key === item.key),\n );\n if (bucket >= 0) map[item.key] = bucket;\n }\n return { columns: cols, columnMap: map };\n});\n\nwatch(layoutColumnMap, (val) => {\n emit('layoutChange', val);\n}, { immediate: true });\n\n// ─── CSS class/style helpers ──────────────────────────────────────────────────\n\nfunction getItemClasses(item: BMasonryItem, columnIndex: number) {\n const base = ['b-masonry__item'];\n if (!classNames) return base;\n\n if (typeof classNames === 'function') {\n const extra = classNames(item, columnIndex);\n if (extra) base.push(...(Array.isArray(extra) ? extra : [extra as string]));\n } else if (typeof classNames.item === 'function') {\n const extra = classNames.item(item, columnIndex);\n if (extra) base.push(...(Array.isArray(extra) ? extra : [extra as string]));\n } else if (typeof classNames.item === 'string') {\n base.push(classNames.item);\n }\n return base;\n}\n\nfunction getItemStyles(item: BMasonryItem, columnIndex: number): Record<string, string> {\n if (!styles) return {};\n if (typeof styles === 'function') return styles(item, columnIndex) ?? {};\n if (typeof styles.item === 'function') return styles.item(item, columnIndex) ?? {};\n if (styles.item && typeof styles.item === 'object') return styles.item as Record<string, string>;\n return {};\n}\n\nfunction getColumnClasses(_colIndex: number): string[] {\n const base = ['b-masonry__column'];\n if (!classNames || typeof classNames === 'function') return base;\n if (classNames.column) base.push(classNames.column);\n return base;\n}\n\nfunction getColumnStyles(_colIndex: number): Record<string, string> {\n if (!styles || typeof styles === 'function') return {};\n return (styles.column as Record<string, string>) ?? {};\n}\n\nconst rootClasses = computed(() => {\n const base = ['b-masonry'];\n if (!classNames || typeof classNames === 'function') return base;\n if (classNames.root) base.push(classNames.root);\n return base;\n});\n\nconst rootStyles = computed(() => {\n const base: Record<string, string> = {\n '--b-masonry-columns': String(resolvedColumns.value),\n '--b-masonry-col-gap': `${resolvedGutter.value[0]}px`,\n '--b-masonry-row-gap': `${resolvedGutter.value[1]}px`,\n };\n if (styles && typeof styles === 'object' && !('root' in styles) === false) {\n const s = styles as { root?: Record<string, string> };\n if (s.root) Object.assign(base, s.root);\n }\n return base;\n});\n\n// ─── Lifecycle ────────────────────────────────────────────────────────────────\n\nonMounted(() => {\n updateWidth();\n\n if (typeof ResizeObserver !== 'undefined') {\n containerObserver = new ResizeObserver(() => updateWidth());\n if (rootEl.value) containerObserver.observe(rootEl.value);\n } else {\n // SSR / no ResizeObserver: listen to window resize\n window.addEventListener('resize', updateWidth);\n }\n\n if (fresh) setupItemObserver();\n});\n\nwatch(\n () => fresh,\n (enabled) => {\n if (enabled) {\n setupItemObserver();\n } else {\n itemObserver?.disconnect();\n itemObserver = null;\n itemHeights.value = {};\n }\n },\n);\n\nonBeforeUnmount(() => {\n containerObserver?.disconnect();\n itemObserver?.disconnect();\n window.removeEventListener('resize', updateWidth);\n});\n</script>\n\n<template>\n <!-- role=\"list\" lets screen readers announce item count -->\n <div\n ref=\"rootEl\"\n :class=\"rootClasses\"\n :style=\"rootStyles\"\n role=\"list\"\n aria-label=\"Masonry layout\"\n >\n <!-- Column-based layout: each column is a flex column -->\n <div\n v-for=\"(bucket, colIdx) in columnBuckets\"\n :key=\"colIdx\"\n :class=\"getColumnClasses(colIdx)\"\n :style=\"getColumnStyles(colIdx)\"\n role=\"presentation\"\n >\n <div\n v-for=\"{ item, originalIndex } in bucket\"\n :key=\"item.key\"\n :ref=\"(el) => registerItemEl(item.key, el as Element | null)\"\n :data-masonry-key=\"item.key\"\n :class=\"getItemClasses(item, colIdx)\"\n :style=\"getItemStyles(item, colIdx)\"\n role=\"listitem\"\n >\n <!-- Named item slot (prop-driven items) -->\n <slot v-if=\"$slots.item\" name=\"item\" :item=\"item\" :index=\"originalIndex\" :column=\"colIdx\" />\n <!-- Default slot fallback when using raw children (no items prop) -->\n <template v-else>\n <slot />\n </template>\n </div>\n </div>\n </div>\n</template>\n\n<style>\n/* ─────────────────────────────────────────────────────────────────────────────\n BMasonry — CSS custom properties (scoped to component root)\n ───────────────────────────────────────────────────────────────────────────── */\n.b-masonry {\n /* Layout tokens */\n --b-masonry-columns: 3;\n --b-masonry-col-gap: 0px;\n --b-masonry-row-gap: 0px;\n\n /* Item tokens */\n --b-masonry-item-transition-duration: 200ms;\n --b-masonry-item-transition-timing: ease;\n --b-masonry-item-border-radius: 0px;\n --b-masonry-item-bg: transparent;\n\n /* ── Layout ── */\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: var(--b-masonry-col-gap);\n width: 100%;\n box-sizing: border-box;\n}\n\n/* ── Column ── */\n.b-masonry__column {\n display: flex;\n flex: 1 1 0;\n min-width: 0;\n flex-direction: column;\n gap: var(--b-masonry-row-gap);\n}\n\n/* ── Item ── */\n.b-masonry__item {\n width: 100%;\n box-sizing: border-box;\n background: var(--b-masonry-item-bg);\n border-radius: var(--b-masonry-item-border-radius);\n transition:\n transform var(--b-masonry-item-transition-duration) var(--b-masonry-item-transition-timing),\n opacity var(--b-masonry-item-transition-duration) var(--b-masonry-item-transition-timing);\n}\n\n/* ── Dark mode ── */\n[data-prefers-color='dark'] .b-masonry {\n /* Tokens that shift in dark mode — override as needed by the consumer */\n --b-masonry-item-bg: transparent;\n}\n\n@media (prefers-color-scheme: dark) {\n [data-prefers-color='system'] .b-masonry {\n /* Tokens that shift in dark mode — override as needed by the consumer */\n --b-masonry-item-bg: transparent;\n }\n}\n\n/* ── Reduced motion ── */\n@media (prefers-reduced-motion: reduce) {\n .b-masonry {\n --b-masonry-item-transition-duration: 0ms;\n }\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"design-system113.js","names":[],"sources":["../src/components/BInput/types.ts"],"sourcesContent":["export enum BInputVariant {\n Outlined = 'outlined',\n Filled = 'filled',\n Borderless = 'borderless',\n Underlined = 'underlined',\n}\n\nexport enum BInputStatus {\n Error = 'error',\n Warning = 'warning',\n}\n\nexport interface BInputCountConfig {\n /** Custom character count strategy (e.g., for emoji or CJK). */\n strategy?: (value: string) => number;\n /** Maximum count to display. Triggers exceedFormatter when exceeded. */\n max?: number;\n /** Formatter when count exceeds max. */\n exceedFormatter?: (value: string, config: { max: number }) => string;\n /** Whether to show the count indicator. */\n show?: boolean | ((args: { value: string; count: number; maxLength?: number }) => string);\n}\n\nexport interface BInputFocusOptions {\n preventScroll?: boolean;\n cursor?: 'start' | 'end' | 'all';\n}\n"],"mappings":";AAAA,IAAY,IAAL,yBAAA,GAAA;QACL,EAAA,WAAA,YACA,EAAA,SAAA,UACA,EAAA,aAAA,cACA,EAAA,aAAA;KACD,EAEW,IAAL,yBAAA,GAAA;QACL,EAAA,QAAA,SACA,EAAA,UAAA;KACD"}
|
package/dist/design-system114.js
CHANGED
|
@@ -1,12 +1,212 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { BCommonSize as e } from "./design-system3.js";
|
|
2
|
+
import { useComponentId as t } from "./design-system10.js";
|
|
3
|
+
import { BInputStatus as n, BInputVariant as r } from "./design-system113.js";
|
|
4
|
+
import { computed as i, createCommentVNode as a, createElementBlock as o, createElementVNode as s, defineComponent as c, mergeModels as l, normalizeClass as u, openBlock as d, ref as f, renderSlot as p, toDisplayString as m, unref as h, useModel as g, useSlots as _, watch as v, withModifiers as y } from "vue";
|
|
5
|
+
//#region src/components/BInput/BInput.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var b = {
|
|
7
|
+
key: 0,
|
|
8
|
+
class: "b-input__addon b-input__addon--before"
|
|
9
|
+
}, x = { class: "b-input__wrapper" }, S = {
|
|
10
|
+
key: 0,
|
|
11
|
+
class: "b-input__prefix",
|
|
12
|
+
"aria-hidden": "true"
|
|
13
|
+
}, C = [
|
|
14
|
+
"id",
|
|
15
|
+
"value",
|
|
16
|
+
"type",
|
|
17
|
+
"placeholder",
|
|
18
|
+
"disabled",
|
|
19
|
+
"readonly",
|
|
20
|
+
"maxlength",
|
|
21
|
+
"aria-invalid",
|
|
22
|
+
"aria-describedby"
|
|
23
|
+
], w = {
|
|
24
|
+
key: 1,
|
|
25
|
+
class: "b-input__clear-wrapper"
|
|
26
|
+
}, T = {
|
|
27
|
+
key: 2,
|
|
28
|
+
class: "b-input__password-toggle-wrapper"
|
|
29
|
+
}, E = ["aria-label", "aria-pressed"], D = {
|
|
30
|
+
key: 0,
|
|
31
|
+
viewBox: "64 64 896 896",
|
|
32
|
+
width: "1em",
|
|
33
|
+
height: "1em",
|
|
34
|
+
fill: "currentColor",
|
|
35
|
+
"aria-hidden": "true"
|
|
36
|
+
}, O = {
|
|
37
|
+
key: 1,
|
|
38
|
+
viewBox: "64 64 896 896",
|
|
39
|
+
width: "1em",
|
|
40
|
+
height: "1em",
|
|
41
|
+
fill: "currentColor",
|
|
42
|
+
"aria-hidden": "true"
|
|
43
|
+
}, k = {
|
|
44
|
+
key: 3,
|
|
45
|
+
class: "b-input__suffix",
|
|
46
|
+
"aria-hidden": "true"
|
|
47
|
+
}, A = ["id"], j = {
|
|
48
|
+
key: 1,
|
|
49
|
+
class: "b-input__addon b-input__addon--after"
|
|
50
|
+
}, M = /* @__PURE__ */ c({
|
|
51
|
+
inheritAttrs: !1,
|
|
52
|
+
__name: "BInput",
|
|
53
|
+
props: /* @__PURE__ */ l({
|
|
54
|
+
size: { default: () => e.Medium },
|
|
55
|
+
variant: { default: () => r.Outlined },
|
|
56
|
+
disabled: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: !1
|
|
59
|
+
},
|
|
60
|
+
readOnly: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
default: !1
|
|
63
|
+
},
|
|
64
|
+
status: {},
|
|
65
|
+
type: { default: "text" },
|
|
66
|
+
maxLength: {},
|
|
67
|
+
placeholder: {},
|
|
68
|
+
id: {},
|
|
69
|
+
allowClear: {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
default: !1
|
|
72
|
+
},
|
|
73
|
+
showCount: {
|
|
74
|
+
type: [Boolean, Function],
|
|
75
|
+
default: !1
|
|
76
|
+
},
|
|
77
|
+
count: {}
|
|
78
|
+
}, {
|
|
79
|
+
modelValue: { default: "" },
|
|
80
|
+
modelModifiers: {}
|
|
81
|
+
}),
|
|
82
|
+
emits: /* @__PURE__ */ l([
|
|
83
|
+
"change",
|
|
84
|
+
"pressEnter",
|
|
85
|
+
"clear",
|
|
86
|
+
"focus",
|
|
87
|
+
"blur"
|
|
88
|
+
], ["update:modelValue"]),
|
|
89
|
+
setup(e, { expose: r, emit: c }) {
|
|
90
|
+
let l = _(), M = c, N = g(e, "modelValue"), { componentUID: P } = t(), F = i(() => e.id ?? `b-input-${P.value}`), I = f(null), L = f(!1), R = f(!1), z = i(() => !!l.addonBefore), B = i(() => !!l.addonAfter), V = i(() => !!l.prefix), H = i(() => !!l.suffix), U = i(() => e.type === "password"), W = i(() => U.value), G = i(() => U.value ? R.value ? "text" : "password" : e.type), K = i(() => {
|
|
91
|
+
let t = N.value ?? "";
|
|
92
|
+
return e.count?.strategy ? e.count.strategy(t) : t.length;
|
|
93
|
+
}), q = i(() => e.count?.max ?? e.maxLength), J = i(() => e.count?.show === !1 ? !1 : e.count?.show === void 0 ? !!e.showCount : !0), Y = i(() => {
|
|
94
|
+
let t = N.value ?? "", n = K.value;
|
|
95
|
+
return typeof e.count?.show == "function" ? e.count.show({
|
|
96
|
+
value: t,
|
|
97
|
+
count: n,
|
|
98
|
+
maxLength: q.value
|
|
99
|
+
}) : typeof e.showCount == "function" ? e.showCount({
|
|
100
|
+
value: t,
|
|
101
|
+
count: n,
|
|
102
|
+
maxLength: q.value
|
|
103
|
+
}) : q.value === void 0 ? `${n}` : `${n} / ${q.value}`;
|
|
104
|
+
}), X = i(() => q.value === void 0 ? !1 : K.value > q.value), Z = i(() => e.allowClear && !!N.value && !e.disabled && !e.readOnly), Q = (t) => {
|
|
105
|
+
let n = t.target, r = n.value;
|
|
106
|
+
e.count?.exceedFormatter && q.value !== void 0 && (e.count.strategy ?? ((e) => e.length))(r) > q.value && (r = e.count.exceedFormatter(r, { max: q.value }), n.value = r), N.value = r, M("change", r, t);
|
|
107
|
+
}, $ = (e) => {
|
|
108
|
+
e.key === "Enter" && M("pressEnter", e);
|
|
109
|
+
}, ee = (e) => {
|
|
110
|
+
L.value = !0, M("focus", e);
|
|
111
|
+
}, te = (e) => {
|
|
112
|
+
L.value = !1, M("blur", e);
|
|
113
|
+
}, ne = () => {
|
|
114
|
+
N.value = "", M("clear"), M("change", "", new Event("change")), I.value?.focus();
|
|
115
|
+
}, re = () => {
|
|
116
|
+
R.value = !R.value, I.value?.focus();
|
|
117
|
+
};
|
|
118
|
+
return v(N, (t) => {
|
|
119
|
+
e.count?.exceedFormatter && q.value !== void 0 && (e.count.strategy ?? ((e) => e.length))(t) > q.value && (N.value = e.count.exceedFormatter(t, { max: q.value }));
|
|
120
|
+
}), r({
|
|
121
|
+
focus: (e) => {
|
|
122
|
+
if (I.value?.focus({ preventScroll: e?.preventScroll }), e?.cursor && I.value) {
|
|
123
|
+
let t = I.value.value.length;
|
|
124
|
+
switch (e.cursor) {
|
|
125
|
+
case "start":
|
|
126
|
+
I.value.setSelectionRange(0, 0);
|
|
127
|
+
break;
|
|
128
|
+
case "end":
|
|
129
|
+
I.value.setSelectionRange(t, t);
|
|
130
|
+
break;
|
|
131
|
+
case "all":
|
|
132
|
+
I.value.setSelectionRange(0, t);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
blur: () => {
|
|
138
|
+
I.value?.blur();
|
|
139
|
+
}
|
|
140
|
+
}), (t, r) => (d(), o("span", { class: u(["b-input", [
|
|
141
|
+
`b-input--${e.size}`,
|
|
142
|
+
`b-input--${e.variant}`,
|
|
143
|
+
{
|
|
144
|
+
"b-input--focused": L.value,
|
|
145
|
+
"b-input--disabled": e.disabled,
|
|
146
|
+
"b-input--readonly": e.readOnly,
|
|
147
|
+
"b-input--error": e.status === h(n).Error,
|
|
148
|
+
"b-input--warning": e.status === h(n).Warning,
|
|
149
|
+
"b-input--has-addon-before": z.value,
|
|
150
|
+
"b-input--has-addon-after": B.value,
|
|
151
|
+
"b-input--over-count": X.value
|
|
152
|
+
}
|
|
153
|
+
]]) }, [
|
|
154
|
+
z.value ? (d(), o("span", b, [p(t.$slots, "addonBefore", {}, void 0, !0)])) : a("", !0),
|
|
155
|
+
s("span", x, [
|
|
156
|
+
V.value ? (d(), o("span", S, [p(t.$slots, "prefix", {}, void 0, !0)])) : a("", !0),
|
|
157
|
+
s("input", {
|
|
158
|
+
id: F.value,
|
|
159
|
+
ref_key: "inputRef",
|
|
160
|
+
ref: I,
|
|
161
|
+
value: N.value,
|
|
162
|
+
type: G.value,
|
|
163
|
+
placeholder: e.placeholder,
|
|
164
|
+
disabled: e.disabled,
|
|
165
|
+
readonly: e.readOnly,
|
|
166
|
+
maxlength: e.maxLength && !e.count?.exceedFormatter ? e.maxLength : void 0,
|
|
167
|
+
"aria-invalid": e.status === h(n).Error ? !0 : void 0,
|
|
168
|
+
"aria-describedby": J.value ? `${F.value}-count` : void 0,
|
|
169
|
+
class: "b-input__input",
|
|
170
|
+
onInput: Q,
|
|
171
|
+
onKeydown: $,
|
|
172
|
+
onFocus: ee,
|
|
173
|
+
onBlur: te
|
|
174
|
+
}, null, 40, C),
|
|
175
|
+
Z.value ? (d(), o("span", w, [s("button", {
|
|
176
|
+
type: "button",
|
|
177
|
+
class: "b-input__clear",
|
|
178
|
+
"aria-label": "Clear input",
|
|
179
|
+
tabindex: "-1",
|
|
180
|
+
onMousedown: y(ne, ["prevent"])
|
|
181
|
+
}, [...r[0] ||= [s("svg", {
|
|
182
|
+
viewBox: "64 64 896 896",
|
|
183
|
+
width: "1em",
|
|
184
|
+
height: "1em",
|
|
185
|
+
fill: "currentColor",
|
|
186
|
+
"aria-hidden": "true"
|
|
187
|
+
}, [s("path", { d: "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z" })], -1)]], 32)])) : a("", !0),
|
|
188
|
+
W.value ? (d(), o("span", T, [s("button", {
|
|
189
|
+
type: "button",
|
|
190
|
+
class: "b-input__password-toggle",
|
|
191
|
+
"aria-label": R.value ? "Hide password" : "Show password",
|
|
192
|
+
"aria-pressed": R.value,
|
|
193
|
+
tabindex: "-1",
|
|
194
|
+
onMousedown: y(re, ["prevent"])
|
|
195
|
+
}, [R.value ? (d(), o("svg", O, [...r[2] ||= [s("path", { d: "M942.2 486.2C847.4 286.5 704.1 186 512 186c-53.8 0-104.5 9.6-151.7 28.4L212.7 67.2a8.03 8.03 0 00-11.3 0L160 108.5a8.03 8.03 0 000 11.3l740.3 740.3a8.03 8.03 0 0011.3 0l41.3-41.3a8.03 8.03 0 000-11.3l-106.8-106.8c53.1-57.6 94.3-127.4 106.2-153a60.3 60.3 0 000-51.5zM512 730c-114.9 0-208-93.1-208-208 0-40.1 11.4-77.6 31-109.4L297 374.6C270.6 414.1 256 466 256 522c0 141.4 114.6 256 256 256 56 0 107.9-18 150.2-48.5l-38-38C597.6 714.6 556.1 730 512 730zm0-520c114.9 0 208 93.1 208 208 0 40.1-11.4 77.6-31 109.4L727 565.4C753.4 525.9 768 474 768 418c0-141.4-114.6-256-256-256-56 0-107.9 18-150.2 48.5l38 38C426.4 225.4 467.9 210 512 210z" }, null, -1)]])) : (d(), o("svg", D, [...r[1] ||= [s("path", { d: "M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 730c-114.9 0-208-93.1-208-208s93.1-208 208-208 208 93.1 208 208-93.1 208-208 208zm0-319.8c-61.7 0-111.8 50.1-111.8 111.8S450.3 633.8 512 633.8 623.8 583.7 623.8 522 573.7 410.2 512 410.2z" }, null, -1)]]))], 40, E)])) : a("", !0),
|
|
196
|
+
H.value ? (d(), o("span", k, [p(t.$slots, "suffix", {}, void 0, !0)])) : a("", !0),
|
|
197
|
+
J.value ? (d(), o("span", {
|
|
198
|
+
key: 4,
|
|
199
|
+
id: `${F.value}-count`,
|
|
200
|
+
class: u(["b-input__count", { "b-input__count--over": X.value }]),
|
|
201
|
+
"aria-live": "polite",
|
|
202
|
+
"aria-atomic": "true"
|
|
203
|
+
}, m(Y.value), 11, A)) : a("", !0)
|
|
204
|
+
]),
|
|
205
|
+
B.value ? (d(), o("span", j, [p(t.$slots, "addonAfter", {}, void 0, !0)])) : a("", !0)
|
|
206
|
+
], 2));
|
|
207
|
+
}
|
|
208
|
+
});
|
|
9
209
|
//#endregion
|
|
10
|
-
export {
|
|
210
|
+
export { M as default };
|
|
11
211
|
|
|
12
212
|
//# sourceMappingURL=design-system114.js.map
|