@fiscozen/card 0.1.5 → 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/dist/card.js ADDED
@@ -0,0 +1,169 @@
1
+ import { defineComponent as O, useSlots as j, ref as M, watch as T, computed as n, onMounted as V, createElementBlock as i, openBlock as r, normalizeClass as a, createCommentVNode as t, withDirectives as A, createElementVNode as f, renderSlot as m, toDisplayString as Y, createBlock as s, unref as c, withModifiers as q, vShow as C } from "vue";
2
+ import { FzIconButton as k, FzButton as h } from "@fiscozen/button";
3
+ const x = { class: "flex flex-row gap-12 items-center" }, H = ["title"], L = { class: "flex flex-row gap-8 items-center" }, P = "border-1 border-solid border-grey-100 rounded flex flex-col", G = "border-solid pt-16 px-16 flex flex-row justify-between", J = "border-solid pt-0 px-16 pb-16 flex justify-end gap-12 items-center", R = /* @__PURE__ */ O({
4
+ __name: "FzCard",
5
+ props: {
6
+ title: {},
7
+ color: {},
8
+ primaryAction: {},
9
+ secondaryAction: {},
10
+ tertiaryAction: {},
11
+ contentClass: {},
12
+ collapsible: { type: Boolean },
13
+ defaultExpanded: { type: Boolean },
14
+ alwaysAlive: { type: Boolean },
15
+ hasInfoIcon: { type: Boolean },
16
+ environment: { default: "frontoffice" }
17
+ },
18
+ emits: ["fzprimary:click", "fzsecondary:click", "fztertiary:click", "fzcard:click-info"],
19
+ setup(z, { expose: B, emit: S }) {
20
+ const o = z, u = S, v = j(), d = M(o.defaultExpanded ?? !1);
21
+ T(
22
+ () => o.color === "aliceblue",
23
+ (e) => {
24
+ e && console.warn(
25
+ "[FzCard] The color prop value 'aliceblue' is deprecated and will be removed in a future version. Please use 'blue' instead. The component will automatically map 'aliceblue' to 'blue' for now."
26
+ );
27
+ },
28
+ { immediate: !0 }
29
+ );
30
+ const y = n(() => o.color === "aliceblue" ? "blue" : o.color), p = n(() => d.value || !o.collapsible), g = n(() => o.alwaysAlive || p.value), $ = n(
31
+ () => o.title || v.header || v["header-content"]
32
+ ), F = n(() => [
33
+ o.collapsible ? "cursor-pointer" : ""
34
+ ]), N = n(() => {
35
+ switch (y.value) {
36
+ case "blue":
37
+ return "bg-background-alice-blue";
38
+ case "orange":
39
+ return "bg-background-seashell";
40
+ case "purple":
41
+ return "bg-background-pale-purple";
42
+ case "grey":
43
+ return "bg-background-white-smoke";
44
+ default:
45
+ return "bg-core-white";
46
+ }
47
+ }), I = n(() => "text-core-black"), D = n(() => {
48
+ switch (y.value) {
49
+ case "blue":
50
+ return "border-background-alice-blue";
51
+ case "orange":
52
+ return "border-orange-200";
53
+ case "purple":
54
+ return "border-purple-200";
55
+ case "grey":
56
+ return "border-grey-200";
57
+ default:
58
+ return "border-grey-100";
59
+ }
60
+ });
61
+ n(() => {
62
+ switch (y.value) {
63
+ case "blue":
64
+ case "orange":
65
+ case "purple":
66
+ case "grey":
67
+ return "border-0";
68
+ default:
69
+ return "border-1";
70
+ }
71
+ });
72
+ const E = n(
73
+ () => o.primaryAction !== void 0 || o.secondaryAction !== void 0 || o.tertiaryAction !== void 0
74
+ );
75
+ function w() {
76
+ o.collapsible && (d.value = !d.value);
77
+ }
78
+ return V(() => {
79
+ o.tertiaryAction && !o.secondaryAction && !o.primaryAction ? console.warn(
80
+ "[Fiscozen Design System]: You should set primaryAction and secondaryAction if you want to set tertiaryAction"
81
+ ) : o.secondaryAction && !o.primaryAction && console.warn(
82
+ "[Fiscozen Design System]: You should set primaryAction if you want to set secondaryAction"
83
+ );
84
+ }), B({
85
+ /**
86
+ * Method to toggle the card open/closed state
87
+ */
88
+ toggleOpen: w
89
+ }), (e, l) => (r(), i("section", {
90
+ class: a([P, N.value, I.value, D.value, { "pb-16": !p.value }])
91
+ }, [
92
+ $.value ? (r(), i("header", {
93
+ key: 0,
94
+ class: a([F.value]),
95
+ onClick: w
96
+ }, [
97
+ f("div", {
98
+ class: a(G)
99
+ }, [
100
+ f("div", x, [
101
+ e.title ? (r(), i("h2", {
102
+ key: 0,
103
+ class: "text-core-black font-medium text-xl m-0 p-0 break-words",
104
+ title: e.title
105
+ }, Y(e.title), 9, H)) : t("", !0),
106
+ m(e.$slots, "header")
107
+ ]),
108
+ f("div", L, [
109
+ e.hasInfoIcon ? (r(), s(c(k), {
110
+ key: 0,
111
+ iconName: "circle-question",
112
+ variant: "invisible",
113
+ environment: e.environment,
114
+ onClick: l[0] || (l[0] = q((b) => u("fzcard:click-info"), ["stop"]))
115
+ }, null, 8, ["environment"])) : t("", !0),
116
+ e.collapsible ? (r(), s(c(k), {
117
+ key: 1,
118
+ iconName: d.value ? "chevron-up" : "chevron-down",
119
+ variant: "invisible",
120
+ environment: e.environment
121
+ }, null, 8, ["iconName", "environment"])) : t("", !0)
122
+ ])
123
+ ]),
124
+ m(e.$slots, "header-content")
125
+ ], 2)) : t("", !0),
126
+ g.value ? A((r(), i("article", {
127
+ key: 1,
128
+ class: a(["p-20", e.contentClass])
129
+ }, [
130
+ m(e.$slots, "default")
131
+ ], 2)), [
132
+ [C, p.value]
133
+ ]) : t("", !0),
134
+ (v.footer || E.value) && g.value ? A((r(), i("footer", {
135
+ key: 2,
136
+ class: a([J])
137
+ }, [
138
+ m(e.$slots, "footer", {}, () => [
139
+ e.tertiaryAction ? (r(), s(c(k), {
140
+ key: 0,
141
+ onClick: l[1] || (l[1] = (b) => u("fztertiary:click")),
142
+ iconName: e.tertiaryAction.icon,
143
+ variant: "invisible",
144
+ environment: e.environment
145
+ }, null, 8, ["iconName", "environment"])) : t("", !0),
146
+ e.secondaryAction ? (r(), s(c(h), {
147
+ key: 1,
148
+ onClick: l[2] || (l[2] = (b) => u("fzsecondary:click")),
149
+ label: e.secondaryAction.label,
150
+ variant: "secondary",
151
+ environment: e.environment
152
+ }, null, 8, ["label", "environment"])) : t("", !0),
153
+ e.primaryAction ? (r(), s(c(h), {
154
+ key: 2,
155
+ onClick: l[3] || (l[3] = (b) => u("fzprimary:click")),
156
+ label: e.primaryAction.label,
157
+ variant: "primary",
158
+ environment: e.environment
159
+ }, null, 8, ["label", "environment"])) : t("", !0)
160
+ ])
161
+ ], 2)), [
162
+ [C, p.value]
163
+ ]) : t("", !0)
164
+ ], 2));
165
+ }
166
+ });
167
+ export {
168
+ R as FzCard
169
+ };
@@ -0,0 +1 @@
1
+ (function(t,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("@fiscozen/button")):typeof define=="function"&&define.amd?define(["exports","vue","@fiscozen/button"],e):(t=typeof globalThis<"u"?globalThis:t||self,e(t.FzCard={},t.Vue,t.button))})(this,function(t,e,l){"use strict";const u={class:"flex flex-row gap-12 items-center"},y=["title"],b={class:"flex flex-row gap-8 items-center"},k="border-1 border-solid border-grey-100 rounded flex flex-col",C="border-solid pt-16 px-16 flex flex-row justify-between",B="border-solid pt-0 px-16 pb-16 flex justify-end gap-12 items-center",g=e.defineComponent({__name:"FzCard",props:{title:{},color:{},primaryAction:{},secondaryAction:{},tertiaryAction:{},contentClass:{},collapsible:{type:Boolean},defaultExpanded:{type:Boolean},alwaysAlive:{type:Boolean},hasInfoIcon:{type:Boolean},environment:{default:"frontoffice"}},emits:["fzprimary:click","fzsecondary:click","fztertiary:click","fzcard:click-info"],setup(h,{expose:w,emit:z}){const n=h,a=z,s=e.useSlots(),i=e.ref(n.defaultExpanded??!1);e.watch(()=>n.color==="aliceblue",o=>{o&&console.warn("[FzCard] The color prop value 'aliceblue' is deprecated and will be removed in a future version. Please use 'blue' instead. The component will automatically map 'aliceblue' to 'blue' for now.")},{immediate:!0});const d=e.computed(()=>n.color==="aliceblue"?"blue":n.color),c=e.computed(()=>i.value||!n.collapsible),p=e.computed(()=>n.alwaysAlive||c.value),A=e.computed(()=>n.title||s.header||s["header-content"]),N=e.computed(()=>[n.collapsible?"cursor-pointer":""]),S=e.computed(()=>{switch(d.value){case"blue":return"bg-background-alice-blue";case"orange":return"bg-background-seashell";case"purple":return"bg-background-pale-purple";case"grey":return"bg-background-white-smoke";default:return"bg-core-white"}}),V=e.computed(()=>"text-core-black"),F=e.computed(()=>{switch(d.value){case"blue":return"border-background-alice-blue";case"orange":return"border-orange-200";case"purple":return"border-purple-200";case"grey":return"border-grey-200";default:return"border-grey-100"}});e.computed(()=>{switch(d.value){case"blue":case"orange":case"purple":case"grey":return"border-0";default:return"border-1"}});const E=e.computed(()=>n.primaryAction!==void 0||n.secondaryAction!==void 0||n.tertiaryAction!==void 0);function f(){n.collapsible&&(i.value=!i.value)}return e.onMounted(()=>{n.tertiaryAction&&!n.secondaryAction&&!n.primaryAction?console.warn("[Fiscozen Design System]: You should set primaryAction and secondaryAction if you want to set tertiaryAction"):n.secondaryAction&&!n.primaryAction&&console.warn("[Fiscozen Design System]: You should set primaryAction if you want to set secondaryAction")}),w({toggleOpen:f}),(o,r)=>(e.openBlock(),e.createElementBlock("section",{class:e.normalizeClass([k,S.value,V.value,F.value,{"pb-16":!c.value}])},[A.value?(e.openBlock(),e.createElementBlock("header",{key:0,class:e.normalizeClass([N.value]),onClick:f},[e.createElementVNode("div",{class:e.normalizeClass(C)},[e.createElementVNode("div",u,[o.title?(e.openBlock(),e.createElementBlock("h2",{key:0,class:"text-core-black font-medium text-xl m-0 p-0 break-words",title:o.title},e.toDisplayString(o.title),9,y)):e.createCommentVNode("",!0),e.renderSlot(o.$slots,"header")]),e.createElementVNode("div",b,[o.hasInfoIcon?(e.openBlock(),e.createBlock(e.unref(l.FzIconButton),{key:0,iconName:"circle-question",variant:"invisible",environment:o.environment,onClick:r[0]||(r[0]=e.withModifiers(m=>a("fzcard:click-info"),["stop"]))},null,8,["environment"])):e.createCommentVNode("",!0),o.collapsible?(e.openBlock(),e.createBlock(e.unref(l.FzIconButton),{key:1,iconName:i.value?"chevron-up":"chevron-down",variant:"invisible",environment:o.environment},null,8,["iconName","environment"])):e.createCommentVNode("",!0)])]),e.renderSlot(o.$slots,"header-content")],2)):e.createCommentVNode("",!0),p.value?e.withDirectives((e.openBlock(),e.createElementBlock("article",{key:1,class:e.normalizeClass(["p-20",o.contentClass])},[e.renderSlot(o.$slots,"default")],2)),[[e.vShow,c.value]]):e.createCommentVNode("",!0),(s.footer||E.value)&&p.value?e.withDirectives((e.openBlock(),e.createElementBlock("footer",{key:2,class:e.normalizeClass([B])},[e.renderSlot(o.$slots,"footer",{},()=>[o.tertiaryAction?(e.openBlock(),e.createBlock(e.unref(l.FzIconButton),{key:0,onClick:r[1]||(r[1]=m=>a("fztertiary:click")),iconName:o.tertiaryAction.icon,variant:"invisible",environment:o.environment},null,8,["iconName","environment"])):e.createCommentVNode("",!0),o.secondaryAction?(e.openBlock(),e.createBlock(e.unref(l.FzButton),{key:1,onClick:r[2]||(r[2]=m=>a("fzsecondary:click")),label:o.secondaryAction.label,variant:"secondary",environment:o.environment},null,8,["label","environment"])):e.createCommentVNode("",!0),o.primaryAction?(e.openBlock(),e.createBlock(e.unref(l.FzButton),{key:2,onClick:r[3]||(r[3]=m=>a("fzprimary:click")),label:o.primaryAction.label,variant:"primary",environment:o.environment},null,8,["label","environment"])):e.createCommentVNode("",!0)])],2)),[[e.vShow,c.value]]):e.createCommentVNode("",!0)],2))}});t.FzCard=g,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1 @@
1
+ export * from './src/index'
@@ -0,0 +1,48 @@
1
+ import { FzCardProps, FzCardSlots } from './types';
2
+
3
+ declare function toggleOpen(): void;
4
+ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<FzCardProps>, {
5
+ environment: string;
6
+ }>>, {
7
+ /**
8
+ * Method to toggle the card open/closed state
9
+ */
10
+ toggleOpen: typeof toggleOpen;
11
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
12
+ "fzprimary:click": () => void;
13
+ "fzsecondary:click": () => void;
14
+ "fztertiary:click": () => void;
15
+ "fzcard:click-info": () => void;
16
+ }, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<FzCardProps>, {
17
+ environment: string;
18
+ }>>> & Readonly<{
19
+ "onFzprimary:click"?: (() => any) | undefined;
20
+ "onFzsecondary:click"?: (() => any) | undefined;
21
+ "onFztertiary:click"?: (() => any) | undefined;
22
+ "onFzcard:click-info"?: (() => any) | undefined;
23
+ }>, {
24
+ environment: import('./types').FzCardEnvironment;
25
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>, Readonly<FzCardSlots> & FzCardSlots>;
26
+ export default _default;
27
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
28
+ type __VLS_TypePropsToRuntimeProps<T> = {
29
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
30
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
31
+ } : {
32
+ type: import('vue').PropType<T[K]>;
33
+ required: true;
34
+ };
35
+ };
36
+ type __VLS_WithDefaults<P, D> = {
37
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
38
+ default: D[K];
39
+ }> : P[K];
40
+ };
41
+ type __VLS_Prettify<T> = {
42
+ [K in keyof T]: T[K];
43
+ } & {};
44
+ type __VLS_WithTemplateSlots<T, S> = T & {
45
+ new (): {
46
+ $slots: S;
47
+ };
48
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { default as FzCard } from './FzCard.vue';
2
+ export * from './types';
@@ -0,0 +1,117 @@
1
+ export type FzCardProps = {
2
+ /**
3
+ * The title of the card
4
+ */
5
+ title?: string;
6
+ /**
7
+ * The background color of the card
8
+ */
9
+ color?: FzCardColor;
10
+ /**
11
+ * The primary action button
12
+ */
13
+ primaryAction?: FzCardButton;
14
+ /**
15
+ * The secondary action button
16
+ */
17
+ secondaryAction?: FzCardButton;
18
+ /**
19
+ * The tertiary action button
20
+ */
21
+ tertiaryAction?: FzCardIconButton;
22
+ /**
23
+ * Custom css class to apply to the content
24
+ */
25
+ contentClass?: string;
26
+ /**
27
+ * Whether the card is collapsible
28
+ */
29
+ collapsible?: boolean;
30
+ /**
31
+ * Whether the card is expanded by default (only if collapsible)
32
+ */
33
+ defaultExpanded?: boolean;
34
+ /**
35
+ * Whether the card content is always alive (never destroyed) when collapsed
36
+ */
37
+ alwaysAlive?: boolean;
38
+ /**
39
+ * Whether to show an info icon in the header
40
+ * @default false
41
+ */
42
+ hasInfoIcon?: boolean;
43
+ /**
44
+ * The environment context for the card buttons
45
+ * @default 'frontoffice'
46
+ */
47
+ environment?: FzCardEnvironment;
48
+ };
49
+ type FzCardButton = {
50
+ label: string;
51
+ };
52
+ type FzCardIconButton = {
53
+ icon: string;
54
+ };
55
+ /**
56
+ * Card background color variants.
57
+ *
58
+ * @remarks
59
+ * - 'default' renders a white background
60
+ * - 'blue' renders an alice-blue background
61
+ * - 'orange' renders a seashell background
62
+ * - 'purple' renders a pale-purple background
63
+ * - 'grey' renders a white-smoke background
64
+ *
65
+ * @deprecated 'aliceblue' is deprecated and will be removed in a future version. Use 'blue' instead.
66
+ */
67
+ export type FzCardColor = "default" | "blue" | "orange" | "purple" | "grey" | "aliceblue";
68
+ /**
69
+ * Card environment context for buttons
70
+ *
71
+ * @remarks
72
+ * Determines the visual style context for all buttons within the card
73
+ * - 'backoffice' for internal/admin interfaces
74
+ * - 'frontoffice' for public-facing interfaces
75
+ */
76
+ export type FzCardEnvironment = "backoffice" | "frontoffice";
77
+ export interface FzCardEvents {
78
+ /**
79
+ * Event emitted when the primary action is clicked
80
+ * @type {() => void}
81
+ */
82
+ (event: "fzprimary:click"): void;
83
+ /**
84
+ * Event emitted when the secondary action is clicked
85
+ * @type {() => void}
86
+ */
87
+ (event: "fzsecondary:click"): void;
88
+ /**
89
+ * Event emitted when the tertiary action is clicked
90
+ * @type {() => void}
91
+ */
92
+ (event: "fztertiary:click"): void;
93
+ /**
94
+ * Event emitted when the info icon is clicked
95
+ * @type {() => void}
96
+ */
97
+ (event: "fzcard:click-info"): void;
98
+ }
99
+ export interface FzCardSlots {
100
+ /**
101
+ * Slot for the content of the card
102
+ */
103
+ default(props: {}): any;
104
+ /**
105
+ * Slot for the header, it will be displayed on the left of the title
106
+ */
107
+ header(props: {}): any;
108
+ /**
109
+ * Slot for the header content, it will be displayed below the title
110
+ */
111
+ "header-content"(props: {}): any;
112
+ /**
113
+ * Slot for the footer of the card
114
+ */
115
+ footer(props: {}): any;
116
+ }
117
+ export {};
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@fiscozen/card",
3
- "version": "0.1.5",
3
+ "version": "1.0.0-beta.1",
4
4
  "description": "Design System Card component",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
7
7
  "keywords": [],
8
8
  "author": "Cristian Barraco",
9
9
  "dependencies": {
10
- "@fiscozen/button": "^0.1.9",
11
- "@fiscozen/icons": "^0.1.19"
10
+ "@fiscozen/button": "^1.0.0",
11
+ "@fiscozen/icons": "^0.1.35"
12
12
  },
13
13
  "peerDependencies": {
14
14
  "tailwindcss": "^3.4.1",
@@ -33,9 +33,9 @@
33
33
  "@awesome.me/kit-8137893ad3": "^1.0.65",
34
34
  "@fortawesome/fontawesome-svg-core": "^6.5.1",
35
35
  "@fortawesome/vue-fontawesome": "^3.0.6",
36
- "@fiscozen/eslint-config": "^0.1.0",
36
+ "@fiscozen/tsconfig": "^0.1.0",
37
37
  "@fiscozen/prettier-config": "^0.1.0",
38
- "@fiscozen/tsconfig": "^0.1.0"
38
+ "@fiscozen/eslint-config": "^0.1.0"
39
39
  },
40
40
  "license": "MIT",
41
41
  "scripts": {
package/src/FzCard.vue CHANGED
@@ -1,81 +1,82 @@
1
- <template>
2
- <section :class="[sectionStaticClass, backgroundColor]">
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,36 +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
93
  return "bg-background-alice-blue";
94
94
  case "orange":
95
95
  return "bg-background-seashell";
96
96
  case "purple":
97
97
  return "bg-background-pale-purple";
98
+ case "grey":
99
+ return "bg-background-white-smoke";
98
100
  default:
99
101
  return "bg-core-white";
100
102
  }
101
103
  });
102
104
 
105
+ const textColor = computed(() => {
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";
110
+ });
111
+
103
112
  const borderColor = computed(() => {
104
- switch (props.color) {
113
+ switch (normalizedColor.value) {
105
114
  case "blue":
106
- return "border-blue-200";
115
+ return "border-background-alice-blue";
107
116
  case "orange":
108
117
  return "border-orange-200";
109
118
  case "purple":
110
119
  return "border-purple-200";
120
+ case "grey":
121
+ return "border-grey-200";
111
122
  default:
112
123
  return "border-grey-100";
113
124
  }
114
125
  });
115
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
+
116
139
  const atLeastOneButton = computed(
117
140
  () =>
118
141
  props.primaryAction !== undefined ||
@@ -142,3 +165,78 @@ defineExpose({
142
165
  toggleOpen,
143
166
  });
144
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>