ropav 0.0.6 → 0.0.7
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/dist/_plugin-vue_export-helper.js +1 -11
- package/dist/accordion.css +112 -0
- package/dist/accordion.js +360 -0
- package/dist/accordion.js.map +1 -0
- package/dist/badge.css +169 -0
- package/dist/badge.js +103 -0
- package/dist/badge.js.map +1 -0
- package/dist/bem.js +11 -0
- package/dist/bem.js.map +1 -0
- package/dist/button-group.css +8 -8
- package/dist/button-group.js +2 -1
- package/dist/button-group.js.map +1 -1
- package/dist/button.js +3 -2
- package/dist/button.js.map +1 -1
- package/dist/card.js +2 -1
- package/dist/card.js.map +1 -1
- package/dist/checkbox.js +2 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/collapse.css +32 -0
- package/dist/collapse.js +68 -0
- package/dist/collapse.js.map +1 -0
- package/dist/components/accordion/accordion-item.d.ts +40 -0
- package/dist/components/accordion/accordion.d.ts +23 -0
- package/dist/components/accordion/index.d.ts +4 -0
- package/dist/components/accordion/index.js +2 -0
- package/dist/components/accordion/types.d.ts +100 -0
- package/dist/components/accordion/useAccordion.d.ts +3 -0
- package/dist/components/badge/badge.d.ts +25 -0
- package/dist/components/badge/index.d.ts +3 -0
- package/dist/components/badge/index.js +2 -0
- package/dist/components/badge/types.d.ts +16 -0
- package/dist/components/badge/useBadgeColor.d.ts +8 -0
- package/dist/components/collapse/collapse.d.ts +36 -0
- package/dist/components/collapse/index.d.ts +3 -0
- package/dist/components/collapse/index.js +3 -0
- package/dist/components/collapse/types.d.ts +76 -0
- package/dist/components/collapse/useCollapse.d.ts +2 -0
- package/dist/components/dropdown-menu/dropdown-menu-items.d.ts +16 -0
- package/dist/components/dropdown-menu/dropdown-menu-utils.d.ts +23 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +26 -0
- package/dist/components/dropdown-menu/index.d.ts +3 -0
- package/dist/components/dropdown-menu/index.js +2 -0
- package/dist/components/dropdown-menu/types.d.ts +104 -0
- package/dist/components/dropdown-menu/useDropdownMenu.d.ts +32 -0
- package/dist/components/dropdown-menu/useDropdownMenuDisclosure.d.ts +30 -0
- package/dist/components/dropdown-menu/useDropdownMenuDom.d.ts +28 -0
- package/dist/components/dropdown-menu/useDropdownMenuHoverIntent.d.ts +24 -0
- package/dist/components/dropdown-menu/useDropdownMenuInteractions.d.ts +51 -0
- package/dist/components/dropdown-menu/useDropdownMenuNavigation.d.ts +16 -0
- package/dist/components/dropdown-menu/useDropdownMenuRenderItems.d.ts +25 -0
- package/dist/components/dropdown-menu/useDropdownSubmenus.d.ts +18 -0
- package/dist/components/field/field.d.ts +2 -2
- package/dist/components/field/useField.d.ts +16 -0
- package/dist/components/input/useInput.d.ts +8 -0
- package/dist/components/modal/index.d.ts +2 -0
- package/dist/components/modal/index.js +2 -0
- package/dist/components/modal/modal.d.ts +42 -0
- package/dist/components/modal/types.d.ts +32 -0
- package/dist/components/modal/useModal.d.ts +29 -0
- package/dist/components/overlay/index.d.ts +2 -0
- package/dist/components/overlay/index.js +2 -0
- package/dist/components/overlay/overlay.d.ts +19 -0
- package/dist/components/overlay/types.d.ts +12 -0
- package/dist/components/overlay/useOverlay.d.ts +7 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +2 -0
- package/dist/components/popover/popover.d.ts +43 -0
- package/dist/components/popover/types.d.ts +40 -0
- package/dist/components/popover/usePopover.d.ts +20 -0
- package/dist/components/tabs/index.d.ts +6 -0
- package/dist/components/tabs/index.js +2 -0
- package/dist/components/tabs/tabs-content.d.ts +24 -0
- package/dist/components/tabs/tabs-list.d.ts +26 -0
- package/dist/components/tabs/tabs-trigger.d.ts +29 -0
- package/dist/components/tabs/tabs.d.ts +31 -0
- package/dist/components/tabs/types.d.ts +160 -0
- package/dist/components/tabs/useTabs.d.ts +5 -0
- package/dist/dropdown-menu.css +159 -0
- package/dist/dropdown-menu.js +903 -0
- package/dist/dropdown-menu.js.map +1 -0
- package/dist/field.css +8 -8
- package/dist/field.js +68 -50
- package/dist/field.js.map +1 -1
- package/dist/icon-button.css +1 -1
- package/dist/icon-button.js +3 -2
- package/dist/icon-button.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +12 -1
- package/dist/input.css +25 -25
- package/dist/input.js +57 -38
- package/dist/input.js.map +1 -1
- package/dist/modal.css +134 -0
- package/dist/modal.js +433 -0
- package/dist/modal.js.map +1 -0
- package/dist/overlay.css +28 -0
- package/dist/overlay.js +84 -0
- package/dist/overlay.js.map +1 -0
- package/dist/popover.css +75 -0
- package/dist/popover.js +367 -0
- package/dist/popover.js.map +1 -0
- package/dist/progress.js +2 -1
- package/dist/progress.js.map +1 -1
- package/dist/radio.js +4 -9
- package/dist/radio.js.map +1 -1
- package/dist/select.js +8 -37
- package/dist/select.js.map +1 -1
- package/dist/slider.js +2 -1
- package/dist/slider.js.map +1 -1
- package/dist/switch.js +2 -1
- package/dist/switch.js.map +1 -1
- package/dist/tabs.css +279 -0
- package/dist/tabs.js +515 -0
- package/dist/tabs.js.map +1 -0
- package/dist/textarea.js +2 -1
- package/dist/textarea.js.map +1 -1
- package/dist/tooltip.js +2 -1
- package/dist/tooltip.js.map +1 -1
- package/dist/useClickOutside.js +26 -0
- package/dist/useClickOutside.js.map +1 -0
- package/dist/useCollapse.js +94 -0
- package/dist/useCollapse.js.map +1 -0
- package/dist/useRequiredInject.js +11 -0
- package/dist/useRequiredInject.js.map +1 -0
- package/dist/x.js +14 -0
- package/dist/x.js.map +1 -0
- package/package.json +35 -3
- package/dist/_plugin-vue_export-helper.js.map +0 -1
package/dist/tabs.js
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
import './tabs.css';
|
|
2
|
+
import { t as useRequiredInject } from "./useRequiredInject.js";
|
|
3
|
+
import { t as bem } from "./bem.js";
|
|
4
|
+
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
5
|
+
import { computed, createIf, createSlot, defineVaporComponent, onBeforeUnmount, onMounted, provide, ref, renderEffect, setDynamicProps, setInsertionState, shallowRef, template, unref, useId, watch } from "vue";
|
|
6
|
+
//#region src/components/tabs/useTabs.ts
|
|
7
|
+
var TABLIST_SELECTOR = ".rp-tabs-list";
|
|
8
|
+
var TRIGGER_SELECTOR = ".rp-tabs-trigger";
|
|
9
|
+
var DEFAULT_SIZE = "md";
|
|
10
|
+
var DEFAULT_VARIANT = "line";
|
|
11
|
+
var DEFAULT_ORIENTATION = "horizontal";
|
|
12
|
+
var DEFAULT_PLACEMENT = "left";
|
|
13
|
+
var DEFAULT_ACTIVATION_MODE = "automatic";
|
|
14
|
+
var tabsKey = Symbol("tabs");
|
|
15
|
+
var ORIENTATION_NAVIGATION_KEYS = {
|
|
16
|
+
horizontal: {
|
|
17
|
+
ArrowRight: 1,
|
|
18
|
+
ArrowLeft: -1
|
|
19
|
+
},
|
|
20
|
+
vertical: {
|
|
21
|
+
ArrowDown: 1,
|
|
22
|
+
ArrowUp: -1
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function optionalAttr(value) {
|
|
26
|
+
return value || void 0;
|
|
27
|
+
}
|
|
28
|
+
function toTabsState(active) {
|
|
29
|
+
return active ? "active" : "inactive";
|
|
30
|
+
}
|
|
31
|
+
function getDefaultAlign(orientation) {
|
|
32
|
+
return orientation === "vertical" ? "left" : "center";
|
|
33
|
+
}
|
|
34
|
+
function getAriaProps(label, labelledby, describedby) {
|
|
35
|
+
return {
|
|
36
|
+
"aria-label": optionalAttr(label),
|
|
37
|
+
"aria-labelledby": optionalAttr(labelledby),
|
|
38
|
+
"aria-describedby": optionalAttr(describedby)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function getOrientationClasses(disabled, orientation) {
|
|
42
|
+
return {
|
|
43
|
+
disabled,
|
|
44
|
+
[orientation]: true
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function getPlacementClasses(orientation, placement) {
|
|
48
|
+
return { [`placement-${placement}`]: orientation === "vertical" };
|
|
49
|
+
}
|
|
50
|
+
function getStateClasses(active) {
|
|
51
|
+
return {
|
|
52
|
+
active,
|
|
53
|
+
inactive: !active
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function getTriggerClasses(active, disabled, orientation, placement, align) {
|
|
57
|
+
return {
|
|
58
|
+
...getStateClasses(active),
|
|
59
|
+
...getOrientationClasses(disabled, orientation),
|
|
60
|
+
...getPlacementClasses(orientation, placement),
|
|
61
|
+
...align ? { [`align-${align}`]: true } : {}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function findRegistration(entries, value) {
|
|
65
|
+
if (value == null) return void 0;
|
|
66
|
+
return entries.find((entry) => entry.value === value);
|
|
67
|
+
}
|
|
68
|
+
function upsertRegistration(entries, entry) {
|
|
69
|
+
const index = entries.findIndex((current) => current.id === entry.id);
|
|
70
|
+
if (index < 0) return [...entries, entry];
|
|
71
|
+
const nextEntries = entries.slice();
|
|
72
|
+
nextEntries[index] = entry;
|
|
73
|
+
return nextEntries;
|
|
74
|
+
}
|
|
75
|
+
function useTabsRegistry() {
|
|
76
|
+
const items = shallowRef([]);
|
|
77
|
+
return {
|
|
78
|
+
items,
|
|
79
|
+
register(entry) {
|
|
80
|
+
items.value = upsertRegistration(items.value, entry);
|
|
81
|
+
},
|
|
82
|
+
unregister(id) {
|
|
83
|
+
items.value = items.value.filter((item) => item.id !== id);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function useTabsRegistration(getRegistration, register, unregister, watchSource) {
|
|
88
|
+
const registeredId = ref(null);
|
|
89
|
+
function syncRegistration() {
|
|
90
|
+
const registration = getRegistration();
|
|
91
|
+
if (registeredId.value && registeredId.value !== registration.id) unregister(registeredId.value);
|
|
92
|
+
register(registration);
|
|
93
|
+
registeredId.value = registration.id;
|
|
94
|
+
}
|
|
95
|
+
onMounted(syncRegistration);
|
|
96
|
+
watch(watchSource, syncRegistration);
|
|
97
|
+
onBeforeUnmount(() => {
|
|
98
|
+
if (registeredId.value) unregister(registeredId.value);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function getTabsTrigger(event, list) {
|
|
102
|
+
const target = event.target;
|
|
103
|
+
const trigger = target instanceof Element ? target.closest(TRIGGER_SELECTOR) : void 0;
|
|
104
|
+
return trigger?.closest(TABLIST_SELECTOR) === list ? trigger : void 0;
|
|
105
|
+
}
|
|
106
|
+
function getTabsTriggers(list) {
|
|
107
|
+
return Array.from(list.querySelectorAll(TRIGGER_SELECTOR)).filter((trigger) => trigger.closest(TABLIST_SELECTOR) === list && !trigger.disabled);
|
|
108
|
+
}
|
|
109
|
+
function getNextTrigger(list, currentTrigger, key, orientation) {
|
|
110
|
+
const triggers = getTabsTriggers(list);
|
|
111
|
+
const currentIndex = triggers.indexOf(currentTrigger);
|
|
112
|
+
if (currentIndex === -1 || triggers.length === 0) return void 0;
|
|
113
|
+
if (key === "Home") return triggers[0];
|
|
114
|
+
if (key === "End") return triggers[triggers.length - 1];
|
|
115
|
+
const direction = ORIENTATION_NAVIGATION_KEYS[orientation][key];
|
|
116
|
+
if (!direction) return void 0;
|
|
117
|
+
return triggers[(currentIndex + direction + triggers.length) % triggers.length];
|
|
118
|
+
}
|
|
119
|
+
function useTabsItem(componentName, props, suffix) {
|
|
120
|
+
const group = useRequiredInject(tabsKey, componentName);
|
|
121
|
+
const generatedId = useId();
|
|
122
|
+
const id = computed(() => props.id ?? `${generatedId}-${suffix}`);
|
|
123
|
+
const isSelected = computed(() => group.isSelected(props.value));
|
|
124
|
+
return {
|
|
125
|
+
group,
|
|
126
|
+
id,
|
|
127
|
+
isSelected,
|
|
128
|
+
state: computed(() => toTabsState(isSelected.value))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function useTabs(props, emitUpdate) {
|
|
132
|
+
const triggerRegistry = useTabsRegistry();
|
|
133
|
+
const contentRegistry = useTabsRegistry();
|
|
134
|
+
const { items: triggers, unregister: unregisterTrigger } = triggerRegistry;
|
|
135
|
+
const { items: contents, register: registerContent, unregister: unregisterContent } = contentRegistry;
|
|
136
|
+
const isControlled = computed(() => props.modelValue !== void 0);
|
|
137
|
+
const uncontrolledValue = ref(props.defaultValue ?? null);
|
|
138
|
+
const isDisabled = computed(() => Boolean(props.disabled));
|
|
139
|
+
const size = computed(() => props.size ?? DEFAULT_SIZE);
|
|
140
|
+
const variant = computed(() => props.variant ?? DEFAULT_VARIANT);
|
|
141
|
+
const orientation = computed(() => props.orientation ?? DEFAULT_ORIENTATION);
|
|
142
|
+
const placement = computed(() => props.placement ?? DEFAULT_PLACEMENT);
|
|
143
|
+
const align = computed(() => props.align);
|
|
144
|
+
const activationMode = computed(() => props.activationMode ?? DEFAULT_ACTIVATION_MODE);
|
|
145
|
+
const selectedValue = computed(() => isControlled.value ? props.modelValue ?? null : uncontrolledValue.value);
|
|
146
|
+
const firstEnabledTrigger = computed(() => triggers.value.find((trigger) => !trigger.disabled));
|
|
147
|
+
const selectedEnabledTrigger = computed(() => {
|
|
148
|
+
const trigger = findRegistration(triggers.value, selectedValue.value);
|
|
149
|
+
return trigger && !trigger.disabled ? trigger : void 0;
|
|
150
|
+
});
|
|
151
|
+
const rootClass = computed(() => bem("rp-tabs", `size-${size.value}`, variant.value, getOrientationClasses(isDisabled.value, orientation.value), getPlacementClasses(orientation.value, placement.value)));
|
|
152
|
+
const rootProps = computed(() => ({
|
|
153
|
+
id: props.id,
|
|
154
|
+
class: rootClass.value,
|
|
155
|
+
"data-disabled": optionalAttr(isDisabled.value),
|
|
156
|
+
"data-size": size.value,
|
|
157
|
+
"data-variant": variant.value,
|
|
158
|
+
"data-orientation": orientation.value,
|
|
159
|
+
"data-placement": optionalAttr(orientation.value === "vertical" ? placement.value : void 0),
|
|
160
|
+
"data-activation-mode": activationMode.value,
|
|
161
|
+
...getAriaProps(props.ariaLabel, props.labelledby, props.describedby)
|
|
162
|
+
}));
|
|
163
|
+
const slotProps = computed(() => ({
|
|
164
|
+
value: selectedValue.value,
|
|
165
|
+
size: size.value,
|
|
166
|
+
variant: variant.value,
|
|
167
|
+
disabled: isDisabled.value,
|
|
168
|
+
placement: placement.value,
|
|
169
|
+
align: align.value ?? getDefaultAlign(orientation.value),
|
|
170
|
+
select: selectValue
|
|
171
|
+
}));
|
|
172
|
+
function syncUncontrolledValue() {
|
|
173
|
+
if (isControlled.value || isDisabled.value) return;
|
|
174
|
+
const selectedTrigger = findRegistration(triggers.value, selectedValue.value);
|
|
175
|
+
if (selectedValue.value != null && !selectedTrigger?.disabled) return;
|
|
176
|
+
uncontrolledValue.value = firstEnabledTrigger.value?.value ?? null;
|
|
177
|
+
}
|
|
178
|
+
function setValue(value) {
|
|
179
|
+
if (isDisabled.value || value === selectedValue.value) return;
|
|
180
|
+
if (!isControlled.value) uncontrolledValue.value = value;
|
|
181
|
+
emitUpdate(value);
|
|
182
|
+
}
|
|
183
|
+
function selectValue(value) {
|
|
184
|
+
const trigger = findRegistration(triggers.value, value);
|
|
185
|
+
if (isDisabled.value || trigger?.disabled) return;
|
|
186
|
+
setValue(value);
|
|
187
|
+
}
|
|
188
|
+
const getFocusableValue = () => selectedEnabledTrigger.value?.value ?? firstEnabledTrigger.value?.value ?? null;
|
|
189
|
+
const getTriggerId = (value) => findRegistration(triggers.value, value)?.id;
|
|
190
|
+
const getContentId = (value) => findRegistration(contents.value, value)?.id;
|
|
191
|
+
const getTriggerValue = (id) => triggers.value.find((trigger) => trigger.id === id)?.value;
|
|
192
|
+
function registerTrigger(registration) {
|
|
193
|
+
triggerRegistry.register(registration);
|
|
194
|
+
syncUncontrolledValue();
|
|
195
|
+
}
|
|
196
|
+
function onListKeydown(event) {
|
|
197
|
+
const list = event.currentTarget;
|
|
198
|
+
if (!list || isDisabled.value) return;
|
|
199
|
+
const trigger = getTabsTrigger(event, list);
|
|
200
|
+
if (!trigger) return;
|
|
201
|
+
const nextTrigger = getNextTrigger(list, trigger, event.key, orientation.value);
|
|
202
|
+
if (!nextTrigger) return;
|
|
203
|
+
event.preventDefault();
|
|
204
|
+
nextTrigger.focus();
|
|
205
|
+
const nextValue = getTriggerValue(nextTrigger.id);
|
|
206
|
+
if (nextValue !== void 0 && activationMode.value === "automatic") selectValue(nextValue);
|
|
207
|
+
}
|
|
208
|
+
provide(tabsKey, {
|
|
209
|
+
get selectedValue() {
|
|
210
|
+
return selectedValue.value;
|
|
211
|
+
},
|
|
212
|
+
get disabled() {
|
|
213
|
+
return isDisabled.value;
|
|
214
|
+
},
|
|
215
|
+
get size() {
|
|
216
|
+
return size.value;
|
|
217
|
+
},
|
|
218
|
+
get variant() {
|
|
219
|
+
return variant.value;
|
|
220
|
+
},
|
|
221
|
+
get orientation() {
|
|
222
|
+
return orientation.value;
|
|
223
|
+
},
|
|
224
|
+
get placement() {
|
|
225
|
+
return placement.value;
|
|
226
|
+
},
|
|
227
|
+
get align() {
|
|
228
|
+
return align.value;
|
|
229
|
+
},
|
|
230
|
+
get activationMode() {
|
|
231
|
+
return activationMode.value;
|
|
232
|
+
},
|
|
233
|
+
get unmountOnExit() {
|
|
234
|
+
return Boolean(props.unmountOnExit);
|
|
235
|
+
},
|
|
236
|
+
get ariaLabel() {
|
|
237
|
+
return props.ariaLabel;
|
|
238
|
+
},
|
|
239
|
+
get describedby() {
|
|
240
|
+
return props.describedby;
|
|
241
|
+
},
|
|
242
|
+
get labelledby() {
|
|
243
|
+
return props.labelledby;
|
|
244
|
+
},
|
|
245
|
+
isSelected(value) {
|
|
246
|
+
return selectedValue.value === value;
|
|
247
|
+
},
|
|
248
|
+
selectValue,
|
|
249
|
+
getFocusableValue,
|
|
250
|
+
getTriggerId,
|
|
251
|
+
getContentId,
|
|
252
|
+
getTriggerValue,
|
|
253
|
+
registerTrigger,
|
|
254
|
+
unregisterTrigger,
|
|
255
|
+
registerContent,
|
|
256
|
+
unregisterContent,
|
|
257
|
+
onListKeydown
|
|
258
|
+
});
|
|
259
|
+
return {
|
|
260
|
+
rootClass,
|
|
261
|
+
rootProps,
|
|
262
|
+
slotProps,
|
|
263
|
+
selectedValue,
|
|
264
|
+
selectValue
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function useTabsList(props) {
|
|
268
|
+
const group = useRequiredInject(tabsKey, "RpTabsList");
|
|
269
|
+
const rootClass = computed(() => bem("rp-tabs-list", group.variant, getOrientationClasses(group.disabled, group.orientation), getPlacementClasses(group.orientation, group.placement)));
|
|
270
|
+
return {
|
|
271
|
+
rootClass,
|
|
272
|
+
rootProps: computed(() => ({
|
|
273
|
+
id: props.id,
|
|
274
|
+
class: rootClass.value,
|
|
275
|
+
role: "tablist",
|
|
276
|
+
"data-disabled": optionalAttr(group.disabled),
|
|
277
|
+
"data-variant": group.variant,
|
|
278
|
+
"data-orientation": group.orientation,
|
|
279
|
+
"data-placement": optionalAttr(group.orientation === "vertical" ? group.placement : void 0),
|
|
280
|
+
"aria-orientation": group.orientation,
|
|
281
|
+
...getAriaProps(props.ariaLabel ?? group.ariaLabel, props.ariaLabelledby ?? group.labelledby, props.ariaDescribedby ?? group.describedby),
|
|
282
|
+
onKeydown: group.onListKeydown
|
|
283
|
+
})),
|
|
284
|
+
slotProps: computed(() => ({
|
|
285
|
+
disabled: group.disabled,
|
|
286
|
+
variant: group.variant,
|
|
287
|
+
orientation: group.orientation,
|
|
288
|
+
placement: group.placement
|
|
289
|
+
}))
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function useTabsTrigger(props) {
|
|
293
|
+
const { group, id, isSelected, state } = useTabsItem("RpTabsTrigger", props, "tab");
|
|
294
|
+
const isDisabled = computed(() => Boolean(group.disabled || props.disabled));
|
|
295
|
+
const isFocusable = computed(() => group.getFocusableValue() === props.value && !isDisabled.value);
|
|
296
|
+
const align = computed(() => props.align ?? group.align);
|
|
297
|
+
const effectiveAlign = computed(() => align.value ?? getDefaultAlign(group.orientation));
|
|
298
|
+
const rootClass = computed(() => bem("rp-tabs-trigger", `size-${group.size}`, group.variant, getTriggerClasses(isSelected.value, isDisabled.value, group.orientation, group.placement, align.value)));
|
|
299
|
+
const rootProps = computed(() => ({
|
|
300
|
+
id: id.value,
|
|
301
|
+
class: rootClass.value,
|
|
302
|
+
role: "tab",
|
|
303
|
+
type: "button",
|
|
304
|
+
disabled: optionalAttr(isDisabled.value),
|
|
305
|
+
tabIndex: isFocusable.value ? 0 : -1,
|
|
306
|
+
"data-state": state.value,
|
|
307
|
+
"data-disabled": optionalAttr(isDisabled.value),
|
|
308
|
+
"data-variant": group.variant,
|
|
309
|
+
"data-align": optionalAttr(align.value),
|
|
310
|
+
"aria-selected": isSelected.value,
|
|
311
|
+
"aria-controls": group.getContentId(props.value),
|
|
312
|
+
"aria-disabled": optionalAttr(isDisabled.value),
|
|
313
|
+
onClick: select,
|
|
314
|
+
onFocus,
|
|
315
|
+
onKeydown
|
|
316
|
+
}));
|
|
317
|
+
const slotProps = computed(() => ({
|
|
318
|
+
value: props.value,
|
|
319
|
+
selected: isSelected.value,
|
|
320
|
+
size: group.size,
|
|
321
|
+
variant: group.variant,
|
|
322
|
+
disabled: isDisabled.value,
|
|
323
|
+
align: effectiveAlign.value,
|
|
324
|
+
select
|
|
325
|
+
}));
|
|
326
|
+
useTabsRegistration(() => ({
|
|
327
|
+
id: id.value,
|
|
328
|
+
value: props.value,
|
|
329
|
+
disabled: isDisabled.value
|
|
330
|
+
}), group.registerTrigger, group.unregisterTrigger, () => [
|
|
331
|
+
id.value,
|
|
332
|
+
props.value,
|
|
333
|
+
isDisabled.value
|
|
334
|
+
]);
|
|
335
|
+
function select() {
|
|
336
|
+
if (!isDisabled.value) group.selectValue(props.value);
|
|
337
|
+
}
|
|
338
|
+
function onFocus() {
|
|
339
|
+
if (group.activationMode === "automatic") select();
|
|
340
|
+
}
|
|
341
|
+
function onKeydown(event) {
|
|
342
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
343
|
+
event.preventDefault();
|
|
344
|
+
select();
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
id,
|
|
348
|
+
state,
|
|
349
|
+
isSelected,
|
|
350
|
+
isDisabled,
|
|
351
|
+
rootClass,
|
|
352
|
+
rootProps,
|
|
353
|
+
slotProps,
|
|
354
|
+
select
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function useTabsContent(props) {
|
|
358
|
+
const { group, id, isSelected, state } = useTabsItem("RpTabsContent", props, "tabpanel");
|
|
359
|
+
const shouldUnmountOnExit = computed(() => props.unmountOnExit ?? group.unmountOnExit);
|
|
360
|
+
const shouldRenderContent = computed(() => !shouldUnmountOnExit.value || isSelected.value);
|
|
361
|
+
const rootClass = computed(() => bem("rp-tabs-content", getStateClasses(isSelected.value), { vertical: group.orientation === "vertical" }));
|
|
362
|
+
const rootProps = computed(() => ({
|
|
363
|
+
id: id.value,
|
|
364
|
+
class: rootClass.value,
|
|
365
|
+
role: "tabpanel",
|
|
366
|
+
tabIndex: 0,
|
|
367
|
+
hidden: optionalAttr(!isSelected.value),
|
|
368
|
+
"data-state": state.value,
|
|
369
|
+
...getAriaProps(props.ariaLabel, props.ariaLabelledby ?? group.getTriggerId(props.value), props.ariaDescribedby)
|
|
370
|
+
}));
|
|
371
|
+
const slotProps = computed(() => ({
|
|
372
|
+
value: props.value,
|
|
373
|
+
selected: isSelected.value
|
|
374
|
+
}));
|
|
375
|
+
useTabsRegistration(() => ({
|
|
376
|
+
id: id.value,
|
|
377
|
+
value: props.value
|
|
378
|
+
}), group.registerContent, group.unregisterContent, () => [id.value, props.value]);
|
|
379
|
+
return {
|
|
380
|
+
id,
|
|
381
|
+
state,
|
|
382
|
+
isSelected,
|
|
383
|
+
shouldRenderContent,
|
|
384
|
+
rootClass,
|
|
385
|
+
rootProps,
|
|
386
|
+
slotProps
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
//#endregion
|
|
390
|
+
//#region src/components/tabs/tabs.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
391
|
+
var t0$3 = template("<div data-v-32e41419>", 1);
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/components/tabs/tabs.vue
|
|
394
|
+
var tabs_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
|
|
395
|
+
name: "RpTabs",
|
|
396
|
+
__name: "tabs",
|
|
397
|
+
props: {
|
|
398
|
+
id: {},
|
|
399
|
+
modelValue: { default: void 0 },
|
|
400
|
+
defaultValue: { default: void 0 },
|
|
401
|
+
size: { default: "md" },
|
|
402
|
+
variant: { default: "line" },
|
|
403
|
+
orientation: { default: "horizontal" },
|
|
404
|
+
placement: { default: "left" },
|
|
405
|
+
align: {},
|
|
406
|
+
activationMode: { default: "automatic" },
|
|
407
|
+
disabled: {
|
|
408
|
+
type: Boolean,
|
|
409
|
+
default: false
|
|
410
|
+
},
|
|
411
|
+
unmountOnExit: {
|
|
412
|
+
type: Boolean,
|
|
413
|
+
default: false
|
|
414
|
+
},
|
|
415
|
+
ariaLabel: {},
|
|
416
|
+
describedby: {},
|
|
417
|
+
labelledby: {}
|
|
418
|
+
},
|
|
419
|
+
emits: ["update:modelValue"],
|
|
420
|
+
setup(__props, { emit: __emit }) {
|
|
421
|
+
const props = __props;
|
|
422
|
+
const emit = __emit;
|
|
423
|
+
const { rootProps, slotProps } = useTabs(props, (value) => {
|
|
424
|
+
emit("update:modelValue", value);
|
|
425
|
+
});
|
|
426
|
+
const n1 = t0$3();
|
|
427
|
+
renderEffect(() => setDynamicProps(n1, [unref(rootProps)]));
|
|
428
|
+
setInsertionState(n1, null, 0);
|
|
429
|
+
createSlot("default", { $: [() => unref(slotProps)] }, null, 1);
|
|
430
|
+
return n1;
|
|
431
|
+
}
|
|
432
|
+
}), [["__scopeId", "data-v-32e41419"]]);
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region src/components/tabs/tabs-content.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
435
|
+
var t0$2 = template("<section data-v-3ff419c3>", 1);
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/components/tabs/tabs-content.vue
|
|
438
|
+
var tabs_content_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
|
|
439
|
+
name: "RpTabsContent",
|
|
440
|
+
__name: "tabs-content",
|
|
441
|
+
props: {
|
|
442
|
+
id: {},
|
|
443
|
+
value: {},
|
|
444
|
+
unmountOnExit: {
|
|
445
|
+
type: Boolean,
|
|
446
|
+
default: void 0
|
|
447
|
+
},
|
|
448
|
+
ariaLabel: {},
|
|
449
|
+
ariaDescribedby: {},
|
|
450
|
+
ariaLabelledby: {}
|
|
451
|
+
},
|
|
452
|
+
setup(__props) {
|
|
453
|
+
const { rootProps, slotProps, shouldRenderContent } = useTabsContent(__props);
|
|
454
|
+
return createIf(() => unref(shouldRenderContent), () => {
|
|
455
|
+
const n3 = t0$2();
|
|
456
|
+
renderEffect(() => setDynamicProps(n3, [unref(rootProps)]));
|
|
457
|
+
setInsertionState(n3, null, 0);
|
|
458
|
+
createSlot("default", { $: [() => unref(slotProps)] }, null, 1);
|
|
459
|
+
return n3;
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}), [["__scopeId", "data-v-3ff419c3"]]);
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/components/tabs/tabs-list.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
465
|
+
var t0$1 = template("<div data-v-7f168d05>", 1);
|
|
466
|
+
//#endregion
|
|
467
|
+
//#region src/components/tabs/tabs-list.vue
|
|
468
|
+
var tabs_list_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
|
|
469
|
+
name: "RpTabsList",
|
|
470
|
+
__name: "tabs-list",
|
|
471
|
+
props: {
|
|
472
|
+
id: {},
|
|
473
|
+
ariaLabel: {},
|
|
474
|
+
ariaDescribedby: {},
|
|
475
|
+
ariaLabelledby: {}
|
|
476
|
+
},
|
|
477
|
+
setup(__props) {
|
|
478
|
+
const { rootProps, slotProps } = useTabsList(__props);
|
|
479
|
+
const n1 = t0$1();
|
|
480
|
+
renderEffect(() => setDynamicProps(n1, [unref(rootProps)]));
|
|
481
|
+
setInsertionState(n1, null, 0);
|
|
482
|
+
createSlot("default", { $: [() => unref(slotProps)] }, null, 1);
|
|
483
|
+
return n1;
|
|
484
|
+
}
|
|
485
|
+
}), [["__scopeId", "data-v-7f168d05"]]);
|
|
486
|
+
//#endregion
|
|
487
|
+
//#region src/components/tabs/tabs-trigger.vue?vue&type=script&setup=true&vapor=true&lang.ts
|
|
488
|
+
var t0 = template("<button data-v-4adec360>", 1);
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/components/tabs/tabs-trigger.vue
|
|
491
|
+
var tabs_trigger_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
|
|
492
|
+
name: "RpTabsTrigger",
|
|
493
|
+
__name: "tabs-trigger",
|
|
494
|
+
props: {
|
|
495
|
+
id: {},
|
|
496
|
+
value: {},
|
|
497
|
+
disabled: {
|
|
498
|
+
type: Boolean,
|
|
499
|
+
default: false
|
|
500
|
+
},
|
|
501
|
+
align: {}
|
|
502
|
+
},
|
|
503
|
+
setup(__props) {
|
|
504
|
+
const { rootProps, slotProps } = useTabsTrigger(__props);
|
|
505
|
+
const n1 = t0();
|
|
506
|
+
renderEffect(() => setDynamicProps(n1, [unref(rootProps)]));
|
|
507
|
+
setInsertionState(n1, null, 0);
|
|
508
|
+
createSlot("default", { $: [() => unref(slotProps)] }, null, 1);
|
|
509
|
+
return n1;
|
|
510
|
+
}
|
|
511
|
+
}), [["__scopeId", "data-v-4adec360"]]);
|
|
512
|
+
//#endregion
|
|
513
|
+
export { useTabs as a, useTabsTrigger as c, tabs_default as i, tabs_list_default as n, useTabsContent as o, tabs_content_default as r, useTabsList as s, tabs_trigger_default as t };
|
|
514
|
+
|
|
515
|
+
//# sourceMappingURL=tabs.js.map
|
package/dist/tabs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs.js","names":[],"sources":["../src/components/tabs/useTabs.ts","../src/components/tabs/tabs.vue","../src/components/tabs/tabs.vue","../src/components/tabs/tabs-content.vue","../src/components/tabs/tabs-content.vue","../src/components/tabs/tabs-list.vue","../src/components/tabs/tabs-list.vue","../src/components/tabs/tabs-trigger.vue","../src/components/tabs/tabs-trigger.vue"],"sourcesContent":["import {\n computed,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n shallowRef,\n useId,\n watch,\n type InjectionKey,\n} from 'vue';\nimport { useRequiredInject } from '@/composables/useRequiredInject';\nimport { bem } from '@/utils/bem';\nimport type {\n TabsActivationMode,\n TabsContentProps,\n TabsContentRootProps,\n TabsContentSlotProps,\n TabsListProps,\n TabsListRootProps,\n TabsListSlotProps,\n TabsOrientation,\n TabsPlacement,\n TabsProps,\n TabsRootProps,\n TabsSize,\n TabsSlotProps,\n TabsState,\n TabsTriggerAlign,\n TabsTriggerProps,\n TabsTriggerRootProps,\n TabsTriggerSlotProps,\n TabsValue,\n TabsVariant,\n UseTabsContentReturn,\n UseTabsListReturn,\n UseTabsReturn,\n UseTabsTriggerReturn,\n} from './types';\n\nconst TABLIST_SELECTOR = '.rp-tabs-list';\nconst TRIGGER_SELECTOR = '.rp-tabs-trigger';\n\nconst DEFAULT_SIZE: TabsSize = 'md';\nconst DEFAULT_VARIANT: TabsVariant = 'line';\nconst DEFAULT_ORIENTATION: TabsOrientation = 'horizontal';\nconst DEFAULT_PLACEMENT: TabsPlacement = 'left';\nconst DEFAULT_ACTIVATION_MODE: TabsActivationMode = 'automatic';\n\ntype NavigationDirection = 1 | -1;\n\ninterface TabsRegistration {\n id: string;\n value: TabsValue;\n}\n\ninterface TabsTriggerRegistration extends TabsRegistration {\n disabled: boolean;\n}\n\ninterface TabsContext {\n selectedValue: TabsValue | null;\n size: TabsSize;\n variant: TabsVariant;\n disabled: boolean;\n orientation: TabsOrientation;\n placement: TabsPlacement;\n align?: TabsTriggerAlign;\n activationMode: TabsActivationMode;\n unmountOnExit: boolean;\n ariaLabel?: string;\n describedby?: string;\n labelledby?: string;\n isSelected: (value: TabsValue) => boolean;\n selectValue: (value: TabsValue) => void;\n getFocusableValue: () => TabsValue | null;\n getTriggerId: (value: TabsValue) => string | undefined;\n getContentId: (value: TabsValue) => string | undefined;\n getTriggerValue: (id: string) => TabsValue | undefined;\n registerTrigger: (registration: TabsTriggerRegistration) => void;\n unregisterTrigger: (id: string) => void;\n registerContent: (registration: TabsRegistration) => void;\n unregisterContent: (id: string) => void;\n onListKeydown: (event: KeyboardEvent) => void;\n}\n\nconst tabsKey = Symbol('tabs') as InjectionKey<TabsContext>;\n\nconst ORIENTATION_NAVIGATION_KEYS: Record<\n TabsOrientation,\n Partial<Record<string, NavigationDirection>>\n> = {\n horizontal: { ArrowRight: 1, ArrowLeft: -1 },\n vertical: { ArrowDown: 1, ArrowUp: -1 },\n};\n\nfunction optionalAttr<T extends boolean | string | undefined>(value: T): T | undefined {\n return value || undefined;\n}\n\nfunction toTabsState(active: boolean): TabsState {\n return active ? 'active' : 'inactive';\n}\n\nfunction getDefaultAlign(orientation: TabsOrientation): TabsTriggerAlign {\n return orientation === 'vertical' ? 'left' : 'center';\n}\n\nfunction getAriaProps(label?: string, labelledby?: string, describedby?: string) {\n return {\n 'aria-label': optionalAttr(label),\n 'aria-labelledby': optionalAttr(labelledby),\n 'aria-describedby': optionalAttr(describedby),\n };\n}\n\nfunction getOrientationClasses(disabled: boolean, orientation: TabsOrientation) {\n return { disabled, [orientation]: true };\n}\n\nfunction getPlacementClasses(orientation: TabsOrientation, placement: TabsPlacement) {\n return { [`placement-${placement}`]: orientation === 'vertical' };\n}\n\nfunction getStateClasses(active: boolean) {\n return { active, inactive: !active };\n}\n\nfunction getTriggerClasses(\n active: boolean,\n disabled: boolean,\n orientation: TabsOrientation,\n placement: TabsPlacement,\n align: TabsTriggerAlign | undefined,\n) {\n return {\n ...getStateClasses(active),\n ...getOrientationClasses(disabled, orientation),\n ...getPlacementClasses(orientation, placement),\n ...(align ? { [`align-${align}`]: true } : {}),\n };\n}\n\nfunction findRegistration<T extends TabsRegistration>(\n entries: T[],\n value: TabsValue | null | undefined,\n) {\n if (value == null) return undefined;\n return entries.find((entry) => entry.value === value);\n}\n\nfunction upsertRegistration<T extends { id: string }>(entries: T[], entry: T) {\n const index = entries.findIndex((current) => current.id === entry.id);\n if (index < 0) return [...entries, entry];\n\n const nextEntries = entries.slice();\n nextEntries[index] = entry;\n return nextEntries;\n}\n\nfunction useTabsRegistry<T extends { id: string }>() {\n const items = shallowRef<T[]>([]);\n\n return {\n items,\n register(entry: T) {\n items.value = upsertRegistration(items.value, entry);\n },\n unregister(id: string) {\n items.value = items.value.filter((item) => item.id !== id);\n },\n };\n}\n\nfunction useTabsRegistration<T extends { id: string }>(\n getRegistration: () => T,\n register: (registration: T) => void,\n unregister: (id: string) => void,\n watchSource: () => readonly unknown[],\n) {\n const registeredId = ref<string | null>(null);\n\n function syncRegistration() {\n const registration = getRegistration();\n if (registeredId.value && registeredId.value !== registration.id) {\n unregister(registeredId.value);\n }\n\n register(registration);\n registeredId.value = registration.id;\n }\n\n onMounted(syncRegistration);\n watch(watchSource, syncRegistration);\n\n onBeforeUnmount(() => {\n if (registeredId.value) unregister(registeredId.value);\n });\n}\n\nfunction getTabsTrigger(event: KeyboardEvent, list: HTMLElement) {\n const target = event.target;\n const trigger =\n target instanceof Element ? target.closest<HTMLButtonElement>(TRIGGER_SELECTOR) : undefined;\n\n return trigger?.closest(TABLIST_SELECTOR) === list ? trigger : undefined;\n}\n\nfunction getTabsTriggers(list: HTMLElement) {\n return Array.from(list.querySelectorAll<HTMLButtonElement>(TRIGGER_SELECTOR)).filter(\n (trigger) => trigger.closest(TABLIST_SELECTOR) === list && !trigger.disabled,\n );\n}\n\nfunction getNextTrigger(\n list: HTMLElement,\n currentTrigger: HTMLButtonElement,\n key: string,\n orientation: TabsOrientation,\n) {\n const triggers = getTabsTriggers(list);\n const currentIndex = triggers.indexOf(currentTrigger);\n if (currentIndex === -1 || triggers.length === 0) return undefined;\n\n if (key === 'Home') return triggers[0];\n if (key === 'End') return triggers[triggers.length - 1];\n\n const direction = ORIENTATION_NAVIGATION_KEYS[orientation][key];\n if (!direction) return undefined;\n\n return triggers[(currentIndex + direction + triggers.length) % triggers.length];\n}\n\nfunction useTabsItem(\n componentName: string,\n props: Readonly<{ id?: string; value: TabsValue }>,\n suffix: string,\n) {\n const group = useRequiredInject(tabsKey, componentName);\n const generatedId = useId();\n const id = computed(() => props.id ?? `${generatedId}-${suffix}`);\n const isSelected = computed(() => group.isSelected(props.value));\n const state = computed<TabsState>(() => toTabsState(isSelected.value));\n\n return { group, id, isSelected, state };\n}\n\nexport function useTabs(\n props: Readonly<TabsProps>,\n emitUpdate: (value: TabsValue) => void,\n): UseTabsReturn {\n const triggerRegistry = useTabsRegistry<TabsTriggerRegistration>();\n const contentRegistry = useTabsRegistry<TabsRegistration>();\n const { items: triggers, unregister: unregisterTrigger } = triggerRegistry;\n const {\n items: contents,\n register: registerContent,\n unregister: unregisterContent,\n } = contentRegistry;\n\n const isControlled = computed(() => props.modelValue !== undefined);\n const uncontrolledValue = ref<TabsValue | null>(props.defaultValue ?? null);\n const isDisabled = computed(() => Boolean(props.disabled));\n const size = computed<TabsSize>(() => props.size ?? DEFAULT_SIZE);\n const variant = computed<TabsVariant>(() => props.variant ?? DEFAULT_VARIANT);\n const orientation = computed<TabsOrientation>(() => props.orientation ?? DEFAULT_ORIENTATION);\n const placement = computed<TabsPlacement>(() => props.placement ?? DEFAULT_PLACEMENT);\n const align = computed<TabsTriggerAlign | undefined>(() => props.align);\n const activationMode = computed<TabsActivationMode>(\n () => props.activationMode ?? DEFAULT_ACTIVATION_MODE,\n );\n const selectedValue = computed<TabsValue | null>(() =>\n isControlled.value ? (props.modelValue ?? null) : uncontrolledValue.value,\n );\n const firstEnabledTrigger = computed(() => triggers.value.find((trigger) => !trigger.disabled));\n const selectedEnabledTrigger = computed(() => {\n const trigger = findRegistration(triggers.value, selectedValue.value);\n return trigger && !trigger.disabled ? trigger : undefined;\n });\n\n const rootClass = computed(() =>\n bem(\n 'rp-tabs',\n `size-${size.value}`,\n variant.value,\n getOrientationClasses(isDisabled.value, orientation.value),\n getPlacementClasses(orientation.value, placement.value),\n ),\n );\n\n const rootProps = computed<TabsRootProps>(() => ({\n id: props.id,\n class: rootClass.value,\n 'data-disabled': optionalAttr(isDisabled.value),\n 'data-size': size.value,\n 'data-variant': variant.value,\n 'data-orientation': orientation.value,\n 'data-placement': optionalAttr(\n orientation.value === 'vertical' ? placement.value : undefined,\n ),\n 'data-activation-mode': activationMode.value,\n ...getAriaProps(props.ariaLabel, props.labelledby, props.describedby),\n }));\n\n const slotProps = computed<TabsSlotProps>(() => ({\n value: selectedValue.value,\n size: size.value,\n variant: variant.value,\n disabled: isDisabled.value,\n placement: placement.value,\n align: align.value ?? getDefaultAlign(orientation.value),\n select: selectValue,\n }));\n\n function syncUncontrolledValue() {\n if (isControlled.value || isDisabled.value) return;\n\n const selectedTrigger = findRegistration(triggers.value, selectedValue.value);\n if (selectedValue.value != null && !selectedTrigger?.disabled) return;\n\n uncontrolledValue.value = firstEnabledTrigger.value?.value ?? null;\n }\n\n function setValue(value: TabsValue) {\n if (isDisabled.value || value === selectedValue.value) return;\n\n if (!isControlled.value) uncontrolledValue.value = value;\n emitUpdate(value);\n }\n\n function selectValue(value: TabsValue) {\n const trigger = findRegistration(triggers.value, value);\n if (isDisabled.value || trigger?.disabled) return;\n\n setValue(value);\n }\n\n const getFocusableValue = () =>\n selectedEnabledTrigger.value?.value ?? firstEnabledTrigger.value?.value ?? null;\n const getTriggerId = (value: TabsValue) => findRegistration(triggers.value, value)?.id;\n const getContentId = (value: TabsValue) => findRegistration(contents.value, value)?.id;\n const getTriggerValue = (id: string) =>\n triggers.value.find((trigger) => trigger.id === id)?.value;\n\n function registerTrigger(registration: TabsTriggerRegistration) {\n triggerRegistry.register(registration);\n syncUncontrolledValue();\n }\n\n function onListKeydown(event: KeyboardEvent) {\n const list = event.currentTarget as HTMLElement | null;\n if (!list || isDisabled.value) return;\n\n const trigger = getTabsTrigger(event, list);\n if (!trigger) return;\n\n const nextTrigger = getNextTrigger(list, trigger, event.key, orientation.value);\n if (!nextTrigger) return;\n\n event.preventDefault();\n nextTrigger.focus();\n\n const nextValue = getTriggerValue(nextTrigger.id);\n if (nextValue !== undefined && activationMode.value === 'automatic') {\n selectValue(nextValue);\n }\n }\n\n provide<TabsContext>(tabsKey, {\n get selectedValue() {\n return selectedValue.value;\n },\n get disabled() {\n return isDisabled.value;\n },\n get size() {\n return size.value;\n },\n get variant() {\n return variant.value;\n },\n get orientation() {\n return orientation.value;\n },\n get placement() {\n return placement.value;\n },\n get align() {\n return align.value;\n },\n get activationMode() {\n return activationMode.value;\n },\n get unmountOnExit() {\n return Boolean(props.unmountOnExit);\n },\n get ariaLabel() {\n return props.ariaLabel;\n },\n get describedby() {\n return props.describedby;\n },\n get labelledby() {\n return props.labelledby;\n },\n isSelected(value) {\n return selectedValue.value === value;\n },\n selectValue,\n getFocusableValue,\n getTriggerId,\n getContentId,\n getTriggerValue,\n registerTrigger,\n unregisterTrigger,\n registerContent,\n unregisterContent,\n onListKeydown,\n });\n\n return { rootClass, rootProps, slotProps, selectedValue, selectValue };\n}\n\nexport function useTabsList(props: Readonly<TabsListProps>): UseTabsListReturn {\n const group = useRequiredInject(tabsKey, 'RpTabsList');\n\n const rootClass = computed(() =>\n bem(\n 'rp-tabs-list',\n group.variant,\n getOrientationClasses(group.disabled, group.orientation),\n getPlacementClasses(group.orientation, group.placement),\n ),\n );\n\n const rootProps = computed<TabsListRootProps>(() => ({\n id: props.id,\n class: rootClass.value,\n role: 'tablist',\n 'data-disabled': optionalAttr(group.disabled),\n 'data-variant': group.variant,\n 'data-orientation': group.orientation,\n 'data-placement': optionalAttr(\n group.orientation === 'vertical' ? group.placement : undefined,\n ),\n 'aria-orientation': group.orientation,\n ...getAriaProps(\n props.ariaLabel ?? group.ariaLabel,\n props.ariaLabelledby ?? group.labelledby,\n props.ariaDescribedby ?? group.describedby,\n ),\n onKeydown: group.onListKeydown,\n }));\n\n const slotProps = computed<TabsListSlotProps>(() => ({\n disabled: group.disabled,\n variant: group.variant,\n orientation: group.orientation,\n placement: group.placement,\n }));\n\n return { rootClass, rootProps, slotProps };\n}\n\nexport function useTabsTrigger(props: Readonly<TabsTriggerProps>): UseTabsTriggerReturn {\n const { group, id, isSelected, state } = useTabsItem('RpTabsTrigger', props, 'tab');\n const isDisabled = computed(() => Boolean(group.disabled || props.disabled));\n const isFocusable = computed(\n () => group.getFocusableValue() === props.value && !isDisabled.value,\n );\n const align = computed<TabsTriggerAlign | undefined>(() => props.align ?? group.align);\n const effectiveAlign = computed(() => align.value ?? getDefaultAlign(group.orientation));\n\n const rootClass = computed(() =>\n bem(\n 'rp-tabs-trigger',\n `size-${group.size}`,\n group.variant,\n getTriggerClasses(\n isSelected.value,\n isDisabled.value,\n group.orientation,\n group.placement,\n align.value,\n ),\n ),\n );\n\n const rootProps = computed<TabsTriggerRootProps>(() => ({\n id: id.value,\n class: rootClass.value,\n role: 'tab',\n type: 'button',\n disabled: optionalAttr(isDisabled.value),\n tabIndex: isFocusable.value ? 0 : -1,\n 'data-state': state.value,\n 'data-disabled': optionalAttr(isDisabled.value),\n 'data-variant': group.variant,\n 'data-align': optionalAttr(align.value),\n 'aria-selected': isSelected.value,\n 'aria-controls': group.getContentId(props.value),\n 'aria-disabled': optionalAttr(isDisabled.value),\n onClick: select,\n onFocus,\n onKeydown,\n }));\n\n const slotProps = computed<TabsTriggerSlotProps>(() => ({\n value: props.value,\n selected: isSelected.value,\n size: group.size,\n variant: group.variant,\n disabled: isDisabled.value,\n align: effectiveAlign.value,\n select,\n }));\n\n useTabsRegistration(\n () => ({\n id: id.value,\n value: props.value,\n disabled: isDisabled.value,\n }),\n group.registerTrigger,\n group.unregisterTrigger,\n () => [id.value, props.value, isDisabled.value] as const,\n );\n\n function select() {\n if (!isDisabled.value) group.selectValue(props.value);\n }\n\n function onFocus() {\n if (group.activationMode === 'automatic') select();\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n\n event.preventDefault();\n select();\n }\n\n return { id, state, isSelected, isDisabled, rootClass, rootProps, slotProps, select };\n}\n\nexport function useTabsContent(props: Readonly<TabsContentProps>): UseTabsContentReturn {\n const { group, id, isSelected, state } = useTabsItem('RpTabsContent', props, 'tabpanel');\n const shouldUnmountOnExit = computed(() => props.unmountOnExit ?? group.unmountOnExit);\n const shouldRenderContent = computed(() => !shouldUnmountOnExit.value || isSelected.value);\n\n const rootClass = computed(() =>\n bem('rp-tabs-content', getStateClasses(isSelected.value), {\n vertical: group.orientation === 'vertical',\n }),\n );\n\n const rootProps = computed<TabsContentRootProps>(() => ({\n id: id.value,\n class: rootClass.value,\n role: 'tabpanel',\n tabIndex: 0,\n hidden: optionalAttr(!isSelected.value),\n 'data-state': state.value,\n ...getAriaProps(\n props.ariaLabel,\n props.ariaLabelledby ?? group.getTriggerId(props.value),\n props.ariaDescribedby,\n ),\n }));\n\n const slotProps = computed<TabsContentSlotProps>(() => ({\n value: props.value,\n selected: isSelected.value,\n }));\n\n useTabsRegistration(\n () => ({\n id: id.value,\n value: props.value,\n }),\n group.registerContent,\n group.unregisterContent,\n () => [id.value, props.value] as const,\n );\n\n return { id, state, isSelected, shouldRenderContent, rootClass, rootProps, slotProps };\n}\n","<template>\n <div v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabs } from './useTabs';\nimport type { TabsProps, TabsValue } from './types';\n\ndefineOptions({ name: 'RpTabs' });\n\nconst props = withDefaults(defineProps<TabsProps>(), {\n modelValue: undefined,\n defaultValue: undefined,\n size: 'md',\n variant: 'line',\n orientation: 'horizontal',\n placement: 'left',\n activationMode: 'automatic',\n disabled: false,\n unmountOnExit: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: TabsValue];\n}>();\n\nconst { rootProps, slotProps } = useTabs(props, (value) => {\n emit('update:modelValue', value);\n});\n</script>\n\n<style src=\"./tabs.scss\" lang=\"scss\" scoped></style>\n","<template>\n <div v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabs } from './useTabs';\nimport type { TabsProps, TabsValue } from './types';\n\ndefineOptions({ name: 'RpTabs' });\n\nconst props = withDefaults(defineProps<TabsProps>(), {\n modelValue: undefined,\n defaultValue: undefined,\n size: 'md',\n variant: 'line',\n orientation: 'horizontal',\n placement: 'left',\n activationMode: 'automatic',\n disabled: false,\n unmountOnExit: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: TabsValue];\n}>();\n\nconst { rootProps, slotProps } = useTabs(props, (value) => {\n emit('update:modelValue', value);\n});\n</script>\n\n<style src=\"./tabs.scss\" lang=\"scss\" scoped></style>\n","<template>\n <section v-if=\"shouldRenderContent\" v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </section>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabsContent } from './useTabs';\nimport type { TabsContentProps } from './types';\n\ndefineOptions({ name: 'RpTabsContent' });\n\nconst props = withDefaults(defineProps<TabsContentProps>(), {\n unmountOnExit: undefined,\n});\n\nconst { rootProps, slotProps, shouldRenderContent } = useTabsContent(props);\n</script>\n\n<style src=\"./tabs-content.scss\" lang=\"scss\" scoped></style>\n","<template>\n <section v-if=\"shouldRenderContent\" v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </section>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabsContent } from './useTabs';\nimport type { TabsContentProps } from './types';\n\ndefineOptions({ name: 'RpTabsContent' });\n\nconst props = withDefaults(defineProps<TabsContentProps>(), {\n unmountOnExit: undefined,\n});\n\nconst { rootProps, slotProps, shouldRenderContent } = useTabsContent(props);\n</script>\n\n<style src=\"./tabs-content.scss\" lang=\"scss\" scoped></style>\n","<template>\n <div v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabsList } from './useTabs';\nimport type { TabsListProps } from './types';\n\ndefineOptions({ name: 'RpTabsList' });\n\nconst props = defineProps<TabsListProps>();\n\nconst { rootProps, slotProps } = useTabsList(props);\n</script>\n\n<style src=\"./tabs-list.scss\" lang=\"scss\" scoped></style>\n","<template>\n <div v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabsList } from './useTabs';\nimport type { TabsListProps } from './types';\n\ndefineOptions({ name: 'RpTabsList' });\n\nconst props = defineProps<TabsListProps>();\n\nconst { rootProps, slotProps } = useTabsList(props);\n</script>\n\n<style src=\"./tabs-list.scss\" lang=\"scss\" scoped></style>\n","<template>\n <button v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </button>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabsTrigger } from './useTabs';\nimport type { TabsTriggerProps } from './types';\n\ndefineOptions({ name: 'RpTabsTrigger' });\n\nconst props = withDefaults(defineProps<TabsTriggerProps>(), {\n disabled: false,\n});\n\nconst { rootProps, slotProps } = useTabsTrigger(props);\n</script>\n\n<style src=\"./tabs-trigger.scss\" lang=\"scss\" scoped></style>\n","<template>\n <button v-bind=\"rootProps\">\n <slot v-bind=\"slotProps\" />\n </button>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTabsTrigger } from './useTabs';\nimport type { TabsTriggerProps } from './types';\n\ndefineOptions({ name: 'RpTabsTrigger' });\n\nconst props = withDefaults(defineProps<TabsTriggerProps>(), {\n disabled: false,\n});\n\nconst { rootProps, slotProps } = useTabsTrigger(props);\n</script>\n\n<style src=\"./tabs-trigger.scss\" lang=\"scss\" scoped></style>\n"],"mappings":";;;;;AAwCA,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAEzB,IAAM,eAAyB;AAC/B,IAAM,kBAA+B;AACrC,IAAM,sBAAuC;AAC7C,IAAM,oBAAmC;AACzC,IAAM,0BAA8C;AAuCpD,IAAM,UAAU,OAAO,MAAM;AAE7B,IAAM,8BAGF;CACA,YAAY;EAAE,YAAY;EAAG,WAAW;CAAG;CAC3C,UAAU;EAAE,WAAW;EAAG,SAAS;CAAG;AAC1C;AAEA,SAAS,aAAqD,OAAyB;CACnF,OAAO,SAAS,KAAA;AACpB;AAEA,SAAS,YAAY,QAA4B;CAC7C,OAAO,SAAS,WAAW;AAC/B;AAEA,SAAS,gBAAgB,aAAgD;CACrE,OAAO,gBAAgB,aAAa,SAAS;AACjD;AAEA,SAAS,aAAa,OAAgB,YAAqB,aAAsB;CAC7E,OAAO;EACH,cAAc,aAAa,KAAK;EAChC,mBAAmB,aAAa,UAAU;EAC1C,oBAAoB,aAAa,WAAW;CAChD;AACJ;AAEA,SAAS,sBAAsB,UAAmB,aAA8B;CAC5E,OAAO;EAAE;GAAW,cAAc;CAAK;AAC3C;AAEA,SAAS,oBAAoB,aAA8B,WAA0B;CACjF,OAAO,GAAG,aAAa,cAAc,gBAAgB,WAAW;AACpE;AAEA,SAAS,gBAAgB,QAAiB;CACtC,OAAO;EAAE;EAAQ,UAAU,CAAC;CAAO;AACvC;AAEA,SAAS,kBACL,QACA,UACA,aACA,WACA,OACF;CACE,OAAO;EACH,GAAG,gBAAgB,MAAM;EACzB,GAAG,sBAAsB,UAAU,WAAW;EAC9C,GAAG,oBAAoB,aAAa,SAAS;EAC7C,GAAI,QAAQ,GAAG,SAAS,UAAU,KAAK,IAAI,CAAC;CAChD;AACJ;AAEA,SAAS,iBACL,SACA,OACF;CACE,IAAI,SAAS,MAAM,OAAO,KAAA;CAC1B,OAAO,QAAQ,MAAM,UAAU,MAAM,UAAU,KAAK;AACxD;AAEA,SAAS,mBAA6C,SAAc,OAAU;CAC1E,MAAM,QAAQ,QAAQ,WAAW,YAAY,QAAQ,OAAO,MAAM,EAAE;CACpE,IAAI,QAAQ,GAAG,OAAO,CAAC,GAAG,SAAS,KAAK;CAExC,MAAM,cAAc,QAAQ,MAAM;CAClC,YAAY,SAAS;CACrB,OAAO;AACX;AAEA,SAAS,kBAA4C;CACjD,MAAM,QAAQ,WAAgB,CAAC,CAAC;CAEhC,OAAO;EACH;EACA,SAAS,OAAU;GACf,MAAM,QAAQ,mBAAmB,MAAM,OAAO,KAAK;EACvD;EACA,WAAW,IAAY;GACnB,MAAM,QAAQ,MAAM,MAAM,QAAQ,SAAS,KAAK,OAAO,EAAE;EAC7D;CACJ;AACJ;AAEA,SAAS,oBACL,iBACA,UACA,YACA,aACF;CACE,MAAM,eAAe,IAAmB,IAAI;CAE5C,SAAS,mBAAmB;EACxB,MAAM,eAAe,gBAAgB;EACrC,IAAI,aAAa,SAAS,aAAa,UAAU,aAAa,IAC1D,WAAW,aAAa,KAAK;EAGjC,SAAS,YAAY;EACrB,aAAa,QAAQ,aAAa;CACtC;CAEA,UAAU,gBAAgB;CAC1B,MAAM,aAAa,gBAAgB;CAEnC,sBAAsB;EAClB,IAAI,aAAa,OAAO,WAAW,aAAa,KAAK;CACzD,CAAC;AACL;AAEA,SAAS,eAAe,OAAsB,MAAmB;CAC7D,MAAM,SAAS,MAAM;CACrB,MAAM,UACF,kBAAkB,UAAU,OAAO,QAA2B,gBAAgB,IAAI,KAAA;CAEtF,OAAO,SAAS,QAAQ,gBAAgB,MAAM,OAAO,UAAU,KAAA;AACnE;AAEA,SAAS,gBAAgB,MAAmB;CACxC,OAAO,MAAM,KAAK,KAAK,iBAAoC,gBAAgB,CAAC,CAAC,CAAC,QACzE,YAAY,QAAQ,QAAQ,gBAAgB,MAAM,QAAQ,CAAC,QAAQ,QACxE;AACJ;AAEA,SAAS,eACL,MACA,gBACA,KACA,aACF;CACE,MAAM,WAAW,gBAAgB,IAAI;CACrC,MAAM,eAAe,SAAS,QAAQ,cAAc;CACpD,IAAI,iBAAiB,MAAM,SAAS,WAAW,GAAG,OAAO,KAAA;CAEzD,IAAI,QAAQ,QAAQ,OAAO,SAAS;CACpC,IAAI,QAAQ,OAAO,OAAO,SAAS,SAAS,SAAS;CAErD,MAAM,YAAY,4BAA4B,YAAY,CAAC;CAC3D,IAAI,CAAC,WAAW,OAAO,KAAA;CAEvB,OAAO,UAAU,eAAe,YAAY,SAAS,UAAU,SAAS;AAC5E;AAEA,SAAS,YACL,eACA,OACA,QACF;CACE,MAAM,QAAQ,kBAAkB,SAAS,aAAa;CACtD,MAAM,cAAc,MAAM;CAC1B,MAAM,KAAK,eAAe,MAAM,MAAM,GAAG,YAAY,GAAG,QAAQ;CAChE,MAAM,aAAa,eAAe,MAAM,WAAW,MAAM,KAAK,CAAC;CAG/D,OAAO;EAAE;EAAO;EAAI;EAAY,OAFlB,eAA0B,YAAY,WAAW,KAAK,CAEpC;CAAM;AAC1C;AAEA,SAAgB,QACZ,OACA,YACa;CACb,MAAM,kBAAkB,gBAAyC;CACjE,MAAM,kBAAkB,gBAAkC;CAC1D,MAAM,EAAE,OAAO,UAAU,YAAY,sBAAsB;CAC3D,MAAM,EACF,OAAO,UACP,UAAU,iBACV,YAAY,sBACZ;CAEJ,MAAM,eAAe,eAAe,MAAM,eAAe,KAAA,CAAS;CAClE,MAAM,oBAAoB,IAAsB,MAAM,gBAAgB,IAAI;CAC1E,MAAM,aAAa,eAAe,QAAQ,MAAM,QAAQ,CAAC;CACzD,MAAM,OAAO,eAAyB,MAAM,QAAQ,YAAY;CAChE,MAAM,UAAU,eAA4B,MAAM,WAAW,eAAe;CAC5E,MAAM,cAAc,eAAgC,MAAM,eAAe,mBAAmB;CAC5F,MAAM,YAAY,eAA8B,MAAM,aAAa,iBAAiB;CACpF,MAAM,QAAQ,eAA6C,MAAM,KAAK;CACtE,MAAM,iBAAiB,eACb,MAAM,kBAAkB,uBAClC;CACA,MAAM,gBAAgB,eAClB,aAAa,QAAS,MAAM,cAAc,OAAQ,kBAAkB,KACxE;CACA,MAAM,sBAAsB,eAAe,SAAS,MAAM,MAAM,YAAY,CAAC,QAAQ,QAAQ,CAAC;CAC9F,MAAM,yBAAyB,eAAe;EAC1C,MAAM,UAAU,iBAAiB,SAAS,OAAO,cAAc,KAAK;EACpE,OAAO,WAAW,CAAC,QAAQ,WAAW,UAAU,KAAA;CACpD,CAAC;CAED,MAAM,YAAY,eACd,IACI,WACA,QAAQ,KAAK,SACb,QAAQ,OACR,sBAAsB,WAAW,OAAO,YAAY,KAAK,GACzD,oBAAoB,YAAY,OAAO,UAAU,KAAK,CAC1D,CACJ;CAEA,MAAM,YAAY,gBAA+B;EAC7C,IAAI,MAAM;EACV,OAAO,UAAU;EACjB,iBAAiB,aAAa,WAAW,KAAK;EAC9C,aAAa,KAAK;EAClB,gBAAgB,QAAQ;EACxB,oBAAoB,YAAY;EAChC,kBAAkB,aACd,YAAY,UAAU,aAAa,UAAU,QAAQ,KAAA,CACzD;EACA,wBAAwB,eAAe;EACvC,GAAG,aAAa,MAAM,WAAW,MAAM,YAAY,MAAM,WAAW;CACxE,EAAE;CAEF,MAAM,YAAY,gBAA+B;EAC7C,OAAO,cAAc;EACrB,MAAM,KAAK;EACX,SAAS,QAAQ;EACjB,UAAU,WAAW;EACrB,WAAW,UAAU;EACrB,OAAO,MAAM,SAAS,gBAAgB,YAAY,KAAK;EACvD,QAAQ;CACZ,EAAE;CAEF,SAAS,wBAAwB;EAC7B,IAAI,aAAa,SAAS,WAAW,OAAO;EAE5C,MAAM,kBAAkB,iBAAiB,SAAS,OAAO,cAAc,KAAK;EAC5E,IAAI,cAAc,SAAS,QAAQ,CAAC,iBAAiB,UAAU;EAE/D,kBAAkB,QAAQ,oBAAoB,OAAO,SAAS;CAClE;CAEA,SAAS,SAAS,OAAkB;EAChC,IAAI,WAAW,SAAS,UAAU,cAAc,OAAO;EAEvD,IAAI,CAAC,aAAa,OAAO,kBAAkB,QAAQ;EACnD,WAAW,KAAK;CACpB;CAEA,SAAS,YAAY,OAAkB;EACnC,MAAM,UAAU,iBAAiB,SAAS,OAAO,KAAK;EACtD,IAAI,WAAW,SAAS,SAAS,UAAU;EAE3C,SAAS,KAAK;CAClB;CAEA,MAAM,0BACF,uBAAuB,OAAO,SAAS,oBAAoB,OAAO,SAAS;CAC/E,MAAM,gBAAgB,UAAqB,iBAAiB,SAAS,OAAO,KAAK,CAAC,EAAE;CACpF,MAAM,gBAAgB,UAAqB,iBAAiB,SAAS,OAAO,KAAK,CAAC,EAAE;CACpF,MAAM,mBAAmB,OACrB,SAAS,MAAM,MAAM,YAAY,QAAQ,OAAO,EAAE,CAAC,EAAE;CAEzD,SAAS,gBAAgB,cAAuC;EAC5D,gBAAgB,SAAS,YAAY;EACrC,sBAAsB;CAC1B;CAEA,SAAS,cAAc,OAAsB;EACzC,MAAM,OAAO,MAAM;EACnB,IAAI,CAAC,QAAQ,WAAW,OAAO;EAE/B,MAAM,UAAU,eAAe,OAAO,IAAI;EAC1C,IAAI,CAAC,SAAS;EAEd,MAAM,cAAc,eAAe,MAAM,SAAS,MAAM,KAAK,YAAY,KAAK;EAC9E,IAAI,CAAC,aAAa;EAElB,MAAM,eAAe;EACrB,YAAY,MAAM;EAElB,MAAM,YAAY,gBAAgB,YAAY,EAAE;EAChD,IAAI,cAAc,KAAA,KAAa,eAAe,UAAU,aACpD,YAAY,SAAS;CAE7B;CAEA,QAAqB,SAAS;EAC1B,IAAI,gBAAgB;GAChB,OAAO,cAAc;EACzB;EACA,IAAI,WAAW;GACX,OAAO,WAAW;EACtB;EACA,IAAI,OAAO;GACP,OAAO,KAAK;EAChB;EACA,IAAI,UAAU;GACV,OAAO,QAAQ;EACnB;EACA,IAAI,cAAc;GACd,OAAO,YAAY;EACvB;EACA,IAAI,YAAY;GACZ,OAAO,UAAU;EACrB;EACA,IAAI,QAAQ;GACR,OAAO,MAAM;EACjB;EACA,IAAI,iBAAiB;GACjB,OAAO,eAAe;EAC1B;EACA,IAAI,gBAAgB;GAChB,OAAO,QAAQ,MAAM,aAAa;EACtC;EACA,IAAI,YAAY;GACZ,OAAO,MAAM;EACjB;EACA,IAAI,cAAc;GACd,OAAO,MAAM;EACjB;EACA,IAAI,aAAa;GACb,OAAO,MAAM;EACjB;EACA,WAAW,OAAO;GACd,OAAO,cAAc,UAAU;EACnC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACJ,CAAC;CAED,OAAO;EAAE;EAAW;EAAW;EAAW;EAAe;CAAY;AACzE;AAEA,SAAgB,YAAY,OAAmD;CAC3E,MAAM,QAAQ,kBAAkB,SAAS,YAAY;CAErD,MAAM,YAAY,eACd,IACI,gBACA,MAAM,SACN,sBAAsB,MAAM,UAAU,MAAM,WAAW,GACvD,oBAAoB,MAAM,aAAa,MAAM,SAAS,CAC1D,CACJ;CA4BA,OAAO;EAAE;EAAW,WA1BF,gBAAmC;GACjD,IAAI,MAAM;GACV,OAAO,UAAU;GACjB,MAAM;GACN,iBAAiB,aAAa,MAAM,QAAQ;GAC5C,gBAAgB,MAAM;GACtB,oBAAoB,MAAM;GAC1B,kBAAkB,aACd,MAAM,gBAAgB,aAAa,MAAM,YAAY,KAAA,CACzD;GACA,oBAAoB,MAAM;GAC1B,GAAG,aACC,MAAM,aAAa,MAAM,WACzB,MAAM,kBAAkB,MAAM,YAC9B,MAAM,mBAAmB,MAAM,WACnC;GACA,WAAW,MAAM;EACrB,EASoB;EAAW,WAPb,gBAAmC;GACjD,UAAU,MAAM;GAChB,SAAS,MAAM;GACf,aAAa,MAAM;GACnB,WAAW,MAAM;EACrB,EAE+B;CAAU;AAC7C;AAEA,SAAgB,eAAe,OAAyD;CACpF,MAAM,EAAE,OAAO,IAAI,YAAY,UAAU,YAAY,iBAAiB,OAAO,KAAK;CAClF,MAAM,aAAa,eAAe,QAAQ,MAAM,YAAY,MAAM,QAAQ,CAAC;CAC3E,MAAM,cAAc,eACV,MAAM,kBAAkB,MAAM,MAAM,SAAS,CAAC,WAAW,KACnE;CACA,MAAM,QAAQ,eAA6C,MAAM,SAAS,MAAM,KAAK;CACrF,MAAM,iBAAiB,eAAe,MAAM,SAAS,gBAAgB,MAAM,WAAW,CAAC;CAEvF,MAAM,YAAY,eACd,IACI,mBACA,QAAQ,MAAM,QACd,MAAM,SACN,kBACI,WAAW,OACX,WAAW,OACX,MAAM,aACN,MAAM,WACN,MAAM,KACV,CACJ,CACJ;CAEA,MAAM,YAAY,gBAAsC;EACpD,IAAI,GAAG;EACP,OAAO,UAAU;EACjB,MAAM;EACN,MAAM;EACN,UAAU,aAAa,WAAW,KAAK;EACvC,UAAU,YAAY,QAAQ,IAAI;EAClC,cAAc,MAAM;EACpB,iBAAiB,aAAa,WAAW,KAAK;EAC9C,gBAAgB,MAAM;EACtB,cAAc,aAAa,MAAM,KAAK;EACtC,iBAAiB,WAAW;EAC5B,iBAAiB,MAAM,aAAa,MAAM,KAAK;EAC/C,iBAAiB,aAAa,WAAW,KAAK;EAC9C,SAAS;EACT;EACA;CACJ,EAAE;CAEF,MAAM,YAAY,gBAAsC;EACpD,OAAO,MAAM;EACb,UAAU,WAAW;EACrB,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,UAAU,WAAW;EACrB,OAAO,eAAe;EACtB;CACJ,EAAE;CAEF,2BACW;EACH,IAAI,GAAG;EACP,OAAO,MAAM;EACb,UAAU,WAAW;CACzB,IACA,MAAM,iBACN,MAAM,yBACA;EAAC,GAAG;EAAO,MAAM;EAAO,WAAW;CAAK,CAClD;CAEA,SAAS,SAAS;EACd,IAAI,CAAC,WAAW,OAAO,MAAM,YAAY,MAAM,KAAK;CACxD;CAEA,SAAS,UAAU;EACf,IAAI,MAAM,mBAAmB,aAAa,OAAO;CACrD;CAEA,SAAS,UAAU,OAAsB;EACrC,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;EAEhD,MAAM,eAAe;EACrB,OAAO;CACX;CAEA,OAAO;EAAE;EAAI;EAAO;EAAY;EAAY;EAAW;EAAW;EAAW;CAAO;AACxF;AAEA,SAAgB,eAAe,OAAyD;CACpF,MAAM,EAAE,OAAO,IAAI,YAAY,UAAU,YAAY,iBAAiB,OAAO,UAAU;CACvF,MAAM,sBAAsB,eAAe,MAAM,iBAAiB,MAAM,aAAa;CACrF,MAAM,sBAAsB,eAAe,CAAC,oBAAoB,SAAS,WAAW,KAAK;CAEzF,MAAM,YAAY,eACd,IAAI,mBAAmB,gBAAgB,WAAW,KAAK,GAAG,EACtD,UAAU,MAAM,gBAAgB,WACpC,CAAC,CACL;CAEA,MAAM,YAAY,gBAAsC;EACpD,IAAI,GAAG;EACP,OAAO,UAAU;EACjB,MAAM;EACN,UAAU;EACV,QAAQ,aAAa,CAAC,WAAW,KAAK;EACtC,cAAc,MAAM;EACpB,GAAG,aACC,MAAM,WACN,MAAM,kBAAkB,MAAM,aAAa,MAAM,KAAK,GACtD,MAAM,eACV;CACJ,EAAE;CAEF,MAAM,YAAY,gBAAsC;EACpD,OAAO,MAAM;EACb,UAAU,WAAW;CACzB,EAAE;CAEF,2BACW;EACH,IAAI,GAAG;EACP,OAAO,MAAM;CACjB,IACA,MAAM,iBACN,MAAM,yBACA,CAAC,GAAG,OAAO,MAAM,KAAK,CAChC;CAEA,OAAO;EAAE;EAAI;EAAO;EAAY;EAAqB;EAAW;EAAW;CAAU;AACzF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC/jBA,MAAM,QAAQ;EAYd,MAAM,OAAO;EAIb,MAAM,EAAE,WAAW,cAAc,QAAQ,QAAQ,UAAU;GACvD,KAAK,qBAAqB,KAAK;EACnC,CAAC;;0CA7BgB,MAAA,SAAA,CAAS,CAAA,CAAA;;oCACJ,MAAA,SAAA,CAAA,EAAA,GAAA,MAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;EEctB,MAAM,EAAE,WAAW,WAAW,wBAAwB,eAAe,OAAK;wBAfvD,MAAA,mBAAA,SAAmB;;2CAAU,MAAA,SAAA,CAAS,CAAA,CAAA;;qCACnC,MAAA,SAAA,CAAA,EAAA,GAAA,MAAA,CAAA;;;;;;;;;;;;;;;;;;;;EEYtB,MAAM,EAAE,WAAW,cAAc,YAAY,OAAK;;0CAbjC,MAAA,SAAA,CAAS,CAAA,CAAA;;oCACJ,MAAA,SAAA,CAAA,EAAA,GAAA,MAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;EEctB,MAAM,EAAE,WAAW,cAAc,eAAe,OAAK;;0CAfjC,MAAA,SAAA,CAAS,CAAA,CAAA;;oCACP,MAAA,SAAA,CAAA,EAAA,GAAA,MAAA,CAAA"}
|
package/dist/textarea.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import './textarea.css';
|
|
2
|
-
import {
|
|
2
|
+
import { t as bem } from "./bem.js";
|
|
3
|
+
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
|
|
3
4
|
import { t as useControlState } from "./useControlState.js";
|
|
4
5
|
import { child, computed, createInvoker, createTemplateRefSetter, defineVaporComponent, delegateEvents, nextTick, onMounted, ref, renderEffect, setAttr, setClass, setProp, setValue, template, unref, watch } from "vue";
|
|
5
6
|
//#region src/components/textarea/useTextarea.ts
|
package/dist/textarea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textarea.js","names":[],"sources":["../src/components/textarea/useTextarea.ts","../src/components/textarea/textarea.vue","../src/components/textarea/textarea.vue"],"sourcesContent":["import { computed, nextTick, onMounted, ref, watch } from 'vue';\nimport { useControlState } from '@/composables/useControlState';\nimport { bem } from '@/utils/bem';\nimport type { TextareaProps } from './types';\n\nconst MIN_ROWS = 1;\nconst NATIVE_TEXTAREA_SELECTOR = '.rp-textarea__native';\nconst INTERACTIVE_SELECTOR = [\n 'button',\n 'a[href]',\n 'input',\n 'select',\n `textarea:not(${NATIVE_TEXTAREA_SELECTOR})`,\n '[contenteditable=\"true\"]',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\ninterface AutosizeRows {\n minRows: number;\n maxRows: number | undefined;\n}\n\ninterface TextareaMetrics {\n lineHeight: number;\n paddingHeight: number;\n borderHeight: number;\n}\n\nfunction isInteractiveElement(target: Element) {\n return Boolean(target.closest(INTERACTIVE_SELECTOR));\n}\n\nfunction normalizeRows(value: number | undefined, fallback?: number) {\n if (value === undefined || !Number.isFinite(value)) return fallback;\n return Math.max(MIN_ROWS, Math.floor(value));\n}\n\nfunction getPixelValue(value: string) {\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nfunction getLineHeight(styles: CSSStyleDeclaration) {\n const lineHeight = getPixelValue(styles.lineHeight);\n if (lineHeight > 0) return lineHeight;\n\n const fontSize = getPixelValue(styles.fontSize);\n return fontSize > 0 ? fontSize * 1.2 : 0;\n}\n\nfunction getTextareaMetrics(textarea: HTMLTextAreaElement): TextareaMetrics {\n const styles = getComputedStyle(textarea);\n\n return {\n lineHeight: getLineHeight(styles),\n paddingHeight: getPixelValue(styles.paddingTop) + getPixelValue(styles.paddingBottom),\n borderHeight:\n getPixelValue(styles.borderTopWidth) + getPixelValue(styles.borderBottomWidth),\n };\n}\n\nfunction getRowsHeight(metrics: TextareaMetrics, rows: number) {\n return rows * metrics.lineHeight + metrics.paddingHeight + metrics.borderHeight;\n}\n\nfunction getAutosizeMeasurement(textarea: HTMLTextAreaElement, rows: AutosizeRows) {\n const metrics = getTextareaMetrics(textarea);\n const maxHeight = rows.maxRows === undefined ? undefined : getRowsHeight(metrics, rows.maxRows);\n\n return {\n contentHeight: textarea.scrollHeight + metrics.borderHeight,\n minHeight: getRowsHeight(metrics, rows.minRows),\n maxHeight,\n };\n}\n\nfunction resetTextareaHeight(textarea: HTMLTextAreaElement) {\n textarea.style.height = '';\n textarea.style.overflowY = '';\n}\n\nexport function useTextarea(props: Readonly<TextareaProps>, emitUpdate: (value: string) => void) {\n const textareaRef = ref<HTMLTextAreaElement | null>(null);\n const control = useControlState(props);\n\n const autosizeRows = computed<AutosizeRows>(() => {\n const minRows =\n normalizeRows(props.minRows, normalizeRows(props.rows, MIN_ROWS)) ?? MIN_ROWS;\n const maxRows = normalizeRows(props.maxRows);\n\n return {\n minRows,\n maxRows: maxRows === undefined ? undefined : Math.max(minRows, maxRows),\n };\n });\n\n const nativeRows = computed(() => (props.autosize ? autosizeRows.value.minRows : props.rows));\n\n const rootClass = computed(() =>\n bem('rp-textarea', {\n [`size-${props.size}`]: Boolean(props.size),\n [`radius-${props.radius}`]: Boolean(props.radius),\n [`resize-${props.resize}`]: props.resize !== undefined && props.resize !== 'none',\n autosize: props.autosize,\n disabled: control.disabled,\n invalid: control.invalid,\n valid: control.valid && !control.invalid,\n readonly: props.readonly,\n }),\n );\n\n const autosizeWatchSource = computed(() => [\n props.modelValue,\n props.autosize,\n props.minRows,\n props.maxRows,\n props.rows,\n props.size,\n ]);\n\n function syncTextareaHeight() {\n const textarea = textareaRef.value;\n if (!textarea) return;\n\n if (!props.autosize) {\n resetTextareaHeight(textarea);\n return;\n }\n\n textarea.style.height = 'auto';\n\n const { contentHeight, minHeight, maxHeight } = getAutosizeMeasurement(\n textarea,\n autosizeRows.value,\n );\n const heightLimit = maxHeight ?? Number.POSITIVE_INFINITY;\n const nextHeight = Math.min(Math.max(contentHeight, minHeight), heightLimit);\n\n textarea.style.height = `${nextHeight}px`;\n textarea.style.overflowY =\n maxHeight !== undefined && contentHeight > maxHeight ? 'auto' : 'hidden';\n }\n\n function scheduleTextareaHeightSync() {\n void nextTick(syncTextareaHeight);\n }\n\n function onInput(e: Event) {\n emitUpdate((e.target as HTMLTextAreaElement).value);\n syncTextareaHeight();\n }\n\n function focusTextarea(e: MouseEvent) {\n if (control.disabled) return;\n\n const target = e.target;\n if (target instanceof Element && isInteractiveElement(target)) return;\n\n textareaRef.value?.focus();\n }\n\n onMounted(scheduleTextareaHeightSync);\n\n watch(autosizeWatchSource, scheduleTextareaHeightSync);\n\n return {\n textareaRef,\n control,\n rootClass,\n nativeRows,\n onInput,\n focusTextarea,\n };\n}\n","<template>\n <div :class=\"rootClass\" @mousedown=\"focusTextarea\">\n <textarea\n :id=\"control.id\"\n ref=\"textareaRef\"\n :name=\"name\"\n class=\"rp-textarea__native\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :rows=\"nativeRows\"\n :disabled=\"control.disabled || undefined\"\n :readonly=\"readonly || undefined\"\n :required=\"control.required || undefined\"\n :aria-label=\"ariaLabel || undefined\"\n :aria-labelledby=\"control.ariaLabelledby\"\n :aria-describedby=\"control.ariaDescribedby\"\n :aria-invalid=\"control.invalid || undefined\"\n :aria-required=\"control.required || undefined\"\n @input=\"onInput\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTextarea } from './useTextarea';\nimport type { TextareaProps } from './types';\n\ndefineOptions({ name: 'RpTextarea' });\n\nconst props = withDefaults(defineProps<TextareaProps>(), {\n placeholder: '',\n rows: 3,\n resize: 'none',\n autosize: false,\n minRows: undefined,\n maxRows: undefined,\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n valid: undefined,\n readonly: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string];\n}>();\n\nconst { textareaRef, control, rootClass, nativeRows, onInput, focusTextarea } = useTextarea(\n props,\n (value) => {\n emit('update:modelValue', value);\n },\n);\n\nvoid textareaRef;\n</script>\n\n<style src=\"./textarea.scss\" lang=\"scss\" scoped></style>\n","<template>\n <div :class=\"rootClass\" @mousedown=\"focusTextarea\">\n <textarea\n :id=\"control.id\"\n ref=\"textareaRef\"\n :name=\"name\"\n class=\"rp-textarea__native\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :rows=\"nativeRows\"\n :disabled=\"control.disabled || undefined\"\n :readonly=\"readonly || undefined\"\n :required=\"control.required || undefined\"\n :aria-label=\"ariaLabel || undefined\"\n :aria-labelledby=\"control.ariaLabelledby\"\n :aria-describedby=\"control.ariaDescribedby\"\n :aria-invalid=\"control.invalid || undefined\"\n :aria-required=\"control.required || undefined\"\n @input=\"onInput\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTextarea } from './useTextarea';\nimport type { TextareaProps } from './types';\n\ndefineOptions({ name: 'RpTextarea' });\n\nconst props = withDefaults(defineProps<TextareaProps>(), {\n placeholder: '',\n rows: 3,\n resize: 'none',\n autosize: false,\n minRows: undefined,\n maxRows: undefined,\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n valid: undefined,\n readonly: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string];\n}>();\n\nconst { textareaRef, control, rootClass, nativeRows, onInput, focusTextarea } = useTextarea(\n props,\n (value) => {\n emit('update:modelValue', value);\n },\n);\n\nvoid textareaRef;\n</script>\n\n<style src=\"./textarea.scss\" lang=\"scss\" scoped></style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"textarea.js","names":[],"sources":["../src/components/textarea/useTextarea.ts","../src/components/textarea/textarea.vue","../src/components/textarea/textarea.vue"],"sourcesContent":["import { computed, nextTick, onMounted, ref, watch } from 'vue';\nimport { useControlState } from '@/composables/useControlState';\nimport { bem } from '@/utils/bem';\nimport type { TextareaProps } from './types';\n\nconst MIN_ROWS = 1;\nconst NATIVE_TEXTAREA_SELECTOR = '.rp-textarea__native';\nconst INTERACTIVE_SELECTOR = [\n 'button',\n 'a[href]',\n 'input',\n 'select',\n `textarea:not(${NATIVE_TEXTAREA_SELECTOR})`,\n '[contenteditable=\"true\"]',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\ninterface AutosizeRows {\n minRows: number;\n maxRows: number | undefined;\n}\n\ninterface TextareaMetrics {\n lineHeight: number;\n paddingHeight: number;\n borderHeight: number;\n}\n\nfunction isInteractiveElement(target: Element) {\n return Boolean(target.closest(INTERACTIVE_SELECTOR));\n}\n\nfunction normalizeRows(value: number | undefined, fallback?: number) {\n if (value === undefined || !Number.isFinite(value)) return fallback;\n return Math.max(MIN_ROWS, Math.floor(value));\n}\n\nfunction getPixelValue(value: string) {\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nfunction getLineHeight(styles: CSSStyleDeclaration) {\n const lineHeight = getPixelValue(styles.lineHeight);\n if (lineHeight > 0) return lineHeight;\n\n const fontSize = getPixelValue(styles.fontSize);\n return fontSize > 0 ? fontSize * 1.2 : 0;\n}\n\nfunction getTextareaMetrics(textarea: HTMLTextAreaElement): TextareaMetrics {\n const styles = getComputedStyle(textarea);\n\n return {\n lineHeight: getLineHeight(styles),\n paddingHeight: getPixelValue(styles.paddingTop) + getPixelValue(styles.paddingBottom),\n borderHeight:\n getPixelValue(styles.borderTopWidth) + getPixelValue(styles.borderBottomWidth),\n };\n}\n\nfunction getRowsHeight(metrics: TextareaMetrics, rows: number) {\n return rows * metrics.lineHeight + metrics.paddingHeight + metrics.borderHeight;\n}\n\nfunction getAutosizeMeasurement(textarea: HTMLTextAreaElement, rows: AutosizeRows) {\n const metrics = getTextareaMetrics(textarea);\n const maxHeight = rows.maxRows === undefined ? undefined : getRowsHeight(metrics, rows.maxRows);\n\n return {\n contentHeight: textarea.scrollHeight + metrics.borderHeight,\n minHeight: getRowsHeight(metrics, rows.minRows),\n maxHeight,\n };\n}\n\nfunction resetTextareaHeight(textarea: HTMLTextAreaElement) {\n textarea.style.height = '';\n textarea.style.overflowY = '';\n}\n\nexport function useTextarea(props: Readonly<TextareaProps>, emitUpdate: (value: string) => void) {\n const textareaRef = ref<HTMLTextAreaElement | null>(null);\n const control = useControlState(props);\n\n const autosizeRows = computed<AutosizeRows>(() => {\n const minRows =\n normalizeRows(props.minRows, normalizeRows(props.rows, MIN_ROWS)) ?? MIN_ROWS;\n const maxRows = normalizeRows(props.maxRows);\n\n return {\n minRows,\n maxRows: maxRows === undefined ? undefined : Math.max(minRows, maxRows),\n };\n });\n\n const nativeRows = computed(() => (props.autosize ? autosizeRows.value.minRows : props.rows));\n\n const rootClass = computed(() =>\n bem('rp-textarea', {\n [`size-${props.size}`]: Boolean(props.size),\n [`radius-${props.radius}`]: Boolean(props.radius),\n [`resize-${props.resize}`]: props.resize !== undefined && props.resize !== 'none',\n autosize: props.autosize,\n disabled: control.disabled,\n invalid: control.invalid,\n valid: control.valid && !control.invalid,\n readonly: props.readonly,\n }),\n );\n\n const autosizeWatchSource = computed(() => [\n props.modelValue,\n props.autosize,\n props.minRows,\n props.maxRows,\n props.rows,\n props.size,\n ]);\n\n function syncTextareaHeight() {\n const textarea = textareaRef.value;\n if (!textarea) return;\n\n if (!props.autosize) {\n resetTextareaHeight(textarea);\n return;\n }\n\n textarea.style.height = 'auto';\n\n const { contentHeight, minHeight, maxHeight } = getAutosizeMeasurement(\n textarea,\n autosizeRows.value,\n );\n const heightLimit = maxHeight ?? Number.POSITIVE_INFINITY;\n const nextHeight = Math.min(Math.max(contentHeight, minHeight), heightLimit);\n\n textarea.style.height = `${nextHeight}px`;\n textarea.style.overflowY =\n maxHeight !== undefined && contentHeight > maxHeight ? 'auto' : 'hidden';\n }\n\n function scheduleTextareaHeightSync() {\n void nextTick(syncTextareaHeight);\n }\n\n function onInput(e: Event) {\n emitUpdate((e.target as HTMLTextAreaElement).value);\n syncTextareaHeight();\n }\n\n function focusTextarea(e: MouseEvent) {\n if (control.disabled) return;\n\n const target = e.target;\n if (target instanceof Element && isInteractiveElement(target)) return;\n\n textareaRef.value?.focus();\n }\n\n onMounted(scheduleTextareaHeightSync);\n\n watch(autosizeWatchSource, scheduleTextareaHeightSync);\n\n return {\n textareaRef,\n control,\n rootClass,\n nativeRows,\n onInput,\n focusTextarea,\n };\n}\n","<template>\n <div :class=\"rootClass\" @mousedown=\"focusTextarea\">\n <textarea\n :id=\"control.id\"\n ref=\"textareaRef\"\n :name=\"name\"\n class=\"rp-textarea__native\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :rows=\"nativeRows\"\n :disabled=\"control.disabled || undefined\"\n :readonly=\"readonly || undefined\"\n :required=\"control.required || undefined\"\n :aria-label=\"ariaLabel || undefined\"\n :aria-labelledby=\"control.ariaLabelledby\"\n :aria-describedby=\"control.ariaDescribedby\"\n :aria-invalid=\"control.invalid || undefined\"\n :aria-required=\"control.required || undefined\"\n @input=\"onInput\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTextarea } from './useTextarea';\nimport type { TextareaProps } from './types';\n\ndefineOptions({ name: 'RpTextarea' });\n\nconst props = withDefaults(defineProps<TextareaProps>(), {\n placeholder: '',\n rows: 3,\n resize: 'none',\n autosize: false,\n minRows: undefined,\n maxRows: undefined,\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n valid: undefined,\n readonly: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string];\n}>();\n\nconst { textareaRef, control, rootClass, nativeRows, onInput, focusTextarea } = useTextarea(\n props,\n (value) => {\n emit('update:modelValue', value);\n },\n);\n\nvoid textareaRef;\n</script>\n\n<style src=\"./textarea.scss\" lang=\"scss\" scoped></style>\n","<template>\n <div :class=\"rootClass\" @mousedown=\"focusTextarea\">\n <textarea\n :id=\"control.id\"\n ref=\"textareaRef\"\n :name=\"name\"\n class=\"rp-textarea__native\"\n :value=\"modelValue\"\n :placeholder=\"placeholder\"\n :rows=\"nativeRows\"\n :disabled=\"control.disabled || undefined\"\n :readonly=\"readonly || undefined\"\n :required=\"control.required || undefined\"\n :aria-label=\"ariaLabel || undefined\"\n :aria-labelledby=\"control.ariaLabelledby\"\n :aria-describedby=\"control.ariaDescribedby\"\n :aria-invalid=\"control.invalid || undefined\"\n :aria-required=\"control.required || undefined\"\n @input=\"onInput\"\n />\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useTextarea } from './useTextarea';\nimport type { TextareaProps } from './types';\n\ndefineOptions({ name: 'RpTextarea' });\n\nconst props = withDefaults(defineProps<TextareaProps>(), {\n placeholder: '',\n rows: 3,\n resize: 'none',\n autosize: false,\n minRows: undefined,\n maxRows: undefined,\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n valid: undefined,\n readonly: false,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string];\n}>();\n\nconst { textareaRef, control, rootClass, nativeRows, onInput, focusTextarea } = useTextarea(\n props,\n (value) => {\n emit('update:modelValue', value);\n },\n);\n\nvoid textareaRef;\n</script>\n\n<style src=\"./textarea.scss\" lang=\"scss\" scoped></style>\n"],"mappings":";;;;;AAKA,IAAM,WAAW;AAEjB,IAAM,uBAAuB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;AACJ,CAAC,CAAC,KAAK,GAAG;AAaV,SAAS,qBAAqB,QAAiB;CAC3C,OAAO,QAAQ,OAAO,QAAQ,oBAAoB,CAAC;AACvD;AAEA,SAAS,cAAc,OAA2B,UAAmB;CACjE,IAAI,UAAU,KAAA,KAAa,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CAC3D,OAAO,KAAK,IAAI,UAAU,KAAK,MAAM,KAAK,CAAC;AAC/C;AAEA,SAAS,cAAc,OAAe;CAClC,MAAM,SAAS,OAAO,WAAW,KAAK;CACtC,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC9C;AAEA,SAAS,cAAc,QAA6B;CAChD,MAAM,aAAa,cAAc,OAAO,UAAU;CAClD,IAAI,aAAa,GAAG,OAAO;CAE3B,MAAM,WAAW,cAAc,OAAO,QAAQ;CAC9C,OAAO,WAAW,IAAI,WAAW,MAAM;AAC3C;AAEA,SAAS,mBAAmB,UAAgD;CACxE,MAAM,SAAS,iBAAiB,QAAQ;CAExC,OAAO;EACH,YAAY,cAAc,MAAM;EAChC,eAAe,cAAc,OAAO,UAAU,IAAI,cAAc,OAAO,aAAa;EACpF,cACI,cAAc,OAAO,cAAc,IAAI,cAAc,OAAO,iBAAiB;CACrF;AACJ;AAEA,SAAS,cAAc,SAA0B,MAAc;CAC3D,OAAO,OAAO,QAAQ,aAAa,QAAQ,gBAAgB,QAAQ;AACvE;AAEA,SAAS,uBAAuB,UAA+B,MAAoB;CAC/E,MAAM,UAAU,mBAAmB,QAAQ;CAC3C,MAAM,YAAY,KAAK,YAAY,KAAA,IAAY,KAAA,IAAY,cAAc,SAAS,KAAK,OAAO;CAE9F,OAAO;EACH,eAAe,SAAS,eAAe,QAAQ;EAC/C,WAAW,cAAc,SAAS,KAAK,OAAO;EAC9C;CACJ;AACJ;AAEA,SAAS,oBAAoB,UAA+B;CACxD,SAAS,MAAM,SAAS;CACxB,SAAS,MAAM,YAAY;AAC/B;AAEA,SAAgB,YAAY,OAAgC,YAAqC;CAC7F,MAAM,cAAc,IAAgC,IAAI;CACxD,MAAM,UAAU,gBAAgB,KAAK;CAErC,MAAM,eAAe,eAA6B;EAC9C,MAAM,UACF,cAAc,MAAM,SAAS,cAAc,MAAM,MAAM,QAAQ,CAAC,KAAK;EACzE,MAAM,UAAU,cAAc,MAAM,OAAO;EAE3C,OAAO;GACH;GACA,SAAS,YAAY,KAAA,IAAY,KAAA,IAAY,KAAK,IAAI,SAAS,OAAO;EAC1E;CACJ,CAAC;CAED,MAAM,aAAa,eAAgB,MAAM,WAAW,aAAa,MAAM,UAAU,MAAM,IAAK;CAE5F,MAAM,YAAY,eACd,IAAI,eAAe;GACd,QAAQ,MAAM,SAAS,QAAQ,MAAM,IAAI;GACzC,UAAU,MAAM,WAAW,QAAQ,MAAM,MAAM;GAC/C,UAAU,MAAM,WAAW,MAAM,WAAW,KAAA,KAAa,MAAM,WAAW;EAC3E,UAAU,MAAM;EAChB,UAAU,QAAQ;EAClB,SAAS,QAAQ;EACjB,OAAO,QAAQ,SAAS,CAAC,QAAQ;EACjC,UAAU,MAAM;CACpB,CAAC,CACL;CAEA,MAAM,sBAAsB,eAAe;EACvC,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;CACV,CAAC;CAED,SAAS,qBAAqB;EAC1B,MAAM,WAAW,YAAY;EAC7B,IAAI,CAAC,UAAU;EAEf,IAAI,CAAC,MAAM,UAAU;GACjB,oBAAoB,QAAQ;GAC5B;EACJ;EAEA,SAAS,MAAM,SAAS;EAExB,MAAM,EAAE,eAAe,WAAW,cAAc,uBAC5C,UACA,aAAa,KACjB;EACA,MAAM,cAAc,aAAa,OAAO;EACxC,MAAM,aAAa,KAAK,IAAI,KAAK,IAAI,eAAe,SAAS,GAAG,WAAW;EAE3E,SAAS,MAAM,SAAS,GAAG,WAAW;EACtC,SAAS,MAAM,YACX,cAAc,KAAA,KAAa,gBAAgB,YAAY,SAAS;CACxE;CAEA,SAAS,6BAA6B;EAClC,SAAc,kBAAkB;CACpC;CAEA,SAAS,QAAQ,GAAU;EACvB,WAAY,EAAE,OAA+B,KAAK;EAClD,mBAAmB;CACvB;CAEA,SAAS,cAAc,GAAe;EAClC,IAAI,QAAQ,UAAU;EAEtB,MAAM,SAAS,EAAE;EACjB,IAAI,kBAAkB,WAAW,qBAAqB,MAAM,GAAG;EAE/D,YAAY,OAAO,MAAM;CAC7B;CAEA,UAAU,0BAA0B;CAEpC,MAAM,qBAAqB,0BAA0B;CAErD,OAAO;EACH;EACA;EACA;EACA;EACA;EACA;CACJ;AACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EChJA,MAAM,QAAQ;EAcd,MAAM,OAAO;EAIb,MAAM,EAAE,aAAa,SAAS,WAAW,YAAY,SAAS,kBAAkB,YAC5E,QACC,UAAU;GACP,KAAK,qBAAqB,KAAK;EACnC,CACJ;;;;sCAlCoB,MAAA,OAAA,CAAO,CAAA,CAAA,CAAA;;0CAjBa,MAAA,aAAA,CAAa,CAAA,CAAA,CAAA;;;;gBAApC,MAAA,SAAA,CAAS;eAEb,MAAI,SAAO,EAAA;eAEX,QAAM,QAAA,IAAI;gBAEH,QAAA,UAAU;eACjB,eAAa,QAAA,WAAW;eACxB,QAAM,MAAA,UAAA,CAAU;eAChB,YAAU,SAAO,YAAa,KAAA,CAAS;eACvC,YAAU,QAAA,YAAY,KAAA,CAAS;eAC/B,YAAU,qBAAoB,KAAA,CAAS;eACvC,cAAY,QAAA,aAAa,KAAA,CAAS;eAClC,mBAAiB,SAAO,cAAA;eACxB,oBAAkB,SAAO,eAAA;eACzB,gBAAc,SAAO,WAAY,KAAA,CAAS;eAC1C,iBAAe,qBAAoB,KAAA,CAAS"}
|