feat(source): lazy loading (#229)

* optimized build for lazy loading

* 3.0.95

* loading map overlay component

* 3.0.96

* loading screen for dynamic imports

* replace RichTextEditor with TextAreaInput (dummy)

* reduce changeset

---------

Co-authored-by: Anton Tranelis <mail@antontranelis.de>
This commit is contained in:
Ulf Gebhardt 2025-06-04 15:12:57 +02:00 committed by GitHub
parent c82084576a
commit 5dd0191d79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 112 additions and 17 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "utopia-ui", "name": "utopia-ui",
"version": "3.0.93", "version": "3.0.96",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "utopia-ui", "name": "utopia-ui",
"version": "3.0.93", "version": "3.0.96",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"dependencies": { "dependencies": {
"@heroicons/react": "^2.0.17", "@heroicons/react": "^2.0.17",

View File

@ -1,6 +1,6 @@
{ {
"name": "utopia-ui", "name": "utopia-ui",
"version": "3.0.93", "version": "3.0.96",
"description": "Reuseable React Components to build mapping apps for real life communities and networks", "description": "Reuseable React Components to build mapping apps for real life communities and networks",
"repository": "https://github.com/utopia-os/utopia-ui", "repository": "https://github.com/utopia-os/utopia-ui",
"homepage": "https://utopia-os.org/", "homepage": "https://utopia-os.org/",
@ -12,6 +12,11 @@
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"import": "./dist/index.esm.js", "import": "./dist/index.esm.js",
"require": "./dist/index.cjs" "require": "./dist/index.cjs"
},
"./Profile": {
"types": "./dist/Profile.d.ts",
"import": "./dist/Profile.esm.js",
"require": "./dist/Profile.cjs.js"
} }
}, },
"type": "module", "type": "module",

View File

@ -17,17 +17,22 @@ const aliasConfig = alias({
export default [ export default [
{ {
input: 'src/index.tsx', input: {
index: 'src/index.tsx',
Profile: 'src/Components/Profile/index.tsx',
},
output: [ output: [
{ {
file: 'dist/index.esm.js', dir: 'dist/',
format: 'esm', format: 'esm',
sourcemap: true, sourcemap: true,
entryFileNames: '[name].esm.js',
}, },
{ {
file: 'dist/index.cjs', dir: 'dist/',
format: 'cjs', format: 'cjs',
sourcemap: true, sourcemap: true,
entryFileNames: '[name].cjs.js',
}, },
], ],
plugins: [ plugins: [
@ -78,8 +83,15 @@ export default [
], ],
}, },
{ {
input: 'dist/types/src/index.d.ts', input: {
output: [{ file: 'dist/index.d.ts', format: 'es' }], index: path.resolve(__dirname, 'dist/types/src/index.d.ts'),
Profile: path.resolve(__dirname, 'dist/types/src/Components/Profile/index.d.ts'),
},
output: {
dir: path.resolve(__dirname, 'dist'),
format: 'es',
entryFileNames: '[name].d.ts',
},
plugins: [ plugins: [
aliasConfig, aliasConfig,
dts({ dts({
@ -88,7 +100,7 @@ export default [
}, },
}), }),
], ],
external: [/\.css$/], //, /\.d\.ts$/ external: [/\.css$/],
watch: false, watch: false,
}, },
] ]

View File

@ -0,0 +1,65 @@
import { useEffect, useRef, useState } from 'react'
interface TextAreaProps {
labelTitle?: string
labelStyle?: string
containerStyle?: string
dataField?: string
inputStyle?: string
defaultValue: string
placeholder?: string
required?: boolean
size?: string
updateFormValue?: (value: string) => void
}
/**
* @category Input
*/
export function RichTextEditor({
labelTitle,
dataField,
labelStyle,
containerStyle,
inputStyle,
defaultValue,
placeholder,
required = true,
updateFormValue,
}: TextAreaProps) {
const ref = useRef<HTMLTextAreaElement>(null)
const [inputValue, setInputValue] = useState<string>(defaultValue)
useEffect(() => {
setInputValue(defaultValue)
}, [defaultValue])
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const newValue = e.target.value
setInputValue(newValue)
if (updateFormValue) {
updateFormValue(newValue)
}
}
return (
<div className={`tw:form-control tw:w-full ${containerStyle ?? ''}`}>
{labelTitle ? (
<label className='tw:label'>
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
{labelTitle}
</span>
</label>
) : null}
<textarea
required={required}
ref={ref}
value={inputValue}
name={dataField}
className={`tw:textarea tw:textarea-bordered tw:w-full tw:leading-5 ${inputStyle ?? ''}`}
placeholder={placeholder ?? ''}
onChange={handleChange}
></textarea>
</div>
)
}

View File

@ -4,7 +4,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { TextAreaInput } from '#components/Input' import { RichTextEditor } from '#components/Input/RichTextEditor'
import { MarkdownHint } from './MarkdownHint' import { MarkdownHint } from './MarkdownHint'
@ -47,7 +47,7 @@ export const ProfileTextForm = ({
</label> </label>
<MarkdownHint /> <MarkdownHint />
</div> </div>
<TextAreaInput <RichTextEditor
placeholder={'...'} placeholder={'...'}
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
defaultValue={state[field]} defaultValue={state[field]}

View File

@ -9,7 +9,7 @@
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { TextAreaInput } from '#components/Input' import { RichTextEditor } from '#components/Input/RichTextEditor'
import { useUpdateItem } from '#components/Map/hooks/useItems' import { useUpdateItem } from '#components/Map/hooks/useItems'
import { PopupStartEndInput, TextView } from '#components/Map/Subcomponents/ItemPopupComponents' import { PopupStartEndInput, TextView } from '#components/Map/Subcomponents/ItemPopupComponents'
import { ActionButton } from '#components/Profile/Subcomponents/ActionsButton' import { ActionButton } from '#components/Profile/Subcomponents/ActionsButton'
@ -90,7 +90,8 @@ export const TabsForm = ({
></PopupStartEndInput> ></PopupStartEndInput>
)} )}
<TextAreaInput <RichTextEditor
labelTitle='About me'
placeholder='about ...' placeholder='about ...'
defaultValue={item?.text ? item.text : ''} defaultValue={item?.text ? item.text : ''}
updateFormValue={(v) => updateFormValue={(v) =>
@ -102,7 +103,8 @@ export const TabsForm = ({
containerStyle='tw:grow' containerStyle='tw:grow'
inputStyle={`tw:h-full ${!item.layer.itemType.show_start_end_input && 'tw:border-t-0 tw:rounded-tl-none'}`} inputStyle={`tw:h-full ${!item.layer.itemType.show_start_end_input && 'tw:border-t-0 tw:rounded-tl-none'}`}
/> />
<TextAreaInput <RichTextEditor
labelTitle='Contact Info'
placeholder='contact info ...' placeholder='contact info ...'
defaultValue={state.contact || ''} defaultValue={state.contact || ''}
updateFormValue={(c) => updateFormValue={(c) =>

View File

@ -0,0 +1,11 @@
import { MapOverlayPage } from '#components/Templates/MapOverlayPage'
export const LoadingMapOverlay = () => {
return (
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-64 tw:bg-transparent' card={false}>
<div className='tw:flex tw:justify-center tw:items-center tw:h-full'>
<div className='tw:loading tw:loading-spinner tw:loading-xl'></div>
</div>
</MapOverlayPage>
)
}

View File

@ -45,7 +45,7 @@ export function MapOverlayPage({
> >
<div <div
ref={overlayRef} ref={overlayRef}
className={`${card ? 'tw:card tw:card-body' : ''} tw:shadow-xl tw:bg-base-100 tw:p-6 ${className ?? ''} ${backdrop ? '' : 'tw:z-2000'} tw:absolute tw:top-0 tw:bottom-0 tw:right-0 tw:left-0 tw:m-auto`} className={`${card ? 'tw:card tw:card-body tw:shadow-xl' : ''} tw:bg-base-100 tw:p-6 ${className ?? ''} ${backdrop ? '' : 'tw:z-2000'} tw:absolute tw:top-0 tw:bottom-0 tw:right-0 tw:left-0 tw:m-auto`}
> >
{children} {children}
<button <button

View File

@ -5,3 +5,4 @@ export { SelectUser } from './SelectUser'
export { OverlayItemsIndexPage } from './OverlayItemsIndexPage' export { OverlayItemsIndexPage } from './OverlayItemsIndexPage'
export { AttestationForm } from './AttestationForm' export { AttestationForm } from './AttestationForm'
export { MarketView } from './MarketView' export { MarketView } from './MarketView'
export { LoadingMapOverlay } from './LoadingMapOverlay'

View File

@ -4,7 +4,6 @@ import './css'
export * from './Components/Map' export * from './Components/Map'
export * from './Components/AppShell' export * from './Components/AppShell'
export * from './Components/Auth' export * from './Components/Auth'
export * from './Components/Profile'
export * from './Components/Gaming' export * from './Components/Gaming'
export * from './Components/Templates' export * from './Components/Templates'
export * from './Components/Input' export * from './Components/Input'

View File

@ -7,7 +7,7 @@
"module": "esnext", "module": "esnext",
"target": "ESNext", "target": "ESNext",
"lib": ["es6", "dom","es2015", "es2016", "es2017", "es2020"], "lib": ["es6", "dom","es2015", "es2016", "es2017", "es2020"],
"sourceMap": false, "sourceMap": true,
"allowJs": false, "allowJs": false,
"jsx": "react-jsx", "jsx": "react-jsx",
"moduleResolution": "node", "moduleResolution": "node",