tide-design-system 2.4.5 → 2.5.0

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 (66) hide show
  1. package/.storybook/main.ts +1 -0
  2. package/dist/css/reset.css +1 -1
  3. package/dist/css/utilities-responsive.css +0 -546
  4. package/dist/style.css +1 -1
  5. package/dist/tide-design-system.cjs +2 -2
  6. package/dist/tide-design-system.esm.d.ts +171 -73
  7. package/dist/tide-design-system.esm.js +1725 -1594
  8. package/dist/utilities/storybook.ts +6 -2
  9. package/dist/utilities/validation.ts +1 -1
  10. package/docs/upgrading.md +79 -0
  11. package/index.ts +8 -5
  12. package/package.json +1 -1
  13. package/src/assets/css/reset.css +1 -1
  14. package/src/assets/css/utilities-responsive.css +0 -546
  15. package/src/components/InternalBaseLink.vue +11 -0
  16. package/src/components/TideAccordionItem.vue +21 -13
  17. package/src/components/TideBreadCrumbs.vue +3 -2
  18. package/src/components/TideButton.vue +17 -4
  19. package/src/components/TideButtonIcon.vue +15 -2
  20. package/src/components/TideButtonPagination.vue +16 -16
  21. package/src/components/TideButtonSegmented.vue +15 -15
  22. package/src/components/TideCard.vue +12 -2
  23. package/src/components/TideCarousel.vue +10 -5
  24. package/src/components/TideChipAction.vue +7 -1
  25. package/src/components/TideChipFilter.vue +14 -7
  26. package/src/components/TideChipInput.vue +1 -0
  27. package/src/components/TideIcon.vue +8 -9
  28. package/src/components/TideImage.vue +9 -9
  29. package/src/components/TideInputCheckbox.vue +0 -1
  30. package/src/components/TideInputText.vue +2 -0
  31. package/src/components/TideInputTextDeprecated.vue +2 -0
  32. package/src/components/TideInputTextarea.vue +2 -2
  33. package/src/components/TideLink.vue +7 -1
  34. package/src/components/TideMenuItem.vue +83 -0
  35. package/src/components/TideModal.vue +120 -101
  36. package/src/components/TidePagination.vue +17 -19
  37. package/src/components/TideSeoLinks.vue +3 -2
  38. package/src/components/TideSheet.vue +28 -23
  39. package/src/components/TideSwitch.vue +24 -20
  40. package/src/composables/useTideConfig.ts +23 -0
  41. package/src/stories/TideAccordionItem.stories.ts +33 -34
  42. package/src/stories/TideButtonPagination.stories.ts +6 -6
  43. package/src/stories/TideButtonSegmented.stories.ts +33 -25
  44. package/src/stories/TideCarousel.stories.ts +0 -1
  45. package/src/stories/TideChipFilter.stories.ts +33 -23
  46. package/src/stories/TideInputCheckbox.stories.ts +66 -23
  47. package/src/stories/TideInputRadio.stories.ts +39 -30
  48. package/src/stories/TideInputSelect.stories.ts +51 -27
  49. package/src/stories/TideInputText.stories.ts +83 -23
  50. package/src/stories/TideInputTextarea.stories.ts +66 -17
  51. package/src/stories/TideLink.stories.ts +1 -14
  52. package/src/stories/TideMenuItem.stories.ts +117 -0
  53. package/src/stories/TideModal.stories.ts +33 -37
  54. package/src/stories/TidePagination.stories.ts +33 -22
  55. package/src/stories/TidePopover.stories.ts +1 -1
  56. package/src/stories/TideSheet.stories.ts +33 -28
  57. package/src/stories/TideSwitch.stories.ts +33 -34
  58. package/src/types/Badge.ts +4 -0
  59. package/src/types/Element.ts +2 -2
  60. package/src/types/Formatted.ts +1 -0
  61. package/src/types/Storybook.ts +4 -6
  62. package/src/types/Type.ts +6 -0
  63. package/src/types/Validation.ts +1 -0
  64. package/src/utilities/storybook.ts +6 -2
  65. package/src/utilities/validation.ts +1 -1
  66. package/tests/InternalBaseLink.spec.ts +61 -0
@@ -1,4 +1,7 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+
4
+ import InternalBaseLink from '@/components/InternalBaseLink.vue';
2
5
  import TideIcon from '@/components/TideIcon.vue';
3
6
  import { ELEMENT } from '@/types/Element';
4
7
  import { PRIORITY } from '@/types/Priority';
@@ -10,6 +13,7 @@
10
13
  import type { Icon } from '@/types/Icon';
11
14
  import type { Priority } from '@/types/Priority';
12
15
  import type { SizeButton } from '@/types/Size';
16
+ import type { ButtonType } from '@/types/Type';
13
17
 
14
18
  type Props = {
15
19
  disabled?: boolean;
@@ -21,6 +25,7 @@
21
25
  label: string;
22
26
  priority?: Priority;
23
27
  size?: SizeButton;
28
+ type?: ButtonType;
24
29
  };
25
30
 
26
31
  const props = withDefaults(defineProps<Props>(), {
@@ -33,7 +38,14 @@
33
38
  label: undefined,
34
39
  priority: PRIORITY.PRIMARY,
35
40
  size: SIZE_BUTTON.LARGE,
41
+ type: undefined,
36
42
  });
43
+
44
+ const typeAttribute = computed<string | undefined>(() =>
45
+ props.element === ELEMENT.BUTTON ? props.type ?? ELEMENT.BUTTON : undefined
46
+ );
47
+
48
+ const rootElement = computed(() => (props.element === ELEMENT.LINK ? InternalBaseLink : props.element));
37
49
  </script>
38
50
 
39
51
  <template>
@@ -43,18 +55,19 @@
43
55
  props.priority && `tide-button-${props.priority}`,
44
56
  props.element === ELEMENT.LINK ? [CSS.DISPLAY.INLINE_FLEX] : [CSS.DISPLAY.FLEX],
45
57
  props.element === ELEMENT.LINK ? CSS.UNDERLINE.REST.OFF : '',
46
- size === SIZE_BUTTON.SMALL && [CSS.FONT.ROLE.BUTTON_2, CSS.PADDING.X.ONE, CSS.PADDING.Y.HALF],
47
- size === SIZE_BUTTON.LARGE && [CSS.FONT.ROLE.BUTTON_1, CSS.PADDING.X.TWO, CSS.PADDING.Y.ONE],
58
+ size === SIZE_BUTTON.SMALL
59
+ ? [CSS.FONT.ROLE.BUTTON_2, CSS.PADDING.X.ONE, CSS.PADDING.Y.HALF, CSS.BORDER.RADIUS.QUARTER]
60
+ : [CSS.FONT.ROLE.BUTTON_1, CSS.PADDING.X.TWO, CSS.PADDING.Y.ONE, CSS.BORDER.RADIUS.HALF],
48
61
  CSS.AXIS1.CENTER,
49
62
  CSS.AXIS2.CENTER,
50
63
  CSS.GAP.HALF,
51
- CSS.BORDER.RADIUS.HALF,
52
64
  CSS.FONT.ROLE.LABEL_1_SEMIBOLD,
53
65
  ]"
54
66
  :disabled="props.element === ELEMENT.BUTTON && props.disabled"
55
67
  :href="props.element === ELEMENT.LINK && props.href ? props.href : undefined"
56
68
  :target="props.element === ELEMENT.LINK && props.isNewTab ? TARGET.BLANK : TARGET.SELF"
57
- :is="props.element === ELEMENT.LINK ? ELEMENT.LINK : ELEMENT.BUTTON"
69
+ :type="typeAttribute"
70
+ :is="rootElement"
58
71
  >
59
72
  <TideIcon
60
73
  :icon="props.iconLeading"
@@ -1,4 +1,7 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+
4
+ import InternalBaseLink from '@/components/InternalBaseLink.vue';
2
5
  import TideIcon from '@/components/TideIcon.vue';
3
6
  import { ELEMENT } from '@/types/Element';
4
7
  import { PRIORITY } from '@/types/Priority';
@@ -9,6 +12,7 @@
9
12
  import type { Element } from '@/types/Element';
10
13
  import type { Icon } from '@/types/Icon';
11
14
  import type { Priority } from '@/types/Priority';
15
+ import type { ButtonType } from '@/types/Type';
12
16
 
13
17
  type Props = {
14
18
  disabled?: boolean;
@@ -17,6 +21,7 @@
17
21
  icon: Icon;
18
22
  isNewTab?: boolean;
19
23
  priority?: Priority;
24
+ type?: ButtonType;
20
25
  };
21
26
 
22
27
  const props = withDefaults(defineProps<Props>(), {
@@ -26,14 +31,21 @@
26
31
  icon: undefined,
27
32
  isNewTab: false,
28
33
  priority: PRIORITY.PRIMARY,
34
+ type: undefined,
29
35
  });
36
+
37
+ const typeAttribute = computed<string | undefined>(() =>
38
+ props.element === ELEMENT.BUTTON ? props.type ?? ELEMENT.BUTTON : undefined
39
+ );
40
+
41
+ const rootElement = computed(() => (props.element === ELEMENT.LINK ? InternalBaseLink : props.element));
30
42
  </script>
31
43
 
32
44
  <template>
33
45
  <component
34
46
  :aria-label="props.icon"
35
47
  :class="[
36
- props.element === ELEMENT.LINK ? 'tide-link-as-button-icon' : 'tide-button-icon',
48
+ 'tide-button-icon',
37
49
  props.priority && `tide-button-${props.priority}`,
38
50
  [CSS.DISPLAY.FLEX, CSS.AXIS1.CENTER, CSS.AXIS2.CENTER, CSS.BORDER.RADIUS.FULL, CSS.PADDING.FULL.HALF],
39
51
  props.element === ELEMENT.LINK ? [CSS.UNDERLINE.REST.OFF] : '',
@@ -41,7 +53,8 @@
41
53
  :disabled="props.element === ELEMENT.BUTTON && props.disabled"
42
54
  :href="props.element === ELEMENT.LINK && props.href ? props.href : undefined"
43
55
  :target="props.element === ELEMENT.LINK && props.isNewTab ? TARGET.BLANK : TARGET.SELF"
44
- :is="props.element === ELEMENT.LINK ? 'a' : 'button'"
56
+ :type="typeAttribute"
57
+ :is="rootElement"
45
58
  >
46
59
  <TideIcon
47
60
  :icon="props.icon"
@@ -1,42 +1,42 @@
1
1
  <script lang="ts" setup>
2
- import { ELEMENT_TEXT_AS_ICON } from '@/types/Element';
2
+ import { computed } from 'vue';
3
+
4
+ import InternalBaseLink from '@/components/InternalBaseLink.vue';
5
+ import { ELEMENT, ELEMENT_BROAD } from '@/types/Element';
3
6
  import { CSS } from '@/types/Styles';
4
7
 
5
- import type { ElementTextAsIcon } from '@/types/Element';
8
+ import type { ElementBroad } from '@/types/Element';
6
9
 
7
10
  type Props = {
8
11
  disabled?: boolean;
9
- element?: ElementTextAsIcon;
12
+ element?: ElementBroad;
10
13
  href?: string;
11
14
  label: string | number;
12
15
  };
13
16
 
14
17
  const props = withDefaults(defineProps<Props>(), {
15
18
  disabled: false,
16
- element: ELEMENT_TEXT_AS_ICON.BUTTON,
19
+ element: ELEMENT_BROAD.BUTTON,
17
20
  href: undefined,
18
21
  label: undefined,
19
22
  });
23
+
24
+ const rootElement = computed(() => (props.element === ELEMENT.LINK ? InternalBaseLink : props.element));
20
25
  </script>
21
26
 
22
27
  <template>
23
28
  <component
24
29
  :class="[
25
- props.element === ELEMENT_TEXT_AS_ICON.LINK ? 'tide-link-as-button-icon' : 'tide-button-icon',
30
+ 'tide-button-icon',
26
31
  [CSS.DISPLAY.INLINE_BLOCK, CSS.BORDER.RADIUS.FULL, CSS.PADDING.FULL.HALF],
27
- props.element === ELEMENT_TEXT_AS_ICON.LINK ? [CSS.UNDERLINE.REST.OFF] : '',
28
- props.element === ELEMENT_TEXT_AS_ICON.DIV ? [CSS.CURSOR.POINTER] : '',
32
+ props.element === ELEMENT_BROAD.LINK ? [CSS.UNDERLINE.REST.OFF] : '',
33
+ props.element === ELEMENT_BROAD.DIV ? [CSS.CURSOR.POINTER] : '',
29
34
  [CSS.FONT.ROLE.HEADLINE_3],
30
35
  ]"
31
- :disabled="props.element === ELEMENT_TEXT_AS_ICON.BUTTON && props.disabled"
32
- :href="props.element === ELEMENT_TEXT_AS_ICON.LINK && props.href ? props.href : undefined"
33
- :is="
34
- props.element === ELEMENT_TEXT_AS_ICON.LINK
35
- ? 'a'
36
- : props.element === ELEMENT_TEXT_AS_ICON.BUTTON
37
- ? 'button'
38
- : 'div'
39
- "
36
+ :disabled="props.element === ELEMENT_BROAD.BUTTON && props.disabled"
37
+ :href="props.element === ELEMENT_BROAD.LINK && props.href ? props.href : undefined"
38
+ :type="element === ELEMENT_BROAD.BUTTON ? ELEMENT_BROAD.BUTTON : undefined"
39
+ :is="rootElement"
40
40
  >
41
41
  <span :class="['label', CSS.DISPLAY.FLEX, CSS.AXIS1.CENTER, CSS.AXIS2.CENTER]">
42
42
  {{ props.label }}
@@ -4,18 +4,15 @@
4
4
  import type { Tab } from '@/types/Tab';
5
5
 
6
6
  type Props = {
7
- activeTab: number;
8
- tabs: Tab[];
7
+ tabs: Tab[] | readonly Tab[];
9
8
  };
10
9
 
11
- const props = withDefaults(defineProps<Props>(), {
12
- activeTab: 0,
13
- });
10
+ defineProps<Props>();
14
11
 
15
- const emit = defineEmits(['change']);
12
+ const currentIndex = defineModel<number>({ required: true });
16
13
 
17
14
  const handleClick = (index: number) => {
18
- emit('change', index);
15
+ currentIndex.value = index;
19
16
  };
20
17
  </script>
21
18
 
@@ -24,32 +21,34 @@
24
21
  :class="[
25
22
  'tide-button-segmented',
26
23
  CSS.BG.SURFACE.VARIANT,
24
+ CSS.BORDER.RADIUS.FULL,
27
25
  CSS.DISPLAY.FLEX,
26
+ CSS.FLEX.SHRINK.OFF,
28
27
  CSS.GAP.QUARTER,
29
- CSS.BORDER.RADIUS.FULL,
28
+ CSS.OVERFLOW.XY.AUTO,
30
29
  CSS.PADDING.FULL.QUARTER,
31
- CSS.OVERFLOW.XY.HIDDEN,
32
- CSS.WIDTH.FULL,
33
30
  ]"
34
31
  >
35
32
  <button
36
33
  :class="[
37
34
  'tide-button-segmented-tab',
38
- index === activeTab
35
+ index === currentIndex
39
36
  ? [CSS.BG.SURFACE.DEFAULT, CSS.FONT.COLOR.SURFACE.DEFAULT, CSS.SHADOW.BOTTOM]
40
37
  : ['inactive', CSS.FONT.COLOR.SURFACE.VARIANT],
41
- CSS.FLEX.GROW.ON,
42
38
  CSS.BORDER.FULL.TWO,
43
39
  CSS.BORDER.RADIUS.FULL,
44
- CSS.PADDING.Y.QUARTER,
45
- CSS.WIDTH.FULL,
40
+ CSS.FLEX.GROW.ON,
46
41
  CSS.FONT.ROLE.BUTTON_1,
42
+ CSS.PADDING.X.HALF,
43
+ CSS.PADDING.Y.QUARTER,
47
44
  CSS.WHITESPACE_WRAP.OFF,
45
+ CSS.WIDTH.FULL,
48
46
  ]"
49
47
  :data-track="tab.dataTrack || undefined"
50
48
  :key="tab.label"
51
49
  @click="handleClick(index)"
52
- v-for="(tab, index) in props.tabs"
50
+ type="button"
51
+ v-for="(tab, index) in tabs"
53
52
  >
54
53
  <span :class="[CSS.FONT.ROLE.LABEL_2_SEMIBOLD]">
55
54
  {{ tab.label }}
@@ -68,6 +67,7 @@
68
67
  <style scoped>
69
68
  .tide-button-segmented {
70
69
  max-width: 23.3rem;
70
+ align-self: stretch;
71
71
  }
72
72
 
73
73
  .tide-button-segmented-tab {
@@ -1,10 +1,15 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+
4
+ import InternalBaseLink from '@/components/InternalBaseLink.vue';
2
5
  import TideIcon from '@/components/TideIcon.vue';
3
6
  import { TYPE_CARD } from '@/types/Card';
7
+ import { ELEMENT_BROAD } from '@/types/Element';
4
8
  import { SIZE } from '@/types/Size';
5
9
  import { CSS } from '@/types/Styles';
6
10
 
7
11
  import type { CardType } from '@/types/Card';
12
+ import type { ElementBroad } from '@/types/Element';
8
13
  import type { Icon } from '@/types/Icon';
9
14
 
10
15
  type Props = {
@@ -16,13 +21,17 @@
16
21
  href?: string;
17
22
  };
18
23
 
19
- withDefaults(defineProps<Props>(), {
24
+ const props = withDefaults(defineProps<Props>(), {
20
25
  description: undefined,
21
26
  href: undefined,
22
27
  icon: undefined,
23
28
  selected: undefined,
24
29
  type: TYPE_CARD.INFORMATIONAL,
25
30
  });
31
+
32
+ const rootElement = computed<ElementBroad | typeof InternalBaseLink>(() =>
33
+ props.href ? InternalBaseLink : props.type === TYPE_CARD.INFORMATIONAL ? ELEMENT_BROAD.DIV : ELEMENT_BROAD.DIV
34
+ );
26
35
  </script>
27
36
 
28
37
  <template>
@@ -42,7 +51,8 @@
42
51
  type === TYPE_CARD.SELECTABLE && selected && 'selected',
43
52
  ]"
44
53
  :href="href"
45
- :is="href ? 'a' : type === TYPE_CARD.INFORMATIONAL ? 'div' : 'button'"
54
+ :type="rootElement === ELEMENT_BROAD.BUTTON ? ELEMENT_BROAD.BUTTON : undefined"
55
+ :is="rootElement"
46
56
  >
47
57
  <TideIcon
48
58
  :class="[CSS.FLEX.GROW.OFF, CSS.FLEX.SHRINK.OFF]"
@@ -12,7 +12,6 @@
12
12
  isHeadline1?: boolean;
13
13
  isHideawayButtons?: boolean;
14
14
  isScrollByPage?: boolean;
15
- isTouchscreen?: boolean;
16
15
  maxDots?: number;
17
16
  subtitle?: string;
18
17
  title?: string;
@@ -24,7 +23,6 @@
24
23
  isHeadline1: false,
25
24
  isHideawayButtons: true,
26
25
  isScrollByPage: true,
27
- isTouchscreen: undefined,
28
26
  maxDots: 5,
29
27
  subtitle: undefined,
30
28
  title: undefined,
@@ -83,6 +81,7 @@
83
81
 
84
82
  contentWidth.value = containerRef.value.scrollWidth;
85
83
  frameWidth.value = containerRef.value.clientWidth;
84
+ showButtons.value = contentWidth.value > frameWidth.value;
86
85
  };
87
86
 
88
87
  const observeSlides = () => {
@@ -237,14 +236,14 @@
237
236
  v-if="props.title"
238
237
  >
239
238
  <div
240
- :class="[CSS.WHITESPACE_WRAP.OFF, isHeadline1 ? CSS.FONT.ROLE.HEADLINE_1 : CSS.FONT.ROLE.HEADLINE_2]"
239
+ :class="[isHeadline1 ? CSS.FONT.ROLE.HEADLINE_1 : CSS.FONT.ROLE.HEADLINE_2]"
241
240
  v-if="props.title"
242
241
  >
243
242
  {{ props.title }}
244
243
  </div>
245
244
 
246
245
  <div
247
- :class="[CSS.WHITESPACE_WRAP.OFF, CSS.FONT.ROLE.LABEL_2, CSS.FONT.COLOR.SURFACE.VARIANT]"
246
+ :class="[CSS.FONT.ROLE.LABEL_2, CSS.FONT.COLOR.SURFACE.VARIANT]"
248
247
  v-if="props.subtitle"
249
248
  >
250
249
  {{ props.subtitle }}
@@ -273,7 +272,7 @@
273
272
 
274
273
  <slot name="misc" />
275
274
 
276
- <div :class="[CSS.POSITION.RELATIVE, CSS.DISPLAY.FLEX, CSS.AXIS1.CENTER]">
275
+ <div :class="[CSS.POSITION.RELATIVE, CSS.DISPLAY.FLEX]">
277
276
  <ul
278
277
  :class="[
279
278
  'tide-carousel-container',
@@ -393,4 +392,10 @@
393
392
  transform: scale(1);
394
393
  opacity: 1;
395
394
  }
395
+
396
+ @media (pointer: coarse) {
397
+ .tide-carousel .tide-carousel-button-overlay {
398
+ display: none;
399
+ }
400
+ }
396
401
  </style>
@@ -1,4 +1,7 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+
4
+ import InternalBaseLink from '@/components/InternalBaseLink.vue';
2
5
  import TideIcon from '@/components/TideIcon.vue';
3
6
  import { ELEMENT } from '@/types/Element';
4
7
  import { ICON } from '@/types/Icon';
@@ -19,6 +22,8 @@
19
22
  href: undefined,
20
23
  isNewTab: false,
21
24
  });
25
+
26
+ const rootElement = computed(() => (props.element === ELEMENT.LINK ? InternalBaseLink : props.element));
22
27
  </script>
23
28
 
24
29
  <template>
@@ -39,7 +44,8 @@
39
44
  ]"
40
45
  :href="props.href"
41
46
  :target="props.isNewTab ? TARGET.BLANK : TARGET.SELF"
42
- :is="element"
47
+ :type="element === ELEMENT.BUTTON ? ELEMENT.BUTTON : undefined"
48
+ :is="rootElement"
43
49
  >
44
50
  <TideIcon :icon="ICON.SEARCH" />
45
51
 
@@ -2,19 +2,24 @@
2
2
  import { CSS } from '@/types/Styles';
3
3
 
4
4
  type Props = {
5
- isActive: boolean;
6
5
  label: string;
7
6
  };
8
7
 
9
- const props = defineProps<Props>();
8
+ defineProps<Props>();
9
+
10
+ const isActive = defineModel<boolean>({ required: true });
11
+
12
+ const handleClick = () => {
13
+ isActive.value = !isActive.value;
14
+ };
10
15
  </script>
11
16
 
12
17
  <template>
13
18
  <button
14
19
  :class="[
15
20
  'tide-chip-filter',
16
- props.isActive
17
- ? [CSS.BG.SECONDARY, CSS.FONT.COLOR.SECONDARY]
21
+ isActive
22
+ ? ['active', CSS.BG.SECONDARY, CSS.FONT.COLOR.SECONDARY]
18
23
  : [CSS.BG.SURFACE.VARIANT, CSS.FONT.COLOR.SURFACE.DEFAULT],
19
24
  CSS.DISPLAY.FLEX,
20
25
  CSS.AXIS2.CENTER,
@@ -24,13 +29,15 @@
24
29
  CSS.PADDING.X.ONE,
25
30
  CSS.PADDING.Y.HALF,
26
31
  CSS.FONT.ROLE.LABEL_2,
27
- props.isActive ? 'active' : '',
28
32
  ]"
33
+ @click="handleClick"
34
+ type="button"
29
35
  >
30
36
  <slot />
37
+
31
38
  <div :class="[CSS.DISPLAY.FLEX, CSS.AXIS1.CENTER, CSS.AXIS2.CENTER, CSS.GAP.HALF]">
32
- <span :class="[props.isActive ? '' : 'icon-spacing', CSS.FONT.ROLE.LABEL_1, CSS.WHITESPACE_WRAP.OFF]">
33
- {{ props.label }}
39
+ <span :class="[CSS.FONT.ROLE.LABEL_1, CSS.WHITESPACE_WRAP.OFF]">
40
+ {{ label }}
34
41
  </span>
35
42
  </div>
36
43
  </button>
@@ -25,6 +25,7 @@
25
25
  CSS.PADDING.Y.HALF,
26
26
  CSS.FONT.ROLE.LABEL_2,
27
27
  ]"
28
+ type="button"
28
29
  >
29
30
  <span>{{ props.label }}</span>
30
31
 
@@ -1,5 +1,5 @@
1
1
  <script lang="ts" setup>
2
- import { defineAsyncComponent, markRaw, ref, watch } from 'vue';
2
+ import { markRaw, ref, watch } from 'vue';
3
3
 
4
4
  import { REALM } from '@/types/Realm';
5
5
  import { SIZE } from '@/types/Size';
@@ -28,22 +28,21 @@
28
28
  const name = formatPascalCase(id);
29
29
  const [prefix] = id.split('-');
30
30
  const realmFolder = REALM[prefix?.toUpperCase() as keyof typeof REALM];
31
- const component = defineAsyncComponent(() => {
32
- if (realmFolder) {
33
- return import(`../assets/svg/icons/realm/${realmFolder}/Icon${name}.svg?component`);
34
- }
35
31
 
36
- return import(`../assets/svg/icons/Icon${name}.svg?component`);
37
- });
32
+ const loader = realmFolder
33
+ ? () => import(`../assets/svg/icons/realm/${realmFolder}/Icon${name}.svg?component`)
34
+ : () => import(`../assets/svg/icons/Icon${name}.svg?component`);
38
35
 
39
- innerSVG.value = markRaw(component);
36
+ const mod = await loader();
37
+
38
+ innerSVG.value = markRaw(mod.default);
40
39
  },
41
40
  { immediate: true }
42
41
  );
43
42
  </script>
44
43
 
45
44
  <template>
46
- <div :class="['tide-icon', props.size]">
45
+ <div :class="['tide-icon', props.size, CSS.FLEX.SHRINK.OFF]">
47
46
  <Component
48
47
  :class="[CSS.DISPLAY.BLOCK]"
49
48
  :data-icon="icon"
@@ -61,14 +61,6 @@
61
61
  <picture
62
62
  :class="['tide-image', CSS.DISPLAY.BLOCK]"
63
63
  ref="picture"
64
- :style="
65
- width || height
66
- ? {
67
- width: width || undefined,
68
- height: height || undefined,
69
- }
70
- : undefined
71
- "
72
64
  >
73
65
  <source
74
66
  :key="source.srcset"
@@ -79,11 +71,19 @@
79
71
 
80
72
  <img
81
73
  :alt="alt"
82
- :class="['tide-image-img', CSS.WIDTH.FULL, CSS.HEIGHT.FULL, CSS.OBJECT.CENTER, objectFitClassName]"
74
+ :class="[
75
+ 'tide-image-img',
76
+ !props.width && CSS.WIDTH.FULL,
77
+ !props.height && CSS.HEIGHT.FULL,
78
+ CSS.OBJECT.CENTER,
79
+ objectFitClassName,
80
+ ]"
83
81
  :fetchpriority="isLazy ? undefined : 'high'"
82
+ :height="props.height"
84
83
  :loading="props.isLazy ? 'lazy' : 'eager'"
85
84
  ref="img"
86
85
  :src="src ?? imageDefault"
86
+ :width="props.width"
87
87
  @error="setImageFromDefault"
88
88
  />
89
89
  </picture>
@@ -107,7 +107,6 @@
107
107
  showError ? CSS.FONT.COLOR.GLOBAL.ERROR : CSS.FONT.COLOR.SURFACE.DEFAULT,
108
108
  disabled ? [CSS.OPACITY.DISABLED, CSS.CURSOR.NOT_ALLOWED] : [CSS.CURSOR.POINTER],
109
109
  ]"
110
- :for="inputId"
111
110
  >
112
111
  <input
113
112
  :checked="isChecked"
@@ -253,6 +253,7 @@
253
253
 
254
254
  <button
255
255
  @click="handleClear"
256
+ type="button"
256
257
  v-if="shouldShowClearButton"
257
258
  >
258
259
  <TideIcon
@@ -264,6 +265,7 @@
264
265
 
265
266
  <button
266
267
  @click="showPassword = !showPassword"
268
+ type="button"
267
269
  v-if="shouldShowPasswordButton"
268
270
  >
269
271
  <TideIcon
@@ -234,6 +234,7 @@
234
234
 
235
235
  <button
236
236
  @click="handleClear"
237
+ type="button"
237
238
  v-if="hasClear && type !== TEXT_INPUT_TYPE.PASSWORD"
238
239
  >
239
240
  <TideIcon
@@ -245,6 +246,7 @@
245
246
 
246
247
  <button
247
248
  @click="showPassword = !showPassword"
249
+ type="button"
248
250
  v-if="type === TEXT_INPUT_TYPE.PASSWORD"
249
251
  >
250
252
  <TideIcon
@@ -119,7 +119,6 @@
119
119
  CSS.GAP.HALF,
120
120
  CSS.POSITION.RELATIVE,
121
121
  CSS.BORDER.RADIUS.HALF,
122
- CSS.PADDING.LEFT.ONE,
123
122
  CSS.PADDING.TOP.HALF,
124
123
  CSS.OVERFLOW.XY.HIDDEN,
125
124
  CSS.BG.SURFACE.DEFAULT,
@@ -132,6 +131,7 @@
132
131
  <div
133
132
  :class="[
134
133
  'tide-input-textarea-label',
134
+ CSS.PADDING.X.ONE,
135
135
  hasMinilabel ? ['minilabel', CSS.FONT.ROLE.LABEL_3] : CSS.FONT.ROLE.LABEL_1,
136
136
  !showError && CSS.FONT.COLOR.SURFACE.VARIANT,
137
137
  CSS.POINTER_EVENTS.OFF,
@@ -142,7 +142,7 @@
142
142
  </div>
143
143
 
144
144
  <textarea
145
- :class="[CSS.DISPLAY.BLOCK, CSS.WIDTH.FULL, CSS.FONT.ROLE.BODY_1]"
145
+ :class="[CSS.DISPLAY.BLOCK, CSS.FONT.ROLE.BODY_1, CSS.PADDING.X.ONE, CSS.WIDTH.FULL]"
146
146
  :maxlength="maxlength"
147
147
  :minlength="minlength"
148
148
  :name="name"
@@ -1,4 +1,7 @@
1
1
  <script lang="ts" setup>
2
+ import { computed } from 'vue';
3
+
4
+ import InternalBaseLink from '@/components/InternalBaseLink.vue';
2
5
  import TideIcon from '@/components/TideIcon.vue';
3
6
  import { ELEMENT } from '@/types/Element';
4
7
  import { CSS } from '@/types/Styles';
@@ -26,6 +29,8 @@
26
29
  label: undefined,
27
30
  subtle: false,
28
31
  });
32
+
33
+ const rootElement = computed(() => (props.element === ELEMENT.LINK ? InternalBaseLink : props.element));
29
34
  </script>
30
35
 
31
36
  <template>
@@ -38,7 +43,8 @@
38
43
  ]"
39
44
  :href="props.href"
40
45
  :target="props.isNewTab ? TARGET.BLANK : TARGET.SELF"
41
- :is="props.element === ELEMENT.LINK ? ELEMENT.LINK : ELEMENT.BUTTON"
46
+ :type="element === ELEMENT.BUTTON ? ELEMENT.BUTTON : undefined"
47
+ :is="rootElement"
42
48
  >
43
49
  <TideIcon
44
50
  :class="[CSS.DISPLAY.INLINE_BLOCK, CSS.ALIGN.Y.MIDDLE, CSS.MARGIN.RIGHT.QUARTER]"