Feat: add floating label to textarea (#7121)
## Summary Adds the label/name of the widget as a floating label. ## Screenshots <img width="543" height="469" alt="image" src="https://github.com/user-attachments/assets/99d70e0b-f7b7-4b62-bf15-a2db8437c886" /> <!-- Add screenshots or video recording to help explain your changes --> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7121-Feat-add-floating-label-to-textarea-2be6d73d3650819c958efa893e0e304a) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 123 KiB |
@@ -179,8 +179,8 @@ describe('WidgetTextarea Value Binding', () => {
|
|||||||
const widget = createMockWidget('test')
|
const widget = createMockWidget('test')
|
||||||
const wrapper = mountComponent(widget, 'test')
|
const wrapper = mountComponent(widget, 'test')
|
||||||
|
|
||||||
const textarea = wrapper.find('textarea')
|
const textareaLabel = wrapper.find('label')
|
||||||
expect(textarea.attributes('placeholder')).toBe('test_textarea')
|
expect(textareaLabel.text()).toBe('test_textarea')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('uses provided placeholder when specified', () => {
|
it('uses provided placeholder when specified', () => {
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<Textarea
|
<FloatLabel variant="in">
|
||||||
v-model="modelValue"
|
<Textarea
|
||||||
v-bind="filteredProps"
|
v-bind="filteredProps"
|
||||||
:class="cn(WidgetInputBaseClass, 'relative size-full text-xs resize-none')"
|
:id
|
||||||
:placeholder="placeholder || widget.name || ''"
|
v-model="modelValue"
|
||||||
:aria-label="widget.name"
|
:class="cn(WidgetInputBaseClass, 'size-full text-xs resize-none')"
|
||||||
:readonly="widget.options?.read_only"
|
:placeholder
|
||||||
:disabled="widget.options?.read_only"
|
:readonly="widget.options?.read_only"
|
||||||
fluid
|
:disabled="widget.options?.read_only"
|
||||||
data-capture-wheel="true"
|
fluid
|
||||||
@pointerdown.capture.stop
|
data-capture-wheel="true"
|
||||||
@pointermove.capture.stop
|
@pointerdown.capture.stop
|
||||||
@pointerup.capture.stop
|
@pointermove.capture.stop
|
||||||
@contextmenu.capture.stop
|
@pointerup.capture.stop
|
||||||
/>
|
@contextmenu.capture.stop
|
||||||
|
/>
|
||||||
|
<label :for="id">{{ displayName }}</label>
|
||||||
|
</FloatLabel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import FloatLabel from 'primevue/floatlabel'
|
||||||
import Textarea from 'primevue/textarea'
|
import Textarea from 'primevue/textarea'
|
||||||
import { computed } from 'vue'
|
import { computed, useId } from 'vue'
|
||||||
|
|
||||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||||
import { cn } from '@/utils/tailwindUtil'
|
import { cn } from '@/utils/tailwindUtil'
|
||||||
@@ -39,4 +43,7 @@ const modelValue = defineModel<string>({ default: '' })
|
|||||||
const filteredProps = computed(() =>
|
const filteredProps = computed(() =>
|
||||||
filterWidgetProps(widget.options, INPUT_EXCLUDED_PROPS)
|
filterWidgetProps(widget.options, INPUT_EXCLUDED_PROPS)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const displayName = computed(() => widget.label || widget.name)
|
||||||
|
const id = useId()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||