@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseed/redseed-ui-vue3",
3
- "version": "8.53.0",
3
+ "version": "8.54.0",
4
4
  "description": "RedSeed UI Vue 3 components",
5
5
  "main": "index.js",
6
6
  "repository": "https://github.com/redseedtraining/redseed-ui",
@@ -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>
@@ -0,0 +1,5 @@
1
+ import Pill from './Pill.vue'
2
+
3
+ export {
4
+ Pill,
5
+ }