@dpa-id-components/dpa-shared-components 22.0.0-next.2 → 22.0.0-next.4

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.
@@ -1,5 +1,10 @@
1
1
  <template>
2
- <UiPopover :initially-open="isOpen" :animate :placement="floatingUiPlacement">
2
+ <UiPopover
3
+ :initially-open="isOpen"
4
+ :animate
5
+ :placement="floatingUiPlacement"
6
+ @toggle="$event ? $emit('open') : $emit('close')"
7
+ >
3
8
  <template #button="{ toggle, isOpen: isPopoverOpen }">
4
9
  <UiButton
5
10
  class="w-full justify-between"
@@ -10,10 +15,7 @@
10
15
  :disabled
11
16
  :size="filterButtonSize"
12
17
  data-testid="menu-button"
13
- @click="
14
- toggle();
15
- isPopoverOpen ? $emit('close') : $emit('open');
16
- "
18
+ @click="toggle"
17
19
  >
18
20
  <div class="flex items-center gap-2">
19
21
  <UiIcon v-if="iconLeft" :name="iconLeft" size="sm" />
@@ -23,106 +25,100 @@
23
25
  </UiButton>
24
26
  </template>
25
27
 
26
- <template #default="{ close }">
28
+ <div
29
+ class="block w-max max-w-full divide-y overflow-hidden rounded-sm text-base/6 shadow-lg focus:outline-hidden sm:text-sm/5"
30
+ >
27
31
  <div
28
- class="block w-max max-w-full divide-y overflow-hidden rounded-sm text-base/6 shadow-lg focus:outline-hidden sm:text-sm/5"
32
+ v-if="hasSearch"
33
+ class="flex items-center gap-2 rounded-t-sm px-4 py-2 text-neutral-primary [&:has(>input:focus-visible)]:focus-outline [&:has(>input:focus-visible)]:-outline-offset-2"
29
34
  >
30
- <div
31
- v-if="hasSearch"
32
- class="flex items-center gap-2 rounded-t-sm px-4 py-2 text-neutral-primary [&:has(>input:focus-visible)]:focus-outline [&:has(>input:focus-visible)]:-outline-offset-2"
33
- >
34
- <UiIcon
35
- class="shrink-0 text-neutral-emphasis"
36
- name="search"
37
- size="sm"
38
- />
39
- <input
40
- ref="search-input"
41
- v-model="queryModel"
42
- type="text"
43
- spellcheck="false"
44
- class="w-full text-sm focus:outline-hidden"
45
- :placeholder="searchPlaceholder"
46
- data-testid="menu-search-input"
47
- />
48
- </div>
35
+ <UiIcon
36
+ class="shrink-0 text-neutral-emphasis"
37
+ name="search"
38
+ size="sm"
39
+ />
40
+ <input
41
+ ref="search-input"
42
+ v-model="queryModel"
43
+ type="text"
44
+ spellcheck="false"
45
+ class="w-full text-sm focus:outline-hidden"
46
+ :placeholder="searchPlaceholder"
47
+ data-testid="menu-search-input"
48
+ />
49
+ </div>
49
50
 
50
- <slot
51
- v-bind="{
52
- checkboxAppearance,
53
- checkboxSize,
54
- iconSize,
55
- imageShape,
56
- listVariant,
57
- options,
58
- groupedOptions,
59
- }"
51
+ <slot
52
+ v-bind="{
53
+ checkboxAppearance,
54
+ checkboxSize,
55
+ iconSize,
56
+ imageShape,
57
+ listVariant,
58
+ options,
59
+ groupedOptions,
60
+ }"
61
+ >
62
+ <ul
63
+ v-if="processedOptions.some(({ options }) => options.length > 0)"
64
+ class="max-h-80 overflow-y-auto"
65
+ data-testid="menu-option-list"
60
66
  >
61
- <ul
62
- v-if="processedOptions.some(({ options }) => options.length > 0)"
63
- class="max-h-80 overflow-y-auto"
64
- data-testid="menu-option-list"
67
+ <template
68
+ v-for="group in processedOptions"
69
+ :key="`group-${group.groupLabel ?? 'default'}`"
65
70
  >
66
- <template
67
- v-for="group in processedOptions"
68
- :key="`group-${group.groupLabel ?? 'default'}`"
69
- >
70
- <template v-if="group.options.length > 0">
71
- <li
72
- v-if="group.groupLabel"
73
- class="flex h-6 items-center bg-neutral-whisper px-4 text-xs font-semibold tracking-wider text-neutral-subtle uppercase"
74
- >
75
- {{ group.groupLabel }}
76
- </li>
71
+ <template v-if="group.options.length > 0">
72
+ <li
73
+ v-if="group.groupLabel"
74
+ class="flex h-6 items-center bg-neutral-whisper px-4 text-xs font-semibold tracking-wider text-neutral-subtle uppercase"
75
+ >
76
+ {{ group.groupLabel }}
77
+ </li>
77
78
 
78
- <UiListItem
79
- v-for="(option, index) in group.options"
80
- :key="`option-${option.value}`"
81
- :selected="option.selected"
82
- :selectable="listVariant === 'selectable'"
83
- :is-checked="option.selected"
84
- :check-box-menu="listVariant === 'checkbox'"
85
- :icon-size="iconSize"
86
- :image-shape="imageShape"
87
- :image-src="option.imageSrc"
88
- :icon-name="option.iconName"
89
- :checkbox-size="checkboxSize"
90
- :checkbox-appearance="checkboxAppearance"
91
- class="hover:bg-neutral-whisper focus:bg-neutral-faint"
92
- :class="{
93
- 'border-t': option.hasDividerAbove,
94
- }"
95
- :data-testid="`menu-option-button-${index}`"
96
- @list-item-click="
97
- (value, shouldCloseMenu) => {
98
- selectOption(option);
99
- if (shouldCloseMenu) {
100
- close();
101
- }
102
- }
103
- "
104
- >{{ option.label }}</UiListItem
105
- >
106
- </template>
79
+ <UiListItem
80
+ v-for="(option, index) in group.options"
81
+ :key="`option-${option.value}`"
82
+ :selected="option.selected"
83
+ :selectable="listVariant === 'selectable'"
84
+ :is-checked="option.selected"
85
+ :check-box-menu="listVariant === 'checkbox'"
86
+ :icon-size="iconSize"
87
+ :image-shape="imageShape"
88
+ :image-src="option.imageSrc"
89
+ :icon-name="option.iconName"
90
+ :checkbox-size="checkboxSize"
91
+ :checkbox-appearance="checkboxAppearance"
92
+ class="hover:bg-neutral-whisper focus:bg-neutral-faint"
93
+ :class="{
94
+ 'border-t': option.hasDividerAbove,
95
+ }"
96
+ :data-testid="`menu-option-button-${index}`"
97
+ @list-item-click="selectOption(option)"
98
+ >{{ option.label }}</UiListItem
99
+ >
107
100
  </template>
108
- </ul>
109
- </slot>
101
+ </template>
102
+ </ul>
103
+ </slot>
110
104
 
111
- <div v-if="hasResetOption" class="px-4 py-2 text-neutral-primary">
112
- <UiButton
113
- appearance="secondary"
114
- :disabled="disabledReset"
115
- icon-name="reset"
116
- size="xs"
117
- data-testid="menu-search-reset-button"
118
- @click="$emit('reset')"
119
- >
120
- <UiIcon name="reset" />
121
- {{ resetLabel }}
122
- </UiButton>
123
- </div>
105
+ <div v-if="hasResetOption" class="px-4 py-2 text-neutral-primary">
106
+ <UiButton
107
+ appearance="secondary"
108
+ :disabled="disabledReset"
109
+ icon-name="reset"
110
+ size="xs"
111
+ data-testid="menu-search-reset-button"
112
+ @click="
113
+ queryModel = '';
114
+ $emit('reset');
115
+ "
116
+ >
117
+ <UiIcon name="reset" />
118
+ {{ resetLabel }}
119
+ </UiButton>
124
120
  </div>
125
- </template>
121
+ </div>
126
122
  </UiPopover>
127
123
  </template>
128
124
 
@@ -1,5 +1,16 @@
1
1
  <template>
2
- <div ref="reference" v-click-away="close" class="w-fit" @click="update">
2
+ <div
3
+ ref="reference"
4
+ v-click-away="
5
+ () => {
6
+ if (isOpen) {
7
+ close();
8
+ }
9
+ }
10
+ "
11
+ class="w-fit"
12
+ @click="update"
13
+ >
3
14
  <slot name="button" v-bind="{ open, close, toggle, isOpen }" />
4
15
 
5
16
  <Transition :name="animate ? 'fade-up' : 'none'">
@@ -25,7 +36,7 @@ import {
25
36
  shift,
26
37
  useFloating,
27
38
  } from "@floating-ui/vue";
28
- import { ref, useTemplateRef } from "vue";
39
+ import { ref, useTemplateRef, watch } from "vue";
29
40
 
30
41
  import { vClickAway } from "../../directives/vClickAway.ts";
31
42
 
@@ -61,9 +72,12 @@ const {
61
72
  placement?: Placement;
62
73
  }>();
63
74
 
75
+ const emit = defineEmits<{
76
+ toggle: [isOpen: boolean];
77
+ }>();
78
+
64
79
  const reference = useTemplateRef("reference");
65
80
  const floating = useTemplateRef("floating");
66
- const isOpen = ref(initiallyOpen);
67
81
 
68
82
  const { floatingStyles, update } = useFloating(reference, floating, {
69
83
  placement,
@@ -71,6 +85,12 @@ const { floatingStyles, update } = useFloating(reference, floating, {
71
85
  whileElementsMounted: autoUpdate,
72
86
  });
73
87
 
88
+ const isOpen = ref(initiallyOpen);
89
+
90
+ watch(isOpen, (isOpen) => {
91
+ emit("toggle", isOpen);
92
+ });
93
+
74
94
  function open() {
75
95
  isOpen.value = true;
76
96
  }
@@ -13,7 +13,7 @@
13
13
  <input
14
14
  :id="uniqueId"
15
15
  v-model="model"
16
- class="inline-flex aspect-square appearance-none items-center justify-center rounded-full border-2 bg-neutral align-middle transition-colors after:size-2 after:rounded-full checked:after:content-[''] not-read-only:enabled:cursor-pointer disabled:border-neutral-muted disabled:text-neutral-soft disabled:checked:after:bg-neutral-muted"
16
+ class="inline-flex aspect-square appearance-none items-center justify-center rounded-full border-2 bg-neutral align-middle transition-colors after:size-2 after:rounded-full checked:after:content-[''] enabled:cursor-pointer disabled:border-neutral-muted disabled:text-neutral-soft disabled:checked:after:bg-neutral-muted"
17
17
  :class="{
18
18
  'size-4': size === 'sm',
19
19
  'size-5': size === 'md',
@@ -9,35 +9,23 @@
9
9
  "
10
10
  >
11
11
  <slot v-if="labelPosition === 'left'" />
12
- <div class="relative">
13
- <input
14
- :id="toggleId"
15
- v-model="modelValue"
16
- type="checkbox"
17
- data-testid="toggleButton"
18
- role="switch"
19
- class="sr-only"
20
- v-bind="{ ...$attrs, class: null }"
21
- />
22
- <div
23
- class="line rounded-full shadow-inner transition-opacity duration-200 ease-in-out"
24
- :class="{
25
- 'bg-secondary opacity-50': modelValue,
26
- 'bg-neutral-faint': !modelValue,
27
- 'h-3 w-6': size === 'sm',
28
- 'h-4 w-10': size === 'lg',
29
- }"
30
- />
31
- <div
32
- :class="{
33
- 'translate-x-full bg-secondary': modelValue,
34
- 'bg-neutral-muted': !modelValue,
35
- '-top-0.5 size-4': size === 'sm',
36
- '-top-1 size-6': size === 'lg',
37
- }"
38
- class="dot absolute -left-1 rounded-full shadow-sm transition-transform duration-200 ease-in-out"
39
- />
40
- </div>
12
+
13
+ <input
14
+ :id="toggleId"
15
+ v-model="model"
16
+ class="relative appearance-none rounded-full shadow-inner transition-opacity duration-200 ease-in-out after:absolute after:-left-1 after:block after:rounded-full after:shadow-sm after:transition-transform after:duration-200 after:ease-in-out after:content-[''] enabled:cursor-pointer"
17
+ :class="{
18
+ 'bg-secondary-emphasis after:translate-x-full after:bg-secondary':
19
+ model,
20
+ 'bg-neutral-faint after:bg-neutral-muted': !model,
21
+ 'h-3 w-6 after:-top-0.5 after:size-4': size === 'sm',
22
+ 'h-4 w-10 after:-top-1 after:size-6': size === 'lg',
23
+ }"
24
+ type="checkbox"
25
+ role="switch"
26
+ data-testid="toggleButton"
27
+ v-bind="{ ...$attrs, class: null }"
28
+ />
41
29
 
42
30
  <slot v-if="labelPosition === 'right'" />
43
31
  </UiLabel>
@@ -51,13 +39,13 @@ import UiLabel from "../UiLabel/UiLabel.vue";
51
39
 
52
40
  defineOptions({ inheritAttrs: false });
53
41
 
54
- const modelValue = defineModel<boolean>({ default: false });
42
+ const model = defineModel<boolean>({ default: false });
55
43
 
56
44
  defineSlots<{
57
45
  /**
58
46
  * Label content.
59
47
  */
60
- default?: () => any;
48
+ default: () => any;
61
49
  }>();
62
50
 
63
51
  const {