@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 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/eeec410/packages/property/src/index.ts#L1"
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.37",
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.37"
83
+ "version": "2.26.40"
84
84
  }
@@ -0,0 +1,8 @@
1
+ import { ReactNode } from 'react'
2
+
3
+ export interface PropertyAction {
4
+ disabled?: boolean
5
+ name: string
6
+ icon?: ReactNode
7
+ onClick?: () => void
8
+ }
@@ -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,8 @@
1
+ import { FlexBoxProps } from '@xylabs/react-flexbox'
2
+
3
+ import { PropertyAction } from './Action'
4
+
5
+ export interface PropertyActionsProps extends FlexBoxProps {
6
+ buttons?: boolean
7
+ actions?: PropertyAction[]
8
+ }
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ export * from './Action'
2
+ export * from './Group'
3
+ export * from './Property'
4
+ export * from './Props'
5
+ export * from './Value'
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './components'