Separated Links into a feature and Context

This commit is contained in:
thepaperpilot 2022-03-20 13:57:45 -05:00
parent b60d170657
commit 5ce8195779
21 changed files with 188 additions and 125 deletions

View file

@ -1,35 +1,21 @@
<template> <template>
<slot /> <slot />
<div ref="resizeListener" class="resize-listener" /> <div ref="resizeListener" class="resize-listener" />
<svg v-if="validLinks" v-bind="$attrs">
<LinkVue
v-for="(link, index) in validLinks"
:key="index"
:link="link"
:startNode="nodes[link.startNode.id]!"
:endNode="nodes[link.endNode.id]!"
/>
</svg>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { import {
Link, RegisterNodeInjectionKey,
LinkNode, UnregisterNodeInjectionKey,
NodesInjectionKey, NodesInjectionKey,
RegisterLinkNodeInjectionKey, FeatureNode
UnregisterLinkNodeInjectionKey } from "game/layers";
} from "features/links"; import { nextTick, onMounted, provide, ref } from "vue";
import { computed, nextTick, onMounted, provide, ref, toRef } from "vue";
import LinkVue from "./Link.vue";
const _props = defineProps<{ links?: Link[] }>();
const links = toRef(_props, "links");
const observer = new MutationObserver(updateNodes); const observer = new MutationObserver(updateNodes);
const resizeObserver = new ResizeObserver(updateNodes); const resizeObserver = new ResizeObserver(updateNodes);
const nodes = ref<Record<string, LinkNode | undefined>>({}); const nodes = ref<Record<string, FeatureNode | undefined>>({});
defineExpose({ nodes }); defineExpose({ nodes });
@ -43,26 +29,13 @@ onMounted(() => {
} }
}); });
const validLinks = computed(
() =>
links.value?.filter(link => {
const n = nodes.value;
return (
n[link.startNode.id]?.x != undefined &&
n[link.startNode.id]?.y != undefined &&
n[link.endNode.id]?.x != undefined &&
n[link.endNode.id]?.y != undefined
);
}) ?? []
);
const observerOptions = { const observerOptions = {
attributes: true, attributes: true,
childList: true, childList: true,
subtree: false subtree: false
}; };
provide(RegisterLinkNodeInjectionKey, (id, element) => { provide(RegisterNodeInjectionKey, (id, element) => {
nodes.value[id] = { element }; nodes.value[id] = { element };
observer.observe(element, observerOptions); observer.observe(element, observerOptions);
nextTick(() => { nextTick(() => {
@ -71,7 +44,7 @@ provide(RegisterLinkNodeInjectionKey, (id, element) => {
} }
}); });
}); });
provide(UnregisterLinkNodeInjectionKey, id => { provide(UnregisterNodeInjectionKey, id => {
nodes.value[id] = undefined; nodes.value[id] = undefined;
}); });
provide(NodesInjectionKey, nodes); provide(NodesInjectionKey, nodes);

View file

@ -10,9 +10,9 @@
:class="[{ showGoBack }, unref(classes)]" :class="[{ showGoBack }, unref(classes)]"
v-else v-else
> >
<Links :links="unref(links)" ref="linksRef"> <Context ref="contextRef">
<component :is="component" /> <component :is="component" />
</Links> </Context>
</div> </div>
<button v-if="unref(minimizable)" class="minimize" @click="minimized.value = true"> <button v-if="unref(minimizable)" class="minimize" @click="minimized.value = true">
@ -21,17 +21,17 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import Links from "components/links/Links.vue";
import projInfo from "data/projInfo.json"; import projInfo from "data/projInfo.json";
import { CoercableComponent, StyleValue } from "features/feature"; import { CoercableComponent, StyleValue } from "features/feature";
import { Link, LinkNode } from "features/links"; import { FeatureNode } from "game/layers";
import { PersistentRef } from "game/persistence"; import { PersistentRef } from "game/persistence";
import player from "game/player"; import player from "game/player";
import { computeComponent, processedPropType, wrapRef } from "util/vue"; import { computeComponent, processedPropType, wrapRef } from "util/vue";
import { computed, defineComponent, nextTick, PropType, Ref, ref, toRefs, unref, watch } from "vue"; import { computed, defineComponent, nextTick, PropType, Ref, ref, toRefs, unref, watch } from "vue";
import Context from "./Context.vue";
export default defineComponent({ export default defineComponent({
components: { Links }, components: { Context },
props: { props: {
index: { index: {
type: Number, type: Number,
@ -60,10 +60,9 @@ export default defineComponent({
color: processedPropType<string>(String), color: processedPropType<string>(String),
style: processedPropType<StyleValue>(String, Object, Array), style: processedPropType<StyleValue>(String, Object, Array),
classes: processedPropType<Record<string, boolean>>(Object), classes: processedPropType<Record<string, boolean>>(Object),
links: processedPropType<Link[]>(Array),
minimizable: processedPropType<boolean>(Boolean), minimizable: processedPropType<boolean>(Boolean),
nodes: { nodes: {
type: Object as PropType<Ref<Record<string, LinkNode | undefined>>>, type: Object as PropType<Ref<Record<string, FeatureNode | undefined>>>,
required: true required: true
} }
}, },
@ -84,9 +83,9 @@ export default defineComponent({
updateTab(minimized, minWidth) updateTab(minimized, minWidth)
); );
const linksRef = ref<typeof Links | null>(null); const contextRef = ref<typeof Context | null>(null);
watch( watch(
() => linksRef.value?.nodes, () => contextRef.value?.nodes,
nodes => { nodes => {
if (nodes) { if (nodes) {
props.nodes.value = nodes; props.nodes.value = nodes;
@ -116,7 +115,7 @@ export default defineComponent({
return { return {
component, component,
showGoBack, showGoBack,
linksRef, contextRef,
unref, unref,
goBack goBack
}; };

View file

@ -17,9 +17,9 @@
<slot name="header" :shown="isOpen"> default header </slot> <slot name="header" :shown="isOpen"> default header </slot>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<Links :links="links" ref="linksRef"> <Context ref="contextRef">
<slot name="body" :shown="isOpen"> default body </slot> <slot name="body" :shown="isOpen"> default body </slot>
</Links> </Context>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<slot name="footer" :shown="isOpen"> <slot name="footer" :shown="isOpen">
@ -39,13 +39,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Link, LinkNode } from "features/links"; import { FeatureNode } from "game/layers";
import { computed, ref, toRefs } from "vue"; import { computed, ref, toRefs } from "vue";
import Links from "./links/Links.vue"; import Context from "./Context.vue";
const _props = defineProps<{ const _props = defineProps<{
modelValue: boolean; modelValue: boolean;
links?: Link[];
}>(); }>();
const props = toRefs(_props); const props = toRefs(_props);
const emit = defineEmits<{ const emit = defineEmits<{
@ -59,9 +58,9 @@ function close() {
const isAnimating = ref(false); const isAnimating = ref(false);
const linksRef = ref<typeof Links | null>(null); const contextRef = ref<typeof Context | null>(null);
const nodes = computed<Record<string, LinkNode | undefined> | null>( const nodes = computed<Record<string, FeatureNode | undefined> | null>(
() => linksRef.value?.nodes ?? null () => contextRef.value?.nodes ?? null
); );
defineExpose({ isOpen, nodes }); defineExpose({ isOpen, nodes });

View file

@ -1,16 +1,16 @@
<template> <template>
<div class="branch" ref="node"></div> <div class="node" ref="node"></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { RegisterLinkNodeInjectionKey, UnregisterLinkNodeInjectionKey } from "features/links"; import { RegisterNodeInjectionKey, UnregisterNodeInjectionKey } from "game/layers";
import { computed, inject, onUnmounted, ref, toRefs, unref, watch } from "vue"; import { computed, inject, onUnmounted, ref, toRefs, unref, watch } from "vue";
const _props = defineProps<{ id: string }>(); const _props = defineProps<{ id: string }>();
const props = toRefs(_props); const props = toRefs(_props);
const register = inject(RegisterLinkNodeInjectionKey); const register = inject(RegisterNodeInjectionKey);
const unregister = inject(UnregisterLinkNodeInjectionKey); const unregister = inject(UnregisterNodeInjectionKey);
const node = ref<HTMLElement | null>(null); const node = ref<HTMLElement | null>(null);
const parentNode = computed(() => node.value && node.value.parentElement); const parentNode = computed(() => node.value && node.value.parentElement);
@ -30,7 +30,7 @@ if (register && unregister) {
</script> </script>
<style scoped> <style scoped>
.branch { .node {
position: absolute; position: absolute;
z-index: -10; z-index: -10;
top: 0; top: 0;

View file

@ -18,7 +18,7 @@
> >
<component v-if="component" :is="component" /> <component v-if="component" :is="component" />
<MarkNode :mark="unref(mark)" /> <MarkNode :mark="unref(mark)" />
<LinkNode :id="id" /> <Node :id="id" />
</div> </div>
</template> </template>
@ -27,7 +27,7 @@ import { CoercableComponent, Visibility } from "features/feature";
import { computeOptionalComponent, processedPropType } from "util/vue"; import { computeOptionalComponent, processedPropType } from "util/vue";
import { defineComponent, StyleValue, toRefs, unref } from "vue"; import { defineComponent, StyleValue, toRefs, unref } from "vue";
import Tooltip from "components/Tooltip.vue"; import Tooltip from "components/Tooltip.vue";
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import MarkNode from "components/MarkNode.vue"; import MarkNode from "components/MarkNode.vue";
import "components/common/features.css"; import "components/common/features.css";
@ -52,7 +52,7 @@ export default defineComponent({
} }
}, },
components: { components: {
LinkNode, Node,
MarkNode, MarkNode,
Tooltip Tooltip
}, },

View file

@ -40,7 +40,7 @@
<div class="fill" :style="[barStyle, unref(style) ?? {}, unref(fillStyle) ?? {}]" /> <div class="fill" :style="[barStyle, unref(style) ?? {}, unref(fillStyle) ?? {}]" />
</div> </div>
<MarkNode :mark="unref(mark)" /> <MarkNode :mark="unref(mark)" />
<LinkNode :id="id" /> <Node :id="id" />
</div> </div>
</template> </template>
@ -50,7 +50,7 @@ import { CoercableComponent, Visibility } from "features/feature";
import Decimal, { DecimalSource } from "util/bignum"; import Decimal, { DecimalSource } from "util/bignum";
import { computeOptionalComponent, processedPropType, unwrapRef } from "util/vue"; import { computeOptionalComponent, processedPropType, unwrapRef } from "util/vue";
import { computed, CSSProperties, defineComponent, StyleValue, toRefs, unref } from "vue"; import { computed, CSSProperties, defineComponent, StyleValue, toRefs, unref } from "vue";
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import MarkNode from "components/MarkNode.vue"; import MarkNode from "components/MarkNode.vue";
export default defineComponent({ export default defineComponent({
@ -90,7 +90,7 @@ export default defineComponent({
}, },
components: { components: {
MarkNode, MarkNode,
LinkNode Node
}, },
setup(props) { setup(props) {
const { progress, width, height, direction, display } = toRefs(props); const { progress, width, height, direction, display } = toRefs(props);

View file

@ -22,7 +22,7 @@ import {
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { Unsubscribe } from "nanoevents"; import { Unsubscribe } from "nanoevents";
import { computed, Ref, unref } from "vue"; import { computed, Ref, unref } from "vue";
import { Link } from "../links"; import { Link } from "../links/links";
export const BoardType = Symbol("Board"); export const BoardType = Symbol("Board");

View file

@ -22,7 +22,7 @@
</button> </button>
<component v-if="unref(comp)" :is="unref(comp)" /> <component v-if="unref(comp)" :is="unref(comp)" />
<MarkNode :mark="unref(mark)" /> <MarkNode :mark="unref(mark)" />
<LinkNode :id="id" /> <Node :id="id" />
</div> </div>
</template> </template>
@ -43,7 +43,7 @@ import {
UnwrapRef, UnwrapRef,
watchEffect watchEffect
} from "vue"; } from "vue";
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import MarkNode from "components/MarkNode.vue"; import MarkNode from "components/MarkNode.vue";
export default defineComponent({ export default defineComponent({
@ -91,7 +91,7 @@ export default defineComponent({
}, },
components: { components: {
MarkNode, MarkNode,
LinkNode Node
}, },
setup(props) { setup(props) {
const { active, maxed, canComplete, display } = toRefs(props); const { active, maxed, canComplete, display } = toRefs(props);

View file

@ -23,13 +23,13 @@
> >
<component v-if="unref(comp)" :is="unref(comp)" /> <component v-if="unref(comp)" :is="unref(comp)" />
<MarkNode :mark="unref(mark)" /> <MarkNode :mark="unref(mark)" />
<LinkNode :id="id" /> <Node :id="id" />
</button> </button>
</template> </template>
<script lang="tsx"> <script lang="tsx">
import "components/common/features.css"; import "components/common/features.css";
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import MarkNode from "components/MarkNode.vue"; import MarkNode from "components/MarkNode.vue";
import { GenericClickable } from "features/clickables/clickable"; import { GenericClickable } from "features/clickables/clickable";
import { jsx, StyleValue, Visibility } from "features/feature"; import { jsx, StyleValue, Visibility } from "features/feature";
@ -81,7 +81,7 @@ export default defineComponent({
} }
}, },
components: { components: {
LinkNode, Node,
MarkNode MarkNode
}, },
setup(props) { setup(props) {

View file

@ -18,13 +18,13 @@
> >
<div v-if="title"><component :is="titleComponent" /></div> <div v-if="title"><component :is="titleComponent" /></div>
<component :is="component" style="white-space: pre-line" /> <component :is="component" style="white-space: pre-line" />
<LinkNode :id="id" /> <Node :id="id" />
</button> </button>
</template> </template>
<script lang="ts"> <script lang="ts">
import "components/common/features.css"; import "components/common/features.css";
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import { CoercableComponent, StyleValue, Visibility } from "features/feature"; import { CoercableComponent, StyleValue, Visibility } from "features/feature";
import { import {
computeComponent, computeComponent,
@ -58,7 +58,7 @@ export default defineComponent({
} }
}, },
components: { components: {
LinkNode Node
}, },
setup(props) { setup(props) {
const { onClick, onHold, title, display } = toRefs(props); const { onClick, onHold, title, display } = toRefs(props);

View file

@ -24,12 +24,12 @@
<component :is="bodyComponent" :style="unref(bodyStyle)" /> <component :is="bodyComponent" :style="unref(bodyStyle)" />
</div> </div>
</CollapseTransition> </CollapseTransition>
<LinkNode :id="id" /> <Node :id="id" />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import themes from "data/themes"; import themes from "data/themes";
import { CoercableComponent, Visibility } from "features/feature"; import { CoercableComponent, Visibility } from "features/feature";
import settings from "game/settings"; import settings from "game/settings";
@ -66,7 +66,7 @@ export default defineComponent({
} }
}, },
components: { components: {
LinkNode, Node,
CollapseTransition CollapseTransition
}, },
setup(props) { setup(props) {

View file

@ -1,24 +0,0 @@
import { Position } from "game/layers";
import { InjectionKey, Ref, SVGAttributes } from "vue";
export interface LinkNode {
x?: number;
y?: number;
rect?: DOMRect;
element: HTMLElement;
}
export interface Link extends SVGAttributes {
startNode: { id: string };
endNode: { id: string };
offsetStart?: Position;
offsetEnd?: Position;
}
export const RegisterLinkNodeInjectionKey: InjectionKey<
(id: string, element: HTMLElement) => void
> = Symbol("RegisterLinkNode");
export const UnregisterLinkNodeInjectionKey: InjectionKey<(id: string) => void> =
Symbol("UnregisterLinkNode");
export const NodesInjectionKey: InjectionKey<Ref<Record<string, LinkNode | undefined>>> =
Symbol("Nodes");

View file

@ -11,13 +11,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Link, LinkNode } from "features/links"; import { Link } from "features/links/links";
import { FeatureNode } from "game/layers";
import { computed, toRefs, unref } from "vue"; import { computed, toRefs, unref } from "vue";
const _props = defineProps<{ const _props = defineProps<{
link: Link; link: Link;
startNode: LinkNode; startNode: FeatureNode;
endNode: LinkNode; endNode: FeatureNode;
}>(); }>();
const props = toRefs(_props); const props = toRefs(_props);

View file

@ -0,0 +1,37 @@
<template>
<svg v-if="validLinks" v-bind="$attrs">
<LinkVue
v-for="(link, index) in validLinks"
:key="index"
:link="link"
:startNode="nodes[link.startNode.id]!"
:endNode="nodes[link.endNode.id]!"
/>
</svg>
</template>
<script setup lang="ts">
import { Link } from "features/links/links";
import { NodesInjectionKey } from "game/layers";
import { computed, inject, toRef } from "vue";
import LinkVue from "./Link.vue";
const _props = defineProps<{ links?: Link[] }>();
const links = toRef(_props, "links");
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const nodes = inject(NodesInjectionKey)!;
const validLinks = computed(
() =>
links.value?.filter(link => {
const n = nodes.value;
return (
n[link.startNode.id]?.x != undefined &&
n[link.startNode.id]?.y != undefined &&
n[link.endNode.id]?.x != undefined &&
n[link.endNode.id]?.y != undefined
);
}) ?? []
);
</script>

View file

@ -0,0 +1,65 @@
import LinksComponent from "./Links.vue";
import { Component, GatherProps, Replace } from "features/feature";
import { Position } from "game/layers";
import {
Computable,
GetComputableType,
processComputable,
ProcessedComputable
} from "util/computed";
import { createLazyProxy } from "util/proxies";
import { SVGAttributes } from "vue";
export const LinksType = Symbol("Links");
export interface Link extends SVGAttributes {
startNode: { id: string };
endNode: { id: string };
offsetStart?: Position;
offsetEnd?: Position;
}
export interface LinksOptions {
links?: Computable<Link[]>;
}
export interface BaseLinks {
type: typeof LinksType;
[Component]: typeof LinksComponent;
[GatherProps]: () => Record<string, unknown>;
}
export type Links<T extends LinksOptions> = Replace<
T & BaseLinks,
{
links: GetComputableType<T["links"]>;
}
>;
export type GenericLinks = Replace<
Links<LinksOptions>,
{
links: ProcessedComputable<Link[]>;
}
>;
export function createLinks<T extends LinksOptions>(
optionsFunc: (() => T) & ThisType<Links<T>>
): Links<T> {
return createLazyProxy(() => {
const links: T & Partial<BaseLinks> = optionsFunc();
links.type = LinksType;
links[Component] = LinksComponent;
processComputable(links as T, "links");
links[GatherProps] = function (this: GenericLinks) {
const { links } = this;
return {
links
};
};
return links as unknown as Links<T>;
});
}

View file

@ -10,7 +10,7 @@
:class="{ feature: true, milestone: true, done: unref(earned), ...unref(classes) }" :class="{ feature: true, milestone: true, done: unref(earned), ...unref(classes) }"
> >
<component :is="unref(comp)" /> <component :is="unref(comp)" />
<LinkNode :id="id" /> <Node :id="id" />
</div> </div>
</template> </template>
@ -20,7 +20,7 @@ import { jsx, StyleValue, Visibility } from "features/feature";
import { GenericMilestone } from "features/milestones/milestone"; import { GenericMilestone } from "features/milestones/milestone";
import { coerceComponent, isCoercableComponent, processedPropType, unwrapRef } from "util/vue"; import { coerceComponent, isCoercableComponent, processedPropType, unwrapRef } from "util/vue";
import { Component, defineComponent, shallowRef, toRefs, unref, UnwrapRef, watchEffect } from "vue"; import { Component, defineComponent, shallowRef, toRefs, unref, UnwrapRef, watchEffect } from "vue";
import LinkNode from "../../components/links/LinkNode.vue"; import Node from "../../components/Node.vue";
export default defineComponent({ export default defineComponent({
props: { props: {
@ -48,7 +48,7 @@ export default defineComponent({
} }
}, },
components: { components: {
LinkNode Node
}, },
setup(props) { setup(props) {
const { display } = toRefs(props); const { display } = toRefs(props);

View file

@ -25,14 +25,16 @@
small small
/> />
</span> </span>
<Links v-if="branches" :links="unref(branches)" />
</template> </template>
<script lang="ts"> <script lang="ts">
import "components/common/table.css"; import "components/common/table.css";
import { GenericTreeNode } from "features/trees/tree"; import { GenericTreeNode, TreeBranch } from "features/trees/tree";
import { processedPropType } from "util/vue"; import { processedPropType } from "util/vue";
import { defineComponent, unref } from "vue"; import { defineComponent, unref } from "vue";
import TreeNode from "./TreeNode.vue"; import TreeNode from "./TreeNode.vue";
import Links from "features/links/Links.vue";
export default defineComponent({ export default defineComponent({
props: { props: {
@ -41,9 +43,10 @@ export default defineComponent({
required: true required: true
}, },
leftSideNodes: processedPropType<GenericTreeNode[]>(Array), leftSideNodes: processedPropType<GenericTreeNode[]>(Array),
rightSideNodes: processedPropType<GenericTreeNode[]>(Array) rightSideNodes: processedPropType<GenericTreeNode[]>(Array),
branches: processedPropType<TreeBranch[]>(Array)
}, },
components: { TreeNode }, components: { TreeNode, Links },
setup() { setup() {
function gatherNodeProps(node: GenericTreeNode) { function gatherNodeProps(node: GenericTreeNode) {
const { const {

View file

@ -33,12 +33,12 @@
<component :is="unref(comp)" /> <component :is="unref(comp)" />
</button> </button>
<MarkNode :mark="unref(mark)" /> <MarkNode :mark="unref(mark)" />
<LinkNode :id="id" /> <Node :id="id" />
</Tooltip> </Tooltip>
</template> </template>
<script lang="ts"> <script lang="ts">
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import MarkNode from "components/MarkNode.vue"; import MarkNode from "components/MarkNode.vue";
import TooltipVue from "components/Tooltip.vue"; import TooltipVue from "components/Tooltip.vue";
import { CoercableComponent, StyleValue, Visibility } from "features/feature"; import { CoercableComponent, StyleValue, Visibility } from "features/feature";
@ -94,7 +94,7 @@ export default defineComponent({
components: { components: {
Tooltip: TooltipVue, Tooltip: TooltipVue,
MarkNode, MarkNode,
LinkNode Node
}, },
setup(props) { setup(props) {
const { tooltip, forceTooltip, onClick, onHold, display } = toRefs(props); const { tooltip, forceTooltip, onClick, onHold, display } = toRefs(props);

View file

@ -8,7 +8,7 @@ import {
StyleValue, StyleValue,
Visibility Visibility
} from "features/feature"; } from "features/feature";
import { Link } from "features/links"; import { Link } from "features/links/links";
import { GenericReset } from "features/reset"; import { GenericReset } from "features/reset";
import { displayResource, Resource } from "features/resources/resource"; import { displayResource, Resource } from "features/resources/resource";
import { Tooltip } from "features/tooltip"; import { Tooltip } from "features/tooltip";
@ -199,8 +199,8 @@ export function createTree<T extends TreeOptions>(
processComputable(tree as T, "branches"); processComputable(tree as T, "branches");
tree[GatherProps] = function (this: GenericTree) { tree[GatherProps] = function (this: GenericTree) {
const { nodes, leftSideNodes, rightSideNodes } = this; const { nodes, leftSideNodes, rightSideNodes, branches } = this;
return { nodes, leftSideNodes, rightSideNodes }; return { nodes, leftSideNodes, rightSideNodes, branches };
}; };
return tree as unknown as Tree<T>; return tree as unknown as Tree<T>;

View file

@ -20,13 +20,13 @@
> >
<component v-if="unref(component)" :is="unref(component)" /> <component v-if="unref(component)" :is="unref(component)" />
<MarkNode :mark="unref(mark)" /> <MarkNode :mark="unref(mark)" />
<LinkNode :id="id" /> <Node :id="id" />
</button> </button>
</template> </template>
<script lang="tsx"> <script lang="tsx">
import "components/common/features.css"; import "components/common/features.css";
import LinkNode from "components/links/LinkNode.vue"; import Node from "components/Node.vue";
import MarkNode from "components/MarkNode.vue"; import MarkNode from "components/MarkNode.vue";
import { jsx, StyleValue, Visibility } from "features/feature"; import { jsx, StyleValue, Visibility } from "features/feature";
import { displayResource, Resource } from "features/resources/resource"; import { displayResource, Resource } from "features/resources/resource";
@ -77,7 +77,7 @@ export default defineComponent({
} }
}, },
components: { components: {
LinkNode, Node,
MarkNode MarkNode
}, },
setup(props) { setup(props) {

View file

@ -7,7 +7,6 @@ import {
setDefault, setDefault,
StyleValue StyleValue
} from "features/feature"; } from "features/feature";
import { Link, LinkNode } from "features/links";
import { import {
Computable, Computable,
GetComputableType, GetComputableType,
@ -17,11 +16,25 @@ import {
} from "util/computed"; } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { createNanoEvents, Emitter } from "nanoevents"; import { createNanoEvents, Emitter } from "nanoevents";
import { Ref, ref, unref } from "vue"; import { InjectionKey, Ref, ref, unref } from "vue";
import { globalBus } from "./events"; import { globalBus } from "./events";
import { persistent, PersistentRef } from "./persistence"; import { persistent, PersistentRef } from "./persistence";
import player from "./player"; import player from "./player";
export interface FeatureNode {
x?: number;
y?: number;
rect?: DOMRect;
element: HTMLElement;
}
export const RegisterNodeInjectionKey: InjectionKey<(id: string, element: HTMLElement) => void> =
Symbol("RegisterNode");
export const UnregisterNodeInjectionKey: InjectionKey<(id: string) => void> =
Symbol("UnregisterNode");
export const NodesInjectionKey: InjectionKey<Ref<Record<string, FeatureNode | undefined>>> =
Symbol("Nodes");
export interface LayerEvents { export interface LayerEvents {
// Generation // Generation
preUpdate: (diff: number) => void; preUpdate: (diff: number) => void;
@ -55,7 +68,6 @@ export interface LayerOptions {
minimizable?: Computable<boolean>; minimizable?: Computable<boolean>;
forceHideGoBack?: Computable<boolean>; forceHideGoBack?: Computable<boolean>;
minWidth?: Computable<number>; minWidth?: Computable<number>;
links?: Computable<Link[]>;
} }
export interface BaseLayer { export interface BaseLayer {
@ -63,7 +75,7 @@ export interface BaseLayer {
emitter: Emitter<LayerEvents>; emitter: Emitter<LayerEvents>;
on: OmitThisParameter<Emitter<LayerEvents>["on"]>; on: OmitThisParameter<Emitter<LayerEvents>["on"]>;
emit: <K extends keyof LayerEvents>(event: K, ...args: Parameters<LayerEvents[K]>) => void; emit: <K extends keyof LayerEvents>(event: K, ...args: Parameters<LayerEvents[K]>) => void;
nodes: Ref<Record<string, LinkNode | undefined>>; nodes: Ref<Record<string, FeatureNode | undefined>>;
} }
export type Layer<T extends LayerOptions> = Replace< export type Layer<T extends LayerOptions> = Replace<
@ -77,7 +89,6 @@ export type Layer<T extends LayerOptions> = Replace<
minWidth: GetComputableTypeWithDefault<T["minWidth"], 600>; minWidth: GetComputableTypeWithDefault<T["minWidth"], 600>;
minimizable: GetComputableTypeWithDefault<T["minimizable"], true>; minimizable: GetComputableTypeWithDefault<T["minimizable"], true>;
forceHideGoBack: GetComputableType<T["forceHideGoBack"]>; forceHideGoBack: GetComputableType<T["forceHideGoBack"]>;
links: GetComputableType<T["links"]>;
} }
>; >;
@ -112,7 +123,6 @@ export function createLayer<T extends LayerOptions>(
setDefault(layer, "minWidth", 600); setDefault(layer, "minWidth", 600);
processComputable(layer as T, "minimizable"); processComputable(layer as T, "minimizable");
setDefault(layer, "minimizable", true); setDefault(layer, "minimizable", true);
processComputable(layer as T, "links");
return layer as unknown as Layer<T>; return layer as unknown as Layer<T>;
}); });