@carbon/vue 3.0.4-alpha.0 → 3.0.5-alpha.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/carbon-vue-3.common.js +1186 -219
- package/dist/carbon-vue-3.common.js.map +1 -1
- package/dist/carbon-vue-3.umd.js +1186 -219
- package/dist/carbon-vue-3.umd.js.map +1 -1
- package/dist/carbon-vue-3.umd.min.js +2 -2
- package/dist/carbon-vue-3.umd.min.js.map +1 -1
- package/package.json +2 -2
- package/src/components/CvCheckbox/CvCheckbox.vue +0 -2
- package/src/components/CvTextArea/CvTextArea.stories.js +174 -0
- package/src/components/CvTextArea/CvTextArea.vue +107 -0
- package/src/components/CvTextArea/index.js +4 -0
- package/src/components/CvTextInput/CvTextInput.stories.js +245 -0
- package/src/components/CvTextInput/CvTextInput.vue +217 -0
- package/src/components/CvTextInput/const.js +2 -0
- package/src/components/CvTextInput/index.js +4 -0
- package/src/components/CvTile/CvTile.stories.mdx +156 -0
- package/src/components/CvTile/CvTile.vue +67 -0
- package/src/components/CvTile/CvTileClickable.vue +23 -0
- package/src/components/CvTile/CvTileExpandable.vue +103 -0
- package/src/components/CvTile/CvTileSelectable.vue +52 -0
- package/src/components/CvTile/CvTileStandard.vue +7 -0
- package/src/components/CvTile/index.js +4 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="[
|
|
4
|
+
'cv-text-input',
|
|
5
|
+
`${carbonPrefix}--form-item`,
|
|
6
|
+
`${carbonPrefix}--text-input-wrapper`,
|
|
7
|
+
{ [`${carbonPrefix}--password-input-wrapper`]: isPassword },
|
|
8
|
+
]"
|
|
9
|
+
>
|
|
10
|
+
<label
|
|
11
|
+
:for="cvId"
|
|
12
|
+
:class="[
|
|
13
|
+
`${carbonPrefix}--label`,
|
|
14
|
+
{
|
|
15
|
+
[`${carbonPrefix}--label--disabled`]: $attrs.disabled,
|
|
16
|
+
[`${carbonPrefix}--visually-hidden`]: hideLabel,
|
|
17
|
+
},
|
|
18
|
+
]"
|
|
19
|
+
>
|
|
20
|
+
{{ label }}
|
|
21
|
+
</label>
|
|
22
|
+
<div
|
|
23
|
+
:class="[
|
|
24
|
+
`${carbonPrefix}--text-input__field-wrapper`,
|
|
25
|
+
{ [`${carbonPrefix}--text-input__field-wrapper--warning`]: isWarn },
|
|
26
|
+
]"
|
|
27
|
+
:data-invalid="isInvalid"
|
|
28
|
+
>
|
|
29
|
+
<WarningFilled16
|
|
30
|
+
v-if="isInvalid"
|
|
31
|
+
:class="`${carbonPrefix}--text-input__invalid-icon`"
|
|
32
|
+
/>
|
|
33
|
+
<WarningAltFilled16
|
|
34
|
+
v-if="isWarn"
|
|
35
|
+
:class="`${carbonPrefix}--text-input__invalid-icon ${carbonPrefix}--text-input__invalid-icon--warning`"
|
|
36
|
+
/>
|
|
37
|
+
<input
|
|
38
|
+
ref="input"
|
|
39
|
+
:id="cvId"
|
|
40
|
+
:class="[
|
|
41
|
+
`${carbonPrefix}--text-input`,
|
|
42
|
+
{
|
|
43
|
+
[`${carbonPrefix}--text-input--invalid`]: isInvalid,
|
|
44
|
+
[`${carbonPrefix}--text-input--light`]: isLight,
|
|
45
|
+
[`${carbonPrefix}--text-input--warning`]: isWarn,
|
|
46
|
+
[`${carbonPrefix}--password-input`]: isPassword,
|
|
47
|
+
},
|
|
48
|
+
]"
|
|
49
|
+
v-bind="$attrs"
|
|
50
|
+
:type="dataType"
|
|
51
|
+
:value="modelValue"
|
|
52
|
+
:data-toggle-password-visibility="isPassword"
|
|
53
|
+
@input="$event => $emit('update:modelValue', $event.target.value)"
|
|
54
|
+
/>
|
|
55
|
+
<button
|
|
56
|
+
v-if="isPassword"
|
|
57
|
+
:class="[
|
|
58
|
+
`${carbonPrefix}--btn`,
|
|
59
|
+
`${carbonPrefix}--btn--icon-only`,
|
|
60
|
+
`${carbonPrefix}--text-input--password__visibility__toggle`,
|
|
61
|
+
`${carbonPrefix}--tooltip__trigger`,
|
|
62
|
+
`${carbonPrefix}--tooltip--a11y`,
|
|
63
|
+
`${carbonPrefix}--tooltip--bottom`,
|
|
64
|
+
`${carbonPrefix}--tooltip--align-center`,
|
|
65
|
+
{ [`${carbonPrefix}--btn--disabled`]: $attrs.disabled },
|
|
66
|
+
]"
|
|
67
|
+
@click="togglePasswordVisibility"
|
|
68
|
+
type="button"
|
|
69
|
+
:disabled="$attrs.disabled"
|
|
70
|
+
>
|
|
71
|
+
<span :class="`${carbonPrefix}--assistive-text`">
|
|
72
|
+
{{ passwordHideShowLabel }}
|
|
73
|
+
</span>
|
|
74
|
+
<ViewOff16
|
|
75
|
+
v-if="isPasswordVisible"
|
|
76
|
+
:class="`${carbonPrefix}--icon-visibility-off`"
|
|
77
|
+
/>
|
|
78
|
+
<View16 v-else :class="`${carbonPrefix}--icon-visibility-on`" />
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
81
|
+
<div v-if="isInvalid" :class="`${carbonPrefix}--form-requirement`">
|
|
82
|
+
<slot name="invalid-message">{{ invalidMessage }}</slot>
|
|
83
|
+
</div>
|
|
84
|
+
<div v-if="isWarn" :class="`${carbonPrefix}--form__requirement`">
|
|
85
|
+
<slot name="warn-text">{{ warnText }}</slot>
|
|
86
|
+
</div>
|
|
87
|
+
<div
|
|
88
|
+
v-if="isHelper"
|
|
89
|
+
:class="[
|
|
90
|
+
`${carbonPrefix}--form__helper-text`,
|
|
91
|
+
{ [`${carbonPrefix}--form__helper-text--disabled`]: $attrs.disabled },
|
|
92
|
+
]"
|
|
93
|
+
>
|
|
94
|
+
<slot name="helper-text">{{ helperText }}</slot>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</template>
|
|
98
|
+
|
|
99
|
+
<script setup>
|
|
100
|
+
import {
|
|
101
|
+
onBeforeMount,
|
|
102
|
+
onBeforeUpdate,
|
|
103
|
+
ref,
|
|
104
|
+
useSlots,
|
|
105
|
+
computed,
|
|
106
|
+
watch,
|
|
107
|
+
nextTick,
|
|
108
|
+
} from 'vue';
|
|
109
|
+
import {
|
|
110
|
+
WarningFilled16,
|
|
111
|
+
WarningAltFilled16,
|
|
112
|
+
ViewOff16,
|
|
113
|
+
View16,
|
|
114
|
+
} from '@carbon/icons-vue';
|
|
115
|
+
import { carbonPrefix } from '../../global/settings';
|
|
116
|
+
import { useCvId, props as propsCvId } from '../../use/cvId';
|
|
117
|
+
import { useIsLight, props as propsTheme } from '../../use/cvTheme';
|
|
118
|
+
import { inputTypes } from './const';
|
|
119
|
+
|
|
120
|
+
const props = defineProps({
|
|
121
|
+
helperText: { type: String, default: undefined },
|
|
122
|
+
hideLabel: { type: Boolean, default: false },
|
|
123
|
+
invalidMessage: { type: String, default: undefined },
|
|
124
|
+
label: String,
|
|
125
|
+
modelValue: String,
|
|
126
|
+
passwordHideLabel: { type: String, default: 'Hide password' },
|
|
127
|
+
passwordShowLabel: { type: String, default: 'Show password' },
|
|
128
|
+
passwordVisible: { type: Boolean, default: undefined },
|
|
129
|
+
type: {
|
|
130
|
+
type: String,
|
|
131
|
+
default: 'text',
|
|
132
|
+
validator: value => inputTypes.has(value),
|
|
133
|
+
},
|
|
134
|
+
warnText: { type: String, default: undefined },
|
|
135
|
+
...propsCvId,
|
|
136
|
+
...propsTheme,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const cvId = useCvId(props);
|
|
140
|
+
|
|
141
|
+
// DOM Elements
|
|
142
|
+
const input = ref();
|
|
143
|
+
const slots = useSlots();
|
|
144
|
+
|
|
145
|
+
// Data
|
|
146
|
+
const isInvalid = ref(false);
|
|
147
|
+
const isWarn = ref(false);
|
|
148
|
+
const isHelper = ref(false);
|
|
149
|
+
const isLight = useIsLight(props);
|
|
150
|
+
const dataType = ref(props.type);
|
|
151
|
+
const dataPasswordVisible = ref(false);
|
|
152
|
+
|
|
153
|
+
// Computed Values
|
|
154
|
+
const isPassword = computed(() => props.type === 'password');
|
|
155
|
+
const isPasswordVisible = computed(
|
|
156
|
+
() => isPassword.value && dataPasswordVisible.value
|
|
157
|
+
);
|
|
158
|
+
const passwordHideShowLabel = computed(() =>
|
|
159
|
+
isPasswordVisible.value ? props.passwordHideLabel : props.passwordShowLabel
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Watchers
|
|
163
|
+
watch(
|
|
164
|
+
() => props.passwordVisible,
|
|
165
|
+
newValue => {
|
|
166
|
+
if (newValue !== dataPasswordVisible.value) {
|
|
167
|
+
togglePasswordVisibility();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
watch(
|
|
172
|
+
() => props.type,
|
|
173
|
+
newValue => {
|
|
174
|
+
dataType.value = newValue;
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// Methods
|
|
179
|
+
function togglePasswordVisibility() {
|
|
180
|
+
const currentValue = input.value.value;
|
|
181
|
+
dataPasswordVisible.value = !dataPasswordVisible.value;
|
|
182
|
+
dataType.value = dataPasswordVisible.value ? 'text' : 'password';
|
|
183
|
+
nextTick(() => {
|
|
184
|
+
input.value.value = currentValue;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function checkSlots() {
|
|
189
|
+
// NOTE: slots is not reactive so needs to be managed on updated
|
|
190
|
+
isInvalid.value = !!(
|
|
191
|
+
props.invalidMessage?.length || slots['invalid-message']
|
|
192
|
+
);
|
|
193
|
+
isWarn.value =
|
|
194
|
+
!isInvalid.value && !!(props.warnText?.length || slots['warn-text']);
|
|
195
|
+
isHelper.value =
|
|
196
|
+
!isInvalid.value &&
|
|
197
|
+
!isWarn.value &&
|
|
198
|
+
!!(props.helperText?.length || slots['helper-text']);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Lifecycle Hooks
|
|
202
|
+
onBeforeMount(() => {
|
|
203
|
+
checkSlots();
|
|
204
|
+
// update initial state for dataPasswordVisible & dataType
|
|
205
|
+
if (isPassword.value && props.passwordVisible) {
|
|
206
|
+
dataPasswordVisible.value = true;
|
|
207
|
+
dataType.value = 'text';
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
onBeforeUpdate(checkSlots);
|
|
211
|
+
</script>
|
|
212
|
+
|
|
213
|
+
<script>
|
|
214
|
+
export default {
|
|
215
|
+
inheritAttrs: false,
|
|
216
|
+
};
|
|
217
|
+
</script>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Canvas, Meta, Story } from '@storybook/addon-docs';
|
|
2
|
+
import CvTile from './CvTile.vue';
|
|
3
|
+
import CvTileStandard from './CvTileStandard.vue';
|
|
4
|
+
import CvTileClickable from './CvTileClickable.vue';
|
|
5
|
+
import { sbCompPrefix } from '../../global/storybook-utils';
|
|
6
|
+
import { action } from '@storybook/addon-actions';
|
|
7
|
+
|
|
8
|
+
<Meta title={`${sbCompPrefix}/CvTile`} component={CvTile} />
|
|
9
|
+
|
|
10
|
+
export const Template = args => ({
|
|
11
|
+
// Components used in your story `template` are defined in the `components` object
|
|
12
|
+
components: {
|
|
13
|
+
CvTile,
|
|
14
|
+
CvTileStandard,
|
|
15
|
+
CvTileClickable,
|
|
16
|
+
},
|
|
17
|
+
// The story's `args` need to be mapped into the template through the `setup()` method
|
|
18
|
+
setup() {
|
|
19
|
+
return {
|
|
20
|
+
args: {
|
|
21
|
+
light: args.light,
|
|
22
|
+
kind: args.kind,
|
|
23
|
+
disabled: args.disabled,
|
|
24
|
+
expanded: args.expanded,
|
|
25
|
+
tileCollapsedLabel: args.tileCollapsedLabel,
|
|
26
|
+
tileExpandedLabel: args.tileExpandedLabel,
|
|
27
|
+
},
|
|
28
|
+
onChange: action('change'),
|
|
29
|
+
onExpanded: action('expanded'),
|
|
30
|
+
onClick: action('click'),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
// And then the `args` are bound to your component with `v-bind="args"`
|
|
34
|
+
template: args.template,
|
|
35
|
+
});
|
|
36
|
+
const defaultTemplate = `<cv-tile v-bind='args'>Hello!</cv-tile>`;
|
|
37
|
+
const defaultCode = defaultTemplate.replace("v-bind='args'", '');
|
|
38
|
+
const expandableTemplate = `<cv-tile v-bind='args' kind="expandable" @expanded="onExpanded">Hello expandable!<template #below><h1>More Content</h1><p>Expanded</p></template></cv-tile>`;
|
|
39
|
+
const expandableCode = expandableTemplate.replace("v-bind='args'", '');
|
|
40
|
+
const clickableTemplate = `<cv-tile v-bind='args' kind="clickable" @click="onClick" to="{name: 'something'}">Hello clickable!</cv-tile>`;
|
|
41
|
+
const clickableCode = clickableTemplate.replace("v-bind='args'", '');
|
|
42
|
+
const selectableTemplate = `<cv-tile v-bind='args' kind="selectable" value="my-selection" @change="onChange">Hello selectable! </cv-tile>`;
|
|
43
|
+
const selectableCode = selectableTemplate.replace("v-bind='args'", '');
|
|
44
|
+
|
|
45
|
+
# CvTile
|
|
46
|
+
|
|
47
|
+
**Migration notes:**
|
|
48
|
+
|
|
49
|
+
- The `light` and '`theme` options continue to be supported but the boolean `light` is preferred.
|
|
50
|
+
- The expandable tile now emits a `expanded` event with a Boolean value.
|
|
51
|
+
|
|
52
|
+
<Canvas>
|
|
53
|
+
<Story
|
|
54
|
+
name="Default"
|
|
55
|
+
parameters={{
|
|
56
|
+
controls: {
|
|
57
|
+
exclude: [
|
|
58
|
+
'default',
|
|
59
|
+
'selected',
|
|
60
|
+
'template',
|
|
61
|
+
'data',
|
|
62
|
+
'kind',
|
|
63
|
+
'expanded',
|
|
64
|
+
'tileExpandedLabel',
|
|
65
|
+
'tileCollapsedLabel',
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
docs: { source: { code: defaultCode } },
|
|
69
|
+
}}
|
|
70
|
+
args={{
|
|
71
|
+
kind: '',
|
|
72
|
+
light: false,
|
|
73
|
+
disabled: false,
|
|
74
|
+
template: defaultTemplate,
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
{Template.bind({})}
|
|
78
|
+
</Story>
|
|
79
|
+
</Canvas>
|
|
80
|
+
|
|
81
|
+
<Canvas>
|
|
82
|
+
<Story
|
|
83
|
+
name="Expandable"
|
|
84
|
+
parameters={{
|
|
85
|
+
controls: {
|
|
86
|
+
exclude: ['default', 'selected', 'template', 'data', 'kind', 'slots'],
|
|
87
|
+
},
|
|
88
|
+
docs: { source: { code: expandableCode } },
|
|
89
|
+
}}
|
|
90
|
+
args={{
|
|
91
|
+
light: false,
|
|
92
|
+
disabled: false,
|
|
93
|
+
template: expandableTemplate,
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
{Template.bind({})}
|
|
97
|
+
</Story>
|
|
98
|
+
</Canvas>
|
|
99
|
+
|
|
100
|
+
<Canvas>
|
|
101
|
+
<Story
|
|
102
|
+
name="Clickable"
|
|
103
|
+
parameters={{
|
|
104
|
+
controls: {
|
|
105
|
+
exclude: [
|
|
106
|
+
'default',
|
|
107
|
+
'selected',
|
|
108
|
+
'template',
|
|
109
|
+
'data',
|
|
110
|
+
'kind',
|
|
111
|
+
'slots',
|
|
112
|
+
'expanded',
|
|
113
|
+
'tileExpandedLabel',
|
|
114
|
+
'tileCollapsedLabel',
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
docs: { source: { code: clickableCode } },
|
|
118
|
+
}}
|
|
119
|
+
args={{
|
|
120
|
+
light: false,
|
|
121
|
+
disabled: false,
|
|
122
|
+
template: clickableTemplate,
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
{Template.bind({})}
|
|
126
|
+
</Story>
|
|
127
|
+
</Canvas>
|
|
128
|
+
|
|
129
|
+
<Canvas>
|
|
130
|
+
<Story
|
|
131
|
+
name="Selectable"
|
|
132
|
+
parameters={{
|
|
133
|
+
controls: {
|
|
134
|
+
exclude: [
|
|
135
|
+
'default',
|
|
136
|
+
'selected',
|
|
137
|
+
'template',
|
|
138
|
+
'data',
|
|
139
|
+
'kind',
|
|
140
|
+
'slots',
|
|
141
|
+
'expanded',
|
|
142
|
+
'tileExpandedLabel',
|
|
143
|
+
'tileCollapsedLabel',
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
docs: { source: { code: selectableCode } },
|
|
147
|
+
}}
|
|
148
|
+
args={{
|
|
149
|
+
light: false,
|
|
150
|
+
disabled: false,
|
|
151
|
+
template: selectableTemplate,
|
|
152
|
+
}}
|
|
153
|
+
>
|
|
154
|
+
{Template.bind({})}
|
|
155
|
+
</Story>
|
|
156
|
+
</Canvas>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="tagType"
|
|
4
|
+
:checked="checkProp('checked', selected)"
|
|
5
|
+
:expanded="checkProp('expanded', expanded)"
|
|
6
|
+
:tileCollapsedLabel="checkProp('tileCollapsedLabel', tileCollapsedLabel)"
|
|
7
|
+
:tileExpandedLabel="checkProp('tileCollapsedLabel', tileExpandedLabel)"
|
|
8
|
+
:class="[
|
|
9
|
+
`cv-tile ${carbonPrefix}--tile`,
|
|
10
|
+
{ [`${carbonPrefix}--tile--light`]: isLight },
|
|
11
|
+
]"
|
|
12
|
+
>
|
|
13
|
+
<template v-for="(_, name) in $slots" v-slot:[name]="slotData"
|
|
14
|
+
><slot :name="name" v-bind="slotData"
|
|
15
|
+
/></template>
|
|
16
|
+
</component>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
import { computed } from 'vue';
|
|
21
|
+
import { carbonPrefix } from '../../global/settings';
|
|
22
|
+
import { props as propsTheme, useIsLight } from '../../use/cvTheme';
|
|
23
|
+
import CvTileStandard from './CvTileStandard.vue';
|
|
24
|
+
import CvTileClickable from './CvTileClickable.vue';
|
|
25
|
+
import CvTileSelectable from './CvTileSelectable.vue';
|
|
26
|
+
import CvTileExpandable from './CvTileExpandable.vue';
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
expanded: Boolean,
|
|
30
|
+
selected: Boolean,
|
|
31
|
+
tileCollapsedLabel: { type: String, default: 'Tile collapsed' },
|
|
32
|
+
tileExpandedLabel: { type: String, default: 'Tile expanded' },
|
|
33
|
+
kind: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: '',
|
|
36
|
+
validator: value =>
|
|
37
|
+
['clickable', 'expandable', 'selectable', 'standard', ''].includes(value),
|
|
38
|
+
},
|
|
39
|
+
...propsTheme,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const tagType = computed(() => {
|
|
43
|
+
switch (props.kind) {
|
|
44
|
+
case 'clickable':
|
|
45
|
+
return CvTileClickable;
|
|
46
|
+
case 'selectable':
|
|
47
|
+
return CvTileSelectable;
|
|
48
|
+
case 'expandable':
|
|
49
|
+
return CvTileExpandable;
|
|
50
|
+
default:
|
|
51
|
+
return CvTileStandard;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const isLight = useIsLight(props);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* If the prop is defined on the tagType pass it along otherwise, discard it.
|
|
58
|
+
* @param {string} prop
|
|
59
|
+
* @param {any} value
|
|
60
|
+
* @returns {*|undefined}
|
|
61
|
+
*/
|
|
62
|
+
function checkProp(prop, value) {
|
|
63
|
+
return prop in (tagType.value.props || {}) ? value : undefined;
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<style scoped></style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="tagType"
|
|
4
|
+
ref="target"
|
|
5
|
+
data-tile="clickable"
|
|
6
|
+
:class="`cv-tile-clickable ${carbonPrefix}--tile--clickable`"
|
|
7
|
+
v-bind="{ ...$attrs, ...linkProps }"
|
|
8
|
+
tabindex="0"
|
|
9
|
+
>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</component>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup>
|
|
15
|
+
import { carbonPrefix } from '../../global/settings';
|
|
16
|
+
import { props as propsLink, useLinkProps, useTagType } from '../../use/cvLink';
|
|
17
|
+
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
...propsLink,
|
|
20
|
+
});
|
|
21
|
+
const tagType = useTagType(props);
|
|
22
|
+
const linkProps = useLinkProps(props);
|
|
23
|
+
</script>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
type="button"
|
|
4
|
+
:style="data.styleObject"
|
|
5
|
+
@click="toggle"
|
|
6
|
+
:class="[
|
|
7
|
+
`cv-tile-expandable ${carbonPrefix}--tile--expandable`,
|
|
8
|
+
{ [`${carbonPrefix}--tile--is-expanded`]: data.internalExpanded },
|
|
9
|
+
]"
|
|
10
|
+
ref="el"
|
|
11
|
+
>
|
|
12
|
+
<div :class="`${carbonPrefix}--tile-content`">
|
|
13
|
+
<span
|
|
14
|
+
data-tile-atf
|
|
15
|
+
:class="`${carbonPrefix}--tile-content__above-the-fold`"
|
|
16
|
+
ref="aboveFold"
|
|
17
|
+
>
|
|
18
|
+
<slot>
|
|
19
|
+
<!-- Above the fold content here -->
|
|
20
|
+
</slot>
|
|
21
|
+
</span>
|
|
22
|
+
<div :class="`${carbonPrefix}--tile__chevron`">
|
|
23
|
+
<span>{{ chevronLabel }}</span>
|
|
24
|
+
<ChevronDown16 />
|
|
25
|
+
</div>
|
|
26
|
+
<span
|
|
27
|
+
:class="`${carbonPrefix}--tile-content__below-the-fold`"
|
|
28
|
+
ref="belowFold"
|
|
29
|
+
v-show="data.internalExpanded || data.initialized"
|
|
30
|
+
>
|
|
31
|
+
<slot name="below">
|
|
32
|
+
<!-- Rest of the content here -->
|
|
33
|
+
</slot>
|
|
34
|
+
</span>
|
|
35
|
+
</div>
|
|
36
|
+
</button>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup>
|
|
40
|
+
import { carbonPrefix } from '../../global/settings';
|
|
41
|
+
import ChevronDown16 from '@carbon/icons-vue/es/chevron--down/16';
|
|
42
|
+
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
|
43
|
+
|
|
44
|
+
const props = defineProps({
|
|
45
|
+
expanded: Boolean,
|
|
46
|
+
tileCollapsedLabel: String,
|
|
47
|
+
tileExpandedLabel: String,
|
|
48
|
+
});
|
|
49
|
+
const data = reactive({
|
|
50
|
+
styleObject: {
|
|
51
|
+
maxHeight: 'initial',
|
|
52
|
+
},
|
|
53
|
+
initialized: false,
|
|
54
|
+
internalExpanded: props.expanded,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
watch(
|
|
58
|
+
() => props.expanded,
|
|
59
|
+
val => {
|
|
60
|
+
if (val !== data.internalExpanded) {
|
|
61
|
+
toggle(val);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const chevronLabel = computed(() => {
|
|
67
|
+
return data.internalExpanded
|
|
68
|
+
? props.tileExpandedLabel
|
|
69
|
+
: props.tileCollapsedLabel;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const el = ref(null);
|
|
73
|
+
const belowFold = ref(null);
|
|
74
|
+
function toggle(force) {
|
|
75
|
+
let currentHeight = el?.value.getBoundingClientRect().height;
|
|
76
|
+
if (!data.initialized) {
|
|
77
|
+
data.styleObject.maxHeight = `${currentHeight}px`;
|
|
78
|
+
data.initialized = true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
nextTick(() => {
|
|
82
|
+
const forceType = typeof force;
|
|
83
|
+
data.internalExpanded =
|
|
84
|
+
forceType === 'boolean' ? force : !data.internalExpanded;
|
|
85
|
+
|
|
86
|
+
const belowFoldHeight = belowFold?.value.getBoundingClientRect().height;
|
|
87
|
+
|
|
88
|
+
if (data.internalExpanded) {
|
|
89
|
+
currentHeight += belowFoldHeight;
|
|
90
|
+
} else {
|
|
91
|
+
currentHeight -= belowFoldHeight;
|
|
92
|
+
}
|
|
93
|
+
data.styleObject.maxHeight = `${currentHeight}px`;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const emit = defineEmits(['expanded']);
|
|
97
|
+
watch(
|
|
98
|
+
() => data.internalExpanded,
|
|
99
|
+
val => {
|
|
100
|
+
emit('expanded', val);
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
</script>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label
|
|
3
|
+
:for="uid"
|
|
4
|
+
:aria-label="ariaLabel"
|
|
5
|
+
:class="[
|
|
6
|
+
`cv-tile-selectable ${carbonPrefix}--tile--selectable`,
|
|
7
|
+
{ [`${carbonPrefix}--tile--is-selected`]: isChecked },
|
|
8
|
+
]"
|
|
9
|
+
data-tile="selectable"
|
|
10
|
+
tabindex="0"
|
|
11
|
+
:data-contained-checkbox-state="isChecked"
|
|
12
|
+
>
|
|
13
|
+
<input
|
|
14
|
+
tabindex="-1"
|
|
15
|
+
data-tile-input
|
|
16
|
+
:id="uid"
|
|
17
|
+
type="checkbox"
|
|
18
|
+
:checked="isChecked === true"
|
|
19
|
+
:aria-checked="`${isChecked}`"
|
|
20
|
+
:class="`${carbonPrefix}--tile-input`"
|
|
21
|
+
v-bind="$attrs"
|
|
22
|
+
@change="onChange"
|
|
23
|
+
/>
|
|
24
|
+
<div :class="`${carbonPrefix}--tile__checkmark`">
|
|
25
|
+
<CheckmarkFilled16 />
|
|
26
|
+
</div>
|
|
27
|
+
<div :class="`${carbonPrefix}--tile-content`">
|
|
28
|
+
<slot>
|
|
29
|
+
<!-- Tile content here -->
|
|
30
|
+
</slot>
|
|
31
|
+
</div>
|
|
32
|
+
</label>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import { carbonPrefix } from '../../global/settings';
|
|
37
|
+
import { props as propsCvCheck, useCheck } from '../../use/cvCheck';
|
|
38
|
+
import { props as propsCvId, useCvId } from '../../use/cvId';
|
|
39
|
+
import CheckmarkFilled16 from '@carbon/icons-vue/es/checkmark--filled/16';
|
|
40
|
+
import { toRefs } from 'vue';
|
|
41
|
+
|
|
42
|
+
const props = defineProps({
|
|
43
|
+
ariaLabel: { type: String, default: 'tile' },
|
|
44
|
+
...propsCvCheck,
|
|
45
|
+
...propsCvId,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const uid = useCvId(props, true);
|
|
49
|
+
|
|
50
|
+
const emit = defineEmits(['update:modelValue', 'change']);
|
|
51
|
+
const { onChange, isChecked } = useCheck(toRefs(props), emit);
|
|
52
|
+
</script>
|