@fiscozen/card 0.1.6 → 1.0.0-beta.1

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/src/FzCard.vue CHANGED
@@ -1,81 +1,82 @@
1
- <template>
2
- <section :class="[sectionStaticClass, backgroundColor, textColor]">
3
- <header
4
- v-if="existHeader"
5
- :class="[headerContainerComputedClass, borderColor]"
6
- @click="toggleOpen"
7
- >
8
- <div :class="headerStaticClass">
9
- <div class="flex flex-row gap-12 items-center">
10
- <h2
11
- v-if="title"
12
- class="text-core-black font-medium text-2xl m-0 p-0 break-words"
13
- :title="title"
14
- >
15
- {{ title }}
16
- </h2>
17
- <slot name="header"></slot>
18
- </div>
19
- <FzIconButton
20
- v-if="collapsible"
21
- :iconName="isOpen ? 'chevron-up' : 'chevron-down'"
22
- variant="invisible"
23
- />
24
- </div>
25
- <slot name="header-content"></slot>
26
- </header>
27
- <article
28
- v-if="isAlive"
29
- :class="['p-20', contentClass]"
30
- v-show="showContent"
31
- >
32
- <slot></slot>
33
- </article>
34
- <footer
35
- v-if="(slots.footer || atLeastOneButton) && isAlive"
36
- :class="[footerStaticClass, borderColor]"
37
- v-show="showContent"
38
- >
39
- <slot name="footer">
40
- <FzIconButton
41
- v-if="tertiaryAction"
42
- @click="emit('fztertiary:click')"
43
- :iconName="tertiaryAction.icon"
44
- variant="invisible"
45
- />
46
- <FzButton
47
- v-if="secondaryAction"
48
- @click="emit('fzsecondary:click')"
49
- :label="secondaryAction.label"
50
- variant="secondary"
51
- />
52
- <FzButton
53
- v-if="primaryAction"
54
- @click="emit('fzprimary:click')"
55
- :label="primaryAction.label"
56
- variant="primary"
57
- />
58
- </slot>
59
- </footer>
60
- </section>
61
- </template>
62
-
63
1
  <script setup lang="ts">
64
- import { computed, onMounted, ref } from "vue";
2
+ /**
3
+ * FzCard Component
4
+ *
5
+ * A flexible container used to group related content and actions. Cards can include
6
+ * elements like text, images or tables. It also has a set of buttons related to the
7
+ * content, but other can be added inside the main area.
8
+ *
9
+ * Supports multiple color variants, collapsible functionality, and customizable actions.
10
+ * The card can be divided into header, main content area, and footer sections.
11
+ *
12
+ * @component
13
+ * @example
14
+ * <FzCard title="Card Title" color="default">
15
+ * <p>Card content goes here</p>
16
+ * </FzCard>
17
+ *
18
+ * @example
19
+ * <FzCard
20
+ * title="Collapsible Card"
21
+ * collapsible
22
+ * :primaryAction="{ label: 'Save' }"
23
+ * >
24
+ * <p>This card can be collapsed</p>
25
+ * </FzCard>
26
+ */
27
+ import { computed, onMounted, ref, watch } from "vue";
65
28
  import { FzCardEvents, FzCardProps, FzCardSlots } from "./types";
66
29
  import { FzButton, FzIconButton } from "@fiscozen/button";
67
30
 
68
- const props = defineProps<FzCardProps>();
31
+ const props = withDefaults(defineProps<FzCardProps>(), {
32
+ environment: 'frontoffice'
33
+ });
69
34
  const emit = defineEmits<FzCardEvents>();
70
35
  const slots = defineSlots<FzCardSlots>();
71
36
  const isOpen = ref(props.defaultExpanded ?? false);
72
37
 
38
+ /**
39
+ * Deprecation warning for 'aliceblue' color prop value.
40
+ *
41
+ * Watches for 'aliceblue' color usage and logs warning once on mount or when color changes.
42
+ * Using watch with immediate:true ensures the warning only fires once per component instance.
43
+ */
44
+ watch(
45
+ () => props.color === "aliceblue",
46
+ (isAliceblue) => {
47
+ if (isAliceblue) {
48
+ console.warn(
49
+ "[FzCard] The color prop value 'aliceblue' is deprecated and will be removed in a future version. " +
50
+ "Please use 'blue' instead. The component will automatically map 'aliceblue' to 'blue' for now."
51
+ );
52
+ }
53
+ },
54
+ { immediate: true }
55
+ );
56
+
57
+ /**
58
+ * Normalizes deprecated color values to their replacements.
59
+ *
60
+ * Maps deprecated colors to their replacements:
61
+ * - 'aliceblue' → 'blue'
62
+ *
63
+ * This ensures backward compatibility while encouraging migration to new values.
64
+ * Deprecation warnings are handled separately via watch hooks.
65
+ */
66
+ const normalizedColor = computed(() => {
67
+ if (props.color === "aliceblue") {
68
+ return "blue";
69
+ }
70
+
71
+ return props.color;
72
+ });
73
+
73
74
  const sectionStaticClass =
74
75
  "border-1 border-solid border-grey-100 rounded flex flex-col";
75
76
  const headerStaticClass =
76
- "h-64 border-solid p-16 flex flex-row justify-between";
77
+ "border-solid pt-16 px-16 flex flex-row justify-between";
77
78
  const footerStaticClass =
78
- "h-64 border-t-1 border-solid p-16 flex justify-end gap-8 items-center";
79
+ "border-solid pt-0 px-16 pb-16 flex justify-end gap-12 items-center";
79
80
 
80
81
  const showContent = computed(() => isOpen.value || !props.collapsible);
81
82
  const isAlive = computed(() => props.alwaysAlive || showContent.value);
@@ -83,49 +84,58 @@ const existHeader = computed(
83
84
  () => props.title || slots["header"] || slots["header-content"],
84
85
  );
85
86
  const headerContainerComputedClass = computed(() => [
86
- showContent.value ? "border-b-1" : "border-b-0",
87
87
  props.collapsible ? "cursor-pointer" : "",
88
88
  ]);
89
89
 
90
90
  const backgroundColor = computed(() => {
91
- switch (props.color) {
91
+ switch (normalizedColor.value) {
92
92
  case "blue":
93
- return "bg-blue-500";
94
- case "aliceblue":
95
93
  return "bg-background-alice-blue";
96
94
  case "orange":
97
95
  return "bg-background-seashell";
98
96
  case "purple":
99
97
  return "bg-background-pale-purple";
98
+ case "grey":
99
+ return "bg-background-white-smoke";
100
100
  default:
101
101
  return "bg-core-white";
102
102
  }
103
103
  });
104
104
 
105
105
  const textColor = computed(() => {
106
- switch (props.color) {
107
- case "blue":
108
- return "text-core-white";
109
- default:
110
- return "text-core-black";
111
- }
106
+ // Note: Based on Figma designs, all color variants use black text
107
+ // The blue-500 background variant was previously using white text but
108
+ // the new alice-blue background uses black text
109
+ return "text-core-black";
112
110
  });
113
111
 
114
112
  const borderColor = computed(() => {
115
- switch (props.color) {
113
+ switch (normalizedColor.value) {
116
114
  case "blue":
117
- return "border-blue-500";
118
- case "aliceblue":
119
115
  return "border-background-alice-blue";
120
116
  case "orange":
121
117
  return "border-orange-200";
122
118
  case "purple":
123
119
  return "border-purple-200";
120
+ case "grey":
121
+ return "border-grey-200";
124
122
  default:
125
123
  return "border-grey-100";
126
124
  }
127
125
  });
128
126
 
127
+ const borderWidth = computed(() => {
128
+ switch (normalizedColor.value) {
129
+ case "blue":
130
+ case "orange":
131
+ case "purple":
132
+ case "grey":
133
+ return "border-0";
134
+ default:
135
+ return "border-1";
136
+ }
137
+ });
138
+
129
139
  const atLeastOneButton = computed(
130
140
  () =>
131
141
  props.primaryAction !== undefined ||
@@ -155,3 +165,78 @@ defineExpose({
155
165
  toggleOpen,
156
166
  });
157
167
  </script>
168
+
169
+ <template>
170
+ <section :class="[sectionStaticClass, backgroundColor, textColor, borderColor, {'pb-16': !showContent}]">
171
+ <header
172
+ v-if="existHeader"
173
+ :class="[headerContainerComputedClass]"
174
+ @click="toggleOpen"
175
+ >
176
+ <div :class="headerStaticClass">
177
+ <div class="flex flex-row gap-12 items-center">
178
+ <h2
179
+ v-if="title"
180
+ class="text-core-black font-medium text-xl m-0 p-0 break-words"
181
+ :title="title"
182
+ >
183
+ {{ title }}
184
+ </h2>
185
+ <slot name="header"></slot>
186
+ </div>
187
+ <div class="flex flex-row gap-8 items-center">
188
+ <FzIconButton
189
+ v-if="hasInfoIcon"
190
+ iconName="circle-question"
191
+ variant="invisible"
192
+ :environment="environment"
193
+ @click.stop="emit('fzcard:click-info')"
194
+ />
195
+ <FzIconButton
196
+ v-if="collapsible"
197
+ :iconName="isOpen ? 'chevron-up' : 'chevron-down'"
198
+ variant="invisible"
199
+ :environment="environment"
200
+ />
201
+ </div>
202
+ </div>
203
+ <slot name="header-content"></slot>
204
+ </header>
205
+ <article
206
+ v-if="isAlive"
207
+ :class="['p-16', contentClass]"
208
+ v-show="showContent"
209
+ >
210
+ <slot></slot>
211
+ </article>
212
+ <footer
213
+ v-if="(slots.footer || atLeastOneButton) && isAlive"
214
+ :class="[footerStaticClass]"
215
+ v-show="showContent"
216
+ >
217
+ <slot name="footer">
218
+ <FzIconButton
219
+ v-if="tertiaryAction"
220
+ @click="emit('fztertiary:click')"
221
+ :iconName="tertiaryAction.icon"
222
+ variant="invisible"
223
+ :environment="environment"
224
+ />
225
+ <FzButton
226
+ v-if="secondaryAction"
227
+ @click="emit('fzsecondary:click')"
228
+ :label="secondaryAction.label"
229
+ variant="secondary"
230
+ :environment="environment"
231
+ />
232
+ <FzButton
233
+ v-if="primaryAction"
234
+ @click="emit('fzprimary:click')"
235
+ :label="primaryAction.label"
236
+ variant="primary"
237
+ :environment="environment"
238
+ />
239
+ </slot>
240
+ </footer>
241
+ </section>
242
+ </template>