|
|
|
|
@ -8,7 +8,7 @@ import { Soma } from '../../core/soma.svelte';
|
|
|
|
|
import { Gesture } from '../../layers/gesture';
|
|
|
|
|
import { CAROUSEL_LANGS } from './langs';
|
|
|
|
|
import { carouselMorfo } from '../../../morfo/components/carousel';
|
|
|
|
|
import type { SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
|
|
|
|
|
|
|
|
|
|
const attrs = createAttrs(carouselMorfo);
|
|
|
|
|
|
|
|
|
|
@ -34,6 +34,8 @@ interface CarouselOpts
|
|
|
|
|
export class CarouselProvider {
|
|
|
|
|
readonly opts: CarouselOpts;
|
|
|
|
|
readonly runtimePart: SomaRuntimePart;
|
|
|
|
|
readonly soma: Soma;
|
|
|
|
|
readonly runtime: SomaRuntime;
|
|
|
|
|
static readonly ctx = context<CarouselProvider>('Carousel');
|
|
|
|
|
static get(): CarouselProvider | undefined {
|
|
|
|
|
return this.ctx.getOr(undefined) as CarouselProvider | undefined;
|
|
|
|
|
@ -46,8 +48,6 @@ export class CarouselProvider {
|
|
|
|
|
return new CarouselProvider(opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly soma = Soma.get();
|
|
|
|
|
|
|
|
|
|
// Refs — set by the respective child providers.
|
|
|
|
|
viewportRef = $state<HTMLElement | null>(null);
|
|
|
|
|
itemGroupRef = $state<HTMLElement | null>(null);
|
|
|
|
|
@ -63,9 +63,14 @@ export class CarouselProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('provider', { id: opts.id, ref: opts.ref, owner: this, context: CarouselProvider.ctx });
|
|
|
|
|
this.soma = Soma.require();
|
|
|
|
|
this.runtime = this.soma.runtime(carouselMorfo, {});
|
|
|
|
|
this.runtimePart = this.runtime.part('provider', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
context: CarouselProvider.ctx
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.gesture = Gesture.base({
|
|
|
|
|
ref: readableActive(() => this.itemGroupRef),
|
|
|
|
|
@ -233,7 +238,7 @@ export class CarouselProvider {
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
readonly resolvedAriaLabel: Active<string | undefined> = readableActive(
|
|
|
|
|
() => this.opts.ariaLabel.current || this.soma?.langs.ts(CAROUSEL_LANGS.LABEL) || undefined
|
|
|
|
|
() => this.opts.ariaLabel.current || this.soma.langs.ts(CAROUSEL_LANGS.LABEL) || undefined
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
@ -271,17 +276,15 @@ export class CarouselViewportProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselViewportOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('viewport', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.viewportRef = el;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('viewport', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.viewportRef = el;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
@ -308,17 +311,15 @@ export class CarouselItemGroupProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselItemGroupOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('item-group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.itemGroupRef = el;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('item-group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this,
|
|
|
|
|
onRefChange: (el) => {
|
|
|
|
|
this.provider.itemGroupRef = el;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Drag lifecycle — track offset during drag, commit on release.
|
|
|
|
|
let wasDragging = false;
|
|
|
|
|
@ -369,10 +370,12 @@ export class CarouselItemProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselItemOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('item', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('item', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly isActive = $derived.by(
|
|
|
|
|
@ -417,10 +420,12 @@ export class CarouselPrevTriggerProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselPrevTriggerOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('prev-trigger', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('prev-trigger', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly isDisabled = $derived.by(() => this.provider.isDisabled || !this.provider.canGoPrev);
|
|
|
|
|
@ -434,8 +439,7 @@ export class CarouselPrevTriggerProvider {
|
|
|
|
|
this.runtimePart.assert({
|
|
|
|
|
...this.runtimePart.props,
|
|
|
|
|
type: 'button' as const,
|
|
|
|
|
'aria-label':
|
|
|
|
|
this.opts.ariaLabel.current || this.provider.soma?.langs.ts(CAROUSEL_LANGS.PREV),
|
|
|
|
|
'aria-label': this.opts.ariaLabel.current || this.provider.soma.langs.ts(CAROUSEL_LANGS.PREV),
|
|
|
|
|
disabled: this.isDisabled || undefined,
|
|
|
|
|
'data-disabled': boolToEmptyStrOrUndef(this.isDisabled),
|
|
|
|
|
onclick: this.onclick
|
|
|
|
|
@ -459,10 +463,12 @@ export class CarouselNextTriggerProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselNextTriggerOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('next-trigger', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('next-trigger', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly isDisabled = $derived.by(() => this.provider.isDisabled || !this.provider.canGoNext);
|
|
|
|
|
@ -476,8 +482,7 @@ export class CarouselNextTriggerProvider {
|
|
|
|
|
this.runtimePart.assert({
|
|
|
|
|
...this.runtimePart.props,
|
|
|
|
|
type: 'button' as const,
|
|
|
|
|
'aria-label':
|
|
|
|
|
this.opts.ariaLabel.current || this.provider.soma?.langs.ts(CAROUSEL_LANGS.NEXT),
|
|
|
|
|
'aria-label': this.opts.ariaLabel.current || this.provider.soma.langs.ts(CAROUSEL_LANGS.NEXT),
|
|
|
|
|
disabled: this.isDisabled || undefined,
|
|
|
|
|
'data-disabled': boolToEmptyStrOrUndef(this.isDisabled),
|
|
|
|
|
onclick: this.onclick
|
|
|
|
|
@ -500,10 +505,12 @@ export class CarouselIndicatorGroupProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselIndicatorGroupOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('indicator-group', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('indicator-group', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly props = $derived.by(() =>
|
|
|
|
|
@ -532,10 +539,12 @@ export class CarouselIndicatorProvider {
|
|
|
|
|
|
|
|
|
|
private constructor(opts: CarouselIndicatorOpts) {
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
this.runtimePart = Soma.require()
|
|
|
|
|
.runtime(carouselMorfo, {})
|
|
|
|
|
.part('indicator', { id: opts.id, ref: opts.ref, owner: this });
|
|
|
|
|
this.provider = CarouselProvider.require();
|
|
|
|
|
this.runtimePart = this.provider.runtime.part('indicator', {
|
|
|
|
|
id: opts.id,
|
|
|
|
|
ref: opts.ref,
|
|
|
|
|
owner: this
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readonly isActive = $derived.by(
|
|
|
|
|
|