@redseed/redseed-ui-vue3 8.63.0 → 8.64.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redseed/redseed-ui-vue3",
3
- "version": "8.63.0",
3
+ "version": "8.64.0",
4
4
  "description": "RedSeed UI Vue 3 components",
5
5
  "main": "index.js",
6
6
  "repository": "https://github.com/redseedtraining/redseed-ui",
@@ -7,6 +7,12 @@ const props = defineProps({
7
7
  type: Boolean,
8
8
  default: false,
9
9
  },
10
+ // Declared rather than left to fall through: a prop named onXxx is ambiguous
11
+ // with an event listener, so it is forwarded by name. See ButtonSlot.
12
+ onColor: {
13
+ type: Boolean,
14
+ default: false,
15
+ },
10
16
  })
11
17
 
12
18
  const buttonClass = computed(() => [
@@ -17,7 +23,7 @@ const buttonClass = computed(() => [
17
23
  ])
18
24
  </script>
19
25
  <template>
20
- <ButtonSlot :class="buttonClass">
26
+ <ButtonSlot :class="buttonClass" :on-color="props.onColor">
21
27
  <slot></slot>
22
28
  </ButtonSlot>
23
29
  </template>
@@ -1,15 +1,21 @@
1
1
  <script setup>
2
2
  import ButtonPrimary from './ButtonPrimary.vue'
3
3
 
4
- defineProps({
4
+ // Forwarded by name for the same reason ButtonPrimary declares it: a prop called onXxx
5
+ // is ambiguous with an event listener, so it is not left to fall through.
6
+ const props = defineProps({
5
7
  invert: {
6
8
  type: Boolean,
7
9
  default: false,
8
10
  },
11
+ onColor: {
12
+ type: Boolean,
13
+ default: false,
14
+ },
9
15
  })
10
16
  </script>
11
17
  <template>
12
- <ButtonPrimary full :invert="invert">
18
+ <ButtonPrimary full :on-color="props.onColor" :invert="props.invert">
13
19
  <slot></slot>
14
20
  </ButtonPrimary>
15
21
  </template>
@@ -1,8 +1,22 @@
1
1
  <script setup>
2
+ import { computed } from 'vue'
2
3
  import ButtonSlot from './ButtonSlot.vue'
4
+
5
+ const props = defineProps({
6
+ // Declared rather than left to fall through: a prop named onXxx is ambiguous
7
+ // with an event listener, so it is forwarded by name. See ButtonSlot.
8
+ onColor: {
9
+ type: Boolean,
10
+ default: false,
11
+ },
12
+ })
13
+
14
+ const buttonClass = computed(() => [
15
+ 'rsui-button-secondary',
16
+ ])
3
17
  </script>
4
18
  <template>
5
- <ButtonSlot class="rsui-button-secondary">
19
+ <ButtonSlot :class="buttonClass" :on-color="props.onColor">
6
20
  <slot></slot>
7
21
  </ButtonSlot>
8
22
  </template>
@@ -1,8 +1,17 @@
1
1
  <script setup>
2
2
  import ButtonSecondary from './ButtonSecondary.vue'
3
+
4
+ // Forwarded by name for the same reason ButtonSecondary declares it: a prop called onXxx
5
+ // is ambiguous with an event listener, so it is not left to fall through.
6
+ const props = defineProps({
7
+ onColor: {
8
+ type: Boolean,
9
+ default: false,
10
+ },
11
+ })
3
12
  </script>
4
13
  <template>
5
- <ButtonSecondary full>
14
+ <ButtonSecondary full :on-color="props.onColor">
6
15
  <slot></slot>
7
16
  </ButtonSecondary>
8
17
  </template>
@@ -35,6 +35,22 @@ const props = defineProps({
35
35
  default: 'center',
36
36
  validator: (value) => ['left', 'center', 'right'].includes(value)
37
37
  },
38
+ // Set when the button sits on a COLOURED or DARK surface — a tonal PageHeader
39
+ // band, a toned MetricCard, the AI insight panel. Every variant is drawn for a
40
+ // light ground and has no correct rendering on a dark one: secondary's white
41
+ // fill disappears, tertiary's ink goes near-invisible.
42
+ //
43
+ // Named to match BodyText's and StageDial's `onColor` rather than the existing
44
+ // `invert` on Primary and Danger, which is a different thing: invert means a
45
+ // transparent fill with brand ink, an outline treatment for a LIGHT surface.
46
+ // The two compose.
47
+ //
48
+ // The ink for the filled treatment comes from the surface, through
49
+ // --rsui-button-on-color-ink — the button cannot know what it is sitting on.
50
+ onColor: {
51
+ type: Boolean,
52
+ default: false,
53
+ },
38
54
  })
39
55
 
40
56
  defineEmits(['click'])
@@ -90,6 +106,9 @@ const buttonSlotClass = computed(() => [
90
106
  // button full width
91
107
  'rsui-button-slot--full': props.full,
92
108
 
109
+ // button on a coloured or dark surface
110
+ 'rsui-button-slot--on-color': props.onColor,
111
+
93
112
  // button alignment
94
113
  'rsui-button-slot--left': props.alignment === 'left',
95
114
  'rsui-button-slot--center': props.alignment === 'center',
@@ -1,8 +1,22 @@
1
1
  <script setup>
2
+ import { computed } from 'vue'
2
3
  import ButtonSlot from './ButtonSlot.vue'
4
+
5
+ const props = defineProps({
6
+ // Declared rather than left to fall through: a prop named onXxx is ambiguous
7
+ // with an event listener, so it is forwarded by name. See ButtonSlot.
8
+ onColor: {
9
+ type: Boolean,
10
+ default: false,
11
+ },
12
+ })
13
+
14
+ const buttonClass = computed(() => [
15
+ 'rsui-button-tertiary',
16
+ ])
3
17
  </script>
4
18
  <template>
5
- <ButtonSlot class="rsui-button-tertiary">
19
+ <ButtonSlot :class="buttonClass" :on-color="props.onColor">
6
20
  <slot></slot>
7
21
  </ButtonSlot>
8
22
  </template>
@@ -1,8 +1,17 @@
1
1
  <script setup>
2
2
  import ButtonTertiary from './ButtonTertiary.vue'
3
+
4
+ // Forwarded by name for the same reason ButtonTertiary declares it: a prop called onXxx
5
+ // is ambiguous with an event listener, so it is not left to fall through.
6
+ const props = defineProps({
7
+ onColor: {
8
+ type: Boolean,
9
+ default: false,
10
+ },
11
+ })
3
12
  </script>
4
13
  <template>
5
- <ButtonTertiary full>
14
+ <ButtonTertiary full :on-color="props.onColor">
6
15
  <slot></slot>
7
16
  </ButtonTertiary>
8
17
  </template>
@@ -27,6 +27,17 @@ const props = defineProps({
27
27
  type: Boolean,
28
28
  default: false,
29
29
  },
30
+ // The AI family at full strength: a BOLD dark surface rather than the pale
31
+ // lilac wash `ai` gives. Every other Card variant is a light tint, so this is
32
+ // the first card that has to carry light type — it adapts CardHeader's ink and
33
+ // flips the hover scrim, both of which assume a light ground.
34
+ //
35
+ // BodyText inside it is NOT adapted: that component has its own `onColor` prop,
36
+ // which is the explicit route and would only fight an override from here.
37
+ aiBold: {
38
+ type: Boolean,
39
+ default: false,
40
+ },
30
41
  secondary: {
31
42
  type: Boolean,
32
43
  default: false,
@@ -111,6 +122,7 @@ const cardClass = computed(() => [
111
122
  'rsui-card--clickable': props.clickable && !props.disabled,
112
123
  'rsui-card--bordered': props.bordered,
113
124
  'rsui-card--ai': props.ai,
125
+ 'rsui-card--ai-bold': props.aiBold,
114
126
  'rsui-card--secondary': props.secondary,
115
127
  'rsui-card--brand': props.brand,
116
128
  'rsui-card--success': props.success,
@@ -14,6 +14,12 @@ const props = defineProps({
14
14
  type: Boolean,
15
15
  default: true,
16
16
  },
17
+ // Matches showBadge and showSubtitle: the slot is opt-in by being filled, and
18
+ // this exists so a consumer can suppress it without unbinding the slot.
19
+ showEyebrow: {
20
+ type: Boolean,
21
+ default: true,
22
+ },
17
23
  showSubtitle: {
18
24
  type: Boolean,
19
25
  default: true,
@@ -26,9 +32,14 @@ const props = defineProps({
26
32
  type: Boolean,
27
33
  default: true,
28
34
  },
35
+ // Default false: Material 3 cards are one continuous padded surface, and a
36
+ // full-bleed rule between the header and the body made every card read as two
37
+ // stacked boxes rather than one tile. Still available for the cases that want
38
+ // it — a header over a table, or a disclosure — where it separates two genuinely
39
+ // different regions rather than splitting one.
29
40
  showDivider: {
30
41
  type: Boolean,
31
- default: true,
42
+ default: false,
32
43
  },
33
44
  singleLine: {
34
45
  type: Boolean,
@@ -95,6 +106,19 @@ function handleMoreActionsClick() {
95
106
 
96
107
  <div class="rsui-card-header__text">
97
108
 
109
+ <!--
110
+ Eyebrow slot, optional. ABOVE the title, which is the one position
111
+ the header had no slot for: badge and subtitle both render below it
112
+ and the flex column has no order overrides, so there was no way to
113
+ put a label over a card title without hand-rolling the header.
114
+ Takes plain text or a badge — BadgeRedSeedAI is the common case.
115
+ -->
116
+ <div class="rsui-card-header__eyebrow"
117
+ v-if="showEyebrow && $slots.eyebrow"
118
+ >
119
+ <slot name="eyebrow"></slot>
120
+ </div>
121
+
98
122
  <!-- Title slot, default slot -->
99
123
  <div class="rsui-card-header__title-container">
100
124
  <div :class="[
@@ -119,13 +143,6 @@ function handleMoreActionsClick() {
119
143
  >
120
144
  <slot name="subtitle"></slot>
121
145
  </div>
122
-
123
- <!-- Badge slot, optional -->
124
- <div class="rsui-card-header__badge"
125
- v-if="showBadge && $slots.badge"
126
- >
127
- <slot name="badge"></slot>
128
- </div>
129
146
  </div>
130
147
 
131
148
  <!-- Actions slot, optional -->
@@ -158,6 +175,15 @@ function handleMoreActionsClick() {
158
175
  </div>
159
176
  </div>
160
177
 
178
+ <!-- Badge slot, optional. A sibling of __header rather than a child of __text, so it
179
+ sits on the card's own left edge — level with the body below it — instead of being
180
+ indented past the avatar with the title. -->
181
+ <div class="rsui-card-header__badge"
182
+ v-if="showBadge && $slots.badge"
183
+ >
184
+ <slot name="badge"></slot>
185
+ </div>
186
+
161
187
  <!-- Mobile actions slot, optional -->
162
188
  <div class="rsui-card-header__actions-mobile"
163
189
  v-if="showActions && !responsiveWidth.specific && $slots.actions"
@@ -16,6 +16,18 @@ const props = defineProps({
16
16
  type: Boolean,
17
17
  default: false
18
18
  },
19
+ // Size ramp. Booleans, only one applies at a time — the library convention, and
20
+ // the same three steps StageDial uses. `sm` is the default and renders exactly
21
+ // as the unnamed default did, so nothing changes for existing consumers.
22
+ //
23
+ // Note the names sit one step below the type scale they produce: sm is text-xs,
24
+ // md is text-sm, lg is text-base. That predates this change and is left alone,
25
+ // because `md` and `lg` are used in consuming apps and renaming them would be a
26
+ // breaking change for a cosmetic gain.
27
+ sm: {
28
+ type: Boolean,
29
+ default: false
30
+ },
19
31
  md: {
20
32
  type: Boolean,
21
33
  default: false
@@ -26,12 +38,23 @@ const props = defineProps({
26
38
  }
27
39
  })
28
40
 
41
+ // Largest flag wins, so passing more than one still gives a defined result. It used
42
+ // to spread the booleans straight onto the class list, which meant `<MetaInfo md lg>`
43
+ // emitted BOTH modifiers and the winner came down to the order meta_info.css
44
+ // happened to be imported in.
45
+ const activeSize = computed(() => {
46
+ if (props.lg) return 'lg'
47
+ if (props.md) return 'md'
48
+ if (props.sm) return 'sm'
49
+
50
+ return 'sm'
51
+ })
52
+
29
53
  const metaInfoClass = computed(() => [
30
54
  'rsui-meta-info',
55
+ `rsui-meta-info--${activeSize.value}`,
31
56
  {
32
57
  'rsui-meta-info--inline': props.inline,
33
- 'rsui-meta-info--md': props.md,
34
- 'rsui-meta-info--lg': props.lg,
35
58
  }
36
59
  ])
37
60
 
@@ -22,9 +22,14 @@ const props = defineProps({
22
22
  type: Boolean,
23
23
  default: true,
24
24
  },
25
+ // Default false. It was true, but no CSS rule existed behind the --divider class,
26
+ // so every consumer has been seeing no rule regardless. The rule exists now; keeping
27
+ // the default at true would make hairlines appear under every section header in every
28
+ // app off the back of a spacing fix. False preserves what they actually see today and
29
+ // makes the prop work for anyone who opts in. Matches CardHeader.
25
30
  showDivider: {
26
31
  type: Boolean,
27
- default: true,
32
+ default: false,
28
33
  },
29
34
  noClamp: {
30
35
  type: Boolean,