@teammodlr/ui-kit 1.0.4 → 1.0.5

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 (147) hide show
  1. package/package.json +2 -1
  2. package/src/__storybook__/argTypes.ts +42 -0
  3. package/src/__storybook__/createStory.ts +15 -0
  4. package/src/__storybook__/index.ts +2 -0
  5. package/src/components/avatar/Avatar.css +69 -0
  6. package/src/components/avatar/Avatar.vue +102 -0
  7. package/src/components/avatar/examples/basic.vue +6 -0
  8. package/src/components/avatar/examples/custom-size.vue +7 -0
  9. package/src/components/avatar/examples/index.stories.ts +28 -0
  10. package/src/components/avatar/examples/index.ts +5 -0
  11. package/src/components/avatar/examples/sizes.vue +33 -0
  12. package/src/components/avatar/examples/slots.vue +7 -0
  13. package/src/components/avatar/examples/variants.vue +18 -0
  14. package/src/components/avatargroup/AvatarGroup.css +8 -0
  15. package/src/components/avatargroup/AvatarGroup.vue +32 -0
  16. package/src/components/avatargroup/examples/basic.vue +11 -0
  17. package/src/components/avatargroup/examples/index.stories.ts +28 -0
  18. package/src/components/avatargroup/examples/index.ts +1 -0
  19. package/src/components/breadcrumb/Breadcrumb.css +46 -0
  20. package/src/components/breadcrumb/Breadcrumb.vue +51 -0
  21. package/src/components/breadcrumb/examples/basic.vue +9 -0
  22. package/src/components/breadcrumb/examples/index.stories.ts +20 -0
  23. package/src/components/breadcrumb/examples/index.ts +1 -0
  24. package/src/components/breadcrumbitem/BreadcrumbItem.vue +66 -0
  25. package/src/components/breadcrumbitem/index.ts +1 -0
  26. package/src/components/button/Button.css +378 -0
  27. package/src/components/button/Button.vue +108 -0
  28. package/src/components/button/examples/basic.vue +3 -0
  29. package/src/components/button/examples/colors-secondary.vue +8 -0
  30. package/src/components/button/examples/colors.vue +8 -0
  31. package/src/components/button/examples/disabled.vue +3 -0
  32. package/src/components/button/examples/icon.vue +10 -0
  33. package/src/components/button/examples/index.stories.ts +33 -0
  34. package/src/components/button/examples/index.ts +7 -0
  35. package/src/components/button/examples/rounded.vue +7 -0
  36. package/src/components/button/examples/size.vue +7 -0
  37. package/src/components/buttongroup/ButtonGroup.vue +47 -0
  38. package/src/components/buttongroup/examples/basic.vue +9 -0
  39. package/src/components/buttongroup/examples/index.stories.ts +21 -0
  40. package/src/components/buttongroup/examples/index.ts +1 -0
  41. package/src/components/checkbox/Checkbox.css +185 -0
  42. package/src/components/checkbox/Checkbox.vue +140 -0
  43. package/src/components/checkbox/examples/basic.vue +9 -0
  44. package/src/components/checkbox/examples/index.stories.ts +21 -0
  45. package/src/components/checkbox/examples/index.ts +3 -0
  46. package/src/components/checkbox/examples/slot.vue +11 -0
  47. package/src/components/dropdown/Dropdown.css +68 -0
  48. package/src/components/dropdown/Dropdown.vue +237 -0
  49. package/src/components/dropdown/DropdownItem.vue +118 -0
  50. package/src/components/dropdown/DropdownList.vue +20 -0
  51. package/src/components/dropdown/DropdownWrapper.vue +17 -0
  52. package/src/components/dropdown/examples/basic.vue +73 -0
  53. package/src/components/dropdown/examples/context.vue +71 -0
  54. package/src/components/dropdown/examples/index.stories.ts +23 -0
  55. package/src/components/dropdown/examples/index.ts +2 -0
  56. package/src/components/dropdown/hooks.ts +30 -0
  57. package/src/components/form/Form.vue +141 -0
  58. package/src/components/form/examples/basic.vue +73 -0
  59. package/src/components/form/examples/index.stories.ts +23 -0
  60. package/src/components/form/examples/index.ts +1 -0
  61. package/src/components/image/Image.vue +71 -0
  62. package/src/components/image/examples/basic.vue +5 -0
  63. package/src/components/image/examples/index.stories.ts +12 -0
  64. package/src/components/image/examples/index.ts +1 -0
  65. package/src/components/index.ts +27 -0
  66. package/src/components/input/Input.css +173 -0
  67. package/src/components/input/Input.vue +176 -0
  68. package/src/components/input/examples/basic.vue +7 -0
  69. package/src/components/input/examples/index.stories.ts +24 -0
  70. package/src/components/input/examples/index.ts +4 -0
  71. package/src/components/input/examples/prefix.vue +7 -0
  72. package/src/components/input/examples/sizes.vue +9 -0
  73. package/src/components/input/examples/suffix.vue +7 -0
  74. package/src/components/link/Link.css +147 -0
  75. package/src/components/link/Link.vue +54 -0
  76. package/src/components/link/examples/basic.vue +3 -0
  77. package/src/components/link/examples/index.stories.ts +20 -0
  78. package/src/components/link/examples/index.ts +1 -0
  79. package/src/components/messageprovider/Message.vue +76 -0
  80. package/src/components/messageprovider/MessageProvider.css +36 -0
  81. package/src/components/messageprovider/MessageProvider.vue +142 -0
  82. package/src/components/messageprovider/examples/basic.vue +19 -0
  83. package/src/components/messageprovider/examples/index.stories.ts +30 -0
  84. package/src/components/messageprovider/examples/index.ts +1 -0
  85. package/src/components/messageprovider/examples/wrapper.vue +9 -0
  86. package/src/components/messageprovider/types.ts +39 -0
  87. package/src/components/messageprovider/useMessage.ts +12 -0
  88. package/src/components/select/Select.css +226 -0
  89. package/src/components/select/Select.vue +474 -0
  90. package/src/components/select/examples/basic.vue +20 -0
  91. package/src/components/select/examples/index.stories.ts +22 -0
  92. package/src/components/select/examples/index.ts +3 -0
  93. package/src/components/select/examples/multiple.vue +22 -0
  94. package/src/components/select/examples/searchable.vue +20 -0
  95. package/src/components/skeleton/Skeleton.css +73 -0
  96. package/src/components/skeleton/Skeleton.vue +47 -0
  97. package/src/components/skeleton/examples/basic.vue +3 -0
  98. package/src/components/skeleton/examples/index.stories.ts +24 -0
  99. package/src/components/skeleton/examples/index.ts +2 -0
  100. package/src/components/skeleton/examples/post.vue +8 -0
  101. package/src/components/tab/Tab.css +113 -0
  102. package/src/components/tab/Tab.vue +98 -0
  103. package/src/components/tab/TabGroup.vue +90 -0
  104. package/src/components/tab/examples/basic.vue +19 -0
  105. package/src/components/tab/examples/index.stories.ts +25 -0
  106. package/src/components/tab/examples/index.ts +2 -0
  107. package/src/components/tab/examples/vertical.vue +19 -0
  108. package/src/components/table/Table.css +45 -0
  109. package/src/components/table/Table.vue +108 -0
  110. package/src/components/table/TableBody.vue +13 -0
  111. package/src/components/table/TableCell.vue +13 -0
  112. package/src/components/table/TableHead.vue +22 -0
  113. package/src/components/table/TableHeadRow.vue +15 -0
  114. package/src/components/table/TableRow.vue +13 -0
  115. package/src/components/table/examples/basic.vue +46 -0
  116. package/src/components/table/examples/index.stories.ts +19 -0
  117. package/src/components/table/examples/index.ts +1 -0
  118. package/src/components/table/types/index.ts +5 -0
  119. package/src/components/tooltip/Tooltip.css +49 -0
  120. package/src/components/tooltip/Tooltip.vue +85 -0
  121. package/src/components/tooltip/examples/basic.vue +8 -0
  122. package/src/components/tooltip/examples/index.stories.ts +21 -0
  123. package/src/components/tooltip/examples/index.ts +1 -0
  124. package/src/components/virtualscroll/VirtualScroll.css +13 -0
  125. package/src/components/virtualscroll/VirtualScroll.vue +61 -0
  126. package/src/components/virtualscroll/examples/basic.vue +37 -0
  127. package/src/components/virtualscroll/examples/index.stories.ts +31 -0
  128. package/src/components/virtualscroll/examples/index.ts +1 -0
  129. package/src/composables/element.ts +13 -0
  130. package/src/composables/useCachedUid.ts +48 -0
  131. package/src/composables/useEventListener.ts +14 -0
  132. package/src/composables/useInput.ts +134 -0
  133. package/src/composables/useIsServer.ts +7 -0
  134. package/src/composables/useMount.ts +43 -0
  135. package/src/composables/usePopper.ts +194 -0
  136. package/src/create.ts +34 -0
  137. package/src/css/components.css +14 -0
  138. package/src/css/index.css +4 -0
  139. package/src/css/normalize.css +379 -0
  140. package/src/css/transitions.css +40 -0
  141. package/src/css/variables.css +80 -0
  142. package/src/exports/nuxt.js +33 -0
  143. package/src/exports/nuxt.plugin.js +8 -0
  144. package/src/index.ts +5 -0
  145. package/src/install.ts +8 -0
  146. package/src/shims-vue.d.ts +6 -0
  147. package/src/types/props.ts +3 -0
@@ -0,0 +1,19 @@
1
+ import MTable from "../Table.vue";
2
+ import MButton from "../../button/Button.vue";
3
+ import {
4
+ MTableBasic
5
+ } from "./index";
6
+
7
+ import {
8
+ createStory
9
+ } from "@/__storybook__";
10
+
11
+ export default {
12
+ component: MTable,
13
+ subcomponents: {
14
+ MButton
15
+ },
16
+ title: 'Components/Table',
17
+ }
18
+
19
+ export const Basic = createStory(MTableBasic);
@@ -0,0 +1 @@
1
+ export { default as MTableBasic } from './basic.vue';
@@ -0,0 +1,5 @@
1
+ export type TableHeadItem = {
2
+ key: string;
3
+ name?: string;
4
+ width?: string | number;
5
+ }
@@ -0,0 +1,49 @@
1
+ .m-tooltip--wrapper {
2
+ position: relative;
3
+ display: inline-block;
4
+ cursor: pointer;
5
+ }
6
+
7
+ .m-tooltip {
8
+ box-sizing: border-box;
9
+ }
10
+
11
+ .m-tooltip.m-tooltip--reverse .m-tooltip--content {
12
+ background-color: rgba(255, 255, 255, 0.9);
13
+ color: #000;
14
+ }
15
+
16
+ .m-tooltip .m-tooltip--content {
17
+ transition: opacity 0.3s ease;
18
+ font-size: 12px;
19
+ font-weight: normal;
20
+ color: #fff;
21
+ background-color: rgba(0, 0, 0, 0.75);
22
+ border-radius: 4px;
23
+ padding: 5px 10px;
24
+ pointer-events: none;
25
+ width: max-content;
26
+ max-width: 300px;
27
+ }
28
+
29
+ .m-tooltip .tooltip--arrow {
30
+ position: absolute;
31
+ color: rgba(0, 0, 0, 0.75);
32
+ width: 10px;
33
+ }
34
+
35
+ .m-tooltip[data-popper-placement^=top] {
36
+ padding: 5px 0 14px;
37
+ }
38
+
39
+ .m-tooltip[data-popper-placement^=bottom] {
40
+ padding: 14px 0 5px;
41
+ }
42
+
43
+ .m-tooltip[data-popper-placement^=left] {
44
+ padding: 0 8px 0 5px;
45
+ }
46
+
47
+ .m-tooltip[data-popper-placement^=right] {
48
+ padding: 0 5px 0 8px;
49
+ }
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <span @mouseenter="isOpen = true" @mouseleave="isOpen = false" ref="reference">
3
+ <slot name="trigger" />
4
+ <Teleport :to="'body'">
5
+ <Transition :name="transitionName">
6
+ <div ref="popper" v-show="isOpen" :class="computedClasses">
7
+ <span class="m-tooltip--content">
8
+ <slot />
9
+ </span>
10
+ </div>
11
+ </Transition>
12
+ </Teleport>
13
+ </span>
14
+ </template>
15
+
16
+ <script lang="ts">
17
+ import { defineComponent, ref, toRef, type PropType, computed, watch } from 'vue';
18
+ import { type Placement, placementWhileList, usePopper } from "../../composables/usePopper";
19
+
20
+ export default defineComponent({
21
+ name: "MTooltip",
22
+ props: {
23
+ placement: {
24
+ type: String as PropType<Placement>,
25
+ default: 'top',
26
+ validator: (value: Placement) => placementWhileList.includes(value)
27
+ },
28
+ transitionName: {
29
+ type: String,
30
+ default: 'scale'
31
+ },
32
+ reverse: {
33
+ type: Boolean,
34
+ default: false
35
+ },
36
+ transfer: {
37
+ type: Boolean,
38
+ default: false
39
+ }
40
+ },
41
+ setup(props, { emit }) {
42
+ const placement = ref(props.placement);
43
+ // @ts-ignore
44
+ const transfer = toRef(props, 'transfer');
45
+ const wrapper = ref<HTMLElement | null>(null);
46
+ const reference = ref<HTMLElement | null>(null);
47
+ const isOpen = ref(false);
48
+
49
+ const { popper, transferTo, updatePopper } = usePopper({
50
+ placement,
51
+ transfer,
52
+ reference,
53
+ wrapper
54
+ });
55
+
56
+ const transitionName = computed(() => {
57
+ return `m-transition__${props.transitionName}`;
58
+ });
59
+
60
+ const computedClasses = computed(() => {
61
+ return [
62
+ 'm-tooltip',
63
+ {
64
+ 'm-tooltip--reverse': props.reverse
65
+ }
66
+ ]
67
+ });
68
+
69
+ watch(() => isOpen.value, (value) => {
70
+ if (value) {
71
+ updatePopper();
72
+ }
73
+ });
74
+
75
+ return {
76
+ reference,
77
+ popper,
78
+ transferTo,
79
+ transitionName,
80
+ isOpen,
81
+ computedClasses
82
+ }
83
+ }
84
+ })
85
+ </script>
@@ -0,0 +1,8 @@
1
+ <template>
2
+ <MTooltip>
3
+ <template #trigger>
4
+ <MButton>Top</MButton>
5
+ </template>
6
+ The top textdsfsdfsdf
7
+ </MTooltip>
8
+ </template>
@@ -0,0 +1,21 @@
1
+ import MTooltip from "../Tooltip.vue";
2
+ import MButton from "@/components/button/Button.vue";
3
+ import {
4
+ MTooltipBasic
5
+ } from "./index";
6
+
7
+ import {
8
+ createStory,
9
+ popperPositionArgType
10
+ } from "@/__storybook__";
11
+
12
+ export default {
13
+ component: MTooltip,
14
+ subcomponents: { MButton },
15
+ title: 'Components/Tooltip',
16
+ argTypes: {
17
+ ...popperPositionArgType()
18
+ }
19
+ }
20
+
21
+ export const Basic = createStory(MTooltipBasic);
@@ -0,0 +1 @@
1
+ export { default as MTooltipBasic } from "./basic.vue";
@@ -0,0 +1,13 @@
1
+ .virtual-scroller {
2
+ overflow: auto;
3
+ will-change: transform;
4
+ }
5
+
6
+ .virtual-scroller>div {
7
+ overflow: hidden;
8
+ will-change: transform;
9
+ }
10
+
11
+ .virtual-scroller>div>div {
12
+ will-change: transform;
13
+ }
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div ref="scroller" class="m-virtual-scroller" @scroll="onScroll">
3
+ <div :style="{ height: `${totalHeight}px` }">
4
+ <div :style="{ transform: `translateY(${offsetY}px)` }">
5
+ <template v-for="item in renderedItems">
6
+ <slot :item="item" :height="itemHeight"></slot>
7
+ </template>
8
+ </div>
9
+ </div>
10
+ </div>
11
+ </template>
12
+
13
+ <script lang="ts">
14
+ export default {
15
+ name: "MVirtualScroller"
16
+ }
17
+ </script>
18
+
19
+ <script lang="ts" setup>
20
+ import { computed, onMounted, ref, toRefs } from 'vue';
21
+ const props = defineProps({
22
+ items: {
23
+ required: true,
24
+ type: Array,
25
+ },
26
+ itemHeight: {
27
+ required: true,
28
+ type: Number,
29
+ default: 35,
30
+ },
31
+ buffer: {
32
+ default: 10,
33
+ type: Number,
34
+ }
35
+ });
36
+ const { items, itemHeight, buffer } = toRefs(props);
37
+ const scroller = ref();
38
+ const scrollerHeight = ref(0);
39
+ const scrollTop = ref(0);
40
+ const totalHeight = computed(() => items.value.length * itemHeight.value);
41
+ const startPosition = computed(() =>
42
+ Math.max(0, Math.floor(scrollTop.value / itemHeight.value) - buffer.value)
43
+ );
44
+ const offsetY = computed(() => startPosition.value * itemHeight.value);
45
+ const renderedItems = computed(() => {
46
+ let count =
47
+ Math.ceil(scrollerHeight.value / itemHeight.value) + 2 * buffer.value;
48
+ count = Math.min(items.value.length - startPosition.value, count);
49
+ return items.value.slice(startPosition.value, startPosition.value + count);
50
+ });
51
+ const onScroll = (e: Event) => {
52
+ requestAnimationFrame(() => (scrollTop.value = (e.target as HTMLElement).scrollTop));
53
+ };
54
+ const observer = new ResizeObserver((entries) =>
55
+ entries.forEach((el) => (scrollerHeight.value = el.contentRect.height))
56
+ );
57
+ onMounted(() => {
58
+ observer.observe(scroller.value);
59
+ scrollerHeight.value = scroller.value.offsetHeight;
60
+ });
61
+ </script>
@@ -0,0 +1,37 @@
1
+ <script lang="ts" setup>
2
+ const props = defineProps({
3
+ items: {
4
+ type: Array,
5
+ default: () => []
6
+ },
7
+ itemHeight: {
8
+ type: Number,
9
+ default: 50
10
+ },
11
+ buffer: {
12
+ type: Number,
13
+ default: 3
14
+ },
15
+ pageHeight: {
16
+ type: Number,
17
+ default: 400
18
+ }
19
+ })
20
+ </script>
21
+
22
+ <template>
23
+ <div>
24
+ <MVirtualScroll
25
+ v-slot="{ item, height }"
26
+ v-bind="props"
27
+ :style="{
28
+ height: `${props.pageHeight}px`,
29
+ overflow: 'auto'
30
+ }"
31
+ >
32
+ <div :key="item.id" :style="{height: `${height}px`}">
33
+ {{ item.name }}
34
+ </div>
35
+ </MVirtualScroll>
36
+ </div>
37
+ </template>
@@ -0,0 +1,31 @@
1
+ import MVirtualScroll from "../VirtualScroll.vue";
2
+ import {
3
+ MVirtualScrollBasic
4
+ } from "./index";
5
+
6
+ import {
7
+ createStory
8
+ } from "@/__storybook__";
9
+
10
+ export default {
11
+ component: MVirtualScroll,
12
+ title: 'Components/VirtualScroll'
13
+ }
14
+
15
+ const items = [] as any[];
16
+
17
+ for (let i = 0; i < 1000; i++) {
18
+ items.push({
19
+ id: i + 1,
20
+ name: 'Some name here ' + (i + 1),
21
+ });
22
+ }
23
+
24
+ export const Basic = createStory(MVirtualScrollBasic).bind({});
25
+ // @ts-ignore
26
+ Basic.args = {
27
+ items: items,
28
+ itemHeight: 50,
29
+ buffer: 3,
30
+ pageHeight: 500,
31
+ };
@@ -0,0 +1 @@
1
+ export { default as MVirtualScrollBasic } from './basic.vue';
@@ -0,0 +1,13 @@
1
+ import type { Ref } from "vue";
2
+
3
+ export function getElement(ref: Ref) {
4
+ if(ref === null) {
5
+ return null;
6
+ }
7
+
8
+ if(ref.value === null) {
9
+ return null;
10
+ }
11
+
12
+ return "$el" in ref.value ? ref.value.$el : ref.value;
13
+ }
@@ -0,0 +1,48 @@
1
+ // https://github.com/liip/chusho/blob/main/packages/chusho/lib/composables/useCachedUid.ts#L20-L41 - Legend :D
2
+ import { onMounted, readonly, ref } from 'vue';
3
+ import { getElement } from './element';
4
+ import type { ComponentPublicInstance, Ref } from 'vue';
5
+
6
+ const UID_CACHE_ATTR = 'data-modlr-ssr-uid';
7
+
8
+ // @ts-nocheck
9
+ type CacheElement = HTMLElement | SVGElement | ComponentPublicInstance | null;
10
+
11
+ export function uid(prefix: string = ''): string {
12
+ const id = Date.now().toString(36) + Math.random().toString(36).substring(2);
13
+ return prefix ? `${prefix}-${id}` : id;
14
+ }
15
+
16
+ export interface IUseCacheUid {
17
+ id: Readonly<Ref<string>>;
18
+ cacheAttrs: {
19
+ ref: Ref<CacheElement>;
20
+ [UID_CACHE_ATTR]?: string;
21
+ };
22
+ }
23
+
24
+ export function useCachedUid(prefix?: string): IUseCacheUid {
25
+ let id = ref(uid(prefix));
26
+ const cacheElement = ref<CacheElement>(null);
27
+
28
+ onMounted(() => {
29
+ if(cacheElement.value) {
30
+ const element = getElement(cacheElement);
31
+ const serverId = element?.getAttribute(UID_CACHE_ATTR);
32
+
33
+ if(serverId) {
34
+ id.value = serverId;
35
+ }
36
+
37
+ element?.removeAttribute(UID_CACHE_ATTR);
38
+ }
39
+ });
40
+
41
+ return {
42
+ id: readonly(id),
43
+ cacheAttrs: {
44
+ ref: cacheElement,
45
+ [UID_CACHE_ATTR]: typeof window === undefined ? id.value : undefined
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,14 @@
1
+ import { watchEffect } from "vue";
2
+
3
+ export function useEventListener<T extends EventTarget | HTMLElement, E extends EventListener>(element: T, type: string, listener: E, options: boolean) {
4
+ if(typeof window === undefined) {
5
+ return;
6
+ }
7
+
8
+ watchEffect((onInvalidate) => {
9
+ element = element ?? window;
10
+
11
+ element.addEventListener(type, listener, options);
12
+ onInvalidate(() => element.removeEventListener(type, listener, options));
13
+ })
14
+ }
@@ -0,0 +1,134 @@
1
+ // inspired by indielayer ui
2
+ import type { PropType } from 'vue';
3
+ import { ref, watch, inject, computed, onMounted, onUnmounted } from 'vue';
4
+ import { useCachedUid } from './useCachedUid';
5
+
6
+ export interface FormInput {
7
+ focus: () => void;
8
+ validate: (value: any) => void;
9
+ setError: (value: string) => void;
10
+ }
11
+
12
+ export const useInput = (props: any, { focus, emit, withListeners = true }: {
13
+ focus: () => void,
14
+ emit: any,
15
+ withListeners?: boolean
16
+ }) => {
17
+ const isFirstValidation = ref(true);
18
+ const formError = ref(props.error);
19
+
20
+ const { id } = useCachedUid('input');
21
+ const name = props.name ? props.name : id.value;
22
+ const _name = ref(name);
23
+
24
+ watch(() => props.error, (value) => formError.value = value);
25
+ watch(() => props.name, (value) => name.value = value);
26
+
27
+ const form = inject('m-form', {
28
+ add: (inputName: string, methods: FormInput) => {},
29
+ remove: (inputName: string) => {},
30
+ insideForm: false,
31
+ disabled: false,
32
+ loading: false
33
+ });
34
+
35
+ const reset = () => {
36
+ formError.value = '';
37
+ isFirstValidation.value = true;
38
+ emit('update:modelValue', '');
39
+ };
40
+
41
+ const setError = (value: string) => {
42
+ formError.value = value;
43
+ };
44
+
45
+ const validate = (value: any): boolean => {
46
+ value = value || props.modelValue;
47
+
48
+ isFirstValidation.value = false;
49
+
50
+ for (let i = 0; i < props.rules.length; i++) {
51
+ const item = props.rules[i];
52
+
53
+ let valid = true;
54
+
55
+ if (typeof item === 'function') {
56
+ valid = item(value);
57
+ } else if(Array.isArray(item) && item.length === 2) {
58
+ const { 0: rule, 1: options } = item;
59
+ valid = rule(value, options);
60
+ } else {
61
+ const rule = item.fn;
62
+ const { options } = item;
63
+
64
+ valid = rule(value, options);
65
+ }
66
+
67
+ if (valid !== true) {
68
+ formError.value = valid;
69
+ return false;
70
+ }
71
+ }
72
+
73
+ formError.value = '';
74
+ return true;
75
+ };
76
+
77
+ const listeners = withListeners ? computed(() => {
78
+ return {
79
+ blur: (event: Event) => emit('blur', event),
80
+ focus: (event: Event) => emit('focus', event),
81
+ input: (event: Event) => {
82
+ emit('update:modelValue', (event.target as HTMLInputElement).value);
83
+ },
84
+ change: (event: Event) => emit('change', event)
85
+ }
86
+ }) : {};
87
+
88
+ onMounted(() => {
89
+ form.add(_name.value,
90
+ focus,
91
+ // @ts-ignore
92
+ validate,
93
+ // @ts-ignore
94
+ setError
95
+ );
96
+ })
97
+
98
+ onUnmounted(() => {
99
+ form.remove(_name.value);
100
+ });
101
+
102
+ return {
103
+ id,
104
+ isFirstValidation,
105
+ formError,
106
+ insideForm: form.insideForm,
107
+ listeners,
108
+ reset,
109
+ validate,
110
+ setError,
111
+ //@ts-ignore
112
+ formDisabled: form.disabled.value,
113
+ //@ts-ignore
114
+ formLoading: form.loading.value
115
+ }
116
+ };
117
+
118
+ useInput.emits = (withListeners: boolean = true): string[] => {
119
+ return withListeners ?
120
+ ['update:modelValue', 'blur', 'focus', 'input', 'change'] :
121
+ ['update:modelValue'];
122
+ }
123
+
124
+ useInput.props = () => ({
125
+ modelValue: [String, Number, Boolean, Object, Array] as PropType<string | number | boolean | object | any[] | undefined>,
126
+ name: String,
127
+ readonly: Boolean,
128
+ required: Boolean,
129
+ error: String,
130
+ rules: {
131
+ type: Array,
132
+ default: () => [],
133
+ }
134
+ } as const);
@@ -0,0 +1,7 @@
1
+ import { ref } from 'vue';
2
+
3
+ export function useIsServer() {
4
+ const isServer = ref(typeof window === 'undefined');
5
+
6
+ return isServer;
7
+ }
@@ -0,0 +1,43 @@
1
+ import { createVNode, render } from "vue";
2
+ import type { App, Component } from "vue";
3
+
4
+ export function mount(
5
+ component: Component,
6
+ {
7
+ props,
8
+ children,
9
+ element,
10
+ app
11
+ }: {
12
+ props?: Record<string, unknown>,
13
+ children?: unknown,
14
+ app?: App,
15
+ element?: HTMLElement
16
+ } = {}
17
+ ) {
18
+ let el = element;
19
+
20
+ const vNode = createVNode(component, props, children);
21
+
22
+ if (app && app._context) {
23
+ vNode.appContext = app._context;
24
+ }
25
+
26
+ if (el) {
27
+ render(vNode, el);
28
+ } else if(typeof document !== 'undefined') {
29
+ render(vNode, (el = document.createElement('div')))
30
+ }
31
+
32
+ const destroy = () => {
33
+ if (el) {
34
+ render(null, el);
35
+ }
36
+ }
37
+
38
+ return {
39
+ el,
40
+ vNode,
41
+ destroy,
42
+ }
43
+ }