Skip to content

Commit

Permalink
feat: track focused field in app state
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvxd committed Nov 14, 2024
1 parent 229cbdd commit 91bc97a
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 12 deletions.
7 changes: 7 additions & 0 deletions apps/docs/pages/docs/api-reference/app-state.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The current state of the Puck editor interface.
| ----------------------------------------------- | ----------------------------------------------------- | ------- |
| [`arrayState`](#uiarraystate) | `{}` | Object |
| [`componentList`](#uicomponentlist) | `{ typography: { components: [ "HeadingBlock" ] } }` | Object |
| [`field.focus`](#fieldfocus) | `"title"` | String |
| [`isDragging`](#isdragging) | `false` | Boolean |
| [`itemSelector`](#uiitemselector) | `{ index: 0, zone: "my-content" }` | Object |
| [`leftSideBarVisible`](#uileftsidebarvisible) | `false` | Boolean |
Expand Down Expand Up @@ -52,6 +53,12 @@ Whether or not the category is expanded in the side bar

---

### `ui.field.focus`

The name of the currently focused field.

---

### `ui.isDragging`

A boolean stating whether or not the user is currently dragging a component.
Expand Down
42 changes: 38 additions & 4 deletions packages/core/components/AutoField/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { useAppContext } from "../Puck/context";
import { useSafeId } from "../../lib/use-safe-id";

const getClassName = getClassNameFactory("Input", styles);
const getClassNameWrapper = getClassNameFactory("InputWrapper", styles);

export const FieldLabel = ({
children,
Expand Down Expand Up @@ -127,7 +128,7 @@ function AutoFieldInternal<
Label?: React.FC<FieldLabelPropsInternal>;
}
) {
const { overrides } = useAppContext();
const { dispatch, overrides } = useAppContext();

const { id, Label = FieldLabelInternal } = props;

Expand Down Expand Up @@ -168,6 +169,33 @@ function AutoFieldInternal<
id: resolvedId,
};

const onFocus = useCallback(
(e: React.FocusEvent) => {
if (mergedProps.name && e.target.nodeName === "INPUT") {
e.stopPropagation();

dispatch({
type: "setUi",
ui: {
field: { focus: mergedProps.name },
},
});
}
},
[mergedProps.name]
);

const onBlur = useCallback((e: React.FocusEvent) => {
if ("name" in e.target) {
dispatch({
type: "setUi",
ui: {
field: { focus: null },
},
});
}
}, []);

if (field.type === "custom") {
if (!field.render) {
return null;
Expand All @@ -176,8 +204,10 @@ function AutoFieldInternal<
const CustomField = field.render as any;

return (
<div className={getClassName()}>
<CustomField {...mergedProps} />
<div className={getClassNameWrapper()} onFocus={onFocus} onBlur={onBlur}>
<div className={getClassName()}>
<CustomField {...mergedProps} />
</div>
</div>
);
}
Expand All @@ -186,7 +216,11 @@ function AutoFieldInternal<

const Render = render[field.type] as (props: FieldProps) => ReactElement;

return <Render {...mergedProps}>{children}</Render>;
return (
<div className={getClassNameWrapper()} onFocus={onFocus} onBlur={onBlur}>
<Render {...mergedProps}>{children}</Render>
</div>
);
}

// Don't let external value changes update this if it's changed manually in the last X ms
Expand Down
16 changes: 8 additions & 8 deletions packages/core/components/AutoField/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
.Input {
.InputWrapper {
color: var(--puck-color-grey-04);
padding: 16px;
padding-bottom: 12px;
display: block;
}

.Input .Input {
.InputWrapper + .InputWrapper {
border-top: 1px solid var(--puck-color-grey-09);
margin-top: 8px;
}

.Input .InputWrapper {
padding: 0px;
}

.Input * {
box-sizing: border-box;
}

.Input + .Input {
border-top: 1px solid var(--puck-color-grey-09);
margin-top: 8px;
}

.Input .Input + .Input {
.Input .InputWrapper + .InputWrapper {
border-top: 0px;
margin-top: 12px;
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/components/Puck/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const defaultAppState: AppState = {
options: [],
controlsVisible: true,
},
field: { focus: null },
},
};

Expand Down
3 changes: 3 additions & 0 deletions packages/core/lib/__tests__/use-resolved-data.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ describe("use-resolved-data", () => {
"ui": {
"arrayState": {},
"componentList": {},
"field": {
"focus": null,
},
"isDragging": false,
"itemSelector": null,
"leftSideBarVisible": true,
Expand Down
1 change: 1 addition & 0 deletions packages/core/types/AppState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type UiState = {
controlsVisible: boolean;
options: Viewport[];
};
field: { focus?: string | null };
};

export type AppState<UserData extends Data = Data> = {
Expand Down

0 comments on commit 91bc97a

Please sign in to comment.