sprintify-ui 0.0.93 → 0.0.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sprintify-ui.es.js +15388 -6135
- package/dist/style.css +1 -1
- package/dist/types/src/components/BaseActionItem.vue.d.ts +25 -102
- package/dist/types/src/components/BaseApp.vue.d.ts +8 -47
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +90 -326
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +85 -290
- package/dist/types/src/components/BaseBadge.vue.d.ts +27 -110
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +89 -294
- package/dist/types/src/components/BaseButtonGroup.vue.d.ts +71 -254
- package/dist/types/src/components/BaseCard.vue.d.ts +15 -68
- package/dist/types/src/components/BaseClipboard.vue.d.ts +15 -68
- package/dist/types/src/components/BaseColor.vue.d.ts +79 -0
- package/dist/types/src/components/BaseDataIterator.vue.d.ts +82 -258
- package/dist/types/src/components/BaseDataTable.vue.d.ts +158 -509
- package/dist/types/src/components/BaseDescriptionList.vue.d.ts +8 -47
- package/dist/types/src/components/BaseDescriptionListItem.vue.d.ts +9 -48
- package/dist/types/src/components/BaseDialog.vue.d.ts +31 -131
- package/dist/types/src/components/BaseDropdown.vue.d.ts +28 -110
- package/dist/types/src/components/BaseField.vue.d.ts +31 -124
- package/dist/types/src/components/BaseFileUploader.vue.d.ts +54 -192
- package/dist/types/src/components/BaseForm.vue.d.ts +62 -226
- package/dist/types/src/components/BaseHasMany.vue.d.ts +66 -219
- package/dist/types/src/components/BaseInput.vue.d.ts +9 -0
- package/dist/types/src/components/BaseInputError.vue.d.ts +8 -47
- package/dist/types/src/components/BaseLayoutSidebar.vue.d.ts +25 -98
- package/dist/types/src/components/BaseLayoutSidebarConfigurable.vue.d.ts +39 -155
- package/dist/types/src/components/BaseLayoutStacked.vue.d.ts +17 -70
- package/dist/types/src/components/BaseLayoutStackedConfigurable.vue.d.ts +39 -155
- package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +63 -234
- package/dist/types/src/components/BaseMenu.vue.d.ts +32 -105
- package/dist/types/src/components/BaseModalCenter.vue.d.ts +42 -132
- package/dist/types/src/components/BaseModalSide.vue.d.ts +29 -118
- package/dist/types/src/components/BaseNavbar.vue.d.ts +24 -87
- package/dist/types/src/components/BaseRadioGroup.vue.d.ts +53 -194
- package/dist/types/src/components/BaseReadMore.vue.d.ts +15 -68
- package/dist/types/src/components/BaseRichText.vue.d.ts +92 -0
- package/dist/types/src/components/BaseSelect.vue.d.ts +35 -144
- package/dist/types/src/components/BaseSideNavigation.vue.d.ts +8 -47
- package/dist/types/src/components/BaseSideNavigationItem.vue.d.ts +23 -94
- package/dist/types/src/components/BaseSkeleton.vue.d.ts +19 -82
- package/dist/types/src/components/BaseSwitch.vue.d.ts +35 -144
- package/dist/types/src/components/BaseSystemAlert.vue.d.ts +27 -116
- package/dist/types/src/components/BaseTabItem.vue.d.ts +23 -94
- package/dist/types/src/components/BaseTable.vue.d.ts +101 -361
- package/dist/types/src/components/BaseTableColumn.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTabs.vue.d.ts +8 -47
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +66 -236
- package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +62 -212
- package/dist/types/src/components/index.d.ts +3 -1
- package/package.json +5 -1
- package/src/components/BaseButtonGroup.vue +2 -2
- package/src/components/BaseColor.stories.js +52 -0
- package/src/components/BaseColor.vue +98 -0
- package/src/components/BaseForm.vue +3 -3
- package/src/components/BaseInput.stories.js +52 -0
- package/src/components/BaseInput.vue +38 -1
- package/src/components/BaseModalCenter.stories.js +5 -0
- package/src/components/BaseModalCenter.vue +13 -5
- package/src/components/BaseRichText.stories.js +102 -0
- package/src/components/BaseRichText.vue +121 -0
- package/src/components/BaseTextarea.vue +1 -1
- package/src/components/index.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprintify-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.94",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "rimraf dist && vue-tsc && vite build",
|
|
6
6
|
"build-fast": "rimraf dist && vite build",
|
|
@@ -16,11 +16,13 @@
|
|
|
16
16
|
"@tailwindcss/forms": "^0.5.3",
|
|
17
17
|
"@tailwindcss/line-clamp": "^0.4.2",
|
|
18
18
|
"@tailwindcss/typography": "^0.5.8",
|
|
19
|
+
"@vueup/vue-quill": "^1.0.0",
|
|
19
20
|
"@vueuse/core": "^9.0.0",
|
|
20
21
|
"axios": "^0.26.1",
|
|
21
22
|
"humanize-duration": "^3.0.0",
|
|
22
23
|
"lodash": "^4.17.21",
|
|
23
24
|
"luxon": "^3.0.0",
|
|
25
|
+
"maska": "^2.1.1",
|
|
24
26
|
"microtip": "^0.2.2",
|
|
25
27
|
"object-to-formdata": "^4.4.2",
|
|
26
28
|
"pikaday": "^1.8.2",
|
|
@@ -58,6 +60,7 @@
|
|
|
58
60
|
"@typescript-eslint/parser": "^5.42.1",
|
|
59
61
|
"@vitejs/plugin-vue": "^3.2.0",
|
|
60
62
|
"@vue/eslint-config-typescript": "^11.0.2",
|
|
63
|
+
"@vueup/vue-quill": "^1.0.0",
|
|
61
64
|
"@vueuse/core": "^9.5.0",
|
|
62
65
|
"autoprefixer": "^10.4.13",
|
|
63
66
|
"axios": "^0.26.1",
|
|
@@ -71,6 +74,7 @@
|
|
|
71
74
|
"humanize-duration": "^3.27.3",
|
|
72
75
|
"lodash": "^4.17.21",
|
|
73
76
|
"luxon": "^3.1.0",
|
|
77
|
+
"maska": "^2.1.1",
|
|
74
78
|
"microtip": "^0.2.2",
|
|
75
79
|
"object-hash": "^3.0.0",
|
|
76
80
|
"object-to-formdata": "^4.4.2",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
>
|
|
17
17
|
<slot
|
|
18
18
|
name="option"
|
|
19
|
-
:selected="isSelected(option)"
|
|
19
|
+
:selected="computed(() => isSelected(option))"
|
|
20
20
|
:option="option"
|
|
21
21
|
:disabled="disabled"
|
|
22
22
|
>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
|
|
30
30
|
<script lang="ts" setup>
|
|
31
|
-
import { PropType } from 'vue';
|
|
31
|
+
import { PropType, computed } from 'vue';
|
|
32
32
|
import { NormalizedOption, Option } from '@/types';
|
|
33
33
|
import { cloneDeep, isArray } from 'lodash';
|
|
34
34
|
import { useHasOptions } from '@/composables/hasOptions';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createFieldStory, colors } from '../../.storybook/utils';
|
|
2
|
+
import BaseColor from './BaseColor.vue';
|
|
3
|
+
import ShowValue from '../../.storybook/components/ShowValue.vue';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Form/BaseColor',
|
|
7
|
+
component: BaseColor,
|
|
8
|
+
argTypes: {},
|
|
9
|
+
args: {
|
|
10
|
+
labelKey: 'label',
|
|
11
|
+
valueKey: 'value',
|
|
12
|
+
colors: colors,
|
|
13
|
+
},
|
|
14
|
+
decorators: [() => ({ template: '<div class="mb-36"><story/></div>' })],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const Template = (args) => ({
|
|
18
|
+
components: { BaseColor, ShowValue },
|
|
19
|
+
setup() {
|
|
20
|
+
const value = ref(null);
|
|
21
|
+
return { args, value };
|
|
22
|
+
},
|
|
23
|
+
template: `
|
|
24
|
+
<BaseColor v-model="value" v-bind="args"></BaseColor>
|
|
25
|
+
<ShowValue :value="value"></ShowValue>
|
|
26
|
+
`,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const Single = Template.bind({});
|
|
30
|
+
Single.args = {};
|
|
31
|
+
|
|
32
|
+
export const SingleRequired = Template.bind({});
|
|
33
|
+
SingleRequired.args = {
|
|
34
|
+
required: true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const Multiple = Template.bind({});
|
|
38
|
+
Multiple.args = {
|
|
39
|
+
multiple: true,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Disabled = Template.bind({});
|
|
43
|
+
Disabled.args = {
|
|
44
|
+
disabled: true,
|
|
45
|
+
modelValue: { label: '#16a34a', value: '#16a34a' },
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const Field = createFieldStory({
|
|
49
|
+
component: BaseColor,
|
|
50
|
+
componentName: 'BaseColor',
|
|
51
|
+
label: 'Choose your favorite color',
|
|
52
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<BaseButtonGroup
|
|
4
|
+
:model-value="modelValue"
|
|
5
|
+
:disabled="disabled"
|
|
6
|
+
:value-key="valueKey"
|
|
7
|
+
:label-key="labelKey"
|
|
8
|
+
:options="colorOptions"
|
|
9
|
+
:multiple="multiple"
|
|
10
|
+
:button-type="buttonType"
|
|
11
|
+
:button-class="''"
|
|
12
|
+
:button-selected-class="''"
|
|
13
|
+
:button-unselected-class="''"
|
|
14
|
+
@update:model-value="$emit('update:modelValue', $event)"
|
|
15
|
+
>
|
|
16
|
+
<template #option="option">
|
|
17
|
+
<div
|
|
18
|
+
:style="{ background: option.option.value }"
|
|
19
|
+
class="p-3 border-none rounded-md"
|
|
20
|
+
:class="[
|
|
21
|
+
option.selected.value ? 'text-white' : 'text-transparent',
|
|
22
|
+
disabled ? ' cursor-not-allowed opacity-50' : '',
|
|
23
|
+
]"
|
|
24
|
+
>
|
|
25
|
+
<BaseIcon icon="heroicons-solid:check-circle" class="w-5 h-5" />
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
</BaseButtonGroup>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script lang="ts" setup>
|
|
33
|
+
import { PropType } from 'vue';
|
|
34
|
+
import { Option } from '@/types';
|
|
35
|
+
import { BaseButtonGroup } from '.';
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
modelValue: {
|
|
39
|
+
default: undefined,
|
|
40
|
+
type: [Object, Array, null, undefined] as PropType<
|
|
41
|
+
Option[] | Option | null | undefined
|
|
42
|
+
>,
|
|
43
|
+
},
|
|
44
|
+
required: {
|
|
45
|
+
default: false,
|
|
46
|
+
type: Boolean,
|
|
47
|
+
},
|
|
48
|
+
disabled: {
|
|
49
|
+
default: false,
|
|
50
|
+
type: Boolean,
|
|
51
|
+
},
|
|
52
|
+
buttonType: {
|
|
53
|
+
default: 'button',
|
|
54
|
+
type: String as PropType<'button' | 'submit'>,
|
|
55
|
+
},
|
|
56
|
+
colors: {
|
|
57
|
+
type: [Array] as PropType<string[]>,
|
|
58
|
+
default() {
|
|
59
|
+
return [
|
|
60
|
+
'#0f172a',
|
|
61
|
+
'#dc2626',
|
|
62
|
+
'#ea580c',
|
|
63
|
+
'#eab308',
|
|
64
|
+
'#16a34a',
|
|
65
|
+
'#0d9488',
|
|
66
|
+
'#0891b2',
|
|
67
|
+
'#2563eb',
|
|
68
|
+
'#4f46e5',
|
|
69
|
+
'#9333ea',
|
|
70
|
+
'#db2777',
|
|
71
|
+
];
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
labelKey: {
|
|
75
|
+
required: true,
|
|
76
|
+
type: String,
|
|
77
|
+
},
|
|
78
|
+
valueKey: {
|
|
79
|
+
required: true,
|
|
80
|
+
type: String,
|
|
81
|
+
},
|
|
82
|
+
multiple: {
|
|
83
|
+
default: false,
|
|
84
|
+
type: Boolean,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
defineEmits(['update:modelValue']);
|
|
89
|
+
|
|
90
|
+
const colorOptions = computed(() => {
|
|
91
|
+
return props.colors.map((c) => {
|
|
92
|
+
return {
|
|
93
|
+
label: c,
|
|
94
|
+
value: c,
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
</script>
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
>
|
|
18
18
|
<slot v-if="loading" name="loading">
|
|
19
19
|
<div
|
|
20
|
-
class="absolute inset-0 flex
|
|
20
|
+
class="absolute inset-0 flex items-center justify-center w-full h-full"
|
|
21
21
|
>
|
|
22
22
|
<div
|
|
23
|
-
class="absolute inset-0
|
|
23
|
+
class="absolute inset-0 w-full h-full opacity-80"
|
|
24
24
|
:class="loadingMaskClass"
|
|
25
25
|
/>
|
|
26
26
|
<svg
|
|
27
|
-
class="relative
|
|
27
|
+
class="relative w-6 h-6 text-blue-600 animate-spin"
|
|
28
28
|
viewBox="0 0 24 24"
|
|
29
29
|
>
|
|
30
30
|
<path
|
|
@@ -18,6 +18,20 @@ export default {
|
|
|
18
18
|
type: 'text',
|
|
19
19
|
placeholder: 'Enter your name',
|
|
20
20
|
},
|
|
21
|
+
argTypes: {
|
|
22
|
+
mask: {
|
|
23
|
+
control: { type: 'select' },
|
|
24
|
+
options: [
|
|
25
|
+
'phone',
|
|
26
|
+
'date',
|
|
27
|
+
'time',
|
|
28
|
+
'credit-card',
|
|
29
|
+
'zip-code-canada',
|
|
30
|
+
'dynamicMask',
|
|
31
|
+
'customMask',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
21
35
|
};
|
|
22
36
|
|
|
23
37
|
const Template = (args) => ({
|
|
@@ -92,6 +106,44 @@ Error.args = {
|
|
|
92
106
|
iconRight: 'heroicons:currency-dollar',
|
|
93
107
|
};
|
|
94
108
|
|
|
109
|
+
export const PhoneMask = Template.bind({});
|
|
110
|
+
PhoneMask.args = {
|
|
111
|
+
mask: 'phone',
|
|
112
|
+
placeholder: '(250) 555-0199',
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const DateMask = Template.bind({});
|
|
116
|
+
DateMask.args = {
|
|
117
|
+
mask: 'date',
|
|
118
|
+
placeholder: 'yyyy-mm-dd',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const TimeMask = Template.bind({});
|
|
122
|
+
TimeMask.args = {
|
|
123
|
+
mask: 'time',
|
|
124
|
+
placeholder: 'hh:mm:ss',
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const CreditCard = Template.bind({});
|
|
128
|
+
CreditCard.args = {
|
|
129
|
+
mask: 'credit-card', //4555 5666 6666 6634
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const CanadianZipCodeMask = Template.bind({});
|
|
133
|
+
CanadianZipCodeMask.args = {
|
|
134
|
+
mask: 'zip-code-canada', // M5M 4M4
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const DynamicMask = Template.bind({});
|
|
138
|
+
DynamicMask.args = {
|
|
139
|
+
mask: ['###.###.###-##', '##.###.###/####-##'],
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const CustomMask = Template.bind({});
|
|
143
|
+
CustomMask.args = {
|
|
144
|
+
mask: (value) => (value.startsWith('1') ? '#-#' : '##-##'),
|
|
145
|
+
};
|
|
146
|
+
|
|
95
147
|
export const Field = createFieldStory({
|
|
96
148
|
component: BaseInput,
|
|
97
149
|
componentName: 'BaseInput',
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<input
|
|
23
23
|
ref="input"
|
|
24
|
+
v-maska:[maskOptions]
|
|
24
25
|
:value="modelValue"
|
|
25
26
|
:type="type"
|
|
26
27
|
:name="nameInternal"
|
|
@@ -64,10 +65,11 @@
|
|
|
64
65
|
</template>
|
|
65
66
|
|
|
66
67
|
<script lang="ts" setup>
|
|
67
|
-
import { get,
|
|
68
|
+
import { get, isString } from 'lodash';
|
|
68
69
|
import { PropType } from 'vue';
|
|
69
70
|
import { BaseIcon } from '@/index';
|
|
70
71
|
import { useField } from '@/composables/field';
|
|
72
|
+
import { vMaska } from 'maska';
|
|
71
73
|
|
|
72
74
|
const props = defineProps({
|
|
73
75
|
modelValue: {
|
|
@@ -137,6 +139,41 @@ const props = defineProps({
|
|
|
137
139
|
default: undefined,
|
|
138
140
|
type: Number,
|
|
139
141
|
},
|
|
142
|
+
mask: {
|
|
143
|
+
type: [String, Array, Function],
|
|
144
|
+
default() {
|
|
145
|
+
return null;
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const maskOptions = computed(() => {
|
|
151
|
+
if (props.mask) {
|
|
152
|
+
return {
|
|
153
|
+
mask: maskInternal.value,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const maskInternal = computed(() => {
|
|
160
|
+
if (props.mask === 'phone') {
|
|
161
|
+
return '(###) ###-####';
|
|
162
|
+
}
|
|
163
|
+
if (props.mask === 'date') {
|
|
164
|
+
return '####-##-##';
|
|
165
|
+
}
|
|
166
|
+
if (props.mask === 'time') {
|
|
167
|
+
return '##:##:##';
|
|
168
|
+
}
|
|
169
|
+
if (props.mask === 'credit-card') {
|
|
170
|
+
return '#### #### #### ####';
|
|
171
|
+
}
|
|
172
|
+
if (props.mask === 'zip-code-canada') {
|
|
173
|
+
return '@#@ #@#';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return props.mask;
|
|
140
177
|
});
|
|
141
178
|
|
|
142
179
|
const emit = defineEmits(['update:modelValue', 'focus', 'blur']);
|
|
@@ -52,6 +52,11 @@ VerticalAlignTop.args = {
|
|
|
52
52
|
verticalAlign: 'top',
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
export const NoCloseButton = Template.bind({});
|
|
56
|
+
NoCloseButton.args = {
|
|
57
|
+
showCloseButton: false,
|
|
58
|
+
};
|
|
59
|
+
|
|
55
60
|
export const CustomBackdropClass = Template.bind({});
|
|
56
61
|
CustomBackdropClass.args = {
|
|
57
62
|
backdropClass: 'bg-red-500 bg-opacity-70',
|
|
@@ -12,11 +12,14 @@
|
|
|
12
12
|
scroll-lock-target
|
|
13
13
|
>
|
|
14
14
|
<div
|
|
15
|
-
class="flex min-h-full w-full items-end justify-center overflow-hidden
|
|
16
|
-
:class="
|
|
17
|
-
'
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
class="flex min-h-full w-full items-end justify-center overflow-hidden sm:px-6 sm:pb-6"
|
|
16
|
+
:class="[
|
|
17
|
+
showCloseButton ? 'pt-20' : 'pt-6',
|
|
18
|
+
{
|
|
19
|
+
'sm:items-center': verticalAlign == 'center',
|
|
20
|
+
'sm:items-start': verticalAlign == 'top',
|
|
21
|
+
},
|
|
22
|
+
]"
|
|
20
23
|
>
|
|
21
24
|
<div class="pt-safe grow">
|
|
22
25
|
<transition
|
|
@@ -64,6 +67,7 @@
|
|
|
64
67
|
</div>
|
|
65
68
|
|
|
66
69
|
<button
|
|
70
|
+
v-if="showCloseButton"
|
|
67
71
|
class="right fixed top-2 right-2 flex h-16 w-16 items-center justify-center rounded-full hover:bg-black hover:bg-opacity-20"
|
|
68
72
|
type="button"
|
|
69
73
|
@click="modal.close()"
|
|
@@ -100,6 +104,10 @@ const props = defineProps({
|
|
|
100
104
|
default: '512px',
|
|
101
105
|
type: String,
|
|
102
106
|
},
|
|
107
|
+
showCloseButton: {
|
|
108
|
+
default: true,
|
|
109
|
+
type: Boolean,
|
|
110
|
+
},
|
|
103
111
|
});
|
|
104
112
|
|
|
105
113
|
const emit = defineEmits(['update:modelValue']);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import BaseRichText from './BaseRichText.vue';
|
|
2
|
+
import ShowValue from '@/../.storybook/components/ShowValue.vue';
|
|
3
|
+
import { createFieldStory } from '@/../.storybook/utils';
|
|
4
|
+
|
|
5
|
+
const toolbarOptions = [
|
|
6
|
+
'full',
|
|
7
|
+
'essential',
|
|
8
|
+
'minimal',
|
|
9
|
+
['bold', 'italic', 'underline', 'link'],
|
|
10
|
+
['bold', 'italic', 'underline', 'strike'],
|
|
11
|
+
['blockquote', 'code-block'],
|
|
12
|
+
['clean'], // remove formatting button
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
title: 'Form/BaseRichText',
|
|
17
|
+
component: BaseRichText,
|
|
18
|
+
decorators: [
|
|
19
|
+
(story) => ({
|
|
20
|
+
components: { story },
|
|
21
|
+
template: `
|
|
22
|
+
<form @submit.prevent="" class="border-none">
|
|
23
|
+
<story/>
|
|
24
|
+
</form>`,
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
args: {
|
|
28
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
29
|
+
},
|
|
30
|
+
argTypes: {
|
|
31
|
+
theme: {
|
|
32
|
+
control: { type: 'select' },
|
|
33
|
+
options: ['snow', 'bubble', ''],
|
|
34
|
+
},
|
|
35
|
+
toolbar: {
|
|
36
|
+
control: { type: 'select' },
|
|
37
|
+
options: toolbarOptions,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const Template = (args) => ({
|
|
43
|
+
components: { BaseRichText, ShowValue },
|
|
44
|
+
setup() {
|
|
45
|
+
const value = ref(null);
|
|
46
|
+
return { args, value };
|
|
47
|
+
},
|
|
48
|
+
template: `
|
|
49
|
+
<BaseRichText v-model="value" v-bind="args" class="w-full"></BaseRichText>
|
|
50
|
+
<ShowValue :value="value" />
|
|
51
|
+
`,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const Demo = Template.bind({});
|
|
55
|
+
|
|
56
|
+
export const Basic = Template.bind({});
|
|
57
|
+
Basic.args = {
|
|
58
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const FullToolbar = Template.bind({});
|
|
62
|
+
FullToolbar.args = {
|
|
63
|
+
toolbar: 'full',
|
|
64
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const EssentialToolbar = Template.bind({});
|
|
68
|
+
EssentialToolbar.args = {
|
|
69
|
+
toolbar: 'essential',
|
|
70
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const MinimalToolbar = Template.bind({});
|
|
74
|
+
MinimalToolbar.args = {
|
|
75
|
+
toolbar: 'minimal',
|
|
76
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const SnowTheme = Template.bind({});
|
|
80
|
+
SnowTheme.args = {
|
|
81
|
+
theme: 'snow',
|
|
82
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const BubbleTheme = Template.bind({});
|
|
86
|
+
BubbleTheme.args = {
|
|
87
|
+
theme: 'bubble',
|
|
88
|
+
placeholder: 'Describe your complete life in 4 sentences...',
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const Disabled = Template.bind({});
|
|
92
|
+
Disabled.args = {
|
|
93
|
+
modelValue: 'Lorem ipsum...',
|
|
94
|
+
disabled: true,
|
|
95
|
+
placeholder: '',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const Field = createFieldStory({
|
|
99
|
+
component: BaseRichText,
|
|
100
|
+
componentName: 'BaseRichText',
|
|
101
|
+
label: 'Name',
|
|
102
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="base-rich-text relative"
|
|
4
|
+
:class="[hasErrorInternal ? 'error' : '']"
|
|
5
|
+
>
|
|
6
|
+
<quill-editor
|
|
7
|
+
:name="nameInternal"
|
|
8
|
+
:required="requiredInternal"
|
|
9
|
+
:theme="theme"
|
|
10
|
+
:toolbar="toolbar"
|
|
11
|
+
:placeholder="placeholder"
|
|
12
|
+
:content="modelValue"
|
|
13
|
+
:read-only="disabled"
|
|
14
|
+
:enable="enable"
|
|
15
|
+
content-type="html"
|
|
16
|
+
@update:content="emitUpdate(updateChange($event))"
|
|
17
|
+
@ready="onReady"
|
|
18
|
+
>
|
|
19
|
+
</quill-editor>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script lang="ts" setup>
|
|
24
|
+
import { isString, trim } from 'lodash';
|
|
25
|
+
import { PropType } from 'vue';
|
|
26
|
+
import { useField } from '@/composables/field';
|
|
27
|
+
|
|
28
|
+
import { QuillEditor, Quill } from '@vueup/vue-quill';
|
|
29
|
+
import Delta from 'quill-delta';
|
|
30
|
+
import '@vueup/vue-quill/dist/vue-quill.bubble.css';
|
|
31
|
+
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
|
32
|
+
|
|
33
|
+
const props = defineProps({
|
|
34
|
+
modelValue: {
|
|
35
|
+
default: undefined,
|
|
36
|
+
type: [String, Delta, undefined] as PropType<string | Delta | undefined>,
|
|
37
|
+
},
|
|
38
|
+
theme: {
|
|
39
|
+
type: String as PropType<'' | 'snow' | 'bubble'>,
|
|
40
|
+
default: 'snow',
|
|
41
|
+
},
|
|
42
|
+
toolbar: {
|
|
43
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
44
|
+
default() {
|
|
45
|
+
return ['bold', 'italic', 'underline', 'link'];
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
placeholder: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: '',
|
|
51
|
+
},
|
|
52
|
+
enable: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
default: true,
|
|
55
|
+
},
|
|
56
|
+
disabled: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: false,
|
|
59
|
+
},
|
|
60
|
+
required: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
default: false,
|
|
63
|
+
},
|
|
64
|
+
name: {
|
|
65
|
+
default: undefined,
|
|
66
|
+
type: String,
|
|
67
|
+
},
|
|
68
|
+
hasError: {
|
|
69
|
+
default: false,
|
|
70
|
+
type: Boolean,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const emit = defineEmits(['update:modelValue']);
|
|
75
|
+
|
|
76
|
+
const { nameInternal, requiredInternal, hasErrorInternal, emitUpdate } =
|
|
77
|
+
useField({
|
|
78
|
+
name: computed(() => props.name),
|
|
79
|
+
required: computed(() => props.required),
|
|
80
|
+
hasError: computed(() => props.hasError),
|
|
81
|
+
emit: emit,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
function updateChange(value: string | null): string | null {
|
|
85
|
+
if (value === null) {
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (isString(value)) {
|
|
90
|
+
return trim(value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function onReady(quill: Quill) {
|
|
97
|
+
if (quill.root) {
|
|
98
|
+
//(quill.root as HTMLElement).classList.add('prose', 'max-w-full');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<style lang="postcss">
|
|
104
|
+
.base-rich-text {
|
|
105
|
+
.ql-toolbar.ql-snow {
|
|
106
|
+
@apply rounded-t border-slate-300 font-sans;
|
|
107
|
+
}
|
|
108
|
+
.ql-container.ql-snow {
|
|
109
|
+
@apply rounded-b border-slate-300 font-sans;
|
|
110
|
+
}
|
|
111
|
+
.ql-container {
|
|
112
|
+
@apply font-sans;
|
|
113
|
+
}
|
|
114
|
+
&.error {
|
|
115
|
+
& .ql-toolbar.ql-snow,
|
|
116
|
+
& .ql-container.ql-snow {
|
|
117
|
+
@apply border-red-500;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
:required="requiredInternal"
|
|
9
9
|
:rows="rows"
|
|
10
10
|
:class="[hasErrorInternal ? 'border-red-500' : 'border-slate-300']"
|
|
11
|
-
class="mb-0
|
|
11
|
+
class="block mb-0 rounded disabled:cursor-not-allowed disabled:text-slate-300"
|
|
12
12
|
@input="emitUpdate(transformInputValue($event))"
|
|
13
13
|
/>
|
|
14
14
|
</template>
|
package/src/components/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ import BaseCard from './BaseCard.vue';
|
|
|
17
17
|
import BaseCardRow from './BaseCardRow.vue';
|
|
18
18
|
import BaseCharacterCounter from './BaseCharacterCounter.vue';
|
|
19
19
|
import BaseClipboard from './BaseClipboard.vue';
|
|
20
|
+
import BaseColor from './BaseColor.vue';
|
|
20
21
|
import BaseContainer from './BaseContainer.vue';
|
|
21
22
|
import BaseCounter from './BaseCounter.vue';
|
|
22
23
|
import BaseDataIterator from './BaseDataIterator.vue';
|
|
@@ -53,6 +54,7 @@ import BasePassword from './BasePassword.vue';
|
|
|
53
54
|
import BaseProgressCircle from './BaseProgressCircle.vue';
|
|
54
55
|
import BaseRadioGroup from './BaseRadioGroup.vue';
|
|
55
56
|
import BaseReadMore from './BaseReadMore.vue';
|
|
57
|
+
import BaseRichText from './BaseRichText.vue';
|
|
56
58
|
import BaseSelect from './BaseSelect.vue';
|
|
57
59
|
import BaseShortcut from './BaseShortcut.vue';
|
|
58
60
|
import BaseSideNavigation from './BaseSideNavigation.vue';
|
|
@@ -97,6 +99,7 @@ export {
|
|
|
97
99
|
BaseCardRow,
|
|
98
100
|
BaseCharacterCounter,
|
|
99
101
|
BaseClipboard,
|
|
102
|
+
BaseColor,
|
|
100
103
|
BaseContainer,
|
|
101
104
|
BaseCounter,
|
|
102
105
|
BaseDataIterator,
|
|
@@ -133,6 +136,7 @@ export {
|
|
|
133
136
|
BaseProgressCircle,
|
|
134
137
|
BaseRadioGroup,
|
|
135
138
|
BaseReadMore,
|
|
139
|
+
BaseRichText,
|
|
136
140
|
BaseSelect,
|
|
137
141
|
BaseShortcut,
|
|
138
142
|
BaseSideNavigation,
|