@carbon/vue 3.0.30 → 3.0.32
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 +153 -60
- package/dist/carbon-vue-3.common.js.map +1 -1
- package/dist/carbon-vue-3.umd.js +153 -60
- 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/dist/web-types.json +31 -1
- package/package.json +1 -1
- package/src/components/CvContentSwitcher/CvContentSwitcher.stories.mdx +2 -2
- package/src/components/CvContentSwitcher/CvContentSwitcher.vue +17 -3
- package/src/components/CvDropdown/CvDropdown.vue +1 -0
- package/src/components/CvModal/CvModal.vue +9 -1
- package/src/components/CvPagination/CvPagination.stories.mdx +127 -14
- package/src/components/CvPagination/CvPagination.vue +79 -32
- package/src/components/CvUIShell/CvSideNav.vue +5 -2
package/dist/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"framework": "vue",
|
|
3
3
|
"name": "@carbon/vue",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.31",
|
|
5
5
|
"contributions": {
|
|
6
6
|
"html": {
|
|
7
7
|
"description-markup": "markdown",
|
|
@@ -3503,6 +3503,14 @@
|
|
|
3503
3503
|
},
|
|
3504
3504
|
"default": "undefined"
|
|
3505
3505
|
},
|
|
3506
|
+
{
|
|
3507
|
+
"name": "pageSize",
|
|
3508
|
+
"value": {
|
|
3509
|
+
"kind": "expression",
|
|
3510
|
+
"type": "number"
|
|
3511
|
+
},
|
|
3512
|
+
"default": "undefined"
|
|
3513
|
+
},
|
|
3506
3514
|
{
|
|
3507
3515
|
"name": "pageSizes",
|
|
3508
3516
|
"value": {
|
|
@@ -3510,11 +3518,33 @@
|
|
|
3510
3518
|
"type": "array"
|
|
3511
3519
|
},
|
|
3512
3520
|
"default": "[10, 20, 30, 40, 50]"
|
|
3521
|
+
},
|
|
3522
|
+
{
|
|
3523
|
+
"name": "rangeTextFormatter",
|
|
3524
|
+
"value": {
|
|
3525
|
+
"kind": "expression",
|
|
3526
|
+
"type": "func"
|
|
3527
|
+
},
|
|
3528
|
+
"default": "undefined"
|
|
3529
|
+
},
|
|
3530
|
+
{
|
|
3531
|
+
"name": "pageOfPagesFormatter",
|
|
3532
|
+
"value": {
|
|
3533
|
+
"kind": "expression",
|
|
3534
|
+
"type": "func"
|
|
3535
|
+
},
|
|
3536
|
+
"default": "undefined"
|
|
3513
3537
|
}
|
|
3514
3538
|
],
|
|
3515
3539
|
"events": [
|
|
3516
3540
|
{
|
|
3517
3541
|
"name": "change"
|
|
3542
|
+
},
|
|
3543
|
+
{
|
|
3544
|
+
"name": "update:page"
|
|
3545
|
+
},
|
|
3546
|
+
{
|
|
3547
|
+
"name": "update:pageSize"
|
|
3518
3548
|
}
|
|
3519
3549
|
],
|
|
3520
3550
|
"slots": [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carbon/vue",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.32",
|
|
5
5
|
"description": "A collection of components for the Carbon Design System built using Vue.js",
|
|
6
6
|
"packageManager": "yarn@3.2.0",
|
|
7
7
|
"main": "dist/carbon-vue-3.umd.min.js",
|
|
@@ -77,7 +77,7 @@ const domTemplate = `
|
|
|
77
77
|
const domCode = domTemplate.replace("v-bind='args'", '');
|
|
78
78
|
const multipleTemplate = `
|
|
79
79
|
<div>
|
|
80
|
-
<cv-content-switcher aria-label='Choose content' v-bind='args' @selected="onSelected" id="star-wars">
|
|
80
|
+
<cv-content-switcher tabindex="0" aria-label='Choose content' v-bind='args' @selected="onSelected" id="star-wars">
|
|
81
81
|
<cv-content-switcher-button parent-switcher="star-wars" owner-id="episode-1" :selected="selectedIndex === 0">Episode 1</cv-content-switcher-button>
|
|
82
82
|
<cv-content-switcher-button parent-switcher="star-wars" owner-id="episode-2" :selected="selectedIndex === 1">Episode 2</cv-content-switcher-button>
|
|
83
83
|
<cv-content-switcher-button parent-switcher="star-wars" :icon="iconSample" owner-id="episode-3" :selected="selectedIndex === 2">Episode 3</cv-content-switcher-button>
|
|
@@ -96,7 +96,7 @@ const multipleTemplate = `
|
|
|
96
96
|
<p>Yoda</p>
|
|
97
97
|
</cv-content-switcher-content>
|
|
98
98
|
</section>
|
|
99
|
-
<cv-content-switcher aria-label='Choose content' v-bind='args' @selected="onSelected" id="LotR">
|
|
99
|
+
<cv-content-switcher tabindex="1" aria-label='Choose content' v-bind='args' @selected="onSelected" id="LotR">
|
|
100
100
|
<cv-content-switcher-button parent-switcher="LotR" owner-id="book-1" :selected="selectedIndex === 0">Book 1</cv-content-switcher-button>
|
|
101
101
|
<cv-content-switcher-button parent-switcher="LotR" owner-id="book-2" :selected="selectedIndex === 1">Book 2</cv-content-switcher-button>
|
|
102
102
|
<cv-content-switcher-button parent-switcher="LotR" :icon="iconSample" owner-id="book-3" :selected="selectedIndex === 2">Book 3</cv-content-switcher-button>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { carbonPrefix } from '../../global/settings';
|
|
19
19
|
import { props as propsCvId, useCvId } from '../../use/cvId';
|
|
20
20
|
import { useIsLight, props as propsTheme } from '../../use/cvTheme';
|
|
21
|
-
import { onUnmounted, watch } from 'vue';
|
|
21
|
+
import { onUnmounted, watch, onMounted, nextTick } from 'vue';
|
|
22
22
|
import store from './cvContentSwitcherStore';
|
|
23
23
|
|
|
24
24
|
const emit = defineEmits(['selected']);
|
|
@@ -36,14 +36,26 @@ const cvId = useCvId(props, true);
|
|
|
36
36
|
const isLight = useIsLight(props);
|
|
37
37
|
store.addParent(cvId.value);
|
|
38
38
|
store.setContentSelected('global', undefined);
|
|
39
|
+
|
|
40
|
+
// Check for initial selection after child components have set up
|
|
41
|
+
let hadInitialSelection = null;
|
|
42
|
+
onMounted(async () => {
|
|
43
|
+
// Use nextTick to ensure child components have mounted and set their initial state
|
|
44
|
+
await nextTick();
|
|
45
|
+
hadInitialSelection =
|
|
46
|
+
store.state[cvId.value]?.selected !== undefined &&
|
|
47
|
+
store.state[cvId.value]?.selected !== '';
|
|
48
|
+
});
|
|
49
|
+
|
|
39
50
|
onUnmounted(() => {
|
|
40
51
|
store.removeParent(cvId.value);
|
|
41
52
|
});
|
|
53
|
+
|
|
42
54
|
watch(
|
|
43
55
|
() => store.state.global.latest,
|
|
44
56
|
(val, prev) => {
|
|
45
57
|
// if previous is not set, do not emit. This mimics the current v2 behaviour where the initial content does not generate an event
|
|
46
|
-
if (prev) emit('selected', val);
|
|
58
|
+
if (prev || (val && hadInitialSelection === false)) emit('selected', val);
|
|
47
59
|
}
|
|
48
60
|
);
|
|
49
61
|
|
|
@@ -53,7 +65,9 @@ watch(
|
|
|
53
65
|
val => {
|
|
54
66
|
if (ourLatest !== val?.latest) {
|
|
55
67
|
// if ourLatest is not set, do not emit. This mimics the current v2 behaviour where the initial content does not generate an event
|
|
56
|
-
if (
|
|
68
|
+
// However, if there was no initial selection (selectedIndex=-1), we should emit on first click
|
|
69
|
+
if (ourLatest || (val?.latest && hadInitialSelection === false))
|
|
70
|
+
emit('selected', val?.latest);
|
|
57
71
|
ourLatest = val?.latest;
|
|
58
72
|
}
|
|
59
73
|
},
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
tabindex="-1"
|
|
15
15
|
v-bind="$attrs"
|
|
16
16
|
@keydown.esc.prevent="onEsc"
|
|
17
|
+
@mousedown.self="onMouseDown"
|
|
17
18
|
@click.self="onExternalClick"
|
|
18
19
|
>
|
|
19
20
|
<div
|
|
@@ -145,6 +146,8 @@ import {
|
|
|
145
146
|
watch,
|
|
146
147
|
} from 'vue';
|
|
147
148
|
|
|
149
|
+
const mouseDownTarget = ref(null);
|
|
150
|
+
|
|
148
151
|
const props = defineProps({
|
|
149
152
|
/**
|
|
150
153
|
* When set to true, the aria role will be either "alert" or "alertdialog"
|
|
@@ -269,6 +272,7 @@ function show() {
|
|
|
269
272
|
|
|
270
273
|
el.value?.addEventListener('transitionend', onShown);
|
|
271
274
|
dataVisible.value = true;
|
|
275
|
+
mouseDownTarget.value = null;
|
|
272
276
|
}
|
|
273
277
|
const content = ref(null);
|
|
274
278
|
function onShown() {
|
|
@@ -326,6 +330,7 @@ function hide() {
|
|
|
326
330
|
}
|
|
327
331
|
|
|
328
332
|
dataVisible.value = false;
|
|
333
|
+
mouseDownTarget.value = null;
|
|
329
334
|
}
|
|
330
335
|
function afterHide(event) {
|
|
331
336
|
if (event.propertyName === 'opacity') {
|
|
@@ -375,10 +380,13 @@ function focusAfterContent() {
|
|
|
375
380
|
}
|
|
376
381
|
|
|
377
382
|
function onExternalClick(ev) {
|
|
378
|
-
if (ev.target === el.value) {
|
|
383
|
+
if (ev.target === el.value && mouseDownTarget.value === el.value) {
|
|
379
384
|
_maybeHide(ev, 'external-click');
|
|
380
385
|
}
|
|
381
386
|
}
|
|
387
|
+
function onMouseDown(ev) {
|
|
388
|
+
mouseDownTarget.value = ev.target;
|
|
389
|
+
}
|
|
382
390
|
function onEsc(ev) {
|
|
383
391
|
_maybeHide(ev, 'escape-press');
|
|
384
392
|
}
|
|
@@ -3,9 +3,29 @@ import { CvPagination } from '.';
|
|
|
3
3
|
import { sbCompPrefix } from '../../global/storybook-utils';
|
|
4
4
|
import { action } from '@storybook/addon-actions';
|
|
5
5
|
import { ref } from 'vue';
|
|
6
|
-
const myPage=ref(1);
|
|
7
|
-
const myPageSizes=ref([5,7,10,11,13])
|
|
8
|
-
const myNumItems=ref(13)
|
|
6
|
+
const myPage = ref(1);
|
|
7
|
+
const myPageSizes = ref([5, 7, 10, 11, 13]);
|
|
8
|
+
const myNumItems = ref(13);
|
|
9
|
+
const controlledPage = ref(1);
|
|
10
|
+
const controlledPageSize = ref(10);
|
|
11
|
+
const maxAllowedPage = ref(3);
|
|
12
|
+
const onUpdatePageAction = action('update:page');
|
|
13
|
+
const onUpdatePageSizeAction = action('update:page-size');
|
|
14
|
+
function onUpdatePage(page) {
|
|
15
|
+
onUpdatePageAction(page);
|
|
16
|
+
// simulate a parent that constrains the page: requests past
|
|
17
|
+
// maxAllowedPage are declined by simply not assigning them back.
|
|
18
|
+
if (page <= maxAllowedPage.value) {
|
|
19
|
+
controlledPage.value = page;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function onUpdatePageSize(pageSize) {
|
|
23
|
+
onUpdatePageSizeAction(pageSize);
|
|
24
|
+
controlledPageSize.value = pageSize;
|
|
25
|
+
}
|
|
26
|
+
const spanishRangeTextFormatter = ({ start, end, items }) =>
|
|
27
|
+
`Del ${start} al ${end} de ${items}`;
|
|
28
|
+
const germanPageOfPagesFormatter = ({ pages }) => `von ${pages} Seiten`;
|
|
9
29
|
|
|
10
30
|
<Meta title={`${sbCompPrefix}/CvPagination`} component={CvPagination} />
|
|
11
31
|
|
|
@@ -21,6 +41,13 @@ export const Template = args => ({
|
|
|
21
41
|
myPage,
|
|
22
42
|
myPageSizes,
|
|
23
43
|
myNumItems,
|
|
44
|
+
controlledPage,
|
|
45
|
+
controlledPageSize,
|
|
46
|
+
maxAllowedPage,
|
|
47
|
+
onUpdatePage,
|
|
48
|
+
onUpdatePageSize,
|
|
49
|
+
spanishRangeTextFormatter,
|
|
50
|
+
germanPageOfPagesFormatter,
|
|
24
51
|
onChange: action('change'),
|
|
25
52
|
};
|
|
26
53
|
},
|
|
@@ -75,10 +102,42 @@ const slotsTemplate = `
|
|
|
75
102
|
</template>
|
|
76
103
|
</cv-pagination>
|
|
77
104
|
`;
|
|
105
|
+
const controlledTemplate = `
|
|
106
|
+
<cv-pagination
|
|
107
|
+
@change="onChange"
|
|
108
|
+
v-model:page="controlledPage"
|
|
109
|
+
v-model:page-size="controlledPageSize"
|
|
110
|
+
@update:page="onUpdatePage"
|
|
111
|
+
@update:page-size="onUpdatePageSize"
|
|
112
|
+
:number-of-items="103">
|
|
113
|
+
</cv-pagination>
|
|
114
|
+
<div style="margin-top:2rem; background-color: #888888; padding:1rem">
|
|
115
|
+
<h3>Parent-owned state</h3>
|
|
116
|
+
<p>page: {{controlledPage}}, page size: {{controlledPageSize}}</p>
|
|
117
|
+
<p>
|
|
118
|
+
Requests for a page beyond max-allowed-page are declined by this
|
|
119
|
+
story (the parent simply doesn't assign the requested page back) -
|
|
120
|
+
the displayed page stays put instead of drifting or getting stuck.
|
|
121
|
+
</p>
|
|
122
|
+
max allowed page:
|
|
123
|
+
<button @click="maxAllowedPage--">-</button>
|
|
124
|
+
{{maxAllowedPage}}
|
|
125
|
+
<button @click="maxAllowedPage++">+</button>
|
|
126
|
+
</div>
|
|
127
|
+
`;
|
|
128
|
+
const formattersTemplate = `
|
|
129
|
+
<cv-pagination
|
|
130
|
+
@change="onChange"
|
|
131
|
+
:number-of-items="103"
|
|
132
|
+
:range-text-formatter="spanishRangeTextFormatter"
|
|
133
|
+
:page-of-pages-formatter="germanPageOfPagesFormatter">
|
|
134
|
+
</cv-pagination>
|
|
135
|
+
`;
|
|
78
136
|
|
|
79
137
|
# CvPagination
|
|
80
138
|
|
|
81
139
|
Migration notes:
|
|
140
|
+
|
|
82
141
|
- If you specify `pageNumberLabel` a trailing colon (:) is no longer automatically appended to the text
|
|
83
142
|
|
|
84
143
|
<Canvas>
|
|
@@ -111,14 +170,13 @@ Migration notes:
|
|
|
111
170
|
argTypes={{
|
|
112
171
|
page: { control: false },
|
|
113
172
|
pageSizes: { control: false },
|
|
114
|
-
numberOfItems: { control: false }
|
|
173
|
+
numberOfItems: { control: false },
|
|
115
174
|
}}
|
|
116
175
|
>
|
|
117
176
|
{Template.bind({})}
|
|
118
177
|
</Story>
|
|
119
178
|
</Canvas>
|
|
120
179
|
|
|
121
|
-
|
|
122
180
|
Use slots to set the range text and "of n pages" text. A good use case for this is internationalization.
|
|
123
181
|
|
|
124
182
|
<Canvas>
|
|
@@ -126,13 +184,7 @@ Use slots to set the range text and "of n pages" text. A good use case for this
|
|
|
126
184
|
name="Slots"
|
|
127
185
|
parameters={{
|
|
128
186
|
controls: {
|
|
129
|
-
exclude: [
|
|
130
|
-
'default',
|
|
131
|
-
'template',
|
|
132
|
-
'data',
|
|
133
|
-
'change',
|
|
134
|
-
'of-n-pages',
|
|
135
|
-
],
|
|
187
|
+
exclude: ['default', 'template', 'data', 'change', 'of-n-pages'],
|
|
136
188
|
},
|
|
137
189
|
docs: { source: { code: slotsTemplate } },
|
|
138
190
|
}}
|
|
@@ -158,10 +210,71 @@ Use slots to set the range text and "of n pages" text. A good use case for this
|
|
|
158
210
|
backwardsButtonDisabled: false,
|
|
159
211
|
forwardsButtonDisabled: false,
|
|
160
212
|
actualItemsOnPage: Infinity,
|
|
161
|
-
locale: 'en'
|
|
213
|
+
locale: 'en',
|
|
162
214
|
}}
|
|
163
|
-
argTypes={{
|
|
215
|
+
argTypes={{}}
|
|
216
|
+
>
|
|
217
|
+
{Template.bind({})}
|
|
218
|
+
</Story>
|
|
219
|
+
</Canvas>
|
|
220
|
+
|
|
221
|
+
Bind `v-model:page` and/or `v-model:page-size` to opt in to controlled mode:
|
|
222
|
+
the component no longer moves on its own, it emits `update:page` /
|
|
223
|
+
`update:page-size` and only shows the new value once the parent assigns it
|
|
224
|
+
back through the prop. This lets a parent veto a page change - useful when
|
|
225
|
+
loading the next page's data can fail, or is gated behind other state.
|
|
226
|
+
|
|
227
|
+
<Canvas>
|
|
228
|
+
<Story
|
|
229
|
+
name="Controlled"
|
|
230
|
+
parameters={{
|
|
231
|
+
controls: {
|
|
232
|
+
exclude: [
|
|
233
|
+
'default',
|
|
234
|
+
'template',
|
|
235
|
+
'data',
|
|
236
|
+
'range-text',
|
|
237
|
+
'change',
|
|
238
|
+
'of-n-pages',
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
docs: { source: { code: controlledTemplate } },
|
|
242
|
+
}}
|
|
243
|
+
args={{
|
|
244
|
+
data: {},
|
|
245
|
+
template: controlledTemplate,
|
|
246
|
+
}}
|
|
247
|
+
argTypes={{}}
|
|
248
|
+
>
|
|
249
|
+
{Template.bind({})}
|
|
250
|
+
</Story>
|
|
251
|
+
</Canvas>
|
|
252
|
+
|
|
253
|
+
Use `rangeTextFormatter` and `pageOfPagesFormatter` to translate the range
|
|
254
|
+
and page-count text without reimplementing the `range-text` / `of-n-pages`
|
|
255
|
+
slots.
|
|
256
|
+
|
|
257
|
+
<Canvas>
|
|
258
|
+
<Story
|
|
259
|
+
name="Formatters"
|
|
260
|
+
parameters={{
|
|
261
|
+
controls: {
|
|
262
|
+
exclude: [
|
|
263
|
+
'default',
|
|
264
|
+
'template',
|
|
265
|
+
'data',
|
|
266
|
+
'range-text',
|
|
267
|
+
'change',
|
|
268
|
+
'of-n-pages',
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
docs: { source: { code: formattersTemplate } },
|
|
272
|
+
}}
|
|
273
|
+
args={{
|
|
274
|
+
data: {},
|
|
275
|
+
template: formattersTemplate,
|
|
164
276
|
}}
|
|
277
|
+
argTypes={{}}
|
|
165
278
|
>
|
|
166
279
|
{Template.bind({})}
|
|
167
280
|
</Story>
|
|
@@ -84,13 +84,20 @@
|
|
|
84
84
|
|
|
85
85
|
<script setup>
|
|
86
86
|
import { carbonPrefix } from '../../global/settings';
|
|
87
|
-
import {
|
|
87
|
+
import {
|
|
88
|
+
computed,
|
|
89
|
+
getCurrentInstance,
|
|
90
|
+
onMounted,
|
|
91
|
+
ref,
|
|
92
|
+
useAttrs,
|
|
93
|
+
watch,
|
|
94
|
+
} from 'vue';
|
|
88
95
|
import { CaretLeft16, CaretRight16 } from '@carbon/icons-vue';
|
|
89
96
|
import CvSelect from '../CvSelect';
|
|
90
97
|
import CvSelectOption from '../CvSelect/CvSelectOption.vue';
|
|
91
98
|
import { useCvId } from '../../use/cvId';
|
|
92
99
|
|
|
93
|
-
const emit = defineEmits(['change']);
|
|
100
|
+
const emit = defineEmits(['change', 'update:page', 'update:pageSize']);
|
|
94
101
|
|
|
95
102
|
const props = defineProps({
|
|
96
103
|
backwardsButtonDisabled: { type: Boolean, default: false },
|
|
@@ -102,17 +109,38 @@ const props = defineProps({
|
|
|
102
109
|
numberOfItems: { type: Number, default: Infinity },
|
|
103
110
|
actualItemsOnPage: { type: Number, default: Infinity },
|
|
104
111
|
page: { type: Number, default: undefined },
|
|
112
|
+
pageSize: { type: Number, default: undefined },
|
|
105
113
|
pageSizes: { type: Array, default: () => [10, 20, 30, 40, 50] },
|
|
114
|
+
rangeTextFormatter: { type: Function, default: undefined },
|
|
115
|
+
pageOfPagesFormatter: { type: Function, default: undefined },
|
|
106
116
|
});
|
|
107
117
|
const attrs = useAttrs();
|
|
108
118
|
const cvId = useCvId(attrs, true);
|
|
109
119
|
|
|
120
|
+
// Read once at setup time: whether the parent bound a v-model listener for
|
|
121
|
+
// this prop. vnode.props is a plain object Vue replaces on patch, not
|
|
122
|
+
// something Vue's reactivity system tracks, so this can't be a computed()
|
|
123
|
+
// that reacts to listeners being added/removed later - it only reflects
|
|
124
|
+
// how the component was initially used.
|
|
125
|
+
const instance = getCurrentInstance();
|
|
126
|
+
const pageControlled = 'onUpdate:page' in (instance.vnode.props || {});
|
|
127
|
+
const pageSizeControlled = 'onUpdate:pageSize' in (instance.vnode.props || {});
|
|
128
|
+
|
|
110
129
|
const firstItem = ref(1);
|
|
111
|
-
const
|
|
112
|
-
const
|
|
130
|
+
const internalPage = ref(1);
|
|
131
|
+
const internalPageSize = ref(10);
|
|
113
132
|
const pageCount = ref(1);
|
|
114
133
|
const pages = ref([1]);
|
|
115
134
|
|
|
135
|
+
const pageValue = computed(() =>
|
|
136
|
+
pageControlled && props.page !== undefined ? props.page : internalPage.value
|
|
137
|
+
);
|
|
138
|
+
const pageSizeValue = computed(() =>
|
|
139
|
+
pageSizeControlled && props.pageSize !== undefined
|
|
140
|
+
? props.pageSize
|
|
141
|
+
: internalPageSize.value
|
|
142
|
+
);
|
|
143
|
+
|
|
116
144
|
const noWayBack = computed(() => {
|
|
117
145
|
return props.backwardsButtonDisabled || pageValue.value === 1;
|
|
118
146
|
});
|
|
@@ -127,6 +155,9 @@ const ofNPagesProps = computed(() => {
|
|
|
127
155
|
});
|
|
128
156
|
const pageOfPages = computed(() => {
|
|
129
157
|
const { pages, items } = ofNPagesProps.value;
|
|
158
|
+
if (props.pageOfPagesFormatter) {
|
|
159
|
+
return props.pageOfPagesFormatter({ pages, items, page: pageValue.value });
|
|
160
|
+
}
|
|
130
161
|
if (items !== Infinity) {
|
|
131
162
|
return `of ${pages} pages`;
|
|
132
163
|
}
|
|
@@ -147,6 +178,9 @@ const rangeProps = computed(() => {
|
|
|
147
178
|
const rangeText = computed(() => {
|
|
148
179
|
const { start, end, items } = rangeProps.value;
|
|
149
180
|
|
|
181
|
+
if (props.rangeTextFormatter) {
|
|
182
|
+
return props.rangeTextFormatter({ start, end, items });
|
|
183
|
+
}
|
|
150
184
|
if (items !== Infinity) {
|
|
151
185
|
return `${start}-${end} of ${items} items`;
|
|
152
186
|
} else {
|
|
@@ -162,16 +196,23 @@ const internalValue = computed(() => {
|
|
|
162
196
|
});
|
|
163
197
|
|
|
164
198
|
function adjustValues() {
|
|
165
|
-
|
|
199
|
+
if (!pageSizeControlled) {
|
|
200
|
+
internalPageSize.value = newPageSizeValue(props.pageSizes);
|
|
201
|
+
}
|
|
166
202
|
pageCount.value = newPageCount(props.numberOfItems, pageSizeValue.value);
|
|
167
|
-
|
|
203
|
+
if (!pageControlled) {
|
|
204
|
+
internalPage.value = newPageValue(props.page, pageCount.value);
|
|
205
|
+
}
|
|
168
206
|
pages.value = newPagesArray(pageCount.value);
|
|
169
207
|
firstItem.value = newFirstItem(pageValue.value, pageSizeValue.value);
|
|
170
208
|
}
|
|
171
209
|
onMounted(() => {
|
|
172
210
|
adjustValues();
|
|
173
|
-
// always emit on mount
|
|
174
|
-
|
|
211
|
+
// always emit on mount, unless both page and pageSize are fully
|
|
212
|
+
// controlled by the parent, in which case nothing here was derived.
|
|
213
|
+
if (!pageControlled || !pageSizeControlled) {
|
|
214
|
+
emit('change', internalValue.value);
|
|
215
|
+
}
|
|
175
216
|
});
|
|
176
217
|
watch(
|
|
177
218
|
() => props.pageSizes,
|
|
@@ -186,40 +227,46 @@ watch(
|
|
|
186
227
|
() => adjustValues()
|
|
187
228
|
);
|
|
188
229
|
|
|
230
|
+
function propose(nextPage, nextPageSize) {
|
|
231
|
+
if (!pageControlled) {
|
|
232
|
+
internalPage.value = nextPage;
|
|
233
|
+
}
|
|
234
|
+
if (!pageSizeControlled) {
|
|
235
|
+
internalPageSize.value = nextPageSize;
|
|
236
|
+
}
|
|
237
|
+
firstItem.value = newFirstItem(nextPage, nextPageSize);
|
|
238
|
+
|
|
239
|
+
if (pageControlled && nextPage !== pageValue.value) {
|
|
240
|
+
emit('update:page', nextPage);
|
|
241
|
+
}
|
|
242
|
+
if (pageSizeControlled && nextPageSize !== pageSizeValue.value) {
|
|
243
|
+
emit('update:pageSize', nextPageSize);
|
|
244
|
+
}
|
|
245
|
+
emit('change', {
|
|
246
|
+
start: firstItem.value,
|
|
247
|
+
page: nextPage,
|
|
248
|
+
length: nextPageSize,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
189
251
|
function onPageChange(newVal) {
|
|
190
|
-
|
|
191
|
-
firstItem.value = newFirstItem(pageValue.value, pageSizeValue.value);
|
|
192
|
-
emit('change', internalValue.value);
|
|
252
|
+
propose(parseInt(newVal, 10), pageSizeValue.value);
|
|
193
253
|
}
|
|
194
|
-
watch(
|
|
195
|
-
() => props.numberOfItems,
|
|
196
|
-
() => onPageSizeChange(pageSizeValue.value)
|
|
197
|
-
);
|
|
198
254
|
function onPageSizeChange(newVal) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
// this previously resulted in 1 being set on Chrome (other browsers untested)
|
|
206
|
-
pageValue.value = Math.ceil(firstItem.value / pageSizeValue.value);
|
|
207
|
-
firstItem.value = newFirstItem(pageValue.value, pageSizeValue.value);
|
|
208
|
-
emit('change', internalValue.value);
|
|
209
|
-
});
|
|
255
|
+
const nextPageSize = parseInt(newVal, 10);
|
|
256
|
+
const nextPageCount = newPageCount(props.numberOfItems, nextPageSize);
|
|
257
|
+
pageCount.value = nextPageCount;
|
|
258
|
+
pages.value = newPagesArray(nextPageCount);
|
|
259
|
+
const nextPage = Math.ceil(firstItem.value / nextPageSize);
|
|
260
|
+
propose(nextPage, nextPageSize);
|
|
210
261
|
}
|
|
211
262
|
function onPrevPage() {
|
|
212
263
|
if (pageValue.value > 1) {
|
|
213
|
-
pageValue.value
|
|
214
|
-
firstItem.value = newFirstItem(pageValue.value, pageSizeValue.value);
|
|
215
|
-
emit('change', internalValue.value);
|
|
264
|
+
propose(pageValue.value - 1, pageSizeValue.value);
|
|
216
265
|
}
|
|
217
266
|
}
|
|
218
267
|
function onNextPage() {
|
|
219
268
|
if (pageValue.value < pageCount.value) {
|
|
220
|
-
pageValue.value
|
|
221
|
-
firstItem.value = newFirstItem(pageValue.value, pageSizeValue.value);
|
|
222
|
-
emit('change', internalValue.value);
|
|
269
|
+
propose(pageValue.value + 1, pageSizeValue.value);
|
|
223
270
|
}
|
|
224
271
|
}
|
|
225
272
|
function newPageValue(page, lastPage) {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
[`${carbonPrefix}--side-nav--ux`]: isChildOfHeader,
|
|
14
14
|
},
|
|
15
15
|
]"
|
|
16
|
-
:aria-hidden="
|
|
17
|
-
:inert="
|
|
16
|
+
:aria-hidden="isHidden ? 'true' : 'false'"
|
|
17
|
+
:inert="isHidden"
|
|
18
18
|
@focusout="onFocusout"
|
|
19
19
|
@mousedown="onMouseDown"
|
|
20
20
|
@mouseenter="onHoverToggle(true)"
|
|
@@ -79,6 +79,9 @@ const panelExpanded = computed({
|
|
|
79
79
|
data.dataExpanded = val;
|
|
80
80
|
},
|
|
81
81
|
});
|
|
82
|
+
const isHidden = computed(() => {
|
|
83
|
+
return !panelExpanded.value && !props.fixed && !props.rail;
|
|
84
|
+
});
|
|
82
85
|
/**
|
|
83
86
|
* @type {CvHeaderPanel}
|
|
84
87
|
*/
|