Temel kavramlar
motif Ad Alanı
Bileşen üzerindeki çerçeve işlemleri: `show`/`hide`/`toggle`, `on`/`off`/`trigger`, `setDisposable`/`register`, `clear`, `stopAnimations` ve `motif.options`.
MotifJS'in bir bileşen üzerinde yaptığı işlemler motif ad alanında toplanır: sınıfta ve Options'ta this.motif, fonksiyon bileşeninde kökün ya da ref ile tutulan bir bileşenin motif'i. Bu işlemler sınıfın kendi üyeleriyle karışmaz; sınıfta show, on ya da clear adında kendi metodunuzu yazabilirsiniz (bkz. Sınıf üyelerinin adları).
Üyeler
| Üye | Ne yapar |
|---|---|
show(), hide(), toggle() |
Bileşeni serbest bırakmadan gösterir ve gizler. Gizlenen elemanın yerinde <!--h--> izi kalır, gösterilince eleman izin yerine döner. show ve hide geçiş bitince çözülen bir söz döndürür (bkz. Görünürlük). |
on(ad, fn), off(ad, fn) |
Bir DOM olayını ya da bileşen olayını dinler ve bırakır. "keydown:prevent", "click:once" gibi değiştiriciler yazılır. Dinleyiciler bileşen serbest bırakılınca kalkar (bkz. Bileşen olay API'si). |
trigger(ad, veri) |
O adla kaydedilmiş işleyicileri veri ile çağırır; DOM'a olay göndermez. |
addHandler(ad, fn) |
on(ad, fn) ile aynıdır, değer döndürmez. |
setDisposable(fn) |
fn bileşen serbest bırakılırken çalışır: belgeye eklenen dinleyiciyi, zamanlayıcıyı ya da dış bir kütüphanenin kurulumunu bırakmak için (bkz. Bellek Yönetimi ve Serbest Bırakma). |
register(nesne) |
dispose() metodu olan bir nesneyi bileşenin ömrüne bağlar; bileşenle birlikte serbest bırakılır. |
clear() |
Bütün çocukları serbest bırakır (controls.clearAsync()). options.disableDisposal açıksa hiçbir şey yapmaz. |
stopAnimations() |
Süren CSS sınıf geçişini bitirir, WAAPI animasyonlarını iptal eder (bkz. Stil ve Animasyon). |
options |
Bileşenin ayarları; aşağıda. |
Bir örnek
Not listesinin arama kutusu üç işi motif ile yapar. / tuşu sayfanın her yerinden aramaya odak verir; bu dinleyici belgeye eklendiği için bileşen kaldırılınca setDisposable ile bırakılır. Escape aramayı temizler: kutunun motif.on("keydown", …) dinleyicisi alandan kabaran olayı yakalar. Alan odaktayken / ipucu motif.hide() ile gizlenir, odak gidince motif.show() ile geri gelir. Aramanın kendisi ebeveynin reaktif state nesnesindedir:
import { Component } from "@motifx/core";
export class SearchBox extends Component<HTMLDivElement, { state: { query: string } }> {
input!: Component<HTMLInputElement>;
hint!: Component<HTMLElement>;
override onConfigured() {
this.class.add("search");
}
override onConfig() {
this.motif.on("keydown", (_box, e: KeyboardEvent) => {
if (e.key === "Escape") this.props.state.query = "";
});
const focusSearch = (e: KeyboardEvent) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement as HTMLElement | null)?.tagName ?? "")) return;
e.preventDefault();
this.input.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
}
override view() {
const { state } = this.props;
return (
<>
<input
ref={this.input}
type="search"
placeholder="Notlarda ara"
aria-label="Notlarda ara"
autocomplete="off"
x-model={() => state.query}
onfocus={() => this.hint.motif.hide()}
onblur={() => this.hint.motif.show()}
/>
<kbd ref={this.hint}>/</kbd>
</>
);
}
}
import { Component, ComponentBase, motifComponent, motifFragment } from "@motifx/core";
export class SearchBox extends Component<HTMLDivElement, { state: { query: string } }> {
static override elementTag = "div";
input!: Component<HTMLInputElement>;
hint!: Component<HTMLElement>;
override onConfigured() {
this.class.add("search");
}
override onConfig() {
this.motif.on("keydown", (_box, e: KeyboardEvent) => {
if (e.key === "Escape") this.props.state.query = "";
});
const focusSearch = (e: KeyboardEvent) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement as HTMLElement | null)?.tagName ?? "")) return;
e.preventDefault();
this.input.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
}
override view() {
const { state } = this.props;
const input = motifComponent("input", {
ref: (field: Component<HTMLInputElement>) => (this.input = field),
initializeComponent: (field: ComponentBase) => {
field.attr.add({ type: "search", placeholder: "Notlarda ara", "aria-label": "Notlarda ara", autocomplete: "off" });
field.bindings.model(() => state.query, (value: string) => (state.query = value));
field.motif.on("focus", () => this.hint.motif.hide());
field.motif.on("blur", () => this.hint.motif.show());
},
});
const hint = motifComponent("kbd", {
ref: (kbd: Component<HTMLElement>) => (this.hint = kbd),
initializeComponent: (kbd: ComponentBase) => kbd.setText("/"),
});
return motifFragment({ childs: [input, hint] });
}
}
import type { Component, ComponentBase } from "@motifx/core";
export function SearchBox(props: { state: { query: string } }) {
const { state } = props;
let input!: Component<HTMLInputElement>;
let hint!: Component<HTMLElement>;
const configured = (box: ComponentBase) => {
box.motif.on("keydown", (_box, e: KeyboardEvent) => {
if (e.key === "Escape") state.query = "";
});
const focusSearch = (e: KeyboardEvent) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement as HTMLElement | null)?.tagName ?? "")) return;
e.preventDefault();
input.element.focus();
};
document.addEventListener("keydown", focusSearch);
box.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
};
return (
<div class="search" onConfig={configured}>
<input
ref={input}
type="search"
placeholder="Notlarda ara"
aria-label="Notlarda ara"
autocomplete="off"
x-model={() => state.query}
onfocus={() => hint.motif.hide()}
onblur={() => hint.motif.show()}
/>
<kbd ref={hint}>/</kbd>
</div>
);
}
import { Component, ComponentBase, motifComponent } from "@motifx/core";
export function SearchBox(props: { state: { query: string } }) {
const { state } = props;
let input!: Component<HTMLInputElement>;
let hint!: Component<HTMLElement>;
const configured = (box: ComponentBase) => {
box.motif.on("keydown", (_box, e: KeyboardEvent) => {
if (e.key === "Escape") state.query = "";
});
const focusSearch = (e: KeyboardEvent) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement as HTMLElement | null)?.tagName ?? "")) return;
e.preventDefault();
input.element.focus();
};
document.addEventListener("keydown", focusSearch);
box.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
};
return motifComponent("div", {
class: "search",
onConfig: configured,
initializeComponent: (box: ComponentBase) => {
const field = motifComponent("input", {
ref: (c: Component<HTMLInputElement>) => (input = c),
initializeComponent: (c: ComponentBase) => {
c.attr.add({ type: "search", placeholder: "Notlarda ara", "aria-label": "Notlarda ara", autocomplete: "off" });
c.bindings.model(() => state.query, (value: string) => (state.query = value));
c.motif.on("focus", () => hint.motif.hide());
c.motif.on("blur", () => hint.motif.show());
},
});
const kbd = motifComponent("kbd", {
ref: (c: Component<HTMLElement>) => (hint = c),
initializeComponent: (c: ComponentBase) => c.setText("/"),
});
box.controls.add(field, kbd);
},
});
}
import { motifOptions, type Component } from "@motifx/core";
export const SearchBox = (props: { state: { query: string } }) => motifOptions({
el: "div",
input: undefined as Component<HTMLInputElement> | undefined,
hint: undefined as Component<HTMLElement> | undefined,
onConfigured() {
this.class.add("search");
this.motif.on("keydown", (_box, e: KeyboardEvent) => {
if (e.key === "Escape") props.state.query = "";
});
const focusSearch = (e: KeyboardEvent) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement as HTMLElement | null)?.tagName ?? "")) return;
e.preventDefault();
this.input!.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
},
view() {
const { state } = props;
return (
<>
<input
ref={this.input}
type="search"
placeholder="Notlarda ara"
aria-label="Notlarda ara"
autocomplete="off"
x-model={() => state.query}
onfocus={() => this.hint!.motif.hide()}
onblur={() => this.hint!.motif.show()}
/>
<kbd ref={this.hint}>/</kbd>
</>
);
},
});
import { Component, ComponentBase, motifComponent, motifFragment, motifOptions } from "@motifx/core";
export const SearchBox = (props: { state: { query: string } }) => motifOptions({
el: "div",
input: undefined as Component<HTMLInputElement> | undefined,
hint: undefined as Component<HTMLElement> | undefined,
onConfigured() {
this.class.add("search");
this.motif.on("keydown", (_box, e: KeyboardEvent) => {
if (e.key === "Escape") props.state.query = "";
});
const focusSearch = (e: KeyboardEvent) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement as HTMLElement | null)?.tagName ?? "")) return;
e.preventDefault();
this.input!.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
},
view() {
const { state } = props;
const input = motifComponent("input", {
ref: (field: Component<HTMLInputElement>) => (this.input = field),
initializeComponent: (field: ComponentBase) => {
field.attr.add({ type: "search", placeholder: "Notlarda ara", "aria-label": "Notlarda ara", autocomplete: "off" });
field.bindings.model(() => state.query, (value: string) => (state.query = value));
field.motif.on("focus", () => this.hint!.motif.hide());
field.motif.on("blur", () => this.hint!.motif.show());
},
});
const hint = motifComponent("kbd", {
ref: (kbd: Component<HTMLElement>) => (this.hint = kbd),
initializeComponent: (kbd: ComponentBase) => kbd.setText("/"),
});
return motifFragment({ childs: [input, hint] });
},
});
import { Component } from "@motifx/core";
export class SearchBox extends Component {
static elementTag = "div";
input;
hint;
onConfigured() {
this.class.add("search");
}
onConfig() {
this.motif.on("keydown", (_box, e) => {
if (e.key === "Escape") this.props.state.query = "";
});
const focusSearch = (e) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement)?.tagName ?? "")) return;
e.preventDefault();
this.input.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
}
view() {
const { state } = this.props;
return (
<>
<input
ref={this.input}
type="search"
placeholder="Notlarda ara"
aria-label="Notlarda ara"
autocomplete="off"
x-model={() => state.query}
onfocus={() => this.hint.motif.hide()}
onblur={() => this.hint.motif.show()}
/>
<kbd ref={this.hint}>/</kbd>
</>
);
}
}
import { Component, motifComponent, motifFragment } from "@motifx/core";
export class SearchBox extends Component {
static elementTag = "div";
input;
hint;
onConfigured() {
this.class.add("search");
}
onConfig() {
this.motif.on("keydown", (_box, e) => {
if (e.key === "Escape") this.props.state.query = "";
});
const focusSearch = (e) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement)?.tagName ?? "")) return;
e.preventDefault();
this.input.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
}
view() {
const { state } = this.props;
const input = motifComponent("input", {
ref: (field) => (this.input = field),
initializeComponent: (field) => {
field.attr.add({ type: "search", placeholder: "Notlarda ara", "aria-label": "Notlarda ara", autocomplete: "off" });
field.bindings.model(() => state.query, (value) => (state.query = value));
field.motif.on("focus", () => this.hint.motif.hide());
field.motif.on("blur", () => this.hint.motif.show());
},
});
const hint = motifComponent("kbd", {
ref: (kbd) => (this.hint = kbd),
initializeComponent: (kbd) => kbd.setText("/"),
});
return motifFragment({ childs: [input, hint] });
}
}
export function SearchBox(props) {
const { state } = props;
let input;
let hint;
const configured = (box) => {
box.motif.on("keydown", (_box, e) => {
if (e.key === "Escape") state.query = "";
});
const focusSearch = (e) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement)?.tagName ?? "")) return;
e.preventDefault();
input.element.focus();
};
document.addEventListener("keydown", focusSearch);
box.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
};
return (
<div class="search" onConfig={configured}>
<input
ref={input}
type="search"
placeholder="Notlarda ara"
aria-label="Notlarda ara"
autocomplete="off"
x-model={() => state.query}
onfocus={() => hint.motif.hide()}
onblur={() => hint.motif.show()}
/>
<kbd ref={hint}>/</kbd>
</div>
);
}
import { motifComponent } from "@motifx/core";
export function SearchBox(props) {
const { state } = props;
let input;
let hint;
const configured = (box) => {
box.motif.on("keydown", (_box, e) => {
if (e.key === "Escape") state.query = "";
});
const focusSearch = (e) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement)?.tagName ?? "")) return;
e.preventDefault();
input.element.focus();
};
document.addEventListener("keydown", focusSearch);
box.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
};
return motifComponent("div", {
class: "search",
onConfig: configured,
initializeComponent: (box) => {
const field = motifComponent("input", {
ref: (c) => (input = c),
initializeComponent: (c) => {
c.attr.add({ type: "search", placeholder: "Notlarda ara", "aria-label": "Notlarda ara", autocomplete: "off" });
c.bindings.model(() => state.query, (value) => (state.query = value));
c.motif.on("focus", () => hint.motif.hide());
c.motif.on("blur", () => hint.motif.show());
},
});
const kbd = motifComponent("kbd", {
ref: (c) => (hint = c),
initializeComponent: (c) => c.setText("/"),
});
box.controls.add(field, kbd);
},
});
}
import { motifOptions } from "@motifx/core";
export const SearchBox = (props) => motifOptions({
el: "div",
input: undefined,
hint: undefined,
onConfigured() {
this.class.add("search");
this.motif.on("keydown", (_box, e) => {
if (e.key === "Escape") props.state.query = "";
});
const focusSearch = (e) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement)?.tagName ?? "")) return;
e.preventDefault();
this.input.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
},
view() {
const { state } = props;
return (
<>
<input
ref={this.input}
type="search"
placeholder="Notlarda ara"
aria-label="Notlarda ara"
autocomplete="off"
x-model={() => state.query}
onfocus={() => this.hint.motif.hide()}
onblur={() => this.hint.motif.show()}
/>
<kbd ref={this.hint}>/</kbd>
</>
);
},
});
import { motifComponent, motifFragment, motifOptions } from "@motifx/core";
export const SearchBox = (props) => motifOptions({
el: "div",
input: undefined,
hint: undefined,
onConfigured() {
this.class.add("search");
this.motif.on("keydown", (_box, e) => {
if (e.key === "Escape") props.state.query = "";
});
const focusSearch = (e) => {
if (e.key !== "/" || /^(INPUT|TEXTAREA)$/.test((document.activeElement)?.tagName ?? "")) return;
e.preventDefault();
this.input.element.focus();
};
document.addEventListener("keydown", focusSearch);
this.motif.setDisposable(() => document.removeEventListener("keydown", focusSearch));
},
view() {
const { state } = props;
const input = motifComponent("input", {
ref: (field) => (this.input = field),
initializeComponent: (field) => {
field.attr.add({ type: "search", placeholder: "Notlarda ara", "aria-label": "Notlarda ara", autocomplete: "off" });
field.bindings.model(() => state.query, (value) => (state.query = value));
field.motif.on("focus", () => this.hint.motif.hide());
field.motif.on("blur", () => this.hint.motif.show());
},
});
const hint = motifComponent("kbd", {
ref: (kbd) => (this.hint = kbd),
initializeComponent: (kbd) => kbd.setText("/"),
});
return motifFragment({ childs: [input, hint] });
},
});
Not listesi kutuyu kendi arama durumuyla yerleştirir: <SearchBox state={this.state} />.
Not listesi kutuyu kendi arama durumuyla yerleştirir: new SearchBox({ state: this.state }).
Not listesi kutuyu kendi arama durumuyla yerleştirir: motifComponent(SearchBox, { state: this.state }).
motif.on ile eklenen dinleyiciyi bileşen kendisi bırakır; belgeye ya da window'a doğrudan eklenen dinleyiciyi ise bileşen tanımaz, onu setDisposable bırakır. Aynı kural zamanlayıcılar, gözlemciler (ResizeObserver, IntersectionObserver) ve dış kütüphanelerin kurulumları için de geçerlidir.
motif.options
| Alan | Anlamı |
|---|---|
hideStrategy |
Gizlenen elemanın DOM'da nasıl duracağı: "auto" (varsayılan), "placeholder" ya da "detach" (bkz. Gizleme stratejisi). |
disableDisposal |
true ise motif.clear() çocukları serbest bırakmaz. |
transition |
Geçiş ayarı ve WAAPI ile in/out animasyonları (bkz. Stil ve Animasyon). |
enableRouterClassing |
Yalnız yazılır: elemana geçerli adrese göre sınıf verir (bkz. Rota sınıfları). |
display |
Okununca isVisible'ı verir; true yazmak show(), false yazmak hide() çağırır. |
hasEvent(ad) |
O adla kaydedilmiş bir işleyici var mı. |
getInstance() |
Bileşenin kendisi. |
hideStrategy ve disableDisposal bileşen yaratılırken options prop'uyla da verilir: JSX'te options={{ hideStrategy: "detach" }}, JSX'siz yazımda props nesnesinin options anahtarı.
Sonraki adım
Bileşenin bağlarını tanımak için bindings bölümüne geçin.