cja-phoenix 0.2.1 → 0.2.3

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.
Files changed (33) hide show
  1. package/dist/cja-phoenix.es.js +2805 -2529
  2. package/dist/style.css +1 -1
  3. package/dist/types/components/composite/FunnelSubmit.vue.d.ts +24 -0
  4. package/dist/types/components/composite/FunnelSummary.vue.d.ts +72 -0
  5. package/dist/types/components/composite/FunnelTitle.vue.d.ts +19 -0
  6. package/dist/types/components/forms/CheckboxInput.vue.d.ts +2 -2
  7. package/dist/types/components/forms/FileInput.vue.d.ts +2 -2
  8. package/dist/types/components/forms/InputToggle.vue.d.ts +1 -1
  9. package/dist/types/components/forms/NumberInput.vue.d.ts +55 -0
  10. package/dist/types/components/forms/PhoneInput.vue.d.ts +2 -2
  11. package/dist/types/components/forms/SelectInput.vue.d.ts +2 -2
  12. package/dist/types/components/forms/SelectionTiles.vue.d.ts +33 -5
  13. package/dist/types/components/forms/TextInput.vue.d.ts +2 -6
  14. package/dist/types/components/index.d.ts +8 -3
  15. package/dist/types/components/structural/CjaButton.vue.d.ts +4 -2
  16. package/dist/types/components/structural/GridItem.vue.d.ts +6 -6
  17. package/dist/types/types/TileOption.d.ts +3 -2
  18. package/dist/types/utils/RouteGenerator.d.ts +1 -1
  19. package/package.json +1 -1
  20. package/src/components/composite/FunnelSubmit.vue +42 -0
  21. package/src/components/composite/FunnelSummary.vue +192 -0
  22. package/src/components/composite/FunnelTitle.vue +57 -0
  23. package/src/components/forms/CheckboxInput.vue +3 -3
  24. package/src/components/forms/NumberInput.vue +165 -0
  25. package/src/components/forms/SelectInput.vue +5 -10
  26. package/src/components/forms/SelectionTiles.vue +150 -73
  27. package/src/components/forms/TextInput.vue +0 -2
  28. package/src/components/index.ts +12 -2
  29. package/src/components/structural/CjaButton.vue +50 -11
  30. package/src/components/structural/GridItem.vue +17 -17
  31. package/src/types/TileOption.ts +3 -2
  32. package/src/utils/RouteGenerator.ts +1 -1
  33. package/src/utils/ViewportDetector.ts +10 -4
@@ -3,15 +3,20 @@ import CjaButton from "./structural/CjaButton.vue";
3
3
  import LoadingSpinner from "./structural/LoadingSpinner.vue";
4
4
  import ContentTabs from "./structural/ContentTabs.vue";
5
5
  import Scaffold from "./structural/Scaffold.vue";
6
+ import GridContainer from "./structural/GridContainer.vue";
7
+ import GridItem from "./structural/GridItem.vue";
6
8
  import TextInput from "./forms/TextInput.vue";
7
9
  import PhoneInput from "./forms/PhoneInput.vue";
8
10
  import CheckboxInput from "./forms/CheckboxInput.vue";
9
11
  import TileCheckboxInput from "./forms/TileCheckboxInput.vue";
10
12
  import SelectInput from "./forms/SelectInput.vue";
11
13
  import FileInput from "./forms/FileInput.vue";
14
+ import NumberInput from "./forms/NumberInput.vue";
12
15
  import InputToggle from "./forms/InputToggle.vue";
13
16
  import CollapseContainer from "./structural/CollapseContainer.vue";
14
- import GridContainer from "./structural/GridContainer.vue";
15
- import GridItem from "./structural/GridItem.vue";
17
+ import SelectionTiles from "./forms/SelectionTiles.vue";
16
18
  import ProductDetails from "./composite/ProductDetails.vue";
17
- export { Modal, CjaButton, TextInput, PhoneInput, CheckboxInput, TileCheckboxInput, SelectInput, LoadingSpinner, Scaffold, ProductDetails, InputToggle, FileInput, ContentTabs, CollapseContainer, GridContainer, GridItem, };
19
+ import FunnelSubmit from "./composite/FunnelSubmit.vue";
20
+ import FunnelSummary from "./composite/FunnelSummary.vue";
21
+ import FunnelTitle from "./composite/FunnelTitle.vue";
22
+ export { Modal, CjaButton, TextInput, PhoneInput, CheckboxInput, TileCheckboxInput, NumberInput, SelectInput, SelectionTiles, LoadingSpinner, Scaffold, ProductDetails, InputToggle, FileInput, ContentTabs, CollapseContainer, GridContainer, GridItem, FunnelSubmit, FunnelSummary, FunnelTitle, };
@@ -3,7 +3,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
3
3
  color?: "blue" | "orange" | "white" | undefined;
4
4
  size?: "sm" | "md" | "lg" | undefined;
5
5
  icon?: string | undefined;
6
- iconPosition?: "right" | "left" | undefined;
6
+ iconPosition?: "left" | "right" | undefined;
7
+ loading?: boolean | undefined;
7
8
  }>, {
8
9
  type: string;
9
10
  color: string;
@@ -14,7 +15,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
14
15
  color?: "blue" | "orange" | "white" | undefined;
15
16
  size?: "sm" | "md" | "lg" | undefined;
16
17
  icon?: string | undefined;
17
- iconPosition?: "right" | "left" | undefined;
18
+ iconPosition?: "left" | "right" | undefined;
19
+ loading?: boolean | undefined;
18
20
  }>, {
19
21
  type: string;
20
22
  color: string;
@@ -1,11 +1,11 @@
1
1
  declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__VLS_TypePropsToRuntimeProps<{
2
- sizeSm: 1 | 2 | 3 | 4;
3
- sizeMd: 1 | 2 | 3 | 4;
4
- sizeLg: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
2
+ sizeSm?: 2 | 1 | 3 | 4 | undefined;
3
+ sizeMd?: 2 | 1 | 3 | 4 | undefined;
4
+ sizeLg?: 2 | 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | undefined;
5
5
  }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
6
- sizeSm: 1 | 2 | 3 | 4;
7
- sizeMd: 1 | 2 | 3 | 4;
8
- sizeLg: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
6
+ sizeSm?: 2 | 1 | 3 | 4 | undefined;
7
+ sizeMd?: 2 | 1 | 3 | 4 | undefined;
8
+ sizeLg?: 2 | 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | undefined;
9
9
  }>>>, {}>, {
10
10
  default: (_: {}) => any;
11
11
  }>;
@@ -1,7 +1,8 @@
1
1
  export interface TileOption {
2
- value: [string, number, boolean];
3
- title: string;
2
+ value: any;
3
+ label: string;
4
4
  description?: string;
5
+ descriptionLong?: string;
5
6
  tooltip?: string;
6
7
  image?: string;
7
8
  }
@@ -1,2 +1,2 @@
1
1
  import { RouteRecordRaw } from "vue-router";
2
- export declare const generateRoutes: (routes: RouteRecordRaw[]) => RouteRecordRaw[];
2
+ export declare const generateRoutes: (routes: any[]) => RouteRecordRaw[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cja-phoenix",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "scripts": {
5
5
  "build:dev": "rimraf dist && vue-tsc && vite build -m development",
6
6
  "build:link": "rimraf dist && vue-tsc && vite build -m development && npm link",
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <div class="button-container">
3
+ <CjaButton
4
+ :color="'orange'"
5
+ :size="'lg'"
6
+ :loading="loading"
7
+ @click="$emit('btn:click')"
8
+ >
9
+ <slot>Continuar</slot>
10
+ </CjaButton>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import CjaButton from "../structural/CjaButton.vue";
16
+
17
+ defineProps<{
18
+ loading?: boolean;
19
+ }>();
20
+
21
+ defineEmits(["btn:click"]);
22
+ </script>
23
+
24
+ <style lang="scss" scoped>
25
+ .button-container {
26
+ position: fixed;
27
+ bottom: 0;
28
+ left: 0;
29
+ width: 100%;
30
+ padding: 20px 15px;
31
+ background-color: #fff;
32
+ display: flex;
33
+ flex-direction: row;
34
+ justify-content: center;
35
+
36
+ @media screen and (min-width: 1200px) {
37
+ position: static;
38
+ margin: 30px 0 0;
39
+ padding: 0;
40
+ }
41
+ }
42
+ </style>
@@ -0,0 +1,192 @@
1
+ <template>
2
+ <div class="summary-container">
3
+ <div class="summary-wrapper">
4
+ <div class="title-container">
5
+ <h3>{{ title }}</h3>
6
+ <button
7
+ @click="
8
+ editMode = true;
9
+ formLock = false;
10
+ $emit('btn:edit');
11
+ "
12
+ >
13
+ <span class="m-cgg-icon--edit"></span>
14
+ <span>{{ customText.edit }}</span>
15
+ </button>
16
+ </div>
17
+ <div class="info-container" :class="{ 'edit-mode': editMode }">
18
+ <div class="info-wrapper" v-for="info in infoList">
19
+ <div class="info-title">
20
+ {{ info.title }}
21
+ </div>
22
+ <div class="info-display" v-if="!editMode">
23
+ {{ info.value || "-" }}
24
+ </div>
25
+ <div class="info-edit" v-else>
26
+ <slot :name="info.control"></slot>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ <div class="summary-footer" v-if="editMode">
31
+ <CjaButton :type="'secondary'" :size="'sm'" @click="cancelEdit">
32
+ {{ customText.cancel }}
33
+ </CjaButton>
34
+ <CjaButton :size="'sm'" @click="saveEdit">
35
+ {{ customText.save }}
36
+ </CjaButton>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </template>
41
+
42
+ <script lang="ts" setup>
43
+ import { ref } from "vue";
44
+ import CjaButton from "../structural/CjaButton.vue";
45
+
46
+ const editMode = ref(false);
47
+
48
+ const formLock = ref();
49
+
50
+ const props = withDefaults(
51
+ defineProps<{
52
+ title?: string;
53
+ customText?: {
54
+ edit?: string;
55
+ cancel?: string;
56
+ save?: string;
57
+ };
58
+ infoList: {
59
+ title: string;
60
+ value: any;
61
+ control: string;
62
+ }[];
63
+ validateForm: () => boolean;
64
+ }>(),
65
+ {
66
+ title: "O seu resumo",
67
+ customText: () => ({
68
+ edit: "Editar",
69
+ cancel: "Cancelar",
70
+ save: "Guardar",
71
+ }),
72
+ }
73
+ );
74
+
75
+ const cancelEdit = () => {
76
+ if (!formLock.value) {
77
+ formLock.value = true;
78
+ editMode.value = false;
79
+ emit("btn:cancel");
80
+ }
81
+ };
82
+
83
+ const saveEdit = () => {
84
+ if (props.validateForm() && !formLock.value) {
85
+ formLock.value = true;
86
+ editMode.value = false;
87
+
88
+ emit("btn:save");
89
+ }
90
+ };
91
+
92
+ const emit = defineEmits(["btn:cancel", "btn:save", "btn:edit"]);
93
+ </script>
94
+
95
+ <style lang="scss" scoped>
96
+ .summary-container {
97
+ .summary-wrapper {
98
+ background: #ffffff;
99
+ border: 1px solid #dedede;
100
+ box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.1);
101
+ border-radius: 16px;
102
+ padding: 20px 30px;
103
+
104
+ .title-container {
105
+ display: flex;
106
+ flex-direction: row;
107
+ justify-content: space-between;
108
+ align-items: center;
109
+ padding-bottom: 10px;
110
+ margin-bottom: 10px;
111
+ border-bottom: 1px solid #dedede;
112
+
113
+ h3 {
114
+ font-weight: 700;
115
+ font-size: 18px;
116
+ line-height: 22px;
117
+ margin: 0;
118
+ }
119
+
120
+ button {
121
+ padding: 0;
122
+ border: none;
123
+ background: none;
124
+ color: #9fabbc;
125
+ font-size: 14px;
126
+ line-height: 14px;
127
+
128
+ &:focus,
129
+ &:focus-within {
130
+ outline: none;
131
+ }
132
+
133
+ span.m-cgg-icon--edit {
134
+ margin-right: 10px;
135
+ }
136
+ }
137
+ }
138
+
139
+ .info-container {
140
+ display: flex;
141
+ flex-direction: column;
142
+ gap: 20px;
143
+
144
+ .info-wrapper {
145
+ display: grid;
146
+ grid-template-columns: auto 1fr;
147
+ gap: 10px 20px;
148
+ font-size: 16px;
149
+ line-height: 16px;
150
+
151
+ .info-display {
152
+ text-align: right;
153
+ font-weight: 700;
154
+
155
+ &.active {
156
+ color: #56924b;
157
+ }
158
+ }
159
+
160
+ .info-error {
161
+ margin-top: 0;
162
+ }
163
+ }
164
+
165
+ &.edit-mode .info-wrapper {
166
+ grid-template-columns: 1fr 1fr;
167
+ align-items: center;
168
+
169
+ .info-title {
170
+ grid-area: 1 / 1 / 2 / 2;
171
+ }
172
+ .info-edit {
173
+ grid-area: 1 / 2 / 2 / 3;
174
+ }
175
+ .info-error {
176
+ grid-area: 2 / 1 / 3 / 3;
177
+ }
178
+ }
179
+ }
180
+
181
+ .summary-footer {
182
+ margin-top: 20px;
183
+ padding-top: 15px;
184
+ border-top: 1px solid #dedede;
185
+ display: flex;
186
+ flex-direction: row;
187
+ justify-content: flex-end;
188
+ gap: 10px;
189
+ }
190
+ }
191
+ }
192
+ </style>
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <div class="title-container">
3
+ <div class="title-wrapper">
4
+ <span>
5
+ {{ title }}
6
+ </span>
7
+ <span v-if="tooltip" class="m-cgg-icon--help" v-tippy="tooltip"></span>
8
+ </div>
9
+ <div class="description" v-if="description">
10
+ {{ description }}
11
+ </div>
12
+ </div>
13
+ </template>
14
+
15
+ <script lang="ts" setup>
16
+ defineProps<{
17
+ title: string;
18
+ description?: string;
19
+ tooltip?: string;
20
+ }>();
21
+ </script>
22
+
23
+ <style lang="scss" scoped>
24
+ .title-container {
25
+ text-align: center;
26
+ margin-bottom: 25px;
27
+
28
+ .title-wrapper {
29
+ display: flex;
30
+ flex-direction: row;
31
+ align-items: center;
32
+ justify-content: center;
33
+ font-size: 18px;
34
+ line-height: 20px;
35
+ font-weight: 700;
36
+ margin-bottom: 20px;
37
+ color: #076b9c;
38
+
39
+ @media screen and (min-width: 768px) {
40
+ font-size: 26px;
41
+ line-height: 30px;
42
+ }
43
+
44
+ .m-cgg-icon--help {
45
+ flex-shrink: 0;
46
+ font-size: 20px;
47
+ color: #076b9c;
48
+ }
49
+ }
50
+
51
+ .description {
52
+ font-weight: 700;
53
+ font-size: 16px;
54
+ line-height: 20px;
55
+ }
56
+ }
57
+ </style>
@@ -22,7 +22,7 @@ import InputError from "./structure/InputError.vue";
22
22
  const props = withDefaults(
23
23
  defineProps<{
24
24
  label: string;
25
- modelValue: boolean;
25
+ modelValue: HTMLInputElement["checked"] | undefined;
26
26
  error?: string;
27
27
  errorDisplay?: boolean;
28
28
  }>(),
@@ -74,8 +74,8 @@ const emit = defineEmits(["update:modelValue"]);
74
74
  }
75
75
 
76
76
  .text-container {
77
- font-size: 10px;
78
- line-height: 12px;
77
+ font-size: 12px;
78
+ line-height: 14px;
79
79
  user-select: none;
80
80
 
81
81
  a {
@@ -0,0 +1,165 @@
1
+ <template>
2
+ <div class="number-input-container">
3
+ <div class="text-container" v-if="title">
4
+ <div class="title">
5
+ {{ title }}
6
+ </div>
7
+ <div class="description" v-if="description">
8
+ {{ description }}
9
+ </div>
10
+ </div>
11
+ <div class="controls-container">
12
+ <button
13
+ class="btn-minus"
14
+ :disabled="value - step < min"
15
+ @click="$emit('update:modelValue', value - step)"
16
+ ></button>
17
+ <div class="value">{{ value }}</div>
18
+ <button
19
+ class="btn-plus"
20
+ :disabled="max ? value + step > max : false"
21
+ @click="$emit('update:modelValue', value + step)"
22
+ ></button>
23
+ </div>
24
+ </div>
25
+ <InputError :error="errorMessage" v-if="errorMessage && errorDisplay" />
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { useField } from "vee-validate";
30
+ import InputError from "./structure/InputError.vue";
31
+
32
+ const props = withDefaults(
33
+ defineProps<{
34
+ title?: string;
35
+ description?: string;
36
+ modelValue: number;
37
+ max?: number;
38
+ min?: number;
39
+ step?: number;
40
+ validation?: any;
41
+ errorDisplay?: boolean;
42
+ }>(),
43
+ {
44
+ modelValue: 0,
45
+ min: 0,
46
+ step: 1,
47
+ errorDisplay: true,
48
+ }
49
+ );
50
+
51
+ defineEmits(["update:modelValue"]);
52
+
53
+ const { value, errorMessage, meta, validate } = useField(
54
+ "input",
55
+ props.validation,
56
+ { initialValue: props.modelValue }
57
+ );
58
+
59
+ defineExpose({ errorMessage, meta, validate });
60
+ </script>
61
+
62
+ <style lang="scss" scoped>
63
+ .number-input-container {
64
+ display: flex;
65
+ justify-content: space-between;
66
+ align-items: center;
67
+ gap: 30px;
68
+ padding: 20px;
69
+ border: 1px solid #dedede;
70
+ box-shadow: 0px 0px 16px rgba(0, 0, 0, 0.06);
71
+ border-radius: 8px;
72
+
73
+ .text-container {
74
+ display: flex;
75
+ flex-direction: column;
76
+ gap: 5px;
77
+
78
+ .title {
79
+ font-weight: 700;
80
+ font-size: 15px;
81
+ line-height: 18px;
82
+ }
83
+
84
+ .description {
85
+ font-size: 12px;
86
+ line-height: 12px;
87
+ }
88
+ }
89
+
90
+ .controls-container {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 10px;
94
+
95
+ button {
96
+ position: relative;
97
+ width: 32px;
98
+ height: 32px;
99
+ background: none;
100
+ border-width: 2px;
101
+ border-style: solid;
102
+ border-color: #979290;
103
+ border-radius: 50%;
104
+ cursor: pointer;
105
+ transition: all 0.2s ease-in-out;
106
+
107
+ &:before,
108
+ &:after {
109
+ position: absolute;
110
+ left: 50%;
111
+ transform: translateX(-50%);
112
+ width: 12px;
113
+ height: 2px;
114
+ background-color: #979290;
115
+ transition: all 0.2s ease-in-out;
116
+ }
117
+
118
+ &:hover {
119
+ border-color: #0d2745;
120
+
121
+ &:before,
122
+ &:after {
123
+ background-color: #0d2745;
124
+ }
125
+ }
126
+
127
+ &:disabled {
128
+ cursor: auto;
129
+ border-color: #cccbc8;
130
+
131
+ &:before,
132
+ &:after {
133
+ background-color: #cccbc8;
134
+ }
135
+ }
136
+
137
+ &.btn-minus {
138
+ &:before {
139
+ content: "";
140
+ }
141
+ }
142
+
143
+ &.btn-plus {
144
+ &:before {
145
+ content: "";
146
+ }
147
+
148
+ &:after {
149
+ content: "";
150
+ transform: translateX(-50%) rotate(90deg);
151
+ }
152
+ }
153
+ }
154
+
155
+ .value {
156
+ width: 20px;
157
+ text-align: center;
158
+ font-size: 18px;
159
+ line-height: 22px;
160
+ color: #979290;
161
+ user-select: none;
162
+ }
163
+ }
164
+ }
165
+ </style>
@@ -147,17 +147,12 @@ const sizeReset = () => {
147
147
  };
148
148
 
149
149
  const resizeObserver = new ResizeObserver((entries) => {
150
- const displayEl = entries[0].target.querySelector(
151
- ".select-toggle .select-display"
152
- ) as HTMLElement;
153
-
154
- const elWidth = displayEl.getBoundingClientRect().width;
155
-
156
- displayEl.style.whiteSpace = "nowrap";
157
- displayEl.style.width = `${elWidth}px`;
158
-
159
150
  window.requestAnimationFrame(() => {
160
- displayEl.style.width = `${elWidth}px`;
151
+ const displayEl = entries[0].target.querySelector(
152
+ ".select-toggle .select-display"
153
+ ) as HTMLElement;
154
+
155
+ displayEl.style.width = `${displayEl.getBoundingClientRect().width}px`;
161
156
  displayEl.style.whiteSpace = "nowrap";
162
157
  });
163
158
  });