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 wrapper = mountComponent(widget, 'test')
|
||||
|
||||
const textarea = wrapper.find('textarea')
|
||||
expect(textarea.attributes('placeholder')).toBe('test_textarea')
|
||||
const textareaLabel = wrapper.find('label')
|
||||
expect(textareaLabel.text()).toBe('test_textarea')
|
||||
})
|
||||
|
||||
it('uses provided placeholder when specified', () => {
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
<template>
|
||||
<Textarea
|
||||
v-model="modelValue"
|
||||
v-bind="filteredProps"
|
||||
:class="cn(WidgetInputBaseClass, 'relative size-full text-xs resize-none')"
|
||||
:placeholder="placeholder || widget.name || ''"
|
||||
:aria-label="widget.name"
|
||||
:readonly="widget.options?.read_only"
|
||||
:disabled="widget.options?.read_only"
|
||||
fluid
|
||||
data-capture-wheel="true"
|
||||
@pointerdown.capture.stop
|
||||
@pointermove.capture.stop
|
||||
@pointerup.capture.stop
|
||||
@contextmenu.capture.stop
|
||||
/>
|
||||
<FloatLabel variant="in">
|
||||
<Textarea
|
||||
v-bind="filteredProps"
|
||||
:id
|
||||
v-model="modelValue"
|
||||
:class="cn(WidgetInputBaseClass, 'size-full text-xs resize-none')"
|
||||
:placeholder
|
||||
:readonly="widget.options?.read_only"
|
||||
:disabled="widget.options?.read_only"
|
||||
fluid
|
||||
data-capture-wheel="true"
|
||||
@pointerdown.capture.stop
|
||||
@pointermove.capture.stop
|
||||
@pointerup.capture.stop
|
||||
@contextmenu.capture.stop
|
||||
/>
|
||||
<label :for="id">{{ displayName }}</label>
|
||||
</FloatLabel>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FloatLabel from 'primevue/floatlabel'
|
||||
import Textarea from 'primevue/textarea'
|
||||
import { computed } from 'vue'
|
||||
import { computed, useId } from 'vue'
|
||||
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
@@ -39,4 +43,7 @@ const modelValue = defineModel<string>({ default: '' })
|
||||
const filteredProps = computed(() =>
|
||||
filterWidgetProps(widget.options, INPUT_EXCLUDED_PROPS)
|
||||
)
|
||||
|
||||
const displayName = computed(() => widget.label || widget.name)
|
||||
const id = useId()
|
||||
</script>
|
||||
|
||||