sanity-plugin-media 2.0.4 → 2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-media",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "This version of `sanity-plugin-media` is for Sanity Studio V3.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -54,10 +54,10 @@
54
54
  "watch": "pkg-utils watch"
55
55
  },
56
56
  "dependencies": {
57
- "@hookform/resolvers": "2.0.0-beta.3",
57
+ "@hookform/resolvers": "2.9.11",
58
58
  "@reduxjs/toolkit": "^1.9.0",
59
59
  "@sanity/incompatible-plugin": "^1.0.4",
60
- "@sanity/ui": "^1.0.0",
60
+ "@sanity/ui": "^1.7.0",
61
61
  "@tanem/react-nprogress": "^5.0.0",
62
62
  "copy-to-clipboard": "^3.3.1",
63
63
  "date-fns": "^2.27.0",
@@ -71,7 +71,7 @@
71
71
  "react-hook-form": "^6.15.1",
72
72
  "react-redux": "^7.2.2",
73
73
  "react-select": "^5.3.2",
74
- "react-virtuoso": "^2.11.0",
74
+ "react-virtuoso": "^4.3.11",
75
75
  "redux": "^4.2.0",
76
76
  "redux-observable": "^2.0.0",
77
77
  "rxjs": "^7.0.0",
@@ -83,7 +83,7 @@
83
83
  "@sanity/client": "^4.0.1",
84
84
  "@sanity/color": "^2.1.20",
85
85
  "@sanity/icons": "^2.0.0",
86
- "@sanity/pkg-utils": "^1.17.2",
86
+ "@sanity/pkg-utils": "^2.0.0",
87
87
  "@sanity/plugin-kit": "^2.1.16",
88
88
  "@sanity/semantic-release-preset": "^2.0.2",
89
89
  "@types/is-hotkey": "^0.1.7",
@@ -116,8 +116,6 @@
116
116
  "typescript": "^4.8.4"
117
117
  },
118
118
  "peerDependencies": {
119
- "@sanity/color": "^2.1.20",
120
- "@sanity/icons": "^2.0.0",
121
119
  "react": "^18",
122
120
  "react-dom": "^18",
123
121
  "sanity": "^3.0.0",
@@ -36,6 +36,7 @@ const ItemContainer = styled.div`
36
36
  const ListContainer = styled.div`
37
37
  display: grid;
38
38
  grid-template-columns: repeat(auto-fill, ${CARD_WIDTH}px);
39
+ grid-template-rows: repeat(auto-fill, ${CARD_HEIGHT}px);
39
40
  justify-content: center;
40
41
  margin: 0 auto;
41
42
  `
@@ -71,7 +72,7 @@ const AssetGridVirtualized = (props: Props) => {
71
72
  return <VirtualCell item={item} selected={selected} />
72
73
  }}
73
74
  overscan={48}
74
- style={{overflowX: 'hidden'}}
75
+ style={{overflowX: 'hidden', overflowY: 'scroll'}}
75
76
  totalCount={totalCount}
76
77
  />
77
78
  )
@@ -1,8 +1,8 @@
1
1
  import type {MutationEvent} from '@sanity/client'
2
- import {Card, Flex, studioTheme, ThemeProvider, ToastProvider} from '@sanity/ui'
2
+ import {Card, Flex, PortalProvider, studioTheme, ThemeProvider, ToastProvider} from '@sanity/ui'
3
3
  import {Asset, Tag} from '@types'
4
4
  import groq from 'groq'
5
- import React, {useEffect} from 'react'
5
+ import React, {useEffect, useState} from 'react'
6
6
  import {useDispatch} from 'react-redux'
7
7
  import type {AssetSourceComponentProps, SanityDocument} from 'sanity'
8
8
  import {TAG_DOCUMENT_NAME} from '../../constants'
@@ -33,6 +33,8 @@ type Props = {
33
33
  const BrowserContent = ({onClose}: {onClose?: AssetSourceComponentProps['onClose']}) => {
34
34
  const client = useVersionedClient()
35
35
 
36
+ const [portalElement, setPortalElement] = useState<HTMLDivElement | null>(null)
37
+
36
38
  // Redux
37
39
  const dispatch = useDispatch()
38
40
 
@@ -98,31 +100,33 @@ const BrowserContent = ({onClose}: {onClose?: AssetSourceComponentProps['onClose
98
100
  }, [])
99
101
 
100
102
  return (
101
- <UploadDropzone>
102
- <Dialogs />
103
- <Notifications />
104
-
105
- <Card display="flex" height="fill">
106
- <Flex direction="column" flex={1}>
107
- {/* Header */}
108
- <Header onClose={onClose} />
109
-
110
- {/* Browser Controls */}
111
- <Controls />
112
-
113
- <Flex flex={1}>
114
- <Flex align="flex-end" direction="column" flex={1} style={{position: 'relative'}}>
115
- <PickedBar />
116
- <Items />
103
+ <PortalProvider element={portalElement}>
104
+ <UploadDropzone>
105
+ <Dialogs />
106
+ <Notifications />
107
+
108
+ <Card display="flex" height="fill" ref={setPortalElement}>
109
+ <Flex direction="column" flex={1}>
110
+ {/* Header */}
111
+ <Header onClose={onClose} />
112
+
113
+ {/* Browser Controls */}
114
+ <Controls />
115
+
116
+ <Flex flex={1}>
117
+ <Flex align="flex-end" direction="column" flex={1} style={{position: 'relative'}}>
118
+ <PickedBar />
119
+ <Items />
120
+ </Flex>
121
+ <TagsPanel />
117
122
  </Flex>
118
- <TagsPanel />
119
- </Flex>
120
123
 
121
- {/* Debug */}
122
- <DebugControls />
123
- </Flex>
124
- </Card>
125
- </UploadDropzone>
124
+ {/* Debug */}
125
+ <DebugControls />
126
+ </Flex>
127
+ </Card>
128
+ </UploadDropzone>
129
+ </PortalProvider>
126
130
  )
127
131
  }
128
132
 
@@ -2,22 +2,18 @@ import {ClipboardIcon} from '@sanity/icons'
2
2
  import {Button, Popover, Text} from '@sanity/ui'
3
3
  import copy from 'copy-to-clipboard'
4
4
  import React, {useEffect, useRef, useState} from 'react'
5
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
5
6
 
6
7
  type Props = {
7
8
  disabled?: boolean
8
9
  url: string
9
10
  }
10
11
 
11
- const ButtonAssetCopy = (props: Props) => {
12
- const {disabled, url} = props
13
-
14
- // Refs
12
+ const ButtonAssetCopy = ({disabled, url}: Props) => {
13
+ const popoverProps = usePortalPopoverProps()
15
14
  const refPopoverTimeout = useRef<ReturnType<typeof window.setTimeout>>()
16
-
17
- // State
18
15
  const [popoverVisible, setPopoverVisible] = useState(false)
19
16
 
20
- // Callbacks
21
17
  const handleClick = () => {
22
18
  if (refPopoverTimeout.current) {
23
19
  clearTimeout(refPopoverTimeout.current)
@@ -51,6 +47,7 @@ const ButtonAssetCopy = (props: Props) => {
51
47
  padding={2}
52
48
  placement="top"
53
49
  radius={1}
50
+ {...popoverProps}
54
51
  >
55
52
  <Button
56
53
  disabled={disabled}
@@ -1,6 +1,6 @@
1
1
  import {hues} from '@sanity/color'
2
2
  import {CloseIcon} from '@sanity/icons'
3
- import {Box, Button, Flex, Text, Tooltip} from '@sanity/ui'
3
+ import {Box, Button, Flex, Text} from '@sanity/ui'
4
4
  import filesize from 'filesize'
5
5
  import React from 'react'
6
6
  import {useDispatch} from 'react-redux'
@@ -102,10 +102,10 @@ const CardUpload = (props: Props) => {
102
102
  </div>
103
103
  )}
104
104
 
105
- {/*
105
+ {/*
106
106
  Cancel upload button.
107
107
  Assets will only have a `complete` status _after_ it has been created on your dataset.
108
- As such, we also hide the cancel button when `percentLoaded === 100`, as cancelling when the asset
108
+ As such, we also hide the cancel button when `percentLoaded === 100`, as cancelling when the asset
109
109
  has been fully uploaded (even with a status of `progress`) won't stop the asset from being created.
110
110
  */}
111
111
  {!isComplete && percentLoaded !== 100 && (
@@ -121,27 +121,15 @@ const CardUpload = (props: Props) => {
121
121
  width: '100%'
122
122
  }}
123
123
  >
124
- <Tooltip
125
- content={
126
- <Box padding={2}>
127
- <Text muted size={1}>
128
- Cancel
129
- </Text>
130
- </Box>
131
- }
132
- disabled={'ontouchstart' in window}
133
- placement="top"
134
- >
135
- <Button
136
- fontSize={4}
137
- icon={CloseIcon}
138
- mode="bleed"
139
- onClick={handleCancelUpload}
140
- padding={2}
141
- style={{background: 'none', boxShadow: 'none'}}
142
- tone="critical"
143
- />
144
- </Tooltip>
124
+ <Button
125
+ fontSize={4}
126
+ icon={CloseIcon}
127
+ mode="bleed"
128
+ onClick={handleCancelUpload}
129
+ padding={2}
130
+ style={{background: 'none', boxShadow: 'none'}}
131
+ tone="critical"
132
+ />
145
133
  </Flex>
146
134
  )}
147
135
  </Box>
@@ -60,6 +60,7 @@ const DebugControls = () => {
60
60
  }
61
61
  fallbackPlacements={['right', 'left']}
62
62
  placement="bottom"
63
+ portal
63
64
  >
64
65
  <Switch
65
66
  checked={badConnection}
@@ -20,7 +20,6 @@ import AssetMetadata from '../AssetMetadata'
20
20
  import Dialog from '../Dialog'
21
21
  import DocumentList from '../DocumentList'
22
22
  import FileAssetPreview from '../FileAssetPreview'
23
- import FormFieldInputFilename from '../FormFieldInputFilename'
24
23
  import FormFieldInputTags from '../FormFieldInputTags'
25
24
  import FormFieldInputText from '../FormFieldInputText'
26
25
  import FormFieldInputTextarea from '../FormFieldInputTextarea'
@@ -35,14 +34,9 @@ type Props = {
35
34
  type FormData = yup.InferType<typeof formSchema>
36
35
 
37
36
  const formSchema = yup.object().shape({
38
- originalFilename: yup.string().required('Filename cannot be empty')
37
+ originalFilename: yup.string().trim().required('Filename cannot be empty')
39
38
  })
40
39
 
41
- const getFilenameWithoutExtension = (asset?: Asset): string | undefined => {
42
- const extensionIndex = asset?.originalFilename?.toLowerCase().lastIndexOf(`.${asset.extension}`)
43
- return asset?.originalFilename?.slice(0, extensionIndex)
44
- }
45
-
46
40
  const DialogAssetEdit = (props: Props) => {
47
41
  const {
48
42
  children,
@@ -73,7 +67,7 @@ const DialogAssetEdit = (props: Props) => {
73
67
  const generateDefaultValues = (asset?: Asset) => ({
74
68
  altText: asset?.altText || '',
75
69
  description: asset?.description || '',
76
- originalFilename: asset ? getFilenameWithoutExtension(asset) : undefined,
70
+ originalFilename: asset?.originalFilename || '',
77
71
  opt: {media: {tags: assetTagOptions}},
78
72
  title: asset?.title || ''
79
73
  })
@@ -165,9 +159,7 @@ const DialogAssetEdit = (props: Props) => {
165
159
  _weak: true
166
160
  })) || null
167
161
  }
168
- },
169
- // Append extension to filename
170
- originalFilename: `${sanitizedFormData.originalFilename}.${assetItem?.asset.extension}`
162
+ }
171
163
  }
172
164
  })
173
165
  )
@@ -323,14 +315,13 @@ const DialogAssetEdit = (props: Props) => {
323
315
  value={assetTagOptions}
324
316
  />
325
317
  {/* Filename */}
326
- <FormFieldInputFilename
318
+ <FormFieldInputText
327
319
  disabled={formUpdating}
328
320
  error={errors?.originalFilename}
329
- extension={currentAsset?.extension || ''}
330
321
  label="Filename"
331
322
  name="originalFilename"
332
323
  ref={register}
333
- value={getFilenameWithoutExtension(currentAsset)}
324
+ value={currentAsset?.originalFilename}
334
325
  />
335
326
  {/* Title */}
336
327
  <FormFieldInputText
@@ -62,7 +62,7 @@ const useRootPortalElement = () => {
62
62
  return () => {
63
63
  document.body.removeChild(container)
64
64
  }
65
- }, [])
65
+ }, [container])
66
66
 
67
67
  return container
68
68
  }
@@ -40,6 +40,7 @@ const FormSubmitButton = (props: Props) => {
40
40
  }
41
41
  disabled={'ontouchstart' in window}
42
42
  placement="top"
43
+ portal
43
44
  >
44
45
  <Box>
45
46
  <Button
@@ -4,6 +4,7 @@ import React from 'react'
4
4
  import {useDispatch} from 'react-redux'
5
5
  import {getOrderTitle} from '../../config/orders'
6
6
  import {ORDER_OPTIONS} from '../../constants'
7
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
7
8
  import useTypedSelector from '../../hooks/useTypedSelector'
8
9
  import {assetsActions} from '../../modules/assets'
9
10
 
@@ -12,6 +13,8 @@ const OrderSelect = () => {
12
13
  const dispatch = useDispatch()
13
14
  const order = useTypedSelector(state => state.assets.order)
14
15
 
16
+ const popoverProps = usePortalPopoverProps()
17
+
15
18
  return (
16
19
  <MenuButton
17
20
  button={
@@ -51,6 +54,7 @@ const OrderSelect = () => {
51
54
  })}
52
55
  </Menu>
53
56
  }
57
+ popover={popoverProps}
54
58
  />
55
59
  )
56
60
  }
@@ -8,6 +8,7 @@ import {
8
8
  import React from 'react'
9
9
  import {useDispatch} from 'react-redux'
10
10
  import {operators} from '../../config/searchFacets'
11
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
11
12
  import {searchActions} from '../../modules/search'
12
13
  import SearchFacet from '../SearchFacet'
13
14
  import TextInputNumber from '../TextInputNumber'
@@ -16,12 +17,12 @@ type Props = {
16
17
  facet: SearchFacetInputNumberProps
17
18
  }
18
19
 
19
- const SearchFacetNumber = (props: Props) => {
20
- const {facet} = props
21
-
20
+ const SearchFacetNumber = ({facet}: Props) => {
22
21
  // Redux
23
22
  const dispatch = useDispatch()
24
23
 
24
+ const popoverProps = usePortalPopoverProps()
25
+
25
26
  const modifiers = facet?.modifiers
26
27
  const selectedModifier = facet?.modifier
27
28
  ? modifiers?.find(modifier => modifier.name === facet?.modifier)
@@ -75,6 +76,7 @@ const SearchFacetNumber = (props: Props) => {
75
76
  })}
76
77
  </Menu>
77
78
  }
79
+ popover={popoverProps}
78
80
  />
79
81
  )}
80
82
 
@@ -116,6 +118,7 @@ const SearchFacetNumber = (props: Props) => {
116
118
  ))}
117
119
  </Menu>
118
120
  }
121
+ popover={popoverProps}
119
122
  />
120
123
  )}
121
124
  </SearchFacet>
@@ -11,17 +11,18 @@ import {useDispatch} from 'react-redux'
11
11
  import {operators} from '../../config/searchFacets'
12
12
  import {searchActions} from '../../modules/search'
13
13
  import SearchFacet from '../SearchFacet'
14
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
14
15
 
15
16
  type Props = {
16
17
  facet: SearchFacetInputSelectProps
17
18
  }
18
19
 
19
- const SearchFacetSelect = (props: Props) => {
20
- const {facet} = props
21
-
20
+ const SearchFacetSelect = ({facet}: Props) => {
22
21
  // Redux
23
22
  const dispatch = useDispatch()
24
23
 
24
+ const popoverProps = usePortalPopoverProps()
25
+
25
26
  const options = facet?.options
26
27
 
27
28
  const selectedItem = options?.find(v => v.name === facet?.value)
@@ -73,6 +74,7 @@ const SearchFacetSelect = (props: Props) => {
73
74
  })}
74
75
  </Menu>
75
76
  }
77
+ popover={popoverProps}
76
78
  />
77
79
  )}
78
80
 
@@ -101,6 +103,7 @@ const SearchFacetSelect = (props: Props) => {
101
103
  ))}
102
104
  </Menu>
103
105
  }
106
+ popover={popoverProps}
104
107
  />
105
108
  </SearchFacet>
106
109
  )
@@ -5,6 +5,7 @@ import React, {ChangeEvent} from 'react'
5
5
  import {useDispatch} from 'react-redux'
6
6
 
7
7
  import {operators} from '../../config/searchFacets'
8
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
8
9
  import {searchActions} from '../../modules/search'
9
10
  import SearchFacet from '../SearchFacet'
10
11
 
@@ -12,12 +13,12 @@ type Props = {
12
13
  facet: SearchFacetInputStringProps
13
14
  }
14
15
 
15
- const SearchFacetString = (props: Props) => {
16
- const {facet} = props
17
-
16
+ const SearchFacetString = ({facet}: Props) => {
18
17
  // Redux
19
18
  const dispatch = useDispatch()
20
19
 
20
+ const popoverProps = usePortalPopoverProps()
21
+
21
22
  const handleOperatorItemClick = (operatorType: SearchFacetOperatorType) => {
22
23
  dispatch(searchActions.facetsUpdate({name: facet.name, operatorType}))
23
24
  }
@@ -62,6 +63,7 @@ const SearchFacetString = (props: Props) => {
62
63
  })}
63
64
  </Menu>
64
65
  }
66
+ popover={popoverProps}
65
67
  />
66
68
  )}
67
69
 
@@ -5,6 +5,7 @@ import React from 'react'
5
5
  import {useDispatch} from 'react-redux'
6
6
  import Select from 'react-select'
7
7
  import {operators} from '../../config/searchFacets'
8
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
8
9
  import useTypedSelector from '../../hooks/useTypedSelector'
9
10
  import {searchActions} from '../../modules/search'
10
11
  import {selectTags} from '../../modules/tags'
@@ -16,15 +17,15 @@ type Props = {
16
17
  facet: SearchFacetInputSearchableProps
17
18
  }
18
19
 
19
- const SearchFacetTags = (props: Props) => {
20
- const {facet} = props
21
-
20
+ const SearchFacetTags = ({facet}: Props) => {
22
21
  // Redux
23
22
  const dispatch = useDispatch()
24
23
  const tags = useTypedSelector(state => selectTags(state))
25
24
  const tagsFetching = useTypedSelector(state => state.tags.fetching)
26
25
  const allTagOptions = getTagSelectOptions(tags)
27
26
 
27
+ const popoverProps = usePortalPopoverProps()
28
+
28
29
  const handleChange = (option: ReactSelectOption) => {
29
30
  dispatch(
30
31
  searchActions.facetsUpdate({
@@ -79,6 +80,7 @@ const SearchFacetTags = (props: Props) => {
79
80
  })}
80
81
  </Menu>
81
82
  }
83
+ popover={popoverProps}
82
84
  />
83
85
  )}
84
86
 
@@ -4,6 +4,7 @@ import {SearchFacetDivider, SearchFacetGroup, SearchFacetInputProps} from '@type
4
4
  import React from 'react'
5
5
  import {useDispatch} from 'react-redux'
6
6
  import {FACETS} from '../../constants'
7
+ import {usePortalPopoverProps} from '../../hooks/usePortalPopoverProps'
7
8
  import useTypedSelector from '../../hooks/useTypedSelector'
8
9
  import {searchActions} from '../../modules/search'
9
10
 
@@ -14,6 +15,8 @@ const SearchFacetsControl = () => {
14
15
  const searchFacets = useTypedSelector(state => state.search.facets)
15
16
  const selectedDocument = useTypedSelector(state => state.selected.document)
16
17
 
18
+ const popoverProps = usePortalPopoverProps()
19
+
17
20
  const isTool = !selectedDocument
18
21
 
19
22
  const filteredFacets = FACETS
@@ -108,8 +111,10 @@ const SearchFacetsControl = () => {
108
111
  }
109
112
  id="facets"
110
113
  menu={<Menu>{renderMenuFacets(filteredFacets)}</Menu>}
111
- placement="right-start"
112
- portal
114
+ popover={{
115
+ ...popoverProps,
116
+ placement: 'right-start'
117
+ }}
113
118
  />
114
119
 
115
120
  {/* Clear facets button */}
@@ -1,6 +1,6 @@
1
1
  import {hues} from '@sanity/color'
2
2
  import {CloseIcon} from '@sanity/icons'
3
- import {Box, Button, Flex, Grid, Stack, Text, Tooltip, useMediaIndex} from '@sanity/ui'
3
+ import {Box, Button, Flex, Grid, Stack, Text, useMediaIndex} from '@sanity/ui'
4
4
  import filesize from 'filesize'
5
5
  import React from 'react'
6
6
  import {useDispatch} from 'react-redux'
@@ -100,10 +100,10 @@ const TableRowUpload = (props: Props) => {
100
100
  </div>
101
101
  )}
102
102
 
103
- {/*
103
+ {/*
104
104
  Cancel upload button.
105
105
  Assets will only have a `complete` status _after_ it has been created on your dataset.
106
- As such, we also hide the cancel button when `percentLoaded === 100`, as cancelling when the asset
106
+ As such, we also hide the cancel button when `percentLoaded === 100`, as cancelling when the asset
107
107
  has been fully uploaded (even with a status of `progress`) won't stop the asset from being created.
108
108
  */}
109
109
  {!isComplete && percentLoaded !== 100 && (
@@ -118,27 +118,15 @@ const TableRowUpload = (props: Props) => {
118
118
  width: '100%'
119
119
  }}
120
120
  >
121
- <Tooltip
122
- content={
123
- <Box padding={2}>
124
- <Text muted size={1}>
125
- Cancel
126
- </Text>
127
- </Box>
128
- }
129
- disabled={'ontouchstart' in window}
130
- placement="top"
131
- >
132
- <Button
133
- fontSize={3}
134
- icon={CloseIcon}
135
- mode="bleed"
136
- onClick={handleCancelUpload}
137
- padding={2}
138
- style={{background: 'none', boxShadow: 'none'}}
139
- tone="critical"
140
- />
141
- </Tooltip>
121
+ <Button
122
+ fontSize={3}
123
+ icon={CloseIcon}
124
+ mode="bleed"
125
+ onClick={handleCancelUpload}
126
+ padding={2}
127
+ style={{background: 'none', boxShadow: 'none'}}
128
+ tone="critical"
129
+ />
142
130
  </Flex>
143
131
  )}
144
132
  </Box>
@@ -44,6 +44,7 @@ type TagButtonProps = {
44
44
 
45
45
  const TagButton = (props: TagButtonProps) => {
46
46
  const {disabled, icon, onClick, tone, tooltip} = props
47
+
47
48
  return (
48
49
  <Tooltip
49
50
  content={
@@ -55,6 +56,7 @@ const TagButton = (props: TagButtonProps) => {
55
56
  }
56
57
  disabled={'ontouchstart' in window}
57
58
  placement="top"
59
+ portal
58
60
  >
59
61
  <Button
60
62
  disabled={disabled}
@@ -13,15 +13,11 @@ type Props = {
13
13
  title: string
14
14
  }
15
15
 
16
- const TagViewHeader = (props: Props) => {
17
- const {allowCreate, light, title} = props
18
-
19
- // Redux
16
+ const TagViewHeader = ({allowCreate, light, title}: Props) => {
20
17
  const dispatch = useDispatch()
21
18
  const tagsCreating = useTypedSelector(state => state.tags.creating)
22
19
  const tagsFetching = useTypedSelector(state => state.tags.fetching)
23
20
 
24
- // Callbacks
25
21
  const handleTagCreate = () => {
26
22
  dispatch(DIALOG_ACTIONS.showTagCreate())
27
23
  }
@@ -35,6 +31,7 @@ const TagViewHeader = (props: Props) => {
35
31
  style={{
36
32
  background: light ? hues.gray?.[900].hex : black.hex,
37
33
  borderBottom: `1px solid ${hues.gray?.[900].hex}`,
34
+ flexShrink: 0,
38
35
  height: `${PANEL_HEIGHT}px`
39
36
  }}
40
37
  >
@@ -1,24 +1,26 @@
1
1
  import isHotkey from 'is-hotkey'
2
- import {RefObject, useEffect, useRef} from 'react'
2
+ import {RefObject, useCallback, useEffect, useRef} from 'react'
3
3
 
4
4
  const useKeyPress = (hotkey: string, onPress?: () => void): RefObject<boolean> => {
5
5
  const keyPressed = useRef(false)
6
6
 
7
7
  // If pressed key is our target key then set to true
8
- function downHandler(e: KeyboardEvent) {
9
- if (isHotkey(hotkey, e)) {
10
- keyPressed.current = true
11
-
12
- if (onPress) {
13
- onPress()
8
+ const downHandler = useCallback(
9
+ (e: KeyboardEvent) => {
10
+ if (isHotkey(hotkey, e)) {
11
+ keyPressed.current = true
12
+ if (onPress) {
13
+ onPress()
14
+ }
14
15
  }
15
- }
16
- }
16
+ },
17
+ [hotkey, onPress]
18
+ )
17
19
 
18
20
  // If released key is our target key then set to false
19
- const upHandler = () => {
21
+ const upHandler = useCallback(() => {
20
22
  keyPressed.current = false
21
- }
23
+ }, [])
22
24
 
23
25
  // Add event listeners
24
26
  useEffect(() => {
@@ -29,7 +31,7 @@ const useKeyPress = (hotkey: string, onPress?: () => void): RefObject<boolean> =
29
31
  window.removeEventListener('keydown', downHandler)
30
32
  window.removeEventListener('keyup', upHandler)
31
33
  }
32
- }, []) // Empty array ensures that effect is only run on mount and unmount
34
+ }, [downHandler, upHandler])
33
35
 
34
36
  return keyPressed
35
37
  }