@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 7.68 kB
Source Map (JSON)
{"version":3,"file":"List.mjs","names":["formMessages"],"sources":["../../../src/base-ui/FormKit/List.tsx"],"sourcesContent":["'use client';\n\nimport { PlusIcon, XIcon } from 'lucide-react';\nimport { cloneElement, memo, type ReactElement, type ReactNode, useCallback, useRef } from 'react';\n\nimport ActionIcon from '@/base-ui/ActionIcon';\nimport formMessages from '@/i18n/resources/en/form';\nimport { useTranslation } from '@/i18n/useTranslation';\n\nimport { useFormKitContext } from './context';\nimport FormField from './Field';\nimport { getInternals } from './instance';\nimport type { FieldValidate } from './schema';\nimport { listStyles } from './style';\nimport { useStoreSelector } from './useStoreSelector';\n\nexport interface FormListField {\n index: number;\n key: string;\n name: string;\n}\n\nexport interface FormListRenderProps {\n add: (item?: unknown) => void;\n fields: FormListField[];\n move: (from: number, to: number) => void;\n remove: (index: number) => void;\n}\n\nexport interface FormListColumn {\n children: ReactElement;\n flex?: number;\n name: string;\n required?: boolean | string;\n title?: ReactNode;\n validate?: FieldValidate;\n}\n\nexport interface FormListProps {\n addText?: ReactNode;\n children?: (props: FormListRenderProps) => ReactNode;\n columns?: FormListColumn[];\n emptyText?: ReactNode;\n name: string;\n newItem?: unknown;\n}\n\nlet rowSeed = 0;\nconst nextRowKey = () => `row-${(rowSeed += 1)}`;\n\nconst createItem = (newItem: unknown) =>\n typeof newItem === 'function'\n ? newItem()\n : newItem && typeof newItem === 'object'\n ? structuredClone(newItem)\n : (newItem ?? {});\n\nconst labelFor = (column: FormListColumn, index: number) =>\n (column.children as ReactElement<{ 'aria-label'?: string }>).props['aria-label'] ??\n (typeof column.title === 'string' ? `${column.title} ${index + 1}` : undefined);\n\nconst FormList = memo<FormListProps>(({ addText, children, columns, emptyText, name, newItem }) => {\n const { form } = useFormKitContext();\n const { engine } = getInternals(form);\n const { t } = useTranslation(formMessages);\n const length = useStoreSelector(engine, (e) => {\n const value = e.getValue(name);\n return Array.isArray(value) ? value.length : 0;\n });\n\n const keysRef = useRef<string[]>([]);\n const keys = keysRef.current;\n if (keys.length > length) keys.length = length;\n while (keys.length < length) keys.push(nextRowKey());\n\n const add = useCallback(\n (item?: unknown) => {\n keysRef.current.push(nextRowKey());\n engine.pushItem(name, item);\n },\n [engine, name],\n );\n const remove = useCallback(\n (index: number) => {\n keysRef.current.splice(index, 1);\n engine.removeItem(name, index);\n },\n [engine, name],\n );\n const move = useCallback(\n (from: number, to: number) => {\n const [moved] = keysRef.current.splice(from, 1);\n keysRef.current.splice(to, 0, moved);\n engine.moveItem(name, from, to);\n },\n [engine, name],\n );\n\n const fields = keys.map((key, index) => ({ index, key, name: `${name}.${index}` }));\n\n if (children || !columns) return <>{children?.({ add, fields, move, remove })}</>;\n\n const gridTemplateColumns = `${columns.map((c) => `minmax(0, ${c.flex ?? 1}fr)`).join(' ')} 36px`;\n const addButton = (\n <button className={listStyles.add} type=\"button\" onClick={() => add(createItem(newItem))}>\n <PlusIcon size={14} />\n {addText ?? t('form.list.add')}\n </button>\n );\n\n return (\n <div className={listStyles.table}>\n <div className={listStyles.head} style={{ gridTemplateColumns }}>\n {columns.map((column) => (\n <div className={listStyles.title} key={column.name}>\n {column.title}\n </div>\n ))}\n </div>\n {fields.length === 0 ? (\n <div className={listStyles.empty}>\n <span>{emptyText ?? t('form.list.empty')}</span>\n {addButton}\n </div>\n ) : (\n <>\n {fields.map((field) => (\n <div className={listStyles.row} key={field.key} style={{ gridTemplateColumns }}>\n {columns.map((column) => (\n <div className={listStyles.cell} key={column.name}>\n <FormField\n bare\n name={`${field.name}.${column.name}`}\n required={column.required}\n validate={column.validate}\n >\n {cloneElement(column.children as ReactElement<any>, {\n 'aria-label': labelFor(column, field.index),\n })}\n </FormField>\n </div>\n ))}\n <ActionIcon\n aria-label={t('form.list.remove')}\n icon={XIcon}\n size={'small'}\n title={t('form.list.remove')}\n onClick={() => remove(field.index)}\n />\n </div>\n ))}\n <div className={listStyles.foot}>{addButton}</div>\n </>\n )}\n </div>\n );\n});\n\nFormList.displayName = 'FormList';\n\nexport default FormList;\n"],"mappings":";;;;;;;;;;;;;AA+CA,IAAI,UAAU;AACd,MAAM,mBAAmB,OAAQ,WAAW;AAE5C,MAAM,cAAc,YAClB,OAAO,YAAY,aACf,QAAQ,IACR,WAAW,OAAO,YAAY,WAC5B,gBAAgB,OAAO,IACtB,WAAW,CAAC;AAErB,MAAM,YAAY,QAAwB,UACvC,OAAO,SAAqD,MAAM,kBAClE,OAAO,OAAO,UAAU,WAAW,GAAG,OAAO,MAAM,GAAG,QAAQ,MAAM,KAAA;AAEvE,MAAM,WAAW,MAAqB,EAAE,SAAS,UAAU,SAAS,WAAW,MAAM,cAAc;CACjG,MAAM,EAAE,SAAS,kBAAkB;CACnC,MAAM,EAAE,WAAW,aAAa,IAAI;CACpC,MAAM,EAAE,MAAM,eAAeA,YAAY;CACzC,MAAM,SAAS,iBAAiB,SAAS,MAAM;EAC7C,MAAM,QAAQ,EAAE,SAAS,IAAI;EAC7B,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS;CAC/C,CAAC;CAED,MAAM,UAAU,OAAiB,CAAC,CAAC;CACnC,MAAM,OAAO,QAAQ;CACrB,IAAI,KAAK,SAAS,QAAQ,KAAK,SAAS;CACxC,OAAO,KAAK,SAAS,QAAQ,KAAK,KAAK,WAAW,CAAC;CAEnD,MAAM,MAAM,aACT,SAAmB;EAClB,QAAQ,QAAQ,KAAK,WAAW,CAAC;EACjC,OAAO,SAAS,MAAM,IAAI;CAC5B,GACA,CAAC,QAAQ,IAAI,CACf;CACA,MAAM,SAAS,aACZ,UAAkB;EACjB,QAAQ,QAAQ,OAAO,OAAO,CAAC;EAC/B,OAAO,WAAW,MAAM,KAAK;CAC/B,GACA,CAAC,QAAQ,IAAI,CACf;CACA,MAAM,OAAO,aACV,MAAc,OAAe;EAC5B,MAAM,CAAC,SAAS,QAAQ,QAAQ,OAAO,MAAM,CAAC;EAC9C,QAAQ,QAAQ,OAAO,IAAI,GAAG,KAAK;EACnC,OAAO,SAAS,MAAM,MAAM,EAAE;CAChC,GACA,CAAC,QAAQ,IAAI,CACf;CAEA,MAAM,SAAS,KAAK,KAAK,KAAK,WAAW;EAAE;EAAO;EAAK,MAAM,GAAG,KAAK,GAAG;CAAQ,EAAE;CAElF,IAAI,YAAY,CAAC,SAAS,OAAO,oBAAA,YAAA,EAAA,UAAG,WAAW;EAAE;EAAK;EAAQ;EAAM;CAAO,CAAC,EAAI,CAAA;CAEhF,MAAM,sBAAsB,GAAG,QAAQ,KAAK,MAAM,aAAa,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE;CAC3F,MAAM,YACJ,qBAAC,UAAD;EAAQ,WAAW,WAAW;EAAK,MAAK;EAAS,eAAe,IAAI,WAAW,OAAO,CAAC;EAAvF,UAAA,CACE,oBAAC,UAAD,EAAU,MAAM,GAAK,CAAA,GACpB,WAAW,EAAE,eAAe,CACvB;;CAGV,OACE,qBAAC,OAAD;EAAK,WAAW,WAAW;EAA3B,UAAA,CACE,oBAAC,OAAD;GAAK,WAAW,WAAW;GAAM,OAAO,EAAE,oBAAoB;GAC3D,UAAA,QAAQ,KAAK,WACZ,oBAAC,OAAD;IAAK,WAAW,WAAW;IACxB,UAAA,OAAO;GACL,GAFkC,OAAO,IAEzC,CACN;EACE,CAAA,GACJ,OAAO,WAAW,IACjB,qBAAC,OAAD;GAAK,WAAW,WAAW;GAA3B,UAAA,CACE,oBAAC,QAAD,EAAA,UAAO,aAAa,EAAE,iBAAiB,EAAQ,CAAA,GAC9C,SACE;EAEL,CAAA,IAAA,qBAAA,YAAA,EAAA,UAAA,CACG,OAAO,KAAK,UACX,qBAAC,OAAD;GAAK,WAAW,WAAW;GAAqB,OAAO,EAAE,oBAAoB;GAA7E,UAAA,CACG,QAAQ,KAAK,WACZ,oBAAC,OAAD;IAAK,WAAW,WAAW;IACzB,UAAA,oBAAC,WAAD;KACE,MAAA;KACA,MAAM,GAAG,MAAM,KAAK,GAAG,OAAO;KAC9B,UAAU,OAAO;KACjB,UAAU,OAAO;KAEhB,UAAA,aAAa,OAAO,UAA+B,EAClD,cAAc,SAAS,QAAQ,MAAM,KAAK,EAC5C,CAAC;IACQ,CAAA;GACR,GAXiC,OAAO,IAWxC,CACN,GACD,oBAAC,YAAD;IACE,cAAY,EAAE,kBAAkB;IAChC,MAAM;IACN,MAAM;IACN,OAAO,EAAE,kBAAkB;IAC3B,eAAe,OAAO,MAAM,KAAK;GAClC,CAAA,CACE;EAtBgC,GAAA,MAAM,GAsBtC,CACN,GACD,oBAAC,OAAD;GAAK,WAAW,WAAW;GAAO,UAAA;EAAe,CAAA,CACjD,EAAA,CAAA,CAED;;AAET,CAAC;AAED,SAAS,cAAc"}