ropav 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +31 -0
  2. package/dist/_plugin-vue_export-helper.js +18 -0
  3. package/dist/_plugin-vue_export-helper.js.map +1 -0
  4. package/dist/base.css +147 -0
  5. package/dist/button.css +66 -0
  6. package/dist/button.js +62 -0
  7. package/dist/button.js.map +1 -0
  8. package/dist/checkbox.css +60 -0
  9. package/dist/checkbox.js +132 -0
  10. package/dist/checkbox.js.map +1 -0
  11. package/dist/components/_internal/icons/CheckIcon.d.ts +18 -0
  12. package/dist/components/_internal/icons/ChevronDownIcon.d.ts +18 -0
  13. package/dist/components/_internal/icons/MinusIcon.d.ts +18 -0
  14. package/dist/components/_internal/icons/index.d.ts +3 -0
  15. package/dist/components/_internal/optionList.d.ts +9 -0
  16. package/dist/components/button/button.d.ts +25 -0
  17. package/dist/components/button/index.d.ts +2 -0
  18. package/dist/components/button/index.js +2 -0
  19. package/dist/components/button/types.d.ts +6 -0
  20. package/dist/components/checkbox/checkbox.d.ts +23 -0
  21. package/dist/components/checkbox/index.d.ts +2 -0
  22. package/dist/components/checkbox/index.js +2 -0
  23. package/dist/components/checkbox/types.d.ts +12 -0
  24. package/dist/components/checkbox/useCheckbox.d.ts +6 -0
  25. package/dist/components/input/index.d.ts +2 -0
  26. package/dist/components/input/index.js +2 -0
  27. package/dist/components/input/input.d.ts +21 -0
  28. package/dist/components/input/types.d.ts +14 -0
  29. package/dist/components/radio/index.d.ts +3 -0
  30. package/dist/components/radio/index.js +2 -0
  31. package/dist/components/radio/radio-group.d.ts +23 -0
  32. package/dist/components/radio/radio.d.ts +21 -0
  33. package/dist/components/radio/types.d.ts +24 -0
  34. package/dist/components/radio/useRadio.d.ts +12 -0
  35. package/dist/components/select/index.d.ts +2 -0
  36. package/dist/components/select/index.js +2 -0
  37. package/dist/components/select/select.d.ts +23 -0
  38. package/dist/components/select/types.d.ts +18 -0
  39. package/dist/components/select/useSelect.d.ts +21 -0
  40. package/dist/components/switch/index.d.ts +2 -0
  41. package/dist/components/switch/index.js +2 -0
  42. package/dist/components/switch/switch.d.ts +23 -0
  43. package/dist/components/switch/types.d.ts +11 -0
  44. package/dist/components/switch/useSwitch.d.ts +6 -0
  45. package/dist/components/tabs/index.d.ts +5 -0
  46. package/dist/components/tabs/index.js +2 -0
  47. package/dist/components/tabs/tab-panel.d.ts +21 -0
  48. package/dist/components/tabs/tabs-list.d.ts +20 -0
  49. package/dist/components/tabs/tabs-trigger.d.ts +21 -0
  50. package/dist/components/tabs/tabs.d.ts +23 -0
  51. package/dist/components/tabs/types.d.ts +18 -0
  52. package/dist/components/tabs/useTabs.d.ts +19 -0
  53. package/dist/components/textarea/index.d.ts +2 -0
  54. package/dist/components/textarea/index.js +2 -0
  55. package/dist/components/textarea/textarea.d.ts +21 -0
  56. package/dist/components/textarea/types.d.ts +14 -0
  57. package/dist/components/textarea/useTextarea.d.ts +6 -0
  58. package/dist/components/tooltip/index.d.ts +2 -0
  59. package/dist/components/tooltip/index.js +2 -0
  60. package/dist/components/tooltip/tooltip.d.ts +23 -0
  61. package/dist/components/tooltip/types.d.ts +5 -0
  62. package/dist/components/tooltip/useTooltip.d.ts +8 -0
  63. package/dist/index.d.ts +9 -0
  64. package/dist/index.js +10 -0
  65. package/dist/input.css +51 -0
  66. package/dist/input.js +79 -0
  67. package/dist/input.js.map +1 -0
  68. package/dist/radio.css +66 -0
  69. package/dist/radio.js +160 -0
  70. package/dist/radio.js.map +1 -0
  71. package/dist/select.css +122 -0
  72. package/dist/select.js +362 -0
  73. package/dist/select.js.map +1 -0
  74. package/dist/switch.css +70 -0
  75. package/dist/switch.js +94 -0
  76. package/dist/switch.js.map +1 -0
  77. package/dist/tabs.css +45 -0
  78. package/dist/tabs.js +205 -0
  79. package/dist/tabs.js.map +1 -0
  80. package/dist/textarea.css +46 -0
  81. package/dist/textarea.js +91 -0
  82. package/dist/textarea.js.map +1 -0
  83. package/dist/tooltip.css +78 -0
  84. package/dist/tooltip.js +112 -0
  85. package/dist/tooltip.js.map +1 -0
  86. package/dist/useControlState.js +38 -0
  87. package/dist/useControlState.js.map +1 -0
  88. package/dist/useRequiredInject.js +11 -0
  89. package/dist/useRequiredInject.js.map +1 -0
  90. package/package.json +110 -0
  91. package/src/styles/_mixins.scss +128 -0
  92. package/src/styles/_tokens.scss +184 -0
  93. package/src/styles/_variables.scss +112 -0
  94. package/src/styles/base.scss +1 -0
package/dist/select.js ADDED
@@ -0,0 +1,362 @@
1
+ import './select.css';
2
+ import { n as bem, t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
3
+ import { t as useControlState } from "./useControlState.js";
4
+ import { VaporTransition, child, computed, createComponent, createFor, createIf, createInvoker, createSelector, createSlot, createTemplateRefSetter, defineVaporComponent, delegateEvents, extend, next, nextTick, on, onBeforeUnmount, onMounted, ref, renderEffect, setAttr, setClass, setClassName, setInsertionState, setProp, setText, setValue, template, toDisplayString, txt, unref, useId, watch } from "vue";
5
+ //#region src/components/_internal/icons/ChevronDownIcon.vue?vue&type=script&setup=true&vapor=true&lang.ts
6
+ var t0$1 = template("<svg viewBox=\"0 0 16 16\"fill=none stroke=currentColor stroke-width=1.5><path d=\"M4 6l4 4 4-4\">", 3, 1);
7
+ //#endregion
8
+ //#region src/components/_internal/icons/ChevronDownIcon.vue
9
+ var ChevronDownIcon_default = /* @__PURE__ */ defineVaporComponent({
10
+ name: "ChevronDownIcon",
11
+ __name: "ChevronDownIcon",
12
+ setup(__props) {
13
+ return t0$1();
14
+ }
15
+ });
16
+ //#endregion
17
+ //#region src/components/_internal/optionList.ts
18
+ function hasOptionListValue(value) {
19
+ return value != null && value !== "";
20
+ }
21
+ function getOptionListDisplayLabel(options, value) {
22
+ if (!hasOptionListValue(value)) return "";
23
+ return options?.find((option) => option.value === value)?.label ?? "";
24
+ }
25
+ function getOptionListActiveDescendantId(baseId, focusedIndex) {
26
+ return focusedIndex < 0 ? void 0 : `${baseId}-option-${focusedIndex}`;
27
+ }
28
+ //#endregion
29
+ //#region src/composables/useClickOutside.ts
30
+ function useClickOutside(target, active, callback) {
31
+ let isListening = false;
32
+ let stopWatch;
33
+ function handler(e) {
34
+ if (target.value && !target.value.contains(e.target)) callback();
35
+ }
36
+ function setListening(value) {
37
+ if (typeof document === "undefined" || value === isListening) return;
38
+ isListening = value;
39
+ if (value) document.addEventListener("click", handler, true);
40
+ else document.removeEventListener("click", handler, true);
41
+ }
42
+ onMounted(() => {
43
+ stopWatch = watch(active, setListening, { immediate: true });
44
+ });
45
+ onBeforeUnmount(() => {
46
+ stopWatch?.();
47
+ setListening(false);
48
+ });
49
+ }
50
+ //#endregion
51
+ //#region src/composables/useListNavigation.ts
52
+ function useListNavigation(options) {
53
+ const localFocusedIndex = ref(-1);
54
+ const loop = options.loop ?? true;
55
+ const enabledIndexes = computed(() => options.items().map((item, index) => item.disabled ? -1 : index).filter((index) => index >= 0));
56
+ function resetFocus() {
57
+ localFocusedIndex.value = -1;
58
+ }
59
+ function setNearest(index, direction) {
60
+ const indexes = enabledIndexes.value;
61
+ if (indexes.length === 0) {
62
+ resetFocus();
63
+ return;
64
+ }
65
+ if (options.items()[index] && !options.items()[index]?.disabled) {
66
+ localFocusedIndex.value = index;
67
+ return;
68
+ }
69
+ const next = direction === 1 ? indexes.find((i) => i > index) : [...indexes].reverse().find((i) => i < index);
70
+ if (next !== void 0) localFocusedIndex.value = next;
71
+ else if (loop) localFocusedIndex.value = direction === 1 ? indexes[0] : indexes[indexes.length - 1];
72
+ }
73
+ function focusSelected() {
74
+ const items = options.items();
75
+ const selectedIndex = options.isSelected ? items.findIndex((item) => options.isSelected(item) && !item.disabled) : -1;
76
+ if (selectedIndex >= 0) localFocusedIndex.value = selectedIndex;
77
+ else focusFirst();
78
+ }
79
+ function focusFirst() {
80
+ const first = enabledIndexes.value[0];
81
+ localFocusedIndex.value = first ?? -1;
82
+ }
83
+ function focusLast() {
84
+ const indexes = enabledIndexes.value;
85
+ localFocusedIndex.value = indexes[indexes.length - 1] ?? -1;
86
+ }
87
+ function moveFocus(delta) {
88
+ if (localFocusedIndex.value < 0) {
89
+ delta === 1 ? focusFirst() : focusLast();
90
+ return;
91
+ }
92
+ setNearest(localFocusedIndex.value + delta, delta);
93
+ }
94
+ return {
95
+ focusedIndex: localFocusedIndex,
96
+ resetFocus,
97
+ focusSelected,
98
+ focusFirst,
99
+ focusLast,
100
+ moveFocus
101
+ };
102
+ }
103
+ //#endregion
104
+ //#region src/components/select/useSelect.ts
105
+ function useSelect(props, emitUpdate) {
106
+ const selectRef = ref(null);
107
+ const triggerRef = ref(null);
108
+ const isOpen = ref(false);
109
+ const selectId = useId();
110
+ const listboxId = `${selectId}-listbox`;
111
+ const control = useControlState(props);
112
+ const visibleOptions = computed(() => props.options ?? []);
113
+ const navigation = useListNavigation({
114
+ items: () => visibleOptions.value,
115
+ isSelected: (item) => item.value === props.modelValue
116
+ });
117
+ const focusedIndex = navigation.focusedIndex;
118
+ const activeDescendantId = computed(() => getOptionListActiveDescendantId(selectId, focusedIndex.value));
119
+ const rootClass = computed(() => bem("rp-select", {
120
+ open: isOpen.value,
121
+ disabled: control.disabled,
122
+ invalid: control.invalid
123
+ }));
124
+ const hasValue = computed(() => hasOptionListValue(props.modelValue));
125
+ const displayLabel = computed(() => getOptionListDisplayLabel(props.options, props.modelValue));
126
+ function focusTrigger() {
127
+ nextTick(() => triggerRef.value?.focus());
128
+ }
129
+ function open() {
130
+ if (control.disabled || isOpen.value) return;
131
+ isOpen.value = true;
132
+ navigation.focusSelected();
133
+ }
134
+ function close() {
135
+ isOpen.value = false;
136
+ navigation.resetFocus();
137
+ }
138
+ function toggle() {
139
+ if (control.disabled) return;
140
+ if (isOpen.value) {
141
+ close();
142
+ focusTrigger();
143
+ } else open();
144
+ }
145
+ function selectOption(option) {
146
+ if (option.disabled) return;
147
+ emitUpdate(option.value);
148
+ close();
149
+ focusTrigger();
150
+ }
151
+ function onOptionMouseenter(option, index) {
152
+ if (!option.disabled) focusedIndex.value = index;
153
+ }
154
+ function selectFocusedOption() {
155
+ if (focusedIndex.value < 0 || focusedIndex.value >= visibleOptions.value.length) return;
156
+ selectOption(visibleOptions.value[focusedIndex.value]);
157
+ }
158
+ function onTriggerKeydown(e) {
159
+ if (control.disabled) return;
160
+ switch (e.key) {
161
+ case "Enter":
162
+ e.preventDefault();
163
+ if (!isOpen.value) open();
164
+ else selectFocusedOption();
165
+ break;
166
+ case " ":
167
+ e.preventDefault();
168
+ if (!isOpen.value) open();
169
+ else selectFocusedOption();
170
+ break;
171
+ case "ArrowDown":
172
+ e.preventDefault();
173
+ if (!isOpen.value) open();
174
+ else navigation.moveFocus(1);
175
+ break;
176
+ case "ArrowUp":
177
+ e.preventDefault();
178
+ if (!isOpen.value) {
179
+ open();
180
+ navigation.focusLast();
181
+ } else navigation.moveFocus(-1);
182
+ break;
183
+ case "Home":
184
+ if (isOpen.value) {
185
+ e.preventDefault();
186
+ navigation.focusFirst();
187
+ }
188
+ break;
189
+ case "End":
190
+ if (isOpen.value) {
191
+ e.preventDefault();
192
+ navigation.focusLast();
193
+ }
194
+ break;
195
+ case "Escape":
196
+ e.preventDefault();
197
+ close();
198
+ focusTrigger();
199
+ break;
200
+ }
201
+ }
202
+ useClickOutside(selectRef, isOpen, close);
203
+ return {
204
+ selectRef,
205
+ triggerRef,
206
+ isOpen,
207
+ selectId,
208
+ listboxId,
209
+ control,
210
+ visibleOptions,
211
+ focusedIndex,
212
+ activeDescendantId,
213
+ rootClass,
214
+ hasValue,
215
+ displayLabel,
216
+ toggle,
217
+ selectOption,
218
+ onOptionMouseenter,
219
+ onTriggerKeydown
220
+ };
221
+ }
222
+ //#endregion
223
+ //#region src/components/select/select.vue?vue&type=script&setup=true&vapor=true&lang.ts
224
+ var t0 = template("<input data-v-692ef421 type=hidden>");
225
+ var t1 = template("No options", 2);
226
+ var t2 = template("<div data-v-692ef421 class=rp-select__empty>");
227
+ var t3 = template("<div data-v-692ef421 role=option> ");
228
+ var t4 = template("<div data-v-692ef421 class=rp-select__dropdown role=listbox>");
229
+ var t5 = template("<div data-v-692ef421><div data-v-692ef421 class=rp-select__trigger role=combobox aria-haspopup=listbox><span data-v-692ef421> </span><span data-v-692ef421>", 1);
230
+ delegateEvents("click", "keydown");
231
+ //#endregion
232
+ //#region src/components/select/select.vue
233
+ var select_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
234
+ name: "RpSelect",
235
+ __name: "select",
236
+ props: {
237
+ id: {},
238
+ name: {},
239
+ modelValue: {},
240
+ options: { default: () => [] },
241
+ placeholder: { default: "Select..." },
242
+ disabled: {
243
+ type: Boolean,
244
+ default: void 0
245
+ },
246
+ required: {
247
+ type: Boolean,
248
+ default: void 0
249
+ },
250
+ invalid: {
251
+ type: Boolean,
252
+ default: void 0
253
+ },
254
+ ariaLabel: {},
255
+ describedby: {},
256
+ labelledby: {}
257
+ },
258
+ emits: ["update:modelValue"],
259
+ setup(__props, { emit: __emit }) {
260
+ const props = __props;
261
+ const emit = __emit;
262
+ const { selectRef, triggerRef, isOpen, selectId, listboxId, control, visibleOptions, focusedIndex, activeDescendantId, rootClass, hasValue, displayLabel, toggle, selectOption, onOptionMouseenter, onTriggerKeydown } = useSelect(props, (value) => {
263
+ emit("update:modelValue", value);
264
+ });
265
+ const _setTemplateRef = createTemplateRefSetter();
266
+ const n20 = t5();
267
+ const n6 = child(n20, 1);
268
+ const n3 = child(n6);
269
+ const n5 = next(n3, 1);
270
+ renderEffect(() => setClass(n20, unref(rootClass)));
271
+ setInsertionState(n20, 0, 0);
272
+ createIf(() => __props.name, () => {
273
+ const n2 = t0();
274
+ renderEffect(() => {
275
+ setProp(n2, "name", __props.name);
276
+ setValue(n2, __props.modelValue ?? "");
277
+ setProp(n2, "disabled", unref(control).disabled || void 0);
278
+ });
279
+ return n2;
280
+ });
281
+ const x3 = txt(n3);
282
+ renderEffect(() => {
283
+ const _control = unref(control);
284
+ const _isOpen = unref(isOpen);
285
+ const _control_disabled = _control.disabled;
286
+ setProp(n6, "id", _control.id);
287
+ setAttr(n6, "aria-expanded", _isOpen);
288
+ setAttr(n6, "aria-activedescendant", unref(activeDescendantId));
289
+ setAttr(n6, "aria-controls", unref(listboxId));
290
+ setAttr(n6, "aria-disabled", _control_disabled || void 0);
291
+ setAttr(n6, "aria-invalid", _control.invalid || void 0);
292
+ setAttr(n6, "aria-required", _control.required || void 0);
293
+ setAttr(n6, "aria-label", __props.ariaLabel || void 0);
294
+ setAttr(n6, "aria-labelledby", _control.ariaLabelledby);
295
+ setAttr(n6, "aria-describedby", _control.ariaDescribedby);
296
+ setAttr(n6, "data-state", _isOpen ? "open" : "closed");
297
+ setAttr(n6, "data-disabled", _control_disabled || void 0);
298
+ setProp(n6, "tabindex", _control_disabled ? -1 : 0);
299
+ setClassName(n3, !unref(hasValue) ? 1 : 0, " rp-select__placeholder", "rp-select__value");
300
+ setText(x3, toDisplayString(unref(displayLabel) || __props.placeholder));
301
+ setClassName(n5, _isOpen ? 1 : 0, " rp-select__arrow--open", "rp-select__arrow");
302
+ });
303
+ setInsertionState(n5, null, 0);
304
+ createComponent(unref(ChevronDownIcon_default));
305
+ n6.$evtclick = createInvoker((e) => unref(toggle)(e));
306
+ n6.$evtkeydown = createInvoker((e) => unref(onTriggerKeydown)(e));
307
+ _setTemplateRef(n6, triggerRef, null, "triggerRef");
308
+ setInsertionState(n20, null, 2);
309
+ createComponent(VaporTransition, { name: "rp-select-dropdown" }, extend(() => {
310
+ return createIf(() => unref(isOpen), () => {
311
+ const n18 = t4();
312
+ renderEffect(() => setProp(n18, "id", unref(listboxId)));
313
+ setInsertionState(n18, null, 0);
314
+ createIf(() => unref(visibleOptions).length === 0, () => {
315
+ const n14 = t2();
316
+ setInsertionState(n14, null, 0);
317
+ createSlot("empty", null, () => {
318
+ return t1();
319
+ }, 1);
320
+ return n14;
321
+ });
322
+ setInsertionState(n18, null, 1);
323
+ const _selector15 = createSelector(() => __props.modelValue);
324
+ createFor(() => unref(visibleOptions), (_for_item0, _for_key0) => {
325
+ const n17 = t3();
326
+ const x17 = txt(n17);
327
+ n17.$evtclick = createInvoker(() => unref(selectOption)(_for_item0.value));
328
+ on(n17, "mouseenter", () => unref(onOptionMouseenter)(_for_item0.value, _for_key0.value));
329
+ let _index, _option, _modelValue, _option_disabled, _option_value;
330
+ renderEffect(() => {
331
+ _index = _for_key0.value;
332
+ _option = _for_item0.value;
333
+ _modelValue = __props.modelValue;
334
+ _option_disabled = _option.disabled;
335
+ _option_value = _option.value;
336
+ setProp(n17, "id", `${unref(selectId)}-option-${_index}`);
337
+ setAttr(n17, "aria-disabled", _option_disabled || void 0);
338
+ setAttr(n17, "data-selected", _option_value === _modelValue || void 0);
339
+ setAttr(n17, "data-disabled", _option_disabled || void 0);
340
+ setClass(n17, ["rp-select__option", {
341
+ "rp-select__option--selected": _option_value === _modelValue,
342
+ "rp-select__option--focused": _index === unref(focusedIndex),
343
+ "rp-select__option--disabled": _option_disabled
344
+ }]);
345
+ setText(x17, toDisplayString(_option.label));
346
+ });
347
+ _selector15(_option.value, () => {
348
+ setAttr(n17, "aria-selected", _option.value === _modelValue);
349
+ });
350
+ return n17;
351
+ }, (option, index) => option.value, 8).onReset(_selector15.reset);
352
+ return n18;
353
+ }, null, 129);
354
+ }, { _: 8 }));
355
+ _setTemplateRef(n20, selectRef, null, "selectRef");
356
+ return n20;
357
+ }
358
+ }), [["__scopeId", "data-v-692ef421"]]);
359
+ //#endregion
360
+ export { select_default as t };
361
+
362
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.js","names":[],"sources":["../src/components/_internal/icons/ChevronDownIcon.vue","../src/components/_internal/icons/ChevronDownIcon.vue","../src/components/_internal/optionList.ts","../src/composables/useClickOutside.ts","../src/composables/useListNavigation.ts","../src/components/select/useSelect.ts","../src/components/select/select.vue","../src/components/select/select.vue"],"sourcesContent":["<template>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M4 6l4 4 4-4\" />\n </svg>\n</template>\n\n<script lang=\"ts\" setup vapor>\ndefineOptions({ name: 'ChevronDownIcon' });\n</script>\n","<template>\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M4 6l4 4 4-4\" />\n </svg>\n</template>\n\n<script lang=\"ts\" setup vapor>\ndefineOptions({ name: 'ChevronDownIcon' });\n</script>\n","export interface OptionListItem {\n label: string;\n value: string | number;\n disabled?: boolean;\n}\n\nexport type OptionListValue = string | number | null;\n\nexport function hasOptionListValue(value: OptionListValue) {\n return value != null && value !== '';\n}\n\nexport function getOptionListDisplayLabel<T extends OptionListItem>(\n options: T[] | undefined,\n value: OptionListValue,\n) {\n if (!hasOptionListValue(value)) return '';\n return options?.find((option) => option.value === value)?.label ?? '';\n}\n\nexport function getOptionListActiveDescendantId(baseId: string, focusedIndex: number) {\n return focusedIndex < 0 ? undefined : `${baseId}-option-${focusedIndex}`;\n}\n","import { watch, onMounted, onBeforeUnmount, type Ref } from 'vue';\n\nexport function useClickOutside(\n target: Ref<HTMLElement | null>,\n active: Ref<boolean>,\n callback: () => void,\n) {\n let isListening = false;\n let stopWatch: (() => void) | undefined;\n\n function handler(e: MouseEvent) {\n if (target.value && !target.value.contains(e.target as Node)) {\n callback();\n }\n }\n\n function setListening(value: boolean) {\n if (typeof document === 'undefined' || value === isListening) return;\n isListening = value;\n\n if (value) {\n document.addEventListener('click', handler, true);\n } else {\n document.removeEventListener('click', handler, true);\n }\n }\n\n onMounted(() => {\n stopWatch = watch(active, setListening, { immediate: true });\n });\n\n onBeforeUnmount(() => {\n stopWatch?.();\n setListening(false);\n });\n}\n","import { computed, ref } from 'vue';\n\nexport interface ListNavigationItem {\n disabled?: boolean;\n}\n\nexport interface UseListNavigationOptions<T extends ListNavigationItem> {\n items: () => T[];\n isSelected?: (item: T) => boolean;\n loop?: boolean;\n}\n\nexport function useListNavigation<T extends ListNavigationItem>(\n options: UseListNavigationOptions<T>,\n) {\n const localFocusedIndex = ref(-1);\n const loop = options.loop ?? true;\n\n const enabledIndexes = computed(() =>\n options.items()\n .map((item, index) => item.disabled ? -1 : index)\n .filter((index) => index >= 0),\n );\n\n function resetFocus() {\n localFocusedIndex.value = -1;\n }\n\n function setNearest(index: number, direction: 1 | -1) {\n const indexes = enabledIndexes.value;\n if (indexes.length === 0) {\n resetFocus();\n return;\n }\n\n if (options.items()[index] && !options.items()[index]?.disabled) {\n localFocusedIndex.value = index;\n return;\n }\n\n const next = direction === 1\n ? indexes.find((i) => i > index)\n : [...indexes].reverse().find((i) => i < index);\n\n if (next !== undefined) {\n localFocusedIndex.value = next;\n } else if (loop) {\n localFocusedIndex.value = direction === 1 ? indexes[0]! : indexes[indexes.length - 1]!;\n }\n }\n\n function focusSelected() {\n const items = options.items();\n const selectedIndex = options.isSelected\n ? items.findIndex((item) => options.isSelected!(item) && !item.disabled)\n : -1;\n if (selectedIndex >= 0) {\n localFocusedIndex.value = selectedIndex;\n } else {\n focusFirst();\n }\n }\n\n function focusFirst() {\n const first = enabledIndexes.value[0];\n localFocusedIndex.value = first ?? -1;\n }\n\n function focusLast() {\n const indexes = enabledIndexes.value;\n localFocusedIndex.value = indexes[indexes.length - 1] ?? -1;\n }\n\n function moveFocus(delta: 1 | -1) {\n if (localFocusedIndex.value < 0) {\n delta === 1 ? focusFirst() : focusLast();\n return;\n }\n setNearest(localFocusedIndex.value + delta, delta);\n }\n\n return {\n focusedIndex: localFocusedIndex,\n resetFocus,\n focusSelected,\n focusFirst,\n focusLast,\n moveFocus,\n };\n}\n","import { computed, nextTick, ref, useId } from 'vue';\nimport {\n getOptionListActiveDescendantId,\n getOptionListDisplayLabel,\n hasOptionListValue,\n} from '@/components/_internal/optionList';\nimport { useClickOutside } from '@/composables/useClickOutside';\nimport { useControlState } from '@/composables/useControlState';\nimport { useListNavigation } from '@/composables/useListNavigation';\nimport { bem } from '@/utils/bem';\nimport type { SelectOption, SelectProps } from './types';\n\ntype SelectValue = string | number | null;\n\nexport function useSelect(\n props: Readonly<SelectProps>,\n emitUpdate: (value: SelectValue) => void,\n) {\n const selectRef = ref<HTMLElement | null>(null);\n const triggerRef = ref<HTMLElement | null>(null);\n const isOpen = ref(false);\n\n const selectId = useId();\n const listboxId = `${selectId}-listbox`;\n\n const control = useControlState(props);\n const visibleOptions = computed(() => props.options ?? []);\n\n const navigation = useListNavigation<SelectOption>({\n items: () => visibleOptions.value,\n isSelected: (item) => item.value === props.modelValue,\n });\n\n const focusedIndex = navigation.focusedIndex;\n const activeDescendantId = computed(() =>\n getOptionListActiveDescendantId(selectId, focusedIndex.value),\n );\n\n const rootClass = computed(() =>\n bem('rp-select', {\n open: isOpen.value,\n disabled: control.disabled,\n invalid: control.invalid,\n }),\n );\n\n const hasValue = computed(() => hasOptionListValue(props.modelValue));\n const displayLabel = computed(() => getOptionListDisplayLabel(props.options, props.modelValue));\n\n function focusTrigger() {\n nextTick(() => triggerRef.value?.focus());\n }\n\n function open() {\n if (control.disabled || isOpen.value) return;\n isOpen.value = true;\n navigation.focusSelected();\n }\n\n function close() {\n isOpen.value = false;\n navigation.resetFocus();\n }\n\n function toggle() {\n if (control.disabled) return;\n if (isOpen.value) {\n close();\n focusTrigger();\n } else {\n open();\n }\n }\n\n function selectOption(option: SelectOption) {\n if (option.disabled) return;\n emitUpdate(option.value);\n close();\n focusTrigger();\n }\n\n function onOptionMouseenter(option: SelectOption, index: number) {\n if (!option.disabled) focusedIndex.value = index;\n }\n\n function selectFocusedOption() {\n if (focusedIndex.value < 0 || focusedIndex.value >= visibleOptions.value.length) return;\n selectOption(visibleOptions.value[focusedIndex.value]!);\n }\n\n function onTriggerKeydown(e: KeyboardEvent) {\n if (control.disabled) return;\n\n switch (e.key) {\n case 'Enter':\n e.preventDefault();\n if (!isOpen.value) open();\n else selectFocusedOption();\n break;\n case ' ':\n e.preventDefault();\n if (!isOpen.value) open();\n else selectFocusedOption();\n break;\n case 'ArrowDown':\n e.preventDefault();\n if (!isOpen.value) open();\n else navigation.moveFocus(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (!isOpen.value) {\n open();\n navigation.focusLast();\n } else {\n navigation.moveFocus(-1);\n }\n break;\n case 'Home':\n if (isOpen.value) {\n e.preventDefault();\n navigation.focusFirst();\n }\n break;\n case 'End':\n if (isOpen.value) {\n e.preventDefault();\n navigation.focusLast();\n }\n break;\n case 'Escape':\n e.preventDefault();\n close();\n focusTrigger();\n break;\n }\n }\n\n useClickOutside(selectRef, isOpen, close);\n\n return {\n selectRef,\n triggerRef,\n isOpen,\n selectId,\n listboxId,\n control,\n visibleOptions,\n focusedIndex,\n activeDescendantId,\n rootClass,\n hasValue,\n displayLabel,\n toggle,\n selectOption,\n onOptionMouseenter,\n onTriggerKeydown,\n };\n}\n","<template>\n <div :class=\"rootClass\" ref=\"selectRef\">\n <input v-if=\"name\" type=\"hidden\" :name=\"name\" :value=\"modelValue ?? ''\" :disabled=\"control.disabled || undefined\" />\n <div\n :id=\"control.id\"\n ref=\"triggerRef\"\n class=\"rp-select__trigger\"\n role=\"combobox\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"listbox\"\n :aria-activedescendant=\"activeDescendantId\"\n :aria-controls=\"listboxId\"\n :aria-disabled=\"control.disabled || undefined\"\n :aria-invalid=\"control.invalid || undefined\"\n :aria-required=\"control.required || undefined\"\n :aria-label=\"ariaLabel || undefined\"\n :aria-labelledby=\"control.ariaLabelledby\"\n :aria-describedby=\"control.ariaDescribedby\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n :data-disabled=\"control.disabled || undefined\"\n :tabindex=\"control.disabled ? -1 : 0\"\n @click=\"toggle\"\n @keydown=\"onTriggerKeydown\"\n >\n <span class=\"rp-select__value\" :class=\"{ 'rp-select__placeholder': !hasValue }\">\n {{ displayLabel || placeholder }}\n </span>\n\n <span class=\"rp-select__arrow\" :class=\"{ 'rp-select__arrow--open': isOpen }\">\n <ChevronDownIcon />\n </span>\n </div>\n\n <Transition name=\"rp-select-dropdown\">\n <div v-if=\"isOpen\" class=\"rp-select__dropdown\" role=\"listbox\" :id=\"listboxId\">\n <div\n v-if=\"visibleOptions.length === 0\"\n class=\"rp-select__empty\"\n >\n <slot name=\"empty\">No options</slot>\n </div>\n <div\n v-for=\"(option, index) in visibleOptions\"\n :key=\"option.value\"\n role=\"option\"\n :id=\"`${selectId}-option-${index}`\"\n :aria-selected=\"option.value === modelValue\"\n :aria-disabled=\"option.disabled || undefined\"\n :data-selected=\"option.value === modelValue || undefined\"\n :data-disabled=\"option.disabled || undefined\"\n :class=\"[\n 'rp-select__option',\n {\n 'rp-select__option--selected': option.value === modelValue,\n 'rp-select__option--focused': index === focusedIndex,\n 'rp-select__option--disabled': option.disabled,\n },\n ]\"\n @click=\"selectOption(option)\"\n @mouseenter=\"onOptionMouseenter(option, index)\"\n >\n {{ option.label }}\n </div>\n </div>\n </Transition>\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { ChevronDownIcon } from '@/components/_internal/icons';\nimport { useSelect } from './useSelect';\nimport type { SelectProps } from './types';\n\ndefineOptions({ name: 'RpSelect' });\n\nconst props = withDefaults(defineProps<SelectProps>(), {\n options: () => [],\n placeholder: 'Select...',\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number | null];\n}>();\n\nconst {\n selectRef,\n triggerRef,\n isOpen,\n selectId,\n listboxId,\n control,\n visibleOptions,\n focusedIndex,\n activeDescendantId,\n rootClass,\n hasValue,\n displayLabel,\n toggle,\n selectOption,\n onOptionMouseenter,\n onTriggerKeydown,\n} = useSelect(props, (value) => {\n emit('update:modelValue', value);\n});\n\nvoid selectRef;\nvoid triggerRef;\n</script>\n\n<style src=\"./select.scss\" lang=\"scss\" scoped></style>\n","<template>\n <div :class=\"rootClass\" ref=\"selectRef\">\n <input v-if=\"name\" type=\"hidden\" :name=\"name\" :value=\"modelValue ?? ''\" :disabled=\"control.disabled || undefined\" />\n <div\n :id=\"control.id\"\n ref=\"triggerRef\"\n class=\"rp-select__trigger\"\n role=\"combobox\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"listbox\"\n :aria-activedescendant=\"activeDescendantId\"\n :aria-controls=\"listboxId\"\n :aria-disabled=\"control.disabled || undefined\"\n :aria-invalid=\"control.invalid || undefined\"\n :aria-required=\"control.required || undefined\"\n :aria-label=\"ariaLabel || undefined\"\n :aria-labelledby=\"control.ariaLabelledby\"\n :aria-describedby=\"control.ariaDescribedby\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n :data-disabled=\"control.disabled || undefined\"\n :tabindex=\"control.disabled ? -1 : 0\"\n @click=\"toggle\"\n @keydown=\"onTriggerKeydown\"\n >\n <span class=\"rp-select__value\" :class=\"{ 'rp-select__placeholder': !hasValue }\">\n {{ displayLabel || placeholder }}\n </span>\n\n <span class=\"rp-select__arrow\" :class=\"{ 'rp-select__arrow--open': isOpen }\">\n <ChevronDownIcon />\n </span>\n </div>\n\n <Transition name=\"rp-select-dropdown\">\n <div v-if=\"isOpen\" class=\"rp-select__dropdown\" role=\"listbox\" :id=\"listboxId\">\n <div\n v-if=\"visibleOptions.length === 0\"\n class=\"rp-select__empty\"\n >\n <slot name=\"empty\">No options</slot>\n </div>\n <div\n v-for=\"(option, index) in visibleOptions\"\n :key=\"option.value\"\n role=\"option\"\n :id=\"`${selectId}-option-${index}`\"\n :aria-selected=\"option.value === modelValue\"\n :aria-disabled=\"option.disabled || undefined\"\n :data-selected=\"option.value === modelValue || undefined\"\n :data-disabled=\"option.disabled || undefined\"\n :class=\"[\n 'rp-select__option',\n {\n 'rp-select__option--selected': option.value === modelValue,\n 'rp-select__option--focused': index === focusedIndex,\n 'rp-select__option--disabled': option.disabled,\n },\n ]\"\n @click=\"selectOption(option)\"\n @mouseenter=\"onOptionMouseenter(option, index)\"\n >\n {{ option.label }}\n </div>\n </div>\n </Transition>\n </div>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { ChevronDownIcon } from '@/components/_internal/icons';\nimport { useSelect } from './useSelect';\nimport type { SelectProps } from './types';\n\ndefineOptions({ name: 'RpSelect' });\n\nconst props = withDefaults(defineProps<SelectProps>(), {\n options: () => [],\n placeholder: 'Select...',\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number | null];\n}>();\n\nconst {\n selectRef,\n triggerRef,\n isOpen,\n selectId,\n listboxId,\n control,\n visibleOptions,\n focusedIndex,\n activeDescendantId,\n rootClass,\n hasValue,\n displayLabel,\n toggle,\n selectOption,\n onOptionMouseenter,\n onTriggerKeydown,\n} = useSelect(props, (value) => {\n emit('update:modelValue', value);\n});\n\nvoid selectRef;\nvoid triggerRef;\n</script>\n\n<style src=\"./select.scss\" lang=\"scss\" scoped></style>\n"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ .rp-switch[data-v-8d0cc56f] {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ cursor: pointer;
5
+ font-family: var(--rp-font-family);
6
+ user-select: none;
7
+ }
8
+ .rp-switch--disabled[data-v-8d0cc56f] {
9
+ opacity: var(--rp-opacity-disabled);
10
+ cursor: not-allowed;
11
+ }
12
+ .rp-switch[data-v-8d0cc56f] {
13
+ gap: var(--rp-spacing-2);
14
+ font-size: var(--rp-font-size-base);
15
+ --_track-w: 40px;
16
+ --_track-h: 22px;
17
+ --_thumb-size: 18px;
18
+ --_thumb-offset: 2px;
19
+ }
20
+ .rp-switch__native[data-v-8d0cc56f] {
21
+ position: absolute;
22
+ width: 1px;
23
+ height: 1px;
24
+ padding: 0;
25
+ margin: -1px;
26
+ overflow: hidden;
27
+ clip: rect(0, 0, 0, 0);
28
+ white-space: nowrap;
29
+ border-width: 0;
30
+ pointer-events: none;
31
+ }
32
+ .rp-switch__native:focus-visible + .rp-switch__track[data-v-8d0cc56f] {
33
+ border-color: var(--rp-color-control-border-focus);
34
+ box-shadow: 0 0 0 var(--rp-border-width-medium) var(--rp-color-focus-ring);
35
+ }
36
+ .rp-switch__track[data-v-8d0cc56f] {
37
+ position: relative;
38
+ display: inline-flex;
39
+ align-items: center;
40
+ width: var(--_track-w);
41
+ height: var(--_track-h);
42
+ flex-shrink: 0;
43
+ background-color: var(--rp-color-control-track-bg);
44
+ border-radius: var(--rp-radius-full);
45
+ transition: background-color var(--rp-transition-fast);
46
+ }
47
+ .rp-switch--checked .rp-switch__track[data-v-8d0cc56f] {
48
+ background-color: var(--rp-color-control-selected-bg);
49
+ }
50
+ .rp-switch--invalid .rp-switch__track[data-v-8d0cc56f] {
51
+ outline: var(--rp-border-width-thin) solid var(--rp-color-danger-fg);
52
+ outline-offset: var(--_thumb-offset);
53
+ }
54
+ .rp-switch__thumb[data-v-8d0cc56f] {
55
+ position: absolute;
56
+ left: var(--_thumb-offset);
57
+ width: var(--_thumb-size);
58
+ height: var(--_thumb-size);
59
+ background-color: var(--rp-color-control-thumb-bg);
60
+ border-radius: var(--rp-radius-full);
61
+ box-shadow: var(--rp-shadow-sm);
62
+ transition: transform var(--rp-transition-fast);
63
+ }
64
+ .rp-switch--checked .rp-switch__thumb[data-v-8d0cc56f] {
65
+ transform: translateX(calc(var(--_track-w) - var(--_thumb-size) - var(--_thumb-offset) * 2));
66
+ }
67
+ .rp-switch__label[data-v-8d0cc56f] {
68
+ line-height: var(--rp-line-height-normal);
69
+ color: var(--rp-color-text);
70
+ }
package/dist/switch.js ADDED
@@ -0,0 +1,94 @@
1
+ import './switch.css';
2
+ import { n as bem, t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
3
+ import { t as useControlState } from "./useControlState.js";
4
+ import { child, computed, createIf, createSlot, defineVaporComponent, on, renderEffect, setAttr, setClass, setInsertionState, setProp, template, unref } from "vue";
5
+ //#region src/components/switch/useSwitch.ts
6
+ function useSwitch(props, emitUpdate) {
7
+ const control = useControlState(props);
8
+ const rootClass = computed(() => bem("rp-switch", {
9
+ checked: props.modelValue,
10
+ disabled: control.disabled,
11
+ invalid: control.invalid
12
+ }));
13
+ function onChange(e) {
14
+ emitUpdate(e.target.checked);
15
+ }
16
+ return {
17
+ control,
18
+ rootClass,
19
+ onChange
20
+ };
21
+ }
22
+ //#endregion
23
+ //#region src/components/switch/switch.vue?vue&type=script&setup=true&vapor=true&lang.ts
24
+ var t0 = template("<span data-v-8d0cc56f class=rp-switch__label>");
25
+ var t1 = template("<label data-v-8d0cc56f><input data-v-8d0cc56f type=checkbox class=rp-switch__native role=switch><span data-v-8d0cc56f class=rp-switch__track><span data-v-8d0cc56f class=rp-switch__thumb></span></span>", 1);
26
+ //#endregion
27
+ //#region src/components/switch/switch.vue
28
+ var switch_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineVaporComponent({
29
+ name: "RpSwitch",
30
+ __name: "switch",
31
+ props: {
32
+ id: {},
33
+ name: {},
34
+ modelValue: { type: Boolean },
35
+ disabled: {
36
+ type: Boolean,
37
+ default: void 0
38
+ },
39
+ required: {
40
+ type: Boolean,
41
+ default: void 0
42
+ },
43
+ invalid: {
44
+ type: Boolean,
45
+ default: void 0
46
+ },
47
+ ariaLabel: {},
48
+ describedby: {},
49
+ labelledby: {}
50
+ },
51
+ emits: ["update:modelValue"],
52
+ setup(__props, { emit: __emit, slots: $slots }) {
53
+ const props = __props;
54
+ const emit = __emit;
55
+ const { control, rootClass, onChange } = useSwitch(props, (value) => {
56
+ emit("update:modelValue", value);
57
+ });
58
+ const n5 = t1();
59
+ const n0 = child(n5);
60
+ on(n0, "change", (e) => unref(onChange)(e));
61
+ renderEffect(() => {
62
+ const _control = unref(control);
63
+ const _modelValue = __props.modelValue;
64
+ const _control_disabled = _control.disabled;
65
+ const _control_required = _control.required;
66
+ setClass(n5, unref(rootClass));
67
+ setAttr(n5, "data-disabled", _control_disabled || void 0);
68
+ setAttr(n5, "data-state", _modelValue ? "checked" : "unchecked");
69
+ setProp(n0, "id", _control.id);
70
+ setProp(n0, "name", __props.name);
71
+ setProp(n0, "checked", _modelValue);
72
+ setProp(n0, "disabled", _control_disabled || void 0);
73
+ setProp(n0, "required", _control_required || void 0);
74
+ setAttr(n0, "aria-checked", _modelValue);
75
+ setAttr(n0, "aria-label", __props.ariaLabel || void 0);
76
+ setAttr(n0, "aria-labelledby", _control.ariaLabelledby);
77
+ setAttr(n0, "aria-describedby", _control.ariaDescribedby);
78
+ setAttr(n0, "aria-invalid", _control.invalid || void 0);
79
+ setAttr(n0, "aria-required", _control_required || void 0);
80
+ });
81
+ setInsertionState(n5, null, 2);
82
+ createIf(() => $slots.default, () => {
83
+ const n4 = t0();
84
+ setInsertionState(n4, null, 0);
85
+ createSlot("default", null, null, 1);
86
+ return n4;
87
+ });
88
+ return n5;
89
+ }
90
+ }), [["__scopeId", "data-v-8d0cc56f"]]);
91
+ //#endregion
92
+ export { switch_default as t };
93
+
94
+ //# sourceMappingURL=switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.js","names":[],"sources":["../src/components/switch/useSwitch.ts","../src/components/switch/switch.vue","../src/components/switch/switch.vue"],"sourcesContent":["import { computed } from 'vue';\nimport { useControlState } from '@/composables/useControlState';\nimport { bem } from '@/utils/bem';\nimport type { SwitchProps } from './types';\n\nexport function useSwitch(\n props: Readonly<SwitchProps>,\n emitUpdate: (value: boolean) => void,\n) {\n const control = useControlState(props);\n\n const rootClass = computed(() =>\n bem('rp-switch', {\n checked: props.modelValue,\n disabled: control.disabled,\n invalid: control.invalid,\n }),\n );\n\n function onChange(e: Event) {\n emitUpdate((e.target as HTMLInputElement).checked);\n }\n\n return {\n control,\n rootClass,\n onChange,\n };\n}\n","<template>\n <label :class=\"rootClass\" :data-disabled=\"control.disabled || undefined\" :data-state=\"modelValue ? 'checked' : 'unchecked'\">\n <input\n :id=\"control.id\"\n :name=\"name\"\n type=\"checkbox\"\n class=\"rp-switch__native\"\n role=\"switch\"\n :checked=\"modelValue\"\n :disabled=\"control.disabled || undefined\"\n :required=\"control.required || undefined\"\n :aria-checked=\"modelValue\"\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 @change=\"onChange\"\n />\n <span class=\"rp-switch__track\">\n <span class=\"rp-switch__thumb\" />\n </span>\n <span v-if=\"$slots.default\" class=\"rp-switch__label\">\n <slot />\n </span>\n </label>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useSwitch } from './useSwitch';\nimport type { SwitchProps } from './types';\n\ndefineOptions({ name: 'RpSwitch' });\n\nconst props = withDefaults(defineProps<SwitchProps>(), {\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean];\n}>();\n\nconst { control, rootClass, onChange } = useSwitch(props, (value) => {\n emit('update:modelValue', value);\n});\n</script>\n\n<style src=\"./switch.scss\" lang=\"scss\" scoped></style>\n","<template>\n <label :class=\"rootClass\" :data-disabled=\"control.disabled || undefined\" :data-state=\"modelValue ? 'checked' : 'unchecked'\">\n <input\n :id=\"control.id\"\n :name=\"name\"\n type=\"checkbox\"\n class=\"rp-switch__native\"\n role=\"switch\"\n :checked=\"modelValue\"\n :disabled=\"control.disabled || undefined\"\n :required=\"control.required || undefined\"\n :aria-checked=\"modelValue\"\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 @change=\"onChange\"\n />\n <span class=\"rp-switch__track\">\n <span class=\"rp-switch__thumb\" />\n </span>\n <span v-if=\"$slots.default\" class=\"rp-switch__label\">\n <slot />\n </span>\n </label>\n</template>\n\n<script lang=\"ts\" setup vapor>\nimport { useSwitch } from './useSwitch';\nimport type { SwitchProps } from './types';\n\ndefineOptions({ name: 'RpSwitch' });\n\nconst props = withDefaults(defineProps<SwitchProps>(), {\n disabled: undefined,\n required: undefined,\n invalid: undefined,\n});\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean];\n}>();\n\nconst { control, rootClass, onChange } = useSwitch(props, (value) => {\n emit('update:modelValue', value);\n});\n</script>\n\n<style src=\"./switch.scss\" lang=\"scss\" scoped></style>\n"],"mappings":";;;;AAKA,SAAgB,UACZ,OACA,YACF;CACE,MAAM,UAAU,gBAAgB,KAAK;CAErC,MAAM,YAAY,eACd,IAAI,aAAa;EACb,SAAS,MAAM;EACf,UAAU,QAAQ;EAClB,SAAS,QAAQ;CACrB,CAAC,CACL;CAEA,SAAS,SAAS,GAAU;EACxB,WAAY,EAAE,OAA4B,OAAO;CACrD;CAEA,OAAO;EACH;EACA;EACA;CACJ;AACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECMA,MAAM,QAAQ;EAMd,MAAM,OAAO;EAIb,MAAM,EAAE,SAAS,WAAW,aAAa,UAAU,QAAQ,UAAU;GACjE,KAAK,qBAAqB,KAAK;EACnC,CAAC;;;SA7BY,WAAM,MAAE,MAAA,QAAA,CAAQ,CAAA,CAAA,CAAA;;;;;;gBAhBV,MAAA,SAAA,CAAS;eAAG,iBAAe,qBAAoB,KAAA,CAAS;eAAG,cAAY,cAAU,YAAA,WAAA;eAEvF,MAAI,SAAO,EAAA;eACX,QAAM,QAAA,IAAI;eAIV,WAAS,WAAU;eACnB,YAAU,qBAAoB,KAAA,CAAS;eACvC,YAAU,qBAAoB,KAAA,CAAS;eACvC,gBAAc,WAAU;eACxB,cAAY,QAAA,aAAa,KAAA,CAAS;eAClC,mBAAiB,SAAO,cAAA;eACxB,oBAAkB,SAAO,eAAA;eACzB,gBAAc,SAAO,WAAY,KAAA,CAAS;eAC1C,iBAAe,qBAAoB,KAAA,CAAS;;;iBAMrC,OAAM,eAAA"}
package/dist/tabs.css ADDED
@@ -0,0 +1,45 @@
1
+ .rp-tabs[data-v-f9df84ad] {
2
+ font-family: var(--rp-font-family);
3
+ }.rp-tabs__list[data-v-f020ecc8] {
4
+ display: flex;
5
+ border-bottom: var(--rp-border-width-medium) solid var(--rp-color-border);
6
+ gap: var(--rp-spacing-1);
7
+ }.rp-tabs__trigger[data-v-7fa65d85] {
8
+ padding: 0;
9
+ font: inherit;
10
+ background: none;
11
+ border: none;
12
+ cursor: pointer;
13
+ font-weight: var(--rp-font-weight-medium);
14
+ color: var(--rp-color-text-secondary);
15
+ }
16
+ .rp-tabs__trigger[data-v-7fa65d85]:hover:not(:disabled) {
17
+ color: var(--rp-color-text);
18
+ }
19
+ .rp-tabs__trigger[data-v-7fa65d85]:focus-visible {
20
+ outline: none;
21
+ border-color: var(--rp-color-control-border-focus);
22
+ box-shadow: 0 0 0 var(--rp-border-width-medium) var(--rp-color-focus-ring);
23
+ }
24
+ .rp-tabs__trigger[data-v-7fa65d85] {
25
+ padding: var(--rp-spacing-2) var(--rp-spacing-4);
26
+ font-size: var(--rp-font-size-sm);
27
+ position: relative;
28
+ transition: color var(--rp-transition-fast);
29
+ margin-bottom: calc(-1 * var(--rp-border-width-medium));
30
+ border-bottom: var(--rp-border-width-medium) solid transparent;
31
+ }
32
+ .rp-tabs__trigger--active[data-v-7fa65d85] {
33
+ color: var(--rp-color-primary-fg);
34
+ border-bottom-color: var(--rp-color-primary-fg);
35
+ }
36
+ .rp-tabs__trigger--disabled[data-v-7fa65d85] {
37
+ opacity: var(--rp-opacity-disabled);
38
+ cursor: not-allowed;
39
+ }.rp-tab-panel[data-v-6205e839] {
40
+ font-family: var(--rp-font-family);
41
+ font-size: var(--rp-font-size-base);
42
+ color: var(--rp-color-text);
43
+ line-height: var(--rp-line-height-loose);
44
+ padding: var(--rp-spacing-4) 0;
45
+ }