@wishbone-media/spark 1.0.0 → 1.2.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": "@wishbone-media/spark",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -18,8 +18,8 @@ defineEmits(['click'])
18
18
  const props = defineProps({
19
19
  size: {
20
20
  type: String,
21
- default: 'md',
22
- validator: (value) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(value),
21
+ default: undefined,
22
+ validator: (value) => value === undefined || ['xs', 'sm', 'md', 'lg', 'xl'].includes(value),
23
23
  },
24
24
  variant: {
25
25
  type: String,
@@ -37,6 +37,8 @@ const props = defineProps({
37
37
 
38
38
  const buttonRef = ref(null)
39
39
  const buttonGroup = inject('buttonGroup', null)
40
+ const headerContext = inject('sparkCardHeaderContext', null)
41
+ const effectiveSize = computed(() => props.size ?? headerContext?.buttonSize ?? 'md')
40
42
 
41
43
  const groupPosition = computed(() => {
42
44
  if (!buttonGroup?.isInGroup || !buttonRef.value) return null
@@ -91,7 +93,7 @@ const computedButtonClass = computed(() => {
91
93
  let classes = 'cursor-pointer'
92
94
  let roundingSize = ''
93
95
 
94
- switch (props.size) {
96
+ switch (effectiveSize.value) {
95
97
  case 'xs':
96
98
  classes += ' px-4 py-1 text-xs'
97
99
  roundingSize = 'sm'
@@ -10,39 +10,52 @@
10
10
  <slot name="header" />
11
11
  </div>
12
12
 
13
- <div
14
- v-else-if="hasDefaultHeader"
15
- :class="[
16
- 'flex h-20 items-stretch justify-between gap-4 border-b border-gray-300 px-5',
17
- props.headerClass,
18
- ]"
19
- >
20
- <div class="flex min-w-0 items-center gap-3">
21
- <SparkButton
22
- v-if="props.backTo"
23
- variant="secondary"
24
- button-class="w-10 h-10 grid place-content-center"
25
- @click="router?.push(props.backTo)"
26
- >
27
- <FontAwesomeIcon :icon="Icons.farChevronLeft" class="text-gray-500" />
28
- </SparkButton>
29
- <h3
30
- v-if="props.title"
31
- class="min-w-0 truncate text-xl font-semibold leading-6 text-gray-800"
32
- >
33
- {{ props.title }}
34
- </h3>
35
- <slot name="title-extra" />
36
- <div v-if="$slots.nav" class="flex self-stretch items-stretch">
37
- <slot name="nav" />
13
+ <HeaderContext v-else-if="hasDefaultHeader">
14
+ <div
15
+ :class="[
16
+ 'flex h-20 items-stretch justify-between gap-2.5 border-b border-gray-300 px-5',
17
+ props.headerClass,
18
+ ]"
19
+ >
20
+ <div class="flex min-w-0 items-center gap-3">
21
+ <SparkButton
22
+ v-if="props.backTo"
23
+ variant="secondary"
24
+ size="sm"
25
+ button-class="w-[34px] h-[34px] grid place-content-center"
26
+ @click="router?.push(props.backTo)"
27
+ >
28
+ <FontAwesomeIcon :icon="Icons.farChevronLeft" class="text-gray-500" />
29
+ </SparkButton>
30
+ <h3 v-if="props.title" class="min-w-0 truncate font-semibold leading-6 text-gray-800">
31
+ {{ props.title }}
32
+ </h3>
33
+ <slot name="title-extra" />
34
+ <div v-if="$slots.nav" class="flex self-stretch items-stretch">
35
+ <slot name="nav" />
36
+ </div>
37
+ <div
38
+ v-if="$slots['header-left']"
39
+ class="flex items-center gap-2.5 text-sm text-gray-700 [&_.formkit-outer]:!mb-0"
40
+ >
41
+ <slot name="header-left" />
42
+ </div>
38
43
  </div>
39
- </div>
40
44
 
41
- <div v-if="$slots.meta || $slots.actions" class="flex shrink-0 items-center gap-4">
42
- <slot name="meta" />
43
- <slot name="actions" />
45
+ <div
46
+ v-if="$slots['header-right'] || $slots.actions"
47
+ class="flex shrink-0 items-center gap-2.5"
48
+ >
49
+ <div
50
+ v-if="$slots['header-right']"
51
+ class="flex items-center gap-2.5 text-sm text-gray-700 [&_.formkit-outer]:!mb-0"
52
+ >
53
+ <slot name="header-right" />
54
+ </div>
55
+ <slot name="actions" />
56
+ </div>
44
57
  </div>
45
- </div>
58
+ </HeaderContext>
46
59
 
47
60
  <div
48
61
  ref="bodyEl"
@@ -59,12 +72,19 @@
59
72
  </template>
60
73
 
61
74
  <script setup>
62
- import { computed, ref, useSlots } from 'vue'
75
+ import { computed, defineComponent, provide, ref, useSlots } from 'vue'
63
76
  import { useRouter } from 'vue-router'
64
77
  import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
65
78
  import { Icons } from '../plugins/fontawesome.js'
66
79
  import SparkButton from './SparkButton.vue'
67
80
 
81
+ const HeaderContext = defineComponent({
82
+ setup(_, { slots }) {
83
+ provide('sparkCardHeaderContext', { buttonSize: 'xl' })
84
+ return () => slots.default?.()
85
+ },
86
+ })
87
+
68
88
  const props = defineProps({
69
89
  padded: {
70
90
  type: Boolean,
@@ -95,8 +115,8 @@ const props = defineProps({
95
115
  default: '',
96
116
  },
97
117
  // Default header: main heading text. Renders the header without needing
98
- // the #header slot; combine with backTo and the title-extra/nav/meta/actions
99
- // slots. The #header slot overrides the default header entirely.
118
+ // the #header slot; combine with backTo and the named/catch-all slots.
119
+ // The #header slot overrides the default header entirely.
100
120
  title: {
101
121
  type: String,
102
122
  default: null,
@@ -114,7 +134,13 @@ const bodyEl = ref(null)
114
134
 
115
135
  const hasDefaultHeader = computed(() =>
116
136
  Boolean(
117
- props.title || props.backTo || slots['title-extra'] || slots.nav || slots.meta || slots.actions,
137
+ props.title ||
138
+ props.backTo ||
139
+ slots['title-extra'] ||
140
+ slots.nav ||
141
+ slots['header-left'] ||
142
+ slots['header-right'] ||
143
+ slots.actions,
118
144
  ),
119
145
  )
120
146
 
@@ -220,10 +220,10 @@ function getItemClasses(item) {
220
220
 
221
221
  // Tabs layout (underline style)
222
222
  function getTabsClasses(isActive, isDisabled) {
223
- const classes = ['border-b-2 -mb-px rounded-t font-medium']
223
+ const classes = ['border-b-2 -mb-2px rounded-t font-medium']
224
224
 
225
225
  // Size classes
226
- const sizeClasses = props.compact ? 'text-sm px-3 py-1.5' : 'text-sm px-8 py-4'
226
+ const sizeClasses = props.compact ? 'text-sm px-3 py-1.5' : 'text-sm px-5 py-4'
227
227
  classes.push(sizeClasses)
228
228
 
229
229
  if (isActive) {
@@ -241,7 +241,7 @@ function getTabsClasses(isActive, isDisabled) {
241
241
  function getButtonClasses(isActive, isDisabled) {
242
242
  const classes = ['rounded-lg border font-medium']
243
243
 
244
- classes.push(props.compact ? 'text-sm px-3 py-1.5' : 'text-sm px-4 py-2')
244
+ classes.push(props.compact ? 'text-sm px-3 py-1.5' : 'text-sm px-4 py-2.5')
245
245
 
246
246
  if (isActive) {
247
247
  classes.push('border-gray-300 bg-white text-gray-900')