@redseed/redseed-ui-vue3 2.20.0 → 2.21.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": "2.20.0",
3
+ "version": "2.21.0",
4
4
  "description": "RedSeed UI Vue 3 components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,73 @@
1
+ <script setup>
2
+ import { ref, computed, watch } from 'vue'
3
+ import ProgressTrackerStep from './ProgressTrackerStep.vue'
4
+
5
+ const props = defineProps({
6
+ steps: {
7
+ type: Array,
8
+ default: () => [],
9
+ },
10
+ clickable: {
11
+ type: Boolean,
12
+ default: false,
13
+ },
14
+ skippable: {
15
+ type: Boolean,
16
+ default: false,
17
+ },
18
+ })
19
+
20
+ const internalSteps = ref(props.steps)
21
+
22
+ const activeStep = ref(props.steps.find(step => !!step.active) || props.steps[0])
23
+
24
+ const activeStepIndex = computed(() => internalSteps.value.findIndex(step => step === activeStep.value))
25
+
26
+ watch(() => props.steps, () => {
27
+ internalSteps.value = props.steps
28
+ activeStep.value = internalSteps.value.find(step => !!step.active) || internalSteps.value[0]
29
+ }, { deep: true })
30
+
31
+ const emit = defineEmits(['change'])
32
+
33
+ function handleStepClick(clickedStep) {
34
+ if (!props.clickable) return
35
+
36
+ const currentActiveStep = internalSteps.value.find(step => step === activeStep.value)
37
+ currentActiveStep.completed = true
38
+ currentActiveStep.active = false
39
+
40
+ const step = internalSteps.value.find(step => step === clickedStep)
41
+ step.active = true
42
+ activeStep.value = step
43
+
44
+ emit('change', step)
45
+ }
46
+ </script>
47
+ <template>
48
+ <div class="rsui-progress-tracker">
49
+ <slot :internalSteps="internalSteps">
50
+ <ProgressTrackerStep v-for="(step, index) in internalSteps"
51
+ :key="step"
52
+ :step="step"
53
+ :completed="!!step.completed"
54
+ :active="index === activeStepIndex"
55
+ :clickable="clickable"
56
+ :skippable="skippable || index === activeStepIndex + 1"
57
+ @click="handleStepClick(step)"
58
+ >
59
+ <template #indicator>
60
+ {{ index + 1 }}
61
+ </template>
62
+
63
+ {{ step.label }}
64
+ </ProgressTrackerStep>
65
+ </slot>
66
+ </div>
67
+ </template>
68
+ <style lang="scss" scoped>
69
+ .rsui-progress-tracker {
70
+ @apply grid grid-flow-col auto-cols-fr gap-16;
71
+ @apply text-xl font-medium;
72
+ }
73
+ </style>
@@ -0,0 +1,107 @@
1
+ <script setup>
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps({
5
+ step: {
6
+ type: Object,
7
+ default: null,
8
+ },
9
+ active: {
10
+ type: Boolean,
11
+ default: false,
12
+ },
13
+ completed: {
14
+ type: Boolean,
15
+ default: false,
16
+ },
17
+ clickable: {
18
+ type: Boolean,
19
+ default: false,
20
+ },
21
+ skippable: {
22
+ type: Boolean,
23
+ default: false,
24
+ },
25
+ })
26
+
27
+ const canClick = computed(() => {
28
+ if (!props.active && !props.completed) {
29
+ return props.clickable && props.skippable
30
+ }
31
+
32
+ return props.clickable
33
+ })
34
+
35
+ const emit = defineEmits(['click'])
36
+
37
+ const componentClass = computed(() => [
38
+ 'rsui-progress-tracker-step',
39
+ {
40
+ 'rsui-progress-tracker-step--completed': props.completed,
41
+ 'rsui-progress-tracker-step--active': props.active,
42
+ 'rsui-progress-tracker-step--clickable': canClick.value,
43
+ }
44
+ ])
45
+
46
+ const indicatorClass = computed(() => [
47
+ 'rsui-progress-tracker-step__indicator',
48
+ {
49
+ 'rsui-progress-tracker-step__indicator--completed': props.completed,
50
+ 'rsui-progress-tracker-step__indicator--active': props.active,
51
+ }
52
+ ])
53
+
54
+ function handleClick() {
55
+ if (!canClick.value) return
56
+
57
+ if (!props.step) {
58
+ emit('click')
59
+ return
60
+ }
61
+
62
+ emit('click', props.step)
63
+ }
64
+ </script>
65
+ <template>
66
+ <div :class="componentClass"
67
+ @click="handleClick"
68
+ >
69
+ <div :class="indicatorClass">
70
+ <slot name="indicator"></slot>
71
+ </div>
72
+ <slot>Step</slot>
73
+ </div>
74
+ </template>
75
+ <style lang="scss" scoped>
76
+ .rsui-progress-tracker-step {
77
+ @apply relative flex flex-col items-center text-center gap-4;
78
+
79
+ // add a line before each step
80
+ @apply after:content-[''] after:absolute after:bg-rsui-grey-300;
81
+ @apply after:top-6 after:-left-8 after:-translate-x-1/2;
82
+ @apply after:w-[160%] xs:after:w-[140%] lg:after:w-[120%] 3xl:after:w-[104%] after:h-1;
83
+ // hide the line before the first step
84
+ @apply first:after:hidden;
85
+
86
+ &--active,
87
+ &--completed {
88
+ @apply after:bg-primary;
89
+ }
90
+
91
+ &--clickable {
92
+ @apply cursor-pointer;
93
+ }
94
+
95
+ &__indicator {
96
+ @apply relative z-1 size-13 rounded-full border-2 overflow-hidden select-none;
97
+ @apply bg-rsui-grey-300 border-rsui-grey-300 text-white;
98
+ @apply flex items-center justify-center;
99
+ &--completed {
100
+ @apply bg-primary border-primary text-primary-content;
101
+ }
102
+ &--active {
103
+ @apply bg-primary-content border-primary text-primary;
104
+ }
105
+ }
106
+ }
107
+ </style>
@@ -1,5 +1,9 @@
1
1
  import ProgressCircle from './ProgressCircle.vue'
2
+ import ProgressTracker from './ProgressTracker.vue'
3
+ import ProgressTrackerStep from './ProgressTrackerStep.vue'
2
4
 
3
5
  export {
4
6
  ProgressCircle,
7
+ ProgressTracker,
8
+ ProgressTrackerStep
5
9
  }