Download frontend/src/components/widgets/WidgetSpan.svelte from openfree/graphite2: direct link, hf CLI and curl.
- Browser
- Download file 10.3 kB
-
https://huggingface.co/spaces/openfree/graphite2/resolve/main/frontend/src/components/widgets/WidgetSpan.svelte
- Command line
-
hf download hf://spaces/openfree/graphite2/frontend/src/components/widgets/WidgetSpan.svelte
-
curl -L -o WidgetSpan.svelte https://huggingface.co/spaces/openfree/graphite2/resolve/main/frontend/src/components/widgets/WidgetSpan.svelte
10.3 kB
| <script lang="ts"> | |
| import { getContext } from "svelte"; | |
| import type { Editor } from "@graphite/editor"; | |
| import type { Widget, WidgetSpanColumn, WidgetSpanRow } from "@graphite/messages"; | |
| import { narrowWidgetProps, isWidgetSpanColumn, isWidgetSpanRow } from "@graphite/messages"; | |
| import { debouncer } from "@graphite/utility-functions/debounce"; | |
| import NodeCatalog from "@graphite/components/floating-menus/NodeCatalog.svelte"; | |
| import BreadcrumbTrailButtons from "@graphite/components/widgets/buttons/BreadcrumbTrailButtons.svelte"; | |
| import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte"; | |
| import ImageButton from "@graphite/components/widgets/buttons/ImageButton.svelte"; | |
| import ParameterExposeButton from "@graphite/components/widgets/buttons/ParameterExposeButton.svelte"; | |
| import PopoverButton from "@graphite/components/widgets/buttons/PopoverButton.svelte"; | |
| import TextButton from "@graphite/components/widgets/buttons/TextButton.svelte"; | |
| import CheckboxInput from "@graphite/components/widgets/inputs/CheckboxInput.svelte"; | |
| import ColorInput from "@graphite/components/widgets/inputs/ColorInput.svelte"; | |
| import CurveInput from "@graphite/components/widgets/inputs/CurveInput.svelte"; | |
| import DropdownInput from "@graphite/components/widgets/inputs/DropdownInput.svelte"; | |
| import FontInput from "@graphite/components/widgets/inputs/FontInput.svelte"; | |
| import NumberInput from "@graphite/components/widgets/inputs/NumberInput.svelte"; | |
| import RadioInput from "@graphite/components/widgets/inputs/RadioInput.svelte"; | |
| import ReferencePointInput from "@graphite/components/widgets/inputs/ReferencePointInput.svelte"; | |
| import TextAreaInput from "@graphite/components/widgets/inputs/TextAreaInput.svelte"; | |
| import TextInput from "@graphite/components/widgets/inputs/TextInput.svelte"; | |
| import WorkingColorsInput from "@graphite/components/widgets/inputs/WorkingColorsInput.svelte"; | |
| import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte"; | |
| import Separator from "@graphite/components/widgets/labels/Separator.svelte"; | |
| import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte"; | |
| import WidgetLayout from "@graphite/components/widgets/WidgetLayout.svelte"; | |
| const editor = getContext<Editor>("editor"); | |
| export let widgetData: WidgetSpanRow | WidgetSpanColumn; | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| export let layoutTarget: any; | |
| let className = ""; | |
| export { className as class }; | |
| export let classes: Record<string, boolean> = {}; | |
| $: extraClasses = Object.entries(classes) | |
| .flatMap(([className, stateName]) => (stateName ? [className] : [])) | |
| .join(" "); | |
| $: direction = watchDirection(widgetData); | |
| $: widgets = watchWidgets(widgetData); | |
| function watchDirection(widgetData: WidgetSpanRow | WidgetSpanColumn): "row" | "column" | undefined { | |
| if (isWidgetSpanRow(widgetData)) return "row"; | |
| if (isWidgetSpanColumn(widgetData)) return "column"; | |
| } | |
| function watchWidgets(widgetData: WidgetSpanRow | WidgetSpanColumn): Widget[] { | |
| let widgets: Widget[] = []; | |
| if (isWidgetSpanRow(widgetData)) widgets = widgetData.rowWidgets; | |
| else if (isWidgetSpanColumn(widgetData)) widgets = widgetData.columnWidgets; | |
| return widgets; | |
| } | |
| function widgetValueCommit(index: number, value: unknown) { | |
| editor.handle.widgetValueCommit(layoutTarget, widgets[index].widgetId, value); | |
| } | |
| function widgetValueUpdate(index: number, value: unknown) { | |
| editor.handle.widgetValueUpdate(layoutTarget, widgets[index].widgetId, value); | |
| } | |
| function widgetValueCommitAndUpdate(index: number, value: unknown) { | |
| editor.handle.widgetValueCommitAndUpdate(layoutTarget, widgets[index].widgetId, value); | |
| } | |
| // TODO: This seems to work, but verify the correctness and terseness of this, it's adapted from https://stackoverflow.com/a/67434028/775283 | |
| function exclude<T extends object>(props: T, additional?: (keyof T)[]): Omit<T, typeof additional extends Array<infer K> ? K : never> { | |
| const exclusions = ["kind", ...(additional || [])]; | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| return Object.fromEntries(Object.entries(props).filter((entry) => !exclusions.includes(entry[0]))) as any; | |
| } | |
| </script> | |
| <!-- TODO: Refactor this component to use `<svelte:component this={attributesObject} />` to avoid all the separate conditional components --> | |
| <div class={`widget-span ${className} ${extraClasses}`.trim()} class:row={direction === "row"} class:column={direction === "column"}> | |
| {#each widgets as component, index} | |
| {@const checkboxInput = narrowWidgetProps(component.props, "CheckboxInput")} | |
| {#if checkboxInput} | |
| <CheckboxInput {...exclude(checkboxInput)} on:checked={({ detail }) => widgetValueCommitAndUpdate(index, detail)} /> | |
| {/if} | |
| {@const colorInput = narrowWidgetProps(component.props, "ColorInput")} | |
| {#if colorInput} | |
| <ColorInput {...exclude(colorInput)} on:value={({ detail }) => widgetValueUpdate(index, detail)} on:startHistoryTransaction={() => widgetValueCommit(index, colorInput.value)} /> | |
| {/if} | |
| {@const curvesInput = narrowWidgetProps(component.props, "CurveInput")} | |
| {#if curvesInput} | |
| <CurveInput {...exclude(curvesInput)} on:value={({ detail }) => debouncer((value) => widgetValueCommitAndUpdate(index, value), { debounceTime: 120 }).debounceUpdateValue(detail)} /> | |
| {/if} | |
| {@const dropdownInput = narrowWidgetProps(component.props, "DropdownInput")} | |
| {#if dropdownInput} | |
| <DropdownInput | |
| {...exclude(dropdownInput)} | |
| on:hoverInEntry={({ detail }) => { | |
| return widgetValueUpdate(index, detail); | |
| }} | |
| on:hoverOutEntry={({ detail }) => { | |
| return widgetValueUpdate(index, detail); | |
| }} | |
| on:selectedIndex={({ detail }) => widgetValueCommitAndUpdate(index, detail)} | |
| /> | |
| {/if} | |
| {@const fontInput = narrowWidgetProps(component.props, "FontInput")} | |
| {#if fontInput} | |
| <FontInput {...exclude(fontInput)} on:changeFont={({ detail }) => widgetValueCommitAndUpdate(index, detail)} /> | |
| {/if} | |
| {@const parameterExposeButton = narrowWidgetProps(component.props, "ParameterExposeButton")} | |
| {#if parameterExposeButton} | |
| <ParameterExposeButton {...exclude(parameterExposeButton)} action={() => widgetValueCommitAndUpdate(index, undefined)} /> | |
| {/if} | |
| {@const iconButton = narrowWidgetProps(component.props, "IconButton")} | |
| {#if iconButton} | |
| <IconButton {...exclude(iconButton)} action={() => widgetValueCommitAndUpdate(index, undefined)} /> | |
| {/if} | |
| {@const iconLabel = narrowWidgetProps(component.props, "IconLabel")} | |
| {#if iconLabel} | |
| <IconLabel {...exclude(iconLabel)} /> | |
| {/if} | |
| {@const imageButton = narrowWidgetProps(component.props, "ImageButton")} | |
| {#if imageButton} | |
| <ImageButton {...exclude(imageButton)} action={() => widgetValueCommitAndUpdate(index, undefined)} /> | |
| {/if} | |
| {@const nodeCatalog = narrowWidgetProps(component.props, "NodeCatalog")} | |
| {#if nodeCatalog} | |
| <NodeCatalog {...exclude(nodeCatalog)} on:selectNodeType={(e) => widgetValueCommitAndUpdate(index, e.detail)} /> | |
| {/if} | |
| {@const numberInput = narrowWidgetProps(component.props, "NumberInput")} | |
| {#if numberInput} | |
| <NumberInput | |
| {...exclude(numberInput)} | |
| on:value={({ detail }) => debouncer((value) => widgetValueUpdate(index, value)).debounceUpdateValue(detail)} | |
| on:startHistoryTransaction={() => widgetValueCommit(index, numberInput.value)} | |
| incrementCallbackIncrease={() => widgetValueCommitAndUpdate(index, "Increment")} | |
| incrementCallbackDecrease={() => widgetValueCommitAndUpdate(index, "Decrement")} | |
| /> | |
| {/if} | |
| {@const referencePointInput = narrowWidgetProps(component.props, "ReferencePointInput")} | |
| {#if referencePointInput} | |
| <ReferencePointInput {...exclude(referencePointInput)} on:value={({ detail }) => widgetValueCommitAndUpdate(index, detail)} /> | |
| {/if} | |
| {@const popoverButton = narrowWidgetProps(component.props, "PopoverButton")} | |
| {#if popoverButton} | |
| <PopoverButton {...exclude(popoverButton, ["popoverLayout"])}> | |
| <WidgetLayout layout={{ layout: popoverButton.popoverLayout, layoutTarget: layoutTarget }} /> | |
| </PopoverButton> | |
| {/if} | |
| {@const radioInput = narrowWidgetProps(component.props, "RadioInput")} | |
| {#if radioInput} | |
| <RadioInput {...exclude(radioInput)} on:selectedIndex={({ detail }) => widgetValueCommitAndUpdate(index, detail)} /> | |
| {/if} | |
| {@const separator = narrowWidgetProps(component.props, "Separator")} | |
| {#if separator} | |
| <Separator {...exclude(separator)} /> | |
| {/if} | |
| {@const workingColorsInput = narrowWidgetProps(component.props, "WorkingColorsInput")} | |
| {#if workingColorsInput} | |
| <WorkingColorsInput {...exclude(workingColorsInput)} /> | |
| {/if} | |
| {@const textAreaInput = narrowWidgetProps(component.props, "TextAreaInput")} | |
| {#if textAreaInput} | |
| <TextAreaInput {...exclude(textAreaInput)} on:commitText={({ detail }) => widgetValueCommitAndUpdate(index, detail)} /> | |
| {/if} | |
| {@const textButton = narrowWidgetProps(component.props, "TextButton")} | |
| {#if textButton} | |
| <TextButton {...exclude(textButton)} action={() => widgetValueCommitAndUpdate(index, undefined)} /> | |
| {/if} | |
| {@const breadcrumbTrailButtons = narrowWidgetProps(component.props, "BreadcrumbTrailButtons")} | |
| {#if breadcrumbTrailButtons} | |
| <BreadcrumbTrailButtons {...exclude(breadcrumbTrailButtons)} action={(breadcrumbIndex) => widgetValueCommitAndUpdate(index, breadcrumbIndex)} /> | |
| {/if} | |
| {@const textInput = narrowWidgetProps(component.props, "TextInput")} | |
| {#if textInput} | |
| <TextInput {...exclude(textInput)} on:commitText={({ detail }) => widgetValueCommitAndUpdate(index, detail)} /> | |
| {/if} | |
| {@const textLabel = narrowWidgetProps(component.props, "TextLabel")} | |
| {#if textLabel} | |
| <TextLabel {...exclude(textLabel, ["value"])}>{textLabel.value}</TextLabel> | |
| {/if} | |
| {/each} | |
| </div> | |
| <style lang="scss" global> | |
| .widget-span.column { | |
| flex: 0 0 auto; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .widget-span.row { | |
| flex: 0 0 auto; | |
| display: flex; | |
| min-height: 32px; | |
| > * { | |
| --widget-height: 24px; | |
| margin: calc((24px - var(--widget-height)) / 2 + 4px) 0; | |
| min-height: var(--widget-height); | |
| &:not(.multiline) { | |
| line-height: var(--widget-height); | |
| } | |
| &.icon-label.size-12 { | |
| --widget-height: 12px; | |
| } | |
| &.icon-label.size-16 { | |
| --widget-height: 16px; | |
| } | |
| } | |
| } | |
| </style> | |