@samitouri / QOSami-HFS / commits / f59a4135

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[]) {