sprintify-ui 0.5.12 → 0.6.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.
@@ -3,7 +3,6 @@ import BaseAutocomplete from './BaseAutocomplete.vue';
3
3
  import BaseModalCenter from './BaseModalCenter.vue';
4
4
  import BaseDropdown from './BaseDropdown.vue';
5
5
  import BaseDatePicker from './BaseDatePicker.vue';
6
- import BaseClickOutside from './BaseClickOutside.vue';
7
6
  import { options } from '../../.storybook/utils';
8
7
 
9
8
  const items = [];
@@ -21,13 +20,12 @@ export default {
21
20
  placement: {
22
21
  control: {
23
22
  type: 'select',
24
- options: ['top-start', 'top-end', 'bottom-start', 'bottom-end'],
25
23
  },
24
+ options: ['top-start', 'top-end', 'bottom-start', 'bottom-end'],
26
25
  },
27
26
  },
28
27
  args: {
29
28
  placement: 'bottom-start',
30
- padding: 8,
31
29
  },
32
30
  };
33
31
 
@@ -73,40 +71,23 @@ export const WithAutocomplete = (args) => ({
73
71
  components: { BaseDropdown, BaseAutocomplete, BaseBadge },
74
72
  setup() {
75
73
  const value = ref(null);
76
- const autocomplete = ref(null);
77
-
78
- function onOpen() {
79
- if (autocomplete.value) {
80
- setTimeout(() => {
81
- autocomplete.value.open();
82
- }, 1);
83
- }
84
- }
85
-
86
- function onClose() {
87
- setTimeout(() => {
88
- if (autocomplete.value) {
89
- autocomplete.value.setKeywords('');
90
- }
91
- }, 10);
92
- }
93
74
 
94
75
  function onUpdate(v, close) {
95
76
  if (v) {
96
77
  close();
97
78
  }
98
79
  }
99
- return { args, options, value, onOpen, onClose, onUpdate, autocomplete };
80
+
81
+ return { args, options, value, onUpdate };
100
82
  },
101
83
  template: `
102
- <BaseDropdown @open="onOpen" @close="onClose" v-bind="args">
84
+ <BaseDropdown v-bind="args">
103
85
  <template #button>
104
86
  <BaseBadge>{{ value ? value.label : 'Select a Character' }}</BaseBadge>
105
87
  </template>
106
88
  <template #dropdown="{close}">
107
- <div class="bg-white shadow border border-slate-300 py-1 px-1 rounded" style="min-width: 250px">
89
+ <div class="bg-white shadow-lg rounded-md border py-2 px-2" style="min-width: 250px">
108
90
  <BaseAutocomplete
109
- ref="autocomplete"
110
91
  required
111
92
  v-model="value"
112
93
  label-key="label"
@@ -117,6 +98,7 @@ export const WithAutocomplete = (args) => ({
117
98
  :visibleFocus="false"
118
99
  dropdownShow="always"
119
100
  :showModelValue="false"
101
+ focus-on-mount
120
102
  @update:modelValue="onUpdate($event, close)"
121
103
  ></BaseAutocomplete>
122
104
  </div>
@@ -128,37 +110,8 @@ export const WithAutocomplete = (args) => ({
128
110
  WithAutocomplete.args = {
129
111
  animated: true,
130
112
  placement: 'bottom-start',
131
- padding: 3,
132
113
  };
133
114
 
134
- export const ModalWithScroll = (args) => ({
135
- components: { BaseDropdown, BaseModalCenter },
136
- setup() {
137
- return { args, items };
138
- },
139
- template: `
140
- <BaseModalCenter :model-value="true">
141
- <div class="p-10 bg-white">
142
- <BaseDropdown v-bind="args">
143
- <template #button>
144
- <div class="btn btn-primary">Click me</div>
145
- </template>
146
- <template #dropdown>
147
- <div
148
- class="bg-white shadow py-1 px-1 rounded"
149
- style="max-height: 200px; overflow: auto;"
150
- data-scroll-lock-scrollable>
151
- <button type="button" v-for="item in items" :key="item.label" class="block text-sm px-4 py-1.5">{{ item.label }}</button>
152
- </div>
153
- </template>
154
- </BaseDropdown>
155
-
156
- <div style="height: 3000px;"></div>
157
- </div>
158
- </BaseModalCenter>
159
- `,
160
- });
161
-
162
115
  export const WithDatePicker = (args) => ({
163
116
  components: { BaseDropdown, BaseDatePicker },
164
117
  setup() {
@@ -171,7 +124,7 @@ export const WithDatePicker = (args) => ({
171
124
  <div class="btn btn-primary">Click me</div>
172
125
  </template>
173
126
  <template #dropdown>
174
- <div class="bg-white shadow-lg rounded border p-2">
127
+ <div class="bg-white shadow-lg rounded-md ring-1 ring-black ring-opacity-10 p-2">
175
128
  <BaseDatePicker v-model="date" :show-input="true" inline></BaseDatePicker>
176
129
  </div>
177
130
  </template>
@@ -180,31 +133,35 @@ export const WithDatePicker = (args) => ({
180
133
  });
181
134
 
182
135
  WithDatePicker.args = {
136
+ animated: true,
183
137
  placement: 'bottom-start',
184
138
  };
185
139
 
186
- export const WithinClickOutside = (args) => ({
187
- components: { BaseDropdown, BaseClickOutside },
140
+ export const ModalWithScroll = (args) => ({
141
+ components: { BaseDropdown, BaseModalCenter },
188
142
  setup() {
189
- function onClickOutside() {
190
- alert('click outside');
191
- }
192
- return { args, items, onClickOutside };
143
+ const open = ref(true);
144
+ return { args, items, open };
193
145
  },
194
146
  template: `
195
- <BaseClickOutside @clickOutside="onClickOutside">
196
- <div class="bg-slate-200 shadow-md min-h-[100px] p-3">
147
+ <BaseModalCenter v-model="open">
148
+ <div class="p-10 bg-white">
197
149
  <BaseDropdown v-bind="args">
198
150
  <template #button>
199
151
  <div class="btn btn-primary">Click me</div>
200
152
  </template>
201
153
  <template #dropdown>
202
- <div class="bg-white shadow-lg rounded border p-2 w-[260px]">
203
- ...
154
+ <div
155
+ class="bg-white shadow py-1 px-1 rounded"
156
+ style="max-height: 200px; overflow: auto;"
157
+ data-scroll-lock-scrollable>
158
+ <button type="button" v-for="item in items" :key="item.label" class="block text-sm px-4 py-1.5">{{ item.label }}</button>
204
159
  </div>
205
160
  </template>
206
161
  </BaseDropdown>
162
+
163
+ <div style="height: 3000px;"></div>
207
164
  </div>
208
- </BaseClickOutside>
165
+ </BaseModalCenter>
209
166
  `,
210
167
  });
@@ -1,280 +1,74 @@
1
1
  <template>
2
- <div>
3
- <button
4
- ref="button"
5
- type="button"
6
- @click="toggle()"
7
- >
8
- <slot name="button" />
9
- </button>
2
+ <Popover v-slot="{ open }">
3
+ <PopoverButton class="outline-none">
4
+ <div ref="buttonRef">
5
+ <slot name="button" />
6
+ </div>
7
+ </PopoverButton>
8
+
10
9
  <Teleport to="body">
11
10
  <div
12
- ref="dropdown"
13
- class="z-menu"
14
- :style="dropdownStyles"
11
+ ref="dropdownRef"
12
+ :style="floatingStyles"
13
+ class="fixed top-0 left-0 z-menu"
15
14
  >
16
15
  <Transition
17
- :enter-active-class="
18
- animated ? 'transition duration-200 ease-out' : ''
19
- "
16
+ :enter-active-class="animated ? 'transition duration-200 ease-out' : ''"
20
17
  enter-from-class="transform scale-95 opacity-0"
21
18
  enter-to-class="transform scale-100 opacity-100"
22
19
  :leave-active-class="animated ? 'transition duration-75 ease-in' : ''"
23
20
  leave-from-class="transform scale-100 opacity-100"
24
21
  leave-to-class="transform scale-95 opacity-0"
25
22
  >
26
- <template v-if="showDropdown || keepAlive">
27
- <div
28
- v-show="showDropdown"
29
- class="inline-block"
23
+ <div v-if="open || keepAlive">
24
+ <PopoverPanel
25
+ v-show="open"
26
+ v-slot="{ close }"
27
+ static
30
28
  >
31
29
  <slot
32
30
  name="dropdown"
33
- :show-dropdown="showDropdown"
34
31
  :close="close"
35
- :open="open"
36
- :toggle="toggle"
32
+ :opened="open"
37
33
  />
38
- </div>
39
- </template>
34
+ </PopoverPanel>
35
+ </div>
40
36
  </Transition>
41
37
  </div>
42
38
  </Teleport>
43
- </div>
39
+ </Popover>
44
40
  </template>
45
41
 
46
42
  <script lang="ts" setup>
47
- import { useClickOutside } from '@/composables/clickOutside';
48
- import { MaybeElement, MaybeRef, useResizeObserver } from '@vueuse/core';
49
- import { throttle } from 'lodash';
50
- import { PropType, StyleValue } from 'vue';
51
- import { disableScroll, enableScroll } from '../utils';
43
+ import { autoUpdate, offset, flip, shift, useFloating, Placement } from '@floating-ui/vue';
44
+ import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue';
45
+ import { unrefElement } from '@vueuse/core';
46
+ import { PropType } from 'vue';
47
+
48
+ const buttonRef = ref<InstanceType<typeof PopoverButton> | null>(null);
49
+ const dropdownRef = ref<HTMLElement | null>(null);
52
50
 
53
- const button = ref<HTMLElement | null>(null);
54
- const dropdown = ref<HTMLElement | null>(null);
51
+ const buttonRefEl = computed(() => unrefElement(buttonRef));
55
52
 
56
- const showDropdown = ref(false);
57
53
  const props = defineProps({
58
- placement: {
59
- type: String as PropType<
60
- 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'
61
- >,
62
- default() {
63
- return 'bottom-start';
64
- },
65
- },
66
- padding: {
67
- default: 8,
68
- type: Number,
69
- },
70
54
  animated: {
71
- default: false,
55
+ default: true,
72
56
  type: Boolean,
73
57
  },
74
58
  keepAlive: {
75
- default: true,
59
+ default: false,
76
60
  type: Boolean,
77
61
  },
78
- });
79
-
80
- const emit = defineEmits(['close', 'open']);
81
-
82
- const buttonX = ref(0);
83
- const buttonY = ref(0);
84
- const buttonWidth = ref(0);
85
- const buttonHeight = ref(0);
86
-
87
- const dropdownX = ref(0);
88
- const dropdownY = ref(0);
89
- const dropdownWidth = ref(0);
90
- const dropdownHeight = ref(0);
91
-
92
- function setBoundingBoxes() {
93
- if (button.value) {
94
- const { y, x, height, width } = button.value.getBoundingClientRect();
95
- buttonX.value = x;
96
- buttonY.value = y;
97
- buttonWidth.value = width;
98
- buttonHeight.value = height;
99
- }
100
-
101
- if (dropdown.value) {
102
- const { y, x, height, width } = dropdown.value.getBoundingClientRect();
103
- dropdownX.value = x;
104
- dropdownY.value = y;
105
- dropdownWidth.value = width;
106
- dropdownHeight.value = height;
107
- }
108
- }
109
-
110
- function toggle() {
111
- if (showDropdown.value) {
112
- close();
113
- } else {
114
- open();
115
- }
116
- }
117
-
118
- function open() {
119
- activate();
120
- showDropdown.value = true;
121
- nextTick(() => {
122
- setBoundingBoxes();
123
- disableScroll();
124
- emit('open');
125
- });
126
- }
127
-
128
- function close() {
129
- deactivate();
130
- showDropdown.value = false;
131
- enableScroll();
132
- emit('close');
133
- }
134
-
135
- function onKeydown(event: KeyboardEvent) {
136
- if (event.code == 'Escape') {
137
- if (showDropdown.value) {
138
- close();
139
- }
140
- }
141
- }
142
-
143
- const setBoundingBoxesDebounced = throttle(() => {
144
- setBoundingBoxes();
145
- }, 10);
146
-
147
- let buttonResizeObserver = null as any;
148
- let dropdownResizeObserver = null as any;
149
-
150
- function activate() {
151
- buttonResizeObserver = useResizeObserver(button, setBoundingBoxesDebounced);
152
- dropdownResizeObserver = useResizeObserver(
153
- dropdown,
154
- setBoundingBoxesDebounced
155
- );
156
- window.addEventListener('keydown', onKeydown);
157
- window.addEventListener('resize', setBoundingBoxesDebounced);
158
- window.addEventListener('scroll', setBoundingBoxesDebounced, true);
159
- }
160
-
161
- function deactivate() {
162
- buttonResizeObserver?.stop();
163
- dropdownResizeObserver?.stop();
164
- window.removeEventListener('resize', setBoundingBoxesDebounced);
165
- window.removeEventListener('scroll', setBoundingBoxesDebounced, true);
166
- window.removeEventListener('keydown', onKeydown);
167
- }
168
-
169
- useClickOutside(
170
- dropdown,
171
- () => {
172
- if (showDropdown.value) {
173
- close();
174
- }
175
- },
176
- { includes: () => [button] }
177
- );
178
-
179
- const placementInternal = computed(() => {
180
- // vertical
181
- const spaceTop = buttonY.value - props.padding;
182
- const spaceBottom =
183
- window.innerHeight - buttonY.value - buttonHeight.value - props.padding;
184
-
185
- const tooTallForTop = spaceTop < dropdownHeight.value;
186
- const tooTallForBottom = spaceBottom < dropdownHeight.value;
187
-
188
- let verticalPreference = props.placement.split('-')[0];
189
-
190
- if (tooTallForTop && !tooTallForBottom) {
191
- verticalPreference = 'bottom';
192
- } else if (!tooTallForTop && tooTallForBottom) {
193
- verticalPreference = 'top';
194
- } else if (tooTallForTop && tooTallForBottom) {
195
- if (spaceTop > spaceBottom) {
196
- verticalPreference = 'top';
197
- } else {
198
- verticalPreference = 'bottom';
199
- }
200
- }
201
-
202
- // horizontal
203
- const spaceStart = buttonX.value + buttonWidth.value;
204
- const spaceEnd = window.innerWidth - buttonX.value;
205
-
206
- const tooLargeForStart = spaceStart < dropdownWidth.value;
207
- const tooLargeForEnd = spaceEnd < dropdownWidth.value;
208
-
209
- let horizontalPreference = props.placement.split('-')[1];
210
-
211
- if (tooLargeForStart && !tooLargeForEnd) {
212
- horizontalPreference = 'start';
213
- } else if (!tooLargeForStart && tooLargeForEnd) {
214
- horizontalPreference = 'end';
215
- } else if (tooLargeForStart && tooLargeForEnd) {
216
- if (spaceStart > spaceEnd) {
217
- horizontalPreference = 'end';
218
- } else {
219
- horizontalPreference = 'start';
220
- }
221
- }
222
-
223
- return `${verticalPreference}-${horizontalPreference}`;
224
- });
225
-
226
- const dropdownStyles = computed((): StyleValue => {
227
- let top = buttonY.value;
228
-
229
- if (
230
- placementInternal.value == 'bottom-start' ||
231
- placementInternal.value == 'bottom-end'
232
- ) {
233
- top += buttonHeight.value;
234
- top += props.padding;
235
- }
236
-
237
- if (
238
- placementInternal.value == 'top-start' ||
239
- placementInternal.value == 'top-end'
240
- ) {
241
- top -= dropdownHeight.value;
242
- top -= props.padding;
243
- }
244
-
245
- const styles = {
246
- position: 'fixed',
247
- top: `${top}px`,
248
- } as any;
249
-
250
- if (
251
- placementInternal.value == 'bottom-end' ||
252
- placementInternal.value == 'top-end'
253
- ) {
254
- styles.left = `${
255
- buttonX.value + buttonWidth.value - dropdownWidth.value
256
- }px`;
257
- } else {
258
- styles.left = `${buttonX.value}px`;
62
+ placement: {
63
+ default: 'bottom-end',
64
+ type: String as PropType<Placement>,
259
65
  }
260
-
261
- return styles as StyleValue;
262
66
  });
263
67
 
264
- const addClickOutsideInclude = inject('clickOutside:addInclude', () => {
265
- return;
266
- }) as (include: MaybeRef<MaybeElement> | string) => void;
267
-
268
- addClickOutsideInclude(dropdown);
269
-
270
- onBeforeUnmount(() => {
271
- close();
272
- deactivate();
68
+ const { floatingStyles } = useFloating(buttonRefEl, dropdownRef, {
69
+ placement: props.placement,
70
+ middleware: [offset(6), flip(), shift()],
71
+ whileElementsMounted: autoUpdate,
273
72
  });
274
73
 
275
- defineExpose({
276
- open,
277
- close,
278
- toggle,
279
- });
280
74
  </script>
@@ -3,9 +3,6 @@
3
3
  :animated="true"
4
4
  :keep-alive="false"
5
5
  :placement="placement"
6
- :padding="padding"
7
- @open="onOpen"
8
- @close="onClose"
9
6
  >
10
7
  <template #button="buttonProps">
11
8
  <slot
@@ -16,7 +13,7 @@
16
13
  </template>
17
14
  <template #dropdown="{ close }">
18
15
  <div
19
- class="inline-block w-[320px] overflow-hidden rounded-md border border-slate-300 bg-white px-1 pt-1 shadow-lg"
16
+ class="inline-block w-[320px] overflow-hidden rounded-md ring-1 ring-black ring-opacity-10 bg-white px-2 pt-2 shadow-lg"
20
17
  >
21
18
  <component
22
19
  :is="componentName"
@@ -29,6 +26,7 @@
29
26
  :inline="true"
30
27
  :required="required"
31
28
  :select="select"
29
+ :focus-on-mount="true"
32
30
  dropdown-show="always"
33
31
  @update:model-value="onUpdate($event, close)"
34
32
  >
@@ -69,6 +67,7 @@ import BaseAutocomplete from './BaseAutocomplete.vue';
69
67
  import BaseAutocompleteFetch from './BaseAutocompleteFetch.vue';
70
68
  import BaseTagAutocomplete from './BaseTagAutocomplete.vue';
71
69
  import BaseTagAutocompleteFetch from './BaseTagAutocompleteFetch.vue';
70
+ import { Placement } from '@floating-ui/vue';
72
71
 
73
72
  const props = defineProps({
74
73
  modelValue: {
@@ -110,14 +109,8 @@ const props = defineProps({
110
109
  type: String,
111
110
  },
112
111
  placement: {
113
- type: String as PropType<
114
- 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'
115
- >,
116
- default: undefined,
117
- },
118
- padding: {
112
+ type: String as PropType<Placement>,
119
113
  default: undefined,
120
- type: Number,
121
114
  },
122
115
  select: {
123
116
  default: undefined,
@@ -125,7 +118,7 @@ const props = defineProps({
125
118
  },
126
119
  });
127
120
 
128
- const emit = defineEmits(['update:model-value', 'close']);
121
+ const emit = defineEmits(['update:model-value']);
129
122
 
130
123
  const componentName = computed<any>(() => {
131
124
  if (props.multiple) {
@@ -180,24 +173,6 @@ watch(
180
173
  { immediate: true, deep: true }
181
174
  );
182
175
 
183
- function onOpen() {
184
- nextTick(() => {
185
- setTimeout(() => {
186
- autocomplete.value?.open();
187
- }, 1);
188
- });
189
- }
190
-
191
- function onClose() {
192
- nextTick(() => {
193
- setTimeout(() => {
194
- autocomplete.value?.setKeywords('');
195
- }, 1);
196
- });
197
-
198
- emit('close');
199
- }
200
-
201
176
  function onUpdate(
202
177
  value: Option | Option[] | null | undefined,
203
178
  close: () => void
@@ -160,7 +160,6 @@ const props = defineProps({
160
160
  default: false,
161
161
  type: Boolean,
162
162
  },
163
-
164
163
  max: {
165
164
  default: undefined,
166
165
  type: Number,
@@ -185,9 +184,13 @@ const props = defineProps({
185
184
  default: 'focus',
186
185
  type: String as PropType<'focus' | 'always'>,
187
186
  },
187
+ focusOnMount: {
188
+ default: false,
189
+ type: Boolean,
190
+ },
188
191
  twContainer: {
189
192
  default: '',
190
- type: [String, Array] as PropType<string|string[]>,
193
+ type: [String, Array] as PropType<string | string[]>,
191
194
  },
192
195
  });
193
196
 
@@ -214,6 +217,20 @@ const hasOptions = useHasOptions(
214
217
  computed(() => true)
215
218
  );
216
219
 
220
+ let openOfFocusTimeout = 0;
221
+
222
+ onMounted(() => {
223
+ openOfFocusTimeout = setTimeout(() => {
224
+ if (props.focusOnMount) {
225
+ open();
226
+ }
227
+ }, 10)
228
+ });
229
+
230
+ onBeforeUnmount(() => {
231
+ clearTimeout(openOfFocusTimeout);
232
+ });
233
+
217
234
  const drawer = ref<InstanceType<typeof BaseAutocompleteDrawer> | null>(null);
218
235
 
219
236
  const keywords = ref('');
@@ -12,6 +12,7 @@
12
12
  :has-error="hasError"
13
13
  :max="max"
14
14
  :filter="() => true"
15
+ :focus-on-mount="focusOnMount"
15
16
  @open="onOpen"
16
17
  @typing="onTyping"
17
18
  @scroll-bottom="scrollBottom"
@@ -111,6 +112,10 @@ const props = defineProps({
111
112
  default: false,
112
113
  type: Boolean,
113
114
  },
115
+ focusOnMount: {
116
+ default: false,
117
+ type: Boolean,
118
+ },
114
119
  });
115
120
 
116
121
  defineEmits(['update:modelValue', 'typing', 'focus', 'scrollBottom']);
@@ -26,14 +26,10 @@
26
26
 
27
27
  <script lang="ts" setup>
28
28
  import { useTooltip } from '@/composables/tooltip';
29
- import { PropType } from 'vue';
30
29
 
31
- const props = defineProps({
32
- target: {
33
- required: true,
34
- type: Object as PropType<HTMLElement | null>,
35
- }
36
- });
30
+ const props = defineProps<{
31
+ target: HTMLElement | null;
32
+ }>();
37
33
 
38
34
  const targetInternal = computed(() => props.target ?? null);
39
35
 
@@ -18,7 +18,6 @@ import BaseButtonGroup from './BaseButtonGroup.vue';
18
18
  import BaseCard from './BaseCard.vue';
19
19
  import BaseCardRow from './BaseCardRow.vue';
20
20
  import BaseCharacterCounter from './BaseCharacterCounter.vue';
21
- import BaseClickOutside from './BaseClickOutside.vue';
22
21
  import BaseClipboard from './BaseClipboard.vue';
23
22
  import BaseCalendar from './BaseCalendar.vue';
24
23
  import BaseColor from './BaseColor.vue';
@@ -118,7 +117,6 @@ export {
118
117
  BaseCard,
119
118
  BaseCardRow,
120
119
  BaseCharacterCounter,
121
- BaseClickOutside,
122
120
  BaseClipboard,
123
121
  BaseCalendar,
124
122
  BaseColor,
@@ -1,28 +0,0 @@
1
- import { MaybeElement } from '@vueuse/core';
2
- import { MaybeRef } from '@vueuse/shared';
3
- import { PropType } from 'vue';
4
- declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{
5
- includes: {
6
- type: PropType<(string | MaybeRef<MaybeElement>)[]>;
7
- default: () => never[];
8
- };
9
- }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
- clickOutside: (...args: any[]) => void;
11
- }, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
12
- includes: {
13
- type: PropType<(string | MaybeRef<MaybeElement>)[]>;
14
- default: () => never[];
15
- };
16
- }>> & {
17
- onClickOutside?: ((...args: any[]) => any) | undefined;
18
- }, {
19
- includes: (string | MaybeRef<MaybeElement>)[];
20
- }, {}>, {
21
- default?(_: {}): any;
22
- }>;
23
- export default _default;
24
- type __VLS_WithTemplateSlots<T, S> = T & {
25
- new (): {
26
- $slots: S;
27
- };
28
- };