Skip to content

Commit

Permalink
Create pagination (#188)
Browse files Browse the repository at this point in the history
* Task: create pagination story

* Task: create pagination

* Task: create pagination

* Task: create pagination - add page jumper

* Task: merge 1.x and rebuild

* Automatic frontend build

* Task: refactoring

* Task: create pagination

* Task: rebuild

* Task: create pagination

* Task: clean up

* Task: add a11y

* Apply eslint-fixer changes

* Task: small improvements

* Improve: empty input on Blur

* Migrante pagination to new folder structure

* Apply eslint-fixer changes

---------

Co-authored-by: robertSt7 <robertSt7@users.noreply.github.com>
Co-authored-by: vin0401 <marvin.bertram@pimcore.com>
Co-authored-by: vin0401 <vin0401@users.noreply.github.com>
  • Loading branch information
4 people authored May 13, 2024
1 parent ea44c22 commit 6c0b743
Show file tree
Hide file tree
Showing 34 changed files with 899 additions and 45 deletions.
2 changes: 1 addition & 1 deletion assets/dist/core-dll/core-manifest.json

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions assets/dist/sdk/manifest.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion assets/dist/vendor/vendor-manifest.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"name":"studio_vendor","content":{"./node_modules/antd-style/es/index.js":{"id":233,"buildMeta":{"exportsType":"namespace","sideEffectFree":true},"exports":["StyleProvider","ThemeProvider","createGlobalStyle","createInstance","createStyles","createStylish","css","cx","extractStaticStyle","injectGlobal","keyframes","setupStyled","styleManager","useAntdStylish","useAntdTheme","useAntdToken","useResponsive","useTheme","useThemeMode"]},"./node_modules/react-dom/index.js":{"id":3935,"buildMeta":{"exportsType":"dynamic","defaultObject":"redirect"},"exports":["__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","createPortal","createRoot","findDOMNode","flushSync","hydrate","hydrateRoot","render","unmountComponentAtNode","unstable_batchedUpdates","unstable_renderSubtreeIntoContainer","version"]},"./node_modules/inversify/es/inversify.js":{"id":6594,"buildMeta":{"exportsType":"namespace","sideEffectFree":true},"exports":["AsyncContainerModule","BindingScopeEnum","BindingTypeEnum","Container","ContainerModule","LazyServiceIdentifer","LazyServiceIdentifier","METADATA_KEY","MetadataReader","TargetTypeEnum","createTaggedDecorator","decorate","getServiceIdentifierAsString","id","inject","injectable","interfaces","multiBindToService","multiInject","named","namedConstraint","optional","postConstruct","preDestroy","tagged","taggedConstraint","targetName","traverseAncerstors","typeConstraint","unmanaged"]},"./node_modules/react/index.js":{"id":7294,"buildMeta":{"exportsType":"dynamic","defaultObject":"redirect"},"exports":["Children","Component","Fragment","Profiler","PureComponent","StrictMode","Suspense","__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","act","cloneElement","createContext","createElement","createFactory","createRef","forwardRef","isValidElement","lazy","memo","startTransition","unstable_act","useCallback","useContext","useDebugValue","useDeferredValue","useEffect","useId","useImperativeHandle","useInsertionEffect","useLayoutEffect","useMemo","useReducer","useRef","useState","useSyncExternalStore","useTransition","version"]},"./node_modules/reflect-metadata/Reflect.js":{"id":8520,"buildMeta":{}},"./node_modules/antd/es/index.js":{"id":9078,"buildMeta":{"exportsType":"namespace","sideEffectFree":true},"exports":["Affix","Alert","Anchor","App","AutoComplete","Avatar","BackTop","Badge","Breadcrumb","Button","Calendar","Card","Carousel","Cascader","Checkbox","Col","Collapse","ColorPicker","ConfigProvider","DatePicker","Descriptions","Divider","Drawer","Dropdown","Empty","Flex","FloatButton","Form","Grid","Image","Input","InputNumber","Layout","List","Mentions","Menu","Modal","Pagination","Popconfirm","Popover","Progress","QRCode","Radio","Rate","Result","Row","Segmented","Select","Skeleton","Slider","Space","Spin","Statistic","Steps","Switch","Table","Tabs","Tag","TimePicker","Timeline","Tooltip","Tour","Transfer","Tree","TreeSelect","Typography","Upload","Watermark","message","notification","theme","version"]}}}
{"name":"studio_vendor","content":{"./node_modules/antd-style/es/index.js":{"id":233,"buildMeta":{"exportsType":"namespace","sideEffectFree":true},"exports":["StyleProvider","ThemeProvider","createGlobalStyle","createInstance","createStyles","createStylish","css","cx","extractStaticStyle","injectGlobal","keyframes","setupStyled","styleManager","useAntdStylish","useAntdTheme","useAntdToken","useResponsive","useTheme","useThemeMode"]},"./node_modules/antd/es/index.js":{"id":2853,"buildMeta":{"exportsType":"namespace","sideEffectFree":true},"exports":["Affix","Alert","Anchor","App","AutoComplete","Avatar","BackTop","Badge","Breadcrumb","Button","Calendar","Card","Carousel","Cascader","Checkbox","Col","Collapse","ColorPicker","ConfigProvider","DatePicker","Descriptions","Divider","Drawer","Dropdown","Empty","Flex","FloatButton","Form","Grid","Image","Input","InputNumber","Layout","List","Mentions","Menu","Modal","Pagination","Popconfirm","Popover","Progress","QRCode","Radio","Rate","Result","Row","Segmented","Select","Skeleton","Slider","Space","Spin","Statistic","Steps","Switch","Table","Tabs","Tag","TimePicker","Timeline","Tooltip","Tour","Transfer","Tree","TreeSelect","Typography","Upload","Watermark","message","notification","theme","version"]},"./node_modules/antd/es/config-provider/context.js":{"id":3124,"buildMeta":{"exportsType":"namespace"},"exports":["ConfigConsumer","ConfigContext","defaultIconPrefixCls"]},"./node_modules/react-dom/index.js":{"id":3935,"buildMeta":{"exportsType":"dynamic","defaultObject":"redirect"},"exports":["__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","createPortal","createRoot","findDOMNode","flushSync","hydrate","hydrateRoot","render","unmountComponentAtNode","unstable_batchedUpdates","unstable_renderSubtreeIntoContainer","version"]},"./node_modules/antd/es/pagination/style/index.js":{"id":4781,"buildMeta":{"exportsType":"namespace"},"exports":["default","prepareComponentToken","prepareToken"]},"./node_modules/antd/es/table/style/index.js":{"id":5347,"buildMeta":{"exportsType":"namespace"},"exports":["default","prepareComponentToken"]},"./node_modules/inversify/es/inversify.js":{"id":6594,"buildMeta":{"exportsType":"namespace","sideEffectFree":true},"exports":["AsyncContainerModule","BindingScopeEnum","BindingTypeEnum","Container","ContainerModule","LazyServiceIdentifer","LazyServiceIdentifier","METADATA_KEY","MetadataReader","TargetTypeEnum","createTaggedDecorator","decorate","getServiceIdentifierAsString","id","inject","injectable","interfaces","multiBindToService","multiInject","named","namedConstraint","optional","postConstruct","preDestroy","tagged","taggedConstraint","targetName","traverseAncerstors","typeConstraint","unmanaged"]},"./node_modules/react/index.js":{"id":7294,"buildMeta":{"exportsType":"dynamic","defaultObject":"redirect"},"exports":["Children","Component","Fragment","Profiler","PureComponent","StrictMode","Suspense","__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED","act","cloneElement","createContext","createElement","createFactory","createRef","forwardRef","isValidElement","lazy","memo","startTransition","unstable_act","useCallback","useContext","useDebugValue","useDeferredValue","useEffect","useId","useImperativeHandle","useInsertionEffect","useLayoutEffect","useMemo","useReducer","useRef","useState","useSyncExternalStore","useTransition","version"]},"./node_modules/reflect-metadata/Reflect.js":{"id":8520,"buildMeta":{}}}}
3 changes: 3 additions & 0 deletions assets/js/src/core/assets/icons/ellipsis-outlined.inline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/js/src/core/assets/icons/left-outlined.inline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/js/src/core/assets/icons/right-outlined.inline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { type Meta } from '@storybook/react'
import { InlineTextfield as InlineTextfieldComponent } from './inline-textfield'

const config: Meta = {
title: 'Pimcore studio/UI/InlineTextfield',
component: InlineTextfieldComponent,
parameters: {
layout: 'centered'
},
tags: ['autodocs']
}

export default config

export const _default = {
args: {
value: '2',
showDotsValues: ['1', '2', '3', '9', '10'],
onKeyDown: (e) => {
if (e.key === 'Enter') {
e.target.value = ''
e.target.blur()
}
console.log(e.key)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { createStyles } from 'antd-style'

export const useStyle = createStyles(({ token, css }) => {
return {
'editable-container': css`
position: relative;
height: 30px;
.input-field {
font-family: Lato, sans-serif;
font-size: 12px;
text-align: center;
line-height: ${token.controlHeight}px;
border-radius: ${token.borderRadius}px;
border-color: ${token.colorBorder};
background-color: white;
/* Firefox */
-moz-appearance: textfield;
}
.input-field:focus-visible {
outline: none;
}
/* Chrome, Safari, Edge, Opera */
.input-field::-webkit-outer-spin-button,
.input-field::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
& button[type="button"], .input-field {
display: block;
position: absolute;
top: 0;
inset-inline-end: 0;
bottom: 0;
inset-inline-start: 0;
padding: unset;
margin: auto;
width: ${token.controlHeight}px;
height: ${token.controlHeight}px;
}
.input-field.remove-decoration {
border: none;
background: none;
}
& button.inline-label.display-none, & button.inline-label-dots.display-none, & input.input-field.display-none {
display: none;
}
button.inline-label-dots {
border: none;
}
button.inline-label-dots, button.inline-label {
font-family: Lato, sans-serif;
line-height: 30px;
text-align: center;
vertical-align: text-bottom;
box-shadow: none;
background-color: transparent;
cursor: text;
}
button.inline-label {
color: ${token.colorPrimary};
border: 1px solid ${token.colorPrimary};
border-radius: ${token.borderRadius}px;
}
`
}
}, { hashPriority: 'low' })
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { useEffect, useState } from 'react'
import { useStyle } from './inline-textfield.styles'
import { isSet } from '@Pimcore/utils/helpers'
import { Button } from 'antd'
import { Icon } from '@Pimcore/components/icon/icon'

interface InlineTextfieldProps {
value: string
onKeyDown: (e) => void
showDotsValues?: string[]
defaultClassNameInput?: string
defaultClassNameLabel?: string
defaultClassNameLabelDots?: string
}

enum VisibleElement {
input = 'input',
label = 'label',
labelDots = 'labelDots'
}

export const InlineTextfield = ({
value = '',
onKeyDown,
showDotsValues,
defaultClassNameInput = 'remove-decoration',
defaultClassNameLabel = 'display-none',
defaultClassNameLabelDots = ''
}: InlineTextfieldProps): React.JSX.Element => {
const { styles } = useStyle()
const [classNameInput, setClassNameInput] = useState(defaultClassNameInput)
const [classNameLabel, setClassNameLabel] = useState(defaultClassNameLabel)
const [classNameLabelDots, setClassNameLabelDots] = useState(defaultClassNameLabelDots)

const setVisibleElement = (element: VisibleElement): void => {
switch (element) {
case VisibleElement.input:
setClassNameInput('')
setClassNameLabel('display-none')
setClassNameLabelDots('display-none')
break
case VisibleElement.label:
setClassNameInput('remove-decoration')
setClassNameLabel('')
setClassNameLabelDots('display-none')
break
case VisibleElement.labelDots:
setClassNameInput('remove-decoration')
setClassNameLabel('display-none')
setClassNameLabelDots('')
break
}
}

const onClickLabel = (e): void => {
setVisibleElement(VisibleElement.input)
e.target.previousElementSibling?.focus()
}

const onBlurInput = (e): void => {
setClassNameBasedOnValue()
e.target.value = ''
}

const onMouseOverDots = (e): void => {
setVisibleElement(VisibleElement.input)
e.target.focus()
}
const onFocusDots = (e): void => {
setVisibleElement(VisibleElement.input)
}

const onFocusInput = (e): void => {
setVisibleElement(VisibleElement.input)
}

const onMouseLeaveInput = (e): void => {
if (document.activeElement !== e.target) {
setVisibleElement(VisibleElement.labelDots)
}
}

const setClassNameBasedOnValue = (): void => {
if (isSet(showDotsValues)) {
if (showDotsValues!.includes(value) && classNameLabelDots === 'display-none') {
setVisibleElement(VisibleElement.labelDots)
} else if (!showDotsValues!.includes(value) && classNameLabel === 'display-none') {
setVisibleElement(VisibleElement.label)
}
}
}

useEffect(() => {
setClassNameBasedOnValue()
}, [value])

return (
<div className={ styles['editable-container'] }>
<input
className={ 'input-field ' + classNameInput }
min='1'
onBlur={ onBlurInput }
onFocus={ onFocusInput }
onKeyDown={ onKeyDown }
onMouseLeave={ onMouseLeaveInput }
type='number'
/>
<Button
className={ 'inline-label ' + classNameLabel }
onClick={ onClickLabel }
>{value}</Button>
<Button
className={ 'inline-label-dots ' + classNameLabelDots }
icon={ <Icon
name={ 'ellipsis-outlined' }
options={ { width: '32px', height: '32px' } }
/> }
onFocus={ onFocusDots }
onMouseOver={ onMouseOverDots }
/>
</div>
)
}
45 changes: 45 additions & 0 deletions assets/js/src/core/components/pagination/pagination.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { type Meta } from '@storybook/react'
import { Pagination as PaginationComponent } from './pagination'

const config: Meta = {
title: 'Pimcore studio/UI/Pagination',
component: PaginationComponent,
argTypes: {
total: {
control: false
}
},
parameters: {
layout: 'centered'
},
tags: ['autodocs']
}

export default config

export const _default = {
args: {
total: 182,
current: 2,
pageSizeOptions: [5, 25, 55, 80],
defaultPageSize: 25,
showSizeChanger: true,
hideOnSinglePage: true,
amountOfVisiblePages: 4,
showTotal: (total: number) => `Total ${total} items`,
onChange: (currentPage: number, pageSize: number) => { console.log(`Current page: ${currentPage}, Page size: ${pageSize}`) }
}
}
Loading

0 comments on commit 6c0b743

Please sign in to comment.