@bethinkpl/design-system 43.0.0 → 45.0.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 (97) hide show
  1. package/dist/design-system.css +1 -1
  2. package/dist/design-system.js +13826 -13252
  3. package/dist/design-system.js.map +1 -1
  4. package/dist/lib/js/components/Buttons/IconButton/IconButton.vue.d.ts +1 -1
  5. package/dist/lib/js/components/Callout/Callout.consts.d.ts +32 -0
  6. package/dist/lib/js/components/{ActionContent/ActionContent.vue.d.ts → Callout/Callout.vue.d.ts} +17 -6
  7. package/dist/lib/js/components/Callout/index.d.ts +4 -0
  8. package/dist/lib/js/components/DatePickers/DateBox/DateBox.vue.d.ts +1 -1
  9. package/dist/lib/js/components/DatePickers/DatePicker/DatePicker.vue.d.ts +5 -5
  10. package/dist/lib/js/components/DatePickers/DateRangePicker/DateRangePicker.vue.d.ts +2 -2
  11. package/dist/lib/js/components/Divider/Divider.vue.d.ts +1 -1
  12. package/dist/lib/js/components/Drawer/DrawerDivider/DrawerDivider.vue.d.ts +1 -1
  13. package/dist/lib/js/components/Drawer/DrawerSection/DrawerSection.vue.d.ts +4 -4
  14. package/dist/lib/js/components/Drawer/DrawerTile/DrawerTile.vue.d.ts +4 -4
  15. package/dist/lib/js/components/Dropdown/Dropdown.vue.d.ts +1 -1
  16. package/dist/lib/js/components/Form/FormField/FormField.utils.d.ts +1 -1
  17. package/dist/lib/js/components/Form/InputField/InputField.vue.d.ts +2 -2
  18. package/dist/lib/js/components/Form/PasswordField/PasswordField.vue.d.ts +2 -2
  19. package/dist/lib/js/components/Form/PinInputField/PinInputField.consts.d.ts +14 -0
  20. package/dist/lib/js/components/Form/PinInputField/PinInputField.types.d.ts +12 -0
  21. package/dist/lib/js/components/Form/PinInputField/PinInputField.utils.d.ts +2 -0
  22. package/dist/lib/js/components/Form/PinInputField/PinInputField.vue.d.ts +91 -0
  23. package/dist/lib/js/components/Form/PinInputField/index.d.ts +5 -0
  24. package/dist/lib/js/components/Form/PinInputField/usePinInputFieldWithinForm.d.ts +8 -0
  25. package/dist/lib/js/components/Form/SelectField/SelectField.vue.d.ts +2 -2
  26. package/dist/lib/js/components/Form/TextAreaField/TextAreaField.types.d.ts +9 -0
  27. package/dist/lib/js/components/Form/TextAreaField/TextAreaField.vue.d.ts +76 -0
  28. package/dist/lib/js/components/Form/TextAreaField/TextAreaFieldAutosized.vue.d.ts +6 -0
  29. package/dist/lib/js/components/Form/TextAreaField/index.d.ts +4 -0
  30. package/dist/lib/js/components/Headers/OverlayHeader/OverlayHeader.vue.d.ts +5 -5
  31. package/dist/lib/js/components/Headers/PageHeader/PageHeader.vue.d.ts +1 -1
  32. package/dist/lib/js/components/Headers/SectionHeader/SectionHeader.vue.d.ts +3 -3
  33. package/dist/lib/js/components/IconText/IconText.vue.d.ts +1 -1
  34. package/dist/lib/js/components/Image/Image.vue.d.ts +1 -1
  35. package/dist/lib/js/components/LabelValue/LabelValueItem/LabelValueItem.vue.d.ts +12 -1
  36. package/dist/lib/js/components/Menu/MenuDivider/MenuDivider.vue.d.ts +1 -1
  37. package/dist/lib/js/components/Modals/Modal/Modal.vue.d.ts +2 -2
  38. package/dist/lib/js/components/Modals/ModalDialog/ModalDialog.vue.d.ts +2 -2
  39. package/dist/lib/js/components/Pagination/Pagination.vue.d.ts +2 -2
  40. package/dist/lib/js/components/RichList/BasicRichListItem/BasicRichListItem.vue.d.ts +7 -7
  41. package/dist/lib/js/components/RichList/RichListItem/RichListItem.vue.d.ts +3 -3
  42. package/dist/lib/js/components/SelectList/SelectListItemDivider/SelectListItemDivider.vue.d.ts +1 -1
  43. package/dist/lib/js/components/Skeleton/Skeleton.vue.d.ts +1 -1
  44. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionOpenEnded/SurveyQuestionOpenEnded.vue.d.ts +3 -3
  45. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionScale/SurveyQuestionScale.vue.d.ts +3 -3
  46. package/dist/lib/js/components/Tile/Tile.sb.shared.d.ts +2 -2
  47. package/dist/lib/js/components/Tile/Tile.vue.d.ts +2 -2
  48. package/dist/lib/js/components/Toast/Toast.consts.d.ts +11 -9
  49. package/dist/lib/js/components/Toast/Toast.vue.d.ts +51 -433
  50. package/dist/lib/js/components/Toggles/ToggleButton/ToggleButton.vue.d.ts +1 -1
  51. package/dist/lib/js/{components/Form/InputField/useInputFieldWithinForm.d.ts → composables/useTextFieldWithinForm.d.ts} +1 -1
  52. package/dist/lib/js/index.d.ts +6 -1
  53. package/lib/js/components/Callout/Callout.consts.ts +25 -0
  54. package/lib/js/components/Callout/Callout.spec.ts +257 -0
  55. package/lib/js/components/Callout/Callout.stories.ts +209 -0
  56. package/lib/js/components/Callout/Callout.vue +161 -0
  57. package/lib/js/components/Callout/index.ts +4 -0
  58. package/lib/js/components/Cards/Card/Card.vue +1 -1
  59. package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.spec.ts +15 -0
  60. package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.vue +5 -2
  61. package/lib/js/components/Form/Form.stories.ts +23 -2
  62. package/lib/js/components/Form/InputField/InputField.spec.ts +11 -1
  63. package/lib/js/components/Form/InputField/InputField.vue +7 -4
  64. package/lib/js/components/Form/PasswordField/PasswordField.vue +1 -1
  65. package/lib/js/components/Form/PinInputField/PinInputField.consts.ts +18 -0
  66. package/lib/js/components/Form/PinInputField/PinInputField.spec.ts +394 -0
  67. package/lib/js/components/Form/PinInputField/PinInputField.stories.ts +124 -0
  68. package/lib/js/components/Form/PinInputField/PinInputField.types.ts +42 -0
  69. package/lib/js/components/Form/PinInputField/PinInputField.utils.ts +5 -0
  70. package/lib/js/components/Form/PinInputField/PinInputField.vue +211 -0
  71. package/lib/js/components/Form/PinInputField/index.ts +6 -0
  72. package/lib/js/components/Form/PinInputField/usePinInputFieldWithinForm.ts +29 -0
  73. package/lib/js/components/Form/SelectField/SelectField.stories.ts +0 -5
  74. package/lib/js/components/Form/SelectField/useSelectFieldWithinForm.ts +1 -1
  75. package/lib/js/components/Form/TextAreaField/TextAreaField.spec.ts +341 -0
  76. package/lib/js/components/Form/TextAreaField/TextAreaField.stories.ts +99 -0
  77. package/lib/js/components/Form/TextAreaField/TextAreaField.types.ts +23 -0
  78. package/lib/js/components/Form/TextAreaField/TextAreaField.vue +190 -0
  79. package/lib/js/components/Form/TextAreaField/TextAreaFieldAutosized.vue +19 -0
  80. package/lib/js/components/Form/TextAreaField/index.ts +5 -0
  81. package/lib/js/components/LabelValue/LabelValueItem/LabelValueItem.spec.ts +26 -0
  82. package/lib/js/components/LabelValue/LabelValueItem/LabelValueItem.stories.ts +16 -3
  83. package/lib/js/components/LabelValue/LabelValueItem/LabelValueItem.vue +5 -0
  84. package/lib/js/components/LoadingBar/LoadingBar.spec.ts +84 -0
  85. package/lib/js/components/LoadingBar/LoadingBar.vue +30 -19
  86. package/lib/js/components/Toast/Toast.consts.ts +4 -2
  87. package/lib/js/components/Toast/Toast.spec.ts +177 -0
  88. package/lib/js/components/Toast/Toast.stories.ts +65 -31
  89. package/lib/js/components/Toast/Toast.vue +176 -195
  90. package/lib/js/{components/Form/InputField/useInputFieldWithinForm.ts → composables/useTextFieldWithinForm.ts} +7 -2
  91. package/lib/js/index.ts +6 -1
  92. package/package.json +1 -1
  93. package/dist/lib/js/components/ActionContent/index.d.ts +0 -3
  94. package/lib/js/components/ActionContent/ActionContent.spec.ts +0 -99
  95. package/lib/js/components/ActionContent/ActionContent.stories.ts +0 -141
  96. package/lib/js/components/ActionContent/ActionContent.vue +0 -104
  97. package/lib/js/components/ActionContent/index.ts +0 -3
@@ -1,9 +1,14 @@
1
1
  <template>
2
- <div :style="styles" :class="['ds-toast', toastSize, toastPosition]">
2
+ <div
3
+ :class="['ds-toast', toastSize, toastPosition, toastColor, { '-ds-closable': isClosable }]"
4
+ >
3
5
  <ds-card :loading-bar-color="color" has-loading-bar :loading-bar-time="disappearingTimeout">
4
6
  <template #content>
5
- <div class="ds-toast__content">
6
- <slot name="content" />
7
+ <div class="ds-toast__body">
8
+ <div v-if="title" class="ds-toast__title">{{ title }}</div>
9
+ <div class="ds-toast__content">
10
+ <slot name="content" />
11
+ </div>
7
12
  </div>
8
13
  </template>
9
14
  <template
@@ -14,6 +19,7 @@
14
19
  <ds-button
15
20
  v-if="footerSecondaryButtonText.length"
16
21
  :color="buttonSecondaryColor"
22
+ :size="buttonSize"
17
23
  :icon-right="footerSecondaryButtonIcon"
18
24
  :type="BUTTON_TYPES.OUTLINED"
19
25
  :radius="BUTTON_RADIUSES.ROUNDED"
@@ -23,6 +29,7 @@
23
29
  <ds-button
24
30
  v-if="footerPrimaryButtonText.length"
25
31
  :color="buttonPrimaryColor"
32
+ :size="buttonSize"
26
33
  :icon-right="footerPrimaryButtonIcon"
27
34
  :radius="BUTTON_RADIUSES.ROUNDED"
28
35
  @click="$emit('primary-button-click')"
@@ -31,49 +38,113 @@
31
38
  </div>
32
39
  </template>
33
40
  </ds-card>
41
+ <div v-if="isClosable" class="ds-toast__close">
42
+ <ds-icon-button
43
+ :icon="ICONS.FA_XMARK"
44
+ :size="ICON_BUTTON_SIZES.SMALL"
45
+ :color="ICON_BUTTON_COLORS.NEUTRAL_WEAK"
46
+ @click="close"
47
+ />
48
+ </div>
34
49
  </div>
35
50
  </template>
36
51
 
37
52
  <style scoped lang="scss">
53
+ @import '../../../styles/settings/colors/tokens';
38
54
  @import '../../../styles/settings/spacings';
39
55
  @import '../../../styles/settings/typography/tokens';
40
56
  @import '../../../styles/settings/media-queries';
41
57
 
42
58
  .ds-toast {
43
- position: fixed;
59
+ $root: &;
60
+
61
+ max-width: var(--ds-toast-max-width);
62
+ // anchors the absolutely positioned close button, including under `position: none`
63
+ position: relative;
44
64
  width: 100%;
45
65
 
46
66
  &.-ds-size-small {
47
- max-width: 320px + $space-8 * 2;
48
- padding: $space-8;
67
+ --ds-toast-max-width: 320px;
49
68
  }
50
69
 
51
70
  &.-ds-size-medium {
52
- max-width: 500px + $space-8 * 2;
53
- padding: $space-8;
71
+ --ds-toast-max-width: 500px;
72
+ }
73
+
74
+ &.-ds-size-large {
75
+ --ds-toast-max-width: 700px;
76
+ }
77
+
78
+ // The viewport spacing lives in the offsets rather than in padding, so it applies only to the
79
+ // fixed positions — `none` lets the consumer place (and space) the toast themselves.
80
+ &.-ds-position-left,
81
+ &.-ds-position-center,
82
+ &.-ds-position-right {
83
+ --ds-toast-offset: #{$space-8};
84
+
85
+ bottom: var(--ds-toast-offset);
86
+ max-width: min(var(--ds-toast-max-width), calc(100% - var(--ds-toast-offset) * 2));
87
+ position: fixed;
54
88
 
55
89
  @media (#{breakpoint-s()}) {
56
- max-width: 500px + $space-12 * 2;
57
- padding: $space-12;
90
+ &.-ds-size-medium,
91
+ &.-ds-size-large {
92
+ --ds-toast-offset: #{$space-12};
93
+ }
58
94
  }
59
95
  }
60
96
 
61
97
  &.-ds-position-left {
62
- bottom: 0;
63
- left: 0;
98
+ left: var(--ds-toast-offset);
64
99
  }
65
100
 
66
101
  &.-ds-position-right {
67
- bottom: 0;
68
- right: 0;
102
+ right: var(--ds-toast-offset);
69
103
  }
70
104
 
71
105
  &.-ds-position-center {
72
- bottom: 0;
73
106
  left: 50%;
74
107
  transform: translateX(-50%);
75
108
  }
76
109
 
110
+ &__body {
111
+ display: flex;
112
+ flex-direction: column;
113
+ row-gap: $space-2;
114
+ }
115
+
116
+ &__close {
117
+ position: absolute;
118
+ right: $space-1;
119
+ top: $space-3;
120
+ }
121
+
122
+ &__title {
123
+ @include heading-s-default-bold;
124
+
125
+ color: $color-neutral-text-strong;
126
+
127
+ #{$root}.-ds-size-large & {
128
+ @include heading-m-default-bold;
129
+ }
130
+
131
+ #{$root}.-ds-color-success & {
132
+ color: $color-success-text-strong;
133
+ }
134
+
135
+ #{$root}.-ds-color-warning & {
136
+ color: $color-warning-text-strong;
137
+ }
138
+
139
+ #{$root}.-ds-color-danger & {
140
+ color: $color-danger-text-strong;
141
+ }
142
+
143
+ #{$root}.-ds-color-info & {
144
+ color: $color-info-text-strong;
145
+ }
146
+ }
147
+
77
148
  &__content {
78
149
  @include text-m-default-regular;
79
150
  }
@@ -87,9 +158,15 @@
87
158
  }
88
159
  </style>
89
160
 
90
- <script lang="ts">
91
- import DsButton, { BUTTON_COLORS, BUTTON_RADIUSES, BUTTON_TYPES } from '../Buttons/Button';
161
+ <script lang="ts" setup>
162
+ import DsButton, {
163
+ BUTTON_COLORS,
164
+ BUTTON_RADIUSES,
165
+ BUTTON_SIZES,
166
+ BUTTON_TYPES,
167
+ } from '../Buttons/Button';
92
168
  import DsCard from '../Cards/Card';
169
+ import DsIconButton, { ICON_BUTTON_COLORS, ICON_BUTTON_SIZES } from '../Buttons/IconButton';
93
170
  import {
94
171
  TOAST_COLORS,
95
172
  TOAST_POSITIONS,
@@ -98,184 +175,88 @@ import {
98
175
  ToastPositions,
99
176
  ToastSizes,
100
177
  } from './Toast.consts';
101
- import { defineComponent, PropType, toRaw } from 'vue';
102
- import { ICONS } from '../Icons/Icon';
103
-
104
- function calculateBoundariesOffset(boundariesElement: HTMLElement) {
105
- const borderLeftWidth = window.getComputedStyle(boundariesElement).borderLeftWidth;
106
- const borderRightWidth = window.getComputedStyle(boundariesElement).borderRightWidth;
107
- const boundingClientRect = boundariesElement.getBoundingClientRect();
108
- const boundariesOffsetLeft = boundingClientRect.left + parseInt(borderLeftWidth, 10);
109
- const boundariesOffsetRight =
110
- boundingClientRect.right - parseInt(borderRightWidth, 10) - parseInt(borderLeftWidth, 10);
111
- const boundariesOffsetWidth = boundingClientRect.width;
112
- return {
113
- left: {
114
- left: `${boundariesOffsetLeft}px`,
115
- },
116
- right: {
117
- left: `${boundariesOffsetRight}px`,
118
- transform: 'translateX(-100%)',
119
- },
120
- center: {
121
- left: `${boundariesOffsetLeft + boundariesOffsetWidth / 2}px`,
122
- transform: 'translateX(-50%)',
123
- },
124
- };
125
- }
178
+ import { computed, onMounted, onUnmounted } from 'vue';
179
+ import { ICONS, IconItem } from '../Icons/Icon';
126
180
 
127
- export default defineComponent({
128
- name: 'Toast',
129
- components: {
130
- DsButton,
131
- DsCard,
132
- },
133
- props: {
134
- size: {
135
- type: String as PropType<ToastSizes>,
136
- default: TOAST_SIZES.MEDIUM,
137
- },
138
- position: {
139
- type: String as PropType<ToastPositions>,
140
- default: TOAST_POSITIONS.CENTER,
141
- },
142
- boundariesSelector: {
143
- type: [String, Object] as PropType<string | HTMLElement>,
144
- default: null,
145
- },
146
- color: {
147
- type: String as PropType<ToastColors>,
148
- default: TOAST_COLORS.INFO,
149
- },
150
- footerPrimaryButtonText: {
151
- type: String,
152
- default: '',
153
- },
154
- footerPrimaryButtonIcon: {
155
- type: Object,
156
- default: null,
157
- validator(footerPrimaryButtonIcon: any) {
158
- return (
159
- footerPrimaryButtonIcon == null ||
160
- Object.values(ICONS).includes(toRaw(footerPrimaryButtonIcon))
161
- );
162
- },
163
- },
164
- footerSecondaryButtonText: {
165
- type: String,
166
- default: '',
167
- },
168
- footerSecondaryButtonIcon: {
169
- type: Object,
170
- default: null,
171
- validator(footerSecondaryButtonIcon: any) {
172
- return (
173
- footerSecondaryButtonIcon == null ||
174
- Object.values(ICONS).includes(toRaw(footerSecondaryButtonIcon))
175
- );
176
- },
177
- },
178
- isDisappearing: {
179
- type: Boolean,
180
- default: true,
181
- },
182
- disappearingTimeout: {
183
- type: String,
184
- default: '0',
185
- validator(disappearingTimeout: string) {
186
- return (
187
- (disappearingTimeout === '0' || !isNaN(parseInt(disappearingTimeout, 10))) &&
188
- parseInt(disappearingTimeout, 10) >= 0
189
- );
190
- },
191
- },
192
- },
193
- emits: {
194
- close: () => true,
195
- 'primary-button-click': () => true,
196
- 'secondary-button-click': () => true,
197
- },
198
- data() {
199
- return {
200
- boundariesSelectorElement: null,
201
- boundariesSelectorElementResizeObserver: null,
202
- styles: {},
203
- BUTTON_COLORS: Object.freeze(BUTTON_COLORS),
204
- BUTTON_RADIUSES: Object.freeze(BUTTON_RADIUSES),
205
- BUTTON_TYPES: Object.freeze(BUTTON_TYPES),
206
- TOAST_SIZES: Object.freeze(TOAST_SIZES),
207
- TOAST_POSITIONS: Object.freeze(TOAST_POSITIONS),
208
- };
209
- },
210
- computed: {
211
- buttonPrimaryColor() {
212
- return this.color === TOAST_COLORS.DANGER
213
- ? BUTTON_COLORS.NEUTRAL
214
- : BUTTON_COLORS.PRIMARY;
215
- },
216
- buttonSecondaryColor() {
217
- return this.color === TOAST_COLORS.DANGER
218
- ? BUTTON_COLORS.DANGER
219
- : BUTTON_COLORS.NEUTRAL;
220
- },
221
- toastPosition() {
222
- return `-ds-position-${this.position.toLowerCase()}`;
223
- },
224
- toastSize() {
225
- return `-ds-size-${this.size.toLowerCase()}`;
226
- },
227
- },
228
- mounted() {
229
- this.setBoundariesSelectorElement();
230
- this.calculateStyles();
231
- this.boundariesSelectorElementResizeObserver?.disconnect();
232
- this.boundariesSelectorElementResizeObserver = new ResizeObserver(() => {
233
- this.calculateStyles();
234
- });
235
- if (this.boundariesSelectorElement) {
236
- this.boundariesSelectorElementResizeObserver.observe(this.boundariesSelectorElement);
237
- } else {
238
- //window resize does not work for some reason, so we observe body
239
- this.boundariesSelectorElementResizeObserver.observe(document.querySelector('body'));
240
- }
241
- if (this.isDisappearing && this.disappearingTimeout !== '0') {
242
- setTimeout(
243
- () => this.$emit('close'),
244
- parseInt(this.disappearingTimeout, 10) * 1000 + 100, // 100 ms is to let loading bar animation to finish
245
- );
246
- }
247
- },
248
- beforeUnmount() {
249
- this.boundariesSelectorElementResizeObserver.disconnect();
250
- this.boundariesSelectorElementResizeObserver = null;
251
- },
252
- updated() {
253
- const { right, left } = this.$el.getClientRects()[0];
254
- if (parseInt(left, 10) < 0 || right > document.documentElement.clientWidth) {
255
- this.styles = {
256
- left: '50%',
257
- transform: 'translateX(-50%)',
258
- };
259
- }
260
- },
261
- methods: {
262
- calculateStyles() {
263
- if (this.boundariesSelectorElement) {
264
- this.styles = calculateBoundariesOffset(this.boundariesSelectorElement)[
265
- this.position
266
- ];
267
- } else {
268
- this.styles = {};
269
- }
270
- },
271
- setBoundariesSelectorElement() {
272
- if (typeof this.boundariesSelector === 'string') {
273
- this.boundariesSelectorElement =
274
- document.querySelector(this.boundariesSelector) || null;
275
- } else if (this.boundariesSelector instanceof HTMLElement) {
276
- this.boundariesSelectorElement = this.boundariesSelector;
277
- }
278
- },
279
- },
181
+ const {
182
+ title = '',
183
+ size = TOAST_SIZES.MEDIUM,
184
+ position = TOAST_POSITIONS.CENTER,
185
+ color = TOAST_COLORS.INFO,
186
+ footerPrimaryButtonText = '',
187
+ footerPrimaryButtonIcon = null,
188
+ footerSecondaryButtonText = '',
189
+ footerSecondaryButtonIcon = null,
190
+ isDisappearing = true,
191
+ disappearingTimeout = '0',
192
+ isClosable = false,
193
+ } = defineProps<{
194
+ title?: string;
195
+ size?: ToastSizes;
196
+ position?: ToastPositions;
197
+ color?: ToastColors;
198
+ footerPrimaryButtonText?: string;
199
+ footerPrimaryButtonIcon?: IconItem | null;
200
+ footerSecondaryButtonText?: string;
201
+ footerSecondaryButtonIcon?: IconItem | null;
202
+ isDisappearing?: boolean;
203
+ /** Seconds, as a numeric string. `'0'` disables the auto-close. */
204
+ disappearingTimeout?: string;
205
+ isClosable?: boolean;
206
+ }>();
207
+
208
+ const emit = defineEmits<{
209
+ close: [];
210
+ 'primary-button-click': [];
211
+ 'secondary-button-click': [];
212
+ }>();
213
+
214
+ defineSlots<{
215
+ content?: () => any;
216
+ }>();
217
+
218
+ const buttonPrimaryColor = computed(() =>
219
+ color === TOAST_COLORS.DANGER ? BUTTON_COLORS.NEUTRAL : BUTTON_COLORS.PRIMARY,
220
+ );
221
+
222
+ const buttonSecondaryColor = computed(() =>
223
+ color === TOAST_COLORS.DANGER ? BUTTON_COLORS.DANGER : BUTTON_COLORS.NEUTRAL,
224
+ );
225
+
226
+ const buttonSize = computed(() =>
227
+ size === TOAST_SIZES.SMALL ? BUTTON_SIZES.SMALL : BUTTON_SIZES.MEDIUM,
228
+ );
229
+
230
+ const toastSize = computed(() => `-ds-size-${size.toLowerCase()}`);
231
+
232
+ const toastPosition = computed(() => `-ds-position-${position.toLowerCase()}`);
233
+
234
+ const toastColor = computed(() => `-ds-color-${color}`);
235
+
236
+ let disappearingTimeoutId: ReturnType<typeof setTimeout> | null = null;
237
+
238
+ const clearDisappearingTimeout = () => {
239
+ if (disappearingTimeoutId !== null) {
240
+ clearTimeout(disappearingTimeoutId);
241
+ disappearingTimeoutId = null;
242
+ }
243
+ };
244
+
245
+ // `close` is emitted at most once per toast — dismissing it by hand cancels the pending auto-close
246
+ // so consumers driving a queue (or analytics) off the event never see it twice.
247
+ const close = () => {
248
+ clearDisappearingTimeout();
249
+ emit('close');
250
+ };
251
+
252
+ onMounted(() => {
253
+ if (isDisappearing && disappearingTimeout !== '0') {
254
+ disappearingTimeoutId = setTimeout(
255
+ close,
256
+ parseInt(disappearingTimeout, 10) * 1000 + 100, // 100 ms is to let loading bar animation to finish
257
+ );
258
+ }
280
259
  });
260
+
261
+ onUnmounted(clearDisappearingTimeout);
281
262
  </script>
@@ -1,7 +1,12 @@
1
1
  import { MaybeRefOrGetter, ref, Ref } from 'vue';
2
- import { useFormFieldWithinForm } from '../../../composables/useFormFieldWithinForm';
2
+ import { useFormFieldWithinForm } from './useFormFieldWithinForm';
3
3
 
4
- export function useInputFieldWithinForm(
4
+ /**
5
+ * vee-validate bridge shared by the free-text fields (`InputField`, `TextAreaField`). Validation on
6
+ * `input` only starts once the field has been blurred, so a half-typed value is never marked
7
+ * invalid while the user is still filling it in.
8
+ */
9
+ export function useTextFieldWithinForm(
5
10
  name: MaybeRefOrGetter<string | undefined>,
6
11
  modelValue: Ref<string | undefined>,
7
12
  ) {
package/lib/js/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { default as DsActionContent } from './components/ActionContent';
2
1
  export { default as Avatar } from './components/Avatar';
3
2
  export * from './components/Avatar/Avatar.consts';
4
3
  export { default as Badge } from './components/Badge';
@@ -15,6 +14,8 @@ export * from './components/Buttons/Button/Button.consts';
15
14
  export { default as ToggleButton } from './components/Toggles/ToggleButton';
16
15
  export { default as DsToggleButton } from './components/Toggles/ToggleButton';
17
16
  export * from './components/Toggles/ToggleButton/ToggleButton.consts';
17
+ export { default as DsCallout } from './components/Callout';
18
+ export * from './components/Callout/Callout.consts';
18
19
  export { default as Card } from './components/Cards/Card/';
19
20
  export * from './components/Cards/Card';
20
21
  export { default as DsCard } from './components/Cards/Card';
@@ -53,11 +54,15 @@ export { default as NumberInCircle } from './components/NumberInCircle';
53
54
  export { default as DsNumberInCircle } from './components/NumberInCircle';
54
55
  export * from './components/NumberInCircle/NumberInCircle.consts';
55
56
  export { default as DsPasswordField } from './components/Form/PasswordField';
57
+ export { default as DsPinInputField } from './components/Form/PinInputField';
58
+ export * from './components/Form/PinInputField';
56
59
  export { default as DsSelectField } from './components/Form/SelectField';
57
60
  export * from './components/Form/SelectField';
58
61
  export { default as TabItem } from './components/TabItem';
59
62
  export { default as DsTabItem } from './components/TabItem';
60
63
  export * from './components/TabItem/TabItem.consts';
64
+ export { default as DsTextAreaField } from './components/Form/TextAreaField';
65
+ export * from './components/Form/TextAreaField';
61
66
  export { default as Tile } from './components/Tile';
62
67
  export { default as DsTile } from './components/Tile';
63
68
  export * from './components/Tile/Tile.consts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bethinkpl/design-system",
3
- "version": "43.0.0",
3
+ "version": "45.0.0",
4
4
  "description": "Bethink universe design-system",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +0,0 @@
1
- import { default as ActionContent } from './ActionContent.vue';
2
-
3
- export default ActionContent;
@@ -1,99 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { mount } from '@vue/test-utils';
3
- import { h } from 'vue';
4
- import ActionContent from './ActionContent.vue';
5
- import DsFeatureIcon from '../Icons/FeatureIcon';
6
- import DsButton from '../Buttons/Button';
7
- import { ICONS } from '../Icons/Icon';
8
-
9
- describe('ActionContent', () => {
10
- it('renders', () => {
11
- const wrapper = mount(ActionContent);
12
-
13
- expect(wrapper.exists()).toBe(true);
14
- });
15
-
16
- it('renders the feature icon when icon is provided', () => {
17
- const wrapper = mount(ActionContent, {
18
- props: {
19
- icon: ICONS.FA_COMMENT_DOTS,
20
- },
21
- });
22
-
23
- expect(wrapper.findComponent(DsFeatureIcon).exists()).toBe(true);
24
- });
25
-
26
- it('does not render the feature icon when icon is not provided', () => {
27
- const wrapper = mount(ActionContent);
28
-
29
- expect(wrapper.findComponent(DsFeatureIcon).exists()).toBe(false);
30
- });
31
-
32
- it('passes main and supporting text to the text group', () => {
33
- const wrapper = mount(ActionContent, {
34
- props: {
35
- mainText: 'Main text',
36
- supportingText: 'Supporting text',
37
- },
38
- });
39
-
40
- expect(wrapper.find('.ds-actionContent__text').text()).toContain('Main text');
41
- expect(wrapper.find('.ds-actionContent__text').text()).toContain('Supporting text');
42
- });
43
-
44
- it('renders a default primary button with the button label and icon', () => {
45
- const wrapper = mount(ActionContent, {
46
- props: {
47
- buttonLabel: 'Confirm',
48
- buttonIcon: ICONS.FA_COMMENT_DOTS,
49
- },
50
- });
51
-
52
- const button = wrapper.findComponent(DsButton);
53
- expect(button.exists()).toBe(true);
54
- expect(button.text()).toBe('Confirm');
55
- expect(button.props('iconLeft')).toStrictEqual(ICONS.FA_COMMENT_DOTS);
56
- });
57
-
58
- it('emits button-clicked when the default button is clicked', async () => {
59
- const wrapper = mount(ActionContent, {
60
- props: {
61
- buttonLabel: 'Confirm',
62
- },
63
- });
64
-
65
- await wrapper.findComponent(DsButton).trigger('click');
66
-
67
- expect(wrapper.emitted('button-clicked')).toHaveLength(1);
68
- });
69
-
70
- it('renders the actions slot instead of the default button', () => {
71
- const wrapper = mount(ActionContent, {
72
- props: {
73
- buttonLabel: 'Default button',
74
- },
75
- slots: {
76
- actions: () => h('span', { class: 'custom-action' }, 'Custom action'),
77
- },
78
- });
79
-
80
- expect(wrapper.find('.custom-action').exists()).toBe(true);
81
- expect(wrapper.findComponent(DsButton).exists()).toBe(false);
82
- });
83
-
84
- it('adds the vertical modifier when isActionVertical is set', () => {
85
- const wrapper = mount(ActionContent, {
86
- props: {
87
- isActionVertical: true,
88
- },
89
- });
90
-
91
- expect(wrapper.find('.ds-actionContent__actions').classes()).toContain('-ds-vertical');
92
- });
93
-
94
- it('does not add the vertical modifier by default', () => {
95
- const wrapper = mount(ActionContent);
96
-
97
- expect(wrapper.find('.ds-actionContent__actions').classes()).not.toContain('-ds-vertical');
98
- });
99
- });