better code
Massimo Melina committed
Feb 25, 2025 at 21:12 UTC
f59a41358de077983a53d88618c30d66c401c5a9
5 files changed
+32
-27
admin/src/DataTable.ts
+9
-5
@@ -115,13 +115,17 @@ export function DataTable({ columns, initialState={}, actions, actionsProps, ini
115
setCurRow?.(_.find(rest.rows, { id }))
116
})
117
const sizeFooterSide = useGetSize()
118
- const wrappedFooterSide = h(Box, { ...sizeFooterSide.props, className: 'footerSide', sx: { whiteSpace: 'nowrap' } }, footerSide?.(width))
118
+ const wrappedFooterSide = h(Box, {
119
+ ref: sizeFooterSide.refToPass,
120
+ className: 'footerSide',
121
+ sx: { whiteSpace: 'nowrap' }
122
+ }, footerSide?.(width))
123
const [causingScrolling, setCausingScrolling] = useState(false)
120
- useEffect(useCallback(_.debounce(() => {
124
+ const updateCausingScrolling = useCallback(_.debounce(() => {
125
const el = sizeGrid.ref.current?.querySelector('.MuiTablePagination-root')
126
setCausingScrolling(el && (el.scrollWidth > el.clientWidth) || false)
123
- }, 500), [sizeGrid]),
124
- [sizeGrid, width, sizeFooterSide.w]) // recalculate in case the footerSide changes
127
+ }, 500), [sizeGrid])
128
+ useEffect(updateCausingScrolling, [sizeGrid, width, sizeFooterSide.w]) // recalculate in case the footerSide changes
129
130
return h(Fragment, {},
131
error && h(Alert, { severity: 'error' }, error),
@@ -136,7 +140,7 @@ export function DataTable({ columns, initialState={}, actions, actionsProps, ini
140
columns: manipulatedColumns,
141
apiRef,
142
disableRowSelectionOnClick: true,
139
- ...sizeGrid.props,
143
+ ref: sizeGrid.refToPass,
144
...rest,
145
sx: {
146
...fillFlex && { height: 0, flex: 'auto' }, // limit table to available screen space, if parent is flex
frontend/src/icons.ts
+1
-1
@@ -16,7 +16,7 @@ Promise.race([documentComplete, document.fonts?.ready]).then(async () => {
16
state.iconsReady = document.fonts.check(fontTester)
17
})
18
19
-interface IconProps { name:string, className?:string, alt?:string, [rest:string]: any }
19
+export interface IconProps { name:string, className?:string, alt?:string, [rest:string]: any }
20
// name = null ? none : unicode ? unicode : "?" ? file_url : font_icon_class
21
export const Icon = memo(({ name, alt, className='', ...props }: IconProps) => {
22
if (!name) return null
frontend/src/misc.ts
+2
-2
@@ -3,7 +3,7 @@
3
import React, { createElement as h } from 'react'
4
import { iconBtn, Spinner } from './components'
5
import { newDialog, toast } from './dialog'
6
-import { Icon } from './icons'
6
+import { Icon, IconProps } from './icons'
7
import { Callback, Dict, domOn, getHFS, getOrSet, Html, HTTP_MESSAGES, urlParams, useBatch } from '@hfs/shared'
8
import * as cross from '../../src/cross'
9
import * as shared from '@hfs/shared'
@@ -26,7 +26,7 @@ export function err2msg(err: number | Error) {
26
: (HTTP_MESSAGES[(err as any).code] || err.message || String(err))
27
}
28
29
-export function hIcon(name: string, props?:any) {
29
+export function hIcon(name: string, props?: Omit<IconProps, 'name'>) {
30
return h(Icon, { name, ...props })
31
}
32
mui-grid-form/misc-fields.ts
+2
-2
@@ -24,7 +24,7 @@ export function NumberField({ value, onChange, setApi, required, min=0, max, ste
24
: (value < min ? "too low" : value > max ? "too high" : false)
25
}
26
})
27
- const size = useGetSize({ refProp: 'fieldRef' })
27
+ const size = useGetSize()
28
return h(StringField, {
29
type: 'number',
30
value: value == null ? '' : String(value),
@@ -54,7 +54,7 @@ export function NumberField({ value, onChange, setApi, required, min=0, max, ste
54
}, unit),
55
}),
56
...props,
57
- ...size.props,
57
+ fieldRef: size.refToPass,
58
})
59
}
60
shared/react.ts
+18
-17
@@ -121,36 +121,37 @@ export function useIsMobile() {
121
return useMediaQuery('(pointer:coarse)')
122
}
123
124
-// calls back with [width, height]
124
+// returns props to assign to your component, and a copy of the ref; calls back with [width, height]
125
export function useOnResize(cb: Callback<[number, number]>) {
126
const observer = useMemo(() =>
127
- new ResizeObserver(_.debounce(([{contentRect: r}]) => cb([r.width, r.height]), 10)),
127
+ new ResizeObserver(_.debounce(([{ contentRect: r, target }]) => {
128
+ const style = getComputedStyle(target)
129
+ const pw = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight)
130
+ const ph = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom)
131
+ cb([r.width + pw, r.height + ph])
132
+ }, 10)),
133
[])
129
-
130
- return useMemo(() => ({
131
- ref(el: any) {
134
+ const ref = useRef<HTMLElement>()
135
+ return {
136
+ ref,
137
+ refToPass: useCallback((el: any) => {
138
observer.disconnect()
139
if (el)
140
observer.observe(el)
135
- }
136
- }), [observer])
141
+ ref.current = el
142
+ }, [observer])
143
+ }
144
}
145
139
-export function useGetSize({ refProp='ref' }={}) {
146
+export function useGetSize() {
147
const [size, setSize] = useState<[number,number]>()
141
- const ref = useRef<HTMLElement>()
142
- const props = useOnResize(setSize)
143
- const propsRef = useCallback((el: any) => passRef(el, ref, props.ref), [props])
148
+ const { refToPass, ref } = useOnResize(setSize)
149
return useMemo(() => ({
150
w: size?.[0],
151
h: size?.[1],
152
ref,
148
- props: {
149
- ...props,
150
- ...refProp !== 'ref' && { ref: undefined },
151
- [refProp]: propsRef
152
- }
153
- }), [size, ref, propsRef])
153
+ refToPass
154
+ }), [size, ref])
155
}
156
157
export function useEffectOnce(cb: Callback, deps: any[]) {