vue-pane 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +424 -0
  3. package/dist/src/components/PButton.vue.d.ts +11 -0
  4. package/dist/src/components/PCheckbox.vue.d.ts +15 -0
  5. package/dist/src/components/PColor.vue.d.ts +16 -0
  6. package/dist/src/components/PFolder.vue.d.ts +27 -0
  7. package/dist/src/components/PGraph.vue.d.ts +10 -0
  8. package/dist/src/components/PLabel.vue.d.ts +17 -0
  9. package/dist/src/components/PMonitor.vue.d.ts +8 -0
  10. package/dist/src/components/PMonitorMulti.vue.d.ts +8 -0
  11. package/dist/src/components/PNumber.vue.d.ts +18 -0
  12. package/dist/src/components/PPoint2d.vue.d.ts +26 -0
  13. package/dist/src/components/PSelect.vue.d.ts +19 -0
  14. package/dist/src/components/PSeparator.vue.d.ts +3 -0
  15. package/dist/src/components/PSlider.vue.d.ts +18 -0
  16. package/dist/src/components/PTab.vue.d.ts +25 -0
  17. package/dist/src/components/PText.vue.d.ts +15 -0
  18. package/dist/src/components/PTooltipIcon.vue.d.ts +3 -0
  19. package/dist/src/components/VPane.vue.d.ts +28 -0
  20. package/dist/src/composables/useFoldable.d.ts +5 -0
  21. package/dist/src/composables/usePaneConfig.d.ts +8 -0
  22. package/dist/src/composables/usePickerFold.d.ts +2 -0
  23. package/dist/src/composables/useTooltip.d.ts +19 -0
  24. package/dist/src/index.d.ts +19 -0
  25. package/dist/vue-pane.css +2 -0
  26. package/dist/vue-pane.js +3076 -0
  27. package/dist/vue-pane.umd.cjs +1 -0
  28. package/package.json +79 -0
  29. package/src/components/PButton.vue +53 -0
  30. package/src/components/PCheckbox.vue +37 -0
  31. package/src/components/PColor.vue +107 -0
  32. package/src/components/PConfig.vue +10 -0
  33. package/src/components/PFolder.vue +81 -0
  34. package/src/components/PGraph.vue +49 -0
  35. package/src/components/PLabel.vue +50 -0
  36. package/src/components/PMonitor.vue +28 -0
  37. package/src/components/PMonitorMulti.vue +30 -0
  38. package/src/components/PNumber.vue +162 -0
  39. package/src/components/PPoint2d.vue +191 -0
  40. package/src/components/PSelect.vue +44 -0
  41. package/src/components/PSeparator.vue +8 -0
  42. package/src/components/PSlider.vue +96 -0
  43. package/src/components/PTab.vue +73 -0
  44. package/src/components/PText.vue +30 -0
  45. package/src/components/PTooltipIcon.vue +30 -0
  46. package/src/components/VPane.vue +61 -0
  47. package/src/composables/useFoldable.ts +128 -0
  48. package/src/composables/usePaneConfig.ts +25 -0
  49. package/src/composables/usePickerFold.ts +46 -0
  50. package/src/composables/useTooltip.ts +27 -0
  51. package/src/index.ts +38 -0
  52. package/src/styles/_vp.scss +12 -0
  53. package/src/styles/common/_defs.scss +56 -0
  54. package/src/styles/index.scss +1 -0
  55. package/src/styles/view/_button.scss +12 -0
  56. package/src/styles/view/_checkbox.scss +54 -0
  57. package/src/styles/view/_color.scss +57 -0
  58. package/src/styles/view/_folder.scss +70 -0
  59. package/src/styles/view/_graph.scss +11 -0
  60. package/src/styles/view/_label.scss +37 -0
  61. package/src/styles/view/_list.scss +17 -0
  62. package/src/styles/view/_log.scss +13 -0
  63. package/src/styles/view/_monitor-multi.scss +18 -0
  64. package/src/styles/view/_number.scss +110 -0
  65. package/src/styles/view/_point-2d.scss +61 -0
  66. package/src/styles/view/_root.scss +126 -0
  67. package/src/styles/view/_separator.scss +15 -0
  68. package/src/styles/view/_slider.scss +32 -0
  69. package/src/styles/view/_tab.scss +139 -0
  70. package/src/styles/view/_text.scss +24 -0
  71. package/src/styles/view/_tooltip.scss +17 -0
  72. package/src/styles/view/_views.scss +2 -0
  73. package/src/styles/view/placeholder/_button.scss +28 -0
  74. package/src/styles/view/placeholder/_container.scss +80 -0
  75. package/src/styles/view/placeholder/_folder.scss +102 -0
  76. package/src/styles/view/placeholder/_input.scss +26 -0
  77. package/src/styles/view/placeholder/_list.scss +35 -0
  78. package/src/styles/view/placeholder/_monitor.scss +26 -0
  79. package/src/styles/view/placeholder/_texts.scss +11 -0
  80. package/src/styles/view/placeholder/_theme.scss +111 -0
@@ -0,0 +1,28 @@
1
+ <script setup lang="ts">
2
+ import PLabel from './PLabel.vue'
3
+
4
+ const {
5
+ value,
6
+ label,
7
+ tooltip,
8
+ } = defineProps<{
9
+ value: unknown
10
+ label?: string
11
+ tooltip?: string
12
+ }>()
13
+ </script>
14
+ <template>
15
+ <PLabel
16
+ :label="label"
17
+ :tooltip="tooltip"
18
+ >
19
+ <div class="vp-monitor">
20
+ <div class="vp-monitor__value">
21
+ {{ value }}
22
+ </div>
23
+ </div>
24
+ </PLabel>
25
+ </template>
26
+ <style lang="scss">
27
+ @use '../styles/view/log';
28
+ </style>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import PLabel from './PLabel.vue'
3
+
4
+ const {
5
+ value,
6
+ label,
7
+ tooltip,
8
+ } = defineProps<{
9
+ value: unknown
10
+ label?: string
11
+ tooltip?: string
12
+ }>()
13
+ </script>
14
+ <template>
15
+ <PLabel
16
+ :label="label"
17
+ :tooltip="tooltip"
18
+ >
19
+ <div class="vp-monitor-multi">
20
+ <textarea
21
+ class="vp-monitor-multi__value"
22
+ readonly
23
+ :value="String(value)"
24
+ />
25
+ </div>
26
+ </PLabel>
27
+ </template>
28
+ <style lang="scss">
29
+ @use '../styles/view/monitor-multi';
30
+ </style>
@@ -0,0 +1,162 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref, watch } from 'vue'
3
+ import PLabel from './PLabel.vue'
4
+
5
+ const model = defineModel<number>({ required: true })
6
+ const {
7
+ label,
8
+ tooltip,
9
+ min,
10
+ max,
11
+ step = 1,
12
+ } = defineProps<{
13
+ label?: string
14
+ tooltip?: string
15
+ min?: number
16
+ max?: number
17
+ step?: number
18
+ }>()
19
+
20
+ const isDragging = ref(false)
21
+ const isFocused = ref(false)
22
+ const localValue = ref(String(model.value))
23
+ const dragPixelDelta = ref(0)
24
+
25
+ watch(model, (val) => {
26
+ if (!isFocused.value) {
27
+ localValue.value = String(val)
28
+ }
29
+ })
30
+
31
+ function clamp(val: number): number {
32
+ if (min !== undefined) val = Math.max(min, val)
33
+ if (max !== undefined) val = Math.min(max, val)
34
+ return val
35
+ }
36
+
37
+ function snapToStep(val: number): number {
38
+ return Math.round(val / step) * step
39
+ }
40
+
41
+ const guideBodyPath = computed(() => {
42
+ const x = dragPixelDelta.value
43
+ return `M 0,4 L${x},4`
44
+ })
45
+
46
+ const guideHeadPath = computed(() => {
47
+ const x = dragPixelDelta.value
48
+ if (x === 0) return ''
49
+ const aox = x + (x > 0 ? -1 : 1)
50
+ const adx = Math.max(-4, Math.min(4, -aox))
51
+ return `M ${aox + adx},0 L${aox},4 L${aox + adx},8 M ${x},-1 L${x},9`
52
+ })
53
+
54
+ const tooltipText = computed(() => {
55
+ const decimals = step < 1 ? (String(step).split('.')[1]?.length ?? 0) : 0
56
+ return model.value.toFixed(decimals)
57
+ })
58
+
59
+ function onFocus() {
60
+ isFocused.value = true
61
+ }
62
+
63
+ function onBlur() {
64
+ isFocused.value = false
65
+ const parsed = parseFloat(localValue.value)
66
+ if (!isNaN(parsed)) {
67
+ model.value = clamp(parsed)
68
+ } else {
69
+ localValue.value = String(model.value)
70
+ }
71
+ }
72
+
73
+ function onKeydown(e: KeyboardEvent) {
74
+ if (e.key === 'Enter') {
75
+ (e.target as HTMLInputElement).blur()
76
+ } else if (e.key === 'ArrowUp') {
77
+ e.preventDefault()
78
+ const multiplier = e.shiftKey ? 10 : 1
79
+ model.value = clamp(model.value + step * multiplier)
80
+ } else if (e.key === 'ArrowDown') {
81
+ e.preventDefault()
82
+ const multiplier = e.shiftKey ? 10 : 1
83
+ model.value = clamp(model.value - step * multiplier)
84
+ }
85
+ }
86
+
87
+ let dragStartX = 0
88
+ let dragStartValue = 0
89
+
90
+ function onKnobPointerDown(e: PointerEvent) {
91
+ e.preventDefault()
92
+ ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
93
+ isDragging.value = true
94
+ dragStartX = e.clientX
95
+ dragStartValue = model.value
96
+ dragPixelDelta.value = 0
97
+ document.body.style.cursor = 'ew-resize'
98
+ }
99
+
100
+ function onKnobPointerMove(e: PointerEvent) {
101
+ if (!isDragging.value) return
102
+ const delta = e.clientX - dragStartX
103
+ dragPixelDelta.value = delta
104
+ model.value = clamp(snapToStep(dragStartValue + delta))
105
+ }
106
+
107
+ function onKnobPointerUp() {
108
+ isDragging.value = false
109
+ dragPixelDelta.value = 0
110
+ document.body.style.cursor = ''
111
+ }
112
+ </script>
113
+
114
+ <template>
115
+ <PLabel
116
+ :label="label"
117
+ :tooltip="tooltip"
118
+ >
119
+ <div
120
+ class="vp-text vp-text--number"
121
+ :class="{ 'vp-text--dragging': isDragging }"
122
+ >
123
+ <input
124
+ v-model="localValue"
125
+ class="vp-text__input"
126
+ type="text"
127
+ @focus="onFocus"
128
+ @blur="onBlur"
129
+ @keydown="onKeydown"
130
+ >
131
+ <div
132
+ class="vp-text__knob"
133
+ @pointerdown="onKnobPointerDown"
134
+ @pointermove="onKnobPointerMove"
135
+ @pointerup="onKnobPointerUp"
136
+ @pointercancel="onKnobPointerUp"
137
+ >
138
+ <svg class="vp-text__guide">
139
+ <path
140
+ class="vp-text__guide-body"
141
+ :d="guideBodyPath"
142
+ />
143
+ <path
144
+ class="vp-text__guide-head"
145
+ :d="guideHeadPath"
146
+ />
147
+ </svg>
148
+ <div
149
+ class="vp-text__drag-tooltip"
150
+ :style="{ left: `${dragPixelDelta}px` }"
151
+ >
152
+ {{ tooltipText }}
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </PLabel>
157
+ </template>
158
+
159
+ <style lang="scss">
160
+ @use '../styles/view/text';
161
+ @use '../styles/view/number';
162
+ </style>
@@ -0,0 +1,191 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref } from 'vue'
3
+ import { usePickerFold } from '../composables/usePickerFold'
4
+ import PLabel from './PLabel.vue'
5
+
6
+ const model = defineModel<{ x: number, y: number }>({ required: true })
7
+ const {
8
+ label,
9
+ tooltip,
10
+ min = -1,
11
+ max = 1,
12
+ } = defineProps<{
13
+ label?: string
14
+ tooltip?: string
15
+ min?: number
16
+ max?: number
17
+ }>()
18
+
19
+ const isOpen = ref(false)
20
+ const panelRef = ref<HTMLElement | null>(null)
21
+ const canvasRef = ref<HTMLCanvasElement | null>(null)
22
+
23
+ const isComplete = usePickerFold(panelRef, isOpen)
24
+ const canvasSize = 160
25
+
26
+ const localX = computed(() => model.value.x.toFixed(3))
27
+ const localY = computed(() => model.value.y.toFixed(3))
28
+
29
+ function clamp(val: number): number {
30
+ return Math.max(min, Math.min(max, val))
31
+ }
32
+
33
+ function onXBlur(e: Event) {
34
+ const val = parseFloat((e.target as HTMLInputElement).value)
35
+ if (!isNaN(val)) model.value = { x: clamp(val), y: model.value.y }
36
+ }
37
+
38
+ function onYBlur(e: Event) {
39
+ const val = parseFloat((e.target as HTMLInputElement).value)
40
+ if (!isNaN(val)) model.value = { x: model.value.x, y: clamp(val) }
41
+ }
42
+
43
+ function toggle() {
44
+ isOpen.value = !isOpen.value
45
+ }
46
+
47
+ function drawCanvas() {
48
+ const canvas = canvasRef.value
49
+ if (!canvas) return
50
+ const ctx = canvas.getContext('2d')!
51
+ const size = canvasSize
52
+ ctx.clearRect(0, 0, size, size)
53
+ ctx.fillStyle = 'rgba(0,0,0,0.3)'
54
+ ctx.fillRect(0, 0, size, size)
55
+ ctx.strokeStyle = 'rgba(255,255,255,0.1)'
56
+ ctx.lineWidth = 1
57
+ ctx.beginPath()
58
+ ctx.moveTo(size / 2, 0)
59
+ ctx.lineTo(size / 2, size)
60
+ ctx.moveTo(0, size / 2)
61
+ ctx.lineTo(size, size / 2)
62
+ ctx.stroke()
63
+ }
64
+
65
+ onMounted(() => {
66
+ drawCanvas()
67
+ })
68
+
69
+ const crosshairX = computed(() => {
70
+ const range = max - min
71
+ return ((model.value.x - min) / range) * canvasSize
72
+ })
73
+
74
+ const crosshairY = computed(() => {
75
+ const range = max - min
76
+ return canvasSize - ((model.value.y - min) / range) * canvasSize
77
+ })
78
+
79
+ let canvasDragging = false
80
+
81
+ function posToValue(e: PointerEvent) {
82
+ const canvas = canvasRef.value!
83
+ const rect = canvas.getBoundingClientRect()
84
+ const rx = (e.clientX - rect.left) / rect.width
85
+ const ry = 1 - (e.clientY - rect.top) / rect.height
86
+ const range = max - min
87
+ return {
88
+ x: clamp(min + rx * range),
89
+ y: clamp(min + ry * range),
90
+ }
91
+ }
92
+
93
+ function onCanvasDown(e: PointerEvent) {
94
+ e.preventDefault()
95
+ ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
96
+ canvasDragging = true
97
+ model.value = posToValue(e)
98
+ }
99
+
100
+ function onCanvasMove(e: PointerEvent) {
101
+ if (!canvasDragging) return
102
+ model.value = posToValue(e)
103
+ }
104
+
105
+ function onCanvasUp() {
106
+ canvasDragging = false
107
+ }
108
+ </script>
109
+ <template>
110
+ <PLabel
111
+ :label="label"
112
+ :tooltip="tooltip"
113
+ >
114
+ <div
115
+ class="vp-point-2d"
116
+ :class="{ 'vp-point-2d--expanded': isOpen, 'vp-point-2d--complete': isComplete }"
117
+ >
118
+ <div class="vp-point-2d__header">
119
+ <button
120
+ class="vp-point-2d__btn"
121
+ @click="toggle"
122
+ >
123
+ <svg viewBox="0 0 16 16">
124
+ <path d="M8 2 L8 14 M2 8 L14 8" />
125
+ <circle
126
+ cx="8"
127
+ cy="8"
128
+ r="1.5"
129
+ />
130
+ </svg>
131
+ </button>
132
+ <div class="vp-point-2d__inputs">
133
+ <div style="display:flex; gap:2px">
134
+ <div
135
+ class="vp-text vp-text--number vp-text--first"
136
+ style="flex:1"
137
+ >
138
+ <input
139
+ class="vp-text__input"
140
+ type="text"
141
+ :value="localX"
142
+ @blur="onXBlur"
143
+ @keydown.enter="(e) => (e.target as HTMLElement).blur()"
144
+ >
145
+ </div>
146
+ <div
147
+ class="vp-text vp-text--number vp-text--last"
148
+ style="flex:1"
149
+ >
150
+ <input
151
+ class="vp-text__input"
152
+ type="text"
153
+ :value="localY"
154
+ @blur="onYBlur"
155
+ @keydown.enter="(e) => (e.target as HTMLElement).blur()"
156
+ >
157
+ </div>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ <div
162
+ ref="panelRef"
163
+ class="vp-point-2d__picker-panel"
164
+ >
165
+ <div class="vp-point-2d__picker-wrap">
166
+ <canvas
167
+ ref="canvasRef"
168
+ class="vp-point-2d__canvas"
169
+ :height="canvasSize"
170
+ :width="canvasSize"
171
+ @pointerdown="onCanvasDown"
172
+ @pointermove="onCanvasMove"
173
+ @pointerup="onCanvasUp"
174
+ @pointercancel="onCanvasUp"
175
+ />
176
+ <div
177
+ class="vp-point-2d__crosshair-h"
178
+ :style="{ top: crosshairY + 'px' }"
179
+ />
180
+ <div
181
+ class="vp-point-2d__crosshair-v"
182
+ :style="{ left: crosshairX + 'px' }"
183
+ />
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </PLabel>
188
+ </template>
189
+ <style lang="scss">
190
+ @use '../styles/view/point-2d';
191
+ </style>
@@ -0,0 +1,44 @@
1
+ <script setup lang="ts">
2
+ import PLabel from './PLabel.vue'
3
+
4
+ const model = defineModel<string | number>({ required: true })
5
+ const {
6
+ label,
7
+ tooltip,
8
+ options,
9
+ } = defineProps<{
10
+ label?: string
11
+ tooltip?: string
12
+ options: { value: string | number, label: string }[]
13
+ }>()
14
+ </script>
15
+ <template>
16
+ <PLabel
17
+ :label="label"
18
+ :tooltip="tooltip"
19
+ >
20
+ <div class="vp-select">
21
+ <select
22
+ class="vp-select__input"
23
+ :value="model"
24
+ @change="model = ($event.target as HTMLSelectElement).value"
25
+ >
26
+ <option
27
+ v-for="opt in options"
28
+ :key="opt.value"
29
+ :value="opt.value"
30
+ >
31
+ {{ opt.label }}
32
+ </option>
33
+ </select>
34
+ <div class="vp-select__arrow">
35
+ <svg viewBox="0 0 16 16">
36
+ <path d="M 2 5 L 8 11 L 14 5" />
37
+ </svg>
38
+ </div>
39
+ </div>
40
+ </PLabel>
41
+ </template>
42
+ <style lang="scss">
43
+ @use '../styles/view/list';
44
+ </style>
@@ -0,0 +1,8 @@
1
+ <template>
2
+ <div class="vp-separator">
3
+ <hr class="vp-separator__rule">
4
+ </div>
5
+ </template>
6
+ <style lang="scss">
7
+ @use '../styles/view/separator';
8
+ </style>
@@ -0,0 +1,96 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from 'vue'
3
+ import PLabel from './PLabel.vue'
4
+
5
+ const model = defineModel<number>({ required: true })
6
+ const {
7
+ label,
8
+ tooltip,
9
+ min = 0,
10
+ max = 1,
11
+ step = null,
12
+ } = defineProps<{
13
+ label?: string
14
+ tooltip?: string
15
+ min?: number
16
+ max?: number
17
+ step?: number | null
18
+ }>()
19
+
20
+ const trackRef = ref<HTMLElement | null>(null)
21
+ const isDragging = ref(false)
22
+
23
+ const knobPercent = computed(() => {
24
+ const range = max - min
25
+ if (range === 0) return 0
26
+ return ((model.value - min) / range) * 100
27
+ })
28
+
29
+ function clamp(val: number): number {
30
+ return Math.max(min, Math.min(max, val))
31
+ }
32
+
33
+ function valueFromPointer(e: PointerEvent): number {
34
+ const el = trackRef.value
35
+ if (!el) return model.value
36
+ const rect = el.getBoundingClientRect()
37
+ const ratio = (e.clientX - rect.left) / rect.width
38
+ const raw = min + ratio * (max - min)
39
+ if (step === null) return clamp(raw)
40
+ return clamp(Math.round(raw / step) * step)
41
+ }
42
+
43
+ function onTrackPointerDown(e: PointerEvent) {
44
+ e.preventDefault()
45
+ ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
46
+ isDragging.value = true
47
+ model.value = valueFromPointer(e)
48
+ }
49
+
50
+ function onTrackPointerMove(e: PointerEvent) {
51
+ if (!isDragging.value) return
52
+ model.value = valueFromPointer(e)
53
+ }
54
+
55
+ function onPointerUp() {
56
+ isDragging.value = false
57
+ }
58
+
59
+ function onKeydown(e: KeyboardEvent) {
60
+ const increment = step ?? (max - min) / 100
61
+ if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
62
+ e.preventDefault()
63
+ model.value = clamp(model.value + increment * (e.shiftKey ? 10 : 1))
64
+ } else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
65
+ e.preventDefault()
66
+ model.value = clamp(model.value - increment * (e.shiftKey ? 10 : 1))
67
+ }
68
+ }
69
+ </script>
70
+ <template>
71
+ <PLabel
72
+ :label="label"
73
+ :tooltip="tooltip"
74
+ >
75
+ <div class="vp-slider">
76
+ <div
77
+ ref="trackRef"
78
+ class="vp-slider__track"
79
+ tabindex="0"
80
+ @pointerdown="onTrackPointerDown"
81
+ @pointermove="onTrackPointerMove"
82
+ @pointerup="onPointerUp"
83
+ @pointercancel="onPointerUp"
84
+ @keydown="onKeydown"
85
+ >
86
+ <div
87
+ class="vp-slider__knob"
88
+ :style="{ left: knobPercent + '%' }"
89
+ />
90
+ </div>
91
+ </div>
92
+ </PLabel>
93
+ </template>
94
+ <style lang="scss">
95
+ @use '../styles/view/slider';
96
+ </style>
@@ -0,0 +1,73 @@
1
+ <script setup lang="ts">
2
+ import { usePaneConfig } from '../composables/usePaneConfig'
3
+ import { useTooltip } from '../composables/useTooltip'
4
+
5
+ const model = defineModel<number>({ default: 0 })
6
+ const {
7
+ tabs,
8
+ tooltips,
9
+ } = defineProps<{
10
+ tabs: string[]
11
+ tooltips?: string[]
12
+ }>()
13
+
14
+ const { floatingStyles, visible, activeText, show, hide } = useTooltip()
15
+ const config = usePaneConfig()
16
+
17
+ function setTab(i: number) {
18
+ model.value = i
19
+ }
20
+ </script>
21
+ <template>
22
+ <div class="vp-tab">
23
+ <div class="vp-tab__title-bar">
24
+ <div
25
+ v-for="(tab, i) in tabs"
26
+ :key="i"
27
+ class="vp-tab-item"
28
+ :class="{ 'vp-tab-item--selected': i === model }"
29
+ >
30
+ <button
31
+ class="vp-tab-item__btn"
32
+ @click="setTab(i)"
33
+ >
34
+ <span class="vp-tab-item__label">
35
+ {{ tab }}
36
+ <component
37
+ :is="config.tooltipIcon"
38
+ v-if="tooltips?.[i] && config.tooltipIcon"
39
+ @mouseenter="tooltips?.[i] && show($event, tooltips[i])"
40
+ @mouseleave="hide"
41
+ />
42
+ </span>
43
+ </button>
44
+ </div>
45
+ </div>
46
+ <Teleport to="body">
47
+ <div
48
+ v-if="visible"
49
+ ref="floatingEl"
50
+ class="vp-tooltip"
51
+ :style="floatingStyles"
52
+ >
53
+ {{ activeText }}
54
+ </div>
55
+ </Teleport>
56
+ <div class="vp-tab__indent" />
57
+ <div class="vp-tab__content">
58
+ <div
59
+ v-for="(tab, i) in tabs"
60
+ v-show="i === model"
61
+ :key="i"
62
+ class="vp-tab-page"
63
+ >
64
+ <div class="vp-tab-page__content">
65
+ <slot :name="tab" />
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </template>
71
+ <style lang="scss">
72
+ @use '../styles/view/tab';
73
+ </style>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import PLabel from './PLabel.vue'
3
+
4
+ const model = defineModel<string>({ required: true })
5
+ const {
6
+ label,
7
+ tooltip,
8
+ } = defineProps<{
9
+ label?: string
10
+ tooltip?: string
11
+ }>()
12
+ </script>
13
+ <template>
14
+ <PLabel
15
+ :label="label"
16
+ :tooltip="tooltip"
17
+ >
18
+ <div class="vp-text">
19
+ <input
20
+ class="vp-text__input"
21
+ type="text"
22
+ :value="model"
23
+ @input="model = ($event.target as HTMLInputElement).value"
24
+ >
25
+ </div>
26
+ </PLabel>
27
+ </template>
28
+ <style lang="scss">
29
+ @use '../styles/view/text';
30
+ </style>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <svg
3
+ viewBox="0 0 16 16"
4
+ width="10"
5
+ height="10"
6
+ fill="none"
7
+ >
8
+ <circle
9
+ cx="8"
10
+ cy="8"
11
+ r="7"
12
+ stroke="currentColor"
13
+ stroke-width="1.5"
14
+ />
15
+ <circle
16
+ cx="8"
17
+ cy="5.5"
18
+ r="1"
19
+ fill="currentColor"
20
+ />
21
+ <rect
22
+ x="7"
23
+ y="7.5"
24
+ width="2"
25
+ height="4"
26
+ rx="1"
27
+ fill="currentColor"
28
+ />
29
+ </svg>
30
+ </template>