@naptics/vue-collection 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -15
- package/components/NAlert.js +81 -0
- package/components/NBadge.js +57 -0
- package/components/NBreadcrub.js +66 -0
- package/components/NButton.js +65 -0
- package/components/NCheckbox.js +42 -0
- package/components/NCheckboxLabel.js +39 -0
- package/components/NCrudModal.js +105 -0
- package/components/NDialog.js +160 -0
- package/components/NDropdown.js +108 -0
- package/components/NDropzone.js +210 -0
- package/components/NForm.js +28 -0
- package/components/NFormModal.js +54 -0
- package/components/NIconButton.js +81 -0
- package/components/NIconCircle.js +66 -0
- package/components/NInput.js +105 -0
- package/components/NInputPhone.d.ts +1 -1
- package/components/NInputPhone.js +46 -0
- package/components/NInputPhone.jsx +2 -1
- package/components/NInputSelect.js +114 -0
- package/components/NInputSuggestion.d.ts +1 -1
- package/components/NInputSuggestion.js +63 -0
- package/components/NLink.js +59 -0
- package/components/NList.js +24 -0
- package/components/NLoadingIndicator.js +53 -0
- package/components/NModal.js +210 -0
- package/components/NPagination.js +108 -0
- package/components/NSearchbar.js +66 -0
- package/components/NSearchbarList.js +36 -0
- package/components/NSelect.js +84 -0
- package/components/NSuggestionList.js +156 -0
- package/components/NTable.js +126 -0
- package/components/NTableAction.js +49 -0
- package/components/NTextArea.d.ts +1 -1
- package/components/NTextArea.js +128 -0
- package/components/NTooltip.js +178 -0
- package/components/NValInput.d.ts +1 -1
- package/components/NValInput.js +104 -0
- package/components/ValidatedForm.js +18 -18
- package/i18n/index.d.ts +24 -1
- package/i18n/index.js +13 -16
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/package.json +11 -4
- package/utils/breakpoints.js +21 -21
- package/utils/component.js +17 -9
- package/utils/deferred.js +12 -12
- package/utils/identifiable.js +27 -29
- package/utils/stringMaxLength.js +8 -13
- package/utils/tailwind.js +1 -1
- package/utils/utils.js +5 -5
- package/utils/vModel.js +82 -73
- package/utils/validation.d.ts +9 -3
- package/utils/validation.js +67 -83
- package/utils/vue.js +7 -5
- package/i18n/de/template.json +0 -10
- package/i18n/de.d.ts +0 -61
- package/i18n/de.js +0 -5
- package/i18n/en/template.json +0 -10
- package/i18n/en.d.ts +0 -61
- package/i18n/en.js +0 -5
package/README.md
CHANGED
|
@@ -2,26 +2,134 @@
|
|
|
2
2
|
|
|
3
3
|
Vue Collection is a collection of styled and fully functional Vue components which can easily be integrated into our projects.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Demo Page 🎆
|
|
6
6
|
|
|
7
|
-
You can take a look at all components on [
|
|
7
|
+
You can take a look at all components on [GitHub Pages](https://naptics.github.io/vue-collection/).
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Project Setup 🚧
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
This section shows how to create a new Vue project with the recommended tech-stack to be ready to install Vue Collection afterwards.
|
|
12
|
+
|
|
13
|
+
1. Create a new vue-project with `npm init vue@latest`. Add at least typescript, jsx, eslint and prettier.
|
|
12
14
|
2. Remove boilerplate code.
|
|
13
15
|
3. Follow the instructions to [install tailwind](https://tailwindcss.com/docs/installation/using-postcss).
|
|
14
16
|
- `npm install -D tailwindcss postcss autoprefixer`
|
|
15
17
|
- `npx tailwindcss init`
|
|
16
18
|
- ... follow the further instructions
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
4. Add tailwind forms with `npm install -D @tailwindcss/forms`.
|
|
20
|
+
5. Add other dependencies with `npm install @heroicons/vue vue-i18n`
|
|
21
|
+
6. Copy files from `.vscode` to your project. Remove `.vscode/settings.json` file from `.gitignore`. Copy `.prettierrc` to your project.
|
|
22
|
+
7. Make sure typescript config is correct. Double check with this repo.
|
|
23
|
+
|
|
24
|
+
## Installation Guide 🔨
|
|
25
|
+
|
|
26
|
+
These are the steps to add Vue Collection to an existing project. You may have to go through the steps of `Project Setup` and check if you have the neccesary (peer-)dependencies installed.
|
|
27
|
+
|
|
28
|
+
1. Go to [npmjs.com](https://npmjs.com), sign in with naptics and create a new read-only classic access token.
|
|
29
|
+
2. Save your access token under `~/.npmrc` with the following content, replacing `YOUR_TOKEN` with the access token.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
//registry.npmjs.org/:_authToken=YOUR_TOKEN
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. Install Vue Collection with `npm i @naptics/vue-collection`.
|
|
36
|
+
4. Add tailwind config -> See below
|
|
37
|
+
5. Register i18n provider -> See below
|
|
38
|
+
|
|
39
|
+
## Create new components
|
|
40
|
+
|
|
41
|
+
After you have installed Vue Collection, you can start building components using the `createComponent` and the `createView` funcitions, which are exported by Vue Collection. They enforce you to only use the neccesary API provided by Vue and create components in a uniform way.
|
|
42
|
+
|
|
43
|
+
## Tailwind Config
|
|
44
|
+
|
|
45
|
+
With this tailwind config file, Vue Collection works as expected. Feel free to change the `default`, `primary` and `secondary` colors and add whatever is needed in your project.
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
// tailwind.config.js
|
|
49
|
+
|
|
50
|
+
/* eslint-disable no-undef */
|
|
51
|
+
const colors = require('tailwindcss/colors')
|
|
52
|
+
|
|
53
|
+
const unresolvedConfig = require('tailwindcss/defaultConfig')
|
|
54
|
+
const resolveConfig = require('tailwindcss/resolveConfig')
|
|
55
|
+
const config = resolveConfig(unresolvedConfig)
|
|
56
|
+
|
|
57
|
+
const allShades = '50|100|200|300|400|500|600|700|800|900'
|
|
58
|
+
const usedColors = 'default|primary|secondary|green|red|yellow|blue'
|
|
59
|
+
const smallSizes = '1|2|3|4|5|6|7|8|9|10|11|12|14|16|18|20'
|
|
60
|
+
|
|
61
|
+
/** @type {import('tailwindcss').Config} */
|
|
62
|
+
module.exports = {
|
|
63
|
+
content: ['./src/**/*.{tsx,ts}', './node_modules/@naptics/vue-collection/**/*.{jsx,js}'],
|
|
64
|
+
safelist: [
|
|
65
|
+
{
|
|
66
|
+
pattern: new RegExp(`^(bg|text)-(${usedColors})-(${allShades})$`),
|
|
67
|
+
variants: ['hover'],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
pattern: new RegExp(`^ring-(${usedColors})-(${allShades})$`),
|
|
71
|
+
variants: ['focus-visible'],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
pattern: new RegExp(`^(w|h)-(${smallSizes})$`),
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
theme: {
|
|
78
|
+
extend: {
|
|
79
|
+
colors: {
|
|
80
|
+
default: colors.slate,
|
|
81
|
+
primary: colors.violet,
|
|
82
|
+
secondary: colors.fuchsia,
|
|
83
|
+
},
|
|
84
|
+
minHeight: config.theme.spacing,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
plugins: [require('@tailwindcss/forms')],
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Register i18n Provider
|
|
92
|
+
|
|
93
|
+
These are two sample files, how the i18n provider can be registered by using `vue-i18n`. The translation files of Vue Collection have to be added to the i18n provider in order for the Vue Collection components to work properly.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// src/i18n/index.ts
|
|
97
|
+
|
|
98
|
+
import en from './en'
|
|
99
|
+
import de from './de'
|
|
100
|
+
import { createI18n } from 'vue-i18n'
|
|
101
|
+
import { registerTranslationProvider } from '@naptics/vue-collection/i18n'
|
|
102
|
+
|
|
103
|
+
const i18n = createI18n({
|
|
104
|
+
legacy: false,
|
|
105
|
+
locale: 'de',
|
|
106
|
+
messages: {
|
|
107
|
+
en,
|
|
108
|
+
de,
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
registerTranslationProvider({
|
|
113
|
+
trsl(key, params) {
|
|
114
|
+
return i18n.global.t(key, params == null ? {} : params)
|
|
115
|
+
},
|
|
116
|
+
trslc(key, count, params) {
|
|
117
|
+
const newCount = count ?? 0
|
|
118
|
+
const newParams = { n: newCount, ...params }
|
|
119
|
+
return i18n.global.t(key, newParams, { plural: newCount })
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
// src/i18n/de.ts
|
|
126
|
+
|
|
127
|
+
import vueCollection from '@naptics/vue-collection/i18n/de/vue-collection.json'
|
|
128
|
+
|
|
129
|
+
const de = {
|
|
130
|
+
['vue-collection']: vueCollection,
|
|
131
|
+
// other translation files
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export default de
|
|
135
|
+
```
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createVNode as _createVNode } from "vue";
|
|
2
|
+
import { createComponent, createProps } from '../utils/component';
|
|
3
|
+
import { CheckCircleIcon, ExclamationCircleIcon, InformationCircleIcon, XMarkIcon } from '@heroicons/vue/24/solid';
|
|
4
|
+
import { computed } from 'vue';
|
|
5
|
+
import NIconButton from './NIconButton';
|
|
6
|
+
import NLoadingIndicator from './NLoadingIndicator';
|
|
7
|
+
export const nAlertProps = createProps({
|
|
8
|
+
/**
|
|
9
|
+
* The variant of the alert. This defines its color and icon.
|
|
10
|
+
*/
|
|
11
|
+
variant: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: 'success'
|
|
14
|
+
},
|
|
15
|
+
/**
|
|
16
|
+
* The text of the alert.
|
|
17
|
+
*/
|
|
18
|
+
text: String,
|
|
19
|
+
/**
|
|
20
|
+
* If set to `true` the X-button of the alert is hidden.
|
|
21
|
+
*/
|
|
22
|
+
hideX: Boolean,
|
|
23
|
+
/**
|
|
24
|
+
* This is called, when the X-button is clicked.
|
|
25
|
+
*/
|
|
26
|
+
onDismiss: Function
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* The `NAlert` is a fully styled alert with multiple variants.
|
|
30
|
+
* It can be used as a normal blocking element or as part of an alert queue.
|
|
31
|
+
*/
|
|
32
|
+
export default createComponent('NAlert', nAlertProps, props => {
|
|
33
|
+
const variant = computed(() => VARIANTS[props.variant]);
|
|
34
|
+
return () => _createVNode("div", {
|
|
35
|
+
"class": `rounded-md p-3 shadow-lg bg-${variant.value.color}-50`
|
|
36
|
+
}, [_createVNode("div", {
|
|
37
|
+
"class": "flex items-center"
|
|
38
|
+
}, [_createVNode("div", {
|
|
39
|
+
"class": "flex flex-shrink-0 items-center"
|
|
40
|
+
}, [variant.value.icon()]), _createVNode("div", {
|
|
41
|
+
"class": "ml-3 flex-grow"
|
|
42
|
+
}, [_createVNode("p", {
|
|
43
|
+
"class": `text-sm font-medium text-${variant.value.color}-900`
|
|
44
|
+
}, [props.text])]), !props.hideX && _createVNode("div", {
|
|
45
|
+
"class": "flex items-center flex-shrink-0 ml-3"
|
|
46
|
+
}, [_createVNode(NIconButton, {
|
|
47
|
+
"color": variant.value.color,
|
|
48
|
+
"size": 5,
|
|
49
|
+
"icon": XMarkIcon,
|
|
50
|
+
"onClick": props.onDismiss
|
|
51
|
+
}, null)])])]);
|
|
52
|
+
});
|
|
53
|
+
const icon = (icon, color) => () => _createVNode(icon, {
|
|
54
|
+
"class": `h-5 w-5 text-${color}-500`
|
|
55
|
+
}, null);
|
|
56
|
+
const VARIANTS = {
|
|
57
|
+
success: {
|
|
58
|
+
icon: icon(CheckCircleIcon, 'green'),
|
|
59
|
+
color: 'green'
|
|
60
|
+
},
|
|
61
|
+
info: {
|
|
62
|
+
icon: icon(InformationCircleIcon, 'blue'),
|
|
63
|
+
color: 'blue'
|
|
64
|
+
},
|
|
65
|
+
warning: {
|
|
66
|
+
icon: icon(ExclamationCircleIcon, 'yellow'),
|
|
67
|
+
color: 'yellow'
|
|
68
|
+
},
|
|
69
|
+
error: {
|
|
70
|
+
icon: icon(ExclamationCircleIcon, 'red'),
|
|
71
|
+
color: 'red'
|
|
72
|
+
},
|
|
73
|
+
loading: {
|
|
74
|
+
icon: () => _createVNode(NLoadingIndicator, {
|
|
75
|
+
"color": "blue",
|
|
76
|
+
"size": 7,
|
|
77
|
+
"shade": 500
|
|
78
|
+
}, null),
|
|
79
|
+
color: 'blue'
|
|
80
|
+
}
|
|
81
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createVNode as _createVNode } from "vue";
|
|
2
|
+
import { createComponent, createProps } from '../utils/component';
|
|
3
|
+
import NTooltip, { mapTooltipProps, nToolTipPropsForImplementor } from './NTooltip';
|
|
4
|
+
export const nBadgeProps = createProps({
|
|
5
|
+
/**
|
|
6
|
+
* The text of the badge. Can alternatively be passed in the default slot.
|
|
7
|
+
*/
|
|
8
|
+
text: String,
|
|
9
|
+
/**
|
|
10
|
+
* The text size, a standard tailwind text-size class.
|
|
11
|
+
*/
|
|
12
|
+
textSize: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: 'text-sm'
|
|
15
|
+
},
|
|
16
|
+
/**
|
|
17
|
+
* The color of the badge.
|
|
18
|
+
*/
|
|
19
|
+
color: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: 'primary'
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* The background shade of the badge.
|
|
25
|
+
*/
|
|
26
|
+
shade: {
|
|
27
|
+
type: Number,
|
|
28
|
+
default: 200
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* The text shade of the badge.
|
|
32
|
+
*/
|
|
33
|
+
textShade: {
|
|
34
|
+
type: Number,
|
|
35
|
+
default: 900
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* If set to `true` the badges text is all-caps. Default is `true`.
|
|
39
|
+
*/
|
|
40
|
+
allCaps: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: true
|
|
43
|
+
},
|
|
44
|
+
...nToolTipPropsForImplementor
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* The `NBadge` is a styled element to wrap a text.
|
|
48
|
+
*/
|
|
49
|
+
export default createComponent('NBadge', nBadgeProps, (props, {
|
|
50
|
+
slots
|
|
51
|
+
}) => {
|
|
52
|
+
return () => _createVNode(NTooltip, mapTooltipProps(props), {
|
|
53
|
+
default: () => [_createVNode("div", {
|
|
54
|
+
"class": ['px-2 py-1 rounded-md font-semibold shadow', `${props.textSize} bg-${props.color}-${props.shade} text-${props.color}-${props.textShade}`, props.allCaps ? 'uppercase' : '']
|
|
55
|
+
}, [slots.default?.() || props.text])]
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createVNode as _createVNode, Fragment as _Fragment } from "vue";
|
|
2
|
+
import { createComponent, createProps } from '../utils/component';
|
|
3
|
+
import { ChevronRightIcon } from '@heroicons/vue/24/solid';
|
|
4
|
+
import NLink from './NLink';
|
|
5
|
+
export const nBreadcrumbProps = createProps({
|
|
6
|
+
/**
|
|
7
|
+
* The items of the breadcrumb.
|
|
8
|
+
*/
|
|
9
|
+
items: {
|
|
10
|
+
type: Array,
|
|
11
|
+
default: () => []
|
|
12
|
+
},
|
|
13
|
+
/**
|
|
14
|
+
* The color of the breadcrumbs text and icons.
|
|
15
|
+
*/
|
|
16
|
+
color: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: 'primary'
|
|
19
|
+
},
|
|
20
|
+
/**
|
|
21
|
+
* The text-size of the breadcrumb labels.
|
|
22
|
+
*/
|
|
23
|
+
textSize: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: 'text-base'
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* The icon which is used as a seperator between two breadcrumb items.
|
|
29
|
+
*/
|
|
30
|
+
icon: {
|
|
31
|
+
type: Function,
|
|
32
|
+
default: ChevronRightIcon
|
|
33
|
+
},
|
|
34
|
+
/**
|
|
35
|
+
* The size of the icon in tailwind units.
|
|
36
|
+
*/
|
|
37
|
+
iconSize: {
|
|
38
|
+
type: Number,
|
|
39
|
+
default: 5
|
|
40
|
+
},
|
|
41
|
+
/**
|
|
42
|
+
* A slot the replace the breadcrumb labels.
|
|
43
|
+
*/
|
|
44
|
+
item: Function,
|
|
45
|
+
/**
|
|
46
|
+
* A slot to replace the separators between the breadcrumb labels.
|
|
47
|
+
* The passsed item is the item before the seperator.
|
|
48
|
+
*/
|
|
49
|
+
seperator: Function
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* The `NBreadcrumb` is a styled breadcrumb which can be used as a navigation in hierarchical views.
|
|
53
|
+
*/
|
|
54
|
+
export default createComponent('NBreadcrumb', nBreadcrumbProps, props => {
|
|
55
|
+
return () => _createVNode("div", {
|
|
56
|
+
"class": "flex flex-wrap items-center"
|
|
57
|
+
}, [props.items.map((item, index) => _createVNode(_Fragment, null, [props.item?.(item, index) || _createVNode(NLink, {
|
|
58
|
+
"textSize": props.textSize,
|
|
59
|
+
"route": item.route,
|
|
60
|
+
"color": props.color
|
|
61
|
+
}, {
|
|
62
|
+
default: () => [item.label]
|
|
63
|
+
}), index < props.items.length - 1 && (props.seperator?.(item, index) || _createVNode(props.icon, {
|
|
64
|
+
"class": `mx-2 w-${props.iconSize} h-${props.iconSize} text-${props.color}-500`
|
|
65
|
+
}, null))]))]);
|
|
66
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createVNode as _createVNode } from "vue";
|
|
2
|
+
import { createComponent, createProps } from '../utils/component';
|
|
3
|
+
import { computed } from 'vue';
|
|
4
|
+
import NLoadingIndicator from './NLoadingIndicator';
|
|
5
|
+
import NTooltip, { mapTooltipProps, nToolTipPropsForImplementor } from './NTooltip';
|
|
6
|
+
export const nButtonProps = createProps({
|
|
7
|
+
/**
|
|
8
|
+
* The color of the button.
|
|
9
|
+
*/
|
|
10
|
+
color: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: 'primary'
|
|
13
|
+
},
|
|
14
|
+
/**
|
|
15
|
+
* The html attribute, which indicates the type of the button.
|
|
16
|
+
*/
|
|
17
|
+
type: {
|
|
18
|
+
type: String,
|
|
19
|
+
default: 'button'
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* If set to `true` the button is disabled and no interaction is possible.
|
|
23
|
+
*/
|
|
24
|
+
disabled: Boolean,
|
|
25
|
+
/**
|
|
26
|
+
* If set to `true` the button will show a loading animation.
|
|
27
|
+
* Setting `loading` to `true` will also disable the button.
|
|
28
|
+
*/
|
|
29
|
+
loading: Boolean,
|
|
30
|
+
/**
|
|
31
|
+
* If set to `true` the button will appear smaller.
|
|
32
|
+
*/
|
|
33
|
+
small: Boolean,
|
|
34
|
+
/**
|
|
35
|
+
* This is called, when the button is clicked.
|
|
36
|
+
*/
|
|
37
|
+
onClick: Function,
|
|
38
|
+
...nToolTipPropsForImplementor
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* The `NButton` is a styled button.
|
|
42
|
+
*/
|
|
43
|
+
export default createComponent('NButton', nButtonProps, (props, {
|
|
44
|
+
slots
|
|
45
|
+
}) => {
|
|
46
|
+
const isDisabled = computed(() => props.loading || props.disabled);
|
|
47
|
+
return () => _createVNode(NTooltip, mapTooltipProps(props), {
|
|
48
|
+
default: () => [_createVNode("button", {
|
|
49
|
+
"disabled": isDisabled.value,
|
|
50
|
+
"type": props.type,
|
|
51
|
+
"class": [`block w-full font-medium rounded-md focus:outline-none focus-visible:ring-2 shadow text-${props.color}-900 relative`, isDisabled.value ? `bg-${props.color}-100 text-opacity-20 cursor-default` : `bg-${props.color}-200 hover:bg-${props.color}-300 focus-visible:ring-${props.color}-500`, props.small ? 'py-1 px-2 text-xs' : 'py-2 px-4 text-sm'],
|
|
52
|
+
"onClick": props.onClick
|
|
53
|
+
}, [_createVNode("span", {
|
|
54
|
+
"class": {
|
|
55
|
+
'opacity-10': props.loading
|
|
56
|
+
}
|
|
57
|
+
}, [slots.default?.()]), props.loading && _createVNode("div", {
|
|
58
|
+
"class": "absolute inset-0 flex items-center justify-center opacity-50"
|
|
59
|
+
}, [_createVNode(NLoadingIndicator, {
|
|
60
|
+
"color": props.color,
|
|
61
|
+
"size": props.small ? 4 : 6,
|
|
62
|
+
"shade": 600
|
|
63
|
+
}, null)])])]
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createVNode as _createVNode } from "vue";
|
|
2
|
+
import { createComponent, createProps } from '../utils/component';
|
|
3
|
+
import { vModelProps } from '../utils/vModel';
|
|
4
|
+
import { nextTick, ref } from 'vue';
|
|
5
|
+
export const nCheckboxProps = createProps({
|
|
6
|
+
...vModelProps(Boolean),
|
|
7
|
+
/**
|
|
8
|
+
* The color of the checkbox.
|
|
9
|
+
*/
|
|
10
|
+
color: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: 'primary'
|
|
13
|
+
},
|
|
14
|
+
/**
|
|
15
|
+
* If set to `true` the checkbox is disabled and no interaction is possible.
|
|
16
|
+
*/
|
|
17
|
+
disabled: Boolean
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* The `NCheckbox` is a styled checkbox.
|
|
21
|
+
*/
|
|
22
|
+
export default createComponent('NCheckbox', nCheckboxProps, props => {
|
|
23
|
+
const toggle = () => {
|
|
24
|
+
props.onUpdateValue?.(!props.value);
|
|
25
|
+
forceUpdate();
|
|
26
|
+
};
|
|
27
|
+
const checkBoxRef = ref();
|
|
28
|
+
const updateKey = ref(0);
|
|
29
|
+
const forceUpdate = () => {
|
|
30
|
+
updateKey.value += 1;
|
|
31
|
+
nextTick(() => checkBoxRef.value?.focus());
|
|
32
|
+
};
|
|
33
|
+
return () => _createVNode("input", {
|
|
34
|
+
"type": "checkbox",
|
|
35
|
+
"ref": checkBoxRef,
|
|
36
|
+
"checked": props.value,
|
|
37
|
+
"disabled": props.disabled,
|
|
38
|
+
"onClick": toggle,
|
|
39
|
+
"key": updateKey.value,
|
|
40
|
+
"class": [`h-5 w-5 border-default-300 rounded focus:outline-none focus:ring-0 focus-visible:ring-2 focus-visible:ring-${props.color}-500`, props.disabled ? `cursor-default bg-default-100 text-${props.color}-200` : `cursor-pointer text-${props.color}-400`]
|
|
41
|
+
}, null);
|
|
42
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createVNode as _createVNode } from "vue";
|
|
2
|
+
import { createComponent, createProps } from '../utils/component';
|
|
3
|
+
import NCheckbox, { nCheckboxProps } from './NCheckbox';
|
|
4
|
+
export const nCheckboxLabelProps = createProps({
|
|
5
|
+
...nCheckboxProps,
|
|
6
|
+
/**
|
|
7
|
+
* The title of the checkbox.
|
|
8
|
+
*/
|
|
9
|
+
title: String,
|
|
10
|
+
/**
|
|
11
|
+
* The description of the checkbox.
|
|
12
|
+
*/
|
|
13
|
+
description: String,
|
|
14
|
+
/**
|
|
15
|
+
* If set to `true`, a smaller margin is applied between the label and the checkbox.
|
|
16
|
+
*/
|
|
17
|
+
compact: Boolean
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* The `NCheckboxLabel` is a checkbox with a title and a description.
|
|
21
|
+
*/
|
|
22
|
+
export default createComponent('NCheckboxLabel', nCheckboxLabelProps, props => {
|
|
23
|
+
const toggleValue = () => {
|
|
24
|
+
if (!props.disabled) props.onUpdateValue?.(!props.value);
|
|
25
|
+
};
|
|
26
|
+
return () => _createVNode("div", {
|
|
27
|
+
"class": "flex items-center"
|
|
28
|
+
}, [_createVNode(NCheckbox, props, null), _createVNode("div", {
|
|
29
|
+
"class": `${props.compact ? 'ml-2' : 'ml-3'} text-sm`
|
|
30
|
+
}, [_createVNode("label", {
|
|
31
|
+
"onClick": toggleValue,
|
|
32
|
+
"class": ['font-medium select-none', props.disabled ? 'text-default-300' : 'text-default-700 cursor-pointer']
|
|
33
|
+
}, [props.title]), _createVNode("p", {
|
|
34
|
+
"class": props.disabled ? 'text-default-300' : 'text-default-500'
|
|
35
|
+
}, [_createVNode("span", {
|
|
36
|
+
"onClick": toggleValue,
|
|
37
|
+
"class": ['select-none', props.disabled ? '' : 'cursor-pointer']
|
|
38
|
+
}, [props.description])])])]);
|
|
39
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { mergeProps as _mergeProps, createVNode as _createVNode } from "vue";
|
|
2
|
+
import { trsl } from '../i18n';
|
|
3
|
+
import { createComponent, createProps } from '../utils/component';
|
|
4
|
+
import { ref } from 'vue';
|
|
5
|
+
import NButton from './NButton';
|
|
6
|
+
import NDialog from './NDialog';
|
|
7
|
+
import NFormModal, { nFormModalProps } from './NFormModal';
|
|
8
|
+
export const nCrudModalProps = createProps({
|
|
9
|
+
...nFormModalProps,
|
|
10
|
+
/**
|
|
11
|
+
* The text of the remove-button.
|
|
12
|
+
*/
|
|
13
|
+
removeText: {
|
|
14
|
+
type: String,
|
|
15
|
+
default: trsl('vue-collection.action.remove')
|
|
16
|
+
},
|
|
17
|
+
/**
|
|
18
|
+
* The color of the remove-button.
|
|
19
|
+
*/
|
|
20
|
+
removeColor: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: 'red'
|
|
23
|
+
},
|
|
24
|
+
/**
|
|
25
|
+
* The title of the dialog which appears when clicking on the remove-button.
|
|
26
|
+
*/
|
|
27
|
+
removeDialogTitle: String,
|
|
28
|
+
/**
|
|
29
|
+
* The text of the dialog which appears when clicking on the remove-button.
|
|
30
|
+
*/
|
|
31
|
+
removeDialogText: String,
|
|
32
|
+
/**
|
|
33
|
+
* The variant of the dialog which appears when clicking on the remove-button. Default is `remove`.
|
|
34
|
+
*/
|
|
35
|
+
removeDialogVariant: {
|
|
36
|
+
type: String,
|
|
37
|
+
default: 'remove'
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* The text of the dialog's ok-button. Is already set by the `removeDialogVariant` but can be overridden.
|
|
41
|
+
*/
|
|
42
|
+
removeDialogOkText: String,
|
|
43
|
+
/**
|
|
44
|
+
* If set to `true` the modal will close itself when `onRemove` is called.
|
|
45
|
+
*/
|
|
46
|
+
closeOnRemove: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* This is called, when the remove-button has been clicked and the dialog has been accepted.
|
|
52
|
+
*/
|
|
53
|
+
onRemove: Function
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* The `NCrudModal` is a {@link NFormModal} which has some convenience features for a CRUD-scenario.
|
|
57
|
+
* It has an integrated remove-button with a user-dialog to remove the editing element.
|
|
58
|
+
* When the dialog is accepted `onRemove` is called.
|
|
59
|
+
*/
|
|
60
|
+
export default createComponent('NCrudModal', nCrudModalProps, (props, {
|
|
61
|
+
slots
|
|
62
|
+
}) => {
|
|
63
|
+
const removeDialog = ref();
|
|
64
|
+
const remove = () => {
|
|
65
|
+
removeDialog.value?.show().then(result => {
|
|
66
|
+
if (result) {
|
|
67
|
+
props.onRemove?.();
|
|
68
|
+
if (props.closeOnRemove) props.onUpdateValue?.(false);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
return () => _createVNode(NFormModal, _mergeProps(props, {
|
|
73
|
+
"footer": props.footer || (({
|
|
74
|
+
ok,
|
|
75
|
+
cancel
|
|
76
|
+
}) => _createVNode("div", {
|
|
77
|
+
"class": "flex justify-between"
|
|
78
|
+
}, [_createVNode("div", null, [_createVNode(NButton, {
|
|
79
|
+
"color": props.removeColor,
|
|
80
|
+
"onClick": remove
|
|
81
|
+
}, {
|
|
82
|
+
default: () => [props.removeText]
|
|
83
|
+
})]), _createVNode("div", null, [_createVNode(NButton, {
|
|
84
|
+
"color": props.cancelColor,
|
|
85
|
+
"onClick": cancel
|
|
86
|
+
}, {
|
|
87
|
+
default: () => [props.cancelText]
|
|
88
|
+
}), _createVNode(NButton, {
|
|
89
|
+
"color": props.okColor,
|
|
90
|
+
"onClick": ok,
|
|
91
|
+
"class": "ml-2",
|
|
92
|
+
"disabled": props.okDisabled
|
|
93
|
+
}, {
|
|
94
|
+
default: () => [props.okText]
|
|
95
|
+
})])]))
|
|
96
|
+
}), {
|
|
97
|
+
default: () => [slots.default?.(), _createVNode(NDialog, {
|
|
98
|
+
"ref": removeDialog,
|
|
99
|
+
"variant": props.removeDialogVariant,
|
|
100
|
+
"title": props.removeDialogTitle,
|
|
101
|
+
"text": props.removeDialogText,
|
|
102
|
+
"okText": props.removeDialogOkText
|
|
103
|
+
}, null)]
|
|
104
|
+
});
|
|
105
|
+
});
|