@chem-po/react-web 0.0.5 → 0.0.6

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.
Files changed (123) hide show
  1. package/dist/index.cjs +2 -2
  2. package/dist/index.js +2 -2
  3. package/package.json +22 -20
  4. package/src/components/auth/SignIn.tsx +43 -0
  5. package/src/components/auth/index.ts +1 -0
  6. package/src/components/box/CollapseHorizontal.tsx +18 -0
  7. package/src/components/box/ContentBox.tsx +17 -0
  8. package/src/components/box/ExpandOnMount.tsx +48 -0
  9. package/src/components/box/Expandable.tsx +96 -0
  10. package/src/components/box/FullSizeContainer.tsx +50 -0
  11. package/src/components/box/MobileFrame/index.tsx +145 -0
  12. package/src/components/box/MobileFrame/styles.css +35 -0
  13. package/src/components/box/index.ts +6 -0
  14. package/src/components/button/DeleteButton.tsx +178 -0
  15. package/src/components/button/Toggle.tsx +88 -0
  16. package/src/components/button/ViewButton.tsx +30 -0
  17. package/src/components/button/index.ts +3 -0
  18. package/src/components/feed/FeedContentPane.tsx +111 -0
  19. package/src/components/feed/MediaFeed.tsx +200 -0
  20. package/src/components/feed/MediaFeedBackground.tsx +127 -0
  21. package/src/components/feed/MediaFeedRefresh.tsx +78 -0
  22. package/src/components/feed/MediaFeedSwipeUp.tsx +34 -0
  23. package/src/components/feed/constants.ts +11 -0
  24. package/src/components/feed/context.tsx +19 -0
  25. package/src/components/feed/hooks.ts +290 -0
  26. package/src/components/feed/index.ts +2 -0
  27. package/src/components/feed/types.ts +50 -0
  28. package/src/components/form/Condition.tsx +26 -0
  29. package/src/components/form/Field.tsx +39 -0
  30. package/src/components/form/Form.tsx +425 -0
  31. package/src/components/form/FormFooter.tsx +82 -0
  32. package/src/components/form/UploadProgress/index.tsx +38 -0
  33. package/src/components/form/UploadProgress/styles.css +23 -0
  34. package/src/components/form/index.ts +4 -0
  35. package/src/components/form/input/Editable.tsx +129 -0
  36. package/src/components/form/input/InputSlider.tsx +75 -0
  37. package/src/components/form/input/OptionalTag.tsx +33 -0
  38. package/src/components/form/input/StandaloneInput.tsx +41 -0
  39. package/src/components/form/input/boolean/index.tsx +53 -0
  40. package/src/components/form/input/color/index.tsx +126 -0
  41. package/src/components/form/input/date/index.tsx +122 -0
  42. package/src/components/form/input/datetime/index.tsx +93 -0
  43. package/src/components/form/input/file.tsx +379 -0
  44. package/src/components/form/input/hooks/index.ts +2 -0
  45. package/src/components/form/input/hooks/useInputImperativeHandle.ts +16 -0
  46. package/src/components/form/input/hooks/useInputStyle.ts +39 -0
  47. package/src/components/form/input/index.ts +2 -0
  48. package/src/components/form/input/input.css +44 -0
  49. package/src/components/form/input/input.tsx +130 -0
  50. package/src/components/form/input/multipleSelect/index.tsx +55 -0
  51. package/src/components/form/input/number/index.tsx +83 -0
  52. package/src/components/form/input/number/styles.css +8 -0
  53. package/src/components/form/input/select/index.tsx +80 -0
  54. package/src/components/form/input/socialMedia/index.tsx +158 -0
  55. package/src/components/form/input/text/index.tsx +72 -0
  56. package/src/components/form/input/text/textarea.tsx +44 -0
  57. package/src/components/form/input/time/index.tsx +33 -0
  58. package/src/components/form/input/type.ts +0 -0
  59. package/src/components/form/input/types.ts +4 -0
  60. package/src/components/form/view/file.tsx +45 -0
  61. package/src/components/form/view/index.tsx +61 -0
  62. package/src/components/form/view/multipleSelect.tsx +38 -0
  63. package/src/components/form/view/select.tsx +33 -0
  64. package/src/components/index.ts +14 -0
  65. package/src/components/list/Body/InfiniteScrollGridBody.tsx +177 -0
  66. package/src/components/list/Body/InfiniteScrollListBody.tsx +114 -0
  67. package/src/components/list/Body/ListBody.tsx +23 -0
  68. package/src/components/list/Body/PagedGridBody.tsx +104 -0
  69. package/src/components/list/Body/PagedListBody.tsx +92 -0
  70. package/src/components/list/Body/hooks.ts +84 -0
  71. package/src/components/list/DataList.tsx +32 -0
  72. package/src/components/list/ListContainer.tsx +20 -0
  73. package/src/components/list/ListContent.tsx +54 -0
  74. package/src/components/list/ListCreate.tsx +57 -0
  75. package/src/components/list/ListFilters.tsx +182 -0
  76. package/src/components/list/ListFooter.tsx +458 -0
  77. package/src/components/list/ListHeader.tsx +180 -0
  78. package/src/components/list/ListItem/ListCell.tsx +48 -0
  79. package/src/components/list/ListItem/ListRow.tsx +38 -0
  80. package/src/components/list/ListItemView.tsx +53 -0
  81. package/src/components/list/ListSort.tsx +84 -0
  82. package/src/components/list/NoItems.tsx +33 -0
  83. package/src/components/list/constants.ts +1 -0
  84. package/src/components/list/index.ts +4 -0
  85. package/src/components/list/types.ts +29 -0
  86. package/src/components/list/utils.ts +62 -0
  87. package/src/components/loading/CircularProgress.tsx +11 -0
  88. package/src/components/loading/Loading.tsx +160 -0
  89. package/src/components/loading/LoadingImage.tsx +123 -0
  90. package/src/components/loading/LoadingSwitch.tsx +78 -0
  91. package/src/components/loading/index.ts +4 -0
  92. package/src/components/media/PlayButton.tsx +94 -0
  93. package/src/components/media/index.ts +1 -0
  94. package/src/components/modal/DefaultModal.tsx +18 -0
  95. package/src/components/modal/DesktopModal.tsx +11 -0
  96. package/src/components/modal/ForceMobile.tsx +7 -0
  97. package/src/components/modal/MobileModal.tsx +89 -0
  98. package/src/components/modal/index.ts +3 -0
  99. package/src/components/modal/type.ts +7 -0
  100. package/src/components/nav/NavBar.tsx +101 -0
  101. package/src/components/nav/index.ts +1 -0
  102. package/src/components/overlay/ImageViewOverlay.tsx +88 -0
  103. package/src/components/overlay/MobileOverlay.tsx +22 -0
  104. package/src/components/overlay/index.ts +2 -0
  105. package/src/components/text/GradientText/index.tsx +16 -0
  106. package/src/components/text/GradientText/styles.css +5 -0
  107. package/src/components/text/NumberTicker.tsx +28 -0
  108. package/src/components/text/index.ts +1 -0
  109. package/src/components/theme/colorMode/DarkModeToggle.tsx +40 -0
  110. package/src/components/theme/colorMode/index.ts +1 -0
  111. package/src/components/theme/index.ts +1 -0
  112. package/src/components/view/ErrorView.tsx +13 -0
  113. package/src/components/view/RedirectView.tsx +42 -0
  114. package/src/components/view/index.ts +2 -0
  115. package/src/contexts/index.ts +1 -0
  116. package/src/contexts/theme.ts +316 -0
  117. package/src/custom.d.ts +4 -0
  118. package/src/hooks/index.ts +1 -0
  119. package/src/hooks/ui/index.ts +1 -0
  120. package/src/hooks/ui/useBorderColor.ts +4 -0
  121. package/src/store/index.ts +1 -0
  122. package/src/store/usePlayer.ts +75 -0
  123. package/src/store/useScreen.ts +22 -0
@@ -0,0 +1,83 @@
1
+ import { useColorModeValue } from '@chakra-ui/react'
2
+ import { InputRef } from '@chem-po/core'
3
+ import { CurrencyAmountField, NumberField } from '@chem-po/react'
4
+ import { ForwardedRef, forwardRef, useImperativeHandle, useRef, useState } from 'react'
5
+ import CurrencyInput from 'react-currency-input-field'
6
+ import { InputSlider } from '../InputSlider'
7
+ import { useInputImperativeHandle } from '../hooks/useInputImperativeHandle'
8
+ import { useInputStyle } from '../hooks/useInputStyle'
9
+ import { FieldProps } from '../types'
10
+ import './styles.css'
11
+
12
+ export const NumberComponent = forwardRef<InputRef, FieldProps<NumberField> & { prefix?: string }>(
13
+ ({ input: { onChange, value, ...input }, field, size, prefix, inEditable: _, ...props }, ref) => {
14
+ const { type, defaultValue, placeholder } = field
15
+ const className = useColorModeValue('number-input', 'number-input-dark')
16
+ const style = useInputStyle(size)
17
+ const inputRef = useInputImperativeHandle(ref)
18
+ const [endsWith, setEndsWith] = useState('')
19
+ const displayed = typeof value === 'number' && !Number.isNaN(value) ? `${value}${endsWith}` : ''
20
+ if (type === 'slider') {
21
+ return (
22
+ <InputSlider
23
+ label={placeholder}
24
+ onChange={onChange}
25
+ value={value}
26
+ defaultValue={defaultValue}
27
+ />
28
+ )
29
+ }
30
+ return (
31
+ <CurrencyInput
32
+ className={className}
33
+ placeholder={field.placeholder}
34
+ decimalsLimit={field.precision}
35
+ allowDecimals={!!field.precision}
36
+ prefix={prefix}
37
+ ref={inputRef}
38
+ onValueChange={(v, _, values) => {
39
+ if (v?.endsWith('.')) setEndsWith('.')
40
+ else if (v?.includes('.') && v?.endsWith('0')) setEndsWith('0')
41
+ else setEndsWith('')
42
+ onChange(values?.float)
43
+ }}
44
+ value={displayed}
45
+ {...props}
46
+ style={{
47
+ background: 'none',
48
+ // height: 'auto',
49
+ resize: 'none',
50
+ fontFamily: 'Encode Sans',
51
+ boxSizing: 'border-box',
52
+ width: '100%',
53
+ borderRadius: '4px',
54
+ border: 'none',
55
+ outline: 'none',
56
+ ...style,
57
+ ...props.style,
58
+ }}
59
+ {...input}
60
+ />
61
+ )
62
+ },
63
+ )
64
+ const BaseCurrencyAmountComponent = (
65
+ { field, ...props }: FieldProps<CurrencyAmountField>,
66
+ ref: ForwardedRef<InputRef>,
67
+ ) => {
68
+ const inputRef = useRef<HTMLInputElement>(null)
69
+
70
+ useImperativeHandle(ref, () => ({
71
+ focus: () => {
72
+ inputRef.current?.focus()
73
+ },
74
+ blur: () => {
75
+ inputRef.current?.blur()
76
+ },
77
+ }))
78
+ return <NumberComponent prefix="$" field={{ ...field, _type: 'number' }} {...props} />
79
+ }
80
+
81
+ export const CurrencyAmountComponent = forwardRef<InputRef, FieldProps<CurrencyAmountField>>(
82
+ BaseCurrencyAmountComponent as any,
83
+ )
@@ -0,0 +1,8 @@
1
+ .number-input::placeholder {
2
+ opacity: 0.7;
3
+ color: #000;
4
+ }
5
+ .number-input-dark::placeholder {
6
+ opacity: 0.7;
7
+ color: white;
8
+ }
@@ -0,0 +1,80 @@
1
+ import {
2
+ Box,
3
+ Button,
4
+ Popover,
5
+ PopoverArrow,
6
+ PopoverBody,
7
+ PopoverContent,
8
+ PopoverTrigger,
9
+ Text,
10
+ useColorMode,
11
+ } from '@chakra-ui/react'
12
+ import { InputRef } from '@chem-po/core'
13
+ import { SelectField } from '@chem-po/react'
14
+ import { forwardRef, useImperativeHandle, useMemo } from 'react'
15
+ import { FieldProps } from '../types'
16
+
17
+ const DefaultRenderOption = (value: any) => {
18
+ return <Text>{typeof value === 'string' ? value : JSON.stringify(value)}</Text>
19
+ }
20
+
21
+ export const SelectComponent = forwardRef<InputRef, FieldProps<SelectField>>(
22
+ ({ field, input, meta }, ref) => {
23
+ const { placeholder, options, renderOption: customRender, getOptionKey } = field
24
+ const { onChange, value, onFocus, onBlur } = input
25
+ const { active } = meta
26
+ const selected = useMemo(() => value && options.find(o => o === value), [value, options])
27
+ const { colorMode } = useColorMode()
28
+ useImperativeHandle(ref, () => ({
29
+ focus: () => {
30
+ onFocus()
31
+ },
32
+ blur: () => {
33
+ onBlur()
34
+ },
35
+ }))
36
+
37
+ const renderOption = customRender ?? DefaultRenderOption
38
+
39
+ return (
40
+ <Popover strategy="fixed" placement="bottom" matchWidth isOpen={active} onClose={onBlur}>
41
+ <PopoverTrigger>
42
+ <Button
43
+ fontWeight={500}
44
+ w="100%"
45
+ opacity={value ? 1 : 0.7}
46
+ onClick={e => {
47
+ e.stopPropagation()
48
+ onFocus()
49
+ }}
50
+ variant="unstyled"
51
+ position="relative">
52
+ <Box>{selected ? renderOption(selected, colorMode, true) : placeholder}</Box>
53
+ </Button>
54
+ </PopoverTrigger>
55
+ <PopoverContent w="100%" overflowY="auto" maxH="300px">
56
+ <PopoverBody p={0}>
57
+ {options.map(o => (
58
+ <Button
59
+ key={getOptionKey ? getOptionKey(o) : o}
60
+ w="100%"
61
+ variant="unstyled"
62
+ onClick={e => {
63
+ e.stopPropagation()
64
+ onChange(o)
65
+ onBlur()
66
+ }}
67
+ _hover={{ bg: 'blackAlpha.100' }}
68
+ _dark={{
69
+ _hover: { bg: 'whiteAlpha.100' },
70
+ }}>
71
+ {renderOption(o, colorMode, o === selected)}
72
+ </Button>
73
+ ))}
74
+ </PopoverBody>
75
+ <PopoverArrow />
76
+ </PopoverContent>
77
+ </Popover>
78
+ )
79
+ },
80
+ )
@@ -0,0 +1,158 @@
1
+ import {
2
+ Center,
3
+ Collapse,
4
+ HStack,
5
+ Image,
6
+ Input,
7
+ Popover,
8
+ PopoverBody,
9
+ PopoverContent,
10
+ PopoverTrigger,
11
+ Text,
12
+ VStack,
13
+ } from '@chakra-ui/react'
14
+
15
+ import { getHandle, InputRef, SocialMediaSites } from '@chem-po/core'
16
+ import { SocialMediaField } from '@chem-po/react'
17
+ import { FC, ForwardedRef, forwardRef, useCallback, useImperativeHandle, useMemo } from 'react'
18
+ import { FieldProps } from '../types'
19
+
20
+ const facebookLogo = '/icons/facebook.svg'
21
+ const instagramLogo = '/icons/instagram.svg'
22
+ const soundcloudLogo = '/icons/soundcloud.svg'
23
+ const twitterLogo = '/icons/twitter.svg'
24
+ const youtubeLogo = '/icons/youtube.svg'
25
+
26
+ const siteToIcon: Record<SocialMediaSites, any> = {
27
+ facebook: facebookLogo,
28
+ instagram: instagramLogo,
29
+ twitter: twitterLogo,
30
+ youtube: youtubeLogo,
31
+ soundcloud: soundcloudLogo,
32
+ }
33
+
34
+ const SocialMediaSiteInput: FC<{
35
+ site: SocialMediaSites
36
+ value?: string
37
+ onChange: (v?: string) => void
38
+ }> = ({ site, value, onChange }) => {
39
+ const { handle, error } = useMemo(() => {
40
+ try {
41
+ const h = getHandle(site, value)
42
+ return { handle: h }
43
+ } catch (e: any) {
44
+ return { error: e?.message ?? 'Error parsing handle' }
45
+ }
46
+ }, [value, site])
47
+ const displayedText = useMemo(
48
+ () => (handle ? `${site.toUpperCase()}: ${handle}` : site.toUpperCase()),
49
+ [site, handle],
50
+ )
51
+ return (
52
+ <Popover trigger="hover">
53
+ <PopoverTrigger>
54
+ <Center opacity={handle ? 1 : 0.6} borderRadius="full" width="34px" height="34px">
55
+ <Image
56
+ cursor="pointer"
57
+ filter={`grayscale(${handle ? 0 : 100}%)`}
58
+ height="24px"
59
+ width="24px"
60
+ objectFit="contain"
61
+ src={siteToIcon[site]}
62
+ />
63
+ </Center>
64
+ </PopoverTrigger>
65
+ <PopoverContent w="auto">
66
+ <PopoverBody overflow="hidden" borderRadius={4} p={0} w="auto">
67
+ <VStack spacing={0} p={2} w="300px" align="flex-start">
68
+ <Text fontSize="md">{displayedText}</Text>
69
+
70
+ <Collapse in={!!error} style={{ width: '100%' }}>
71
+ <Text px={1} bg="red.500" fontSize="sm" color="white">
72
+ {error}
73
+ </Text>
74
+ </Collapse>
75
+ <Input
76
+ onChange={e => onChange(e.target.value)}
77
+ placeholder="Handle or URL"
78
+ width="100%"
79
+ value={value}
80
+ size="md"
81
+ />
82
+ </VStack>
83
+ </PopoverBody>
84
+ </PopoverContent>
85
+ </Popover>
86
+ )
87
+ }
88
+ export const SocialMediaComponent = forwardRef<InputRef, FieldProps<SocialMediaField>>(
89
+ (props: FieldProps<SocialMediaField>, ref: ForwardedRef<InputRef>) => {
90
+ const {
91
+ input: { value, onChange },
92
+ field: { sites },
93
+ } = props
94
+ const handleChange = useCallback(
95
+ (site: SocialMediaSites, v?: string) => {
96
+ const { [site]: _curr, ...rest } = value ?? {}
97
+ if (!v && Object.keys(rest).length === 0) {
98
+ onChange({ target: { value: undefined } })
99
+ }
100
+ if (!v) onChange(rest)
101
+ onChange({ ...rest, [site]: v })
102
+ },
103
+ [onChange, value],
104
+ )
105
+
106
+ useImperativeHandle(ref, () => ({
107
+ blur: () => {},
108
+ focus: () => {},
109
+ }))
110
+
111
+ return (
112
+ <VStack w="100%" p={1}>
113
+ <VStack borderRadius={4} p={2} spacing={0} w="100%">
114
+ <Text fontSize="md">Links</Text>
115
+ <HStack>
116
+ {!sites || sites.facebook ? (
117
+ <SocialMediaSiteInput
118
+ onChange={v => handleChange('facebook', v)}
119
+ site="facebook"
120
+ value={value?.facebook}
121
+ />
122
+ ) : null}
123
+ {!sites || sites.instagram ? (
124
+ <SocialMediaSiteInput
125
+ onChange={v => handleChange('instagram', v)}
126
+ site="instagram"
127
+ value={value?.instagram}
128
+ />
129
+ ) : null}
130
+ {!sites || sites.twitter ? (
131
+ <SocialMediaSiteInput
132
+ onChange={v => handleChange('twitter', v)}
133
+ site="twitter"
134
+ value={value?.twitter}
135
+ />
136
+ ) : null}
137
+ {!sites || sites.youtube ? (
138
+ <SocialMediaSiteInput
139
+ onChange={v => handleChange('youtube', v)}
140
+ site="youtube"
141
+ value={value?.youtube}
142
+ />
143
+ ) : null}
144
+ {!sites || sites.soundcloud ? (
145
+ <SocialMediaSiteInput
146
+ onChange={v => handleChange('soundcloud', v)}
147
+ site="soundcloud"
148
+ value={value?.soundcloud}
149
+ />
150
+ ) : null}
151
+ </HStack>
152
+ </VStack>
153
+ </VStack>
154
+ )
155
+ },
156
+ )
157
+
158
+ SocialMediaComponent.displayName = 'SocialMediaComponent'
@@ -0,0 +1,72 @@
1
+ import { ViewIcon, ViewOffIcon } from '@chakra-ui/icons'
2
+ import { Flex, IconButton, Input } from '@chakra-ui/react'
3
+ import { InputRef } from '@chem-po/core'
4
+ import { TextField } from '@chem-po/react'
5
+ import { forwardRef, useImperativeHandle, useRef, useState } from 'react'
6
+ import { FieldProps } from '../types'
7
+ import { TextAreaComponent } from './textarea'
8
+
9
+ export const TextComponent = forwardRef<InputRef, FieldProps<TextField>>(
10
+ ({ input, inEditable, meta, field }, ref) => {
11
+ const { placeholder, type } = field
12
+ const [isHidden, setIsHidden] = useState(type === 'password')
13
+ const { value } = input
14
+ const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null)
15
+
16
+ useImperativeHandle(ref, () => ({
17
+ focus: () => {
18
+ inputRef.current?.focus()
19
+ },
20
+ blur: () => {
21
+ inputRef.current?.blur()
22
+ },
23
+ }))
24
+ const body =
25
+ type === 'textarea' ? (
26
+ <TextAreaComponent inEditable={inEditable} field={field} input={input} meta={meta} />
27
+ ) : (
28
+ <Input
29
+ ref={inputRef as any}
30
+ border="none"
31
+ _dark={{
32
+ border: 'none',
33
+ }}
34
+ borderRadius={0}
35
+ px={inEditable ? 0 : 3}
36
+ background="transparent"
37
+ _focus={{
38
+ border: 'none',
39
+ }}
40
+ py={inEditable ? 0 : 0.5}
41
+ type={isHidden ? 'password' : 'text'}
42
+ height={inEditable ? 'auto' : 10}
43
+ placeholder={placeholder}
44
+ {...input}
45
+ onChange={e => {
46
+ input.onChange({ target: { value: e.target.value } })
47
+ }}
48
+ value={value ?? ''}
49
+ />
50
+ )
51
+
52
+ return type === 'password' ? (
53
+ <Flex width="100%" position="relative" align="center">
54
+ {body}
55
+ <IconButton
56
+ position="absolute"
57
+ right={2}
58
+ onClick={() => setIsHidden(!isHidden)}
59
+ variant="ghost"
60
+ icon={isHidden ? <ViewIcon /> : <ViewOffIcon />}
61
+ aria-label={isHidden ? 'show' : 'hide'}
62
+ title={isHidden ? 'Show' : 'Hide'}
63
+ size="xs"
64
+ />
65
+ </Flex>
66
+ ) : (
67
+ body
68
+ )
69
+ },
70
+ )
71
+
72
+ TextComponent.displayName = 'TextComponent'
@@ -0,0 +1,44 @@
1
+ import { InputRef } from '@chem-po/core'
2
+ import { TextField, useTextColor } from '@chem-po/react'
3
+ import { ForwardedRef, forwardRef, useImperativeHandle, useRef } from 'react'
4
+ import TextareaAutosize from 'react-textarea-autosize'
5
+ import { FieldProps } from '../types'
6
+
7
+ export const TextAreaComponent = forwardRef<InputRef, FieldProps<TextField>>(
8
+ ({ input, field, inEditable }, ref: ForwardedRef<InputRef>) => {
9
+ const textColor = useTextColor()
10
+ const inputRef = useRef<HTMLTextAreaElement>(null)
11
+ useImperativeHandle(ref, () => ({
12
+ focus: () => {
13
+ inputRef.current?.focus()
14
+ },
15
+ blur: () => {
16
+ inputRef.current?.blur()
17
+ },
18
+ }))
19
+ return (
20
+ <TextareaAutosize
21
+ placeholder={field.placeholder}
22
+ minRows={2}
23
+ maxRows={5}
24
+ ref={inputRef}
25
+ style={{
26
+ // height: 'auto',
27
+ resize: 'none',
28
+ width: '100%',
29
+ color: textColor,
30
+ background: 'none',
31
+ fontFamily: 'fonts.body',
32
+ boxSizing: 'border-box',
33
+ borderRadius: '4px',
34
+ padding: inEditable ? 0 : '0.6rem 1rem',
35
+ border: 'none',
36
+ outline: 'none',
37
+ }}
38
+ {...input}
39
+ />
40
+ )
41
+ },
42
+ )
43
+
44
+ TextAreaComponent.displayName = 'TextAreaComponent'
@@ -0,0 +1,33 @@
1
+ import { Input } from '@chakra-ui/react'
2
+ import { InputRef } from '@chem-po/core'
3
+ import { TimeField } from '@chem-po/react'
4
+ import { forwardRef, useImperativeHandle } from 'react'
5
+ import { FieldProps } from '../types'
6
+ // import '../input.css'
7
+
8
+ export const TimeInput = forwardRef<InputRef, FieldProps<TimeField>>(
9
+ ({ field, input }: FieldProps<TimeField>, ref) => {
10
+ useImperativeHandle(ref, () => ({
11
+ focus: () => {},
12
+ blur: () => {},
13
+ }))
14
+ return (
15
+ <Input
16
+ fontFamily="Public Sans"
17
+ css={`
18
+ ::-webkit-calendar-picker-indicator {
19
+ background: url(/svg/clock.svg) center/80% no-repeat;
20
+ color: white;
21
+ }
22
+ `}
23
+ fontSize="md"
24
+ type="time"
25
+ placeholder={field.placeholder}
26
+ {...input}
27
+ value={input.value ?? ''}
28
+ />
29
+ )
30
+ },
31
+ )
32
+
33
+ TimeInput.displayName = 'TimeInput'
File without changes
@@ -0,0 +1,4 @@
1
+ import { BaseFieldProps, Field } from '@chem-po/react'
2
+ import { CSSProperties } from 'react'
3
+
4
+ export type FieldProps<T extends Field> = BaseFieldProps<CSSProperties, T>
@@ -0,0 +1,45 @@
1
+ import { Box, Flex, Text } from '@chakra-ui/react'
2
+ import { ImageViewOptions } from '@chem-po/core'
3
+ import { FileField } from '@chem-po/react'
4
+ import { CSSProperties, useMemo } from 'react'
5
+ import { ExpandOnMount } from '../../box/ExpandOnMount'
6
+ import { FileView } from '../input/file'
7
+
8
+ export const FileFieldView = ({
9
+ field,
10
+ value,
11
+ noLabel,
12
+ style,
13
+ }: {
14
+ field: FileField
15
+ value: any
16
+ noLabel?: boolean
17
+ style?: CSSProperties
18
+ }) => {
19
+ const { imageOptions, placeholder } = field
20
+ const options = useMemo<ImageViewOptions>(
21
+ () => ({
22
+ height: 150,
23
+ ...imageOptions,
24
+ }),
25
+ [imageOptions],
26
+ )
27
+ return (
28
+ <Flex flexFlow={value ? 'column' : 'row'} style={style}>
29
+ {noLabel ? null : (
30
+ <Text pr={2} opacity={0.7} fontWeight={600}>
31
+ {placeholder}
32
+ </Text>
33
+ )}
34
+ {value ? (
35
+ <ExpandOnMount>
36
+ <Box p={1}>
37
+ <FileView imageOptions={options} value={value} />
38
+ </Box>
39
+ </ExpandOnMount>
40
+ ) : (
41
+ <Text opacity={0.7}>None</Text>
42
+ )}
43
+ </Flex>
44
+ )
45
+ }
@@ -0,0 +1,61 @@
1
+ import { Flex, Text } from '@chakra-ui/react'
2
+
3
+ import { formatField } from '@chem-po/core'
4
+ import { Field } from '@chem-po/react'
5
+ import { CSSProperties, useMemo } from 'react'
6
+ import { FileFieldView } from './file'
7
+ import { MultipleSelectFieldView } from './multipleSelect'
8
+ import { SelectFieldView } from './select'
9
+
10
+ const DefaultFieldView = ({
11
+ field,
12
+ value,
13
+ noLabel,
14
+ style,
15
+ }: {
16
+ field: Field
17
+ value: any
18
+ noLabel?: boolean
19
+ style?: CSSProperties
20
+ }) => {
21
+ const { placeholder } = field
22
+
23
+ const formatted = useMemo(() => {
24
+ const format = formatField[field._type]
25
+ if (!format) return value
26
+ return format(field, value)
27
+ }, [value, field])
28
+ return (
29
+ <Flex align="center" style={style}>
30
+ {noLabel ? null : (
31
+ <Text pr={2} opacity={0.7} fontWeight={600}>
32
+ {placeholder}
33
+ </Text>
34
+ )}
35
+ <Text opacity={value !== undefined && value !== null ? 1 : 0.6}>{formatted ?? 'None'}</Text>
36
+ </Flex>
37
+ )
38
+ }
39
+
40
+ export const FieldView = ({
41
+ field,
42
+ value,
43
+ noLabel,
44
+ style,
45
+ }: {
46
+ field: Field
47
+ value: any
48
+ noLabel?: boolean
49
+ style?: CSSProperties
50
+ }) => {
51
+ switch (field._type) {
52
+ case 'select':
53
+ return <SelectFieldView style={style} field={field} value={value} noLabel={noLabel} />
54
+ case 'multipleSelect':
55
+ return <MultipleSelectFieldView style={style} field={field} value={value} noLabel={noLabel} />
56
+ case 'file':
57
+ return <FileFieldView style={style} field={field} value={value} noLabel={noLabel} />
58
+ default:
59
+ return <DefaultFieldView style={style} field={field} value={value} noLabel={noLabel} />
60
+ }
61
+ }
@@ -0,0 +1,38 @@
1
+ import { Box, Text } from '@chakra-ui/react'
2
+
3
+ import { Flex, useColorMode } from '@chakra-ui/react'
4
+ import { MultipleSelectField } from '@chem-po/react'
5
+ import { CSSProperties } from 'react'
6
+
7
+ export const MultipleSelectFieldView = ({
8
+ field,
9
+ value,
10
+ noLabel,
11
+ style,
12
+ }: {
13
+ field: MultipleSelectField
14
+ value: any[]
15
+ noLabel?: boolean
16
+ style?: CSSProperties
17
+ }) => {
18
+ const { placeholder, renderOption } = field
19
+ const { colorMode } = useColorMode()
20
+ return (
21
+ <Flex maxW="100%" flexFlow="row wrap" align="center" style={style}>
22
+ {noLabel ? null : (
23
+ <Text pr={2} opacity={0.7} fontWeight={600}>
24
+ {placeholder}
25
+ </Text>
26
+ )}
27
+ {value ? (
28
+ value.map((v: any) => (
29
+ <Box key={field.getOptionKey ? field.getOptionKey(v) : v} p={0.5}>
30
+ {renderOption(v, colorMode, true)}
31
+ </Box>
32
+ ))
33
+ ) : (
34
+ <Text opacity={0.6}>None</Text>
35
+ )}
36
+ </Flex>
37
+ )
38
+ }
@@ -0,0 +1,33 @@
1
+ import { Flex, Text, useColorMode } from '@chakra-ui/react'
2
+ import { SelectField } from '@chem-po/react'
3
+ import { CSSProperties } from 'react'
4
+
5
+ const DefaultRenderOption = (value: any) => {
6
+ return <Text>{typeof value === 'string' ? value : JSON.stringify(value)}</Text>
7
+ }
8
+
9
+ export const SelectFieldView = ({
10
+ field,
11
+ value,
12
+ noLabel,
13
+ style,
14
+ }: {
15
+ field: SelectField
16
+ value: any
17
+ noLabel?: boolean
18
+ style?: CSSProperties
19
+ }) => {
20
+ const { placeholder, renderOption: customRender } = field
21
+ const { colorMode } = useColorMode()
22
+ const renderOption = customRender ?? DefaultRenderOption
23
+ return (
24
+ <Flex align="center" style={style}>
25
+ {noLabel ? null : (
26
+ <Text pr={2} opacity={0.7} fontWeight={600}>
27
+ {placeholder}
28
+ </Text>
29
+ )}
30
+ {value ? renderOption(value, colorMode, true) : 'None'}
31
+ </Flex>
32
+ )
33
+ }
@@ -0,0 +1,14 @@
1
+ export * from './auth'
2
+ export * from './box'
3
+ export * from './button'
4
+ export * from './feed'
5
+ export * from './form'
6
+ export * from './list'
7
+ export * from './loading'
8
+ export * from './media'
9
+ export * from './modal'
10
+ export * from './nav'
11
+ export * from './overlay'
12
+ export * from './text'
13
+ export * from './theme'
14
+ export * from './view'