|
|
|
|
@ -36,7 +36,7 @@ import {
|
|
|
|
|
import { SafePolygon } from '../../layers/floating/safe-polygon';
|
|
|
|
|
|
|
|
|
|
import { dropdownMenuMorfo } from '../../../morfo/components/dropdown-menu';
|
|
|
|
|
import type { SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
|
|
|
|
|
const attrs = createAttrs(dropdownMenuMorfo);
|
|
|
|
|
|
|
|
|
|
@ -93,6 +93,8 @@ interface MenuOpts
|
|
|
|
|
export class MenuProvider {
|
|
|
|
|
readonly opts: MenuOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
|
|
|
|
readonly soma: Soma;
|
|
|
|
|
readonly runtime: SomaRuntime;
|
|
|
|
|
static readonly ctx = context<MenuProvider>('DropdownMenu');
|
|
|
|
|
static get(): MenuProvider | undefined {
|
|
|
|
|
return this.ctx.getOr(undefined) as MenuProvider | undefined;
|
|
|
|
|
@ -105,7 +107,6 @@ export class MenuProvider {
|
|
|
|
|
return new MenuProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly config = Soma.get();
|
|
|
|
|
readonly floatingProvider: FloatingProvider;
|
|
|
|
|
readonly contentPresence: Presence;
|
|
|
|
|
readonly typeahead = new Typeahead();
|
|
|
|
|
@ -116,9 +117,14 @@ export class MenuProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('provider', { id: opts.id, ref: opts.ref, owner: this, context: MenuProvider.ctx });
|
|
|
|
|
this.soma = Soma.require();
|
|
|
|
|
this.runtime = this.soma.runtime(dropdownMenuMorfo, {});
|
|
|
|
|
this.runtimePart = this.runtime.part('provider', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: MenuProvider.ctx
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.floatingProvider = FloatingProvider.create();
|
|
|
|
|
|
|
|
|
|
@ -178,10 +184,12 @@ export class MenuTriggerProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuTriggerOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('trigger', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('trigger', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.provider.triggerId.current = opts.id.current;
|
|
|
|
|
|
|
|
|
|
FloatingAnchor.create({
|
|
|
|
|
@ -264,17 +272,15 @@ export class MenuContentProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuContentOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('content', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.setContentRef(el);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('content', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.setContentRef(el);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.provider.contentId.current = opts.id.current;
|
|
|
|
|
|
|
|
|
|
// Floating
|
|
|
|
|
@ -342,7 +348,7 @@ export class MenuContentProvider {
|
|
|
|
|
// Text selection
|
|
|
|
|
this.textSelection = TextSelection.use({
|
|
|
|
|
ref: readableActive(() => opts.ref.current),
|
|
|
|
|
dom: Soma.require().dom,
|
|
|
|
|
dom: this.provider.soma.dom,
|
|
|
|
|
enabled: readableActive(() => this.provider.opts.open.current),
|
|
|
|
|
onPointerDown: readableActive(() => () => {}),
|
|
|
|
|
onPointerUp: readableActive(() => () => {})
|
|
|
|
|
@ -432,9 +438,12 @@ export class MenuArrowProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuArrowOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('arrow', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
const provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('arrow', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.floatingArrow = FloatingArrow.create(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -466,10 +475,12 @@ export class MenuItemProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuItemOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('item', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('item', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly onclick = (_e: SomaMouseEvent<HTMLElement>) => {
|
|
|
|
|
@ -527,9 +538,13 @@ export class MenuGroupProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuGroupOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('group', { id: opts.id, ref: opts.ref, owner: this, context: MenuGroupProvider.ctx });
|
|
|
|
|
const provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: MenuGroupProvider.ctx
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
@ -554,9 +569,12 @@ export class MenuGroupHeadingProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuGroupHeadingOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('group-heading', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
const provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('group-heading', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
// Register with parent group if available
|
|
|
|
|
const group = MenuGroupProvider.get() as MenuGroupProvider | undefined;
|
|
|
|
|
if (group) {
|
|
|
|
|
@ -582,9 +600,12 @@ export class MenuSeparatorProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuSeparatorOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('separator', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
const provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('separator', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
@ -657,10 +678,12 @@ export class MenuCheckboxItemProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuCheckboxItemOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('checkbox-item', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('checkbox-item', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.group = MenuCheckboxGroupProvider.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -735,7 +758,8 @@ export class MenuRadioGroupProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuRadioGroupOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require().runtime(dropdownMenuMorfo, {}).part('radio-group', {
|
|
|
|
|
const provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = provider.runtime.part('radio-group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
@ -776,10 +800,12 @@ export class MenuRadioItemProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuRadioItemOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('radio-item', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = MenuProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('radio-item', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
this.radioGroup = MenuRadioGroupProvider.require();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -905,17 +931,15 @@ export class MenuSubTriggerProvider {
|
|
|
|
|
// A30: register subTriggerRef via `onRefChange` (attachRef fires at
|
|
|
|
|
// mount/unmount inside `untrack`), avoiding the `$effect` feedback.
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('sub-trigger', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.sub.subTriggerRef.current = el;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.sub = MenuSubProvider.require();
|
|
|
|
|
this.runtimePart = this.sub.provider.runtime.part('sub-trigger', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.sub.subTriggerRef.current = el;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.sub.subTriggerId.current = opts.id.current;
|
|
|
|
|
|
|
|
|
|
FloatingAnchor.create({
|
|
|
|
|
@ -1032,17 +1056,15 @@ export class MenuSubContentProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: MenuSubContentOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(dropdownMenuMorfo, {})
|
|
|
|
|
.part('sub-content', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.sub.setContentRef(el);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.sub = MenuSubProvider.require();
|
|
|
|
|
this.runtimePart = this.sub.provider.runtime.part('sub-content', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.sub.setContentRef(el);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.sub.contentId.current = opts.id.current;
|
|
|
|
|
|
|
|
|
|
this.floating = FloatingContent.create({
|
|
|
|
|
|