tide-design-system 2.5.3 → 2.5.6
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/.storybook/main.ts +1 -0
- package/README.md +1 -0
- package/dist/css/variables.css +11 -2
- package/dist/style.css +1 -1
- package/dist/tide-design-system.cjs +2 -2
- package/dist/tide-design-system.esm.d.ts +50 -40
- package/dist/tide-design-system.esm.js +512 -469
- package/docs/upgrading.md +37 -0
- package/index.ts +2 -0
- package/package.json +1 -1
- package/src/assets/css/variables.css +11 -2
- package/src/components/TideButtonSave.vue +100 -0
- package/src/components/TideIcon.vue +8 -6
- package/src/stories/TideButtonSave.stories.ts +62 -0
package/docs/upgrading.md
CHANGED
|
@@ -83,9 +83,46 @@ watch(active, doSomething);
|
|
|
83
83
|
|
|
84
84
|
✅ After these changes your project should be compatible with **TIDE 2.5**.
|
|
85
85
|
|
|
86
|
+
## Upgrading from 2.4.5 → 2.4.6
|
|
87
|
+
|
|
88
|
+
### Summary
|
|
89
|
+
|
|
90
|
+
Version **2.4.6** introduced a Nuxt SSR incompatibility. From **2.4.6**, TideModal uses Vue `<Teleport />` to place modal content in `#tide-top-layer`. This is not a problem in CSR apps, but [Nuxt SSR only provides support for one teleport target](https://nuxt.com/docs/4.x/api/components/teleports#:~:text=in%20the%20DOM.-,The,wrapper.,-Body%20Teleport). The default id on this teleport target is `#teleports`.
|
|
91
|
+
|
|
92
|
+
### Migration steps
|
|
93
|
+
|
|
94
|
+
Update the `teleportId` value within the Nuxt config to `tide-top-layer`.
|
|
95
|
+
|
|
96
|
+
``` ts
|
|
97
|
+
// nuxt.config.ts
|
|
98
|
+
export defineNuxtConfig({
|
|
99
|
+
app: {
|
|
100
|
+
teleportId: 'tide-top-layer',
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Alternatively you can use the `teleportAttrs` config value.
|
|
106
|
+
|
|
107
|
+
``` ts
|
|
108
|
+
// nuxt.config.ts
|
|
109
|
+
export defineNuxtConfig({
|
|
110
|
+
app: {
|
|
111
|
+
teleportAttrs: {
|
|
112
|
+
id: 'tide-top-layer',
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
See [Nuxt Configuration docs](https://nuxt.com/docs/4.x/api/nuxt-config#teleportid).
|
|
119
|
+
|
|
120
|
+
✅ After these changes your project should be compatible with TIDE 2.4.6.
|
|
121
|
+
|
|
86
122
|
## Upgrading from 2.3 → 2.4
|
|
87
123
|
|
|
88
124
|
### Summary
|
|
125
|
+
|
|
89
126
|
Version **2.4** introduces a new suite of form components. It remains largely backward-compatible with the previous versions of components, but requires an update to a number of component names. It also removes a number of form-related TS exports.
|
|
90
127
|
|
|
91
128
|
### Migration steps
|
package/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import TideBreadCrumbs from '@/components/TideBreadCrumbs.vue';
|
|
|
7
7
|
import TideButton from '@/components/TideButton.vue';
|
|
8
8
|
import TideButtonIcon from '@/components/TideButtonIcon.vue';
|
|
9
9
|
import TideButtonPagination from '@/components/TideButtonPagination.vue';
|
|
10
|
+
import TideButtonSave from '@/components/TideButtonSave.vue';
|
|
10
11
|
import TideButtonSegmented from '@/components/TideButtonSegmented.vue';
|
|
11
12
|
import TideCard from '@/components/TideCard.vue';
|
|
12
13
|
import TideCarousel from '@/components/TideCarousel.vue';
|
|
@@ -156,6 +157,7 @@ export {
|
|
|
156
157
|
TideButton,
|
|
157
158
|
TideButtonIcon,
|
|
158
159
|
TideButtonPagination,
|
|
160
|
+
TideButtonSave,
|
|
159
161
|
TideButtonSegmented,
|
|
160
162
|
TideCard,
|
|
161
163
|
TideCarousel,
|
package/package.json
CHANGED
|
@@ -11,8 +11,17 @@
|
|
|
11
11
|
--tide-font-28: 1.75rem;
|
|
12
12
|
--tide-font-32: 2rem;
|
|
13
13
|
|
|
14
|
-
/*
|
|
15
|
-
--tide-
|
|
14
|
+
/* Motion */
|
|
15
|
+
--tide-duration-75: 75ms;
|
|
16
|
+
--tide-duration-150: 150ms;
|
|
17
|
+
--tide-duration-300: 300ms;
|
|
18
|
+
--tide-duration-600: 600ms;
|
|
19
|
+
|
|
20
|
+
--tide-easing-ease: ease;
|
|
21
|
+
--tide-easing-ease-out: ease-out;
|
|
22
|
+
--tide-easing-linear: linear;
|
|
23
|
+
|
|
24
|
+
--tide-animate: var(--tide-duration-300) var(--tide-easing-ease);
|
|
16
25
|
|
|
17
26
|
/* Spacing */
|
|
18
27
|
--tide-spacing-0: 0rem;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
import { CSS } from '@/types/Styles';
|
|
5
|
+
|
|
6
|
+
const isTouched = ref(false);
|
|
7
|
+
const isSaved = defineModel<boolean>({ required: true });
|
|
8
|
+
|
|
9
|
+
watch(
|
|
10
|
+
isSaved,
|
|
11
|
+
() => {
|
|
12
|
+
if (!isTouched.value) isTouched.value = true;
|
|
13
|
+
},
|
|
14
|
+
{ immediate: false }
|
|
15
|
+
);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<button
|
|
20
|
+
:class="['tide-button-save', CSS.PADDING.FULL.QUARTER, isSaved && 'saved']"
|
|
21
|
+
@click="isSaved = !isSaved"
|
|
22
|
+
type="button"
|
|
23
|
+
>
|
|
24
|
+
<div :class="['heart-container', CSS.DISPLAY.FLEX, isSaved && isTouched && 'animate-heartbeat']">
|
|
25
|
+
<svg
|
|
26
|
+
:class="['tide-button-save-icon', CSS.FLEX.GROW.OFF, CSS.FLEX.SHRINK.OFF]"
|
|
27
|
+
height="32"
|
|
28
|
+
viewBox="0 0 24 24"
|
|
29
|
+
width="32"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
:class="['heart-filled', isSaved ? CSS.FONT.COLOR.GLOBAL.PRIMARY.RED : 'filled-transparent']"
|
|
34
|
+
d="m12 21-1.45-1.3c-1.6833-1.5167-3.075-2.825-4.175-3.925-1.1-1.1-1.975-2.0875-2.625-2.9625-.65-.875-1.1042-1.6792-1.3625-2.4125C2.1292 9.6667 2 8.9167 2 8.15c0-1.5667.525-2.875 1.575-3.925C4.625 3.175 5.9333 2.65 7.5 2.65c.8667 0 1.6917.1833 2.475.55.7833.3667 1.4583.8833 2.025 1.55.5667-.6667 1.2417-1.1833 2.025-1.55.7833-.3667 1.6083-.55 2.475-.55 1.5667 0 2.875.525 3.925 1.575C21.475 5.275 22 6.5833 22 8.15c0 .7667-.1292 1.5167-.3875 2.25-.2583.7333-.7125 1.5375-1.3625 2.4125s-1.525 1.8625-2.625 2.9625c-1.1 1.1-2.4917 2.4083-4.175 3.925L12 21Z"
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
<path
|
|
38
|
+
:class="['heart-outline', CSS.FONT.COLOR.SURFACE.INVERSE]"
|
|
39
|
+
d="m12 21-1.45-1.3c-1.6833-1.5167-3.075-2.825-4.175-3.925-1.1-1.1-1.975-2.0875-2.625-2.9625-.65-.875-1.1042-1.6792-1.3625-2.4125C2.1292 9.6667 2 8.9167 2 8.15c0-1.5667.525-2.875 1.575-3.925C4.625 3.175 5.9333 2.65 7.5 2.65c.8667 0 1.6917.1833 2.475.55.7833.3667 1.4583.8833 2.025 1.55.5667-.6667 1.2417-1.1833 2.025-1.55.7833-.3667 1.6083-.55 2.475-.55 1.5667 0 2.875.525 3.925 1.575C21.475 5.275 22 6.5833 22 8.15c0 .7667-.1292 1.5167-.3875 2.25-.2583.7333-.7125 1.5375-1.3625 2.4125s-1.525 1.8625-2.625 2.9625c-1.1 1.1-2.4917 2.4083-4.175 3.925L12 21Zm0-2.7c1.6-1.4333 2.9167-2.6625 3.95-3.6875s1.85-1.9167 2.45-2.675c.6-.7583 1.0167-1.4333 1.25-2.025.2333-.5917.35-1.1792.35-1.7625 0-1-.3333-1.8333-1-2.5-.6667-.6667-1.5-1-2.5-1-.7833 0-1.5083.2208-2.175.6625C13.6583 5.7542 13.2 6.3167 12.95 7h-1.9c-.25-.6833-.7083-1.2458-1.375-1.6875S8.2833 4.65 7.5 4.65c-1 0-1.8333.3333-2.5 1-.6667.6667-1 1.5-1 2.5 0 .5833.1167 1.1708.35 1.7625.2333.5917.65 1.2667 1.25 2.025s1.4167 1.65 2.45 2.675S10.4 16.8667 12 18.3Z"
|
|
40
|
+
/>
|
|
41
|
+
</svg>
|
|
42
|
+
</div>
|
|
43
|
+
</button>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<style scoped>
|
|
47
|
+
.heart-container {
|
|
48
|
+
--rotate-during-heart-beat: 9deg;
|
|
49
|
+
filter: drop-shadow(0px 2px 8px rgba(0, 0, 0, 0.3));
|
|
50
|
+
transition: var(--tide-duration-300) var(--tide-easing-ease-out);
|
|
51
|
+
transition-property: transform, scale;
|
|
52
|
+
rotate: 0deg;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.heart-container.animate-heartbeat {
|
|
56
|
+
animation: heartBeat var(--tide-duration-150);
|
|
57
|
+
animation-direction: alternate;
|
|
58
|
+
animation-iteration-count: 4;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.heart-container:active {
|
|
62
|
+
scale: 0.9;
|
|
63
|
+
transition-duration: var(--tide-duration-75);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.tide-button-save-icon {
|
|
67
|
+
fill: currentColor;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media (hover: hover) {
|
|
71
|
+
.heart-container {
|
|
72
|
+
--rotate-during-heart-beat: 0deg;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.tide-button-save:where(:hover, :focus-visible) .heart-container {
|
|
76
|
+
transform: rotate(9deg);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.heart-filled {
|
|
81
|
+
scale: 0.985; /* avoid hairline border render issue */
|
|
82
|
+
transform-origin: center;
|
|
83
|
+
transition: color var(--tide-duration-75) var(--tide-easing-linear);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.filled-transparent {
|
|
87
|
+
color: var(--tide-transparent-400);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes heartBeat {
|
|
91
|
+
from {
|
|
92
|
+
scale: 1;
|
|
93
|
+
rotate: 0deg;
|
|
94
|
+
}
|
|
95
|
+
to {
|
|
96
|
+
scale: 1.25;
|
|
97
|
+
rotate: var(--rotate-during-heart-beat);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { markRaw, ref, watch } from 'vue';
|
|
2
|
+
import { defineAsyncComponent, markRaw, ref, watch } from 'vue';
|
|
3
3
|
|
|
4
4
|
import { REALM } from '@/types/Realm';
|
|
5
5
|
import { SIZE } from '@/types/Size';
|
|
@@ -29,13 +29,15 @@
|
|
|
29
29
|
const [prefix] = id.split('-');
|
|
30
30
|
const realmFolder = REALM[prefix?.toUpperCase() as keyof typeof REALM];
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const component = defineAsyncComponent(() => {
|
|
33
|
+
if (realmFolder) {
|
|
34
|
+
return import(`../assets/svg/icons/realm/${realmFolder}/Icon${name}.svg?component`);
|
|
35
|
+
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
return import(`../assets/svg/icons/Icon${name}.svg?component`);
|
|
38
|
+
});
|
|
37
39
|
|
|
38
|
-
innerSVG.value = markRaw(
|
|
40
|
+
innerSVG.value = markRaw(component);
|
|
39
41
|
},
|
|
40
42
|
{ immediate: true }
|
|
41
43
|
);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ref, watch } from 'vue';
|
|
2
|
+
|
|
3
|
+
import TideButtonSave from '@/components/TideButtonSave.vue';
|
|
4
|
+
import { dataTrack, doSomething, parameters } from '@/utilities/storybook';
|
|
5
|
+
|
|
6
|
+
import type { StoryContext } from '@storybook/vue3';
|
|
7
|
+
|
|
8
|
+
type Args = InstanceType<typeof TideButtonSave>['$props'] & {
|
|
9
|
+
vModel: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const render = (args: Args, context: StoryContext) => ({
|
|
13
|
+
components: { TideButtonSave },
|
|
14
|
+
methods: {
|
|
15
|
+
doSomething,
|
|
16
|
+
handleIsSavedChange: (value: boolean) => {
|
|
17
|
+
context.updateArgs({ ...args, vModel: value });
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
setup: () => {
|
|
21
|
+
const isSaved = ref(args.vModel);
|
|
22
|
+
|
|
23
|
+
watch(
|
|
24
|
+
() => args.vModel,
|
|
25
|
+
(newValue) => {
|
|
26
|
+
isSaved.value = newValue;
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
args,
|
|
32
|
+
isSaved,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
template: `<TideButtonSave v-bind="args" v-model="isSaved" @update:modelValue="handleIsSavedChange" />`,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export default {
|
|
39
|
+
argTypes: {
|
|
40
|
+
dataTrack,
|
|
41
|
+
vModel: {
|
|
42
|
+
control: 'boolean',
|
|
43
|
+
description: 'Data binding to Vue ref',
|
|
44
|
+
table: {
|
|
45
|
+
category: 'Native',
|
|
46
|
+
defaultValue: { summary: 'None' },
|
|
47
|
+
type: { summary: 'Ref<boolean>' },
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
args: {
|
|
52
|
+
dataTrack: '',
|
|
53
|
+
vModel: false,
|
|
54
|
+
},
|
|
55
|
+
component: TideButtonSave,
|
|
56
|
+
parameters,
|
|
57
|
+
render,
|
|
58
|
+
tags: ['autodocs'],
|
|
59
|
+
title: 'Components/TideButtonSave',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Demo = {};
|