@energie360/ui-library 0.1.10 → 0.1.11

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.
@@ -1,18 +1,25 @@
1
1
  <script setup lang="ts">
2
- import { provide, ref } from 'vue'
2
+ import { provide, ref, watch } from 'vue'
3
3
 
4
4
  interface Props {
5
5
  active?: boolean
6
6
  }
7
7
 
8
- defineProps<Props>()
8
+ const { active = false } = defineProps<Props>()
9
9
 
10
- const isActive = ref(false)
10
+ const isActive = ref(active)
11
11
  const toggleActiveCard = (v: boolean) => {
12
12
  isActive.value = v
13
13
  }
14
14
 
15
15
  provide('card', { toggleActiveCard })
16
+
17
+ watch(
18
+ () => active,
19
+ (newV) => {
20
+ isActive.value = newV
21
+ },
22
+ )
16
23
  </script>
17
24
 
18
25
  <template>
@@ -0,0 +1,87 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ title: string
4
+ subtitle: string
5
+ disabled?: boolean
6
+ }
7
+
8
+ const { disabled = false } = defineProps<Props>()
9
+ </script>
10
+
11
+ <template>
12
+ <div class="card-cta-header" :class="{ disabled }">
13
+ <slot></slot>
14
+ <div class="card-cta-header__header">
15
+ <div class="card-cta-header__image">
16
+ <slot name="image"></slot>
17
+ </div>
18
+
19
+ <div>
20
+ <h2 class="card-cta-header__title">{{ title }}</h2>
21
+ <p class="card-cta-header__subtitle">{{ subtitle }}</p>
22
+ </div>
23
+ </div>
24
+
25
+ <div class="card-cta-header__cta">
26
+ <slot name="cta"></slot>
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <style scoped lang="scss">
32
+ // We add the styles directly in the component
33
+ // because the :slotted selector won't work when styles are added via `src`.
34
+
35
+ @use '../../base/abstracts/' as a;
36
+
37
+ .card-cta-header {
38
+ display: flex;
39
+ align-items: center;
40
+ gap: var(--e-space-4);
41
+
42
+ @include a.bp(m) {
43
+ flex-direction: column;
44
+ align-items: flex-start;
45
+ }
46
+ }
47
+
48
+ .card-cta-header__header {
49
+ display: flex;
50
+ align-items: center;
51
+ column-gap: var(--e-space-6);
52
+ }
53
+
54
+ .card-cta-header__title {
55
+ @include a.type(300, strong);
56
+
57
+ color: var(--e-c-mono-900);
58
+
59
+ .disabled & {
60
+ color: var(--e-c-mono-500);
61
+ }
62
+ }
63
+
64
+ .card-cta-header__subtitle {
65
+ @include a.type(300);
66
+
67
+ color: var(--e-c-mono-700);
68
+ }
69
+
70
+ .card-cta-header__cta {
71
+ margin-left: auto;
72
+
73
+ @include a.bp(m) {
74
+ display: flex;
75
+ flex-direction: column;
76
+ width: 100%;
77
+ margin-left: 0;
78
+
79
+ // This is used mostly because <nuxt-link> is probably used to wrap a button component.
80
+ // And <nuxt-link> always renders to <a>.
81
+ :slotted(a) {
82
+ display: flex;
83
+ flex-direction: column;
84
+ }
85
+ }
86
+ }
87
+ </style>
@@ -0,0 +1,34 @@
1
+ // From https://www.30secondsofcode.org/css/s/circular-progress-bar/
2
+ .circular-progress {
3
+ --stroke-width: 4px;
4
+ --half-size: calc(var(--size) / 2);
5
+ --radius: calc((var(--size) - var(--stroke-width)) / 2);
6
+ --circumference: calc(var(--radius) * pi * 2);
7
+ --dash: calc((var(--progress) * var(--circumference)) / 100);
8
+
9
+ width: var(--size);
10
+ height: var(--size);
11
+ pointer-events: none;
12
+ }
13
+
14
+ .circular-progress__background,
15
+ .circular-progress__foreground {
16
+ cx: var(--half-size);
17
+ cy: var(--half-size);
18
+ r: var(--radius);
19
+ stroke-width: var(--stroke-width);
20
+ fill: none;
21
+ stroke-linecap: round;
22
+ }
23
+
24
+ .circular-progress__background {
25
+ stroke: var(--e-c-primary-01-100);
26
+ }
27
+
28
+ .circular-progress__foreground {
29
+ transform: rotate(-90deg);
30
+ transform-origin: var(--half-size) var(--half-size);
31
+ stroke-dasharray: var(--dash) calc(var(--circumference) - var(--dash));
32
+ transition: stroke-dasharray var(--e-trs-duration-fast) ease-out 0.1s;
33
+ stroke: var(--e-c-primary-01-500);
34
+ }
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ interface Props {
5
+ size?: number
6
+ progress: number
7
+ }
8
+
9
+ const { size = 100 } = defineProps<Props>()
10
+
11
+ const viewBox = computed(() => `0 0 ${size} ${size}`)
12
+ </script>
13
+
14
+ <template>
15
+ <svg
16
+ class="circular-progress"
17
+ :viewBox
18
+ :style="{ '--size': `${size}px`, '--progress': progress }"
19
+ >
20
+ <circle class="circular-progress__background"></circle>
21
+ <circle class="circular-progress__foreground"></circle>
22
+ </svg>
23
+ </template>
24
+
25
+ <style scoped lang="scss" src="./circular-progress.scss"></style>
@@ -14,6 +14,7 @@ export { default as UCardPrice } from './card-price/u-card-price.vue'
14
14
  export { default as UCardSection } from './card-section/u-card-section.vue'
15
15
  export { default as UCardTable } from './card-table/u-card-table.vue'
16
16
  export { default as UCardToggleSwitches } from './card-toggle-switches/u-card-toggle-switches.vue'
17
+ export { default as UCardCtaHeader } from './card-cta-header/u-card-cta-header.vue'
17
18
 
18
19
  // Collapsible
19
20
  export { default as UCollapsible } from './collapsible/u-collapsible.vue'
@@ -45,3 +46,5 @@ export { default as UNavigationToolbarLink } from './navigation-toolbar-link/u-n
45
46
  export { default as UContextMenu } from './context-menu/u-context-menu.vue'
46
47
  export { default as UContextMenuLink } from './context-menu-link/u-context-menu-link.vue'
47
48
  export { default as UContextMenuDivider } from './context-menu-divider/u-context-menu-divider.vue'
49
+ export { default as UCircularProgress } from './circular-progress/u-circular-progress.vue'
50
+ export { default as UProgressAvatar } from './progress-avatar/u-progress-avatar.vue'
@@ -0,0 +1,27 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .progress-avatar {
4
+ position: relative;
5
+ display: block;
6
+ padding: a.rem(6);
7
+ width: a.rem(88);
8
+ height: a.rem(88);
9
+ }
10
+
11
+ .progress-avatar__anim-container {
12
+ position: absolute;
13
+ inset: 0;
14
+ }
15
+
16
+ .progress-avatar__image-container {
17
+ border-radius: 100%;
18
+ overflow: hidden;
19
+ aspect-ratio: 1;
20
+
21
+ img {
22
+ object-fit: cover;
23
+ object-position: center;
24
+ width: 100%;
25
+ height: 100%;
26
+ }
27
+ }
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ import { Image } from '../../elements/types'
3
+ import { UCircularProgress } from '../'
4
+
5
+ interface Props {
6
+ image: Image
7
+ progress: number
8
+ }
9
+
10
+ defineProps<Props>()
11
+ </script>
12
+
13
+ <template>
14
+ <div class="progress-avatar">
15
+ <div class="progress-avatar__anim-container">
16
+ <UCircularProgress :size="88" :progress />
17
+ </div>
18
+
19
+ <div class="progress-avatar__image-container">
20
+ <img v-bind="image" />
21
+ </div>
22
+ </div>
23
+ </template>
24
+
25
+ <style scoped lang="scss" src="./progress-avatar.scss"></style>
@@ -1,4 +1,4 @@
1
- @use '../../base/abstracts/' as a;
1
+ @use '../../base/abstracts' as a;
2
2
 
3
3
  .wizard-text-block {
4
4
  .wizard-text-block__title {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import UIcon from '../icon/u-icon.vue'
3
- import ULoader from '../loader/u-loader.vue'
2
+ import { UIcon, ULoader } from '../'
3
+ import { computed } from 'vue'
4
4
 
5
5
  // TODO: use enums for variant prop.
6
6
  interface ButtonProps {
@@ -11,9 +11,12 @@ interface ButtonProps {
11
11
  href?: string
12
12
  target?: string
13
13
  variant?: string
14
+ asSpan?: boolean
14
15
  }
15
16
 
16
- defineProps<ButtonProps>()
17
+ const { asSpan = false } = defineProps<ButtonProps>()
18
+
19
+ const buttonTag = computed(() => (asSpan ? 'span' : 'button'))
17
20
  </script>
18
21
 
19
22
  <template>
@@ -25,14 +28,18 @@ defineProps<ButtonProps>()
25
28
  </template>
26
29
 
27
30
  <template v-else>
28
- <button :class="['button', variant, { loading: loading }]" :disabled="disabled || null">
31
+ <component
32
+ :is="buttonTag"
33
+ :class="['button', variant, { loading: loading, disabled }]"
34
+ :disabled="disabled || null"
35
+ >
29
36
  <UIcon v-if="icon" :name="icon" />
30
37
  <slot>{{ label }}</slot>
31
38
 
32
39
  <span v-if="loading" class="button__loader">
33
40
  <ULoader />
34
41
  </span>
35
- </button>
42
+ </component>
36
43
  </template>
37
44
  </template>
38
45
 
@@ -0,0 +1,174 @@
1
+ @use '../../base/abstracts/' as a;
2
+
3
+ .form {
4
+ .form__messages {
5
+ display: none;
6
+ }
7
+
8
+ .form__title {
9
+ @include a.type(800, strong);
10
+
11
+ color: var(--e-c-primary-01-500);
12
+
13
+ @include a.bp(lg) {
14
+ @include a.type(700, strong);
15
+ }
16
+ }
17
+
18
+ .form__lead {
19
+ @include a.type(200, weak);
20
+
21
+ .form__subtitle-info {
22
+ color: var(--e-c-secondary-01-900);
23
+ margin-left: var(--e-space-1);
24
+
25
+ e-icon {
26
+ display: inline-block;
27
+ vertical-align: middle;
28
+ }
29
+ }
30
+ }
31
+
32
+ .form__title + .form__lead {
33
+ @include a.type(300);
34
+
35
+ @include a.bp(lg) {
36
+ @include a.type(200);
37
+ }
38
+ }
39
+
40
+ .form__subtitle {
41
+ @include a.type(300, strong);
42
+
43
+ color: var(--e-c-primary-01-500);
44
+
45
+ .form__subtitle-info {
46
+ color: var(--e-c-secondary-01-900);
47
+ margin-left: var(--e-space-1);
48
+
49
+ e-icon {
50
+ display: inline-block;
51
+ vertical-align: middle;
52
+ }
53
+ }
54
+ }
55
+
56
+ .form__cta-group {
57
+ display: flex;
58
+ grid-gap: var(--e-space-5);
59
+
60
+ @include a.bp(m) {
61
+ flex-direction: column;
62
+ }
63
+ }
64
+
65
+ // Spacing rules for text elements.
66
+ .form__title + .form__lead,
67
+ .form__subtitle + .form__lead {
68
+ margin-top: var(--e-space-3); // get 12px from title to lead
69
+
70
+ @include a.bp(lg) {
71
+ margin-top: var(--e-space-1_5); // get 6px from title to lead
72
+ }
73
+ }
74
+
75
+ // Vertical spacing classes
76
+ // These classes will be set programatically for 'e-form' extension.
77
+
78
+ // Special case
79
+ .form__lead-row + * {
80
+ margin-top: var(--e-space-5);
81
+
82
+ @include a.bp(lg) {
83
+ margin-top: var(--e-space-3);
84
+ }
85
+ }
86
+
87
+ .form__subtitle-row + *,
88
+ .form__lead-row.form__subtitle-row + * {
89
+ margin-top: var(--e-space-6);
90
+
91
+ @include a.bp(lg) {
92
+ margin-top: var(--e-space-3);
93
+ }
94
+ }
95
+
96
+ .form__input-row + .form__input-row,
97
+ .form__title-row + *,
98
+ *:not(legend) + .form__lead-row {
99
+ margin-top: var(--e-space-10);
100
+
101
+ @include a.bp(lg) {
102
+ margin-top: var(--e-space-6);
103
+ }
104
+ }
105
+
106
+ .form__input-row.form__input-row--compact + .form__input-row.form__input-row--compact {
107
+ margin-top: var(--e-space-6);
108
+ }
109
+
110
+ *:not(legend) + .form__title-row,
111
+ *:not(legend) + .form__cta-row,
112
+ *:not(legend) + .form__subtitle-row {
113
+ margin-top: var(--e-space-16);
114
+
115
+ @include a.bp(lg) {
116
+ margin-top: var(--e-space-10);
117
+ }
118
+ }
119
+
120
+ .form__input-col + .form__input-col {
121
+ @include a.bp(lg) {
122
+ margin-top: var(--e-space-6);
123
+ }
124
+ }
125
+
126
+ .form__messages-row {
127
+ display: none;
128
+ margin-top: var(--e-space-10);
129
+ }
130
+
131
+ .form__cookiebot-message {
132
+ margin-bottom: var(--e-space-6);
133
+ }
134
+ //.alert + .button {
135
+ // margin-top: var(--e-space-6);
136
+ //}
137
+
138
+ // States
139
+ &.form--has-general-error {
140
+ .form__messages-row,
141
+ .form__messages {
142
+ display: block;
143
+ }
144
+ }
145
+
146
+ &.form--hide-form-elements {
147
+ > *:not(.success-screen) {
148
+ display: none;
149
+ }
150
+ }
151
+
152
+ &.form--is-submitting {
153
+ .form-row:not(.form__cta-row) {
154
+ opacity: 0.6;
155
+ pointer-events: none;
156
+ }
157
+ }
158
+
159
+ .form__recaptcha {
160
+ font-size: a.rem(10);
161
+ line-height: 1.5;
162
+ margin-top: var(--e-space-6);
163
+ color: var(--e-c-mono-700);
164
+
165
+ a {
166
+ color: var(--e-c-primary-01-700);
167
+ text-underline-offset: var(--e-space-1);
168
+ }
169
+ }
170
+ }
171
+
172
+ .grecaptcha-badge {
173
+ visibility: hidden;
174
+ }
@@ -0,0 +1,42 @@
1
+ @use '../grid/grid.mixin' as g;
2
+ @use '../../base/abstracts' as a;
3
+
4
+ // TODO: This class doesn't seem to be necessary. Check first then remove it.
5
+ .form-grid {
6
+ width: 100%;
7
+ }
8
+
9
+ .form-row {
10
+ @include g.grid-row;
11
+
12
+ .form-col {
13
+ // Default column width
14
+ @include g.grid-col(6);
15
+ }
16
+
17
+ .form-col-1\/4 {
18
+ @include g.grid-col(3);
19
+ }
20
+
21
+ .form-col-2\/4 {
22
+ // Default column width
23
+ @include g.grid-col(6);
24
+ }
25
+
26
+ .form-col-3\/4 {
27
+ @include g.grid-col(9);
28
+ }
29
+
30
+ .form-col-4\/4 {
31
+ @include g.grid-col(12);
32
+ }
33
+
34
+ .form-col,
35
+ .form-col-1\/4,
36
+ .form-col-2\/4,
37
+ .form-col-3\/4 {
38
+ @include a.bp(lg) {
39
+ @include g.grid-col(12);
40
+ }
41
+ }
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energie360/ui-library",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,7 +14,9 @@
14
14
  "./wizard": "./wizard/index.js",
15
15
  "./utility/elements/*": "./dist/elements/*",
16
16
  "./utility/layout/*": "./dist/layout/*",
17
- "./base/abstracts": "./base/abstracts/index.scss"
17
+ "./base/abstracts": "./base/abstracts/index.scss",
18
+ "./styles/form": "./elements/form/form.scss",
19
+ "./styles/form-grid": "./layout/form-grid.scss"
18
20
  },
19
21
  "keywords": [],
20
22
  "author": "",