feat(pager): [pager] add simplest pager to adaptive x-design (#2126)

* feat(pager): [pager] add simplest pager to adaptive x-design

* feat(pager): [pager] add simplest pager to adaptive x-design
This commit is contained in:
gimmyhehe 2024-09-14 09:36:32 +08:00 committed by GitHub
parent ecedc485e3
commit 5bce345e3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 120 additions and 60 deletions

View File

@ -92,10 +92,10 @@ export default {
},
{
name: 'mode',
type: "'number' | 'simple' | 'complete' | 'fixed'",
type: "'number' | 'simple' | 'complete' | 'fixed' | 'simplest'",
defaultValue: '',
desc: {
'zh-CN': '设置分页组件显示模式,此属性优先级大于 layout',
'zh-CN': '设置分页组件显示模式,此属性优先级大于 layout, 3.19.0新增simplest',
'en-US': 'Set the display mode of pagination components, which takes priority over layout'
},
mode: ['pc'],

View File

@ -12,8 +12,8 @@ test('禁用和尺寸', async ({ page }) => {
const next = pager.locator('.tiny-pager__btn-next')
await demo.locator('.tiny-switch').click()
await expect(sizeChange).toHaveCSS('color', 'rgb(138, 142, 153)')
await expect(sizeChange).toHaveCSS('border-top-color', 'rgba(0, 0, 0, 0)')
await expect(sizeChange).toHaveCSS('color', 'rgb(194, 194, 194)')
await expect(sizeChange).toHaveCSS('border-top-color', 'rgb(219, 219, 219)')
await expect(prev).toBeDisabled()
await expect(next).toBeDisabled()
await expect(pageItem.first()).toHaveCSS('cursor', 'not-allowed')

View File

@ -6,6 +6,7 @@
<tiny-radio-button label="simple"></tiny-radio-button>
<tiny-radio-button label="complete"></tiny-radio-button>
<tiny-radio-button label="fixed"></tiny-radio-button>
<tiny-radio-button label="simplest"></tiny-radio-button>
</tiny-radio-group>
<tiny-pager :mode="mode" :total="100"></tiny-pager>
</div>

View File

@ -6,6 +6,7 @@
<tiny-radio-button label="simple"></tiny-radio-button>
<tiny-radio-button label="complete"></tiny-radio-button>
<tiny-radio-button label="fixed"></tiny-radio-button>
<tiny-radio-button label="simplest"></tiny-radio-button>
</tiny-radio-group>
<tiny-pager :mode="mode" :total="100"></tiny-pager>
</div>

View File

@ -1,7 +1,6 @@
export default {
state: {
pageSizeText: '',
align: 'right',
totalFixedLeft: true
align: 'right'
}
}

View File

@ -18,6 +18,7 @@ export const computedInternalLayout =
props.mode === 'simple' && (layout = 'sizes, total, prev, current, next')
props.mode === 'complete' && (layout = 'sizes, total, prev, pager, next, jumper')
props.mode === 'fixed' && (layout = 'prev,pager,next')
props.mode === 'simplest' && (layout = 'total, prev, simplest-pager, next')
} else if ((!props.mode && props.layout) || (props.mode && props.layout)) {
layout = props.layout
} else {
@ -67,6 +68,25 @@ export const computedInternalPageCount =
return null
}
export const computedSimplestPagerOption =
({ props, state }: Pick<IPagerRenderlessParams, 'props' | 'state'>) =>
(): Array<{ value: number; label: string }> => {
const itemSizes = Math.max(1, Math.ceil(props.total / state.internalPageSize))
return Array.from({ length: itemSizes }).map((item, index) => ({
value: index + 1,
label: `${index + 1}/${itemSizes}`
}))
}
export const computedSimplestPagerWidth =
({ state }: Pick<IPagerRenderlessParams, 'state'>) =>
(): number => {
const baseWidth = 60
const num = String(state.internalCurrentPage).length + String(state.simplestPagerOption.length).length
// 输入框长度 = 基本宽度加数字长度
return baseWidth + num * 8
}
export const handleJumperFocus =
({ state }: Pick<IPagerRenderlessParams, 'state'>) =>
(e: Event): void => {

View File

@ -10,6 +10,8 @@ import {
computedInternalLayout,
computedTotalText,
computedInternalPageCount,
computedSimplestPagerOption,
computedSimplestPagerWidth,
handleJumperFocus,
handleSizeChange,
handleJumperInput,
@ -83,6 +85,8 @@ export const renderless = (
internalTotal: props.total,
jumperValue: '1',
jumperBackup: '1',
simplestPagerOption: computed(() => api.computedSimplestPagerOption()),
simplestPagerWidth: computed(() => api.computedSimplestPagerWidth()),
showPager: computed(() => api.computedShowPager()),
internalLayout: computed(() => api.computedInternalLayout()),
totalText: computed(() => api.computedTotalText()),
@ -90,7 +94,9 @@ export const renderless = (
showJumperSufix: designConfig?.state?.showJumperSufix ?? true,
align: props.align || designConfig?.state?.align || 'left',
totalI18n: designConfig?.state?.totalI18n || 'totals',
totalFixedLeft: props.totalFixedLeft ?? designConfig?.state?.totalFixedLeft ?? false,
totalFixedLeft: computed(
() => props.totalFixedLeft ?? designConfig?.state?.totalFixedLeft ?? props.mode !== 'simplest' ?? true
),
pageSizeText: props.pageSizeText ?? designConfig?.state?.pageSizeText
})
@ -100,6 +106,8 @@ export const renderless = (
computedInternalLayout: computedInternalLayout({ props }),
computedTotalText: computedTotalText({ props, t }),
computedInternalPageCount: computedInternalPageCount({ props, state }),
computedSimplestPagerOption: computedSimplestPagerOption({ props, state }),
computedSimplestPagerWidth: computedSimplestPagerWidth({ state }),
getValidCurrentPage: getValidCurrentPage({ state }),
handleJumperFocus: handleJumperFocus({ state }),
handleSizeChange: handleSizeChange({ props, state, api, emit, vm }),

View File

@ -24,7 +24,7 @@
// 小型选择器尾部图标距离输入框的垂直距离
--ti-select-input-icon-top-small: var(--ti-common-space-4x);
// 迷你型选择器尾部图标距离输入框的垂直距离
--ti-select-input-icon-top-mini: var(--ti-common-space-4x);
--ti-select-input-icon-top-mini: var(--ti-common-space-3x);
// 选择器输入框尾部图标的颜色
--ti-select-input-caret-icon-color: var(--ti-common-color-icon-normal);
// 选择器输入框尾部图标悬浮时的颜色

View File

@ -132,9 +132,6 @@
.@{pager-prefix-cls}__total-loading {
width: 30px;
}
.tiny-loading__spinner {
margin-top: 3px;
}
}
&__goto {
@ -169,9 +166,11 @@
border: 1px solid var(--ti-pager-primary-border-color);
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
}
&[disabled] {
color: var(--ti-pager-disabled-text-color);
border-color: var(--ti-pager-disabled-border-color);
border-color: var(--ti-pager-select-disabled-border-color);
background: var(--ti-pager-select-disabled-bg-color);
cursor: not-allowed;
}
}
@ -182,6 +181,7 @@
padding-left: var(--ti-pager-normal-text-padding-left);
margin-right: 8px;
line-height: var(--ti-pager-input-height);
&-sufix {
padding-left: 4px;
}
@ -210,10 +210,12 @@
background 0.3s;
outline: 0;
.user-select(none);
&:hover {
border: 1px solid var(--ti-pager-goto-btn-border-hover-color);
color: var(--ti-pager-goto-btn-text-hover-color);
}
&.is-disabled {
color: var(--ti-pager-disabled-text-color);
border-color: var(--ti-pager-disabled-border-color);
@ -316,11 +318,12 @@
.list-item {
min-height: var(--ti-pager-poplist-item-min-height);
padding: 0 8px;
line-height: 30px;
line-height: var(--ti-pager-poplist-item-min-height);
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: center;
&:hover {
cursor: pointer;
@ -512,8 +515,8 @@
.@{pager-prefix-cls}__page-size {
color: var(--ti-pager-disabled-text-color);
cursor: not-allowed;
border-color: var(--ti-pager-disabled-border-color);
background-color: var(--ti-base-color-bg-1);
border-color: var(--ti-pager-select-disabled-border-color);
background: var(--ti-pager-select-disabled-bg-color);
}
.@{pager-prefix-cls}__page-size-btn {
@ -528,6 +531,20 @@
color: var(--ti-pager-disabled-text-color);
}
}
&__simplest-pager-popover {
.component-css-vars-pager();
.tiny-option-label {
text-align: center;
font-family: var(--ti-pager-number-font-family);
}
.tiny-option.selected {
color: var(--ti-pager-poplist-item-selected-text-color);
background: var(--ti-pager-poplist-item-selected-bg-color);
}
}
}
@media (max-width: 768px) {

View File

@ -22,7 +22,6 @@ export const tinyPagerOldTheme = {
'ti-pager-prev-padding-left': '6px',
'ti-pager-goto-btn-text-hover-color': 'var(--ti-common-color-text-highlight, #526ecc)',
'ti-pager-poplist-item-min-height': '30px',
'ti-pager-pop-body-margin-top': '4px',
'ti-pager-poplist-item-selected-bg-color': 'var(--ti-common-color-selected-background, #5e7ce0)',
'ti-pager-poplist-item-hover-text-color': 'var(--ti-common-color-text-highlight, #526ecc)',
'ti-pager-poplist-item-hover-bg-color': 'var(--ti-common-color-hover-background, #f2f5fc)',

View File

@ -18,7 +18,7 @@
// 分页页码选中项文字色
--ti-pager-active-font-color: var(--ti-common-color-text-primary);
// 分页页码选中项背景色
--ti-pager-active-bg-color: #F5F5F5;
--ti-pager-active-bg-color: #f5f5f5;
// 自定义上下页按钮文本色
--ti-pager-primary-text-color: var(--ti-common-color-text-link, #526ecc);
// 分页跳转输入框激活颜色
@ -31,6 +31,10 @@
--ti-pager-disabled-text-color: var(--ti-common-color-text-disabled, #adb0b8);
// 分页禁用状态下边框颜色
--ti-pager-disabled-border-color: transparent;
// 分页禁用选择框边框颜色
--ti-pager-select-disabled-border-color: #dbdbdb;
// 分页禁用选择框背景颜色
--ti-pager-select-disabled-bg-color: var(--ti-common-color-bg-disabled);
// 分页输入框和选项框边框色
--ti-pager-input-border-color: var(--ti-common-color-line-normal);
@ -85,11 +89,11 @@
--ti-pager-li-item-hover-font-weight: var(--ti-common-font-weight-6);
// 分页项默认悬浮背景色
--ti-pager-poplist-item-hover-bg-color: #F5F5F5;
--ti-pager-poplist-item-hover-bg-color: #f5f5f5;
// 分页下拉框项|列表项悬浮文本色
--ti-pager-poplist-item-hover-text-color: var(--ti-common-color-text-primary);
// 分页下拉框选中项默认背景色
--ti-pager-poplist-item-selected-bg-color: #F5F5F5;
--ti-pager-poplist-item-selected-bg-color: #f5f5f5;
// 分页下拉框项选中字体颜色
--ti-pager-poplist-item-selected-text-color: var(--ti-common-color-selected-text-color, #fff);
// 分页页码项默认悬浮边框色
@ -99,7 +103,7 @@
// 分页下拉框顶部外边距
--ti-pager-pop-body-margin-top: var(--ti-common-space-base);
// 分页下拉项最小高度
--ti-pager-poplist-item-min-height: var(--ti-common-line-height-6);
--ti-pager-poplist-item-min-height: 32px;
// 分页下一页文字禁用色
--ti-pager-prev-next-text-color-disabled: var(--ti-common-color-text-disabled, #adb0b8);

View File

@ -1,37 +1,35 @@
{
"name": "@opentiny/vue-base-select",
"type": "module",
"version": "3.18.0",
"description": "",
"license": "MIT",
"sideEffects": false,
"main": "lib/index.js",
"module": "index.ts",
"sideEffects": false,
"type": "module",
"devDependencies": {
"@opentiny-internal/vue-test-utils": "workspace:*",
"vitest": "^0.31.0"
},
"scripts": {
"build": "pnpm -w build:ui $npm_package_name",
"//postversion": "pnpm build"
},
"dependencies": {
"@opentiny/vue-renderless": "workspace:~",
"@opentiny/vue-common": "workspace:~",
"@opentiny/vue-locale": "workspace:~",
"@opentiny/vue-tag": "workspace:~",
"@opentiny/vue-input": "workspace:~",
"@opentiny/vue-option": "workspace:~",
"@opentiny/vue-scrollbar": "workspace:~",
"@opentiny/vue-icon": "workspace:~",
"@opentiny/vue-select-dropdown": "workspace:~",
"@opentiny/vue-grid": "workspace:~",
"@opentiny/vue-tree": "workspace:~",
"@opentiny/vue-tooltip": "workspace:~",
"@opentiny/vue-filter-box": "workspace:~",
"@opentiny/vue-button": "workspace:~",
"@opentiny/vue-checkbox": "workspace:~",
"@opentiny/vue-theme": "workspace:~",
"@opentiny/vue-common": "workspace:~",
"@opentiny/vue-filter-box": "workspace:~",
"@opentiny/vue-icon": "workspace:~",
"@opentiny/vue-input": "workspace:~",
"@opentiny/vue-locale": "workspace:~",
"@opentiny/vue-option": "workspace:~",
"@opentiny/vue-recycle-scroller": "workspace:~",
"@opentiny/vue-button": "workspace:~"
"@opentiny/vue-renderless": "workspace:~",
"@opentiny/vue-scrollbar": "workspace:~",
"@opentiny/vue-select-dropdown": "workspace:~",
"@opentiny/vue-tag": "workspace:~",
"@opentiny/vue-theme": "workspace:~",
"@opentiny/vue-tooltip": "workspace:~"
},
"license": "MIT"
}
"devDependencies": {
"@opentiny-internal/vue-test-utils": "workspace:*",
"vitest": "^0.31.0"
}
}

View File

@ -540,8 +540,6 @@ import {
IconEllipsis,
IconChevronUp
} from '@opentiny/vue-icon'
import Grid from '@opentiny/vue-grid'
import Tree from '@opentiny/vue-tree'
import TinyTooltip from '@opentiny/vue-tooltip'
import FilterBox from '@opentiny/vue-filter-box'
import RecycleScroller from '@opentiny/vue-recycle-scroller'
@ -593,8 +591,6 @@ export default defineComponent({
TinyTag,
TinyInput,
TinyOption,
TinyGrid: Grid,
TinyTree: Tree,
TinyButton,
IconClose: IconClose(),
TinyScrollbar,

View File

@ -1,27 +1,28 @@
{
"name": "@opentiny/vue-pager",
"type": "module",
"version": "3.18.0",
"description": "",
"license": "MIT",
"sideEffects": false,
"main": "lib/index.js",
"module": "index.ts",
"sideEffects": false,
"type": "module",
"devDependencies": {
"@opentiny-internal/vue-test-utils": "workspace:*",
"vitest": "^0.31.0"
},
"scripts": {
"build": "pnpm -w build:ui $npm_package_name",
"//postversion": "pnpm build"
},
"dependencies": {
"@opentiny/vue-renderless": "workspace:~",
"@opentiny/vue-base-select": "workspace:~",
"@opentiny/vue-common": "workspace:~",
"@opentiny/vue-icon": "workspace:~",
"@opentiny/vue-popover": "workspace:~",
"@opentiny/vue-pager-item": "workspace:~",
"@opentiny/vue-loading": "workspace:~",
"@opentiny/vue-theme": "workspace:~",
"@opentiny/vue-common": "workspace:~"
"@opentiny/vue-pager-item": "workspace:~",
"@opentiny/vue-popover": "workspace:~",
"@opentiny/vue-renderless": "workspace:~",
"@opentiny/vue-theme": "workspace:~"
},
"license": "MIT"
}
"devDependencies": {
"@opentiny-internal/vue-test-utils": "workspace:*",
"vitest": "^0.31.0"
}
}

View File

@ -69,6 +69,20 @@
@before-page-change="beforePagerChangeHandler"
></pager>
<!-- simplest-pager-item -->
<tiny-base-select
v-else-if="item === 'simplest-pager'"
:style="{ width: state.simplestPagerWidth + 'px' }"
:size="size"
:key="'simplest-pager' + index"
v-model="state.internalCurrentPage"
:disabled="disabled"
:options="state.simplestPagerOption"
popper-class="tiny-pager__simplest-pager-popover"
:optimization="state.simplestPagerOption.length > 30"
@change="handleCurrentChange"
></tiny-base-select>
<!-- next -->
<button
v-else-if="item === 'next'"
@ -156,6 +170,7 @@
<script lang="tsx">
import Pager from '@opentiny/vue-pager-item'
import TinyBaseSelect from '@opentiny/vue-base-select'
import Popover from '@opentiny/vue-popover'
import Loading from '@opentiny/vue-loading'
import { $prefix, setup, defineComponent, props } from '@opentiny/vue-common'
@ -200,6 +215,7 @@ export default defineComponent({
},
components: {
TinyPopover: Popover,
TinyBaseSelect,
ChevronLeft: iconChevronLeft(),
ChevronRight: iconChevronRight(),
TriangleDown: iconTriangleDown(),