mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-02 18:18:35 +09:00
Ref https://github.com/webstudio-is/webstudio/issues/3632 This is big one. So I switched to html elements whole forms section in components. Though here I introduced some deviation from specification **Textarea** Initial value is represented as text content ```html <textarea>content</textarea> ```` Though it is trickier to manage text content as state and all frameworks rely on value property of textarea dom interface. **Select** Similar story. There is no value attribute and state is represented by selected boolean attribute on options ```html <select> <option value="value1" selected></option> <option value="value2"></option> </select> ``` We replace selected attribute on option with value attribute on selected when paste. So basically all form elements are using "value" and "checked" attributes which can be easily mapped to html and all frameworks.
59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
import type { IndexesWithinAncestors, Instance, Prop } from "@webstudio-is/sdk";
|
|
|
|
export type InstanceData = {
|
|
id: Instance["id"];
|
|
instanceKey: string;
|
|
component: Instance["component"];
|
|
tag?: Instance["tag"];
|
|
};
|
|
|
|
/**
|
|
* Hooks are subscriptions to builder events
|
|
* with limited way to interact with it.
|
|
* Called independently from components.
|
|
*/
|
|
|
|
export type HookContext = {
|
|
indexesWithinAncestors: IndexesWithinAncestors;
|
|
getPropValue: (instanceData: InstanceData, propName: Prop["name"]) => unknown;
|
|
setMemoryProp: (
|
|
instanceData: InstanceData,
|
|
propName: Prop["name"],
|
|
value: unknown
|
|
) => void;
|
|
};
|
|
|
|
export type InstancePath = InstanceData[];
|
|
|
|
type NavigatorEvent = {
|
|
/**
|
|
* List of instances from selected to the root
|
|
*/
|
|
instancePath: InstancePath;
|
|
};
|
|
|
|
export type Hook = {
|
|
onNavigatorSelect?: (context: HookContext, event: NavigatorEvent) => void;
|
|
onNavigatorUnselect?: (context: HookContext, event: NavigatorEvent) => void;
|
|
};
|
|
|
|
/**
|
|
* Find closest matching instance by component name
|
|
* by lookup in instance path
|
|
*/
|
|
export const getClosestInstance = (
|
|
instancePath: InstancePath,
|
|
currentInstance: InstanceData,
|
|
closestComponent: InstanceData["component"]
|
|
) => {
|
|
let matched = false;
|
|
for (const instance of instancePath) {
|
|
if (currentInstance === instance) {
|
|
matched = true;
|
|
}
|
|
if (matched && instance.component === closestComponent) {
|
|
return instance;
|
|
}
|
|
}
|
|
};
|