@redseed/redseed-ui-vue3 8.53.0 → 8.54.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/index.js +1 -0
- package/package.json +1 -1
- package/src/components/Pill/Pill.vue +103 -0
- package/src/components/Pill/index.js +5 -0
package/index.js
CHANGED
|
@@ -36,6 +36,7 @@ export * from './src/components/MessageBox'
|
|
|
36
36
|
export * from './src/components/MetaInfo'
|
|
37
37
|
export * from './src/components/Modal'
|
|
38
38
|
export * from './src/components/Pagination'
|
|
39
|
+
export * from './src/components/Pill'
|
|
39
40
|
export * from './src/components/Progress'
|
|
40
41
|
export * from './src/components/Section'
|
|
41
42
|
export * from './src/components/Skeleton'
|
package/package.json
CHANGED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed, onMounted, watchEffect } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
selected: {
|
|
6
|
+
type: Boolean,
|
|
7
|
+
default: false,
|
|
8
|
+
},
|
|
9
|
+
disabled: {
|
|
10
|
+
type: Boolean,
|
|
11
|
+
default: false,
|
|
12
|
+
},
|
|
13
|
+
// The name of a RUNTIME CSS custom property to use as the accent — applied as
|
|
14
|
+
// `var(--<color>, <neutral>)`, driving the icon-badge fill and the selected
|
|
15
|
+
// ring/tint. Pass a real runtime theme variable, e.g. the consuming app's
|
|
16
|
+
// palette (`color7` → `var(--color7)`). NOTE: RSUI's own Tailwind `@theme`
|
|
17
|
+
// color tokens (e.g. `--color-brand-500`) are inlined into utilities, not
|
|
18
|
+
// exposed as runtime vars, so they will NOT resolve here. An UNRESOLVABLE
|
|
19
|
+
// (undefined) token degrades to a neutral grey rather than an invisible pill;
|
|
20
|
+
// a token that *resolves* to `transparent`/empty is not caught — passing a
|
|
21
|
+
// real colour is the consumer's responsibility. Optional — falls back to a
|
|
22
|
+
// neutral accent when omitted, so RSUI stays theme-agnostic.
|
|
23
|
+
color: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: '',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const emit = defineEmits(['click'])
|
|
30
|
+
|
|
31
|
+
// The single accent token colours both the icon badge and the selected
|
|
32
|
+
// treatment. When no color is supplied we leave the property unset so the CSS
|
|
33
|
+
// neutral fallback applies. When a color IS supplied it carries an inline
|
|
34
|
+
// fallback to the neutral grey, so an UNRESOLVABLE (undefined) token degrades to
|
|
35
|
+
// grey rather than an invisible badge/selection. Note: var()'s fallback does not
|
|
36
|
+
// fire for a token that *resolves* to transparent/empty — passing a real colour
|
|
37
|
+
// is the consumer's responsibility.
|
|
38
|
+
const accentStyle = computed(() =>
|
|
39
|
+
props.color
|
|
40
|
+
? { '--rsui-pill-accent': `var(--${props.color}, var(--Colors-Grey-500))` }
|
|
41
|
+
: {},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const pillClass = computed(() => [
|
|
45
|
+
'rsui-pill',
|
|
46
|
+
{
|
|
47
|
+
'rsui-pill--selected': props.selected && !props.disabled,
|
|
48
|
+
'rsui-pill--disabled': props.disabled,
|
|
49
|
+
},
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
function handleClick(event) {
|
|
53
|
+
// Guarded — a disabled pill emits nothing even if a click reaches it.
|
|
54
|
+
if (props.disabled) return
|
|
55
|
+
|
|
56
|
+
emit('click', event)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// button element ref, used for the icon-only accessibility check
|
|
60
|
+
const pillElementRef = ref(null)
|
|
61
|
+
|
|
62
|
+
// an icon-only pill has no visible label text
|
|
63
|
+
const iconOnly = computed(
|
|
64
|
+
() => pillElementRef.value && !pillElementRef.value.textContent.trim(),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
// warn in development when an icon-only pill lacks an accessible name
|
|
68
|
+
onMounted(() => {
|
|
69
|
+
watchEffect(() => {
|
|
70
|
+
if (
|
|
71
|
+
process.env.NODE_ENV !== 'production' &&
|
|
72
|
+
iconOnly.value &&
|
|
73
|
+
!pillElementRef.value.getAttribute('aria-label') &&
|
|
74
|
+
!pillElementRef.value.getAttribute('aria-labelledby')
|
|
75
|
+
) {
|
|
76
|
+
console.warn(
|
|
77
|
+
'[RSUI] Icon-only Pill detected without aria-label. Add aria-label for accessibility.',
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
defineExpose({
|
|
84
|
+
pillElementRef,
|
|
85
|
+
})
|
|
86
|
+
</script>
|
|
87
|
+
<template>
|
|
88
|
+
<button
|
|
89
|
+
ref="pillElementRef"
|
|
90
|
+
:class="pillClass"
|
|
91
|
+
:style="accentStyle"
|
|
92
|
+
:disabled="props.disabled"
|
|
93
|
+
:aria-pressed="props.selected && !props.disabled"
|
|
94
|
+
type="button"
|
|
95
|
+
@click="handleClick"
|
|
96
|
+
>
|
|
97
|
+
<span v-if="$slots.icon" class="rsui-pill__icon" aria-hidden="true">
|
|
98
|
+
<slot name="icon"></slot>
|
|
99
|
+
</span>
|
|
100
|
+
|
|
101
|
+
<slot></slot>
|
|
102
|
+
</button>
|
|
103
|
+
</template>
|