cja-phoenix 0.2.4 → 0.2.5

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 (45) hide show
  1. package/dist/cja-phoenix.es.js +2707 -3358
  2. package/dist/style.css +1 -1
  3. package/dist/types/components/composite/CjaMenuBar.vue.d.ts +8 -5
  4. package/dist/types/components/composite/FunnelLayout.vue.d.ts +9 -9
  5. package/dist/types/components/composite/FunnelSubmit.vue.d.ts +2 -2
  6. package/dist/types/components/composite/FunnelSummary.vue.d.ts +9 -6
  7. package/dist/types/components/composite/FunnelTitle.vue.d.ts +1 -1
  8. package/dist/types/components/composite/JourneyMacroSteps.vue.d.ts +1 -1
  9. package/dist/types/components/composite/ProductDetails.vue.d.ts +4 -4
  10. package/dist/types/components/composite/ResultsLayout.vue.d.ts +11 -0
  11. package/dist/types/components/forms/CheckboxInput.vue.d.ts +8 -5
  12. package/dist/types/components/forms/FileInput.vue.d.ts +7 -4
  13. package/dist/types/components/forms/InputToggle.vue.d.ts +11 -7
  14. package/dist/types/components/forms/NumberInput.vue.d.ts +6 -3
  15. package/dist/types/components/forms/PhoneInput.vue.d.ts +16 -14
  16. package/dist/types/components/forms/RadioInput.vue.d.ts +41 -0
  17. package/dist/types/components/forms/SelectInput.vue.d.ts +18 -17
  18. package/dist/types/components/forms/SelectionTiles.vue.d.ts +7 -4
  19. package/dist/types/components/forms/TextInput.vue.d.ts +20 -18
  20. package/dist/types/components/forms/TileCheckboxInput.vue.d.ts +1 -1
  21. package/dist/types/components/forms/structure/InputContainer.vue.d.ts +2 -2
  22. package/dist/types/components/forms/structure/InputError.vue.d.ts +1 -1
  23. package/dist/types/components/forms/structure/InputTitle.vue.d.ts +1 -1
  24. package/dist/types/components/index.d.ts +6 -2
  25. package/dist/types/components/structural/CjaButton.vue.d.ts +8 -5
  26. package/dist/types/components/structural/CollapseContainer.vue.d.ts +3 -3
  27. package/dist/types/components/structural/ContentTabs.vue.d.ts +1 -1
  28. package/dist/types/components/structural/FixedContainer.vue.d.ts +63 -0
  29. package/dist/types/components/structural/GridContainer.vue.d.ts +9 -6
  30. package/dist/types/components/structural/GridItem.vue.d.ts +8 -8
  31. package/dist/types/components/structural/InfoMessage.vue.d.ts +30 -0
  32. package/dist/types/components/structural/LoadingSpinner.vue.d.ts +1 -1
  33. package/dist/types/components/structural/Modal.vue.d.ts +3 -3
  34. package/dist/types/components/structural/Scaffold.vue.d.ts +2 -2
  35. package/dist/types/stories/Modal.story.vue.d.ts +1 -1
  36. package/package.json +2 -2
  37. package/src/components/composite/ResultsLayout.vue +49 -0
  38. package/src/components/forms/InputToggle.vue +6 -1
  39. package/src/components/forms/RadioInput.vue +90 -0
  40. package/src/components/forms/SelectInput.vue +17 -7
  41. package/src/components/index.ts +9 -1
  42. package/src/components/structural/CjaButton.vue +1 -1
  43. package/src/components/structural/CollapseContainer.vue +35 -32
  44. package/src/components/structural/FixedContainer.vue +87 -0
  45. package/src/components/structural/InfoMessage.vue +97 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cja-phoenix",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
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",
@@ -33,7 +33,7 @@
33
33
  "vee-validate": "^4.7.2",
34
34
  "vite": "^3.0.0",
35
35
  "vitepress": "^0.21.6",
36
- "vue": "^3.2.25",
36
+ "vue": "^3.3.4",
37
37
  "vue-router": "^4.1.6",
38
38
  "vue-tippy": "^6.0.0",
39
39
  "vue-tsc": "^1.0.24"
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <div class="results-container">
3
+ <slot name="mobile-controls" v-if="!activeViewport.lg"></slot>
4
+ <GridContainer class="results-grid">
5
+ <GridItem :size-lg="3" v-if="activeViewport.lg">
6
+ <div class="btn-container">
7
+ <button class="m-cgg-icon--arrow-back"></button>
8
+ </div>
9
+ <slot name="sidebar"></slot>
10
+ </GridItem>
11
+ <GridItem :size-sm="2" :size-md="4" :size-lg="9">
12
+ <slot name="content"></slot>
13
+ </GridItem>
14
+ </GridContainer>
15
+ </div>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ import { inject } from "vue";
20
+ import GridContainer from "../structural/GridContainer.vue";
21
+ import GridItem from "../structural/GridItem.vue";
22
+
23
+ const activeViewport: any = inject("activeViewport");
24
+ </script>
25
+
26
+ <style lang="scss" scoped>
27
+ .results-container {
28
+ .results-grid {
29
+ padding-top: 24px;
30
+ padding-bottom: 24px;
31
+ }
32
+
33
+ .btn-container {
34
+ button {
35
+ background: none;
36
+ padding: 0;
37
+ border: none;
38
+ cursor: pointer;
39
+ font-size: 26px;
40
+ line-height: 37px;
41
+ margin-bottom: 15px;
42
+
43
+ :focus {
44
+ outline: none;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ </style>
@@ -2,7 +2,7 @@
2
2
  <div class="input-container">
3
3
  <div
4
4
  class="input-wrapper"
5
- :class="[`size-${size}`, { active: modelValue }]"
5
+ :class="[`size-${size}`, { active: modelValue, 'full-width': fullWidth }]"
6
6
  @click="$emit('update:modelValue', !modelValue)"
7
7
  >
8
8
  <div class="label">
@@ -25,6 +25,7 @@ const props = withDefaults(
25
25
  validation?: any;
26
26
  label: string;
27
27
  modelValue: boolean;
28
+ fullWidth: boolean;
28
29
  error?: string;
29
30
  errorDisplay?: boolean;
30
31
  }>(),
@@ -47,6 +48,10 @@ const emit = defineEmits(["update:modelValue"]);
47
48
  align-items: center;
48
49
  gap: 10px;
49
50
 
51
+ &.full-width {
52
+ justify-content: space-between;
53
+ }
54
+
50
55
  .label {
51
56
  @include input-title;
52
57
 
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <div class="input-container">
3
+ <div class="input-container-radio">
4
+ <label>
5
+ <input
6
+ type="radio"
7
+ :name="name"
8
+ :checked="modelValue == value"
9
+ @change="handleChange"
10
+ />
11
+ <div class="radio-icon"></div>
12
+ <div class="text-container" v-html="label"></div>
13
+ </label>
14
+ </div>
15
+
16
+ <InputError :error="error" v-if="error && errorDisplay" />
17
+ </div>
18
+ </template>
19
+
20
+ <script lang="ts" setup>
21
+ import InputError from "./structure/InputError.vue";
22
+
23
+ const props = withDefaults(
24
+ defineProps<{
25
+ name: string;
26
+ value: any;
27
+ label: string;
28
+ modelValue?: any;
29
+ error?: string;
30
+ errorDisplay?: boolean;
31
+ }>(),
32
+ {
33
+ errorDisplay: true,
34
+ }
35
+ );
36
+
37
+ const handleChange = (event: any) => {
38
+ if (event.target.checked) {
39
+ emit("update:modelValue", props.value);
40
+ }
41
+ };
42
+
43
+ const emit = defineEmits(["update:modelValue"]);
44
+ </script>
45
+
46
+ <style lang="scss" scoped>
47
+ .input-container-radio {
48
+ label {
49
+ display: flex;
50
+ flex-direction: row;
51
+ align-items: center;
52
+ flex-wrap: nowrap;
53
+ gap: 15px;
54
+ cursor: pointer;
55
+ margin: 0;
56
+ font-weight: 400;
57
+
58
+ input {
59
+ display: none;
60
+ }
61
+
62
+ .radio-icon {
63
+ width: 20px;
64
+ height: 20px;
65
+ border: 1px solid #64748b;
66
+ border-radius: 50%;
67
+ }
68
+
69
+ input:checked + .radio-icon {
70
+ border: 6px solid #076b9c;
71
+ }
72
+
73
+ .text-container {
74
+ font-size: 16px;
75
+ line-height: 19px;
76
+ user-select: none;
77
+
78
+ a {
79
+ color: inherit;
80
+ font-weight: 700;
81
+ text-decoration: underline;
82
+
83
+ &:hover {
84
+ text-decoration: none;
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ </style>
@@ -9,7 +9,11 @@
9
9
  >
10
10
  <div
11
11
  class="select-toggle"
12
- :class="[`size-${size}`, { open: open, disabled: disabled }]"
12
+ :class="[
13
+ `size-${size}`,
14
+ collapsePosition,
15
+ { open: open, disabled: disabled },
16
+ ]"
13
17
  @click="toggleCollapse()"
14
18
  >
15
19
  <span class="select-display">{{ displayValue || placeholder }}</span>
@@ -44,7 +48,7 @@
44
48
  ></span>
45
49
  {{ option.label }}
46
50
  </li>
47
- <li v-if="searchFilter && filteredOptions.length == 0">
51
+ <li v-if="searchFilter && filteredOptions?.length == 0">
48
52
  {{ searchFilter.noResults }}
49
53
  </li>
50
54
  </ul>
@@ -86,7 +90,7 @@ const props = withDefaults(
86
90
  id?: InputHTMLAttributes["id"];
87
91
  disabled?: InputHTMLAttributes["disabled"];
88
92
  modelValue: SelectHTMLAttributes["value"];
89
- options: SelectOption[];
93
+ options: SelectOption[] | null;
90
94
  multiSelect?: boolean;
91
95
  searchFilter?: {
92
96
  placeholder: string;
@@ -108,7 +112,7 @@ const inputEl = ref();
108
112
  const collapseEl = ref();
109
113
  const collapsePosition = ref();
110
114
  const filteredOptions = computed(() =>
111
- search.value
115
+ search.value && props.options
112
116
  ? props.options.filter((opt) =>
113
117
  opt.label.toLowerCase().includes(search.value.toLowerCase())
114
118
  )
@@ -127,7 +131,7 @@ defineExpose({ errorMessage, meta, validate });
127
131
  const emit = defineEmits(["update:modelValue"]);
128
132
 
129
133
  const displayValue = computed(() =>
130
- inputValue.value
134
+ inputValue.value && props.options
131
135
  ? props.multiSelect
132
136
  ? props.options
133
137
  .filter((o) => inputValue.value.includes(o.value))
@@ -193,7 +197,7 @@ const toggleCollapse = () => {
193
197
  }
194
198
  };
195
199
 
196
- const calcPosition = (el: HTMLElement) => {
200
+ const calcPosition = (el: any) => {
197
201
  const elRect = el.getBoundingClientRect();
198
202
  const inputRect = inputEl.value.getBoundingClientRect();
199
203
  const position =
@@ -252,7 +256,13 @@ const selectValue = (value: string) => {
252
256
  }
253
257
 
254
258
  &.open {
255
- border-radius: 5px 5px 0 0;
259
+ &.position-bottom {
260
+ border-radius: 5px 5px 0 0;
261
+ }
262
+
263
+ &.position-top {
264
+ border-radius: 0 0 5px 5px;
265
+ }
256
266
 
257
267
  em {
258
268
  transform: rotate(180deg);
@@ -2,19 +2,22 @@ import Modal from "./structural/Modal.vue";
2
2
  import CjaButton from "./structural/CjaButton.vue";
3
3
  import LoadingSpinner from "./structural/LoadingSpinner.vue";
4
4
  import ContentTabs from "./structural/ContentTabs.vue";
5
+ import InfoMessage from "./structural/InfoMessage.vue";
5
6
  import Scaffold from "./structural/Scaffold.vue";
6
7
  import GridContainer from "./structural/GridContainer.vue";
7
8
  import GridItem from "./structural/GridItem.vue";
9
+ import CollapseContainer from "./structural/CollapseContainer.vue";
10
+ import FixedContainer from "./structural/FixedContainer.vue";
8
11
 
9
12
  import TextInput from "./forms/TextInput.vue";
10
13
  import PhoneInput from "./forms/PhoneInput.vue";
11
14
  import CheckboxInput from "./forms/CheckboxInput.vue";
15
+ import RadioInput from "./forms/RadioInput.vue";
12
16
  import TileCheckboxInput from "./forms/TileCheckboxInput.vue";
13
17
  import SelectInput from "./forms/SelectInput.vue";
14
18
  import FileInput from "./forms/FileInput.vue";
15
19
  import NumberInput from "./forms/NumberInput.vue";
16
20
  import InputToggle from "./forms/InputToggle.vue";
17
- import CollapseContainer from "./structural/CollapseContainer.vue";
18
21
  import SelectionTiles from "./forms/SelectionTiles.vue";
19
22
 
20
23
  import JourneyMacroSteps from "./composite/JourneyMacroSteps.vue";
@@ -22,6 +25,7 @@ import FunnelLayout from "./composite/FunnelLayout.vue";
22
25
  import FunnelSubmit from "./composite/FunnelSubmit.vue";
23
26
  import FunnelSummary from "./composite/FunnelSummary.vue";
24
27
  import FunnelTitle from "./composite/FunnelTitle.vue";
28
+ import ResultsLayout from "./composite/ResultsLayout.vue";
25
29
  import ProductDetails from "./composite/ProductDetails.vue";
26
30
  import CjaMenuBar from "./composite/CjaMenuBar.vue";
27
31
 
@@ -30,6 +34,7 @@ export {
30
34
  CjaButton,
31
35
  TextInput,
32
36
  PhoneInput,
37
+ RadioInput,
33
38
  CheckboxInput,
34
39
  TileCheckboxInput,
35
40
  NumberInput,
@@ -50,4 +55,7 @@ export {
50
55
  FunnelTitle,
51
56
  JourneyMacroSteps,
52
57
  CjaMenuBar,
58
+ FixedContainer,
59
+ ResultsLayout,
60
+ InfoMessage,
53
61
  };
@@ -6,7 +6,7 @@
6
6
  `btn-size-${size}`,
7
7
  `btn-color-${color}`,
8
8
  `icon-${iconPosition}`,
9
- { ['btn-loading']: loading },
9
+ { 'btn-loading': loading },
10
10
  ]"
11
11
  >
12
12
  <Scaffold v-if="!loading">
@@ -1,10 +1,6 @@
1
1
  <template>
2
- <div class="collapse-container">
3
- <div
4
- class="collapse-header"
5
- @click="active = !active"
6
- :class="{ active: active }"
7
- >
2
+ <div class="collapse-container" :class="{ active: active }">
3
+ <div class="collapse-header" @click="active = !active">
8
4
  <div class="header-wrapper">
9
5
  <slot name="header"></slot>
10
6
  </div>
@@ -14,13 +10,14 @@
14
10
  name="slide"
15
11
  @before-enter="setHeightZero"
16
12
  @enter="setHeightSize"
13
+ @after-enter="clearHeight"
17
14
  @leave="setHeightZero"
18
15
  >
19
16
  <div
20
17
  v-show="active"
21
18
  ref="contentContainer"
22
19
  class="content-container"
23
- :class="{ active: active }"
20
+ :style="{ height: containerHeight, overflow: containerOverflow }"
24
21
  >
25
22
  <div ref="contentWrapper" class="content-wrapper">
26
23
  <slot name="content"></slot>
@@ -43,11 +40,13 @@ const props = defineProps<{
43
40
  const active = ref(props.defaultActive);
44
41
  const contentContainer = ref();
45
42
  const contentWrapper = ref();
43
+ const containerHeight = ref();
44
+ const containerOverflow = ref();
46
45
 
47
46
  const setHeightSize = () => {
48
47
  requestAnimationFrame(() => {
49
48
  if (contentContainer.value && contentWrapper.value) {
50
- contentContainer.value.style.height = `${contentWrapper.value.clientHeight}px`;
49
+ containerHeight.value = `${contentWrapper.value.clientHeight}px`;
51
50
 
52
51
  if (active.value && props.scrollToContent) {
53
52
  setTimeout(() => {
@@ -58,24 +57,24 @@ const setHeightSize = () => {
58
57
  });
59
58
  }, 250);
60
59
  }
61
-
62
- setTimeout(() => {
63
- contentContainer.value.style.height = "";
64
- contentContainer.value.style.overflow = "visible";
65
- }, 200);
66
60
  }
67
61
  });
68
62
  };
69
63
 
70
64
  const setHeightZero = () => {
71
- contentContainer.value.style.height = `${contentWrapper.value.clientHeight}px`;
65
+ containerHeight.value = `${contentWrapper.value.clientHeight}px`;
72
66
 
73
67
  requestAnimationFrame(() => {
74
- contentContainer.value.style.height = "0";
75
- contentContainer.value.style.overflow = "";
68
+ containerHeight.value = "0";
69
+ containerOverflow.value = "";
76
70
  });
77
71
  };
78
72
 
73
+ const clearHeight = () => {
74
+ containerHeight.value = "";
75
+ containerOverflow.value = "visible";
76
+ };
77
+
79
78
  onMounted(() => {
80
79
  if (props.defaultActive) {
81
80
  setHeightSize();
@@ -90,26 +89,30 @@ onUnmounted(() => {
90
89
  </script>
91
90
 
92
91
  <style lang="scss" scoped>
93
- .collapse-header {
94
- display: flex;
95
- flex-direction: row;
96
- align-items: center;
97
- justify-content: space-between;
98
- cursor: pointer;
99
- user-select: none;
92
+ .collapse-container {
93
+ .collapse-header {
94
+ display: flex;
95
+ flex-direction: row;
96
+ align-items: center;
97
+ justify-content: space-between;
98
+ cursor: pointer;
99
+ user-select: none;
100
100
 
101
- > span {
102
- transition: all 0.2s linear;
101
+ > span {
102
+ transition: all 0.2s linear;
103
+ }
103
104
  }
104
105
 
105
- &.active > span {
106
- transform: rotate(180deg);
106
+ .content-container {
107
+ box-sizing: border-box;
108
+ overflow: hidden;
109
+ transition: all 0.2s linear;
107
110
  }
108
- }
109
111
 
110
- .content-container {
111
- box-sizing: border-box;
112
- overflow: hidden;
113
- transition: all 0.2s linear;
112
+ &.active {
113
+ .collapse-header > span {
114
+ transform: rotate(180deg);
115
+ }
116
+ }
114
117
  }
115
118
  </style>
@@ -0,0 +1,87 @@
1
+ <template>
2
+ <div
3
+ class="fixed-container"
4
+ :style="{ height: fixedContainerHeight }"
5
+ ref="fixedContainer"
6
+ >
7
+ <div
8
+ class="fixed-wrapper"
9
+ :class="{ 'position-fixed': positionFixed }"
10
+ :style="{ ...size, ...position }"
11
+ ref="fixedWrapper"
12
+ >
13
+ <slot></slot>
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ import { onUnmounted, onMounted } from "vue";
20
+ import { ref } from "vue";
21
+
22
+ const props = withDefaults(
23
+ defineProps<{
24
+ scrollThreshold?: number;
25
+ fixWidth?: boolean;
26
+ size?: {
27
+ height?: string;
28
+ width?: string;
29
+ };
30
+ position?: {
31
+ left?: string;
32
+ top?: string;
33
+ right?: string;
34
+ bottom?: string;
35
+ };
36
+ }>(),
37
+ {
38
+ scrollThreshold: 0,
39
+ fixWidth: true,
40
+ }
41
+ );
42
+
43
+ const positionFixed = ref(false);
44
+ const fixedContainer = ref();
45
+ const fixedContainerHeight = ref("");
46
+ const fixedWrapper = ref();
47
+
48
+ const fixPosition = () => {
49
+ if (fixedContainer.value) {
50
+ positionFixed.value =
51
+ window.scrollY > fixedContainer.value.offsetTop + props.scrollThreshold;
52
+
53
+ fixedContainerHeight.value = positionFixed.value
54
+ ? `${fixedWrapper.value.clientHeight}px`
55
+ : "";
56
+ }
57
+ };
58
+
59
+ const setWidth = () => {
60
+ fixedWrapper.value.style.maxWidth = `${fixedContainer.value.offsetWidth}px`;
61
+ };
62
+
63
+ onMounted(() => {
64
+ window.addEventListener("scroll", fixPosition);
65
+ fixPosition();
66
+
67
+ if (props.fixWidth) {
68
+ window.addEventListener("resize", setWidth);
69
+ setWidth();
70
+ }
71
+ });
72
+
73
+ onUnmounted(() => {
74
+ window.removeEventListener("scroll", fixPosition);
75
+ window.removeEventListener("resize", setWidth);
76
+ });
77
+
78
+ defineExpose({ positionFixed });
79
+ </script>
80
+
81
+ <style lang="scss" scoped>
82
+ .fixed-wrapper {
83
+ &.position-fixed {
84
+ position: fixed;
85
+ }
86
+ }
87
+ </style>
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <div
3
+ class="info-message"
4
+ :class="[
5
+ `color-${color}`,
6
+ { 'has-icon': $slots.icon, 'has-toggle': toggle },
7
+ ]"
8
+ >
9
+ <div class="icon-container" v-if="$slots.icon">
10
+ <slot name="icon"></slot>
11
+ </div>
12
+ <div class="text-container">
13
+ <h4 v-if="title">{{ title }}</h4>
14
+ <p v-if="description" v-html="description"></p>
15
+ </div>
16
+ <div class="btn-container" v-if="toggle">
17
+ <button class="m-cgg-icon--cross2" @click="$emit('btn:close')"></button>
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script lang="ts" setup>
23
+ defineProps<{
24
+ title?: string;
25
+ description?: string;
26
+ toggle?: boolean;
27
+ color: "blue" | "green";
28
+ }>();
29
+
30
+ defineEmits(["btn:close"]);
31
+ </script>
32
+
33
+ <style lang="scss" scoped>
34
+ .info-message {
35
+ display: grid;
36
+ grid-template-columns: 1fr;
37
+ gap: 16px;
38
+ padding: 16px 24px;
39
+ border: 2px solid #000;
40
+ border-radius: 16px;
41
+
42
+ &.has-icon {
43
+ grid-template-columns: auto 1fr;
44
+ }
45
+
46
+ &.has-toggle {
47
+ grid-template-columns: 1fr 18px;
48
+ }
49
+
50
+ &.has-icon.has-toggle {
51
+ grid-template-columns: auto 1fr 18px;
52
+ }
53
+
54
+ &.color-green {
55
+ background-color: #f8faf5;
56
+ border-color: #c4dab1;
57
+ color: #56924b;
58
+ }
59
+
60
+ &.color-blue {
61
+ background-color: #f4f9fc;
62
+ border-color: #076b9c;
63
+ color: #076b9c;
64
+ }
65
+
66
+ .text-container {
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: 15px;
70
+
71
+ h4 {
72
+ font-weight: 700;
73
+ font-size: 16px;
74
+ line-height: 20px;
75
+ margin: 0;
76
+ }
77
+
78
+ p {
79
+ font-size: 13px;
80
+ line-height: 17px;
81
+ margin: 0;
82
+ }
83
+ }
84
+
85
+ .btn-container {
86
+ button {
87
+ padding: 0;
88
+ border: none;
89
+ font-size: 18px;
90
+ line-height: 18px;
91
+ color: inherit;
92
+ cursor: pointer;
93
+ background: none;
94
+ }
95
+ }
96
+ }
97
+ </style>