@bethinkpl/design-system 30.1.2 → 30.3.0
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/design-system.css +1 -1
- package/dist/design-system.js +26585 -272
- package/dist/design-system.js.map +1 -1
- package/dist/lib/js/components/Buttons/IconButton/IconButton.vue.d.ts +4 -0
- package/dist/lib/js/components/Cards/Card/Card.vue.d.ts +2 -0
- package/dist/lib/js/components/Cards/CardExpandable/CardExpandable.vue.d.ts +13 -0
- package/dist/lib/js/components/Chip/Chip.vue.d.ts +8 -0
- package/dist/lib/js/components/DatePickers/DateBox/DateBox.vue.d.ts +4 -0
- package/dist/lib/js/components/DatePickers/DatePicker/DatePicker.vue.d.ts +4 -0
- package/dist/lib/js/components/DatePickers/DateRangePicker/DateRangePicker.vue.d.ts +4 -0
- package/dist/lib/js/components/Drawer/DrawerHeader/DrawerHeader.vue.d.ts +44 -14
- package/dist/lib/js/components/Drawer/DrawerListItem/DrawerListItem.vue.d.ts +4 -0
- package/dist/lib/js/components/Drawer/DrawerSection/DrawerSection.vue.d.ts +12 -0
- package/dist/lib/js/components/Form/Checkbox/Checkbox.consts.d.ts +18 -5
- package/dist/lib/js/components/Form/Checkbox/Checkbox.vue.d.ts +31 -461
- package/dist/lib/js/components/Form/Checkbox/index.d.ts +2 -0
- package/dist/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.consts.d.ts +9 -0
- package/dist/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.types.d.ts +12 -0
- package/dist/lib/js/components/Form/CheckboxGroupField/index.d.ts +1 -0
- package/dist/lib/js/components/Form/FormControlLabel/FormControlLabel.consts.d.ts +13 -0
- package/dist/lib/js/components/Form/FormControlLabel/FormControlLabel.vue.d.ts +28 -0
- package/dist/lib/js/components/Form/FormField/FormField.types.d.ts +1 -0
- package/dist/lib/js/components/Form/FormField/FormField.utils.d.ts +2 -2
- package/dist/lib/js/components/Form/InputField/useInputFieldWithinForm.d.ts +1 -1
- package/dist/lib/js/components/Form/RadioButton/RadioButton.vue.d.ts +4 -0
- package/dist/lib/js/components/Headers/OverlayHeader/OverlayHeader.vue.d.ts +8 -0
- package/dist/lib/js/components/Headers/SectionHeader/SectionHeader.vue.d.ts +8 -0
- package/dist/lib/js/components/Icons/Icon/Icon.consts.d.ts +4 -0
- package/dist/lib/js/components/Modal/Modal.vue.d.ts +4 -0
- package/dist/lib/js/components/Modals/Modal/Modal.vue.d.ts +8 -0
- package/dist/lib/js/components/Modals/ModalDialog/ModalDialog.vue.d.ts +8 -0
- package/dist/lib/js/components/Outline/OutlineItem/OutlineItem.vue.d.ts +4 -0
- package/dist/lib/js/components/Pagination/Pagination.vue.d.ts +12 -0
- package/dist/lib/js/components/ProgressBar/ProgressBar.vue.d.ts +4 -0
- package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.vue.d.ts +4 -0
- package/dist/lib/js/components/RichList/BasicRichListItem/BasicRichListItem.vue.d.ts +69 -469
- package/dist/lib/js/components/RichList/RichListItem/RichListItem.vue.d.ts +69 -469
- package/dist/lib/js/components/SelectList/SelectListItem/SelectListItem.vue.d.ts +4 -0
- package/dist/lib/js/components/SelectList/SelectListItemToggle/SelectListItemToggle.vue.d.ts +4 -0
- package/dist/lib/js/components/SelectionTile/SelectionTile.vue.d.ts +29 -1533
- package/dist/lib/js/components/Statuses/AccessStatus/AccessStatus.vue.d.ts +4 -0
- package/dist/lib/js/components/Statuses/BlockadeStatus/BlockadeStatus.vue.d.ts +4 -0
- package/dist/lib/js/components/SurveyQuestions/SurveyQuestionOpenEnded/SurveyQuestionOpenEnded.vue.d.ts +21 -0
- package/dist/lib/js/components/SurveyQuestions/SurveyQuestionScale/SurveyQuestionScale.vue.d.ts +21 -0
- package/dist/lib/js/components/Switch/Switch.vue.d.ts +4 -0
- package/dist/lib/js/components/Tile/Tile.sb.shared.d.ts +4 -0
- package/dist/lib/js/components/Toast/Toast.vue.d.ts +9 -0
- package/dist/lib/js/components/Toggles/ToggleButton/ToggleButton.vue.d.ts +4 -0
- package/dist/lib/js/composables/useFormFieldWithinForm.d.ts +7 -0
- package/dist/lib/js/icons/fontawesome.d.ts +4 -0
- package/dist/storybook/localhost:8080/node_modules/.vite/deps/@bethinkpl_design-system.js?v=62a0baa6 +7919 -0
- package/lib/js/components/Cards/Card/Card.spec.ts +23 -0
- package/lib/js/components/Cards/Card/Card.stories.ts +1 -0
- package/lib/js/components/Cards/Card/Card.vue +21 -4
- package/lib/js/components/Drawer/DrawerHeader/DrawerHeader.vue +13 -13
- package/lib/js/components/Form/Checkbox/Checkbox.consts.ts +27 -10
- package/lib/js/components/Form/Checkbox/Checkbox.spec.ts +294 -0
- package/lib/js/components/Form/Checkbox/Checkbox.stories.ts +60 -19
- package/lib/js/components/Form/Checkbox/Checkbox.vue +272 -55
- package/lib/js/components/Form/Checkbox/index.ts +2 -0
- package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.consts.ts +11 -0
- package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.spec.ts +268 -0
- package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.stories.ts +92 -0
- package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.types.ts +13 -0
- package/lib/js/components/Form/CheckboxGroupField/CheckboxGroupField.vue +97 -0
- package/lib/js/components/Form/CheckboxGroupField/index.ts +1 -0
- package/lib/js/components/Form/Form.stories.ts +67 -0
- package/lib/js/components/Form/FormControlLabel/FormControlLabel.consts.ts +16 -0
- package/lib/js/components/Form/FormControlLabel/FormControlLabel.vue +61 -0
- package/lib/js/components/Form/FormField/FormField.types.ts +2 -1
- package/lib/js/components/Form/FormField/FormField.utils.ts +14 -10
- package/lib/js/components/Form/FormField/FormField.vue +3 -2
- package/lib/js/components/Form/InputField/InputField.vue +1 -7
- package/lib/js/components/Form/InputField/useInputFieldWithinForm.ts +4 -29
- package/lib/js/components/RichList/RichListItem/RichListItem.vue +11 -8
- package/lib/js/components/SelectionTile/SelectionTile.vue +64 -95
- package/lib/js/composables/useFormFieldWithinForm.ts +26 -0
- package/lib/js/composables/useLegacyI18n.ts +0 -1
- package/lib/js/icons/fontawesome.ts +8 -0
- package/lib/styles/settings/_animations.scss +3 -0
- package/package.json +7 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3';
|
|
2
|
+
import CheckboxGroupField from './CheckboxGroupField.vue';
|
|
3
|
+
import Checkbox from '../Checkbox/Checkbox.vue';
|
|
4
|
+
import { CHECKBOX_ELEVATIONS, CHECKBOX_SIZES, CHECKBOX_STATES } from '../Checkbox/Checkbox.consts';
|
|
5
|
+
import { args, argTypes } from '../FormField/FormField.stories.shared';
|
|
6
|
+
import { reactive, toRefs } from 'vue';
|
|
7
|
+
import { ICONS } from '../../Icons/Icon';
|
|
8
|
+
import HelpButton from '../../Buttons/HelpButton';
|
|
9
|
+
import Banner from '../../Banner';
|
|
10
|
+
|
|
11
|
+
const meta: Meta<typeof CheckboxGroupField> = {
|
|
12
|
+
title: 'Components/Form/CheckboxGroupField',
|
|
13
|
+
component: CheckboxGroupField,
|
|
14
|
+
render: (args) => ({
|
|
15
|
+
components: { CheckboxGroupField, Checkbox, HelpButton, Banner },
|
|
16
|
+
setup() {
|
|
17
|
+
const { help, labelAside, message, fieldStatus, field, ...restRefs } = toRefs(args);
|
|
18
|
+
const props = reactive({ ...restRefs });
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
props,
|
|
22
|
+
labelAside,
|
|
23
|
+
fieldStatus,
|
|
24
|
+
message,
|
|
25
|
+
help,
|
|
26
|
+
CHECKBOX_STATES,
|
|
27
|
+
ICONS,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
template: `
|
|
31
|
+
<CheckboxGroupField v-bind="props">
|
|
32
|
+
<template #field>
|
|
33
|
+
<Checkbox value="option1">Option 1</Checkbox>
|
|
34
|
+
<Checkbox value="option2">Option 2</Checkbox>
|
|
35
|
+
<Checkbox value="option3">Option 3</Checkbox>
|
|
36
|
+
</template>
|
|
37
|
+
<template v-if="help" #help>
|
|
38
|
+
<HelpButton :is-disabled="props.state === CHECKBOX_STATES.DISABLED" modal-title="Help modal title">
|
|
39
|
+
<template #modalContent>
|
|
40
|
+
Modal
|
|
41
|
+
</template>
|
|
42
|
+
</HelpButton>
|
|
43
|
+
</template>
|
|
44
|
+
<template #labelAside v-if="labelAside">
|
|
45
|
+
<div v-html="labelAside" />
|
|
46
|
+
</template>
|
|
47
|
+
<template #fieldStatus v-if="fieldStatus">
|
|
48
|
+
<div v-html="fieldStatus" />
|
|
49
|
+
</template>
|
|
50
|
+
<template #message v-if="message">
|
|
51
|
+
<div v-if="message" v-html="message" />
|
|
52
|
+
</template>
|
|
53
|
+
</CheckboxGroupField>
|
|
54
|
+
<Banner color="danger" title="Uwaga! Mogą wystąpić problemy z pisaniem testów jednostkowych korzystających z tego komponentu. Unikaj jego używania. A jeśli jest rok 2026 i wciąż widzisz ten komunikat — nakrzycz na Karola!" title-in-color />
|
|
55
|
+
`,
|
|
56
|
+
}),
|
|
57
|
+
argTypes,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default meta;
|
|
61
|
+
type Story = StoryObj<typeof CheckboxGroupField>;
|
|
62
|
+
|
|
63
|
+
export const Interactive: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
...args,
|
|
66
|
+
state: CHECKBOX_STATES.DEFAULT,
|
|
67
|
+
size: CHECKBOX_SIZES.SMALL,
|
|
68
|
+
elevation: CHECKBOX_ELEVATIONS.X_SMALL,
|
|
69
|
+
// Override the field arg just to make TS happy; the story doesn't allow editing it anyway
|
|
70
|
+
field: () => {},
|
|
71
|
+
},
|
|
72
|
+
parameters: {
|
|
73
|
+
design: {
|
|
74
|
+
type: 'figma',
|
|
75
|
+
url: 'https://www.figma.com/design/izQdYyiBR1GQgFkaOIfIJI/LMS---DS-Components?node-id=14832-98644&m=dev',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
argTypes: {
|
|
79
|
+
size: {
|
|
80
|
+
control: 'select',
|
|
81
|
+
options: Object.values(CHECKBOX_SIZES),
|
|
82
|
+
},
|
|
83
|
+
state: {
|
|
84
|
+
control: 'select',
|
|
85
|
+
options: Object.values(CHECKBOX_STATES),
|
|
86
|
+
},
|
|
87
|
+
elevation: {
|
|
88
|
+
control: 'select',
|
|
89
|
+
options: Object.values(CHECKBOX_ELEVATIONS),
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FormFieldProps, FormFieldSlots } from '../FormField';
|
|
2
|
+
import type { CheckboxElevation, CheckboxSize, CheckboxState } from '../Checkbox';
|
|
3
|
+
|
|
4
|
+
export interface CheckboxGroupFieldProps extends FormFieldProps {
|
|
5
|
+
size?: CheckboxSize;
|
|
6
|
+
state?: CheckboxState;
|
|
7
|
+
elevation?: CheckboxElevation;
|
|
8
|
+
name?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type CheckboxGroupFieldSlots = Omit<FormFieldSlots, 'field'> & {
|
|
12
|
+
field: () => any;
|
|
13
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<form-field v-bind="formFieldProps">
|
|
3
|
+
<template #field="{ messageId, labelId }">
|
|
4
|
+
<checkbox-group-root
|
|
5
|
+
v-model="value"
|
|
6
|
+
class="ds-checkboxGroupField"
|
|
7
|
+
role="group"
|
|
8
|
+
:aria-describedby="messageId"
|
|
9
|
+
:aria-labelledby="labelId"
|
|
10
|
+
:disabled="formFieldProps.state === FORM_FIELD_STATES.DISABLED"
|
|
11
|
+
loop
|
|
12
|
+
>
|
|
13
|
+
<slot name="field"></slot>
|
|
14
|
+
</checkbox-group-root>
|
|
15
|
+
</template>
|
|
16
|
+
<!-- begin: FormField slots -->
|
|
17
|
+
<template v-if="$slots.labelAside" #labelAside>
|
|
18
|
+
<slot name="labelAside" />
|
|
19
|
+
</template>
|
|
20
|
+
<template v-if="$slots.help" #help>
|
|
21
|
+
<slot name="help" />
|
|
22
|
+
</template>
|
|
23
|
+
<template v-if="$slots.message" #message="{ messageId }">
|
|
24
|
+
<slot name="message" :message-id="messageId" />
|
|
25
|
+
</template>
|
|
26
|
+
<template v-if="$slots.fieldStatus" #fieldStatus>
|
|
27
|
+
<slot name="fieldStatus" />
|
|
28
|
+
</template>
|
|
29
|
+
<!-- end: FormField slots -->
|
|
30
|
+
</form-field>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style scoped lang="scss">
|
|
34
|
+
@import '../../../../styles/settings/spacings';
|
|
35
|
+
|
|
36
|
+
.ds-checkboxGroupField {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: $space-2xs;
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
|
|
43
|
+
<script setup lang="ts">
|
|
44
|
+
import { CheckboxGroupRoot } from 'reka-ui';
|
|
45
|
+
import { provide, computed, toRef } from 'vue';
|
|
46
|
+
import FormField from '../FormField/FormField.vue';
|
|
47
|
+
import { FormFieldProps } from '../FormField/FormField.types';
|
|
48
|
+
import { extractFormFieldProps } from '../FormField/FormField.utils';
|
|
49
|
+
import {
|
|
50
|
+
CHECKBOX_SIZES,
|
|
51
|
+
CHECKBOX_ELEVATIONS,
|
|
52
|
+
type CheckboxState,
|
|
53
|
+
CHECKBOX_STATES,
|
|
54
|
+
} from '../Checkbox/Checkbox.consts';
|
|
55
|
+
import { CHECKBOX_GROUP_INJECTION_KEY } from './CheckboxGroupField.consts';
|
|
56
|
+
import { FORM_FIELD_STATES, FormFieldState } from '../FormField';
|
|
57
|
+
import { CheckboxGroupFieldProps, CheckboxGroupFieldSlots } from './CheckboxGroupField.types';
|
|
58
|
+
import { useFormFieldWithinForm } from '../../../composables/useFormFieldWithinForm';
|
|
59
|
+
|
|
60
|
+
const {
|
|
61
|
+
size = CHECKBOX_SIZES.SMALL,
|
|
62
|
+
elevation = CHECKBOX_ELEVATIONS.NONE,
|
|
63
|
+
name,
|
|
64
|
+
...rest
|
|
65
|
+
} = defineProps<CheckboxGroupFieldProps>();
|
|
66
|
+
|
|
67
|
+
defineSlots<CheckboxGroupFieldSlots>();
|
|
68
|
+
|
|
69
|
+
const modelValue = defineModel<Array<string>>({
|
|
70
|
+
default: [],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const { value, errors } = useFormFieldWithinForm(() => name, modelValue);
|
|
74
|
+
|
|
75
|
+
const formFieldProps = computed<FormFieldProps>(() => {
|
|
76
|
+
// this is needed to avoid passing modelValue to FormField as prop
|
|
77
|
+
return extractFormFieldProps(rest, errors.value);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const mappedState = computed(() => {
|
|
81
|
+
const stateMap: Record<FormFieldState, CheckboxState> = {
|
|
82
|
+
[FORM_FIELD_STATES.DEFAULT]: CHECKBOX_STATES.DEFAULT,
|
|
83
|
+
[FORM_FIELD_STATES.ERROR]: CHECKBOX_STATES.ERROR,
|
|
84
|
+
[FORM_FIELD_STATES.DISABLED]: CHECKBOX_STATES.DISABLED,
|
|
85
|
+
[FORM_FIELD_STATES.SUCCESS]: CHECKBOX_STATES.DEFAULT,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return stateMap[formFieldProps.value.state || CHECKBOX_STATES.DEFAULT];
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Provide context for child checkboxes
|
|
92
|
+
provide(CHECKBOX_GROUP_INJECTION_KEY, {
|
|
93
|
+
size: toRef(() => size),
|
|
94
|
+
state: mappedState,
|
|
95
|
+
elevation: toRef(() => elevation),
|
|
96
|
+
});
|
|
97
|
+
</script>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './CheckboxGroupField.vue';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import Checkbox from './Checkbox/Checkbox.vue';
|
|
2
|
+
import { withActions } from '@storybook/addon-actions/decorator';
|
|
3
|
+
import { Meta } from '@storybook/vue3';
|
|
4
|
+
import InputField from './InputField';
|
|
5
|
+
import { useForm } from 'vee-validate';
|
|
6
|
+
import { toTypedSchema } from '@vee-validate/zod';
|
|
7
|
+
import { array, object, string } from 'zod';
|
|
8
|
+
import CheckboxGroupField from './CheckboxGroupField/CheckboxGroupField.vue';
|
|
9
|
+
import Button from '../Buttons/Button';
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
title: 'Components/Form/FormExamples',
|
|
13
|
+
decorators: [withActions],
|
|
14
|
+
} as Meta<any>;
|
|
15
|
+
|
|
16
|
+
export const SimpleForm = () => ({
|
|
17
|
+
components: { InputField, CheckboxGroupField, Checkbox, Button },
|
|
18
|
+
setup: () => {
|
|
19
|
+
const { handleSubmit } = useForm({
|
|
20
|
+
initialValues: {
|
|
21
|
+
fullName: '',
|
|
22
|
+
newsletterTopics: [],
|
|
23
|
+
},
|
|
24
|
+
validationSchema: toTypedSchema(
|
|
25
|
+
object({
|
|
26
|
+
fullName: string().min(1, 'Imię i nazwisko jest wymagane'),
|
|
27
|
+
newsletterTopics: array(string()).min(
|
|
28
|
+
1,
|
|
29
|
+
'Wybierz przynajmniej jeden temat newslettera',
|
|
30
|
+
),
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const onSubmit = handleSubmit(
|
|
36
|
+
(form) => {
|
|
37
|
+
console.log('Form submitted successfully:', form);
|
|
38
|
+
},
|
|
39
|
+
(errors) => {
|
|
40
|
+
console.log('Validation errors:', errors);
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
onSubmit,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
template: `
|
|
49
|
+
<form @submit.prevent="onSubmit" style="display: flex; flex-direction: column; gap: 16px; max-width: 400px;">
|
|
50
|
+
<InputField label="Imię i nazwisko" name="fullName" />
|
|
51
|
+
<CheckboxGroupField label="Jakie tematy newslettera Cię interesują?" name="newsletterTopics">
|
|
52
|
+
<template #field>
|
|
53
|
+
<Checkbox value="technology">Technologia</Checkbox>
|
|
54
|
+
<Checkbox value="health">Zdrowie</Checkbox>
|
|
55
|
+
<Checkbox value="finance">Finanse</Checkbox>
|
|
56
|
+
<Checkbox value="sports">Sport</Checkbox>
|
|
57
|
+
</template>
|
|
58
|
+
</CheckboxGroupField>
|
|
59
|
+
<Button as="button">
|
|
60
|
+
Wyślij
|
|
61
|
+
</Button>
|
|
62
|
+
</form>
|
|
63
|
+
`,
|
|
64
|
+
data() {
|
|
65
|
+
return {};
|
|
66
|
+
},
|
|
67
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Value } from '../../../utils/type.utils';
|
|
2
|
+
|
|
3
|
+
export const FORM_CONTROL_SIZE = {
|
|
4
|
+
X_SMALL: 'x-small',
|
|
5
|
+
SMALL: 'small',
|
|
6
|
+
MEDIUM: 'medium',
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export type FormControlSize = Value<typeof FORM_CONTROL_SIZE>;
|
|
10
|
+
|
|
11
|
+
export const FORM_CONTROL_STATE = {
|
|
12
|
+
DEFAULT: 'default',
|
|
13
|
+
DISABLED: 'disabled',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type FormControlState = Value<typeof FORM_CONTROL_STATE>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span
|
|
3
|
+
:class="[
|
|
4
|
+
'ds-formControlLabel',
|
|
5
|
+
{
|
|
6
|
+
'-ds-x-small': size === FORM_CONTROL_SIZE.X_SMALL,
|
|
7
|
+
'-ds-small': size === FORM_CONTROL_SIZE.SMALL,
|
|
8
|
+
'-ds-medium': size === FORM_CONTROL_SIZE.MEDIUM,
|
|
9
|
+
'-ds-disabled': state === FORM_CONTROL_STATE.DISABLED,
|
|
10
|
+
},
|
|
11
|
+
]"
|
|
12
|
+
>
|
|
13
|
+
<slot />
|
|
14
|
+
</span>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<style scoped lang="scss">
|
|
18
|
+
@import '../../../../styles/settings/spacings';
|
|
19
|
+
@import '../../../../styles/settings/typography/tokens';
|
|
20
|
+
@import '../../../../styles/settings/colors/tokens';
|
|
21
|
+
|
|
22
|
+
.ds-formControlLabel {
|
|
23
|
+
color: $color-neutral-text-strong;
|
|
24
|
+
|
|
25
|
+
&.-ds-x-small {
|
|
26
|
+
@include formLabel-s-default-regular;
|
|
27
|
+
|
|
28
|
+
padding: $space-4xs 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&.-ds-small {
|
|
32
|
+
@include formLabel-m-default-regular;
|
|
33
|
+
|
|
34
|
+
padding: $space-3xs 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.-ds-medium {
|
|
38
|
+
@include formLabel-l-default-regular;
|
|
39
|
+
|
|
40
|
+
padding: $space-2xs 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&.-ds-disabled {
|
|
44
|
+
color: $color-neutral-text-strong-disabled;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
48
|
+
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
import {
|
|
51
|
+
FORM_CONTROL_SIZE,
|
|
52
|
+
FORM_CONTROL_STATE,
|
|
53
|
+
FormControlSize,
|
|
54
|
+
FormControlState,
|
|
55
|
+
} from './FormControlLabel.consts';
|
|
56
|
+
|
|
57
|
+
const { state = FORM_CONTROL_STATE.DEFAULT, size = FORM_CONTROL_SIZE.SMALL } = defineProps<{
|
|
58
|
+
size?: FormControlSize;
|
|
59
|
+
state?: FormControlState;
|
|
60
|
+
}>();
|
|
61
|
+
</script>
|
|
@@ -11,7 +11,8 @@ export interface FormFieldProps {
|
|
|
11
11
|
export interface FormFieldSlots {
|
|
12
12
|
labelAside?: () => any;
|
|
13
13
|
help?: () => any;
|
|
14
|
-
field: (props: { fieldId: string; messageId: string }) => any;
|
|
14
|
+
field: (props: { fieldId: string; messageId: string; labelId: string }) => any;
|
|
15
15
|
message?: (props: { messageId: string }) => any;
|
|
16
16
|
fieldStatus?: () => any;
|
|
17
|
+
// !!!! If you ever add a new slot here, please remember to update all components using FormField component !!!! //
|
|
17
18
|
}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { FormFieldProps } from './FormField.types';
|
|
2
|
+
import { FORM_FIELD_STATES } from './FormField.consts';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Extracts the properties needed for a form field component only
|
|
5
6
|
*/
|
|
6
|
-
export function extractFormFieldProps(
|
|
7
|
-
|
|
8
|
-
state,
|
|
9
|
-
hasRequiredIndicator,
|
|
10
|
-
labelInfo,
|
|
11
|
-
subLabel,
|
|
12
|
-
fieldId,
|
|
13
|
-
messageText,
|
|
14
|
-
}: FormFieldProps) {
|
|
15
|
-
return {
|
|
7
|
+
export function extractFormFieldProps(
|
|
8
|
+
{
|
|
16
9
|
label,
|
|
17
10
|
state,
|
|
18
11
|
hasRequiredIndicator,
|
|
@@ -20,5 +13,16 @@ export function extractFormFieldProps({
|
|
|
20
13
|
subLabel,
|
|
21
14
|
fieldId,
|
|
22
15
|
messageText,
|
|
16
|
+
}: FormFieldProps,
|
|
17
|
+
errors: Array<string> = [],
|
|
18
|
+
) {
|
|
19
|
+
return {
|
|
20
|
+
label,
|
|
21
|
+
state: state ?? (errors[0] ? FORM_FIELD_STATES.ERROR : undefined),
|
|
22
|
+
hasRequiredIndicator,
|
|
23
|
+
labelInfo,
|
|
24
|
+
subLabel,
|
|
25
|
+
fieldId,
|
|
26
|
+
messageText: messageText ?? errors[0],
|
|
23
27
|
};
|
|
24
28
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<div v-if="label || subLabel || $slots.labelAside" class="ds-formField__labels">
|
|
11
11
|
<div class="ds-formField__labelRow">
|
|
12
12
|
<div class="ds-formField__labelWrapper">
|
|
13
|
-
<label v-if="label" class="ds-formField__label" :for="id">
|
|
13
|
+
<label v-if="label" :id="labelId" class="ds-formField__label" :for="id">
|
|
14
14
|
<span class="ds-formField__labelText">{{ label }}</span>
|
|
15
15
|
<span
|
|
16
16
|
v-if="hasRequiredIndicator"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<div v-if="subLabel" class="ds-formField__subLabelRow">{{ subLabel }}</div>
|
|
32
32
|
</div>
|
|
33
33
|
<div class="ds-formField__field">
|
|
34
|
-
<slot name="field" :field-id="id" :message-id="messageId"></slot>
|
|
34
|
+
<slot name="field" :field-id="id" :message-id="messageId" :label-id="labelId"></slot>
|
|
35
35
|
</div>
|
|
36
36
|
<div v-if="hasMessage || $slots.fieldStatus" class="ds-formField__footerRow">
|
|
37
37
|
<div class="ds-formField__message">
|
|
@@ -175,6 +175,7 @@ const slots = defineSlots<FormFieldSlots>();
|
|
|
175
175
|
|
|
176
176
|
const baseId = useId();
|
|
177
177
|
const id = computed(() => fieldId || `form-field-${baseId}`);
|
|
178
|
+
const labelId = computed(() => `${id.value}-label`);
|
|
178
179
|
const { hasMessage, messageId } = useMessage();
|
|
179
180
|
|
|
180
181
|
function useMessage() {
|
|
@@ -156,13 +156,7 @@ const {
|
|
|
156
156
|
|
|
157
157
|
const formFieldProps = computed<FormFieldProps>(() => {
|
|
158
158
|
// this is needed to avoid passing modelValue to FormField as prop
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return {
|
|
162
|
-
...extractedProps,
|
|
163
|
-
messageText: extractedProps.messageText ?? errors.value[0],
|
|
164
|
-
state: extractedProps.state ?? (errors.value[0] ? FORM_FIELD_STATES.ERROR : undefined),
|
|
165
|
-
};
|
|
159
|
+
return extractFormFieldProps(rest, errors.value);
|
|
166
160
|
});
|
|
167
161
|
|
|
168
162
|
const finalInputProps = computed<InputHTMLAttributes>(() => {
|
|
@@ -1,37 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { MaybeRefOrGetter, ref, Ref } from 'vue';
|
|
2
|
+
import { useFormFieldWithinForm } from '../../../composables/useFormFieldWithinForm';
|
|
3
3
|
|
|
4
4
|
export function useInputFieldWithinForm(
|
|
5
5
|
name: MaybeRefOrGetter<string | undefined>,
|
|
6
6
|
modelValue: Ref<string | undefined>,
|
|
7
7
|
) {
|
|
8
|
-
const
|
|
9
|
-
const nameValue = toValue(name);
|
|
8
|
+
const { value, errors, field } = useFormFieldWithinForm(name, modelValue);
|
|
10
9
|
|
|
11
|
-
// this computed property was created only for type safety so we can use it with `useField`
|
|
12
|
-
const nameString = computed(() => {
|
|
13
|
-
const value = toValue(name);
|
|
14
|
-
|
|
15
|
-
if (value === undefined) {
|
|
16
|
-
throw new Error('fieldName is required');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return value;
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
if (nameValue && !form) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
`InputField with name "${nameValue}" must be used within a component that provides a FormContext, e.g. by using useForm()`,
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const field = nameValue
|
|
29
|
-
? useField(nameString, undefined, {
|
|
30
|
-
validateOnValueUpdate: false,
|
|
31
|
-
})
|
|
32
|
-
: null;
|
|
33
|
-
|
|
34
|
-
const value = field ? field.value : modelValue;
|
|
35
10
|
const blurred = ref(false);
|
|
36
11
|
|
|
37
12
|
const onBlur = (event: Event) => {
|
|
@@ -49,6 +24,6 @@ export function useInputFieldWithinForm(
|
|
|
49
24
|
onBlur,
|
|
50
25
|
onInput,
|
|
51
26
|
value,
|
|
52
|
-
errors
|
|
27
|
+
errors,
|
|
53
28
|
};
|
|
54
29
|
}
|
|
@@ -54,8 +54,9 @@
|
|
|
54
54
|
<div v-if="isSelectable" class="ds-richListItem__checkbox">
|
|
55
55
|
<ds-divider v-if="isHorizontal" is-vertical />
|
|
56
56
|
<ds-checkbox
|
|
57
|
-
:
|
|
58
|
-
|
|
57
|
+
:elevation="CHECKBOX_ELEVATIONS.NONE"
|
|
58
|
+
:model-value="isSelected"
|
|
59
|
+
@update:model-value="(value) => $emit('update:is-selected', !!value)"
|
|
59
60
|
@click.stop
|
|
60
61
|
/>
|
|
61
62
|
</div>
|
|
@@ -503,6 +504,7 @@ import {
|
|
|
503
504
|
RichListItemState,
|
|
504
505
|
RichListItemType,
|
|
505
506
|
} from './RichListItem.consts';
|
|
507
|
+
import { CHECKBOX_ELEVATIONS } from '../../Form/Checkbox';
|
|
506
508
|
|
|
507
509
|
export default defineComponent({
|
|
508
510
|
name: 'RichListItem',
|
|
@@ -621,13 +623,14 @@ export default defineComponent({
|
|
|
621
623
|
click: (event: Event) => true,
|
|
622
624
|
'update:is-selected': (isSelected: boolean) => true,
|
|
623
625
|
},
|
|
624
|
-
|
|
626
|
+
setup() {
|
|
625
627
|
return {
|
|
626
|
-
ICONS
|
|
627
|
-
ICON_SIZES
|
|
628
|
-
RICH_LIST_ITEM_TYPE
|
|
629
|
-
RICH_LIST_ITEM_STATE
|
|
630
|
-
RICH_LIST_ITEM_SIZE
|
|
628
|
+
ICONS,
|
|
629
|
+
ICON_SIZES,
|
|
630
|
+
RICH_LIST_ITEM_TYPE,
|
|
631
|
+
RICH_LIST_ITEM_STATE,
|
|
632
|
+
RICH_LIST_ITEM_SIZE,
|
|
633
|
+
CHECKBOX_ELEVATIONS,
|
|
631
634
|
};
|
|
632
635
|
},
|
|
633
636
|
computed: {
|