Fix Svelte regressions related to some input widgets
This commit is contained in:
parent
a993938d80
commit
964cf6df15
|
|
@ -306,7 +306,7 @@
|
||||||
value={newColor.toHexOptionalAlpha() || "-"}
|
value={newColor.toHexOptionalAlpha() || "-"}
|
||||||
on:commitText={({ detail }) => setColorCode(detail)}
|
on:commitText={({ detail }) => setColorCode(detail)}
|
||||||
centered={true}
|
centered={true}
|
||||||
tooltip="Color code in hexadecimal format. 6 digits if opaque, 8 with alpha.\nAccepts input of CSS color values including named colors."
|
tooltip={"Color code in hexadecimal format. 6 digits if opaque, 8 with alpha.\nAccepts input of CSS color values including named colors."}
|
||||||
/>
|
/>
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
|
|
@ -347,8 +347,8 @@
|
||||||
unit={channel === "h" ? "°" : "%"}
|
unit={channel === "h" ? "°" : "%"}
|
||||||
minWidth={56}
|
minWidth={56}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
h: "Hue component, the "color" along the rainbow",
|
h: `Hue component, the "color" along the rainbow`,
|
||||||
s: "Saturation component, the "colorfulness" from gray to vivid",
|
s: `Saturation component, the "colorfulness" from gray to vivid`,
|
||||||
v: "Value (or Brightness), the distance away from being darkened to black",
|
v: "Value (or Brightness), the distance away from being darkened to black",
|
||||||
}[channel]}
|
}[channel]}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
<svelte:options accessors={true} />
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from "svelte";
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
|
|
@ -28,32 +30,23 @@
|
||||||
export let virtualScrollingEntryHeight = 0;
|
export let virtualScrollingEntryHeight = 0;
|
||||||
export let tooltip: string | undefined = undefined;
|
export let tooltip: string | undefined = undefined;
|
||||||
|
|
||||||
let isOpen = open;
|
|
||||||
let highlighted = activeEntry as MenuListEntry | undefined;
|
let highlighted = activeEntry as MenuListEntry | undefined;
|
||||||
let virtualScrollingEntriesStart = 0;
|
let virtualScrollingEntriesStart = 0;
|
||||||
|
|
||||||
// Called only when `open` is changed from outside this component (with v-model)
|
// Called only when `open` is changed from outside this component (with v-model)
|
||||||
$: watchOpen(open);
|
$: watchOpen(open);
|
||||||
$: dispatch("open", isOpen);
|
$: watchRemeasureWidth(entries, drawIcon);
|
||||||
$: watchEntries(entries, self);
|
|
||||||
$: watchDrawIcon(drawIcon, self);
|
|
||||||
$: virtualScrollingTotalHeight = entries.length === 0 ? 0 : entries[0].length * virtualScrollingEntryHeight;
|
$: virtualScrollingTotalHeight = entries.length === 0 ? 0 : entries[0].length * virtualScrollingEntryHeight;
|
||||||
$: virtualScrollingStartIndex = Math.floor(virtualScrollingEntriesStart / virtualScrollingEntryHeight) || 0;
|
$: virtualScrollingStartIndex = Math.floor(virtualScrollingEntriesStart / virtualScrollingEntryHeight) || 0;
|
||||||
$: virtualScrollingEndIndex = entries.length === 0 ? 0 : Math.min(entries[0].length, virtualScrollingStartIndex + 1 + 400 / virtualScrollingEntryHeight);
|
$: virtualScrollingEndIndex = entries.length === 0 ? 0 : Math.min(entries[0].length, virtualScrollingStartIndex + 1 + 400 / virtualScrollingEntryHeight);
|
||||||
|
|
||||||
function watchOpen(open: boolean) {
|
function watchOpen(open: boolean) {
|
||||||
isOpen = open;
|
|
||||||
highlighted = activeEntry;
|
highlighted = activeEntry;
|
||||||
|
dispatch("open", open);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Svelte: fix infinite loop and reenable
|
function watchRemeasureWidth(_: MenuListEntry[][], __: boolean) {
|
||||||
function watchEntries(_: MenuListEntry[][], floatingMenu: FloatingMenu) {
|
self?.measureAndEmitNaturalWidth();
|
||||||
// floatingMenu?.div().measureAndEmitNaturalWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Svelte: fix infinite loop and reenable
|
|
||||||
function watchDrawIcon(_: boolean, floatingMenu: FloatingMenu) {
|
|
||||||
// floatingMenu?.div().measureAndEmitNaturalWidth();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onScroll(e: Event) {
|
function onScroll(e: Event) {
|
||||||
|
|
@ -69,29 +62,29 @@
|
||||||
dispatch("activeEntry", menuListEntry);
|
dispatch("activeEntry", menuListEntry);
|
||||||
|
|
||||||
// Close the containing menu
|
// Close the containing menu
|
||||||
if (menuListEntry.ref) menuListEntry.ref.isOpen = false;
|
if (menuListEntry.ref) menuListEntry.ref.open = false;
|
||||||
dispatch("open", false);
|
dispatch("open", false);
|
||||||
isOpen = false; // TODO: This is a hack for MenuBarInput submenus, remove it when we get rid of using `ref`
|
open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEntryPointerEnter(menuListEntry: MenuListEntry): void {
|
function onEntryPointerEnter(menuListEntry: MenuListEntry): void {
|
||||||
if (!menuListEntry.children?.length) return;
|
if (!menuListEntry.children?.length) return;
|
||||||
|
|
||||||
if (menuListEntry.ref) menuListEntry.ref.isOpen = true;
|
if (menuListEntry.ref) menuListEntry.ref.open = true;
|
||||||
else dispatch("open", true);
|
else dispatch("open", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEntryPointerLeave(menuListEntry: MenuListEntry): void {
|
function onEntryPointerLeave(menuListEntry: MenuListEntry): void {
|
||||||
if (!menuListEntry.children?.length) return;
|
if (!menuListEntry.children?.length) return;
|
||||||
|
|
||||||
if (menuListEntry.ref) menuListEntry.ref.isOpen = false;
|
if (menuListEntry.ref) menuListEntry.ref.open = false;
|
||||||
else dispatch("open", false);
|
else dispatch("open", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEntryOpen(menuListEntry: MenuListEntry): boolean {
|
function isEntryOpen(menuListEntry: MenuListEntry): boolean {
|
||||||
if (!menuListEntry.children?.length) return false;
|
if (!menuListEntry.children?.length) return false;
|
||||||
|
|
||||||
return open;
|
return menuListEntry.ref?.open || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles keyboard navigation for the menu. Returns if the entire menu stack should be dismissed
|
/// Handles keyboard navigation for the menu. Returns if the entire menu stack should be dismissed
|
||||||
|
|
@ -99,13 +92,13 @@
|
||||||
// Interactive menus should keep the active entry the same as the highlighted one
|
// Interactive menus should keep the active entry the same as the highlighted one
|
||||||
if (interactive) highlighted = activeEntry;
|
if (interactive) highlighted = activeEntry;
|
||||||
|
|
||||||
const menuOpen = isOpen;
|
const menuOpen = open;
|
||||||
const flatEntries = entries.flat().filter((entry) => !entry.disabled);
|
const flatEntries = entries.flat().filter((entry) => !entry.disabled);
|
||||||
const openChild = flatEntries.findIndex((entry) => entry.children?.length && entry.ref?.isOpen);
|
const openChild = flatEntries.findIndex((entry) => entry.children?.length && entry.ref?.open);
|
||||||
|
|
||||||
const openSubmenu = (highlighted: MenuListEntry): void => {
|
const openSubmenu = (highlighted: MenuListEntry): void => {
|
||||||
if (highlighted.ref && highlighted.children?.length) {
|
if (highlighted.ref && highlighted.children?.length) {
|
||||||
highlighted.ref.isOpen = true;
|
highlighted.ref.open = true;
|
||||||
|
|
||||||
// Highlight first item
|
// Highlight first item
|
||||||
highlighted.ref.setHighlighted(highlighted.children[0][0]);
|
highlighted.ref.setHighlighted(highlighted.children[0][0]);
|
||||||
|
|
@ -114,7 +107,7 @@
|
||||||
|
|
||||||
if (!menuOpen && (e.key === " " || e.key === "Enter")) {
|
if (!menuOpen && (e.key === " " || e.key === "Enter")) {
|
||||||
// Allow opening menu with space or enter
|
// Allow opening menu with space or enter
|
||||||
isOpen = true;
|
open = true;
|
||||||
highlighted = activeEntry;
|
highlighted = activeEntry;
|
||||||
} else if (menuOpen && openChild >= 0) {
|
} else if (menuOpen && openChild >= 0) {
|
||||||
// Redirect the keyboard navigation to a submenu if one is open
|
// Redirect the keyboard navigation to a submenu if one is open
|
||||||
|
|
@ -125,7 +118,7 @@
|
||||||
|
|
||||||
// Handle the child closing the entire menu stack
|
// Handle the child closing the entire menu stack
|
||||||
if (shouldCloseStack) {
|
if (shouldCloseStack) {
|
||||||
isOpen = false;
|
open = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if ((menuOpen || interactive) && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
|
} else if ((menuOpen || interactive) && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
|
||||||
|
|
@ -145,7 +138,7 @@
|
||||||
setHighlighted(newEntry);
|
setHighlighted(newEntry);
|
||||||
} else if (menuOpen && e.key === "Escape") {
|
} else if (menuOpen && e.key === "Escape") {
|
||||||
// Close menu with escape key
|
// Close menu with escape key
|
||||||
isOpen = false;
|
open = false;
|
||||||
|
|
||||||
// Reset active to before open
|
// Reset active to before open
|
||||||
setHighlighted(activeEntry);
|
setHighlighted(activeEntry);
|
||||||
|
|
@ -164,7 +157,7 @@
|
||||||
openSubmenu(highlighted);
|
openSubmenu(highlighted);
|
||||||
} else if (menuOpen && e.key === "ArrowLeft") {
|
} else if (menuOpen && e.key === "ArrowLeft") {
|
||||||
// Left arrow closes a submenu
|
// Left arrow closes a submenu
|
||||||
if (submenu) isOpen = false;
|
if (submenu) open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, keep the menu stack open
|
// By default, keep the menu stack open
|
||||||
|
|
@ -177,20 +170,15 @@
|
||||||
if (interactive && newHighlight?.value !== activeEntry?.value && newHighlight) dispatch("activeEntry", newHighlight);
|
if (interactive && newHighlight?.value !== activeEntry?.value && newHighlight) dispatch("activeEntry", newHighlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Svelte: Re-enable the `export` prefix
|
|
||||||
export function scrollViewTo(distanceDown: number): void {
|
export function scrollViewTo(distanceDown: number): void {
|
||||||
scroller.div().scrollTo(0, distanceDown);
|
scroller.div().scrollTo(0, distanceDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function menuIsOpen(): boolean {
|
|
||||||
return open;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FloatingMenu
|
<FloatingMenu
|
||||||
class="menu-list"
|
class="menu-list"
|
||||||
open={isOpen}
|
{open}
|
||||||
on:open={({ detail }) => (isOpen = detail)}
|
on:open={({ detail }) => (open = detail)}
|
||||||
on:naturalWidth
|
on:naturalWidth
|
||||||
type="Dropdown"
|
type="Dropdown"
|
||||||
windowEdgeMargin={0}
|
windowEdgeMargin={0}
|
||||||
|
|
@ -248,7 +236,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if entry.children}
|
{#if entry.children}
|
||||||
<svelte:self on:naturalWidth open={entry.ref?.menuIsOpen() || false} direction="TopRight" entries={entry.children} {minWidth} {drawIcon} {scrollableY} bind:this={entry.ref} />
|
<svelte:self on:naturalWidth open={entry.ref?.open || false} direction="TopRight" entries={entry.children} {minWidth} {drawIcon} {scrollableY} bind:this={entry.ref} />
|
||||||
{/if}
|
{/if}
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,8 @@
|
||||||
// Gets the client bounds of the elements and apply relevant styles to them
|
// Gets the client bounds of the elements and apply relevant styles to them
|
||||||
// TODO: Use the Vue :style attribute more whilst not causing recursive updates
|
// TODO: Use the Vue :style attribute more whilst not causing recursive updates
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
// Turning measuring on and off both cause the component to change, which causes the `updated()` Vue event to fire extraneous times (hurting performance and sometimes causing an infinite loop)
|
// Turning measuring on and off both causes the component to change, which causes the `updated()` Vue event to fire extraneous times (hurting performance and sometimes causing an infinite loop)
|
||||||
if (measuringOngoingGuard) return;
|
if (!measuringOngoingGuard) positionAndStyleFloatingMenu();
|
||||||
|
|
||||||
positionAndStyleFloatingMenu();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function resizeObserverCallback(entries: ResizeObserverEntry[]) {
|
function resizeObserverCallback(entries: ResizeObserverEntry[]) {
|
||||||
|
|
@ -204,13 +202,13 @@
|
||||||
|
|
||||||
// To be called by the parent component. Measures the actual width of the floating menu content element and returns it in a promise.
|
// To be called by the parent component. Measures the actual width of the floating menu content element and returns it in a promise.
|
||||||
export async function measureAndEmitNaturalWidth(): Promise<void> {
|
export async function measureAndEmitNaturalWidth(): Promise<void> {
|
||||||
|
if (!measuringOngoingGuard) return;
|
||||||
|
|
||||||
// Wait for the changed content which fired the `updated()` Vue event to be put into the DOM
|
// Wait for the changed content which fired the `updated()` Vue event to be put into the DOM
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
// Wait until all fonts have been loaded and rendered so measurements of content involving text are accurate
|
// Wait until all fonts have been loaded and rendered so measurements of content involving text are accurate
|
||||||
// API is experimental but supported in all browsers - https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready
|
await document.fonts.ready;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
await (document as any).fonts.ready;
|
|
||||||
|
|
||||||
// Make the component show itself with 0 min-width so it can be measured, and wait until the values have been updated to the DOM
|
// Make the component show itself with 0 min-width so it can be measured, and wait until the values have been updated to the DOM
|
||||||
measuringOngoing = true;
|
measuringOngoing = true;
|
||||||
|
|
|
||||||
|
|
@ -60,25 +60,20 @@
|
||||||
let layerTreeOptionsLayout = defaultWidgetLayout();
|
let layerTreeOptionsLayout = defaultWidgetLayout();
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerTreeStructureJs, (updateDocumentLayerTreeStructure) => {
|
|
||||||
rebuildLayerTree(updateDocumentLayerTreeStructure);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateLayerTreeOptionsLayout, (updateLayerTreeOptionsLayout) => {
|
editor.subscriptions.subscribeJsMessage(UpdateLayerTreeOptionsLayout, (updateLayerTreeOptionsLayout) => {
|
||||||
patchWidgetLayout(layerTreeOptionsLayout, updateLayerTreeOptionsLayout);
|
patchWidgetLayout(layerTreeOptionsLayout, updateLayerTreeOptionsLayout);
|
||||||
layerTreeOptionsLayout = layerTreeOptionsLayout;
|
layerTreeOptionsLayout = layerTreeOptionsLayout;
|
||||||
});
|
});
|
||||||
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerTreeStructureJs, (updateDocumentLayerTreeStructure) => {
|
||||||
const targetPath = updateDocumentLayerDetails.data.path;
|
rebuildLayerTree(updateDocumentLayerTreeStructure);
|
||||||
const targetLayer = updateDocumentLayerDetails.data;
|
});
|
||||||
|
|
||||||
const layer = layerCache.get(targetPath.toString());
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentLayerDetails, (updateDocumentLayerDetails) => {
|
||||||
if (layer) {
|
const targetLayer = updateDocumentLayerDetails.data;
|
||||||
Object.assign(layer, targetLayer);
|
const targetPath = targetLayer.path;
|
||||||
} else {
|
|
||||||
layerCache.set(targetPath.toString(), targetLayer);
|
updateLayerInTree(targetPath, targetLayer);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -134,34 +129,23 @@
|
||||||
window.getSelection()?.removeAllRanges();
|
window.getSelection()?.removeAllRanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Svelte: test this works
|
|
||||||
function selectLayerWithModifiers(e: MouseEvent, listing: LayerListingInfo) {
|
function selectLayerWithModifiers(e: MouseEvent, listing: LayerListingInfo) {
|
||||||
const ctrl = e.ctrlKey;
|
// Get the pressed state of the modifier keys
|
||||||
const meta = e.metaKey;
|
const [ctrl, meta, shift, alt] = [e.ctrlKey, e.metaKey, e.shiftKey, e.altKey];
|
||||||
const shift = e.shiftKey;
|
// Get the state of the platform's accel key and its opposite platform's accel key
|
||||||
const alt = e.altKey;
|
const [accel, oppositeAccel] = platformIsMac() ? [meta, ctrl] : [ctrl, meta];
|
||||||
|
|
||||||
if (!ctrl && !meta && !shift && !alt) selectLayer(false, false, false, listing, e);
|
// Select the layer only if the accel and/or shift keys are pressed
|
||||||
else if (!ctrl && !meta && shift && !alt) selectLayer(false, false, true, listing, e);
|
if (!oppositeAccel && !alt) selectLayer(accel, shift, listing);
|
||||||
else if (ctrl && !meta && !shift && !alt) selectLayer(true, false, false, listing, e);
|
|
||||||
else if (ctrl && !meta && shift && !alt) selectLayer(true, false, true, listing, e);
|
e.stopPropagation();
|
||||||
else if (!ctrl && meta && !shift && !alt) selectLayer(false, true, false, listing, e);
|
|
||||||
else if (!ctrl && meta && shift && !alt) selectLayer(false, true, true, listing, e);
|
|
||||||
else if ((ctrl && meta) || alt) e.stopPropagation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function selectLayer(ctrl: boolean, cmd: boolean, shift: boolean, listing: LayerListingInfo, event: Event) {
|
function selectLayer(accel: boolean, shift: boolean, listing: LayerListingInfo) {
|
||||||
|
// Don't select while we are entering text to rename the layer
|
||||||
if (listing.editingName) return;
|
if (listing.editingName) return;
|
||||||
|
|
||||||
const ctrlOrCmd = platformIsMac() ? cmd : ctrl;
|
editor.instance.selectLayer(listing.entry.path, accel, shift);
|
||||||
// Pressing the Ctrl key on a Mac, or the Cmd key on another platform, is a violation of the `.exact` qualifier so we filter it out here
|
|
||||||
const opposite = platformIsMac() ? ctrl : cmd;
|
|
||||||
|
|
||||||
if (!opposite) editor.instance.selectLayer(listing.entry.path, ctrlOrCmd, shift);
|
|
||||||
|
|
||||||
// We always want to stop propagation so the click event doesn't pass through the layer and cause a deselection by clicking the layer panel background
|
|
||||||
// This is also why we cover the remaining cases not considered by the `.exact` qualifier, in the last two bindings on the layer element, with a `stopPropagation()` call
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deselectAllLayers() {
|
async function deselectAllLayers() {
|
||||||
|
|
@ -243,7 +227,7 @@
|
||||||
fakeHighlight = [layer.path];
|
fakeHighlight = [layer.path];
|
||||||
}
|
}
|
||||||
const select = (): void => {
|
const select = (): void => {
|
||||||
if (!layer.layerMetadata.selected) selectLayer(false, false, false, listing, event);
|
if (!layer.layerMetadata.selected) selectLayer(false, false, listing);
|
||||||
};
|
};
|
||||||
|
|
||||||
const target = (event.target || undefined) as HTMLElement | undefined;
|
const target = (event.target || undefined) as HTMLElement | undefined;
|
||||||
|
|
@ -283,16 +267,19 @@
|
||||||
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
const layerWithNameBeingEdited = layers.find((layer: LayerListingInfo) => layer.editingName);
|
||||||
const layerPathWithNameBeingEdited = layerWithNameBeingEdited?.entry.path;
|
const layerPathWithNameBeingEdited = layerWithNameBeingEdited?.entry.path;
|
||||||
const layerIdWithNameBeingEdited = layerPathWithNameBeingEdited?.slice(-1)[0];
|
const layerIdWithNameBeingEdited = layerPathWithNameBeingEdited?.slice(-1)[0];
|
||||||
const path = [] as bigint[];
|
const path: bigint[] = [];
|
||||||
layers = [] as LayerListingInfo[];
|
|
||||||
|
|
||||||
const recurse = (folder: UpdateDocumentLayerTreeStructureJs, layers: LayerListingInfo[], cache: Map<string, LayerPanelEntry>): void => {
|
// Clear the layer tree before rebuilding it
|
||||||
|
layers = [];
|
||||||
|
|
||||||
|
// Build the new layer tree
|
||||||
|
const recurse = (folder: UpdateDocumentLayerTreeStructureJs): void => {
|
||||||
folder.children.forEach((item, index) => {
|
folder.children.forEach((item, index) => {
|
||||||
// TODO: fix toString
|
// TODO: fix toString
|
||||||
const layerId = BigInt(item.layerId.toString());
|
const layerId = BigInt(item.layerId.toString());
|
||||||
path.push(layerId);
|
path.push(layerId);
|
||||||
|
|
||||||
const mapping = cache.get(path.toString());
|
const mapping = layerCache.get(path.toString());
|
||||||
if (mapping) {
|
if (mapping) {
|
||||||
layers.push({
|
layers.push({
|
||||||
folderIndex: index,
|
folderIndex: index,
|
||||||
|
|
@ -303,13 +290,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call self recursively if there are any children
|
// Call self recursively if there are any children
|
||||||
if (item.children.length >= 1) recurse(item, layers, cache);
|
if (item.children.length >= 1) recurse(item);
|
||||||
|
|
||||||
path.pop();
|
path.pop();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
recurse(updateDocumentLayerTreeStructure);
|
||||||
|
layers = layers;
|
||||||
|
}
|
||||||
|
|
||||||
recurse(updateDocumentLayerTreeStructure, layers, layerCache);
|
function updateLayerInTree(targetPath: BigUint64Array, targetLayer: LayerPanelEntry) {
|
||||||
|
const path = targetPath.toString();
|
||||||
|
layerCache.set(path, targetLayer);
|
||||||
|
|
||||||
|
const layer = layers.find((layer: LayerListingInfo) => layer.entry.path.toString() === path);
|
||||||
|
if (layer) {
|
||||||
|
layer.entry = targetLayer;
|
||||||
|
layers = layers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLayerTypeData(layerType: LayerType): LayerTypeData {
|
function getLayerTypeData(layerType: LayerType): LayerTypeData {
|
||||||
|
|
|
||||||
|
|
@ -52,5 +52,9 @@
|
||||||
.sections {
|
.sections {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-button {
|
||||||
|
flex-basis: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 0 0 0;
|
flex: 0 0 auto;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
const editor = getContext<Editor>("editor");
|
const editor = getContext<Editor>("editor");
|
||||||
|
|
||||||
let self: HTMLDivElement;
|
|
||||||
let entries: MenuListEntry[] = [];
|
let entries: MenuListEntry[] = [];
|
||||||
|
|
||||||
function clickEntry(menuListEntry: MenuListEntry, e: MouseEvent) {
|
function clickEntry(menuListEntry: MenuListEntry, e: MouseEvent) {
|
||||||
|
|
@ -36,7 +35,7 @@
|
||||||
(e.target as HTMLElement | undefined)?.focus();
|
(e.target as HTMLElement | undefined)?.focus();
|
||||||
|
|
||||||
if (menuListEntry.ref) {
|
if (menuListEntry.ref) {
|
||||||
menuListEntry.ref.isOpen = true;
|
menuListEntry.ref.open = true;
|
||||||
entries = entries;
|
entries = entries;
|
||||||
} else {
|
} else {
|
||||||
throw new Error("The menu bar floating menu has no associated ref");
|
throw new Error("The menu bar floating menu has no associated ref");
|
||||||
|
|
@ -74,7 +73,7 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="menu-bar-input" bind:this={self} data-menu-bar-input>
|
<div class="menu-bar-input" data-menu-bar-input>
|
||||||
{#each entries as entry, index (index)}
|
{#each entries as entry, index (index)}
|
||||||
<div class="entry-container">
|
<div class="entry-container">
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||||
|
|
@ -82,7 +81,7 @@
|
||||||
on:click={(e) => clickEntry(entry, e)}
|
on:click={(e) => clickEntry(entry, e)}
|
||||||
on:keydown={(e) => entry.ref?.keydown(e, false)}
|
on:keydown={(e) => entry.ref?.keydown(e, false)}
|
||||||
class="entry"
|
class="entry"
|
||||||
class:open={entry.ref?.isOpen}
|
class:open={entry.ref?.open}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
data-floating-menu-spawner={entry.children && entry.children.length > 0 ? "" : "no-hover-transfer"}
|
data-floating-menu-spawner={entry.children && entry.children.length > 0 ? "" : "no-hover-transfer"}
|
||||||
>
|
>
|
||||||
|
|
@ -96,9 +95,9 @@
|
||||||
{#if entry.children && entry.children.length > 0}
|
{#if entry.children && entry.children.length > 0}
|
||||||
<MenuList
|
<MenuList
|
||||||
on:open={(e) => {
|
on:open={(e) => {
|
||||||
if (entry.ref) entry.ref.isOpen = e.detail;
|
if (entry.ref) entry.ref.open = e.detail;
|
||||||
}}
|
}}
|
||||||
open={entry.ref?.isOpen || false}
|
open={entry.ref?.open || false}
|
||||||
entries={entry.children || []}
|
entries={entry.children || []}
|
||||||
direction="Bottom"
|
direction="Bottom"
|
||||||
minWidth={240}
|
minWidth={240}
|
||||||
|
|
|
||||||
|
|
@ -1232,7 +1232,7 @@ export function defaultWidgetLayout(): WidgetLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates a widget layout based on a list of updates, returning the new layout
|
// Updates a widget layout based on a list of updates, returning the new layout
|
||||||
export function patchWidgetLayout(layout: WidgetLayout, updates: WidgetDiffUpdate): void {
|
export function patchWidgetLayout(/* mut */ layout: WidgetLayout, updates: WidgetDiffUpdate): void {
|
||||||
layout.layoutTarget = updates.layoutTarget;
|
layout.layoutTarget = updates.layoutTarget;
|
||||||
|
|
||||||
updates.diff.forEach((update) => {
|
updates.diff.forEach((update) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue