@7pmlabs/design-system 2.0.9 → 2.1.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 +4 -4
- package/dist/design-system.css +1 -1
- package/dist/design-system.js +65 -59
- package/dist/design-system100.js +1 -1
- package/dist/design-system100.js.map +1 -1
- package/dist/design-system101.js +87 -53
- package/dist/design-system101.js.map +1 -1
- package/dist/design-system103.js +5 -13
- package/dist/design-system103.js.map +1 -1
- package/dist/design-system104.js +53 -108
- package/dist/design-system104.js.map +1 -1
- package/dist/{design-system102.js → design-system105.js} +1 -1
- package/dist/{design-system102.js.map → design-system105.js.map} +1 -1
- package/dist/design-system106.js +13 -6
- package/dist/design-system106.js.map +1 -1
- package/dist/design-system107.js +93 -190
- package/dist/design-system107.js.map +1 -1
- package/dist/design-system109.js +2 -2
- package/dist/design-system109.js.map +1 -1
- package/dist/design-system110.js +183 -484
- package/dist/design-system110.js.map +1 -1
- package/dist/design-system112.js +5 -4
- package/dist/design-system112.js.map +1 -1
- package/dist/design-system113.js +507 -7
- package/dist/design-system113.js.map +1 -1
- package/dist/design-system115.js +8 -0
- package/dist/design-system115.js.map +1 -0
- package/dist/design-system116.js +7 -6
- package/dist/design-system116.js.map +1 -1
- package/dist/design-system117.js +154 -169
- package/dist/design-system117.js.map +1 -1
- package/dist/design-system119.js +2 -2
- package/dist/design-system119.js.map +1 -1
- package/dist/design-system120.js +210 -149
- package/dist/design-system120.js.map +1 -1
- package/dist/design-system122.js +5 -4
- package/dist/design-system122.js.map +1 -1
- package/dist/design-system123.js +160 -9
- package/dist/design-system123.js.map +1 -1
- package/dist/design-system125.js +8 -0
- package/dist/design-system125.js.map +1 -0
- package/dist/design-system126.js +176 -6
- package/dist/design-system126.js.map +1 -1
- package/dist/design-system128.js +8 -0
- package/dist/design-system128.js.map +1 -0
- package/dist/design-system129.js +213 -5
- package/dist/design-system129.js.map +1 -1
- package/dist/design-system131.js +5 -90
- package/dist/design-system131.js.map +1 -1
- package/dist/design-system132.js +166 -0
- package/dist/design-system132.js.map +1 -0
- package/dist/design-system134.js +5 -42
- package/dist/design-system134.js.map +1 -1
- package/dist/design-system135.js +12 -0
- package/dist/design-system135.js.map +1 -0
- package/dist/design-system136.js +274 -5
- package/dist/design-system136.js.map +1 -1
- package/dist/design-system138.js +9 -0
- package/dist/{design-system124.js.map → design-system138.js.map} +1 -1
- package/dist/design-system139.js +16 -5
- package/dist/design-system139.js.map +1 -1
- package/dist/design-system141.js +8 -0
- package/dist/{design-system127.js.map → design-system141.js.map} +1 -1
- package/dist/design-system142.js +12 -5
- package/dist/design-system142.js.map +1 -1
- package/dist/design-system143.js +78 -83
- package/dist/design-system143.js.map +1 -1
- package/dist/design-system145.js +1 -1
- package/dist/design-system145.js.map +1 -1
- package/dist/design-system146.js +42 -9
- package/dist/design-system146.js.map +1 -1
- package/dist/design-system148.js +3 -2
- package/dist/design-system148.js.map +1 -1
- package/dist/design-system149.js +230 -18
- package/dist/design-system149.js.map +1 -1
- package/dist/design-system151.js +5 -158
- package/dist/design-system151.js.map +1 -1
- package/dist/{design-system140.js → design-system152.js} +6 -6
- package/dist/{design-system140.js.map → design-system152.js.map} +1 -1
- package/dist/design-system154.js +5 -307
- package/dist/design-system154.js.map +1 -1
- package/dist/design-system155.js +98 -0
- package/dist/design-system155.js.map +1 -0
- package/dist/design-system157.js +5 -240
- package/dist/design-system157.js.map +1 -1
- package/dist/design-system158.js +12 -0
- package/dist/design-system158.js.map +1 -0
- package/dist/design-system159.js +37 -5
- package/dist/design-system159.js.map +1 -1
- package/dist/design-system160.js +4 -189
- package/dist/design-system160.js.map +1 -1
- package/dist/design-system161.js +24 -0
- package/dist/{design-system150.js.map → design-system161.js.map} +1 -1
- package/dist/design-system162.js +2 -3
- package/dist/design-system162.js.map +1 -1
- package/dist/design-system163.js +158 -3
- package/dist/design-system163.js.map +1 -1
- package/dist/{design-system153.js → design-system165.js} +2 -2
- package/dist/{design-system153.js.map → design-system165.js.map} +1 -1
- package/dist/design-system166.js +307 -6
- package/dist/design-system166.js.map +1 -1
- package/dist/{design-system156.js → design-system168.js} +2 -2
- package/dist/{design-system156.js.map → design-system168.js.map} +1 -1
- package/dist/design-system169.js +167 -6
- package/dist/design-system169.js.map +1 -1
- package/dist/design-system171.js +8 -0
- package/dist/design-system171.js.map +1 -0
- package/dist/design-system172.js +240 -6
- package/dist/design-system172.js.map +1 -1
- package/dist/design-system174.js +8 -0
- package/dist/design-system174.js.map +1 -0
- package/dist/design-system175.js +189 -6
- package/dist/design-system175.js.map +1 -1
- package/dist/design-system177.js +8 -0
- package/dist/design-system177.js.map +1 -0
- package/dist/design-system178.js +3 -5
- package/dist/design-system178.js.map +1 -1
- package/dist/design-system179.js +58 -11
- package/dist/design-system179.js.map +1 -1
- package/dist/design-system181.js +9 -0
- package/dist/design-system181.js.map +1 -0
- package/dist/design-system182.js +56 -6
- package/dist/design-system182.js.map +1 -1
- package/dist/design-system184.js +9 -0
- package/dist/{design-system167.js.map → design-system184.js.map} +1 -1
- package/dist/design-system185.js +69 -5
- package/dist/design-system185.js.map +1 -1
- package/dist/design-system187.js +9 -0
- package/dist/{design-system170.js.map → design-system187.js.map} +1 -1
- package/dist/design-system188.js +182 -5
- package/dist/design-system188.js.map +1 -1
- package/dist/design-system190.js +9 -0
- package/dist/design-system190.js.map +1 -0
- package/dist/design-system191.js +115 -5
- package/dist/design-system191.js.map +1 -1
- package/dist/design-system193.js +8 -0
- package/dist/{design-system176.js.map → design-system193.js.map} +1 -1
- package/dist/design-system194.js +11 -5
- package/dist/design-system194.js.map +1 -1
- package/dist/design-system195.js +453 -24
- package/dist/design-system195.js.map +1 -1
- package/dist/design-system197.js +5 -4
- package/dist/design-system197.js.map +1 -1
- package/dist/design-system198.js +20 -16
- 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 +70 -314
- package/dist/design-system201.js.map +1 -1
- package/dist/design-system203.js +1 -1
- package/dist/design-system203.js.map +1 -1
- package/dist/design-system204.js +24 -89
- 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 +26 -17
- package/dist/design-system207.js.map +1 -1
- package/dist/design-system209.js +5 -3
- package/dist/design-system209.js.map +1 -1
- package/dist/design-system210.js +22 -408
- package/dist/design-system210.js.map +1 -1
- package/dist/design-system212.js +1 -1
- package/dist/design-system212.js.map +1 -1
- package/dist/design-system213.js +24 -52
- 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 +329 -85
- package/dist/design-system216.js.map +1 -1
- package/dist/design-system218.js +5 -108
- package/dist/design-system218.js.map +1 -1
- package/dist/design-system219.js +103 -0
- package/dist/design-system219.js.map +1 -0
- package/dist/design-system221.js +5 -106
- package/dist/design-system221.js.map +1 -1
- package/dist/design-system222.js +22 -0
- package/dist/{design-system208.js.map → design-system222.js.map} +1 -1
- package/dist/design-system223.js +4 -6
- package/dist/design-system223.js.map +1 -1
- package/dist/design-system224.js +3 -737
- package/dist/design-system224.js.map +1 -1
- package/dist/design-system225.js +422 -0
- package/dist/design-system225.js.map +1 -0
- package/dist/design-system227.js +5 -11
- package/dist/design-system227.js.map +1 -1
- package/dist/design-system228.js +51 -517
- package/dist/design-system228.js.map +1 -1
- package/dist/design-system230.js +1 -1
- package/dist/design-system230.js.map +1 -1
- package/dist/design-system231.js +88 -3
- package/dist/design-system231.js.map +1 -1
- package/dist/design-system232.js +4 -46
- package/dist/design-system232.js.map +1 -1
- package/dist/design-system233.js +108 -4
- package/dist/design-system233.js.map +1 -1
- package/dist/{design-system220.js → design-system235.js} +2 -2
- package/dist/{design-system220.js.map → design-system235.js.map} +1 -1
- package/dist/design-system236.js +106 -5
- package/dist/design-system236.js.map +1 -1
- package/dist/design-system238.js +9 -0
- package/dist/design-system238.js.map +1 -0
- package/dist/design-system239.js +737 -5
- package/dist/design-system239.js.map +1 -1
- package/dist/{design-system226.js → design-system241.js} +2 -2
- package/dist/{design-system226.js.map → design-system241.js.map} +1 -1
- package/dist/design-system242.js +3 -5
- package/dist/design-system242.js.map +1 -1
- package/dist/design-system243.js +42 -50
- package/dist/design-system243.js.map +1 -1
- package/dist/design-system244.js +1 -1
- package/dist/design-system244.js.map +1 -1
- package/dist/design-system245.js +254 -141
- package/dist/design-system245.js.map +1 -1
- package/dist/design-system247.js +1 -1
- package/dist/design-system247.js.map +1 -1
- package/dist/design-system248.js +119 -7
- package/dist/design-system248.js.map +1 -1
- package/dist/design-system250.js +8 -0
- package/dist/design-system250.js.map +1 -0
- package/dist/design-system251.js +172 -5
- package/dist/design-system251.js.map +1 -1
- package/dist/design-system253.js +8 -0
- package/dist/design-system253.js.map +1 -0
- package/dist/design-system254.js +11 -6
- package/dist/design-system254.js.map +1 -1
- package/dist/design-system255.js +525 -9
- package/dist/design-system255.js.map +1 -1
- package/dist/design-system257.js +8 -0
- package/dist/design-system257.js.map +1 -0
- package/dist/design-system258.js +112 -6
- package/dist/design-system258.js.map +1 -1
- package/dist/design-system260.js +5 -374
- package/dist/design-system260.js.map +1 -1
- package/dist/design-system261.js +57 -0
- package/dist/design-system261.js.map +1 -0
- package/dist/design-system262.js +4 -6
- package/dist/design-system262.js.map +1 -1
- package/dist/design-system263.js +173 -0
- package/dist/design-system263.js.map +1 -0
- package/dist/design-system265.js +8 -0
- package/dist/design-system265.js.map +1 -0
- package/dist/design-system266.js +10 -0
- package/dist/design-system266.js.map +1 -0
- package/dist/{design-system249.js → design-system267.js} +2 -2
- package/dist/{design-system249.js.map → design-system267.js.map} +1 -1
- package/dist/design-system269.js +8 -0
- package/dist/design-system269.js.map +1 -0
- package/dist/{design-system252.js → design-system270.js} +1 -1
- package/dist/{design-system252.js.map → design-system270.js.map} +1 -1
- package/dist/design-system272.js +9 -0
- package/dist/design-system272.js.map +1 -0
- package/dist/design-system273.js +12 -0
- package/dist/design-system273.js.map +1 -0
- package/dist/{design-system256.js → design-system274.js} +2 -2
- package/dist/{design-system256.js.map → design-system274.js.map} +1 -1
- package/dist/design-system276.js +9 -0
- package/dist/design-system276.js.map +1 -0
- package/dist/{design-system259.js → design-system277.js} +1 -1
- package/dist/{design-system259.js.map → design-system277.js.map} +1 -1
- package/dist/design-system278.js +377 -0
- package/dist/design-system278.js.map +1 -0
- package/dist/design-system280.js +9 -0
- package/dist/design-system280.js.map +1 -0
- package/dist/design-system69.js +182 -13
- package/dist/design-system69.js.map +1 -1
- package/dist/design-system71.js +8 -0
- package/dist/design-system71.js.map +1 -0
- package/dist/design-system72.js +13 -5
- package/dist/design-system72.js.map +1 -1
- package/dist/design-system73.js +677 -139
- package/dist/design-system73.js.map +1 -1
- package/dist/design-system75.js +1 -1
- package/dist/design-system75.js.map +1 -1
- package/dist/design-system76.js +152 -23
- package/dist/design-system76.js.map +1 -1
- package/dist/design-system78.js +5 -49
- package/dist/design-system78.js.map +1 -1
- package/dist/design-system79.js +32 -0
- package/dist/design-system79.js.map +1 -0
- package/dist/design-system80.js +2 -3
- package/dist/design-system80.js.map +1 -1
- package/dist/design-system81.js +38 -188
- package/dist/design-system81.js.map +1 -1
- package/dist/design-system83.js +1 -1
- package/dist/design-system83.js.map +1 -1
- package/dist/design-system84.js +199 -7
- package/dist/design-system84.js.map +1 -1
- package/dist/design-system86.js +8 -0
- package/dist/design-system86.js.map +1 -0
- package/dist/design-system87.js +7 -5
- package/dist/design-system87.js.map +1 -1
- package/dist/design-system88.js +264 -48
- package/dist/design-system88.js.map +1 -1
- package/dist/design-system90.js +1 -1
- package/dist/design-system90.js.map +1 -1
- package/dist/design-system91.js +57 -11
- package/dist/design-system91.js.map +1 -1
- package/dist/design-system93.js +8 -0
- package/dist/design-system93.js.map +1 -0
- package/dist/design-system94.js +11 -5
- package/dist/design-system94.js.map +1 -1
- package/dist/design-system95.js +92 -59
- package/dist/design-system95.js.map +1 -1
- package/dist/design-system97.js +1 -1
- package/dist/design-system97.js.map +1 -1
- package/dist/design-system98.js +56 -78
- package/dist/design-system98.js.map +1 -1
- package/dist/types/components/BContextMenu/BContextMenu.spec.d.ts +1 -0
- package/dist/types/components/BContextMenu/BContextMenu.vue.d.ts +42 -0
- package/dist/types/components/BContextMenu/index.d.ts +2 -0
- package/dist/types/components/BContextMenu/types.d.ts +23 -0
- package/dist/types/components/BInputTags/BInputTags.spec.d.ts +1 -0
- package/dist/types/components/BInputTags/BInputTags.vue.d.ts +54 -0
- package/dist/types/components/BInputTags/index.d.ts +1 -0
- package/dist/types/components/BLink/BLink.spec.d.ts +1 -0
- package/dist/types/components/BLink/BLink.vue.d.ts +100 -0
- package/dist/types/components/BLink/index.d.ts +1 -0
- package/dist/types/components/BListbox/BListbox.spec.d.ts +1 -0
- package/dist/types/components/BListbox/BListbox.vue.d.ts +52 -0
- package/dist/types/components/BListbox/index.d.ts +1 -0
- package/dist/types/components/BModal/BModal.spec.d.ts +1 -0
- package/dist/types/components/BPinInput/BPinInput.spec.d.ts +1 -0
- package/dist/types/components/BPinInput/BPinInput.vue.d.ts +43 -0
- package/dist/types/components/BPinInput/index.d.ts +1 -0
- package/dist/types/components/BProgress/BProgress.vue.d.ts +47 -2
- package/dist/types/components/BTextarea/BTextarea.spec.d.ts +1 -0
- package/dist/types/components/BTextarea/BTextarea.vue.d.ts +77 -0
- package/dist/types/components/BTextarea/index.d.ts +1 -0
- package/dist/types/components/index.d.ts +7 -1
- package/package.json +1 -1
- package/dist/design-system114.js +0 -212
- package/dist/design-system114.js.map +0 -1
- package/dist/design-system124.js +0 -277
- package/dist/design-system127.js +0 -19
- package/dist/design-system130.js +0 -15
- package/dist/design-system130.js.map +0 -1
- package/dist/design-system133.js +0 -8
- package/dist/design-system133.js.map +0 -1
- package/dist/design-system137.js +0 -236
- package/dist/design-system137.js.map +0 -1
- package/dist/design-system147.js +0 -40
- package/dist/design-system147.js.map +0 -1
- package/dist/design-system150.js +0 -7
- package/dist/design-system164.js +0 -61
- package/dist/design-system164.js.map +0 -1
- package/dist/design-system167.js +0 -59
- package/dist/design-system170.js +0 -72
- package/dist/design-system173.js +0 -185
- package/dist/design-system173.js.map +0 -1
- package/dist/design-system176.js +0 -118
- package/dist/design-system180.js +0 -465
- package/dist/design-system180.js.map +0 -1
- package/dist/design-system183.js +0 -38
- package/dist/design-system183.js.map +0 -1
- package/dist/design-system186.js +0 -91
- package/dist/design-system186.js.map +0 -1
- package/dist/design-system189.js +0 -38
- package/dist/design-system189.js.map +0 -1
- package/dist/design-system192.js +0 -31
- package/dist/design-system192.js.map +0 -1
- package/dist/design-system208.js +0 -7
- package/dist/design-system217.js +0 -7
- package/dist/design-system217.js.map +0 -1
- package/dist/design-system234.js +0 -286
- package/dist/design-system234.js.map +0 -1
- package/dist/design-system237.js +0 -122
- package/dist/design-system237.js.map +0 -1
- package/dist/design-system240.js +0 -115
- package/dist/design-system240.js.map +0 -1
- package/dist/design-system70.js +0 -699
- package/dist/design-system70.js.map +0 -1
- package/dist/design-system77.js +0 -7
- package/dist/design-system77.js.map +0 -1
- package/dist/design-system85.js +0 -276
- package/dist/design-system85.js.map +0 -1
- package/dist/design-system92.js +0 -102
- package/dist/design-system92.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
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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"}
|
|
1
|
+
{"version":3,"file":"design-system110.js","names":["$slots"],"sources":["../src/components/BForm/BFormItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useComponentId } from '@/composables/useComponentId.ts';\nimport { useValidationField } from '@/composables/useValidation.ts';\nimport { computed, inject, ref, watch } from 'vue';\nimport type { ZodType } from 'zod';\nimport { BFormContextKey } from './context.ts';\nimport {\n BFormLayout,\n BFormRequiredMark,\n BFormValidateStatus,\n BFormValidateTrigger,\n} from './types.ts';\n\nconst {\n label,\n name,\n schema,\n required = false,\n validateStatus,\n help,\n extra,\n colon = null,\n labelAlign,\n labelWidth,\n hidden = false,\n noStyle = false,\n hasFeedback = false,\n tooltip,\n layout,\n validateTrigger,\n} = defineProps<{\n /** Label text for the form item. */\n label?: string;\n /** Field name (used for validation and form data collection). */\n name?: string;\n /** Zod schema for field validation. */\n schema?: ZodType;\n /** Whether to display a required mark (visual only, does not add validation). */\n required?: boolean;\n /** Manual validation status override. */\n validateStatus?: `${BFormValidateStatus}`;\n /** Custom help/error message (overrides auto-generated). */\n help?: string;\n /** Extra hint text below the control. */\n extra?: string;\n /** Override parent form colon setting. Pass true/false to override, omit to inherit. */\n colon?: boolean | null;\n /** Override parent form label alignment. */\n labelAlign?: 'left' | 'right';\n /** Override parent form label width. */\n labelWidth?: string;\n /** Hide the form item visually but still validate. */\n hidden?: boolean;\n /** Render control only, no wrapper/label/margin. */\n noStyle?: boolean;\n /** Show validation feedback icon. */\n hasFeedback?: boolean;\n /** Override validation trigger. */\n validateTrigger?: `${BFormValidateTrigger}` | `${BFormValidateTrigger}`[];\n /** Tooltip text for the label. */\n tooltip?: string;\n /** Per-item layout override. */\n layout?: 'horizontal' | 'vertical';\n}>();\n\nconst formContext = inject(BFormContextKey, undefined);\n\nconst { componentUID } = useComponentId();\nconst fieldId = computed(() => `b-form-item-${name ? name + '-' : ''}${componentUID.value}`);\n\nconst fieldValueRef = computed(() => {\n if (name && formContext?.model) {\n return formContext.model[name];\n }\n return undefined;\n});\n\nconst fieldValueAsRef = ref(fieldValueRef.value);\nwatch(fieldValueRef, (val) => {\n fieldValueAsRef.value = val;\n});\n\nconst hasValidation = !!(name && schema);\n\nconst validation = hasValidation\n ? useValidationField(name!, fieldValueAsRef, schema!)\n : undefined;\n\nconst resolvedTrigger = computed(() => {\n if (validateTrigger) return Array.isArray(validateTrigger) ? validateTrigger : [validateTrigger];\n const parentTrigger = formContext?.validateTrigger ?? BFormValidateTrigger.Change;\n return Array.isArray(parentTrigger) ? parentTrigger : [parentTrigger];\n});\n\nconst handleBlur = () => {\n if (validation && resolvedTrigger.value.includes(BFormValidateTrigger.Blur)) {\n validation.markTouched();\n validation.validate();\n }\n};\n\nconst handleChange = () => {\n if (validation && resolvedTrigger.value.includes(BFormValidateTrigger.Change)) {\n validation.validate();\n }\n};\n\nwatch(fieldValueRef, () => {\n handleChange();\n});\n\nconst computedStatus = computed<`${BFormValidateStatus}` | undefined>(() => {\n if (validateStatus) return validateStatus;\n if (!validation) return undefined;\n if (validation.errors.value.length > 0) return BFormValidateStatus.Error;\n if (validation.touched.value && validation.isValid.value) return BFormValidateStatus.Success;\n return undefined;\n});\n\nconst resolvedLayout = computed(() => {\n if (layout !== undefined) return layout;\n if (formContext?.layout !== undefined) return formContext.layout;\n return BFormLayout.Horizontal;\n});\nconst resolvedLabelAlign = computed(() => {\n if (labelAlign !== undefined) return labelAlign;\n if (formContext?.labelAlign !== undefined) return formContext.labelAlign;\n return 'right';\n});\nconst resolvedColon = computed(() => {\n if (colon !== null) return colon;\n if (formContext?.colon !== undefined) return formContext.colon;\n return true;\n});\nconst resolvedLabelWidth = computed(() => labelWidth ?? formContext?.labelWidth);\nconst isDisabled = computed(() => formContext?.disabled ?? false);\n\nconst isRequired = computed(() => {\n if (required) return true;\n if (schema) {\n const result = schema.safeParse(undefined);\n if (!result.success) return true;\n const emptyResult = schema.safeParse('');\n if (!emptyResult.success) return true;\n }\n return false;\n});\n\nconst showColon = computed(() => resolvedColon.value && resolvedLayout.value === 'horizontal');\n\nconst showRequiredMark = computed(() => {\n const mark = formContext?.requiredMark ?? true;\n if (mark === false) return false;\n if (mark === BFormRequiredMark.Optional) return false;\n return isRequired.value;\n});\n\nconst showOptionalMark = computed(() => {\n const mark = formContext?.requiredMark ?? true;\n return mark === BFormRequiredMark.Optional && !isRequired.value;\n});\n\nconst helpMessage = computed(() => {\n if (help !== undefined) return help;\n if (validation && validation.errors.value.length > 0) return validation.errors.value[0];\n return undefined;\n});\n\nconst itemClasses = computed(() => [\n 'b-form-item',\n `b-form-item--${resolvedLayout.value}`,\n {\n 'b-form-item--has-error': computedStatus.value === BFormValidateStatus.Error,\n 'b-form-item--has-warning': computedStatus.value === BFormValidateStatus.Warning,\n 'b-form-item--has-success': computedStatus.value === BFormValidateStatus.Success,\n 'b-form-item--validating': computedStatus.value === BFormValidateStatus.Validating,\n 'b-form-item--has-feedback': hasFeedback,\n 'b-form-item--hidden': hidden,\n 'b-form-item--no-style': noStyle,\n 'b-form-item--required': showRequiredMark.value,\n },\n]);\n\nconst labelStyle = computed(() => {\n const styles: Record<string, string> = {};\n if (resolvedLabelWidth.value) {\n styles.width = resolvedLabelWidth.value;\n styles.flexShrink = '0';\n }\n return styles;\n});\n\ndefineExpose({\n validate: validation?.validate ?? (() => true),\n reset: validation?.reset ?? (() => {}),\n errors: validation?.errors ?? computed(() => []),\n isValid: validation?.isValid ?? computed(() => true),\n dirty: validation?.dirty ?? computed(() => false),\n touched: validation?.touched ?? computed(() => false),\n handleBlur,\n});\n</script>\n\n<template>\n <div\n v-if=\"!noStyle\"\n :class=\"itemClasses\"\n :data-form-field=\"name\"\n role=\"group\"\n :aria-labelledby=\"label ? `${fieldId}-label` : undefined\"\n >\n <div\n v-if=\"label || $slots.label\"\n class=\"b-form-item__label\"\n :class=\"[`b-form-item__label--${resolvedLabelAlign}`]\"\n :style=\"labelStyle\"\n >\n <label :id=\"`${fieldId}-label`\" :for=\"fieldId\">\n <span v-if=\"showRequiredMark\" class=\"b-form-item__required-mark\" aria-hidden=\"true\">*</span>\n <slot name=\"label\">{{ label }}</slot>\n <span v-if=\"showOptionalMark\" class=\"b-form-item__optional-mark\">(optional)</span>\n <span\n v-if=\"showColon\"\n class=\"b-form-item__colon\"\n aria-hidden=\"true\"\n >:</span>\n </label>\n <span v-if=\"tooltip\" class=\"b-form-item__tooltip\" :title=\"tooltip\" role=\"img\" aria-label=\"Help\">\n <svg viewBox=\"64 64 896 896\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z\"\n />\n <path\n d=\"M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.4-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7c0-19.7 12.4-37.7 30.9-44.8 59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3z\"\n />\n <path d=\"M512 732a40 40 0 100-80 40 40 0 000 80z\" />\n </svg>\n </span>\n </div>\n\n <div class=\"b-form-item__control\">\n <div class=\"b-form-item__control-input\">\n <slot :id=\"fieldId\" :status=\"computedStatus\" :disabled=\"isDisabled\" :on-blur=\"handleBlur\" />\n <span v-if=\"hasFeedback && computedStatus\" class=\"b-form-item__feedback-icon\">\n <svg\n v-if=\"computedStatus === 'success'\"\n viewBox=\"64 64 896 896\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z\"\n />\n </svg>\n <svg\n v-else-if=\"computedStatus === 'error'\"\n viewBox=\"64 64 896 896\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L512 449.8 295.9 191.7c-3-3.6-7.5-5.7-12.3-5.7H204c-6.8 0-10.5 7.9-6.1 13.1L460.2 512 197.8 824.9A7.95 7.95 0 00204 838h79.8c4.7 0 9.2-2.1 12.3-5.7L512 574.1l216.2 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z\"\n />\n </svg>\n <svg\n v-else-if=\"computedStatus === 'warning'\"\n viewBox=\"64 64 896 896\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M464 720a48 48 0 1096 0 48 48 0 10-96 0zm16-304v184c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V416c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8z\"\n />\n <path\n d=\"M955.7 856l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48z\"\n />\n </svg>\n <span v-else-if=\"computedStatus === 'validating'\" class=\"b-form-item__loading-icon\">\n <svg viewBox=\"0 0 1024 1024\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n d=\"M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.3 199.3 0 19.9-16.1 36-36 36z\"\n />\n </svg>\n </span>\n </span>\n </div>\n\n <div\n v-if=\"helpMessage || $slots.help\"\n class=\"b-form-item__help\"\n :class=\"{\n 'b-form-item__help--error': computedStatus === 'error',\n 'b-form-item__help--warning': computedStatus === 'warning',\n }\"\n :id=\"`${fieldId}-help`\"\n role=\"alert\"\n aria-live=\"polite\"\n >\n <slot name=\"help\">{{ helpMessage }}</slot>\n </div>\n\n <div v-if=\"extra || $slots.extra\" class=\"b-form-item__extra\">\n <slot name=\"extra\">{{ extra }}</slot>\n </div>\n </div>\n </div>\n\n <template v-else>\n <slot :id=\"fieldId\" :status=\"computedStatus\" :disabled=\"isDisabled\" :on-blur=\"handleBlur\" />\n </template>\n</template>\n\n<style scoped>\n.b-form-item {\n margin-bottom: var(--b-form-item-margin-bottom, 24px);\n}\n\n.b-form-item--horizontal {\n display: flex;\n align-items: flex-start;\n}\n\n.b-form-item--vertical {\n display: flex;\n flex-direction: column;\n}\n\n.b-form-item--hidden {\n display: none;\n}\n\n:deep(.b-form--inline) .b-form-item {\n margin-bottom: var(--b-form-inline-item-margin-bottom, 0);\n}\n\n/* Label */\n.b-form-item__label {\n display: inline-flex;\n align-items: center;\n height: var(--b-form-label-height, 32px);\n color: var(--b-form-label-color, rgba(0, 0, 0, 0.88));\n font-size: var(--b-form-label-font-size, 14px);\n line-height: 1.5714;\n white-space: nowrap;\n}\n\n.b-form-item--horizontal .b-form-item__label {\n margin-right: 8px;\n flex-shrink: 0;\n}\n\n.b-form-item--vertical .b-form-item__label {\n margin: var(--b-form-vertical-label-margin, 0);\n padding: var(--b-form-vertical-label-padding, 0 0 8px);\n height: auto;\n}\n\n.b-form-item__label--left {\n text-align: left;\n justify-content: flex-start;\n}\n\n.b-form-item__label--right {\n text-align: right;\n justify-content: flex-end;\n}\n\n.b-form-item__label label {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n cursor: default;\n}\n\n.b-form-item__required-mark {\n color: var(--b-form-label-required-mark-color, #ff4d4f);\n margin-right: 4px;\n font-family: SimSun, sans-serif;\n line-height: 1;\n}\n\n.b-form-item__optional-mark {\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n margin-left: 4px;\n font-size: 12px;\n font-style: italic;\n}\n\n.b-form-item__colon {\n margin-inline-start: var(--b-form-label-colon-margin-inline-start, 2px);\n margin-inline-end: var(--b-form-label-colon-margin-inline-end, 8px);\n}\n\n.b-form-item__tooltip {\n display: inline-flex;\n align-items: center;\n margin-left: 4px;\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n cursor: help;\n}\n\n/* Control */\n.b-form-item__control {\n flex: 1;\n min-width: 0;\n}\n\n.b-form-item__control-input {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n/* Feedback icon */\n.b-form-item__feedback-icon {\n display: inline-flex;\n align-items: center;\n margin-left: 8px;\n flex-shrink: 0;\n}\n\n.b-form-item--has-success .b-form-item__feedback-icon {\n color: var(--b-form-success-color, #52c41a);\n}\n\n.b-form-item--has-error .b-form-item__feedback-icon {\n color: var(--b-form-error-color, #ff4d4f);\n}\n\n.b-form-item--has-warning .b-form-item__feedback-icon {\n color: var(--b-form-warning-color, #faad14);\n}\n\n.b-form-item__loading-icon {\n display: inline-flex;\n animation: b-form-spin 1s linear infinite;\n}\n\n@keyframes b-form-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Help & Extra */\n.b-form-item__help {\n min-height: 22px;\n padding-top: 2px;\n font-size: 14px;\n line-height: 1.5714;\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1);\n}\n\n.b-form-item__help--error {\n color: var(--b-form-error-color, #ff4d4f);\n}\n\n.b-form-item__help--warning {\n color: var(--b-form-warning-color, #faad14);\n}\n\n.b-form-item__extra {\n padding-top: 2px;\n font-size: 14px;\n line-height: 1.5714;\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .b-form-item__help {\n transition: none;\n }\n\n .b-form-item__loading-icon {\n animation: none;\n }\n}\n</style>\n"],"mappings":"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"}
|
package/dist/design-system112.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import e from "./design-
|
|
1
|
+
import e from "./design-system14.js";
|
|
2
|
+
import t from "./design-system110.js";
|
|
2
3
|
/* empty css */
|
|
3
|
-
//#region src/components/
|
|
4
|
-
var
|
|
4
|
+
//#region src/components/BForm/BFormItem.vue
|
|
5
|
+
var n = /* @__PURE__ */ e(t, [["__scopeId", "data-v-6fe6001b"]]);
|
|
5
6
|
//#endregion
|
|
6
|
-
export {
|
|
7
|
+
export { n as default };
|
|
7
8
|
|
|
8
9
|
//# sourceMappingURL=design-system112.js.map
|
|
@@ -1 +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":""}
|
|
1
|
+
{"version":3,"file":"design-system112.js","names":[],"sources":["../src/components/BForm/BFormItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useComponentId } from '@/composables/useComponentId.ts';\nimport { useValidationField } from '@/composables/useValidation.ts';\nimport { computed, inject, ref, watch } from 'vue';\nimport type { ZodType } from 'zod';\nimport { BFormContextKey } from './context.ts';\nimport {\n BFormLayout,\n BFormRequiredMark,\n BFormValidateStatus,\n BFormValidateTrigger,\n} from './types.ts';\n\nconst {\n label,\n name,\n schema,\n required = false,\n validateStatus,\n help,\n extra,\n colon = null,\n labelAlign,\n labelWidth,\n hidden = false,\n noStyle = false,\n hasFeedback = false,\n tooltip,\n layout,\n validateTrigger,\n} = defineProps<{\n /** Label text for the form item. */\n label?: string;\n /** Field name (used for validation and form data collection). */\n name?: string;\n /** Zod schema for field validation. */\n schema?: ZodType;\n /** Whether to display a required mark (visual only, does not add validation). */\n required?: boolean;\n /** Manual validation status override. */\n validateStatus?: `${BFormValidateStatus}`;\n /** Custom help/error message (overrides auto-generated). */\n help?: string;\n /** Extra hint text below the control. */\n extra?: string;\n /** Override parent form colon setting. Pass true/false to override, omit to inherit. */\n colon?: boolean | null;\n /** Override parent form label alignment. */\n labelAlign?: 'left' | 'right';\n /** Override parent form label width. */\n labelWidth?: string;\n /** Hide the form item visually but still validate. */\n hidden?: boolean;\n /** Render control only, no wrapper/label/margin. */\n noStyle?: boolean;\n /** Show validation feedback icon. */\n hasFeedback?: boolean;\n /** Override validation trigger. */\n validateTrigger?: `${BFormValidateTrigger}` | `${BFormValidateTrigger}`[];\n /** Tooltip text for the label. */\n tooltip?: string;\n /** Per-item layout override. */\n layout?: 'horizontal' | 'vertical';\n}>();\n\nconst formContext = inject(BFormContextKey, undefined);\n\nconst { componentUID } = useComponentId();\nconst fieldId = computed(() => `b-form-item-${name ? name + '-' : ''}${componentUID.value}`);\n\nconst fieldValueRef = computed(() => {\n if (name && formContext?.model) {\n return formContext.model[name];\n }\n return undefined;\n});\n\nconst fieldValueAsRef = ref(fieldValueRef.value);\nwatch(fieldValueRef, (val) => {\n fieldValueAsRef.value = val;\n});\n\nconst hasValidation = !!(name && schema);\n\nconst validation = hasValidation\n ? useValidationField(name!, fieldValueAsRef, schema!)\n : undefined;\n\nconst resolvedTrigger = computed(() => {\n if (validateTrigger) return Array.isArray(validateTrigger) ? validateTrigger : [validateTrigger];\n const parentTrigger = formContext?.validateTrigger ?? BFormValidateTrigger.Change;\n return Array.isArray(parentTrigger) ? parentTrigger : [parentTrigger];\n});\n\nconst handleBlur = () => {\n if (validation && resolvedTrigger.value.includes(BFormValidateTrigger.Blur)) {\n validation.markTouched();\n validation.validate();\n }\n};\n\nconst handleChange = () => {\n if (validation && resolvedTrigger.value.includes(BFormValidateTrigger.Change)) {\n validation.validate();\n }\n};\n\nwatch(fieldValueRef, () => {\n handleChange();\n});\n\nconst computedStatus = computed<`${BFormValidateStatus}` | undefined>(() => {\n if (validateStatus) return validateStatus;\n if (!validation) return undefined;\n if (validation.errors.value.length > 0) return BFormValidateStatus.Error;\n if (validation.touched.value && validation.isValid.value) return BFormValidateStatus.Success;\n return undefined;\n});\n\nconst resolvedLayout = computed(() => {\n if (layout !== undefined) return layout;\n if (formContext?.layout !== undefined) return formContext.layout;\n return BFormLayout.Horizontal;\n});\nconst resolvedLabelAlign = computed(() => {\n if (labelAlign !== undefined) return labelAlign;\n if (formContext?.labelAlign !== undefined) return formContext.labelAlign;\n return 'right';\n});\nconst resolvedColon = computed(() => {\n if (colon !== null) return colon;\n if (formContext?.colon !== undefined) return formContext.colon;\n return true;\n});\nconst resolvedLabelWidth = computed(() => labelWidth ?? formContext?.labelWidth);\nconst isDisabled = computed(() => formContext?.disabled ?? false);\n\nconst isRequired = computed(() => {\n if (required) return true;\n if (schema) {\n const result = schema.safeParse(undefined);\n if (!result.success) return true;\n const emptyResult = schema.safeParse('');\n if (!emptyResult.success) return true;\n }\n return false;\n});\n\nconst showColon = computed(() => resolvedColon.value && resolvedLayout.value === 'horizontal');\n\nconst showRequiredMark = computed(() => {\n const mark = formContext?.requiredMark ?? true;\n if (mark === false) return false;\n if (mark === BFormRequiredMark.Optional) return false;\n return isRequired.value;\n});\n\nconst showOptionalMark = computed(() => {\n const mark = formContext?.requiredMark ?? true;\n return mark === BFormRequiredMark.Optional && !isRequired.value;\n});\n\nconst helpMessage = computed(() => {\n if (help !== undefined) return help;\n if (validation && validation.errors.value.length > 0) return validation.errors.value[0];\n return undefined;\n});\n\nconst itemClasses = computed(() => [\n 'b-form-item',\n `b-form-item--${resolvedLayout.value}`,\n {\n 'b-form-item--has-error': computedStatus.value === BFormValidateStatus.Error,\n 'b-form-item--has-warning': computedStatus.value === BFormValidateStatus.Warning,\n 'b-form-item--has-success': computedStatus.value === BFormValidateStatus.Success,\n 'b-form-item--validating': computedStatus.value === BFormValidateStatus.Validating,\n 'b-form-item--has-feedback': hasFeedback,\n 'b-form-item--hidden': hidden,\n 'b-form-item--no-style': noStyle,\n 'b-form-item--required': showRequiredMark.value,\n },\n]);\n\nconst labelStyle = computed(() => {\n const styles: Record<string, string> = {};\n if (resolvedLabelWidth.value) {\n styles.width = resolvedLabelWidth.value;\n styles.flexShrink = '0';\n }\n return styles;\n});\n\ndefineExpose({\n validate: validation?.validate ?? (() => true),\n reset: validation?.reset ?? (() => {}),\n errors: validation?.errors ?? computed(() => []),\n isValid: validation?.isValid ?? computed(() => true),\n dirty: validation?.dirty ?? computed(() => false),\n touched: validation?.touched ?? computed(() => false),\n handleBlur,\n});\n</script>\n\n<template>\n <div\n v-if=\"!noStyle\"\n :class=\"itemClasses\"\n :data-form-field=\"name\"\n role=\"group\"\n :aria-labelledby=\"label ? `${fieldId}-label` : undefined\"\n >\n <div\n v-if=\"label || $slots.label\"\n class=\"b-form-item__label\"\n :class=\"[`b-form-item__label--${resolvedLabelAlign}`]\"\n :style=\"labelStyle\"\n >\n <label :id=\"`${fieldId}-label`\" :for=\"fieldId\">\n <span v-if=\"showRequiredMark\" class=\"b-form-item__required-mark\" aria-hidden=\"true\">*</span>\n <slot name=\"label\">{{ label }}</slot>\n <span v-if=\"showOptionalMark\" class=\"b-form-item__optional-mark\">(optional)</span>\n <span\n v-if=\"showColon\"\n class=\"b-form-item__colon\"\n aria-hidden=\"true\"\n >:</span>\n </label>\n <span v-if=\"tooltip\" class=\"b-form-item__tooltip\" :title=\"tooltip\" role=\"img\" aria-label=\"Help\">\n <svg viewBox=\"64 64 896 896\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n d=\"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z\"\n />\n <path\n d=\"M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.4-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7c0-19.7 12.4-37.7 30.9-44.8 59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3z\"\n />\n <path d=\"M512 732a40 40 0 100-80 40 40 0 000 80z\" />\n </svg>\n </span>\n </div>\n\n <div class=\"b-form-item__control\">\n <div class=\"b-form-item__control-input\">\n <slot :id=\"fieldId\" :status=\"computedStatus\" :disabled=\"isDisabled\" :on-blur=\"handleBlur\" />\n <span v-if=\"hasFeedback && computedStatus\" class=\"b-form-item__feedback-icon\">\n <svg\n v-if=\"computedStatus === 'success'\"\n viewBox=\"64 64 896 896\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z\"\n />\n </svg>\n <svg\n v-else-if=\"computedStatus === 'error'\"\n viewBox=\"64 64 896 896\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L512 449.8 295.9 191.7c-3-3.6-7.5-5.7-12.3-5.7H204c-6.8 0-10.5 7.9-6.1 13.1L460.2 512 197.8 824.9A7.95 7.95 0 00204 838h79.8c4.7 0 9.2-2.1 12.3-5.7L512 574.1l216.2 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z\"\n />\n </svg>\n <svg\n v-else-if=\"computedStatus === 'warning'\"\n viewBox=\"64 64 896 896\"\n width=\"14\"\n height=\"14\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M464 720a48 48 0 1096 0 48 48 0 10-96 0zm16-304v184c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V416c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8z\"\n />\n <path\n d=\"M955.7 856l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48z\"\n />\n </svg>\n <span v-else-if=\"computedStatus === 'validating'\" class=\"b-form-item__loading-icon\">\n <svg viewBox=\"0 0 1024 1024\" width=\"14\" height=\"14\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n d=\"M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.3 199.3 0 19.9-16.1 36-36 36z\"\n />\n </svg>\n </span>\n </span>\n </div>\n\n <div\n v-if=\"helpMessage || $slots.help\"\n class=\"b-form-item__help\"\n :class=\"{\n 'b-form-item__help--error': computedStatus === 'error',\n 'b-form-item__help--warning': computedStatus === 'warning',\n }\"\n :id=\"`${fieldId}-help`\"\n role=\"alert\"\n aria-live=\"polite\"\n >\n <slot name=\"help\">{{ helpMessage }}</slot>\n </div>\n\n <div v-if=\"extra || $slots.extra\" class=\"b-form-item__extra\">\n <slot name=\"extra\">{{ extra }}</slot>\n </div>\n </div>\n </div>\n\n <template v-else>\n <slot :id=\"fieldId\" :status=\"computedStatus\" :disabled=\"isDisabled\" :on-blur=\"handleBlur\" />\n </template>\n</template>\n\n<style scoped>\n.b-form-item {\n margin-bottom: var(--b-form-item-margin-bottom, 24px);\n}\n\n.b-form-item--horizontal {\n display: flex;\n align-items: flex-start;\n}\n\n.b-form-item--vertical {\n display: flex;\n flex-direction: column;\n}\n\n.b-form-item--hidden {\n display: none;\n}\n\n:deep(.b-form--inline) .b-form-item {\n margin-bottom: var(--b-form-inline-item-margin-bottom, 0);\n}\n\n/* Label */\n.b-form-item__label {\n display: inline-flex;\n align-items: center;\n height: var(--b-form-label-height, 32px);\n color: var(--b-form-label-color, rgba(0, 0, 0, 0.88));\n font-size: var(--b-form-label-font-size, 14px);\n line-height: 1.5714;\n white-space: nowrap;\n}\n\n.b-form-item--horizontal .b-form-item__label {\n margin-right: 8px;\n flex-shrink: 0;\n}\n\n.b-form-item--vertical .b-form-item__label {\n margin: var(--b-form-vertical-label-margin, 0);\n padding: var(--b-form-vertical-label-padding, 0 0 8px);\n height: auto;\n}\n\n.b-form-item__label--left {\n text-align: left;\n justify-content: flex-start;\n}\n\n.b-form-item__label--right {\n text-align: right;\n justify-content: flex-end;\n}\n\n.b-form-item__label label {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n cursor: default;\n}\n\n.b-form-item__required-mark {\n color: var(--b-form-label-required-mark-color, #ff4d4f);\n margin-right: 4px;\n font-family: SimSun, sans-serif;\n line-height: 1;\n}\n\n.b-form-item__optional-mark {\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n margin-left: 4px;\n font-size: 12px;\n font-style: italic;\n}\n\n.b-form-item__colon {\n margin-inline-start: var(--b-form-label-colon-margin-inline-start, 2px);\n margin-inline-end: var(--b-form-label-colon-margin-inline-end, 8px);\n}\n\n.b-form-item__tooltip {\n display: inline-flex;\n align-items: center;\n margin-left: 4px;\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n cursor: help;\n}\n\n/* Control */\n.b-form-item__control {\n flex: 1;\n min-width: 0;\n}\n\n.b-form-item__control-input {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n/* Feedback icon */\n.b-form-item__feedback-icon {\n display: inline-flex;\n align-items: center;\n margin-left: 8px;\n flex-shrink: 0;\n}\n\n.b-form-item--has-success .b-form-item__feedback-icon {\n color: var(--b-form-success-color, #52c41a);\n}\n\n.b-form-item--has-error .b-form-item__feedback-icon {\n color: var(--b-form-error-color, #ff4d4f);\n}\n\n.b-form-item--has-warning .b-form-item__feedback-icon {\n color: var(--b-form-warning-color, #faad14);\n}\n\n.b-form-item__loading-icon {\n display: inline-flex;\n animation: b-form-spin 1s linear infinite;\n}\n\n@keyframes b-form-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Help & Extra */\n.b-form-item__help {\n min-height: 22px;\n padding-top: 2px;\n font-size: 14px;\n line-height: 1.5714;\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1);\n}\n\n.b-form-item__help--error {\n color: var(--b-form-error-color, #ff4d4f);\n}\n\n.b-form-item__help--warning {\n color: var(--b-form-warning-color, #faad14);\n}\n\n.b-form-item__extra {\n padding-top: 2px;\n font-size: 14px;\n line-height: 1.5714;\n color: var(--b-form-help-color, rgba(0, 0, 0, 0.65));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .b-form-item__help {\n transition: none;\n }\n\n .b-form-item__loading-icon {\n animation: none;\n }\n}\n</style>\n"],"mappings":""}
|