@xyo-network/react-property 2.26.37 → 2.26.40
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/docs.json +1 -1
- package/package.json +2 -2
- package/src/components/Action.ts +8 -0
- package/src/components/Actions.tsx +26 -0
- package/src/components/ActionsMenu.tsx +41 -0
- package/src/components/ActionsProps.ts +8 -0
- package/src/components/Group.tsx +44 -0
- package/src/components/IdenticonCorner.tsx +30 -0
- package/src/components/Property.tsx +51 -0
- package/src/components/PropertyBox.stories.tsx +163 -0
- package/src/components/PropertyPaper.stories.tsx +174 -0
- package/src/components/Props.tsx +48 -0
- package/src/components/Title.stories.tsx +32 -0
- package/src/components/Title.tsx +66 -0
- package/src/components/Value.stories.tsx +29 -0
- package/src/components/Value.tsx +55 -0
- package/src/components/index.ts +5 -0
- package/src/index.ts +1 -0
package/dist/docs.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"fileName": "index.ts",
|
|
11
11
|
"line": 1,
|
|
12
12
|
"character": 0,
|
|
13
|
-
"url": "https://github.com/XYOracleNetwork/sdk-xyo-react-js/blob/
|
|
13
|
+
"url": "https://github.com/XYOracleNetwork/sdk-xyo-react-js/blob/0cea94b/packages/property/src/index.ts#L1"
|
|
14
14
|
}
|
|
15
15
|
]
|
|
16
16
|
}
|
package/package.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@xylabs/react-flexbox": "^2.14.10",
|
|
19
19
|
"@xylabs/react-identicon": "^2.14.10",
|
|
20
20
|
"@xylabs/react-quick-tip-button": "^2.14.10",
|
|
21
|
-
"@xyo-network/react-shared": "^2.26.
|
|
21
|
+
"@xyo-network/react-shared": "^2.26.40",
|
|
22
22
|
"@xyo-network/typeof": "^2.22.15",
|
|
23
23
|
"react": "^18.2.0",
|
|
24
24
|
"react-dom": "^18.2.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
},
|
|
81
81
|
"sideEffects": false,
|
|
82
82
|
"types": "dist/esm/index.d.ts",
|
|
83
|
-
"version": "2.26.
|
|
83
|
+
"version": "2.26.40"
|
|
84
84
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { IconButton } from '@mui/material'
|
|
2
|
+
import { ButtonEx } from '@xylabs/react-button'
|
|
3
|
+
import { FlexRow } from '@xylabs/react-flexbox'
|
|
4
|
+
|
|
5
|
+
import { PropertyActionsProps } from './ActionsProps'
|
|
6
|
+
|
|
7
|
+
export const PropertyActions: React.FC<PropertyActionsProps> = ({ buttons = false, actions, ...props }) => {
|
|
8
|
+
if (actions) {
|
|
9
|
+
return (actions?.length ?? 0) > 0 ? (
|
|
10
|
+
<FlexRow gap={1} {...props}>
|
|
11
|
+
{actions.map((action, index) => {
|
|
12
|
+
return action.icon ? (
|
|
13
|
+
<IconButton size="small" key={index} color="inherit" onClick={action.onClick}>
|
|
14
|
+
{action.icon}
|
|
15
|
+
</IconButton>
|
|
16
|
+
) : buttons ? (
|
|
17
|
+
<ButtonEx paddingY={0} color="primary" key={index} size="small" disabled={action.disabled} onClick={action.onClick} variant="contained">
|
|
18
|
+
{action.name}
|
|
19
|
+
</ButtonEx>
|
|
20
|
+
) : null
|
|
21
|
+
})}
|
|
22
|
+
</FlexRow>
|
|
23
|
+
) : null
|
|
24
|
+
}
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'
|
|
2
|
+
import { IconButton, Menu, MenuItem } from '@mui/material'
|
|
3
|
+
import { FlexRow } from '@xylabs/react-flexbox'
|
|
4
|
+
import { useState } from 'react'
|
|
5
|
+
|
|
6
|
+
import { PropertyActionsProps } from './ActionsProps'
|
|
7
|
+
|
|
8
|
+
export const PropertyActionsMenu: React.FC<PropertyActionsProps> = ({ actions, ...props }) => {
|
|
9
|
+
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
|
10
|
+
const open = !!anchorEl
|
|
11
|
+
|
|
12
|
+
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
|
13
|
+
setAnchorEl(event.currentTarget)
|
|
14
|
+
}
|
|
15
|
+
const handleClose = () => {
|
|
16
|
+
setAnchorEl(null)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return actions && actions?.length > 0 ? (
|
|
20
|
+
<FlexRow {...props}>
|
|
21
|
+
<IconButton size="small" color="inherit" onClick={handleClick}>
|
|
22
|
+
<MoreHorizIcon fontSize="inherit" />
|
|
23
|
+
</IconButton>
|
|
24
|
+
<Menu anchorEl={anchorEl} open={open} onClose={handleClose}>
|
|
25
|
+
{actions?.map((action) => {
|
|
26
|
+
return (
|
|
27
|
+
<MenuItem
|
|
28
|
+
key={action.name}
|
|
29
|
+
onClick={() => {
|
|
30
|
+
action?.onClick?.()
|
|
31
|
+
handleClose()
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
{action.name}
|
|
35
|
+
</MenuItem>
|
|
36
|
+
)
|
|
37
|
+
})}
|
|
38
|
+
</Menu>
|
|
39
|
+
</FlexRow>
|
|
40
|
+
) : null
|
|
41
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Paper, useTheme } from '@mui/material'
|
|
2
|
+
import { FlexCol, FlexGrowRow, FlexRow } from '@xylabs/react-flexbox'
|
|
3
|
+
import { typeOf } from '@xyo-network/typeof'
|
|
4
|
+
import { ReactElement } from 'react'
|
|
5
|
+
|
|
6
|
+
import { PropertyGroupBoxProps, PropertyGroupPaperProps, PropertyGroupProps } from './Props'
|
|
7
|
+
import { PropertyTitle } from './Title'
|
|
8
|
+
|
|
9
|
+
const PropertyGroupBox: React.FC<PropertyGroupBoxProps> = ({ titleProps, children, title, tip, ...props }) => {
|
|
10
|
+
const theme = useTheme()
|
|
11
|
+
const childrenArray = typeOf(children) === 'array' ? (children as ReactElement[]) : undefined
|
|
12
|
+
return (
|
|
13
|
+
<FlexCol alignItems="stretch" overflow="hidden" {...props}>
|
|
14
|
+
<FlexRow overflow="hidden" justifyContent="stretch" alignItems="stretch">
|
|
15
|
+
<PropertyTitle alignItems="flex-start" size="full" title={title} tip={tip} {...titleProps} />
|
|
16
|
+
{childrenArray ? (
|
|
17
|
+
<FlexGrowRow>
|
|
18
|
+
{childrenArray?.map((child, index) => {
|
|
19
|
+
return child ? (
|
|
20
|
+
<FlexGrowRow key={index} borderLeft={1} borderColor={theme.palette.divider}>
|
|
21
|
+
{child}
|
|
22
|
+
</FlexGrowRow>
|
|
23
|
+
) : null
|
|
24
|
+
})}
|
|
25
|
+
</FlexGrowRow>
|
|
26
|
+
) : (
|
|
27
|
+
<FlexGrowRow overflow="hidden">{children}</FlexGrowRow>
|
|
28
|
+
)}
|
|
29
|
+
</FlexRow>
|
|
30
|
+
</FlexCol>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const PropertyGroupPaper: React.FC<PropertyGroupPaperProps> = ({ style, variant, elevation, square, ...props }) => {
|
|
35
|
+
return (
|
|
36
|
+
<Paper style={{ minWidth: 0, overflow: 'hidden', ...style }} variant={variant} elevation={elevation} square={square}>
|
|
37
|
+
<PropertyGroupBox {...props} paper={false} />
|
|
38
|
+
</Paper>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const PropertyGroup: React.FC<PropertyGroupProps> = (props) => {
|
|
43
|
+
return props.paper ? <PropertyGroupPaper {...props} /> : <PropertyGroupBox {...props} />
|
|
44
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useTheme } from '@mui/material'
|
|
2
|
+
import { FlexBoxProps, FlexRow } from '@xylabs/react-flexbox'
|
|
3
|
+
import { Identicon } from '@xylabs/react-identicon'
|
|
4
|
+
import { useEffect, useRef, useState } from 'react'
|
|
5
|
+
|
|
6
|
+
export interface IdenticonCornerProps extends FlexBoxProps {
|
|
7
|
+
value?: string | number | boolean | null
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const IdenticonCorner: React.FC<IdenticonCornerProps> = ({ value, ...props }) => {
|
|
11
|
+
const theme = useTheme()
|
|
12
|
+
const [parentHeight, setParentHeight] = useState<number>()
|
|
13
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setParentHeight(ref.current?.parentElement?.parentElement?.clientHeight)
|
|
17
|
+
}, [])
|
|
18
|
+
|
|
19
|
+
const calculatedHeight = parentHeight ?? 0
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<FlexRow alignItems="flex-start" height="100%" position="absolute" right={0} bottom={0}>
|
|
23
|
+
<FlexRow background height={calculatedHeight} width={calculatedHeight} borderLeft={`1px solid ${theme.palette.divider}`}>
|
|
24
|
+
<div ref={ref}>
|
|
25
|
+
<Identicon size={calculatedHeight * 0.6} value={`${value}`} sx={{ padding: `${calculatedHeight * 0.2}px` }} {...props} />
|
|
26
|
+
</div>
|
|
27
|
+
</FlexRow>
|
|
28
|
+
</FlexRow>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CircularProgress, Paper, TypographyVariant } from '@mui/material'
|
|
2
|
+
import { FlexRow } from '@xylabs/react-flexbox'
|
|
3
|
+
import { SizeProp } from '@xyo-network/react-shared'
|
|
4
|
+
|
|
5
|
+
import { PropertyActionsMenu } from './ActionsMenu'
|
|
6
|
+
import { IdenticonCorner } from './IdenticonCorner'
|
|
7
|
+
import { PropertyBoxProps, PropertyPaperProps, PropertyProps } from './Props'
|
|
8
|
+
import { PropertyTitle } from './Title'
|
|
9
|
+
import { PropertyValue } from './Value'
|
|
10
|
+
|
|
11
|
+
const PropertyBox: React.FC<PropertyBoxProps> = ({ titleProps, title, value, children, size = 'medium', tip, actions, required, badge = false, ...props }) => {
|
|
12
|
+
const sizeValueHeight: Record<SizeProp, number> = {
|
|
13
|
+
large: 48,
|
|
14
|
+
medium: 36,
|
|
15
|
+
small: 24,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const sizeVariants: Record<SizeProp, TypographyVariant> = {
|
|
19
|
+
large: 'h6',
|
|
20
|
+
medium: 'body1',
|
|
21
|
+
small: 'body2',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<FlexRow flexDirection="column" minWidth={0} alignItems="stretch" overflow="hidden" {...props}>
|
|
26
|
+
{title !== undefined ? <PropertyTitle tip={tip} title={required ? `${title}*` : title} size={size} more={<PropertyActionsMenu actions={actions} />} {...titleProps} /> : null}
|
|
27
|
+
<FlexRow paddingX={1} justifyContent={value === undefined ? 'center' : 'space-between'} overflow="hidden" height={sizeValueHeight[size]}>
|
|
28
|
+
{children ? (
|
|
29
|
+
children
|
|
30
|
+
) : value !== undefined ? (
|
|
31
|
+
<PropertyValue shortSpace={badge ? sizeValueHeight[size] : 0} value={value} typographyVariant={sizeVariants[size]} />
|
|
32
|
+
) : (
|
|
33
|
+
<CircularProgress size={16} />
|
|
34
|
+
)}
|
|
35
|
+
{value !== undefined ? badge ? <IdenticonCorner value={value} /> : null : null}
|
|
36
|
+
</FlexRow>
|
|
37
|
+
</FlexRow>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const PropertyPaper: React.FC<PropertyPaperProps> = ({ style, variant, elevation = 2, square, ...props }) => {
|
|
42
|
+
return (
|
|
43
|
+
<Paper style={{ minWidth: 0, overflow: 'hidden', ...style }} variant={variant} elevation={elevation} square={square}>
|
|
44
|
+
<PropertyBox {...props} paper={false} />
|
|
45
|
+
</Paper>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const Property: React.FC<PropertyProps> = (props) => {
|
|
50
|
+
return props.paper ? <PropertyPaper {...props} /> : <PropertyBox {...props} />
|
|
51
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import ReplayIcon from '@mui/icons-material/Replay'
|
|
2
|
+
import { TextField } from '@mui/material'
|
|
3
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react'
|
|
4
|
+
import { FlexCol, FlexRow } from '@xylabs/react-flexbox'
|
|
5
|
+
|
|
6
|
+
import { appThemeDecorator, sampleBlockWithPayloads } from '../../../../.storybook'
|
|
7
|
+
import { Property } from './Property'
|
|
8
|
+
|
|
9
|
+
const StorybookEntry = {
|
|
10
|
+
argTypes: {},
|
|
11
|
+
component: Property,
|
|
12
|
+
parameters: {
|
|
13
|
+
docs: {
|
|
14
|
+
page: null,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
title: 'property/PropertyBox',
|
|
18
|
+
} as ComponentMeta<typeof Property>
|
|
19
|
+
|
|
20
|
+
const Template: ComponentStory<typeof Property> = (args) => <Property {...args} paper={false}></Property>
|
|
21
|
+
|
|
22
|
+
const TemplateWithCompare: ComponentStory<typeof Property> = (args) => (
|
|
23
|
+
<FlexCol gap={1} alignItems="stretch">
|
|
24
|
+
<FlexRow gap={1}>
|
|
25
|
+
<TextField size="small" value="Sample text Field" />
|
|
26
|
+
<Property {...args} size="small"></Property>
|
|
27
|
+
</FlexRow>
|
|
28
|
+
<FlexRow gap={1}>
|
|
29
|
+
<Property {...args} size="small"></Property>
|
|
30
|
+
<Property {...args} size="small"></Property>
|
|
31
|
+
</FlexRow>
|
|
32
|
+
<FlexRow gap={1}>
|
|
33
|
+
<TextField size="medium" value="Sample text Field" />
|
|
34
|
+
<Property {...args} size="medium"></Property>
|
|
35
|
+
</FlexRow>
|
|
36
|
+
<FlexRow gap={1}>
|
|
37
|
+
<Property {...args} size="medium"></Property>
|
|
38
|
+
<Property {...args} size="medium"></Property>
|
|
39
|
+
</FlexRow>
|
|
40
|
+
<FlexRow gap={1}>
|
|
41
|
+
<TextField value="Sample text Field" />
|
|
42
|
+
<Property {...args} size="large"></Property>
|
|
43
|
+
</FlexRow>
|
|
44
|
+
<FlexRow gap={1}>
|
|
45
|
+
<Property {...args} size="large"></Property>
|
|
46
|
+
<Property {...args} size="large"></Property>
|
|
47
|
+
</FlexRow>
|
|
48
|
+
</FlexCol>
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const Default = Template.bind({})
|
|
52
|
+
Default.args = {}
|
|
53
|
+
Default.decorators = [appThemeDecorator]
|
|
54
|
+
|
|
55
|
+
const WithTitle = Template.bind({})
|
|
56
|
+
WithTitle.args = { title: 'No Data' }
|
|
57
|
+
WithTitle.decorators = [appThemeDecorator]
|
|
58
|
+
|
|
59
|
+
const WithUndefinedData = Template.bind({})
|
|
60
|
+
WithUndefinedData.args = { title: 'Block Hash' }
|
|
61
|
+
WithUndefinedData.decorators = [appThemeDecorator]
|
|
62
|
+
|
|
63
|
+
const WithData = Template.bind({})
|
|
64
|
+
WithData.args = { title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
65
|
+
WithData.decorators = [appThemeDecorator]
|
|
66
|
+
|
|
67
|
+
const WithDataSmall = Template.bind({})
|
|
68
|
+
WithDataSmall.args = { size: 'small', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
69
|
+
WithDataSmall.decorators = [appThemeDecorator]
|
|
70
|
+
|
|
71
|
+
const WithDataCompare = TemplateWithCompare.bind({})
|
|
72
|
+
WithDataCompare.args = { tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
73
|
+
WithDataCompare.decorators = [appThemeDecorator]
|
|
74
|
+
|
|
75
|
+
const WithDataAndBadgeSmall = Template.bind({})
|
|
76
|
+
WithDataAndBadgeSmall.args = { badge: true, size: 'small', tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
77
|
+
WithDataAndBadgeSmall.decorators = [appThemeDecorator]
|
|
78
|
+
|
|
79
|
+
const WithDataAndBadgeMedium = Template.bind({})
|
|
80
|
+
WithDataAndBadgeMedium.args = { badge: true, size: 'medium', tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
81
|
+
WithDataAndBadgeMedium.decorators = [appThemeDecorator]
|
|
82
|
+
|
|
83
|
+
const WithDataAndBadgeLarge = Template.bind({})
|
|
84
|
+
WithDataAndBadgeLarge.args = { badge: true, size: 'large', tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
85
|
+
WithDataAndBadgeLarge.decorators = [appThemeDecorator]
|
|
86
|
+
|
|
87
|
+
const WithTip = Template.bind({})
|
|
88
|
+
WithTip.args = {
|
|
89
|
+
tip: 'This is the block hash',
|
|
90
|
+
title: 'Block Hash',
|
|
91
|
+
value: sampleBlockWithPayloads._hash,
|
|
92
|
+
}
|
|
93
|
+
WithTip.decorators = [appThemeDecorator]
|
|
94
|
+
|
|
95
|
+
const WithTipAndBadge = Template.bind({})
|
|
96
|
+
WithTipAndBadge.args = {
|
|
97
|
+
badge: true,
|
|
98
|
+
tip: 'This is the block hash',
|
|
99
|
+
title: 'Block Hash',
|
|
100
|
+
value: sampleBlockWithPayloads._hash,
|
|
101
|
+
}
|
|
102
|
+
WithTipAndBadge.decorators = [appThemeDecorator]
|
|
103
|
+
|
|
104
|
+
const WithActions = Template.bind({})
|
|
105
|
+
WithActions.args = {
|
|
106
|
+
actions: [{ name: 'ActionOne' }, { name: 'ActionTwo' }],
|
|
107
|
+
tip: 'This is the block hash',
|
|
108
|
+
title: 'Block Hash',
|
|
109
|
+
value: sampleBlockWithPayloads._hash,
|
|
110
|
+
}
|
|
111
|
+
WithActions.decorators = [appThemeDecorator]
|
|
112
|
+
|
|
113
|
+
const LargeWithValue = Template.bind({})
|
|
114
|
+
LargeWithValue.args = {
|
|
115
|
+
badge: true,
|
|
116
|
+
size: 'large',
|
|
117
|
+
tip: 'This is the block hash',
|
|
118
|
+
title: 'Block Hash',
|
|
119
|
+
value: sampleBlockWithPayloads._hash,
|
|
120
|
+
}
|
|
121
|
+
LargeWithValue.decorators = [appThemeDecorator]
|
|
122
|
+
|
|
123
|
+
const LargeWithValueAndActions = Template.bind({})
|
|
124
|
+
LargeWithValueAndActions.args = {
|
|
125
|
+
actions: [{ icon: <ReplayIcon />, name: 'ActionOne' }, { name: 'ActionTwo' }],
|
|
126
|
+
badge: true,
|
|
127
|
+
size: 'large',
|
|
128
|
+
tip: 'This is the block hash',
|
|
129
|
+
title: 'Block Hash',
|
|
130
|
+
value: sampleBlockWithPayloads._hash,
|
|
131
|
+
}
|
|
132
|
+
LargeWithValueAndActions.decorators = [appThemeDecorator]
|
|
133
|
+
|
|
134
|
+
const SmallWithValueAndActions = Template.bind({})
|
|
135
|
+
SmallWithValueAndActions.args = {
|
|
136
|
+
actions: [{ icon: <ReplayIcon />, name: 'ActionOne' }, { name: 'ActionTwo' }],
|
|
137
|
+
badge: true,
|
|
138
|
+
size: 'small',
|
|
139
|
+
tip: 'This is the block hash',
|
|
140
|
+
title: 'Block Hash',
|
|
141
|
+
value: sampleBlockWithPayloads._hash,
|
|
142
|
+
}
|
|
143
|
+
SmallWithValueAndActions.decorators = [appThemeDecorator]
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
Default,
|
|
147
|
+
LargeWithValue,
|
|
148
|
+
LargeWithValueAndActions,
|
|
149
|
+
SmallWithValueAndActions,
|
|
150
|
+
WithActions,
|
|
151
|
+
WithData,
|
|
152
|
+
WithDataAndBadgeLarge,
|
|
153
|
+
WithDataAndBadgeMedium,
|
|
154
|
+
WithDataAndBadgeSmall,
|
|
155
|
+
WithDataCompare,
|
|
156
|
+
WithDataSmall,
|
|
157
|
+
WithTip,
|
|
158
|
+
WithTipAndBadge,
|
|
159
|
+
WithUndefinedData,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// eslint-disable-next-line import/no-default-export
|
|
163
|
+
export default StorybookEntry
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import ReplayIcon from '@mui/icons-material/Replay'
|
|
2
|
+
import { TextField } from '@mui/material'
|
|
3
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react'
|
|
4
|
+
import { FlexCol, FlexRow } from '@xylabs/react-flexbox'
|
|
5
|
+
|
|
6
|
+
import { appThemeDecorator, sampleBlockWithPayloads } from '../../../../.storybook'
|
|
7
|
+
import { Property } from './Property'
|
|
8
|
+
import { PropertyPaperProps } from './Props'
|
|
9
|
+
|
|
10
|
+
const StorybookEntry = {
|
|
11
|
+
argTypes: {},
|
|
12
|
+
component: Property,
|
|
13
|
+
parameters: {
|
|
14
|
+
docs: {
|
|
15
|
+
page: null,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
title: 'property/PropertyPaper',
|
|
19
|
+
} as ComponentMeta<typeof Property>
|
|
20
|
+
|
|
21
|
+
const Template: ComponentStory<typeof Property> = (args) => <Property {...(args as PropertyPaperProps)} paper={true}></Property>
|
|
22
|
+
|
|
23
|
+
const TemplateWithCompare: ComponentStory<typeof Property> = (args) => (
|
|
24
|
+
<FlexCol gap={1} alignItems="stretch">
|
|
25
|
+
<FlexRow gap={1}>
|
|
26
|
+
<TextField size="small" value="Sample text Field" />
|
|
27
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="small"></Property>
|
|
28
|
+
</FlexRow>
|
|
29
|
+
<FlexRow gap={1}>
|
|
30
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="small"></Property>
|
|
31
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="small"></Property>
|
|
32
|
+
</FlexRow>
|
|
33
|
+
<FlexRow gap={1}>
|
|
34
|
+
<TextField size="medium" value="Sample text Field" />
|
|
35
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="medium"></Property>
|
|
36
|
+
</FlexRow>
|
|
37
|
+
<FlexRow gap={1}>
|
|
38
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="medium"></Property>
|
|
39
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="medium"></Property>
|
|
40
|
+
</FlexRow>
|
|
41
|
+
<FlexRow gap={1}>
|
|
42
|
+
<TextField value="Sample text Field" />
|
|
43
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="large"></Property>
|
|
44
|
+
</FlexRow>
|
|
45
|
+
<FlexRow gap={1}>
|
|
46
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="large"></Property>
|
|
47
|
+
<Property {...(args as PropertyPaperProps)} paper={true} size="large"></Property>
|
|
48
|
+
</FlexRow>
|
|
49
|
+
</FlexCol>
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
const Default = Template.bind({})
|
|
53
|
+
Default.args = {}
|
|
54
|
+
Default.decorators = [appThemeDecorator]
|
|
55
|
+
|
|
56
|
+
const WithTitle = Template.bind({})
|
|
57
|
+
WithTitle.args = { title: 'No Data' }
|
|
58
|
+
WithTitle.decorators = [appThemeDecorator]
|
|
59
|
+
|
|
60
|
+
const WithUndefinedData = Template.bind({})
|
|
61
|
+
WithUndefinedData.args = { title: 'Block Hash' }
|
|
62
|
+
WithUndefinedData.decorators = [appThemeDecorator]
|
|
63
|
+
|
|
64
|
+
const WithData = Template.bind({})
|
|
65
|
+
WithData.args = { title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
66
|
+
WithData.decorators = [appThemeDecorator]
|
|
67
|
+
|
|
68
|
+
const WithDataSmall = Template.bind({})
|
|
69
|
+
WithDataSmall.args = { size: 'small', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
70
|
+
WithDataSmall.decorators = [appThemeDecorator]
|
|
71
|
+
|
|
72
|
+
const WithDataCompare = TemplateWithCompare.bind({})
|
|
73
|
+
WithDataCompare.args = { tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
74
|
+
WithDataCompare.decorators = [appThemeDecorator]
|
|
75
|
+
|
|
76
|
+
const WithDataCompareOutlined = TemplateWithCompare.bind({})
|
|
77
|
+
WithDataCompareOutlined.args = { tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash, variant: 'outlined' }
|
|
78
|
+
WithDataCompareOutlined.decorators = [appThemeDecorator]
|
|
79
|
+
|
|
80
|
+
const WithDataCompareElevation = TemplateWithCompare.bind({})
|
|
81
|
+
WithDataCompareElevation.args = { tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash, variant: 'elevation' }
|
|
82
|
+
WithDataCompareElevation.decorators = [appThemeDecorator]
|
|
83
|
+
|
|
84
|
+
const WithDataAndBadgeSmall = Template.bind({})
|
|
85
|
+
WithDataAndBadgeSmall.args = { badge: true, size: 'small', tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
86
|
+
WithDataAndBadgeSmall.decorators = [appThemeDecorator]
|
|
87
|
+
|
|
88
|
+
const WithDataAndBadgeMedium = Template.bind({})
|
|
89
|
+
WithDataAndBadgeMedium.args = { badge: true, size: 'medium', tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
90
|
+
WithDataAndBadgeMedium.decorators = [appThemeDecorator]
|
|
91
|
+
|
|
92
|
+
const WithDataAndBadgeLarge = Template.bind({})
|
|
93
|
+
WithDataAndBadgeLarge.args = { badge: true, size: 'large', tip: 'This is the block hash', title: 'Block Hash', value: sampleBlockWithPayloads._hash }
|
|
94
|
+
WithDataAndBadgeLarge.decorators = [appThemeDecorator]
|
|
95
|
+
|
|
96
|
+
const WithTip = Template.bind({})
|
|
97
|
+
WithTip.args = {
|
|
98
|
+
tip: 'This is the block hash',
|
|
99
|
+
title: 'Block Hash',
|
|
100
|
+
value: sampleBlockWithPayloads._hash,
|
|
101
|
+
}
|
|
102
|
+
WithTip.decorators = [appThemeDecorator]
|
|
103
|
+
|
|
104
|
+
const WithTipAndBadge = Template.bind({})
|
|
105
|
+
WithTipAndBadge.args = {
|
|
106
|
+
badge: true,
|
|
107
|
+
tip: 'This is the block hash',
|
|
108
|
+
title: 'Block Hash',
|
|
109
|
+
value: sampleBlockWithPayloads._hash,
|
|
110
|
+
}
|
|
111
|
+
WithTipAndBadge.decorators = [appThemeDecorator]
|
|
112
|
+
|
|
113
|
+
const WithActions = Template.bind({})
|
|
114
|
+
WithActions.args = {
|
|
115
|
+
actions: [{ name: 'ActionOne' }, { name: 'ActionTwo' }],
|
|
116
|
+
tip: 'This is the block hash',
|
|
117
|
+
title: 'Block Hash',
|
|
118
|
+
value: sampleBlockWithPayloads._hash,
|
|
119
|
+
}
|
|
120
|
+
WithActions.decorators = [appThemeDecorator]
|
|
121
|
+
|
|
122
|
+
const LargeWithValue = Template.bind({})
|
|
123
|
+
LargeWithValue.args = {
|
|
124
|
+
badge: true,
|
|
125
|
+
size: 'large',
|
|
126
|
+
tip: 'This is the block hash',
|
|
127
|
+
title: 'Block Hash',
|
|
128
|
+
value: sampleBlockWithPayloads._hash,
|
|
129
|
+
}
|
|
130
|
+
LargeWithValue.decorators = [appThemeDecorator]
|
|
131
|
+
|
|
132
|
+
const LargeWithValueAndActions = Template.bind({})
|
|
133
|
+
LargeWithValueAndActions.args = {
|
|
134
|
+
actions: [{ icon: <ReplayIcon />, name: 'ActionOne' }, { name: 'ActionTwo' }],
|
|
135
|
+
badge: true,
|
|
136
|
+
size: 'large',
|
|
137
|
+
tip: 'This is the block hash',
|
|
138
|
+
title: 'Block Hash',
|
|
139
|
+
value: sampleBlockWithPayloads._hash,
|
|
140
|
+
}
|
|
141
|
+
LargeWithValueAndActions.decorators = [appThemeDecorator]
|
|
142
|
+
|
|
143
|
+
const SmallWithValueAndActions = Template.bind({})
|
|
144
|
+
SmallWithValueAndActions.args = {
|
|
145
|
+
actions: [{ icon: <ReplayIcon />, name: 'ActionOne' }, { name: 'ActionTwo' }],
|
|
146
|
+
badge: true,
|
|
147
|
+
size: 'small',
|
|
148
|
+
tip: 'This is the block hash',
|
|
149
|
+
title: 'Block Hash',
|
|
150
|
+
value: sampleBlockWithPayloads._hash,
|
|
151
|
+
}
|
|
152
|
+
SmallWithValueAndActions.decorators = [appThemeDecorator]
|
|
153
|
+
|
|
154
|
+
export {
|
|
155
|
+
Default,
|
|
156
|
+
LargeWithValue,
|
|
157
|
+
LargeWithValueAndActions,
|
|
158
|
+
SmallWithValueAndActions,
|
|
159
|
+
WithActions,
|
|
160
|
+
WithData,
|
|
161
|
+
WithDataAndBadgeLarge,
|
|
162
|
+
WithDataAndBadgeMedium,
|
|
163
|
+
WithDataAndBadgeSmall,
|
|
164
|
+
WithDataCompare,
|
|
165
|
+
WithDataCompareElevation,
|
|
166
|
+
WithDataCompareOutlined,
|
|
167
|
+
WithDataSmall,
|
|
168
|
+
WithTip,
|
|
169
|
+
WithTipAndBadge,
|
|
170
|
+
WithUndefinedData,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// eslint-disable-next-line import/no-default-export
|
|
174
|
+
export default StorybookEntry
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PaperProps } from '@mui/material'
|
|
2
|
+
import { FlexBoxProps } from '@xylabs/react-flexbox'
|
|
3
|
+
import { SizeProp } from '@xyo-network/react-shared'
|
|
4
|
+
import { ReactNode } from 'react'
|
|
5
|
+
|
|
6
|
+
import { PropertyAction } from './Action'
|
|
7
|
+
import { PropertyTitleProps } from './Title'
|
|
8
|
+
|
|
9
|
+
export interface PropertyBaseProps {
|
|
10
|
+
tip?: ReactNode
|
|
11
|
+
title?: string
|
|
12
|
+
paper?: boolean
|
|
13
|
+
titleProps?: PropertyTitleProps
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type PropertyFieldBaseProps = PropertyBaseProps & {
|
|
17
|
+
actions?: PropertyAction[]
|
|
18
|
+
required?: boolean
|
|
19
|
+
value?: string | number | boolean | null
|
|
20
|
+
badge?: boolean
|
|
21
|
+
size?: SizeProp
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type PropertyBoxProps = PropertyFieldBaseProps &
|
|
25
|
+
FlexBoxProps & {
|
|
26
|
+
paper?: false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type PropertyPaperProps = PropertyFieldBaseProps &
|
|
30
|
+
PaperProps & {
|
|
31
|
+
paper: true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type PropertyProps = PropertyBoxProps | PropertyPaperProps
|
|
35
|
+
|
|
36
|
+
export type PropertyGroupBaseProps = PropertyBaseProps
|
|
37
|
+
|
|
38
|
+
export type PropertyGroupBoxProps = PropertyGroupBaseProps &
|
|
39
|
+
FlexBoxProps & {
|
|
40
|
+
paper?: false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type PropertyGroupPaperProps = PropertyGroupBaseProps &
|
|
44
|
+
PaperProps & {
|
|
45
|
+
paper: true
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type PropertyGroupProps = PropertyGroupBoxProps | PropertyGroupPaperProps
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import { PropertyTitle } from './Title'
|
|
4
|
+
|
|
5
|
+
const StorybookEntry = {
|
|
6
|
+
argTypes: {},
|
|
7
|
+
component: PropertyTitle,
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
page: null,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
title: 'property/Title',
|
|
14
|
+
} as ComponentMeta<typeof PropertyTitle>
|
|
15
|
+
|
|
16
|
+
const Template: ComponentStory<typeof PropertyTitle> = (args) => <PropertyTitle {...args}></PropertyTitle>
|
|
17
|
+
|
|
18
|
+
const Default = Template.bind({})
|
|
19
|
+
Default.args = {}
|
|
20
|
+
|
|
21
|
+
const WithData = Template.bind({})
|
|
22
|
+
|
|
23
|
+
WithData.args = { title: 'Sample Title' }
|
|
24
|
+
|
|
25
|
+
const WithDataAndActions = Template.bind({})
|
|
26
|
+
|
|
27
|
+
WithDataAndActions.args = { title: 'Sample Title' }
|
|
28
|
+
|
|
29
|
+
export { Default, WithData, WithDataAndActions }
|
|
30
|
+
|
|
31
|
+
// eslint-disable-next-line import/no-default-export
|
|
32
|
+
export default StorybookEntry
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { darken, lighten, Typography, TypographyVariant, useTheme } from '@mui/material'
|
|
2
|
+
import { FlexBoxProps, FlexRow } from '@xylabs/react-flexbox'
|
|
3
|
+
import { QuickTipButton } from '@xylabs/react-quick-tip-button'
|
|
4
|
+
import { SizeProp } from '@xyo-network/react-shared'
|
|
5
|
+
import { ReactNode } from 'react'
|
|
6
|
+
|
|
7
|
+
type TitleSizeProp = SizeProp | 'full'
|
|
8
|
+
|
|
9
|
+
export interface PropertyTitleProps extends FlexBoxProps {
|
|
10
|
+
tip?: ReactNode
|
|
11
|
+
more?: ReactNode
|
|
12
|
+
title?: string
|
|
13
|
+
size?: TitleSizeProp
|
|
14
|
+
elevation?: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const PropertyTitle: React.FC<PropertyTitleProps> = ({ elevation = 1, size = 'medium', tip, more, title, ...props }) => {
|
|
18
|
+
const sizeVariants: Record<TitleSizeProp, TypographyVariant> = {
|
|
19
|
+
full: 'caption',
|
|
20
|
+
large: 'caption',
|
|
21
|
+
medium: 'caption',
|
|
22
|
+
small: 'caption',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sizeTitleHeight: Record<TitleSizeProp, number | undefined> = {
|
|
26
|
+
full: undefined,
|
|
27
|
+
large: 32,
|
|
28
|
+
medium: 20,
|
|
29
|
+
small: 16,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const sizeFontSize: Record<TitleSizeProp, number> = {
|
|
33
|
+
full: 16,
|
|
34
|
+
large: 16,
|
|
35
|
+
medium: 14,
|
|
36
|
+
small: 10,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const quickTipSize = sizeFontSize[size] < 16 ? sizeFontSize[size] : 16
|
|
40
|
+
|
|
41
|
+
const theme = useTheme()
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<FlexRow
|
|
45
|
+
bgcolor={theme.palette.mode === 'dark' ? lighten(theme.palette.background.paper, 0.05 * elevation) : darken(theme.palette.background.paper, 0.025 * elevation)}
|
|
46
|
+
alignItems="center"
|
|
47
|
+
height={sizeTitleHeight[size]}
|
|
48
|
+
justifyContent="space-between"
|
|
49
|
+
{...props}
|
|
50
|
+
>
|
|
51
|
+
<FlexRow paddingX={1} paddingY={0.5}>
|
|
52
|
+
<Typography fontWeight={500} noWrap variant={sizeVariants[size]} fontSize={sizeFontSize[size]}>
|
|
53
|
+
<small>
|
|
54
|
+
<strong>{title}</strong>
|
|
55
|
+
</small>
|
|
56
|
+
</Typography>
|
|
57
|
+
{tip ? (
|
|
58
|
+
<QuickTipButton style={{ fontSize: quickTipSize }} color="inherit" title={title ?? ''}>
|
|
59
|
+
{tip}
|
|
60
|
+
</QuickTipButton>
|
|
61
|
+
) : null}
|
|
62
|
+
</FlexRow>
|
|
63
|
+
{more}
|
|
64
|
+
</FlexRow>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ComponentMeta, ComponentStory } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
import { sampleBlockWithPayloads } from '../../../../.storybook'
|
|
4
|
+
import { PropertyValue } from './Value'
|
|
5
|
+
|
|
6
|
+
const StorybookEntry = {
|
|
7
|
+
argTypes: {},
|
|
8
|
+
component: PropertyValue,
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
page: null,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
title: 'property/Value',
|
|
15
|
+
} as ComponentMeta<typeof PropertyValue>
|
|
16
|
+
|
|
17
|
+
const Template: ComponentStory<typeof PropertyValue> = (args) => <PropertyValue {...args}></PropertyValue>
|
|
18
|
+
|
|
19
|
+
const Default = Template.bind({})
|
|
20
|
+
Default.args = {}
|
|
21
|
+
|
|
22
|
+
const WithData = Template.bind({})
|
|
23
|
+
|
|
24
|
+
WithData.args = { value: sampleBlockWithPayloads._hash }
|
|
25
|
+
|
|
26
|
+
export { Default, WithData }
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line import/no-default-export
|
|
29
|
+
export default StorybookEntry
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Typography, TypographyProps, useTheme } from '@mui/material'
|
|
2
|
+
import { Variant } from '@mui/material/styles/createTypography'
|
|
3
|
+
import { useEffect, useRef, useState } from 'react'
|
|
4
|
+
|
|
5
|
+
export interface PropertyValueProps extends TypographyProps<'div'> {
|
|
6
|
+
value?: string | number | boolean | null
|
|
7
|
+
typographyVariant?: Variant
|
|
8
|
+
/** @field The space that is removed from the ... at end (mainly for identicon) */
|
|
9
|
+
shortSpace?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const PropertyValue: React.FC<PropertyValueProps> = ({ value, shortSpace, typographyVariant = 'body1', ...props }) => {
|
|
13
|
+
const [parentWidth, setParentWidth] = useState<number>()
|
|
14
|
+
const theme = useTheme()
|
|
15
|
+
|
|
16
|
+
const ref = useRef<HTMLDivElement>(null)
|
|
17
|
+
|
|
18
|
+
const customThemeProps = {
|
|
19
|
+
clamped: parentWidth && theme ? parentWidth - parseInt(theme.spacing(2), 10) - (shortSpace ?? 0) : undefined,
|
|
20
|
+
title: value?.toString(),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const resizeHandler = () => {
|
|
25
|
+
const smallestWidth = getSmallestParentWidth(ref.current)
|
|
26
|
+
setParentWidth(smallestWidth)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const getSmallestParentWidth = (element: HTMLElement | null) => {
|
|
30
|
+
let current = element?.parentElement
|
|
31
|
+
let width: number | null = null
|
|
32
|
+
while (current) {
|
|
33
|
+
if (width === null || current.clientWidth < width) {
|
|
34
|
+
width = current.clientWidth
|
|
35
|
+
}
|
|
36
|
+
current = current.parentElement
|
|
37
|
+
}
|
|
38
|
+
return width ?? undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
window.addEventListener('resize', resizeHandler)
|
|
42
|
+
|
|
43
|
+
setParentWidth(getSmallestParentWidth(ref.current))
|
|
44
|
+
|
|
45
|
+
return () => {
|
|
46
|
+
window?.removeEventListener('resize', resizeHandler)
|
|
47
|
+
}
|
|
48
|
+
}, [])
|
|
49
|
+
|
|
50
|
+
return value !== undefined ? (
|
|
51
|
+
<Typography minWidth={0} ref={ref} component="div" variant={typographyVariant} fontFamily="monospace" fontWeight="light" {...customThemeProps} {...props}>
|
|
52
|
+
{value}
|
|
53
|
+
</Typography>
|
|
54
|
+
) : null
|
|
55
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components'
|