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/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
@@ -63,7 +63,7 @@
63
63
  "main": "dist/tide-design-system.cjs",
64
64
  "module": "dist/tide-design-system.esm.js",
65
65
  "types": "dist/tide-design-system.esm.d.ts",
66
- "version": "2.5.3",
66
+ "version": "2.5.6",
67
67
  "dependencies": {
68
68
  "@floating-ui/vue": "^1.1.6"
69
69
  }
@@ -11,8 +11,17 @@
11
11
  --tide-font-28: 1.75rem;
12
12
  --tide-font-32: 2rem;
13
13
 
14
- /* Animation */
15
- --tide-animate: 300ms ease-in-out;
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 loader = realmFolder
33
- ? () => import(`../assets/svg/icons/realm/${realmFolder}/Icon${name}.svg?component`)
34
- : () => import(`../assets/svg/icons/Icon${name}.svg?component`);
32
+ const component = defineAsyncComponent(() => {
33
+ if (realmFolder) {
34
+ return import(`../assets/svg/icons/realm/${realmFolder}/Icon${name}.svg?component`);
35
+ }
35
36
 
36
- const mod = await loader();
37
+ return import(`../assets/svg/icons/Icon${name}.svg?component`);
38
+ });
37
39
 
38
- innerSVG.value = markRaw(mod.default);
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 = {};