srcdev-nuxt-components 6.1.16 → 6.1.18

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,12 +1,16 @@
1
1
  <template>
2
- <component :is="tag" class="display-card" :class="[variant, elementClasses]">
3
- <div v-if="slots.header" class="display-card-header">
2
+ <component
3
+ :is="tag"
4
+ class="display-card"
5
+ :class="[variant, elementClasses, { 'has-dividers': hasDividers }, { 'no-outline': noOutline }]"
6
+ >
7
+ <div v-if="slots.header" class="card-row display-card-header">
4
8
  <slot name="header"></slot>
5
9
  </div>
6
- <div v-if="slots.default" class="display-card-content">
10
+ <div v-if="slots.default" class="card-row display-card-content">
7
11
  <slot name="default"></slot>
8
12
  </div>
9
- <div v-if="slots.footer" class="display-card-footer">
13
+ <div v-if="slots.footer" class="card-row display-card-footer">
10
14
  <slot name="footer"></slot>
11
15
  </div>
12
16
  </component>
@@ -21,9 +25,17 @@ const props = defineProps({
21
25
  return ["div", "section", "article", "aside", "main", "nav"].includes(value)
22
26
  },
23
27
  },
28
+ hasDividers: {
29
+ type: Boolean,
30
+ default: false,
31
+ },
32
+ noOutline: {
33
+ type: Boolean,
34
+ default: false,
35
+ },
24
36
  variant: {
25
37
  type: String,
26
- default: "subtle",
38
+ default: "solid",
27
39
  validator(value: string) {
28
40
  return ["solid", "subtle", "soft", "outline"].includes(value)
29
41
  },
@@ -48,6 +60,10 @@ watch(
48
60
  <style lang="css">
49
61
  .display-card {
50
62
  --_inner-padding: 1rem;
63
+ --_background-color: transparent;
64
+ --_border-color: transparent;
65
+ --_border-width: 0.2rem;
66
+ --_box-shadow-color: transparent;
51
67
 
52
68
  display: grid;
53
69
  grid-auto-flow: row;
@@ -55,40 +71,49 @@ watch(
55
71
  border-radius: 0.5rem;
56
72
  overflow: hidden;
57
73
 
74
+ background-color: var(--_background-color, transparent);
75
+ border: var(--_border-width) solid var(--_border-color, transparent);
76
+ box-shadow: 0 0 0.4rem var(--_border-width) var(--_box-shadow-color, transparent);
77
+
78
+ &.no-outline {
79
+ --_border-width: 0;
80
+ }
81
+
58
82
  &.solid {
59
- background-color: light-dark(var(--gray-0), var(--gray-12));
60
- border: 0.2rem solid light-dark(var(--gray-4), var(--gray-8));
83
+ --_background-color: light-dark(var(--gray-0), var(--gray-12));
84
+ --_border-color: light-dark(var(--gray-4), var(--gray-8));
61
85
  }
62
86
 
63
87
  &.subtle {
64
- background-color: color-mix(in oklab, light-dark(var(--gray-1), var(--gray-8)) 50%, transparent);
65
- border: 0.2rem solid light-dark(var(--gray-3), var(--gray-9));
88
+ --_background-color: color-mix(in oklab, light-dark(var(--gray-1), var(--gray-8)) 50%, transparent);
89
+ --_border-color: light-dark(var(--gray-3), var(--gray-9));
66
90
  }
67
91
 
68
92
  &.soft {
69
- background-color: color-mix(in oklab, light-dark(var(--gray-1), var(--gray-8)) 20%, transparent);
70
- box-shadow: 0px 0px 4px 2px color-mix(in oklab, light-dark(var(--gray-2), var(--gray-8)) 80%, transparent);
93
+ --_background-color: color-mix(in oklab, light-dark(var(--gray-1), var(--gray-8)) 20%, transparent);
94
+ --_box-shadow-color: color-mix(in oklab, light-dark(var(--gray-2), var(--gray-8)) 80%, transparent);
71
95
  }
72
96
 
73
97
  &.outline {
74
- background-color: transparent;
75
- border: 0.2rem solid light-dark(var(--gray-4), var(--gray-8));
98
+ --_background-color: transparent;
99
+ --_border-color: light-dark(var(--gray-4), var(--gray-8));
100
+ }
101
+
102
+ &.has-dividers {
103
+ .card-row + .card-row {
104
+ border-top: 0.2rem solid var(--_border-color);
105
+ }
76
106
  }
77
107
 
78
108
  .display-card-header {
79
- /* background-color: darkblue; */
80
109
  padding: var(--_inner-padding);
81
- border-bottom: 0.2rem solid light-dark(var(--gray-1), var(--gray-8));
82
110
  }
83
111
 
84
112
  .display-card-content {
85
- /* background-color: darkgreen; */
86
113
  padding: var(--_inner-padding);
87
- border-bottom: 0.2rem solid light-dark(var(--gray-1), var(--gray-8));
88
114
  }
89
115
 
90
116
  .display-card-footer {
91
- /* background-color: darkslateblue; */
92
117
  padding: var(--_inner-padding);
93
118
  }
94
119
  }
@@ -1,5 +1,9 @@
1
1
  <template>
2
- <div class="display-prompt-core" :class="[{ dismissed: hide }]" :data-test-id="`display-prompt-core-${theme}`">
2
+ <div
3
+ class="display-prompt-core"
4
+ :class="[{ closed: !compopnentOpen }]"
5
+ :data-test-id="`display-prompt-core-${theme}`"
6
+ >
3
7
  <div class="display-prompt-wrapper" :data-theme="theme" :class="[elementClasses]" data-test-id="display-prompt">
4
8
  <div class="display-prompt-inner">
5
9
  <div class="display-prompt-icon" data-test-id="prompt-icon">
@@ -17,7 +21,7 @@
17
21
  </div>
18
22
  <button
19
23
  v-if="dismissible"
20
- @click.prevent="dismissPrompt()"
24
+ @click.prevent="updateComponentState()"
21
25
  data-test-id="display-prompt-action"
22
26
  class="display-prompt-action"
23
27
  >
@@ -70,12 +74,17 @@ const props = defineProps({
70
74
  })
71
75
 
72
76
  const slots = useSlots()
73
- const hide = ref(false)
77
+ const parentComponentState = defineModel<boolean>("parentComponentState", { default: false })
78
+ const compopnentOpen = ref(true)
74
79
  const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
75
80
 
76
- const dismissPrompt = () => {
77
- // styleClassPassthrough.value = '';
78
- hide.value = true
81
+ const updateComponentState = () => {
82
+ if (parentComponentState.value) {
83
+ parentComponentState.value = false
84
+ return
85
+ }
86
+
87
+ compopnentOpen.value = false
79
88
  }
80
89
  </script>
81
90
 
@@ -86,7 +95,7 @@ const dismissPrompt = () => {
86
95
  opacity: 1;
87
96
  transition: all 200ms ease-in-out;
88
97
 
89
- &.dismissed {
98
+ &.closed {
90
99
  grid-template-rows: 0fr;
91
100
  opacity: 0;
92
101
  pointer-events: none;
@@ -141,7 +150,7 @@ const dismissPrompt = () => {
141
150
  }
142
151
 
143
152
  .text {
144
- font-size: var(--step-5);
153
+ font-size: var(--step-4);
145
154
  font-weight: normal;
146
155
  line-height: 1.3;
147
156
  color: var(--colour-theme-8);
@@ -0,0 +1,327 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <div
4
+ v-if="privateToastState"
5
+ class="display-notification"
6
+ :class="[
7
+ elementClasses,
8
+ {
9
+ [theme]: !slots.default,
10
+ 'has-theme': !slots.default,
11
+ show: publicToastState && !isHiding && displayDurationInt === 0,
12
+ 'use-timer': displayDurationInt > 0,
13
+ hide: isHiding,
14
+ },
15
+ ]"
16
+ >
17
+ <slot v-if="slots.default"></slot>
18
+
19
+ <div v-else class="display-notification-body">
20
+ <div class="display-notification-description">
21
+ <div class="description-icon icon__wrapper" :class="[theme]">
22
+ <Icon name="akar-icons:circle-check-fill" class="icon-circle-check-fill" />
23
+ </div>
24
+ <div class="description-text page-body-normal">{{ toastDisplayText }}</div>
25
+ <div class="description-close">
26
+ <button class="description-close-btn" @click.prevent="closeToast()">
27
+ <Icon name="material-symbols:close" class="close" :class="[theme]" />
28
+ </button>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ <div v-if="displayDurationInt > 0" @transitionend="closeToast()" class="display-notification-progress"></div>
33
+ </div>
34
+ </Teleport>
35
+ </template>
36
+ <script setup lang="ts">
37
+ const props = defineProps({
38
+ theme: {
39
+ type: String,
40
+ default: "ghost",
41
+ validator(value: string) {
42
+ return ["primary", "secondary", "tertiary", "ghost", "error", "info", "success", "warning"].includes(value)
43
+ },
44
+ },
45
+ revealDuration: {
46
+ type: Number,
47
+ default: 3000,
48
+ },
49
+ duration: {
50
+ type: Number,
51
+ default: 5000,
52
+ },
53
+ toastDisplayText: {
54
+ type: String,
55
+ default: "",
56
+ },
57
+ styleClassPassthrough: {
58
+ type: Array as PropType<string[]>,
59
+ default: () => [],
60
+ },
61
+ })
62
+
63
+ const slots = useSlots()
64
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
65
+
66
+ watch(
67
+ () => props.styleClassPassthrough,
68
+ () => {
69
+ resetElementClasses(props.styleClassPassthrough)
70
+ }
71
+ )
72
+
73
+ const privateToastState = ref(false)
74
+ const isHiding = ref(false)
75
+ const publicToastState = defineModel<boolean>({ default: false })
76
+
77
+ const revealDurationInt = computed(() => props.revealDuration)
78
+ const revealDuration = computed(() => revealDurationInt.value + "ms")
79
+ const displayDurationInt = computed(() => props.duration)
80
+ const displayDuration = computed(() => displayDurationInt.value + "ms")
81
+
82
+ const progressDurationInt = computed(() => Math.floor(displayDurationInt.value - revealDurationInt.value / 2))
83
+ const progressDuration = computed(() => progressDurationInt.value + "ms")
84
+
85
+ const sendCloseEvent = () => {
86
+ publicToastState.value = false
87
+ privateToastState.value = false
88
+ isHiding.value = false
89
+ }
90
+
91
+ const closeToast = async () => {
92
+ isHiding.value = true
93
+ await useSleep(revealDurationInt.value)
94
+ sendCloseEvent()
95
+ }
96
+
97
+ watch(
98
+ () => publicToastState.value,
99
+ async (newValue, previousValue) => {
100
+ if (!previousValue && newValue) {
101
+ privateToastState.value = true
102
+
103
+ if (newValue && displayDurationInt.value > 0) {
104
+ await useSleep(displayDurationInt.value)
105
+ sendCloseEvent()
106
+ }
107
+ } else if (previousValue && !newValue) {
108
+ closeToast()
109
+ }
110
+ }
111
+ )
112
+ </script>
113
+
114
+ <style lang="css">
115
+ @keyframes fade-in {
116
+ 5% {
117
+ opacity: 1;
118
+ visibility: visible;
119
+ transform: translateY(0);
120
+ }
121
+ 95% {
122
+ opacity: 1;
123
+ transform: translateY(0);
124
+ }
125
+ }
126
+
127
+ @keyframes show {
128
+ to {
129
+ opacity: 1;
130
+ visibility: visible;
131
+ transform: translateY(0);
132
+ }
133
+ }
134
+
135
+ @keyframes hide {
136
+ 0% {
137
+ opacity: 1;
138
+ visibility: visible;
139
+ transform: translateY(0);
140
+ }
141
+ 100% {
142
+ opacity: 0;
143
+ visibility: hidden;
144
+ transform: translateY(-30px);
145
+ }
146
+ }
147
+
148
+ @keyframes progress {
149
+ to {
150
+ transform: scaleX(1);
151
+ }
152
+ }
153
+
154
+ .display-notification {
155
+ display: block;
156
+ overflow: hidden;
157
+ position: fixed;
158
+ margin: 0;
159
+ opacity: 0;
160
+ visibility: hidden;
161
+
162
+ z-index: 100;
163
+
164
+ &.use-timer {
165
+ animation: fade-in v-bind(displayDuration) linear;
166
+ }
167
+
168
+ &.show {
169
+ animation: show v-bind(revealDuration)
170
+ linear(
171
+ 0,
172
+ 0.029 1.6%,
173
+ 0.123 3.5%,
174
+ 0.651 10.6%,
175
+ 0.862 14.1%,
176
+ 1.002 17.7%,
177
+ 1.046 19.6%,
178
+ 1.074 21.6%,
179
+ 1.087 23.9%,
180
+ 1.086 26.6%,
181
+ 1.014 38.5%,
182
+ 0.994 46.3%,
183
+ 1
184
+ )
185
+ forwards;
186
+ }
187
+
188
+ &.hide {
189
+ animation: hide v-bind(revealDuration)
190
+ linear(
191
+ 0,
192
+ 0.029 1.6%,
193
+ 0.123 3.5%,
194
+ 0.651 10.6%,
195
+ 0.862 14.1%,
196
+ 1.002 17.7%,
197
+ 1.046 19.6%,
198
+ 1.074 21.6%,
199
+ 1.087 23.9%,
200
+ 1.086 26.6%,
201
+ 1.014 38.5%,
202
+ 0.994 46.3%,
203
+ 1
204
+ )
205
+ forwards;
206
+ }
207
+
208
+ &:hover {
209
+ .display-notification-progress {
210
+ animation-play-state: paused;
211
+ }
212
+ }
213
+
214
+ &.full-width {
215
+ left: 24px;
216
+ right: 24px;
217
+ }
218
+
219
+ &.left {
220
+ left: 24px;
221
+ }
222
+
223
+ &.right {
224
+ right: 24px;
225
+ }
226
+
227
+ &.top {
228
+ top: 24px;
229
+ transform: translateY(-30px);
230
+ }
231
+ &.bottom {
232
+ bottom: 24px;
233
+ transform: translateY(30px);
234
+ }
235
+
236
+ &.has-theme {
237
+ align-items: center;
238
+ border: 2px solid transparent;
239
+ border-radius: 12px;
240
+ background-color: #9ce6a8;
241
+ color: white;
242
+
243
+ &.success {
244
+ background-color: var(--green-4);
245
+ border-color: var(--green-2);
246
+ }
247
+ &.error {
248
+ background-color: var(--red-3);
249
+ border-color: var(--red-2);
250
+ }
251
+ }
252
+
253
+ .display-notification-body {
254
+ display: flex;
255
+ flex-direction: row;
256
+ padding: 6px 12px 10px 12px;
257
+ }
258
+
259
+ .display-notification-description {
260
+ display: flex;
261
+ gap: 4px;
262
+ align-items: center;
263
+ justify-content: space-between;
264
+ font-size: 1rem;
265
+ flex-grow: 2;
266
+
267
+ .description {
268
+ .description-icon {
269
+ transform: translateY(2px);
270
+
271
+ &.success {
272
+ background-color: var(--green-4);
273
+ border-color: var(--green-2);
274
+ }
275
+ &.error {
276
+ background-color: var(--red-3);
277
+ border-color: var(--red-2);
278
+ }
279
+ }
280
+
281
+ .description-text {
282
+ flex-grow: 1;
283
+ text-align: right;
284
+ }
285
+ .description-close {
286
+ .description-close-btn {
287
+ background-color: transparent;
288
+ border: none;
289
+ outline: 0;
290
+ margin: 0;
291
+ padding: 0;
292
+ line-height: initial;
293
+
294
+ svg {
295
+ border-radius: 50%;
296
+ border-width: 1px;
297
+ border-style: solid;
298
+ color: var(--gray-0);
299
+
300
+ &.success {
301
+ background-color: var(--green-2);
302
+ border-color: var(--green-2);
303
+ }
304
+ &.error {
305
+ background-color: var(--red-2);
306
+ border-color: var(--red-2);
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+
314
+ .display-notification-progress {
315
+ position: absolute;
316
+ right: 8px;
317
+ bottom: 4px;
318
+ width: calc(100% - 16px);
319
+ height: 3px;
320
+ transform: scaleX(0);
321
+ transform-origin: right;
322
+ background: linear-gradient(to right, #9ce6a8, #9ce6a8);
323
+ border-radius: inherit;
324
+ animation: progress v-bind(progressDuration) linear forwards;
325
+ }
326
+ }
327
+ </style>
@@ -0,0 +1,140 @@
1
+ <template>
2
+ <component :is="tag" class="glowing-border" :class="[elementClasses, variant]">
3
+ <slot></slot>
4
+ </component>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ const props = defineProps({
9
+ tag: {
10
+ type: String,
11
+ default: "div",
12
+ validator(value: string) {
13
+ return [
14
+ "div",
15
+ "p",
16
+ "span",
17
+ "section",
18
+ "article",
19
+ "aside",
20
+ "header",
21
+ "footer",
22
+ "main",
23
+ "nav",
24
+ "ul",
25
+ "ol",
26
+ ].includes(value)
27
+ },
28
+ },
29
+ variant: {
30
+ type: String,
31
+ default: "subtle",
32
+ validator(value: string) {
33
+ return ["subtle", "vivid", "silver", "steel"].includes(value)
34
+ },
35
+ },
36
+ styleClassPassthrough: {
37
+ type: Array as PropType<string[]>,
38
+ default: () => [],
39
+ },
40
+ })
41
+
42
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
43
+
44
+ watch(
45
+ () => props.styleClassPassthrough,
46
+ () => {
47
+ resetElementClasses(props.styleClassPassthrough)
48
+ }
49
+ )
50
+ </script>
51
+
52
+ <style scoped lang="css">
53
+ @property --glow-deg {
54
+ syntax: "<angle>";
55
+ inherits: true;
56
+ initial-value: -90deg;
57
+ }
58
+
59
+ /* the colors don't need to be registed */
60
+ @property --clr-1 {
61
+ syntax: "<color>";
62
+ inherits: true;
63
+ initial-value: red;
64
+ }
65
+
66
+ @property --clr-2 {
67
+ syntax: "<color>";
68
+ inherits: true;
69
+ initial-value: yellow;
70
+ }
71
+
72
+ @property --clr-3 {
73
+ syntax: "<color>";
74
+ inherits: true;
75
+ initial-value: green;
76
+ }
77
+
78
+ @property --clr-4 {
79
+ syntax: "<color>";
80
+ inherits: true;
81
+ initial-value: blue;
82
+ }
83
+
84
+ @property --clr-5 {
85
+ syntax: "<color>";
86
+ inherits: true;
87
+ initial-value: purple;
88
+ }
89
+
90
+ .glowing-border {
91
+ &.vivid {
92
+ --clr-1: #ff0000;
93
+ --clr-2: #ffa500;
94
+ --clr-3: #ffff00;
95
+ --clr-4: #008000;
96
+ --clr-5: #0000ff;
97
+ }
98
+
99
+ &.subtle {
100
+ --clr-1: #ff9a9e;
101
+ --clr-2: #fad0c4;
102
+ --clr-3: #fad0c4;
103
+ --clr-4: #fbc2eb;
104
+ --clr-5: #a18cd1;
105
+ }
106
+
107
+ &.silver {
108
+ --clr-1: #d4d4d4;
109
+ --clr-2: #e4e4e4;
110
+ --clr-3: #f5f5f5;
111
+ --clr-4: #e4e4e4;
112
+ --clr-5: #d4d4d4;
113
+ }
114
+
115
+ &.steel {
116
+ --clr-1: #434343;
117
+ --clr-2: #5a5a5a;
118
+ --clr-3: #6e6e6e;
119
+ --clr-4: #5a5a5a;
120
+ --clr-5: #434343;
121
+ }
122
+
123
+ --gradient-glow: var(--clr-1), var(--clr-2), var(--clr-3), var(--clr-4), var(--clr-5), var(--clr-1);
124
+
125
+ border: var(--border-width, 3px) solid transparent;
126
+ border-radius: 30px;
127
+ background: linear-gradient(var(--surface, canvas) 0 0) padding-box,
128
+ conic-gradient(from var(--glow-deg), var(--gradient-glow)) border-box;
129
+
130
+ animation: glow 10s infinite linear;
131
+
132
+ overflow: hidden;
133
+ }
134
+
135
+ @keyframes glow {
136
+ 100% {
137
+ --glow-deg: 270deg;
138
+ }
139
+ }
140
+ </style>
@@ -0,0 +1,8 @@
1
+ const useSleep = async (duration: number) => {
2
+ return new Promise((resolve) => {
3
+ setTimeout(() => {
4
+ resolve(true)
5
+ }, duration)
6
+ })
7
+ }
8
+ export default useSleep
@@ -0,0 +1,6 @@
1
+ export interface IToastConfig {
2
+ showToast: boolean
3
+ variant: string
4
+ duration: number
5
+ toastDisplayText: string
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "6.1.16",
4
+ "version": "6.1.18",
5
5
  "main": "nuxt.config.ts",
6
6
  "scripts": {
7
7
  "clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",