@weni/unnnic-system 3.7.1-alpha.2 → 3.7.1-alpha.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weni/unnnic-system",
3
- "version": "3.7.1-alpha.2",
3
+ "version": "3.7.1-alpha.3",
4
4
  "type": "commonjs",
5
5
  "files": [
6
6
  "dist",
@@ -197,7 +197,6 @@ $icon-sizes:
197
197
  -webkit-font-feature-settings: 'liga';
198
198
  -webkit-font-smoothing: antialiased;
199
199
 
200
- cursor: default;
201
200
  user-select: none;
202
201
 
203
202
  &--filled {
@@ -6,6 +6,8 @@
6
6
  :message="message"
7
7
  :tooltip="tooltip"
8
8
  :error="computedError"
9
+ :class="['unnnic-form', size]"
10
+ data-testid="form-element"
9
11
  >
10
12
  <TextInput
11
13
  v-bind="$attrs"
@@ -40,29 +40,21 @@ describe('Input.vue', () => {
40
40
  expect(wrapper.exists()).toBe(true);
41
41
  });
42
42
 
43
- test('renders label correctly', async () => {
44
- const label = wrapper.find('.unnnic-form__label');
45
- expect(label.exists()).toBe(true);
46
- expect(label.text()).toBe('Sample Label');
47
-
48
- await wrapper.setProps({ label: null });
49
- expect(wrapper.find('.unnnic-form__label').exists()).toBe(false);
50
- });
51
-
52
- test('renders message correctly', async () => {
53
- const message = wrapper.find('.unnnic-form__message');
54
- expect(message.exists()).toBe(true);
55
- expect(message.text()).toBe('Error message');
56
-
57
- await wrapper.setProps({ message: null });
58
- expect(wrapper.find('.unnnic-form__message').exists()).toBe(false);
43
+ test('renders form element correctly', async () => {
44
+ const formElement = wrapper.findComponent('[data-testid="form-element"]');
45
+ expect(formElement.exists()).toBe(true);
46
+ expect(formElement.props('label')).toBe('Sample Label');
47
+ expect(formElement.props('size')).toBe('md');
48
+ expect(formElement.props('message')).toBe('Error message');
49
+ expect(formElement.props('disabled')).toBe(false);
50
+ expect(formElement.props('tooltip')).toBe('');
51
+ expect(formElement.props('error')).toBe(false);
59
52
  });
60
53
 
61
- test('applies the correct size class', async () => {
62
- expect(wrapper.classes()).toContain('md');
63
-
64
- await wrapper.setProps({ size: 'sm' });
65
- expect(wrapper.classes()).toContain('sm');
54
+ test('renders maxlength counter correctly', async () => {
55
+ expect(wrapper.text()).not.toContain('0 / 10');
56
+ await wrapper.setProps({ maxlength: 10, showMaxlengthCounter: true });
57
+ expect(wrapper.text()).toContain('0 / 10');
66
58
  });
67
59
 
68
60
  test('renders TextInput component', () => {
@@ -96,18 +88,6 @@ describe('Input.vue', () => {
96
88
  expect(wrapper.vm.val).toBe('new value');
97
89
  });
98
90
 
99
- test('hasLabelSlot computed property works correctly', async () => {
100
- expect(wrapper.vm.hasLabelSlot).toBe(false);
101
-
102
- wrapper = mount(Input, {
103
- slots: {
104
- label: '<span>Custom Label</span>',
105
- },
106
- });
107
-
108
- expect(wrapper.vm.hasLabelSlot).toBe(true);
109
- });
110
-
111
91
  test('correctly mounts with initial modelValue', async () => {
112
92
  wrapper = mount(Input, {
113
93
  props: {
@@ -1,7 +1,7 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`Input.vue > matches the snapshot 1`] = `
4
- "<section data-v-9f8d6c86="" data-v-d890ad85="" class="unnnic-form-element">
4
+ "<section data-v-9f8d6c86="" data-v-d890ad85="" class="unnnic-form-element unnnic-form md" data-testid="form-element">
5
5
  <section data-v-7f222291="" data-v-9f8d6c86="" class="unnnic-label unnnic-form-element__label">
6
6
  <p data-v-7f222291="" class="unnnic-label__label">Sample Label</p>
7
7
  <!--v-if-->
@@ -98,6 +98,7 @@ import { toast } from './Toast/ToastManager';
98
98
  import Popover from './ui/popover/Popover.vue';
99
99
  import PopoverContent from './ui/popover/PopoverContent.vue';
100
100
  import PopoverTrigger from './ui/popover/PopoverTrigger.vue';
101
+ import PopoverFooter from './ui/popover/PopoverFooter.vue';
101
102
  import Dialog from './ui/dialog/Dialog.vue';
102
103
  import DialogContent from './ui/dialog/DialogContent.vue';
103
104
  import DialogFooter from './ui/dialog/DialogFooter.vue';
@@ -321,6 +322,7 @@ export const unnnicChip = Chip;
321
322
  export const unnnicPopover = Popover;
322
323
  export const unnnicPopoverContent = PopoverContent;
323
324
  export const unnnicPopoverTrigger = PopoverTrigger;
325
+ export const unnnicPopoverFooter = PopoverFooter;
324
326
  export const unnnicDialog = Dialog;
325
327
  export const unnnicDialogContent = DialogContent;
326
328
  export const unnnicDialogFooter = DialogFooter;
@@ -429,6 +431,7 @@ export const UnnnicToastManager = toast;
429
431
  export const UnnnicPopover = Popover;
430
432
  export const UnnnicPopoverContent = PopoverContent;
431
433
  export const UnnnicPopoverTrigger = PopoverTrigger;
434
+ export const UnnnicPopoverFooter = PopoverFooter;
432
435
  export const UnnnicDialog = Dialog;
433
436
  export const UnnnicDialogContent = DialogContent;
434
437
  export const UnnnicDialogFooter = DialogFooter;
@@ -11,22 +11,26 @@
11
11
  "
12
12
  >
13
13
  <section :class="`unnnic-popover__content ${props.class || ''}`">
14
- <slot />
14
+ <component
15
+ :is="child"
16
+ v-for="(child, index) in contentChildren"
17
+ :key="index"
18
+ />
15
19
  </section>
16
20
 
17
- <footer
18
- v-if="$slots.footer"
19
- class="unnnic-popover__footer"
20
- >
21
- <slot name="footer" />
22
- </footer>
21
+ <component
22
+ :is="child"
23
+ v-for="(child, index) in footerChildren"
24
+ :key="index"
25
+ />
23
26
  </PopoverContent>
24
27
  </PopoverPortal>
25
28
  </template>
26
29
 
27
30
  <script setup lang="ts">
28
31
  import type { PopoverContentEmits, PopoverContentProps } from 'reka-ui';
29
- import type { HTMLAttributes } from 'vue';
32
+ import type { HTMLAttributes, VNode } from 'vue';
33
+ import { computed, useSlots } from 'vue';
30
34
  import { reactiveOmit } from '@vueuse/core';
31
35
  import { PopoverContent, PopoverPortal, useForwardPropsEmits } from 'reka-ui';
32
36
  import { cn } from '@/lib/utils';
@@ -46,6 +50,7 @@ const props = withDefaults(
46
50
  align: 'center',
47
51
  sideOffset: 4,
48
52
  size: 'medium',
53
+ class: '',
49
54
  },
50
55
  );
51
56
  const emits = defineEmits<PopoverContentEmits>();
@@ -53,6 +58,27 @@ const emits = defineEmits<PopoverContentEmits>();
53
58
  const delegatedProps = reactiveOmit(props, 'class', 'size');
54
59
 
55
60
  const forwarded = useForwardPropsEmits(delegatedProps, emits);
61
+
62
+ const slots = useSlots();
63
+
64
+ const getComponentName = (vnode: VNode): string | undefined => {
65
+ const componentType = vnode.type as { name?: string; __name?: string };
66
+ return componentType?.name || componentType?.__name;
67
+ };
68
+
69
+ const contentChildren = computed(() => {
70
+ const defaultSlot = slots.default?.() || [];
71
+ return defaultSlot.filter(
72
+ (vnode: VNode) => getComponentName(vnode) !== 'UnnnicPopoverFooter',
73
+ );
74
+ });
75
+
76
+ const footerChildren = computed(() => {
77
+ const defaultSlot = slots.default?.() || [];
78
+ return defaultSlot.filter(
79
+ (vnode: VNode) => getComponentName(vnode) === 'UnnnicPopoverFooter',
80
+ );
81
+ });
56
82
  </script>
57
83
 
58
84
  <style lang="scss">
@@ -79,20 +105,5 @@ $popover-space: $unnnic-space-4;
79
105
  &__content {
80
106
  padding: $popover-space;
81
107
  }
82
-
83
- &__footer {
84
- border-top: 1px solid $unnnic-color-border-soft;
85
-
86
- padding: $popover-space;
87
-
88
- display: flex;
89
- justify-content: center;
90
- align-items: center;
91
- gap: $unnnic-space-2;
92
-
93
- > * {
94
- width: 100%;
95
- }
96
- }
97
108
  }
98
109
  </style>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <footer class="unnnic-popover__footer">
3
+ <slot />
4
+ </footer>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ defineOptions({
9
+ name: 'UnnnicPopoverFooter',
10
+ });
11
+ </script>
12
+
13
+ <style lang="scss">
14
+ @use '@/assets/scss/unnnic' as *;
15
+
16
+ $popover-space: $unnnic-space-4;
17
+
18
+ .unnnic-popover__footer {
19
+ border-top: 1px solid $unnnic-color-border-soft;
20
+
21
+ padding: $popover-space;
22
+
23
+ display: flex;
24
+ justify-content: center;
25
+ align-items: center;
26
+ gap: $unnnic-space-2;
27
+
28
+ > * {
29
+ width: 100%;
30
+ }
31
+ }
32
+ </style>
@@ -1,4 +1,5 @@
1
1
  export { default as Popover } from './Popover.vue';
2
2
  export { default as PopoverContent } from './PopoverContent.vue';
3
+ export { default as PopoverFooter } from './PopoverFooter.vue';
3
4
  export { default as PopoverTrigger } from './PopoverTrigger.vue';
4
5
  export { PopoverAnchor } from 'reka-ui';
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  Popover,
3
3
  PopoverContent,
4
+ PopoverFooter,
4
5
  PopoverTrigger,
5
6
  } from '../components/ui/popover';
6
7
  import UnnnicButton from '../components/Button/Button.vue';
@@ -16,7 +17,7 @@ export default {
16
17
  description: {
17
18
  component: `A popover component that displays rich content in a portal, floating on top of other content.
18
19
  <br/>
19
- It supports three sizes (small, medium, large) and optional footer slot for action buttons, for example.
20
+ It supports three sizes (small, medium, large).
20
21
  <br/>
21
22
  API reference: https://www.reka-ui.com/docs/components/popover
22
23
  `,
@@ -48,6 +49,25 @@ export default {
48
49
  };
49
50
 
50
51
  export const Default = {
52
+ parameters: {
53
+ docs: {
54
+ description: {
55
+ story: 'A simple popover with some content inside.',
56
+ },
57
+ source: {
58
+ code: `
59
+ <UnnnicPopover>
60
+ <UnnnicPopoverTrigger>
61
+ <UnnnicButton text="Open Popover" />
62
+ </UnnnicPopoverTrigger>
63
+ <UnnnicPopoverContent v-bind="args">
64
+ <p style="margin: 0;">This is a simple popover with some content inside.</p>
65
+ </UnnnicPopoverContent>
66
+ </UnnnicPopover>
67
+ `,
68
+ },
69
+ },
70
+ },
51
71
  render: (args) => ({
52
72
  components: { Popover, PopoverContent, PopoverTrigger, UnnnicButton },
53
73
  setup() {
@@ -73,12 +93,34 @@ export const WithFooter = {
73
93
  docs: {
74
94
  description: {
75
95
  story:
76
- 'Popover with action buttons in the footer using the `#footer` slot.',
96
+ 'Popover with action buttons in the footer using the `PopoverFooter` component.',
97
+ },
98
+ source: {
99
+ code: `
100
+ <UnnnicPopover>
101
+ <UnnnicPopoverTrigger>
102
+ <UnnnicButton text="Open Popover" />
103
+ </UnnnicPopoverTrigger>
104
+ <UnnnicPopoverContent v-bind="args">
105
+ <p style="margin: 0;">This popover has a footer with action buttons.</p>
106
+ <UnnnicPopoverFooter>
107
+ <UnnnicButton text="Cancel" type="tertiary" />
108
+ <UnnnicButton text="Save" type="primary" />
109
+ </UnnnicPopoverFooter>
110
+ </UnnnicPopoverContent>
111
+ </UnnnicPopover>
112
+ `,
77
113
  },
78
114
  },
79
115
  },
80
116
  render: (args) => ({
81
- components: { Popover, PopoverContent, PopoverTrigger, UnnnicButton },
117
+ components: {
118
+ Popover,
119
+ PopoverContent,
120
+ PopoverFooter,
121
+ PopoverTrigger,
122
+ UnnnicButton,
123
+ },
82
124
  setup() {
83
125
  return { args };
84
126
  },
@@ -90,10 +132,10 @@ export const WithFooter = {
90
132
  </PopoverTrigger>
91
133
  <PopoverContent v-bind="args">
92
134
  <p style="margin: 0;">This popover has a footer with action buttons.</p>
93
- <template #footer>
135
+ <PopoverFooter>
94
136
  <UnnnicButton text="Cancel" type="tertiary" />
95
137
  <UnnnicButton text="Save" type="primary" />
96
- </template>
138
+ </PopoverFooter>
97
139
  </PopoverContent>
98
140
  </Popover>
99
141
  </div>
@@ -113,6 +155,7 @@ export const WithForm = {
113
155
  components: {
114
156
  Popover,
115
157
  PopoverContent,
158
+ PopoverFooter,
116
159
  PopoverTrigger,
117
160
  UnnnicButton,
118
161
  UnnnicInput,
@@ -136,10 +179,10 @@ export const WithForm = {
136
179
  <UnnnicLabel label="Email" />
137
180
  <UnnnicInput placeholder="Enter your email" type="email" />
138
181
  </form>
139
- <template #footer>
182
+ <PopoverFooter>
140
183
  <UnnnicButton text="Cancel" type="tertiary" />
141
184
  <UnnnicButton text="Save" type="primary" />
142
- </template>
185
+ </PopoverFooter>
143
186
  </PopoverContent>
144
187
  </Popover>
145
188
  </div>
@@ -154,6 +197,25 @@ export const Sizes = {
154
197
  story:
155
198
  'The popover comes in three sizes: small (240px), medium (320px), and large (400px).',
156
199
  },
200
+ source: {
201
+ code: `
202
+ <UnnnicPopover>
203
+ <!-- Small popover (240px) -->
204
+ <UnnnicPopoverContent size="small">
205
+ ...
206
+ </UnnnicPopoverContent>
207
+
208
+ <!-- Medium popover (320px) -->
209
+ <UnnnicPopoverContent size="medium">
210
+ ...
211
+ </UnnnicPopoverContent>
212
+ <!-- Large popover (400px) -->
213
+ <UnnnicPopoverContent size="large">
214
+ ...
215
+ </UnnnicPopoverContent>
216
+ </UnnnicPopover>
217
+ `,
218
+ },
157
219
  },
158
220
  },
159
221
  render: (args) => ({
@@ -201,6 +263,28 @@ export const Placements = {
201
263
  story:
202
264
  'The popover can be positioned on any side of the trigger: top, bottom, left, or right.',
203
265
  },
266
+ source: {
267
+ code: `
268
+ <UnnnicPopover>
269
+ <!-- Top -->
270
+ <UnnnicPopoverContent side="top">
271
+ ...
272
+ </UnnnicPopoverContent>
273
+ <!-- Bottom -->
274
+ <UnnnicPopoverContent side="bottom">
275
+ ...
276
+ </UnnnicPopoverContent>
277
+ <!-- Right -->
278
+ <UnnnicPopoverContent side="right">
279
+ ...
280
+ </UnnnicPopoverContent>
281
+ <!-- Left -->
282
+ <UnnnicPopoverContent side="left">
283
+ ...
284
+ </UnnnicPopoverContent>
285
+ </UnnnicPopover>
286
+ `,
287
+ },
204
288
  },
205
289
  },
206
290
  render: (args) => ({
@@ -263,7 +347,13 @@ export const RichContent = {
263
347
  },
264
348
  },
265
349
  render: (args) => ({
266
- components: { Popover, PopoverContent, PopoverTrigger, UnnnicButton },
350
+ components: {
351
+ Popover,
352
+ PopoverContent,
353
+ PopoverFooter,
354
+ PopoverTrigger,
355
+ UnnnicButton,
356
+ },
267
357
  setup() {
268
358
  return { args };
269
359
  },
@@ -295,9 +385,9 @@ export const RichContent = {
295
385
  </div>
296
386
  </div>
297
387
  </div>
298
- <template #footer>
388
+ <PopoverFooter>
299
389
  <UnnnicButton text="View Profile" type="primary" />
300
- </template>
390
+ </PopoverFooter>
301
391
  </PopoverContent>
302
392
  </Popover>
303
393
  </div>