@naptics/vue-collection 0.0.3 → 0.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 (68) hide show
  1. package/README.md +5 -1
  2. package/components/NAlert.js +81 -0
  3. package/components/NBadge.js +57 -0
  4. package/components/NBreadcrub.js +66 -0
  5. package/components/NButton.js +65 -0
  6. package/components/NCheckbox.js +42 -0
  7. package/components/NCheckboxLabel.js +39 -0
  8. package/components/NCrudModal.js +105 -0
  9. package/components/NDialog.js +160 -0
  10. package/components/NDropdown.js +108 -0
  11. package/components/NDropzone.js +210 -0
  12. package/components/NForm.js +28 -0
  13. package/components/NFormModal.js +54 -0
  14. package/components/NIconButton.js +81 -0
  15. package/components/NIconCircle.js +66 -0
  16. package/components/NInput.js +105 -0
  17. package/components/NInputPhone.js +46 -0
  18. package/components/NInputSelect.js +114 -0
  19. package/components/NInputSuggestion.js +63 -0
  20. package/components/NLink.js +59 -0
  21. package/components/NList.js +24 -0
  22. package/components/NLoadingIndicator.js +53 -0
  23. package/components/NModal.js +210 -0
  24. package/components/NPagination.js +108 -0
  25. package/components/NSearchbar.js +66 -0
  26. package/components/NSearchbarList.js +36 -0
  27. package/components/NSelect.js +84 -0
  28. package/components/NSuggestionList.js +156 -0
  29. package/components/NTable.js +126 -0
  30. package/components/NTableAction.js +49 -0
  31. package/components/NTextArea.js +128 -0
  32. package/components/NTooltip.js +178 -0
  33. package/components/NValInput.js +104 -0
  34. package/components/ValidatedForm.js +18 -18
  35. package/i18n/index.js +0 -4
  36. package/package.json +9 -2
  37. package/components/NAlert.jsx +0 -69
  38. package/components/NBadge.jsx +0 -58
  39. package/components/NBreadcrub.jsx +0 -64
  40. package/components/NButton.jsx +0 -58
  41. package/components/NCheckbox.jsx +0 -38
  42. package/components/NCheckboxLabel.jsx +0 -42
  43. package/components/NCrudModal.jsx +0 -89
  44. package/components/NDialog.jsx +0 -144
  45. package/components/NDropdown.jsx +0 -92
  46. package/components/NDropzone.jsx +0 -211
  47. package/components/NForm.jsx +0 -26
  48. package/components/NFormModal.jsx +0 -48
  49. package/components/NIconButton.jsx +0 -71
  50. package/components/NIconCircle.jsx +0 -67
  51. package/components/NInput.jsx +0 -97
  52. package/components/NInputPhone.jsx +0 -32
  53. package/components/NInputSelect.jsx +0 -89
  54. package/components/NInputSuggestion.jsx +0 -48
  55. package/components/NLink.jsx +0 -58
  56. package/components/NList.jsx +0 -24
  57. package/components/NLoadingIndicator.jsx +0 -42
  58. package/components/NModal.jsx +0 -170
  59. package/components/NPagination.jsx +0 -104
  60. package/components/NSearchbar.jsx +0 -58
  61. package/components/NSearchbarList.jsx +0 -20
  62. package/components/NSelect.jsx +0 -81
  63. package/components/NSuggestionList.jsx +0 -157
  64. package/components/NTable.jsx +0 -146
  65. package/components/NTableAction.jsx +0 -35
  66. package/components/NTextArea.jsx +0 -108
  67. package/components/NTooltip.jsx +0 -161
  68. package/components/NValInput.jsx +0 -101
@@ -1,146 +0,0 @@
1
- import { isWidthBreakpoint } from '../utils/breakpoints';
2
- import { createComponent, createProps } from '../utils/component';
3
- import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/vue/24/solid';
4
- import { computed, Fragment, ref, watch } from 'vue';
5
- import NIconButton from './NIconButton';
6
- import './NTable.css';
7
- const N_TABLE_ACTION_KEY = 'action';
8
- export const nTableProps = createProps({
9
- /**
10
- * The headings of the table. These define which columns are shown in the table and in which order.
11
- */
12
- headings: {
13
- type: Array,
14
- required: true,
15
- },
16
- /**
17
- * Details can be added additionally to headings.
18
- * If details are set a little chevron icon is displayed at the end of each table row
19
- * and if clicked on it the data is displayed in a key-value fashion.
20
- * The values of the entries should be passed via the `items` prop
21
- * in the same way as if the details were normal headings.
22
- * Note that details can be added dynamically by adding the `breakpoint` property to the headings.
23
- */
24
- details: {
25
- type: Array,
26
- default: () => [],
27
- },
28
- /**
29
- * The items of the table. They consist of an array of table rows.
30
- * Every tablerow is an object containing elements for the heading keys.
31
- * The elements can either be a primitive value or a function which returns a {@link JSX.Element}.
32
- * If the item should be treated as an action (e.g. icon-button to display at the end of the row)
33
- * the dedicated key 'action' can be used.
34
- * @see TableRow
35
- * @example
36
- * // These headings are defined
37
- * const headings: TableHeading[] = [
38
- * { key: 'id', label: 'ID' },
39
- * { key: 'name', label: 'Name' },
40
- * { key: 'status', label: 'Status' }
41
- * ]
42
- *
43
- * // Appropriate rows for these headings
44
- * const items: TableRow[] = [
45
- * { id: 1, name: 'Hubert', status: () => <NBadge ... />, action: ... }, // Row 1
46
- * { id: 2, name: 'Franzi', status: () => <NBadge ... />, action: ... } // Row 2
47
- * ]
48
- */
49
- items: {
50
- type: Array,
51
- default: () => [],
52
- },
53
- });
54
- /**
55
- * The `NTable` is a styled html table which accepts data and displays it appropriately.
56
- */
57
- export default createComponent('NTable', nTableProps, props => {
58
- const headings = computed(() => {
59
- // remove all headings which are below the breakpoint
60
- const headings = props.headings.filter(heading => !heading.breakpoint || isWidthBreakpoint(heading.breakpoint).value);
61
- // The column for actions is shown if there are details
62
- // or if any of the items contain an element with the action-key.
63
- if (showDetails.value || props.items.filter(row => row.action != null).length != 0) {
64
- headings.push({ key: N_TABLE_ACTION_KEY });
65
- }
66
- return headings;
67
- });
68
- const details = computed(() => {
69
- // take all headings which are below the breakpoint
70
- const details = props.headings.filter(heading => heading.breakpoint && !isWidthBreakpoint(heading.breakpoint).value);
71
- details.push(...props.details);
72
- return details;
73
- });
74
- const showDetails = computed(() => details.value.length > 0);
75
- const detailsOpen = ref([]);
76
- const isDetailsOpen = (index) => detailsOpen.value[index] || false;
77
- const toggleDetailsOpen = (index) => (detailsOpen.value[index] = !detailsOpen.value[index]);
78
- // if the items change, reset all open details to closed
79
- // and create correct amount of booleans for all items
80
- watch(() => props.items, newItems => (detailsOpen.value = Array({ length: newItems.length }).map(() => false)), { immediate: true });
81
- return () => (<div class="overflow-x-auto">
82
- <table class="min-w-full text-default-500 text-sm">
83
- <thead class="bg-default-50 ">
84
- <tr>
85
- {headings.value.map(heading => (<th key={heading.key} scope="col" class="p-4 table-heading">
86
- {heading.label}
87
- </th>))}
88
- </tr>
89
- </thead>
90
-
91
- {props.items.length > 0 &&
92
- props.items.map((item, itemIndex) => (<Fragment key={itemIndex}>
93
- {/* First tbody is the actual table-row with the entries */}
94
- <tbody class={[
95
- 'border-default-200 border-t',
96
- itemIndex % 2 === 0 ? 'bg-white' : 'bg-default-50',
97
- ]}>
98
- <tr>
99
- {headings.value.map(heading => (<td key={itemIndex + '-' + heading.key} class="p-4">
100
- <div class={[
101
- 'flex',
102
- heading.emph ? 'font-medium text-default-900' : '',
103
- heading.cellClass,
104
- heading.key == N_TABLE_ACTION_KEY
105
- ? 'justify-end items-center space-x-3'
106
- : '',
107
- ]}>
108
- {item[heading.key] && buildItem(item[heading.key])}
109
-
110
- {/* Add the chevron icon-button if details are present */}
111
- {heading.key == N_TABLE_ACTION_KEY && showDetails.value && (<NIconButton icon={isDetailsOpen(itemIndex) ? ChevronDownIcon : ChevronUpIcon} onClick={() => toggleDetailsOpen(itemIndex)}/>)}
112
- </div>
113
- </td>))}
114
- </tr>
115
- </tbody>
116
-
117
- {/* Second tbody are the details (only shown if present and opened) */}
118
- {showDetails.value && isDetailsOpen(itemIndex) && (<tbody class={itemIndex % 2 === 0 ? 'bg-white' : 'bg-default-50'}>
119
- {details.value.map((detail, detailIndex) => (<tr key={`detail-${detailIndex}`}>
120
- <td class={[
121
- 'table-heading px-4 py-1',
122
- details.value.length - 1 == detailIndex ? 'pb-4' : '',
123
- ]}>
124
- {detail.label}
125
- </td>
126
- <td class={[
127
- 'px-4 py-1',
128
- details.value.length - 1 == detailIndex ? 'pb-4' : '',
129
- ]} colspan={headings.value.length - 1}>
130
- {item[detail.key] && buildItem(item[detail.key])}
131
- </td>
132
- </tr>))}
133
- </tbody>)}
134
- </Fragment>))}
135
- </table>
136
- </div>);
137
- });
138
- /**
139
- * Builds a JSX-Element out of the item
140
- */
141
- function buildItem(item) {
142
- if (typeof item == 'string' || typeof item == 'number')
143
- return <>{item}</>;
144
- else
145
- return item();
146
- }
@@ -1,35 +0,0 @@
1
- import { createComponent, createProps } from '../utils/component';
2
- import { RouterLink } from 'vue-router';
3
- import { nButtonProps } from './NButton';
4
- export const nTableActionProps = createProps({
5
- /**
6
- * The route of the action. If set the component will be a {@link RouterLink}.
7
- */
8
- route: [String, Object],
9
- /**
10
- * The text of the action.
11
- */
12
- text: String,
13
- /**
14
- * The html attribute, which indicates the type of the button.
15
- */
16
- type: nButtonProps.type,
17
- /**
18
- * This is called when the action is clicked.
19
- * It is only called when the `route` prop is not set on the action.
20
- */
21
- onClick: Function,
22
- });
23
- /**
24
- * The `NTableAction` is a button or {@link RouterLink} which is styled to fit into a table.
25
- * It is basically styled as an emphasized text in the table.
26
- */
27
- export default createComponent('NTableAction', nTableActionProps, (props, { slots }) => {
28
- const content = () => slots.default?.() || <>{props.text}</>;
29
- const classes = 'text-left font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-default-900 rounded-sm ring-offset-2 text-default-900 hover:underline hover:text-default-700';
30
- return () => props.route ? (<RouterLink to={props.route} class={classes}>
31
- {content()}
32
- </RouterLink>) : (<button type={props.type} class={classes} onClick={props.onClick}>
33
- {content()}
34
- </button>);
35
- });
@@ -1,108 +0,0 @@
1
- import { createComponent, createProps } from '../utils/component';
2
- import { ref } from 'vue';
3
- import { ExclamationCircleIcon } from '@heroicons/vue/24/solid';
4
- import NTooltip, { mapTooltipProps, nToolTipPropsForImplementor } from './NTooltip';
5
- import { vModelProps } from '../utils/vModel';
6
- import NValInput, { validationProps } from './NValInput';
7
- const nTextAreaBaseProps = createProps({
8
- ...vModelProps(String),
9
- /**
10
- * The name of the text area. Is displayed as a label above the text area.
11
- */
12
- name: String,
13
- /**
14
- * The placeholder of the text area.
15
- */
16
- placeholder: String,
17
- /**
18
- * The html autocomplete attribute of the text area.
19
- */
20
- autocomplete: {
21
- type: String,
22
- default: 'off',
23
- },
24
- /**
25
- * If set to `true`, the text area is resizable in y-direction.
26
- */
27
- resizable: {
28
- type: Boolean,
29
- default: true,
30
- },
31
- /**
32
- * The initial height of the text area in terms of
33
- * how many text rows fit inside the text area.
34
- * The height can be change if {@link nTextAreaProps.resizable} is `true`
35
- */
36
- rows: Number,
37
- /**
38
- * The maximum length of the input string. Entering longer strings are simply
39
- * prevented, but no error message is shown to the user.
40
- */
41
- maxLength: Number,
42
- /**
43
- * If set to `true` the text area is displayed with a red border.
44
- */
45
- error: Boolean,
46
- /**
47
- * If set to `true` the text area is disabled and no interaction is possible.
48
- */
49
- disabled: Boolean,
50
- /**
51
- * If set to `true` the text area's label is hidden.
52
- */
53
- hideLabel: Boolean,
54
- /**
55
- * This is called when the text area reveices focus.
56
- */
57
- onFocus: Function,
58
- /**
59
- * This is called when the text area looses focus.
60
- */
61
- onBlur: Function,
62
- ...nToolTipPropsForImplementor,
63
- });
64
- export const nTextAreaProps = createProps({
65
- ...nTextAreaBaseProps,
66
- ...validationProps,
67
- });
68
- export default createComponent('NTextArea', nTextAreaProps, (props, context) => {
69
- const textAreaRef = ref();
70
- const exposed = {
71
- focus: () => textAreaRef.value?.focus(),
72
- };
73
- context.expose(exposed);
74
- return () => (<NValInput {...props} input={({ error, onBlur, onUpdateValue }) => (<NTextAreaBase ref={textAreaRef} {...{ ...props, error, onBlur, onUpdateValue }}/>)}/>);
75
- });
76
- /**
77
- * The `NTextArea` wraps the html text area with all the features from {@link NInput} and {@link NValInput}.
78
- */
79
- const NTextAreaBase = createComponent('NTextAreaBase', nTextAreaBaseProps, (props, context) => {
80
- const textAreaRef = ref();
81
- const exposed = {
82
- focus: () => textAreaRef.value?.focus(),
83
- };
84
- context.expose(exposed);
85
- return () => (<div>
86
- {props.name && !props.hideLabel && (<label for={props.name} class={['block text-sm font-medium mb-1', props.disabled ? 'text-default-300' : 'text-default-700']}>
87
- {props.name}
88
- </label>)}
89
- <NTooltip block {...mapTooltipProps(props)}>
90
- <div class="relative">
91
- <textarea ref={textAreaRef} name={props.name} value={props.value} onInput={event => props.onUpdateValue?.(event.target.value)} placeholder={props.placeholder} autocomplete={props.autocomplete} disabled={props.disabled} rows={props.rows} maxlength={props.maxLength} onFocus={() => props.onFocus?.()} onBlur={() => props.onBlur?.()} onInvalid={event => event.preventDefault()} class={[
92
- 'block w-full rounded-md border focus:outline-none focus:ring-1 ',
93
- props.disabled
94
- ? 'text-default-500 placeholder-default-300 bg-default-50'
95
- : 'text-default-900 placeholder-default-400 ',
96
- props.error
97
- ? 'border-red-500 focus:border-red-500 focus:ring-red-500 pr-10'
98
- : 'border-default-300 focus:border-primary-500 focus:ring-primary-500',
99
- props.resizable ? 'resize-y' : 'resize-none',
100
- ]}/>
101
-
102
- <div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none" v-show={props.error}>
103
- <ExclamationCircleIcon class="h-5 w-5 text-red-700" aria-hidden="true"/>
104
- </div>
105
- </div>
106
- </NTooltip>
107
- </div>);
108
- });
@@ -1,161 +0,0 @@
1
- import { createComponent, createProps } from '../utils/component';
2
- import { uniqueId } from '../utils/utils';
3
- import { computed, onMounted, ref, watch, onUnmounted, Transition } from 'vue';
4
- import { createPopper } from '@popperjs/core';
5
- import { watchRef } from '../utils/vue';
6
- import './NTooltip.css';
7
- export const nTooltipProps = createProps({
8
- /**
9
- * The text content of the tooltip.
10
- */
11
- text: String,
12
- /**
13
- * A slot to replace the content of the tooltip. This will override the `text` prop.
14
- */
15
- content: Function,
16
- /**
17
- * If set to `true` the tooltip is shown constantly.
18
- */
19
- show: Boolean,
20
- /**
21
- * If set to `true` the tooltip is hidden constantly.
22
- */
23
- hide: Boolean,
24
- /**
25
- * If set to `true` the `block` class is applied to the tooltip.
26
- * This should be set if the content in the default slot is also block.
27
- */
28
- block: Boolean,
29
- /**
30
- * The placement of the tooltip.
31
- */
32
- placement: {
33
- type: String,
34
- default: 'auto',
35
- },
36
- /**
37
- * The maximum width of the tooltip.
38
- */
39
- maxWidth: {
40
- type: String,
41
- default: 'max-w-xs',
42
- },
43
- });
44
- /**
45
- * These props are made to use on a component which implements the tooltip
46
- * and wants it to be controllable via the own props.
47
- * e.g. `text` is now called `tooltipText`.
48
- * They can be mapped to the normal tooltip props with {@link mapTooltipProps}
49
- */
50
- export const nToolTipPropsForImplementor = {
51
- /**
52
- * Adds a tooltip to the component with the specified text.
53
- * @see {@link nTooltipProps.text}
54
- */
55
- tooltipText: nTooltipProps.text,
56
- /**
57
- * A slot for the tooltip of this component.
58
- * If the slot is set, the tooltip with the specified content is added to the component.
59
- * @see {@link nTooltipProps.content}
60
- */
61
- tooltipContent: nTooltipProps.content,
62
- /**
63
- * @see {@link nTooltipProps.hide}
64
- */
65
- tooltipHide: nTooltipProps.hide,
66
- /**
67
- * @see {@link nTooltipProps.show}
68
- */
69
- tooltipShow: nTooltipProps.show,
70
- /**
71
- * @see {@link nTooltipProps.placement}
72
- */
73
- tooltipPlacement: nTooltipProps.placement,
74
- /**
75
- * @see {@link nTooltipProps.maxWidth}
76
- */
77
- tooltipMaxWidth: nTooltipProps.maxWidth,
78
- };
79
- /**
80
- * Maps the {@link nToolTipPropsForImplementor} props to normal tooltip props
81
- * @returns an object containing the normal tooltip props.
82
- */
83
- export function mapTooltipProps(props) {
84
- return {
85
- text: props.tooltipText,
86
- content: props.tooltipContent,
87
- hide: props.tooltipHide,
88
- show: props.tooltipShow,
89
- placement: props.tooltipPlacement,
90
- maxWidth: props.tooltipMaxWidth,
91
- };
92
- }
93
- /**
94
- * The `NTooltip` is a wrapper for any component which adds a tooltip to it.
95
- * Any component can just be passed in the default slot and a tooltip will be added to it.
96
- * Note that this component disappears when neither the `text` nor the `content`
97
- * prop is passed as the tooltip would then be empty.
98
- * If this is the case, the default slot will just be rendered inside a div.
99
- * @example
100
- * <NTooltip text="Hello">
101
- * <NButton />
102
- * </NTooltip>
103
- */
104
- export default createComponent('NTooltip', nTooltipProps, (props, { slots }) => {
105
- return () => (<div class={props.block ? 'block' : 'inline-block'}>
106
- {props.content || props.text ? (<NTooltipBase {...props}>{slots.default?.()}</NTooltipBase>) : (slots.default?.())}
107
- </div>);
108
- });
109
- const NTooltipBase = createComponent('NTooltipBase', nTooltipProps, (props, { slots }) => {
110
- let popperInstance = null;
111
- const contentId = `content-${uniqueId()}`;
112
- const tooltipId = `tooltip-${uniqueId()}`;
113
- function createTooltip() {
114
- const content = document.getElementById(contentId);
115
- const tooltip = document.getElementById(tooltipId);
116
- if (content && tooltip) {
117
- popperInstance = createPopper(content, tooltip, {
118
- placement: props.placement,
119
- modifiers: [
120
- {
121
- name: 'offset',
122
- options: {
123
- offset: [0, 8],
124
- },
125
- },
126
- ],
127
- });
128
- }
129
- else {
130
- console.error('Could not create tooltip. HTML elements for content or tooltip were not found.');
131
- }
132
- }
133
- function destroyTooltip() {
134
- popperInstance?.destroy();
135
- popperInstance = null;
136
- }
137
- onMounted(createTooltip);
138
- onUnmounted(destroyTooltip);
139
- watch(() => props.placement, newPlacement => popperInstance?.setOptions({ placement: newPlacement }));
140
- const isHoveringContent = ref(false);
141
- const isHoveringTooltip = ref(false);
142
- const isHovering = computed(() => isHoveringContent.value || isHoveringTooltip.value);
143
- const showTooltip = computed(() => props.show || (!props.hide && isHovering.value));
144
- watchRef(showTooltip, () => popperInstance?.update());
145
- return () => (<>
146
- <div class="p-[10px] -m-[10px]" onMouseleave={() => setTimeout(() => (isHoveringContent.value = false), 10)}>
147
- <div id={contentId} onMouseenter={() => (isHoveringContent.value = true)}>
148
- {slots.default?.()}
149
- </div>
150
- </div>
151
-
152
- <Transition enterActiveClass="transition-opacity ease-out duration-100" enterFromClass="opacity-0" enterToClass="opacity-100" leaveActiveClass="transition-opacity ease-in duration-75" leaveFromClass="opacity-100" leaveToClass="opacity-0">
153
- <div id={tooltipId} role="tooltip" onMouseenter={() => (isHoveringTooltip.value = true)} onMouseleave={() => (isHoveringTooltip.value = false)} v-show={showTooltip.value} class={[isHovering.value ? 'z-20' : 'z-10', props.maxWidth, 'tooltip']}>
154
- <div class="bg-white rounded-md py-2 px-4 shadow-lg border-default-200 border text-sm font-normal text-default-700">
155
- {props.content?.() || props.text}
156
- </div>
157
- <div data-popper-arrow class="arrow"/>
158
- </div>
159
- </Transition>
160
- </>);
161
- });
@@ -1,101 +0,0 @@
1
- import { createComponent, createProps } from '../utils/component';
2
- import { computed } from 'vue';
3
- import { ref, reactive, watch } from 'vue';
4
- import NInput, { nInputProps } from './NInput';
5
- import { validate, required } from '../utils/validation';
6
- export const validationProps = createProps({
7
- /**
8
- * If set to `true` this input is always valid when its value is empty.
9
- * If set to `false` the input receives the {@link required} rule. Default is `false`.
10
- */
11
- optional: Boolean,
12
- /**
13
- * The rules which this input is checked with.
14
- * The rules are checked sequentially and the error of the first failed rule is displayed.
15
- * If `optional` is set to false, the rule {@link required} will be checked first.
16
- */
17
- rules: {
18
- type: [Function, Array],
19
- default: () => [],
20
- },
21
- /**
22
- * The form, which this input will be added to.
23
- * On initialization, this input will call {@link ValidatedForm.addInput} passing itself to the form.
24
- */
25
- form: Object,
26
- /**
27
- * Overrides the internal error state. If set to true, it will always display an error.
28
- */
29
- error: Boolean,
30
- /**
31
- * Overrides the internal error message. If set, this message is always displayed.
32
- */
33
- errorMessage: String,
34
- /**
35
- * If set to `true` the error message is not shown.
36
- * However, the input is still marked red if it is in an error state.
37
- */
38
- hideErrorMessage: Boolean,
39
- /**
40
- * Disables the validation on blur. Should only be used in special occasions.
41
- */
42
- disableBlurValidation: Boolean,
43
- });
44
- export const nValInputProps = createProps({
45
- ...nInputProps,
46
- ...validationProps,
47
- /**
48
- * A slot to replace the input.
49
- */
50
- input: Function,
51
- });
52
- /**
53
- * The `NValInput` is a `NInput` with custom validation.
54
- */
55
- export default createComponent('NValInput', nValInputProps, (props, context) => {
56
- const rules = computed(() => {
57
- const otherRules = Array.isArray(props.rules) ? props.rules : [props.rules];
58
- return props.optional ? otherRules : [required, ...otherRules];
59
- });
60
- const validationResult = ref();
61
- const validateRules = (input) => {
62
- const result = validate(input, rules.value);
63
- validationResult.value = result;
64
- return result;
65
- };
66
- const showError = computed(() => props.error || (validationResult.value != null && !validationResult.value.isValid));
67
- const showErrorMessage = computed(() => !props.hideErrorMessage && showError.value);
68
- const errorMessage = computed(() => props.errorMessage || validationResult.value?.errorMessage);
69
- const validateIfError = (value = props.value) => {
70
- if (showError.value)
71
- validateRules(value);
72
- };
73
- watch(() => props.value, () => validateIfError());
74
- watch(() => rules.value, () => validateIfError());
75
- const onBlur = () => {
76
- if (!props.disableBlurValidation)
77
- validateRules(props.value);
78
- props.onBlur?.();
79
- };
80
- const onUpdateValue = (newValue) => {
81
- validateIfError(newValue);
82
- props.onUpdateValue?.(newValue);
83
- };
84
- const inputSlotProps = reactive({
85
- onBlur,
86
- onUpdateValue,
87
- error: showError,
88
- });
89
- const inputRef = ref();
90
- const expose = {
91
- validate: () => validateRules(props.value),
92
- reset: () => (validationResult.value = undefined),
93
- focus: () => inputRef.value?.focus(),
94
- };
95
- context.expose(expose);
96
- props.form?.addInput(expose);
97
- return () => (<div>
98
- {props.input?.(inputSlotProps) || <NInput ref={inputRef} {...{ ...props, ...inputSlotProps }}/>}
99
- {showErrorMessage.value && <p class="text-red-500 text-xs mt-1">{errorMessage.value}</p>}
100
- </div>);
101
- });