@brickflow/ui 0.0.55 → 0.0.57

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 (28) hide show
  1. package/dist/module.d.mts +1 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -0
  4. package/dist/runtime/components/Button/state.demo.vue +9 -1
  5. package/dist/runtime/components/Form/index.vue +50 -0
  6. package/dist/runtime/components/Form/login.demo.vue +68 -0
  7. package/dist/runtime/components/Input/index.vue +147 -22
  8. package/dist/runtime/components/Input/label.demo.vue +15 -3
  9. package/dist/runtime/components/Input/mask.demo.vue +73 -0
  10. package/dist/runtime/components/Input/variants.demo.vue +16 -0
  11. package/dist/runtime/components/InputNumber/denominator.demo.vue +38 -0
  12. package/dist/runtime/components/InputNumber/index.vue +131 -9
  13. package/dist/runtime/components/InputNumber/minmax.demo.vue +39 -0
  14. package/dist/runtime/components/InputNumber/nullable.demo.vue +25 -0
  15. package/dist/runtime/components/InputNumber/step.demo.vue +38 -0
  16. package/dist/runtime/components/TransitionSize/duration.demo.vue +88 -0
  17. package/dist/runtime/components/TransitionSize/flex.demo.vue +112 -0
  18. package/dist/runtime/components/TransitionSize/height.demo.vue +88 -0
  19. package/dist/runtime/components/TransitionSize/index.vue +69 -27
  20. package/dist/runtime/components/TransitionSize/width.demo.vue +88 -0
  21. package/dist/runtime/composables/useBrickflow.d.ts +2 -0
  22. package/dist/runtime/composables/useFieldRules.d.ts +16 -0
  23. package/dist/runtime/composables/useFieldRules.js +42 -0
  24. package/dist/runtime/utils/rules.d.ts +34 -0
  25. package/dist/runtime/utils/rules.js +68 -0
  26. package/dist/types.d.mts +2 -0
  27. package/package.json +2 -1
  28. package/dist/runtime/components/InputNumber/basic.demo.vue +0 -33
@@ -1,5 +1,7 @@
1
1
  <script setup lang="ts" generic="T extends boolean = false">
2
- import { shallowRef, watch } from 'vue'
2
+ import { computed, ref, shallowRef, watch } from 'vue'
3
+
4
+ import type { Rule } from '../../utils/rules'
3
5
 
4
6
  import { isEmpty } from '../../utils/checkup.js'
5
7
  import Input from '../Input/index.vue'
@@ -8,38 +10,75 @@
8
10
 
9
11
  const props = withDefaults(
10
12
  defineProps<{
13
+ align?: InputProps['align']
14
+ autocomplete?: string
15
+ autoWidth?: boolean
11
16
  denominator?: number
12
17
  description?: string
13
18
  disabled?: boolean
19
+ icon?: string
14
20
  label?: string
15
21
  max?: number
16
22
  min?: number
17
- nullable?: T
23
+ nullable?: boolean & T
18
24
  onBlur?: (value: true extends NoInfer<T> ? null | number : number) => void
25
+ onChange?: (value: string, target: HTMLInputElement) => void
19
26
  onFocus?: (value: true extends NoInfer<T> ? null | number : number) => void
27
+ onIconClick?: () => void
20
28
  onInput?: (value: true extends NoInfer<T> ? null | number : number) => void
21
29
  onKeydown?: (event: KeyboardEvent) => void
30
+ onTrailingIconClick?: () => void
31
+ placeholder?: string
32
+ readonly?: boolean
33
+ rules?: Rule<null | number>[]
34
+ size?: InputProps['size']
22
35
  step?: number
36
+ trailingIcon?: string
23
37
  value: true extends NoInfer<T> ? null | number : number
38
+ variant?: InputProps['variant']
24
39
  }>(),
25
40
  {
41
+ align: undefined,
42
+ autocomplete: undefined,
43
+ autoWidth: false,
26
44
  denominator: 0,
27
45
  description: undefined,
28
46
  disabled: false,
47
+ icon: undefined,
29
48
  label: undefined,
30
49
  max: undefined,
31
50
  min: undefined,
32
51
  nullable: undefined,
33
52
  onBlur: undefined,
53
+ onChange: undefined,
34
54
  onFocus: undefined,
55
+ onIconClick: undefined,
35
56
  onInput: undefined,
36
57
  onKeydown: undefined,
37
- onValueChange: undefined,
58
+ onTrailingIconClick: undefined,
59
+ placeholder: undefined,
60
+ readonly: false,
61
+ rules: undefined,
62
+ size: undefined,
38
63
  step: 1,
64
+ trailingIcon: undefined,
65
+ variant: undefined,
39
66
  },
40
67
  )
41
68
 
69
+ type InputProps = InstanceType<typeof Input>['$props']
70
+
71
+ const inputRef = ref<InstanceType<typeof Input> | null>(null)
42
72
  const inputValue = shallowRef(prepareValue(props.value))
73
+ const inputRules = computed(() =>
74
+ props.rules?.map(
75
+ (rule): Rule<string> =>
76
+ (value) =>
77
+ rule(value === '' ? null : Number(value)),
78
+ ),
79
+ )
80
+
81
+ defineExpose({ validate: () => inputRef.value?.validate() ?? true })
43
82
 
44
83
  watch(
45
84
  () => props.value,
@@ -52,31 +91,66 @@
52
91
  if (!target) {
53
92
  return
54
93
  }
94
+ if (props.nullable && target.value === '') {
95
+ inputValue.value = ''
96
+ props.onBlur?.(null as typeof props.value)
97
+ return
98
+ }
55
99
  const nextValue = prepareValue(props.value)
56
100
  target.value = nextValue
57
101
  inputValue.value = nextValue
58
102
  props.onBlur?.(props.value)
59
103
  }
104
+
105
+ function handleChange(value: string, target: HTMLInputElement): void {
106
+ props.onChange?.(value, target)
107
+ }
108
+
109
+ function handleFocus(): void {
110
+ props.onFocus?.(props.value)
111
+ }
112
+
60
113
  const allowedRegexp = /^-?\d*(?:\.\d*)?$/
61
114
  const validNumberRegexp = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/
62
115
 
116
+ function emitInput(value: typeof props.value): void {
117
+ props.onInput?.(value)
118
+ }
119
+
63
120
  function handleInput(rawValue: string, target: HTMLInputElement | null): void {
64
121
  if (!target) {
65
122
  return
66
123
  }
67
- const nextValue = rawValue.replace(/,/, '.')
124
+ let nextValue = rawValue.replace(/,/, '.')
68
125
  target.value = nextValue
69
126
 
70
127
  if (isEmpty(nextValue)) {
128
+ if (props.nullable) {
129
+ inputValue.value = ''
130
+ emitInput(null as typeof props.value)
131
+ }
71
132
  return
72
133
  }
73
134
  if (!allowedRegexp.test(nextValue)) {
74
135
  target.value = inputValue.value
75
136
  return
76
137
  }
77
- if (!validNumberRegexp.test(nextValue)) {
138
+ const fraction = nextValue.split('.')[1]
139
+ if (fraction !== undefined && (props.denominator === 0 || fraction.length > props.denominator)) {
140
+ nextValue =
141
+ props.denominator === 0
142
+ ? nextValue.slice(0, nextValue.indexOf('.'))
143
+ : nextValue.slice(0, nextValue.indexOf('.') + props.denominator + 1)
144
+ target.value = nextValue
145
+ }
146
+ if (isEmpty(nextValue) || !validNumberRegexp.test(nextValue)) {
147
+ if (isEmpty(nextValue) && props.nullable) {
148
+ inputValue.value = ''
149
+ emitInput(null as typeof props.value)
150
+ }
78
151
  return
79
152
  }
153
+
80
154
  let nextValueNumber = Number(nextValue)
81
155
  if (!isEmpty(props.min) && nextValueNumber < props.min) {
82
156
  target.value = prepareValue(props.min)
@@ -86,8 +160,41 @@
86
160
  target.value = prepareValue(props.max)
87
161
  nextValueNumber = props.max
88
162
  }
89
- props.onInput?.(nextValueNumber)
163
+
164
+ emitInput(nextValueNumber)
165
+ }
166
+
167
+ function handleKeydown(event: KeyboardEvent): void {
168
+ props.onKeydown?.(event)
169
+ if (event.defaultPrevented || (event.key !== 'ArrowUp' && event.key !== 'ArrowDown')) {
170
+ return
171
+ }
172
+ const target = event.target
173
+ if (!(target instanceof HTMLInputElement) || target.disabled || target.readOnly) {
174
+ return
175
+ }
176
+ if (!Number.isFinite(props.step) || props.step <= 0) {
177
+ return
178
+ }
179
+
180
+ event.preventDefault()
181
+ const parsedValue = Number(target.value)
182
+ const currentValue = target.value !== '' && Number.isFinite(parsedValue) ? parsedValue : (props.value ?? 0)
183
+ const direction = event.key === 'ArrowUp' ? 1 : -1
184
+ const step = props.step * (event.shiftKey ? 2 : 1)
185
+ const precision = Math.max(0, Math.min(100, Math.trunc(props.denominator)))
186
+ let nextValue = Number((currentValue + direction * step).toFixed(precision))
187
+ if (!isEmpty(props.min) && nextValue < props.min) {
188
+ nextValue = props.min
189
+ }
190
+ if (!isEmpty(props.max) && nextValue > props.max) {
191
+ nextValue = props.max
192
+ }
193
+
194
+ target.value = prepareValue(nextValue)
195
+ emitInput(nextValue)
90
196
  }
197
+
91
198
  function prepareValue(value: typeof props.value): string {
92
199
  return value === null ? '' : String(value)
93
200
  }
@@ -95,17 +202,32 @@
95
202
 
96
203
  <template>
97
204
  <Input
205
+ ref="inputRef"
98
206
  v-bind="{
99
207
  ...$attrs,
100
- // onBlur: handleBlur,
101
- // onKeydown: handleKeydown,
102
208
  }"
103
209
  :value="inputValue"
210
+ :align="props.align"
211
+ :autocomplete="props.autocomplete"
212
+ :autoWidth="props.autoWidth"
104
213
  :label="props.label"
105
214
  :description="props.description"
106
- type="decimal"
215
+ :disabled="props.disabled"
216
+ :icon="props.icon"
217
+ :placeholder="props.placeholder"
218
+ :readonly="props.readonly"
219
+ :rules="inputRules"
220
+ :size="props.size"
221
+ :trailingIcon="props.trailingIcon"
222
+ :type="props.denominator === 0 ? 'numeric' : 'decimal'"
223
+ :variant="props.variant"
107
224
  @input="handleInput"
225
+ @change="handleChange"
108
226
  @blur="handleBlur"
227
+ @focus="handleFocus"
228
+ @iconClick="props.onIconClick?.()"
229
+ @keydown="handleKeydown"
230
+ @trailingIconClick="props.onTrailingIconClick?.()"
109
231
  >
110
232
  <template
111
233
  v-if="$slots.label"
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ export const uiDemo = {
3
+ title: 'Min & Max',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref } from 'vue'
9
+
10
+ import InputNumber from './index.vue'
11
+
12
+ const price1 = ref<number>(25)
13
+ const price2 = ref<number>(-10)
14
+ </script>
15
+
16
+ <template>
17
+ <div class="flex max-w-sm flex-col gap-4">
18
+ <InputNumber
19
+ :value="price1"
20
+ label="Min: 0 — Max: 200"
21
+ :description="`Value: ${price1}`"
22
+ :min="0"
23
+ :max="200"
24
+ @input="price1 = $event"
25
+ >
26
+ <template #leading><span class="text-green-400">$</span></template>
27
+ </InputNumber>
28
+ <InputNumber
29
+ :value="price2"
30
+ label="Min: -100 — Max: 199"
31
+ :description="`Value: ${price2}`"
32
+ :min="-100"
33
+ :max="199"
34
+ @input="price2 = $event"
35
+ >
36
+ <template #leading><span class="text-green-400">$</span></template>
37
+ </InputNumber>
38
+ </div>
39
+ </template>
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ export const uiDemo = {
3
+ title: 'Nullable',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref } from 'vue'
9
+
10
+ import InputNumber from './index.vue'
11
+
12
+ const value = ref<null | number>(null)
13
+ </script>
14
+
15
+ <template>
16
+ <div class="flex max-w-sm flex-col gap-4">
17
+ <InputNumber
18
+ :value="value"
19
+ nullable
20
+ label="Nullable (clear to set null)"
21
+ :description="`Value: ${value === null ? 'null' : value}`"
22
+ @input="value = $event"
23
+ />
24
+ </div>
25
+ </template>
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ export const uiDemo = {
3
+ description: 'Step sets the change per arrow key press. Hold Shift to double it.',
4
+ title: 'Step',
5
+ }
6
+ </script>
7
+
8
+ <script lang="ts" setup>
9
+ import { ref } from 'vue'
10
+
11
+ import InputNumber from './index.vue'
12
+
13
+ const quantity = ref<number>(2)
14
+ const price = ref<number>(25)
15
+ </script>
16
+
17
+ <template>
18
+ <div class="flex max-w-sm flex-col gap-4">
19
+ <InputNumber
20
+ :value="quantity"
21
+ :step="1"
22
+ label="Step: 1"
23
+ :min="0"
24
+ :max="200"
25
+ :description="`Value: ${quantity}`"
26
+ @input="quantity = $event"
27
+ />
28
+ <InputNumber
29
+ :value="price"
30
+ :step="5"
31
+ label="Step: 5"
32
+ :min="-10"
33
+ :max="200"
34
+ :description="`Value: ${price}`"
35
+ @input="price = $event"
36
+ />
37
+ </div>
38
+ </template>
@@ -0,0 +1,88 @@
1
+ <script lang="ts">
2
+ export const uiDemo = {
3
+ title: 'Duration',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref } from 'vue'
9
+
10
+ import TransitionSize from './index.vue'
11
+
12
+ const active100 = ref(true)
13
+ const active500 = ref(true)
14
+ const active2000 = ref(true)
15
+ </script>
16
+
17
+ <template>
18
+ <div class="flex w-full flex-col">
19
+ <code class="mb-2">100</code>
20
+ <div class="flex w-full">
21
+ <TransitionSize
22
+ :duration="100"
23
+ dimension="width"
24
+ >
25
+ <div
26
+ v-if="active100"
27
+ class="w-full rounded-xl bg-slate-700 p-2 text-center"
28
+ >
29
+ Text
30
+ </div>
31
+ </TransitionSize>
32
+ <button
33
+ type="button"
34
+ class="ml-2 w-30 shrink-0 cursor-pointer rounded-xl px-3 py-2"
35
+ :class="active100 ? 'bg-blue-500' : 'bg-blue-800'"
36
+ @click="active100 = !active100"
37
+ >
38
+ {{ active100 ? 'Hide' : 'Show' }}
39
+ </button>
40
+ </div>
41
+
42
+ <code class="mt-4 mb-2">500</code>
43
+ <div class="flex">
44
+ <TransitionSize
45
+ :duration="500"
46
+ dimension="width"
47
+ >
48
+ <div
49
+ v-if="active500"
50
+ class="w-full rounded-xl bg-slate-700 p-2 text-center whitespace-nowrap"
51
+ >
52
+ Text
53
+ </div>
54
+ </TransitionSize>
55
+ <button
56
+ type="button"
57
+ class="ml-2 w-30 shrink-0 cursor-pointer rounded-xl px-3 py-2"
58
+ :class="active500 ? 'bg-blue-500' : 'bg-blue-800'"
59
+ @click="active500 = !active500"
60
+ >
61
+ {{ active500 ? 'Hide' : 'Show' }}
62
+ </button>
63
+ </div>
64
+
65
+ <code class="mt-4 mb-2">2000</code>
66
+ <div class="flex w-full">
67
+ <TransitionSize
68
+ :duration="2000"
69
+ dimension="width"
70
+ >
71
+ <div
72
+ v-if="active2000"
73
+ class="w-full rounded-xl bg-slate-700 p-2 text-center"
74
+ >
75
+ Text
76
+ </div>
77
+ </TransitionSize>
78
+ <button
79
+ type="button"
80
+ class="ml-2 w-30 shrink-0 cursor-pointer rounded-xl px-3 py-2"
81
+ :class="active2000 ? 'bg-blue-500' : 'bg-blue-800'"
82
+ @click="active2000 = !active2000"
83
+ >
84
+ {{ active2000 ? 'Hide' : 'Show' }}
85
+ </button>
86
+ </div>
87
+ </div>
88
+ </template>
@@ -0,0 +1,112 @@
1
+ <script lang="ts">
2
+ export const uiDemo = {
3
+ title: 'Flex Parent with Gap',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref } from 'vue'
9
+
10
+ import TransitionSize from './index.vue'
11
+
12
+ const baseStartRef = ref<HTMLElement | null>(null)
13
+ const baseCenterRef = ref<HTMLElement | null>(null)
14
+ const baseEndRef = ref<HTMLElement | null>(null)
15
+ const activeStart = ref(true)
16
+ const activeCenter = ref(true)
17
+ const activeEnd = ref(true)
18
+ </script>
19
+
20
+ <template>
21
+ <div class="flex flex-col">
22
+ <code class="mb-2">flexDirection="start"</code>
23
+ <div
24
+ ref="baseStartRef"
25
+ class="flex grow basis-1 gap-10"
26
+ >
27
+ <TransitionSize
28
+ :duration="1000"
29
+ :flexParent="baseStartRef"
30
+ flexDirection="start"
31
+ dimension="width"
32
+ >
33
+ <div
34
+ v-if="activeStart"
35
+ class="h-10 grow rounded-xl bg-slate-700 p-2 text-center"
36
+ >
37
+ Text
38
+ </div>
39
+ </TransitionSize>
40
+ <div class="h-10 grow rounded-xl bg-slate-800 p-2 text-center">Text</div>
41
+ <div class="h-10 grow rounded-xl bg-slate-800 p-2 text-center">Text</div>
42
+ </div>
43
+ <button
44
+ type="button"
45
+ class="mt-3 w-30 shrink-0 cursor-pointer rounded-xl px-3 py-2"
46
+ :class="activeStart ? 'bg-blue-500' : 'bg-blue-800'"
47
+ @click="activeStart = !activeStart"
48
+ >
49
+ {{ activeStart ? 'Hide' : 'Show' }}
50
+ </button>
51
+
52
+ <code class="mt-6 mb-2">flexDirection="center"</code>
53
+ <div
54
+ ref="baseCenterRef"
55
+ class="flex grow basis-1 gap-10"
56
+ >
57
+ <div class="h-10 grow rounded-xl bg-slate-800 p-2 text-center">Text</div>
58
+ <TransitionSize
59
+ :duration="1000"
60
+ :flexParent="baseCenterRef"
61
+ flexDirection="center"
62
+ dimension="width"
63
+ >
64
+ <div
65
+ v-if="activeCenter"
66
+ class="h-10 grow rounded-xl bg-slate-700 p-2 text-center"
67
+ >
68
+ Text
69
+ </div>
70
+ </TransitionSize>
71
+ <div class="h-10 grow rounded-xl bg-slate-800 p-2 text-center">Text</div>
72
+ </div>
73
+ <button
74
+ type="button"
75
+ class="mt-3 w-30 shrink-0 cursor-pointer rounded-xl px-3 py-2"
76
+ :class="activeCenter ? 'bg-blue-500' : 'bg-blue-800'"
77
+ @click="activeCenter = !activeCenter"
78
+ >
79
+ {{ activeCenter ? 'Hide' : 'Show' }}
80
+ </button>
81
+
82
+ <code class="mt-6 mb-2">flexDirection="end"</code>
83
+ <div
84
+ ref="baseEndRef"
85
+ class="flex grow basis-1 gap-10"
86
+ >
87
+ <div class="h-10 grow rounded-xl bg-slate-800 p-2 text-center">Text</div>
88
+ <div class="h-10 grow rounded-xl bg-slate-800 p-2 text-center">Text</div>
89
+ <TransitionSize
90
+ :duration="1000"
91
+ :flexParent="baseEndRef"
92
+ flexDirection="end"
93
+ dimension="width"
94
+ >
95
+ <div
96
+ v-if="activeEnd"
97
+ class="h-10 grow rounded-xl bg-slate-700 p-2 text-center"
98
+ >
99
+ Text
100
+ </div>
101
+ </TransitionSize>
102
+ </div>
103
+ <button
104
+ type="button"
105
+ class="mt-3 w-30 shrink-0 cursor-pointer rounded-xl px-3 py-2"
106
+ :class="activeEnd ? 'bg-blue-500' : 'bg-blue-800'"
107
+ @click="activeEnd = !activeEnd"
108
+ >
109
+ {{ activeEnd ? 'Hide' : 'Show' }}
110
+ </button>
111
+ </div>
112
+ </template>
@@ -0,0 +1,88 @@
1
+ <script lang="ts">
2
+ export const uiDemo = {
3
+ title: 'Height',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref } from 'vue'
9
+
10
+ import TransitionSize from './index.vue'
11
+
12
+ const activeHeightFixed = ref(true)
13
+ const activeHeightContent = ref(true)
14
+ const activeHeightFull = ref(true)
15
+ </script>
16
+
17
+ <template>
18
+ <div class="flex w-full gap-4">
19
+ <div class="flex grow basis-1 flex-col">
20
+ <label class="mb-2">Fixed height</label>
21
+ <TransitionSize
22
+ :duration="1000"
23
+ dimension="height"
24
+ >
25
+ <div
26
+ v-if="activeHeightFixed"
27
+ class="h-40 w-full rounded-xl bg-slate-700 p-2 text-center"
28
+ >
29
+ Text
30
+ </div>
31
+ </TransitionSize>
32
+ <button
33
+ type="button"
34
+ class="mt-3 w-full shrink-0 cursor-pointer rounded-xl px-3 py-2"
35
+ :class="activeHeightFixed ? 'bg-blue-500' : 'bg-blue-800'"
36
+ @click="activeHeightFixed = !activeHeightFixed"
37
+ >
38
+ {{ activeHeightFixed ? 'Hide' : 'Show' }}
39
+ </button>
40
+ </div>
41
+
42
+ <div class="flex grow basis-1 flex-col">
43
+ <label class="mb-2">Content based height</label>
44
+ <TransitionSize
45
+ :duration="1000"
46
+ dimension="height"
47
+ >
48
+ <div
49
+ v-if="activeHeightContent"
50
+ class="rounded-xl bg-slate-700 p-2 text-center"
51
+ >
52
+ Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tenetur nihil possimus sunt ipsum rerum maiores
53
+ </div>
54
+ </TransitionSize>
55
+ <button
56
+ type="button"
57
+ class="mt-3 w-full shrink-0 cursor-pointer rounded-xl px-3 py-2"
58
+ :class="activeHeightContent ? 'bg-blue-500' : 'bg-blue-800'"
59
+ @click="activeHeightContent = !activeHeightContent"
60
+ >
61
+ {{ activeHeightContent ? 'Hide' : 'Show' }}
62
+ </button>
63
+ </div>
64
+
65
+ <div class="flex h-auto grow basis-1 flex-col self-stretch">
66
+ <label class="mb-2">Full height</label>
67
+ <TransitionSize
68
+ :duration="1000"
69
+ dimension="height"
70
+ >
71
+ <div
72
+ v-if="activeHeightFull"
73
+ class="w-full grow rounded-xl bg-slate-700 p-2 text-center"
74
+ >
75
+ Text
76
+ </div>
77
+ </TransitionSize>
78
+ <button
79
+ type="button"
80
+ class="mt-3 w-full shrink-0 cursor-pointer rounded-xl px-3 py-2"
81
+ :class="activeHeightFull ? 'bg-blue-500' : 'bg-blue-800'"
82
+ @click="activeHeightFull = !activeHeightFull"
83
+ >
84
+ {{ activeHeightFull ? 'Hide' : 'Show' }}
85
+ </button>
86
+ </div>
87
+ </div>
88
+ </template>