Page MenuHomeSealhub

components.sreact.tsx
No OneTemporary

components.sreact.tsx

import { render, renderEarlyAssets } from "@sealcode/jdd";
import { StatefulPage } from "@sealcode/sealgen";
import { hasShape, predicates } from "@sealcode/ts-predicates";
import type { BaseContext } from "koa";
import type { Templatable } from "tempstream";
import { tempstream, TempstreamJSX } from "tempstream";
import html, { defaultHead } from "../html.js";
import { registry } from "../jdd-components/components.js";
import { makeJDDContext } from "../jdd-context.js";
import { ComponentInput } from "./component-preview/component-input.js";
import { ComponentPreviewActions } from "./component-preview/component-preview-actions.js";
export const actionName = "Components";
export type ComponentPreviewState = {
component: string;
component_args: Record<string, unknown>;
current_size?: string;
};
export default new (class ComponentsPage extends StatefulPage<
ComponentPreviewState,
typeof ComponentPreviewActions
> {
actions = ComponentPreviewActions;
async getInitialState(ctx: BaseContext) {
const [component_name, component] = Object.entries(registry.getAll())[0];
const initial_state = {
component: component_name,
component_args: await component.getExampleValues(makeJDDContext(ctx)),
};
return initial_state;
}
async serializeState(ctx: BaseContext, state: ComponentPreviewState) {
const component = registry.get(state.component);
const result = JSON.stringify({
...state,
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
component_args: component
? await component.convertParsedToStorage(
makeJDDContext(ctx),
state.component_args
)
: {},
});
return result;
}
async deserializeState(ctx: BaseContext, state_string: string) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const raw = JSON.parse(state_string);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-member-access
const component = registry.get(raw.component as string);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const result = {
...raw,
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
component_args: component
? // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
await component.convertStorageToParsed(
makeJDDContext(ctx),
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
raw.component_args || {}
)
: {},
};
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return result as ComponentPreviewState;
}
wrapInLayout(
ctx: BaseContext,
content: Templatable,
state: ComponentPreviewState
): Templatable {
return html(
ctx,
"Components",
content,
{
morphing: true,
preserveScroll: true,
autoRefreshCSS: true,
navbar: () => ``,
},
(...args) =>
tempstream`${defaultHead(...args)}${renderEarlyAssets(
registry,
[
{
component_name: state.component,
args: state.component_args,
},
],
makeJDDContext(ctx)
)}`
);
}
async preprocessOverrides(
ctx: BaseContext,
state: ComponentPreviewState,
overrides: Record<string, unknown>
) {
const jdd_context = makeJDDContext(ctx);
const component_name = state.component;
if (!component_name) {
throw new Error("Unspecified component name");
}
const component = registry.get(component_name);
if (!component) {
throw new Error(`Unknown component: ${component_name}`);
}
if (!hasShape({ component_args: predicates.object }, overrides)) {
return overrides;
}
const promises = Object.entries(component.getArguments()).map(
async ([arg_name, arg]) => {
const value = overrides.component_args[arg_name];
if (value) {
const new_value = await arg.receivedToParsed(jdd_context, value);
overrides.component_args[arg_name] = new_value;
}
}
);
await Promise.all(promises);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return overrides;
}
containerSizes = ["320", "600", "800", "1024", "1300", "1920"];
render(ctx: BaseContext, state: ComponentPreviewState) {
const jdd_context = makeJDDContext(ctx);
const all_components = registry.getAll();
const component =
registry.get(state.component) || Object.values(all_components)[0];
return (
<div
class="two-column"
id="component-debugger"
style="--resizable-column-width: 50vw"
data-controller="component-debugger"
>
<div class="component-arguments">
{/*The below button has to be here in order for it to be the default behavior */}
<input type="submit" value="Preview" />
<select
name="component"
onchange={this.makeActionCallback("change_component")}
autocomplete="off"
>
{Object.entries(all_components).map(([name]) => (
<option value={name} selected={name == state.component}>
{name}
</option>
))}
</select>
{this.makeActionButton(state, "randomize_args")}
<fieldset class="component-preview-parameters">
<legend>Parameters</legend>
{Object.entries(component.getArguments()).map(
async ([arg_name, arg]) => (
<ComponentInput
{...{
state,
ctx,
arg_path: [arg_name],
arg,
value:
state.component_args[arg_name] === undefined
? await arg.getExampleValue(jdd_context)
: state.component_args[arg_name],
onblur: this.rerender(),
page: this,
}}
/>
)
)}
<input type="submit" value="Preview" />
</fieldset>
<code>{this.serializeState(ctx, state)}</code>
</div>
<div class="resize-gutter" data-component-debugger-target="gutter"></div>
<div class="component-preview" data-component-debugger-target="preview">
<fieldset>
<legend>
Preview{" "}
<span data-component-debugger-target="component-width"></span>
<select
name="size"
autocomplete="off"
class="component-preview-size-select"
data-component-debugger-target="size-select"
data-action="change->component-debugger#handleWidthDropdown"
>
{this.containerSizes.map((size) => (
<option
value={size}
selected={size === (state.current_size || "800")}
>
{`${size} px`}
</option>
))}
</select>
<noscript>
{this.makeActionButton(state, "change_size")}
</noscript>
</legend>
{render(
registry,
[
{
component_name: state.component,
args: state.component_args,
},
],
jdd_context
)}
</fieldset>
{
/* HTML */ `<script>
(function () {
const gutter = document.querySelector(".resize-gutter");
})();
</script>`
}
</div>
</div>
);
}
})();

File Metadata

Mime Type
text/x-java
Expires
Sat, Nov 23, 07:15 (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
547919
Default Alt Text
components.sreact.tsx (6 KB)

Event Timeline