Skip to content

Commit aefba5d

Browse files
authored
Merge pull request #7 from devitools/feat/slot-field-factory
feat(core,react-web): add slot() field factory for custom renderers
2 parents 59ec685 + 7e5915d commit aefba5d

7 files changed

Lines changed: 52 additions & 4 deletions

File tree

packages/core/src/fields/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export { CurrencyFieldDefinition, currency } from './currency'
1010
export { FileFieldDefinition, file, image } from './file'
1111
export { ListFieldDefinition, list } from './list'
1212
export { TreeFieldDefinition, tree } from './tree'
13+
export { SlotFieldDefinition, slot } from './slot'
1314

1415
export type { TextKind } from './text'

packages/core/src/fields/slot.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { FieldDefinition } from './base'
2+
3+
export class SlotFieldDefinition extends FieldDefinition<unknown> {
4+
constructor(attrs: Record<string, unknown> = {}) {
5+
super('slot', 'unknown', attrs)
6+
}
7+
}
8+
9+
export function slot(attrs?: Record<string, unknown>): SlotFieldDefinition {
10+
return new SlotFieldDefinition(attrs)
11+
}

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export {
1616
FileFieldDefinition, file, image,
1717
ListFieldDefinition, list,
1818
TreeFieldDefinition, tree,
19+
SlotFieldDefinition, slot,
1920
} from './fields'
2021
export type { TextKind } from './fields'
2122

packages/react-web/src/components/Form.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useCallback } from "react";
2+
import React from "react";
23
import { useTranslation } from "react-i18next";
34
import { useDataForm } from "@ybyra/react";
45
import type { UseDataFormOptions } from "@ybyra/react";
@@ -10,16 +11,17 @@ import { ActionBar } from "./ActionBar";
1011
import { FieldsGrid as DefaultFieldsGrid } from "./defaults/FieldsGrid";
1112
import { DebugPanel } from "./defaults/DebugPanel";
1213
import { ds } from "../support/ds";
13-
import type { DataFormComponents } from "../types";
14+
import type { DataFormComponents, SlotRendererProps } from "../types";
1415
import "../renderers";
1516

1617
interface DataFormProps extends UseDataFormOptions {
1718
debug?: boolean;
1819
components?: DataFormComponents;
1920
filler?: FillerRegistry;
21+
slots?: Record<string, React.ComponentType<SlotRendererProps>>;
2022
}
2123

22-
export function DataForm({ debug, components, filler, ...props }: DataFormProps) {
24+
export function DataForm({ debug, components, filler, slots, ...props }: DataFormProps) {
2325
const { t } = useTranslation();
2426
const theme = useTheme();
2527
const form = useDataForm({ ...props, translate: props.translate ?? t });
@@ -61,6 +63,7 @@ export function DataForm({ debug, components, filler, ...props }: DataFormProps)
6163
<ResolvedFieldsGrid
6264
fields={section.fields}
6365
getFieldProps={form.getFieldProps}
66+
slots={slots}
6467
/>
6568
</GroupWrapper>
6669
);
@@ -77,6 +80,7 @@ export function DataForm({ debug, components, filler, ...props }: DataFormProps)
7780
<ResolvedFieldsGrid
7881
fields={section.fields}
7982
getFieldProps={form.getFieldProps}
83+
slots={slots}
8084
/>
8185
</div>
8286
);
@@ -90,6 +94,7 @@ export function DataForm({ debug, components, filler, ...props }: DataFormProps)
9094
<ResolvedFieldsGrid
9195
fields={section.fields}
9296
getFieldProps={form.getFieldProps}
97+
slots={slots}
9398
/>
9499
</div>
95100
);

packages/react-web/src/components/defaults/FieldsGrid.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,30 @@ import { getRenderer } from "@ybyra/react";
22
import { ds } from "../../support/ds";
33
import type { FieldsGridProps } from "../../types";
44

5-
export function FieldsGrid({ fields, getFieldProps }: FieldsGridProps) {
5+
export function FieldsGrid({ fields, getFieldProps, slots }: FieldsGridProps) {
66
return (
77
<div style={{ display: "grid", gridTemplateColumns: "repeat(100, 1fr)" }}>
88
{fields.map((field) => {
99
if (field.proxy.hidden) return null;
10+
11+
const isSlot = field.config.component === "slot";
12+
const SlotRenderer = isSlot ? slots?.[field.name] : undefined;
13+
14+
if (isSlot && !SlotRenderer) return null;
15+
16+
if (isSlot && SlotRenderer) {
17+
const { value, proxy, scope, domain } = getFieldProps(field.name);
18+
return (
19+
<div
20+
key={field.name}
21+
style={{ gridColumn: `span ${field.proxy.width}` }}
22+
{...ds(`field:${field.name}`)}
23+
>
24+
<SlotRenderer domain={domain} name={field.name} value={value} proxy={proxy} scope={scope} />
25+
</div>
26+
);
27+
}
28+
1029
const Renderer = getRenderer(field.config.component);
1130
if (!Renderer) return null;
1231
return (

packages/react-web/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export type {
2424
LoadingProps,
2525
DividerProps,
2626
DataFormComponents,
27+
SlotRendererProps,
2728
PaginationProps,
2829
ColumnSelectorProps,
2930
EmptyStateProps,

packages/react-web/src/types.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import type { ReactNode, ComponentType } from "react";
22
import type { ResolvedAction, ResolvedField, UseDataFormReturn, ResolvedColumn } from "@ybyra/react";
3-
import type { PositionValue } from "@ybyra/core";
3+
import type { FieldProxy, PositionValue, ScopeValue } from "@ybyra/core";
4+
5+
export interface SlotRendererProps {
6+
domain: string;
7+
name: string;
8+
value: unknown;
9+
proxy: FieldProxy;
10+
scope: ScopeValue;
11+
}
412

513
export interface ActionButtonProps {
614
action: { name: string; config: { variant: string }; execute: () => void };
@@ -16,6 +24,7 @@ export interface ActionBarProps {
1624
export interface FieldsGridProps {
1725
fields: ResolvedField[];
1826
getFieldProps: UseDataFormReturn["getFieldProps"];
27+
slots?: Record<string, ComponentType<SlotRendererProps>>;
1928
}
2029

2130
export interface GroupWrapperProps {
@@ -35,6 +44,7 @@ export interface DataFormComponents {
3544
GroupWrapper?: ComponentType<GroupWrapperProps>;
3645
Loading?: ComponentType<LoadingProps>;
3746
Divider?: ComponentType<DividerProps>;
47+
Slot?: ComponentType<SlotRendererProps>;
3848
}
3949

4050
export interface PaginationProps {

0 commit comments

Comments
 (0)