Gelişmiş
Transport ve TransportTo
İçeriği kendi ağacının dışındaki bir yuvada gösterme; Transport yuvası, TransportTo göndereni, replace/merge kipleri ve programatik taşıma için Transporter.
Bir bileşenin içeriğini kendi ağacının dışındaki bir yerde göstermek için kullanılır. Tipik örnek: sayfaya özel komut düğmelerinin layout'taki üst çubukta görünmesi. İki parçadan oluşur:
Transport— hedef yuva. Layout'a (ya da içeriğin görüneceği herhangi bir yere) konur.TransportTo— gönderen. Etiketleri arasına yazılan içerik, aynı adlı yuvaya taşınır.
Kullanım
Örnekte üst çubuk bir yuva taşır; açık notun sabitleme düğmesi not sayfasından o yuvaya gönderilir. Yuva:
import { Component, Transport } from "@motifx/core";
export class PageBar extends Component<HTMLElement> {
static override elementTag = "header";
override onConfigured() {
this.class.add("pagebar");
}
override view() {
return (
<>
<h1>Notlar</h1>
<Transport name="page-actions" />
</>
);
}
}
import { Component, ComponentBase, Transport, motifComponent, motifFragment } from "@motifx/core";
export class PageBar extends Component<HTMLElement> {
static override elementTag = "header";
override onConfigured() {
this.class.add("pagebar");
}
override view() {
const title = motifComponent("h1", (h1: ComponentBase) => h1.setText("Notlar"));
return motifFragment({ childs: [title, new Transport({ name: "page-actions" })] });
}
}
import { Transport } from "@motifx/core";
export function PageBar() {
return (
<header class="pagebar">
<h1>Notlar</h1>
<Transport name="page-actions" />
</header>
);
}
import { ComponentBase, Transport, motifComponent } from "@motifx/core";
export function PageBar() {
return motifComponent("header", (header: ComponentBase) => {
header.class.add("pagebar");
const title = motifComponent("h1", (h1: ComponentBase) => h1.setText("Notlar"));
header.controls.add(title, new Transport({ name: "page-actions" }));
});
}
import { Transport, motifOptions } from "@motifx/core";
export const PageBar = () => motifOptions({
el: "header",
onConfigured() {
this.class.add("pagebar");
},
view() {
return (
<>
<h1>Notlar</h1>
<Transport name="page-actions" />
</>
);
},
});
import { ComponentBase, Transport, motifComponent, motifFragment, motifOptions } from "@motifx/core";
export const PageBar = () => motifOptions({
el: "header",
onConfigured() {
this.class.add("pagebar");
},
view() {
const title = motifComponent("h1", (h1: ComponentBase) => h1.setText("Notlar"));
return motifFragment({ childs: [title, new Transport({ name: "page-actions" })] });
},
});
import { Component, Transport } from "@motifx/core";
export class PageBar extends Component {
static elementTag = "header";
onConfigured() {
this.class.add("pagebar");
}
view() {
return (
<>
<h1>Notlar</h1>
<Transport name="page-actions" />
</>
);
}
}
import { Component, Transport, motifComponent, motifFragment } from "@motifx/core";
export class PageBar extends Component {
static elementTag = "header";
onConfigured() {
this.class.add("pagebar");
}
view() {
const title = motifComponent("h1", (h1) => h1.setText("Notlar"));
return motifFragment({ childs: [title, new Transport({ name: "page-actions" })] });
}
}
import { Transport } from "@motifx/core";
export function PageBar() {
return (
<header class="pagebar">
<h1>Notlar</h1>
<Transport name="page-actions" />
</header>
);
}
import { Transport, motifComponent } from "@motifx/core";
export function PageBar() {
return motifComponent("header", (header) => {
header.class.add("pagebar");
const title = motifComponent("h1", (h1) => h1.setText("Notlar"));
header.controls.add(title, new Transport({ name: "page-actions" }));
});
}
import { Transport, motifOptions } from "@motifx/core";
export const PageBar = () => motifOptions({
el: "header",
onConfigured() {
this.class.add("pagebar");
},
view() {
return (
<>
<h1>Notlar</h1>
<Transport name="page-actions" />
</>
);
},
});
import { Transport, motifComponent, motifFragment, motifOptions } from "@motifx/core";
export const PageBar = () => motifOptions({
el: "header",
onConfigured() {
this.class.add("pagebar");
},
view() {
const title = motifComponent("h1", (h1) => h1.setText("Notlar"));
return motifFragment({ childs: [title, new Transport({ name: "page-actions" })] });
},
});
Gönderen:
import { Component, TransportTo } from "@motifx/core";
import { NotesService, type Note } from "../services/notes";
export class PinAction extends Component<any, { note: Note }> {
notes = this.getService(NotesService)!;
override view() {
const { note } = this.props;
return (
<TransportTo name="page-actions">
<button type="button" class="button--sm ghost" aria-pressed={() => note.pinned} onclick={() => this.notes.togglePin(note)}>
{() => (note.pinned ? "Sabitlendi" : "Sabitle")}
</button>
</TransportTo>
);
}
}
import { Component, ComponentBase, TransportTo, motifComponent } from "@motifx/core";
import { NotesService, type Note } from "../services/notes";
export class PinAction extends Component<any, { note: Note }> {
notes = this.getService(NotesService)!;
override view() {
const { note } = this.props;
const pin = motifComponent("button", (button: ComponentBase) => {
button.attr.add({ type: "button", "aria-pressed": () => note.pinned });
button.class.add("button--sm ghost");
button.motif.on("click", () => this.notes.togglePin(note));
button.bindings.text(() => (note.pinned ? "Sabitlendi" : "Sabitle"));
});
return motifComponent(TransportTo, { name: "page-actions", childs: [pin] });
}
}
import { FromService, TransportTo } from "@motifx/core";
import { NotesService, type Note } from "../services/notes";
export function PinAction(props: { note: Note }) {
const notes = FromService(NotesService)!;
const { note } = props;
return (
<TransportTo name="page-actions">
<button type="button" class="button--sm ghost" aria-pressed={() => note.pinned} onclick={() => notes.togglePin(note)}>
{() => (note.pinned ? "Sabitlendi" : "Sabitle")}
</button>
</TransportTo>
);
}
import { ComponentBase, FromService, TransportTo, motifComponent } from "@motifx/core";
import { NotesService, type Note } from "../services/notes";
export function PinAction(props: { note: Note }) {
const notes = FromService(NotesService)!;
const { note } = props;
const pin = motifComponent("button", (button: ComponentBase) => {
button.attr.add({ type: "button", "aria-pressed": () => note.pinned });
button.class.add("button--sm ghost");
button.motif.on("click", () => notes.togglePin(note));
button.bindings.text(() => (note.pinned ? "Sabitlendi" : "Sabitle"));
});
return motifComponent(TransportTo, { name: "page-actions", childs: [pin] });
}
import { TransportTo, motifOptions } from "@motifx/core";
import { NotesService, type Note } from "../services/notes";
export const PinAction = (props: { note: Note }) => motifOptions({
el: null,
view() {
const notes = this.getService(NotesService)!;
const { note } = props;
return (
<TransportTo name="page-actions">
<button type="button" class="button--sm ghost" aria-pressed={() => note.pinned} onclick={() => notes.togglePin(note)}>
{() => (note.pinned ? "Sabitlendi" : "Sabitle")}
</button>
</TransportTo>
);
},
});
import { ComponentBase, TransportTo, motifComponent, motifOptions } from "@motifx/core";
import { NotesService, type Note } from "../services/notes";
export const PinAction = (props: { note: Note }) => motifOptions({
el: null,
view() {
const notes = this.getService(NotesService)!;
const { note } = props;
const pin = motifComponent("button", (button: ComponentBase) => {
button.attr.add({ type: "button", "aria-pressed": () => note.pinned });
button.class.add("button--sm ghost");
button.motif.on("click", () => notes.togglePin(note));
button.bindings.text(() => (note.pinned ? "Sabitlendi" : "Sabitle"));
});
return motifComponent(TransportTo, { name: "page-actions", childs: [pin] });
},
});
import { Component, TransportTo } from "@motifx/core";
import { NotesService } from "../services/notes";
export class PinAction extends Component {
notes = this.getService(NotesService);
view() {
const { note } = this.props;
return (
<TransportTo name="page-actions">
<button type="button" class="button--sm ghost" aria-pressed={() => note.pinned} onclick={() => this.notes.togglePin(note)}>
{() => (note.pinned ? "Sabitlendi" : "Sabitle")}
</button>
</TransportTo>
);
}
}
import { Component, TransportTo, motifComponent } from "@motifx/core";
import { NotesService } from "../services/notes";
export class PinAction extends Component {
notes = this.getService(NotesService);
view() {
const { note } = this.props;
const pin = motifComponent("button", (button) => {
button.attr.add({ type: "button", "aria-pressed": () => note.pinned });
button.class.add("button--sm ghost");
button.motif.on("click", () => this.notes.togglePin(note));
button.bindings.text(() => (note.pinned ? "Sabitlendi" : "Sabitle"));
});
return motifComponent(TransportTo, { name: "page-actions", childs: [pin] });
}
}
import { FromService, TransportTo } from "@motifx/core";
import { NotesService } from "../services/notes";
export function PinAction(props) {
const notes = FromService(NotesService);
const { note } = props;
return (
<TransportTo name="page-actions">
<button type="button" class="button--sm ghost" aria-pressed={() => note.pinned} onclick={() => notes.togglePin(note)}>
{() => (note.pinned ? "Sabitlendi" : "Sabitle")}
</button>
</TransportTo>
);
}
import { FromService, TransportTo, motifComponent } from "@motifx/core";
import { NotesService } from "../services/notes";
export function PinAction(props) {
const notes = FromService(NotesService);
const { note } = props;
const pin = motifComponent("button", (button) => {
button.attr.add({ type: "button", "aria-pressed": () => note.pinned });
button.class.add("button--sm ghost");
button.motif.on("click", () => notes.togglePin(note));
button.bindings.text(() => (note.pinned ? "Sabitlendi" : "Sabitle"));
});
return motifComponent(TransportTo, { name: "page-actions", childs: [pin] });
}
import { TransportTo, motifOptions } from "@motifx/core";
import { NotesService } from "../services/notes";
export const PinAction = (props) => motifOptions({
el: null,
view() {
const notes = this.getService(NotesService);
const { note } = props;
return (
<TransportTo name="page-actions">
<button type="button" class="button--sm ghost" aria-pressed={() => note.pinned} onclick={() => notes.togglePin(note)}>
{() => (note.pinned ? "Sabitlendi" : "Sabitle")}
</button>
</TransportTo>
);
},
});
import { TransportTo, motifComponent, motifOptions } from "@motifx/core";
import { NotesService } from "../services/notes";
export const PinAction = (props) => motifOptions({
el: null,
view() {
const notes = this.getService(NotesService);
const { note } = props;
const pin = motifComponent("button", (button) => {
button.attr.add({ type: "button", "aria-pressed": () => note.pinned });
button.class.add("button--sm ghost");
button.motif.on("click", () => notes.togglePin(note));
button.bindings.text(() => (note.pinned ? "Sabitlendi" : "Sabitle"));
});
return motifComponent(TransportTo, { name: "page-actions", childs: [pin] });
},
});
Layout çubuğu <PageBar /> ile, not sayfası düğmeyi <PinAction note={note} /> ile yerleştirir.
Layout çubuğu new PageBar() ile, not sayfası düğmeyi new PinAction({ note }) ile yerleştirir.
Layout çubuğu motifComponent(PageBar) ile, not sayfası düğmeyi motifComponent(PinAction, { note }) ile yerleştirir.
Transport ve TransportTo çekirdeğin sınıflarıdır. JSX'siz yazımda yuva new Transport({ name }), gönderen derleyicinin ürettiği gibi motifComponent(TransportTo, { name, childs }) ile kurulur.
Prop'lar
| Bileşen | Prop | Açıklama |
|---|---|---|
Transport |
name |
Yuvanın adı (zorunlu). |
Transport |
mode |
'replace' (varsayılan) veya 'merge'; bkz. Yuvada birden çok gönderen. |
TransportTo |
name |
İçeriğin gönderileceği yuvanın adı. |
Davranış
- Sıra önemsizdir. Yuva önce ya da sonra oluşabilir;
TransportToyuva henüz yokken kurulursa, içerik yuva kaydolduğu anda taşınır. - İçerik gönderen bileşene bağlı kalır. Taşınan elemanlardaki bağlar ve olay işleyicileri, yazıldıkları bileşenin durumuyla çalışmaya devam eder; örnekte not sabitlenince yuvadaki düğmenin yazısı da değişir.
- Ömür gönderene bağlıdır.
TransportToserbest bırakıldığında taşıdığı içerik yuvadan kaldırılır ve serbest bırakılır. Rota sayfasından çıkılırken içerik, sayfanın serbest bırakılması beklenmeden yuvadan hemen kalkar (bkz. Ayrılan sayfa); komut çubuğu gibi kullanımlarda içerik yeni sayfanınkiyle kendiliğinden yer değiştirir. - Yuva kaldırılırsa içerik de gider. Yuva serbest bırakıldığında içindeki taşınmış içerik de serbest bırakılır; aynı adlı yuva yeniden oluşturulsa bile içerik geri gelmez.
- Sonradan eklenen çocuklar da taşınır.
TransportTo'nuncontrolskoleksiyonuna sonradan eklenen bir bileşen, yuva varsa doğrudan yuvaya gider; ilk çocuklar gibi canlı kalır ve gönderen serbest bırakılınca onlarla birlikte gider. Gönderenincontroladdedolayı her çocuk için tetiklenir. Transportyuvası kendisi bir fragmenttir (DOM'a eleman eklemez; içerik bulunduğu yere yerleşir).TransportTobulunduğu yerde boş bir<div>bırakır; içerik orada değil yuvada görünür.- İkisi de haberleşmeyi uygulama olayları üzerinden yapar; çalışan bir
Applicationiçinde kullanılmalıdır. - Aynı adla ikinci bir
Transportkurulursa kayıt yenisine geçer; gönderenler içeriği yeni yuvaya taşır.
Yuvada birden çok gönderen — mode
Aynı yuvaya birden çok TransportTo içerik gönderdiğinde mode belirleyicidir. Yuvanın gönderenlerden önce ya da sonra kurulması sonucu değiştirmez:
'replace'(varsayılan): yuvada yalnızca en son kurulan gönderenin içeriği kalır. Yuvadaki önceki içerik kaldırılır ve serbest bırakılır; o gönderen kapansa bile geri gelmez.'merge': bütün gönderenlerin içeriği kurulma sırasıyla yuvaya eklenir; her gönderen kapandığında yalnızca kendi içeriği kalkar.
Birden çok bloğun birlikte doldurduğu, gövdede biriken bir alan isteniyorsa ContentBody ve ContentBlock bunun için tasarlanmıştır.
Programatik taşıma — Transporter
Transport/TransportTo çiftinin altındaki yardımcı dışa açıktır; bir bileşeni JSX olmadan başka bir ebeveyne taşımak için kullanılır:
import { Transporter } from '@motifx/core';
Transporter.transport(child, newParent); // sona ekle
Transporter.transport(child, newParent, { index: 0 }); // verilen dizine ekle
Transporter.transportMany([a, b], newParent);
import { Transporter } from '@motifx/core';
Transporter.transport(child, newParent); // sona ekle
Transporter.transport(child, newParent, { index: 0 }); // verilen dizine ekle
Transporter.transportMany([a, b], newParent);
transport çocuğu eski ebeveyninden çıkış geçişi oynatmadan ayırır, yeni ebeveynin controls'una ekler ve bağlarını yeniden etkinleştirir (reState). TransportOptions: index (ekleme dizini; transportMany çocukları bu dizinden başlayarak verilen sırayla yerleştirir), keepState: true (bağları yeniden etkinleştirme), owner (taşıyanı motif.options.ownerTransporter'a yazar). Çocuk zaten o ebeveyndeyse hiçbir şey yapmaz.
Sonraki adım
Birden çok kaynaktan birikerek dolan gövde için ContentBody ve ContentBlock; controls koleksiyonunun geri kalanı için Bileşenler - controls.