Uygulama yapısı

Stil ve Animasyon

class/style/attr yardımcıları, satır içi <style>, CSS sınıf tabanlı transition prop'u, WAAPI keyframe geçişleri, görünürlük ve giriş/çıkış kipi.

Stil verme yolları

class

Elemanın sınıfı JSX'te class (ya da className) özniteliğiyle, JSX'siz yazımda elemanın class.add çağrısıyla verilir. Değer dizge, dizi, nesne ya da getter olabilir:

<a class="row" />
<a class={() => `row${open() ? " active" : ""}`} />
<a class={{ row: true, active: open(), untitled: !note.title.trim() }} />
const fixed = motifComponent("a", (row: ComponentBase) => row.class.add("row"));
const active = motifComponent("a", (row: ComponentBase) => row.class.add(() => `row${open() ? " active" : ""}`));
const flags = motifComponent("a", (row: ComponentBase) => row.class.add({ row: true, active: () => open(), untitled: () => !note.title.trim() }));
<a class="row" />
<a class={() => `row${open() ? " active" : ""}`} />
<a class={{ row: true, active: open(), untitled: !note.title.trim() }} />
const fixed = motifComponent("a", (row) => row.class.add("row"));
const active = motifComponent("a", (row) => row.class.add(() => `row${open() ? " active" : ""}`));
const flags = motifComponent("a", (row) => row.class.add({ row: true, active: () => open(), untitled: () => !note.title.trim() }));

Nesnede anahtar sınıf adı, değer koşuldur: doğruysa sınıf eklenir, değilse kaldırılır.

Düz etikette true/false gibi sabitler bir kez uygulanır, diğer değerler getter'a sarılır ve canlı kalır. Bileşen etiketinde derleyici yalnız ternary'yi sarar; orada canlı koşulu fonksiyon olarak verin (bkz. JSX: class).

class.add'e verilen nesnede fonksiyon olmayan değer çağrı anında bir kez okunur; canlı koşul için fonksiyon verin (bkz. JSX: class).

style

Satır içi stil JSX'te style özniteliğiyle, JSX'siz yazımda elemanın style çağrısıyla verilir. Değer dizge, nesne ya da getter olabilir; getter'ın okuduğu değer değişince stil yeniden yazılır (bkz. JSX: style):

<a style="opacity: 0.6;" />
<a style={{ borderLeft: "3px solid var(--accent)" }} />
<a style={() => ({ opacity: note.archived ? 0.6 : 1 })} />
const dimmed = motifComponent("a", (row: ComponentBase) => row.style("opacity: 0.6;"));
const marked = motifComponent("a", (row: ComponentBase) => row.style({ borderLeft: "3px solid var(--accent)" }));
const live = motifComponent("a", (row: ComponentBase) => row.style(() => ({ opacity: note.archived ? 0.6 : 1 })));
<a style="opacity: 0.6;" />
<a style={{ borderLeft: "3px solid var(--accent)" }} />
<a style={() => ({ opacity: note.archived ? 0.6 : 1 })} />
const dimmed = motifComponent("a", (row) => row.style("opacity: 0.6;"));
const marked = motifComponent("a", (row) => row.style({ borderLeft: "3px solid var(--accent)" }));
const live = motifComponent("a", (row) => row.style(() => ({ opacity: note.archived ? 0.6 : 1 })));

Satır içi <style>

CSS'i view() içinde doğrudan <style> bloğuyla verebilirsiniz; JSX'siz yazımda bu, metni CSS olan bir "style" elemanıdır. Kurallar bileşenle sınırlanmaz, tüm belgeye uygulanır:

import { Component } from "@motifx/core";

export class EmptyState extends Component {
  override view() {
    return (
      <div class="placeholder">
        <style>{`
          .placeholder { display: grid; place-items: center; padding: 2rem; }
          .placeholder p { color: var(--muted); }
        `}</style>
        <p>Henüz not yok.</p>
      </div>
    );
  }
}
export function EmptyState() {
  return (
    <div class="placeholder">
      <style>{`
        .placeholder { display: grid; place-items: center; padding: 2rem; }
        .placeholder p { color: var(--muted); }
      `}</style>
      <p>Henüz not yok.</p>
    </div>
  );
}
import { motifOptions } from "@motifx/core";

export const EmptyState = () => motifOptions({
  el: "div",

  onConfigured() {
    this.class.add("placeholder");
  },

  view() {
    return (
      <>
        <style>{`
          .placeholder { display: grid; place-items: center; padding: 2rem; }
          .placeholder p { color: var(--muted); }
        `}</style>
        <p>Henüz not yok.</p>
      </>
    );
  },
});
import { Component, ComponentBase, motifComponent } from "@motifx/core";

const css = `
  .placeholder { display: grid; place-items: center; padding: 2rem; }
  .placeholder p { color: var(--muted); }
`;

export class EmptyState extends Component {
  override view() {
    return motifComponent("div", (root: ComponentBase) => {
      root.class.add("placeholder");
      const style = motifComponent("style", (tag: ComponentBase) => tag.setText(css));
      const text = motifComponent("p", (p: ComponentBase) => p.setText("Henüz not yok."));
      root.controls.add(style, text);
    });
  }
}
import { ComponentBase, motifComponent } from "@motifx/core";

const css = `
  .placeholder { display: grid; place-items: center; padding: 2rem; }
  .placeholder p { color: var(--muted); }
`;

export function EmptyState() {
  return motifComponent("div", (root: ComponentBase) => {
    root.class.add("placeholder");
    const style = motifComponent("style", (tag: ComponentBase) => tag.setText(css));
    const text = motifComponent("p", (p: ComponentBase) => p.setText("Henüz not yok."));
    root.controls.add(style, text);
  });
}
import { ComponentBase, motifComponent, motifOptions } from "@motifx/core";

const css = `
  .placeholder { display: grid; place-items: center; padding: 2rem; }
  .placeholder p { color: var(--muted); }
`;

export const EmptyState = () => motifOptions({
  el: "div",

  onConfigured() {
    this.class.add("placeholder");
  },

  view() {
    const style = motifComponent("style", (tag: ComponentBase) => tag.setText(css));
    const text = motifComponent("p", (p: ComponentBase) => p.setText("Henüz not yok."));
    return [style, text];
  },
});
import { Component } from "@motifx/core";

export class EmptyState extends Component {
  view() {
    return (
      <div class="placeholder">
        <style>{`
          .placeholder { display: grid; place-items: center; padding: 2rem; }
          .placeholder p { color: var(--muted); }
        `}</style>
        <p>Henüz not yok.</p>
      </div>
    );
  }
}
export function EmptyState() {
  return (
    <div class="placeholder">
      <style>{`
        .placeholder { display: grid; place-items: center; padding: 2rem; }
        .placeholder p { color: var(--muted); }
      `}</style>
      <p>Henüz not yok.</p>
    </div>
  );
}
import { motifOptions } from "@motifx/core";

export const EmptyState = () => motifOptions({
  el: "div",

  onConfigured() {
    this.class.add("placeholder");
  },

  view() {
    return (
      <>
        <style>{`
          .placeholder { display: grid; place-items: center; padding: 2rem; }
          .placeholder p { color: var(--muted); }
        `}</style>
        <p>Henüz not yok.</p>
      </>
    );
  },
});
import { Component, motifComponent } from "@motifx/core";

const css = `
  .placeholder { display: grid; place-items: center; padding: 2rem; }
  .placeholder p { color: var(--muted); }
`;

export class EmptyState extends Component {
  view() {
    return motifComponent("div", (root) => {
      root.class.add("placeholder");
      const style = motifComponent("style", (tag) => tag.setText(css));
      const text = motifComponent("p", (p) => p.setText("Henüz not yok."));
      root.controls.add(style, text);
    });
  }
}
import { motifComponent } from "@motifx/core";

const css = `
  .placeholder { display: grid; place-items: center; padding: 2rem; }
  .placeholder p { color: var(--muted); }
`;

export function EmptyState() {
  return motifComponent("div", (root) => {
    root.class.add("placeholder");
    const style = motifComponent("style", (tag) => tag.setText(css));
    const text = motifComponent("p", (p) => p.setText("Henüz not yok."));
    root.controls.add(style, text);
  });
}
import { motifComponent, motifOptions } from "@motifx/core";

const css = `
  .placeholder { display: grid; place-items: center; padding: 2rem; }
  .placeholder p { color: var(--muted); }
`;

export const EmptyState = () => motifOptions({
  el: "div",

  onConfigured() {
    this.class.add("placeholder");
  },

  view() {
    const style = motifComponent("style", (tag) => tag.setText(css));
    const text = motifComponent("p", (p) => p.setText("Henüz not yok."));
    return [style, text];
  },
});

Kodla sınıf ve stil

Kurulumdan sonra sınıf ve stil bileşenin class ve style yardımcılarıyla değişir:

this.class.add("active");
this.class.add("row", "pinned");
this.class.add(() => (note.pinned ? "pinned" : ""));
this.class.add({ active: () => open() });
this.class.remove("active");
this.class.remove("**");
this.class.has("row");

this.style({ opacity: 0.6 });
this.style("opacity: 0.6; font-weight: bold;");
this.style(() => ({ opacity: note.archived ? 0.6 : 1 }));
row.class.add("active");
row.class.add("row", "pinned");
row.class.add(() => (note.pinned ? "pinned" : ""));
row.class.add({ active: () => open() });
row.class.remove("active");
row.class.remove("**");
row.class.has("row");

row.style({ opacity: 0.6 });
row.style("opacity: 0.6; font-weight: bold;");
row.style(() => ({ opacity: note.archived ? 0.6 : 1 }));
this.class.add("active");
this.class.add("row", "pinned");
this.class.add(() => (note.pinned ? "pinned" : ""));
this.class.add({ active: () => open() });
this.class.remove("active");
this.class.remove("**");
this.class.has("row");

this.style({ opacity: 0.6 });
this.style("opacity: 0.6; font-weight: bold;");
this.style(() => ({ opacity: note.archived ? 0.6 : 1 }));
row.class.add("active");
row.class.add("row", "pinned");
row.class.add(() => (note.pinned ? "pinned" : ""));
row.class.add({ active: () => open() });
row.class.remove("active");
row.class.remove("**");
row.class.has("row");

row.style({ opacity: 0.6 });
row.style("opacity: 0.6; font-weight: bold;");
row.style(() => ({ opacity: note.archived ? 0.6 : 1 }));

Fonksiyon bileşeninde bu çağrılar bileşenin kendisi üzerinde yapılır (örnekte row): JSX'te kökün onConfig kancasına ya da ref'ine gelen bileşen, JSX'siz yazımda kökü kuran motifComponent fonksiyonunun aldığı bileşen.

class.remove("**") bütün sınıfları ve canlı kaynakları kaldırır, class.has sınıfın elemanda olup olmadığını söyler. class.add katkı sayımı (reference counting) tutar: aynı sınıf birden çok kaynaktan eklenirse hepsi kaldırılana kadar sınıf durur. class.add'e verilen nesnede fonksiyon olmayan değer çağrı anında bir kez okunur; canlı koşul için fonksiyon verin. Nesne biçimindeki style yalnız verdiği özellikleri değiştirir, dizge biçimi bütün satır içi stili değiştirir.

Öznitelik yardımcısı — attr

Öznitelikler kodla bileşenin attr yardımcısıyla yazılır:

this.attr.add({ href: `/notes/${note.id}`, title: note.title });
row.attr.add({ href: `/notes/${note.id}`, title: note.title });
this.attr.add({ href: `/notes/${note.id}`, title: note.title });
row.attr.add({ href: `/notes/${note.id}`, title: note.title });

JSX'te etikete yazılan öznitelikler de derleyici çıktısında birer attr.add çağrısıdır; aşağıdaki değer kuralları ikisinde aynıdır.

RouterLink bileşeni de href'i (showHref: false verilmemişse) bu yolla ekler.

attr.add değerleri: false, null ve undefined özniteliği kaldırır, true boş değerle ("") yazar, dizge ve sayılar olduğu gibi yazılır. aria-* ve data-* özniteliklerinde true/false metin olarak yazılır ("true"/"false"). Nesnedeki bir anahtar null ise yalnızca o öznitelik kaldırılır, diğer anahtarlar yazılır (attr.add({ title: null, role: "tab" })).

Öznitelik adları yalnızca attr.add'e verilen nesnenin kendi anahtarlarıdır; değerin içine inilmez. Nesne ya da dizi değer tek bir öznitelik değeri olarak metne çevrilip yazılır: { title: { a: 1 } } → title="[object Object]", { 'data-ids': [1, 2] } → data-ids="1,2". Getter'ın döndürdüğü nesne ve dizi de aynı biçimde yazılır. Adı bir eleman metoduyla aynı olan anahtarda değer o metodun argümanıdır (bkz. Eleman metotları).

Tailwind, Bootstrap ve harici CSS

MotifJS herhangi bir CSS çözümüne bağlı değildir; bir CSS kütüphanesinin sınıfları da diğer sınıflar gibi verilir:

<a rel="router" href="/notes" class="btn btn-primary">Notlar</a>
const link = motifComponent("a", (a: ComponentBase) => {
  a.attr.add({ rel: "router", href: "/notes" });
  a.class.add("btn btn-primary");
  a.controls.add(motifComponent("text", (node: ComponentBase) => node.setText("Notlar")));
});
<a rel="router" href="/notes" class="btn btn-primary">Notlar</a>
const link = motifComponent("a", (a) => {
  a.attr.add({ rel: "router", href: "/notes" });
  a.class.add("btn btn-primary");
  a.controls.add(motifComponent("text", (node) => node.setText("Notlar")));
});

Tailwind için @tailwindcss/vite eklentisini vite.config.ts'e ekleyin.

Geçiş (transition) sistemi

MotifJS iki tür giriş/çıkış animasyonu destekler:

  1. CSS sınıf tabanlı geçiş — transition prop'u ile.
  2. WAAPI (Web Animations API) keyframe — motif.options.transition.in/out ile programatik.

Geçişler; bir bileşen DOM'a eklendiğinde (enter) ve kaldırıldığında/gizlendiğinde (leave) otomatik oynatılır.

CSS sınıf tabanlı geçiş — transition prop'u

Geçişe bir ad verilir: JSX'te transition özniteliği, JSX'siz yazımda props nesnesinin transition anahtarı. Örnekteki sabitleme işareti not sabitlendikçe gösterilip gizlenir; geçiş ikisinde de oynar:

<i class="pin" transition="fade" x-display={() => note.pinned} />
const pin = motifComponent("i", {
  preconfig: (i: ComponentBase) => i.bindings.display(() => note.pinned),
  transition: "fade",
  initializeComponent: (i: ComponentBase) => i.class.add("pin"),
});
<i class="pin" transition="fade" x-display={() => note.pinned} />
const pin = motifComponent("i", {
  preconfig: (i) => i.bindings.display(() => note.pinned),
  transition: "fade",
  initializeComponent: (i) => i.class.add("pin"),
});

Bu, aşağıdaki CSS sınıflarını uygun aşamalarda uygular:

Aşama Uygulanan sınıflar
Giriş (enter) fade-enter-from → fade-enter-active → fade-enter-to
Çıkış (leave) fade-leave-from → fade-leave-active → fade-leave-to

Karşılık gelen CSS'i siz yazarsınız:

.fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; }
.fade-enter-from,   .fade-leave-to     { opacity: 0; }
.fade-enter-to,     .fade-leave-from   { opacity: 1; }

transition düz elemanda, sınıf bileşeninde ve fonksiyon bileşeninde aynı şekilde çalışır; fonksiyon bileşeninde döndürülen köke uygulanır ve dışarıdan verilen değer, fonksiyonun kendi köküne yazdığı değerin önüne geçer. Değer getter da olabilir: bileşen yaşadığı sürece izlenir, getter null ya da boş dizge dönerse geçiş kapanır. JSX'te etikete yazılan üçlü ifade kendiliğinden getter'a derlenir; JSX'siz yazımda getter'ı siz verirsiniz:

<FolderBadge folder="notes" transition={this.settings.state.density === "compact" ? "fade-fast" : "fade"} />
<FolderBadge folder="notes" transition={settings.state.density === "compact" ? "fade-fast" : "fade"} />
const badge = motifComponent(FolderBadge, {
  folder: "notes",
  transition: () => (this.settings.state.density === "compact" ? "fade-fast" : "fade"),
});
const badge = motifComponent(FolderBadge, {
  folder: "notes",
  transition: () => (settings.state.density === "compact" ? "fade-fast" : "fade"),
});
<FolderBadge folder="notes" transition={this.settings.state.density === "compact" ? "fade-fast" : "fade"} />
<FolderBadge folder="notes" transition={settings.state.density === "compact" ? "fade-fast" : "fade"} />
const badge = motifComponent(FolderBadge, {
  folder: "notes",
  transition: () => (this.settings.state.density === "compact" ? "fade-fast" : "fade"),
});
const badge = motifComponent(FolderBadge, {
  folder: "notes",
  transition: () => (settings.state.density === "compact" ? "fade-fast" : "fade"),
});

Fonksiyon bileşeninde settings, bileşenin FromService(SettingsService) ile aldığı servistir.

Özel sınıf adları ve süre — nesne biçimi

transition'a bir TransitionProps nesnesi verilerek sınıf adları ve süre özelleştirilir:

<div
  class="confirm"
  transition={{
    name: "slide",
    duration: { enter: 300, leave: 200 },
    enterFromClass: "slide-in-start",
    enterActiveClass: "slide-in-active",
    enterToClass: "slide-in-end",
    leaveFromClass: "slide-out-start",
    leaveActiveClass: "slide-out-active",
    leaveToClass: "slide-out-end",
  }}
>
  …
</div>
const confirm = motifComponent("div", {
  transition: {
    name: "slide",
    duration: { enter: 300, leave: 200 },
    enterFromClass: "slide-in-start",
    enterActiveClass: "slide-in-active",
    enterToClass: "slide-in-end",
    leaveFromClass: "slide-out-start",
    leaveActiveClass: "slide-out-active",
    leaveToClass: "slide-out-end",
  },
  initializeComponent: (div: ComponentBase) => div.class.add("confirm"),
});
<div
  class="confirm"
  transition={{
    name: "slide",
    duration: { enter: 300, leave: 200 },
    enterFromClass: "slide-in-start",
    enterActiveClass: "slide-in-active",
    enterToClass: "slide-in-end",
    leaveFromClass: "slide-out-start",
    leaveActiveClass: "slide-out-active",
    leaveToClass: "slide-out-end",
  }}
>
  …
</div>
const confirm = motifComponent("div", {
  transition: {
    name: "slide",
    duration: { enter: 300, leave: 200 },
    enterFromClass: "slide-in-start",
    enterActiveClass: "slide-in-active",
    enterToClass: "slide-in-end",
    leaveFromClass: "slide-out-start",
    leaveActiveClass: "slide-out-active",
    leaveToClass: "slide-out-end",
  },
  initializeComponent: (div) => div.class.add("confirm"),
});

WAAPI keyframe animasyonu — motif.options.transition.in/out

Kodla tanımlanan keyframe animasyonları için giriş ve çıkış motif.options.transition.in / out ile, bileşenin onConfig ya da initializeComponent aşamasında verilir:

<section
  onConfig={(panel) => {
    panel.motif.options.transition.in({
      keyframes: [{ opacity: 0, transform: "translateX(-50px)" }, { opacity: 1, transform: "translateX(0)" }],
      options: { duration: 300, easing: "ease-out", fill: "forwards" },
    });
    panel.motif.options.transition.out({
      keyframes: [{ opacity: 1, transform: "translateX(0)" }, { opacity: 0, transform: "translateX(-50px)" }],
      options: { duration: 200, easing: "ease-in", fill: "forwards" },
    });
  }}
>
  …
</section>
const panel = motifComponent("section", {
  onConfig: (panel: ComponentBase) => {
    panel.motif.options.transition.in({
      keyframes: [{ opacity: 0, transform: "translateX(-50px)" }, { opacity: 1, transform: "translateX(0)" }],
      options: { duration: 300, easing: "ease-out", fill: "forwards" },
    });
    panel.motif.options.transition.out({
      keyframes: [{ opacity: 1, transform: "translateX(0)" }, { opacity: 0, transform: "translateX(-50px)" }],
      options: { duration: 200, easing: "ease-in", fill: "forwards" },
    });
  },
});
<section
  onConfig={(panel) => {
    panel.motif.options.transition.in({
      keyframes: [{ opacity: 0, transform: "translateX(-50px)" }, { opacity: 1, transform: "translateX(0)" }],
      options: { duration: 300, easing: "ease-out", fill: "forwards" },
    });
    panel.motif.options.transition.out({
      keyframes: [{ opacity: 1, transform: "translateX(0)" }, { opacity: 0, transform: "translateX(-50px)" }],
      options: { duration: 200, easing: "ease-in", fill: "forwards" },
    });
  }}
>
  …
</section>
const panel = motifComponent("section", {
  onConfig: (panel) => {
    panel.motif.options.transition.in({
      keyframes: [{ opacity: 0, transform: "translateX(-50px)" }, { opacity: 1, transform: "translateX(0)" }],
      options: { duration: 300, easing: "ease-out", fill: "forwards" },
    });
    panel.motif.options.transition.out({
      keyframes: [{ opacity: 1, transform: "translateX(0)" }, { opacity: 0, transform: "translateX(-50px)" }],
      options: { duration: 200, easing: "ease-in", fill: "forwards" },
    });
  },
});

Sınıf bileşeninde ve Options nesnesinde aynı çağrılar bileşenin kendi onConfigured kancasında this.motif.options.transition.in(...) ve out(...) olarak yazılır.

in/out, standart WAAPI element.animate(keyframes, options) imzasını kullanır:

in/out tanımı bileşene aittir ve sonraki her giriş/çıkışta kullanılır; yeniden çağrılırsa öncekinin yerine geçer. Süren animasyonlar motif.options.transition.activeAnimations dizisinde tutulur. Bileşende yeni bir keyframe animasyonu başlarken süren animasyonu iptal edilir: giriş sürerken motif.hide() çağrılırsa giriş kesilir, çıkış oynar; çıkış sürerken motif.show() çağrılırsa çıkış kesilir, giriş oynar.

Öncelik: Bir bileşende hem WAAPI (motif.options.transition.in/out) hem CSS sınıf geçişi tanımlıysa, WAAPI keyframe'leri önceliklidir.

Geçiş ve görünürlük

motif.hide()/motif.show() çağrıldığında ilgili leave/enter geçişi otomatik oynatılır. Çıkışta DOM'dan kaldırma, leave animasyonu bittikten sonra gerçekleşir. İki çağrı üst üste gelirse son çağrı geçerlidir: giriş sürerken motif.hide() gelirse giriş kesilir ve çıkış oynar; çıkış sürerken motif.show() gelirse çıkış kesilir, eleman yerinden kaldırılmaz ve giriş geçişi baştan oynar. Kesilen çıkışın await motif.hide() sözü o anda çözülür; bileşen görünür kalmıştır. x-display ve x-wait koşulları aynı kurala uyar: koşul çıkış bitmeden geri dönerse eleman kaldırılmaz. Kök bir fragment ise çocukları için de böyledir. Bir sonraki çıkışı animasyonsuz yapmak için bileşenin skipNextLeave bayrağı açılır:

this.motif.options.transition.skipNextLeave = true;
await this.motif.hide();
panel.motif.options.transition.skipNextLeave = true;
await panel.motif.hide();
this.motif.options.transition.skipNextLeave = true;
await this.motif.hide();
panel.motif.options.transition.skipNextLeave = true;
await panel.motif.hide();

Fonksiyon bileşeninde panel, gizlenecek bileşendir: ref ile tutulan ya da onConfig kancasına gelen bileşen, JSX'siz yazımda motifComponent'in döndürdüğü bileşen.

Bayrak yalnızca bir sonraki çıkışı etkiler ve kullanılınca sıfırlanır. Kök bir fragment ise görünür çocuklar da animasyonsuz gizlenir.

Rota sayfasının geçişleri gezinmede de oynar: ayrılan sayfa çıkış geçişini bitirir, sonra gelen sayfa girer. Router yığın kipindeyken (useRouter({ stack })) ve stack.animation verilmemişse (ya da 'none' ise) bu geçişler yığın geçişi olarak kullanılır ve sayfa öğesi giriş geçişi süresince data-nav-direction taşır. stack.animation verildiğinde push, back ve forward gezinmelerinde sayfanın kendi giriş geçişi yerine yığın animasyonu oynar; bkz. Yığın Gezinmesi.

Giriş ve çıkış sırası — mode

Bir kapsayıcıda bir çocuk çıkarken başka biri girdiğinde iki kip vardır:

Kip Davranış
'concurrent' (varsayılan) Gelen çocuk hemen yerleşir ve girişini oynar, giden çocuğun çıkışı aynı anda sürer.
'out-in' Gelen çocuk, o kapsayıcıda süren çıkışlar bitene kadar DOM'a yerleşmez; çıkış bitince yerleşir ve girişini oynar.
'in-out' Gelen çocuk hemen yerleşir ve girişini oynar; giden çocuk o sırada yerinde durur, çıkışını gelenin girişi bitince oynar.

Kip üç yerden verilir; dar olan geniş olanı ezer. Uygulamanın tamamı için, router gerekmeden:

app.useTransitions({ mode: "out-in" });
app.useTransitions({ mode: "out-in" });

Kapsayıcı başına, kapsayıcının transition değeriyle:

<main class="detail" transition={{ mode: "out-in" }}>…</main>
const detail = motifComponent("main", {
  transition: { mode: "out-in" },
  initializeComponent: (main: ComponentBase) => main.class.add("detail"),
});
<main class="detail" transition={{ mode: "out-in" }}>…</main>
const detail = motifComponent("main", {
  transition: { mode: "out-in" },
  initializeComponent: (main) => main.class.add("detail"),
});

ya da kapsayıcının ayarıyla, kodla:

this.motif.options.transition.mode = "concurrent";
detail.motif.options.transition.mode = "concurrent";
this.motif.options.transition.mode = "concurrent";
detail.motif.options.transition.mode = "concurrent";

Yalnız mode taşıyan transition değeri kipi ayarlar, kapsayıcının kendisine animasyon eklemez; name ve sınıf adlarıyla birlikte de verilebilir. Kip, kapsayıcıya controls.add ile gelen her çocuğa uygulanır: when/ternary/switch dalları, Frame ve Lazy içerikleri, liste satırları, elle eklenen bileşenler. Kip en yakın eleman kapsayıcıdan okunur: Frame ve fragment gibi yorum düğümlü kapsayıcılar kendi kipi yoksa ebeveynlerininkini kullanır; bu yüzden kipi taşıyan bir elemanın içindeki koşullu dal değişiminde de çalışır (bkz. Frame zamanlaması). Kardeşler arasında motif.hide() / motif.show() ile geçişte de show, kardeşin çıkışını bekler. Bekleme sırasında gelen çocuk kaldırılırsa ya da tekrar gizlenirse hiç yerleşmez. Süren bir çıkış yoksa out-in beklemez. İptal edilen çıkış (Animation.cancel) bekleyeni serbest bırakır.

in-out kipinde giden çocuğun çıkışı, aynı işlemde başlayan girişleri görmek için bir mikro görev bekler; giriş geçişi olmayan bir çocuk geliyorsa ya da hiç gelen yoksa çıkış hemen oynar. Giden çocuk serbest bırakılıyorsa dispose() Promise'i çıkış bitince çözülür; motif.hide() için de aynısı geçerlidir. İptal edilen giriş bekleyen çıkışı serbest bırakır.

Aktif animasyonları durdurma

await this.motif.stopAnimations();
await panel.motif.stopAnimations();
await this.motif.stopAnimations();
await panel.motif.stopAnimations();

Süren CSS sınıf geçişi hemen bitirilir, süren WAAPI animasyonları iptal edilir ve activeAnimations boşalır. Kesilen geçiş bir çıkışsa gizleme o anda tamamlanır: eleman belgeden çıkar, yerinde izi kalır. Serbest bırakılan bir bileşenin süren animasyonları da aynı yolla iptal edilir.

Sonraki adım

Bileşenlerin ve kaynakların ömrünü yönetmek için Bellek Yönetimi ve Serbest Bırakma bölümüne geçin.