mirror of
https://github.com/huntabyte/shadcn-svelte.git
synced 2026-09-14 19:33:46 +08:00
30 lines
9.9 KiB
JSON
30 lines
9.9 KiB
JSON
{
|
|
"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
|
|
"name": "data-table",
|
|
"type": "registry:ui",
|
|
"devDependencies": [
|
|
"@tanstack/table-core@^8.21.3"
|
|
],
|
|
"files": [
|
|
{
|
|
"content": "import {\n\ttype RowData,\n\ttype TableOptions,\n\ttype TableOptionsResolved,\n\ttype TableState,\n\ttype Updater,\n\tcreateTable,\n} from \"@tanstack/table-core\";\n\n/**\n * Creates a reactive TanStack table object for Svelte.\n * @param options Table options to create the table with.\n * @returns A reactive table object.\n * @example\n * ```svelte\n * <script>\n * const table = createSvelteTable({ ... })\n * </script>\n *\n * <table>\n * <thead>\n * {#each table.getHeaderGroups() as headerGroup}\n * <tr>\n * {#each headerGroup.headers as header}\n * <th colspan={header.colSpan}>\n * \t <FlexRender content={header.column.columnDef.header} context={header.getContext()} />\n * \t </th>\n * {/each}\n * </tr>\n * {/each}\n * </thead>\n * \t <!-- ... -->\n * </table>\n * ```\n */\nexport function createSvelteTable<TData extends RowData>(options: TableOptions<TData>) {\n\tconst resolvedOptions: TableOptionsResolved<TData> = mergeObjects(\n\t\t{\n\t\t\tstate: {},\n\t\t\tonStateChange() {},\n\t\t\trenderFallbackValue: null,\n\t\t\tmergeOptions: (\n\t\t\t\tdefaultOptions: TableOptions<TData>,\n\t\t\t\toptions: Partial<TableOptions<TData>>\n\t\t\t) => {\n\t\t\t\treturn mergeObjects(defaultOptions, options);\n\t\t\t},\n\t\t},\n\t\toptions\n\t);\n\n\tconst table = createTable(resolvedOptions);\n\tlet state = $state<TableState>(table.initialState);\n\n\tfunction updateOptions() {\n\t\ttable.setOptions(() => {\n\t\t\treturn mergeObjects(resolvedOptions, options, {\n\t\t\t\tstate: mergeObjects(state, options.state || {}),\n\n\t\t\t\tonStateChange: (updater: Updater<TableState>) => {\n\t\t\t\t\tif (updater instanceof Function) state = updater(state);\n\t\t\t\t\telse state = mergeObjects(state, updater);\n\n\t\t\t\t\toptions.onStateChange?.(updater);\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\tupdateOptions();\n\n\t$effect.pre(() => {\n\t\tupdateOptions();\n\t});\n\n\treturn table;\n}\n\ntype MaybeThunk<T extends object> = T | (() => T | null | undefined);\ntype Intersection<T extends readonly unknown[]> = (T extends [infer H, ...infer R]\n\t? H & Intersection<R>\n\t: unknown) & {};\n\n/**\n * Lazily merges several objects (or thunks) while preserving\n * getter semantics from every source.\n *\n * Proxy-based to avoid known WebKit recursion issue.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function mergeObjects<Sources extends readonly MaybeThunk<any>[]>(\n\t...sources: Sources\n): Intersection<{ [K in keyof Sources]: Sources[K] }> {\n\tconst resolve = <T extends object>(src: MaybeThunk<T>): T | undefined =>\n\t\ttypeof src === \"function\" ? (src() ?? undefined) : src;\n\n\tconst findSourceWithKey = (key: PropertyKey) => {\n\t\tfor (let i = sources.length - 1; i >= 0; i--) {\n\t\t\tconst obj = resolve(sources[i]);\n\t\t\tif (obj && key in obj) return obj;\n\t\t}\n\t\treturn undefined;\n\t};\n\n\treturn new Proxy(Object.create(null), {\n\t\tget(_, key) {\n\t\t\tconst src = findSourceWithKey(key);\n\n\t\t\treturn src?.[key as never];\n\t\t},\n\n\t\thas(_, key) {\n\t\t\treturn !!findSourceWithKey(key);\n\t\t},\n\n\t\townKeys(): (string | symbol)[] {\n\t\t\t// eslint-disable-next-line svelte/prefer-svelte-reactivity\n\t\t\tconst all = new Set<string | symbol>();\n\t\t\tfor (const s of sources) {\n\t\t\t\tconst obj = resolve(s);\n\t\t\t\tif (obj) {\n\t\t\t\t\tfor (const k of Reflect.ownKeys(obj) as (string | symbol)[]) {\n\t\t\t\t\t\tall.add(k);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [...all];\n\t\t},\n\n\t\tgetOwnPropertyDescriptor(_, key) {\n\t\t\tconst src = findSourceWithKey(key);\n\t\t\tif (!src) return undefined;\n\t\t\treturn {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\tvalue: (src as any)[key],\n\t\t\t\twritable: true,\n\t\t\t};\n\t\t},\n\t}) as Intersection<{ [K in keyof Sources]: Sources[K] }>;\n}\n",
|
|
"type": "registry:file",
|
|
"target": "data-table/data-table.svelte.ts"
|
|
},
|
|
{
|
|
"content": "<script\n\tlang=\"ts\"\n\tgenerics=\"TData, TValue, TContext extends HeaderContext<TData, TValue> | CellContext<TData, TValue>\"\n>\n\timport type { CellContext, ColumnDefTemplate, HeaderContext } from \"@tanstack/table-core\";\n\timport { RenderComponentConfig, RenderSnippetConfig } from \"./render-helpers.js\";\n\timport type { Attachment } from \"svelte/attachments\";\n\ttype Props = {\n\t\t/** The cell or header field of the current cell's column definition. */\n\t\tcontent?: TContext extends HeaderContext<TData, TValue>\n\t\t\t? ColumnDefTemplate<HeaderContext<TData, TValue>>\n\t\t\t: TContext extends CellContext<TData, TValue>\n\t\t\t\t? ColumnDefTemplate<CellContext<TData, TValue>>\n\t\t\t\t: never;\n\t\t/** The result of the `getContext()` function of the header or cell */\n\t\tcontext: TContext;\n\n\t\t/** Used to pass attachments that can't be gotten through context */\n\t\tattach?: Attachment;\n\t};\n\n\tlet { content, context, attach }: Props = $props();\n</script>\n\n{#if typeof content === \"string\"}\n\t{content}\n{:else if content instanceof Function}\n\t<!-- It's unlikely that a CellContext will be passed to a Header -->\n\t<!-- eslint-disable-next-line @typescript-eslint/no-explicit-any -->\n\t{@const result = content(context as any)}\n\t{#if result instanceof RenderComponentConfig}\n\t\t{@const { component: Component, props } = result}\n\t\t<Component {...props} {attach} />\n\t{:else if result instanceof RenderSnippetConfig}\n\t\t{@const { snippet, params } = result}\n\t\t{@render snippet({ ...params, attach })}\n\t{:else}\n\t\t{result}\n\t{/if}\n{/if}\n",
|
|
"type": "registry:file",
|
|
"target": "data-table/flex-render.svelte"
|
|
},
|
|
{
|
|
"content": "export { default as FlexRender } from \"./flex-render.svelte\";\nexport { renderComponent, renderSnippet } from \"./render-helpers.js\";\nexport { createSvelteTable } from \"./data-table.svelte.js\";\n",
|
|
"type": "registry:file",
|
|
"target": "data-table/index.ts"
|
|
},
|
|
{
|
|
"content": "import type { Component, ComponentProps, Snippet } from \"svelte\";\n\n/**\n * A helper class to make it easy to identify Svelte components in\n * `columnDef.cell` and `columnDef.header` properties.\n *\n * > NOTE: This class should only be used internally by the adapter. If you're\n * reading this and you don't know what this is for, you probably don't need it.\n *\n * @example\n * ```svelte\n * {@const result = content(context as any)}\n * {#if result instanceof RenderComponentConfig}\n * {@const { component: Component, props } = result}\n * <Component {...props} />\n * {/if}\n * ```\n */\nexport class RenderComponentConfig<TComponent extends Component> {\n\tcomponent: TComponent;\n\tprops: ComponentProps<TComponent> | Record<string, never>;\n\tconstructor(\n\t\tcomponent: TComponent,\n\t\tprops: ComponentProps<TComponent> | Record<string, never> = {}\n\t) {\n\t\tthis.component = component;\n\t\tthis.props = props;\n\t}\n}\n\n/**\n * A helper class to make it easy to identify Svelte Snippets in `columnDef.cell` and `columnDef.header` properties.\n *\n * > NOTE: This class should only be used internally by the adapter. If you're\n * reading this and you don't know what this is for, you probably don't need it.\n *\n * @example\n * ```svelte\n * {@const result = content(context as any)}\n * {#if result instanceof RenderSnippetConfig}\n * {@const { snippet, params } = result}\n * {@render snippet(params)}\n * {/if}\n * ```\n */\nexport class RenderSnippetConfig<TProps> {\n\tsnippet: Snippet<[TProps]>;\n\tparams: TProps;\n\tconstructor(snippet: Snippet<[TProps]>, params: TProps) {\n\t\tthis.snippet = snippet;\n\t\tthis.params = params;\n\t}\n}\n\n/**\n * A helper function to help create cells from Svelte components through ColumnDef's `cell` and `header` properties.\n *\n * This is only to be used with Svelte Components - use `renderSnippet` for Svelte Snippets.\n *\n * @param component A Svelte component\n * @param props The props to pass to `component`\n * @returns A `RenderComponentConfig` object that helps svelte-table know how to render the header/cell component.\n * @example\n * ```ts\n * // +page.svelte\n * const defaultColumns = [\n * columnHelper.accessor('name', {\n * header: header => renderComponent(SortHeader, { label: 'Name', header }),\n * }),\n * columnHelper.accessor('state', {\n * header: header => renderComponent(SortHeader, { label: 'State', header }),\n * }),\n * ]\n * ```\n * @see {@link https://tanstack.com/table/latest/docs/guide/column-defs}\n */\nexport function renderComponent<\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tT extends Component<any>,\n\tProps extends ComponentProps<T>,\n>(component: T, props: Props = {} as Props) {\n\treturn new RenderComponentConfig(component, props);\n}\n\n/**\n * A helper function to help create cells from Svelte Snippets through ColumnDef's `cell` and `header` properties.\n *\n * The snippet must only take one parameter.\n *\n * This is only to be used with Snippets - use `renderComponent` for Svelte Components.\n *\n * @param snippet\n * @param params\n * @returns - A `RenderSnippetConfig` object that helps svelte-table know how to render the header/cell snippet.\n * @example\n * ```ts\n * // +page.svelte\n * const defaultColumns = [\n * columnHelper.accessor('name', {\n * cell: cell => renderSnippet(nameSnippet, { name: cell.row.name }),\n * }),\n * columnHelper.accessor('state', {\n * cell: cell => renderSnippet(stateSnippet, { state: cell.row.state }),\n * }),\n * ]\n * ```\n * @see {@link https://tanstack.com/table/latest/docs/guide/column-defs}\n */\nexport function renderSnippet<TProps>(snippet: Snippet<[TProps]>, params: TProps = {} as TProps) {\n\treturn new RenderSnippetConfig(snippet, params);\n}\n",
|
|
"type": "registry:file",
|
|
"target": "data-table/render-helpers.ts"
|
|
}
|
|
]
|
|
} |