Framework entegrasyonları
Tek-sayfa uygulamalarında kapsayıcı öğeler sayfa yüklendikten sonra oluşur; bu yüzden yükleyiciyi bir kez yükleyip her bileşende mount/unmount çağırmak gerekir. Aşağıdaki örnekler aynı kalıbı izler: betiği (gerekirse) yükle → kapsayıcıyı mount et → bileşen kaldırılırken unmount et. Daha az kodla ilerlemek için son üç sekmedeki özel öğeleri veya SDK bileşenlerini kullanabilirsiniz.
import { useEffect, useRef } from 'react';
const LOADER = 'https://api.mirac-ozdemir.com/widget.js';let loading: Promise<void> | null = null;
function loadWidget(): Promise<void> { if (window.MiracOzdemirWidget) return Promise.resolve(); loading ??= new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = LOADER; script.async = true; script.onload = () => resolve(); script.onerror = () => reject(new Error('widget.js yüklenemedi')); document.head.append(script); }); return loading;}
export function Calculator({ tool, locale = 'tr' }: { tool: string; locale?: 'tr' | 'en' }) { const ref = useRef<HTMLDivElement>(null);
useEffect(() => { const node = ref.current; if (!node) return; let active = true; loadWidget().then(() => active && window.MiracOzdemirWidget?.mount(node)).catch(console.error); return () => { active = false; window.MiracOzdemirWidget?.unmount(node); }; }, [tool, locale]);
return <div ref={ref} data-mo-tool={tool} data-locale={locale} />;}// components/calculator.tsx — App Router'use client';
import { useEffect, useRef } from 'react';
export function Calculator({ tool }: { tool: string }) { const ref = useRef<HTMLDivElement>(null);
useEffect(() => { const node = ref.current; const mount = () => node && window.MiracOzdemirWidget?.mount(node); if (window.MiracOzdemirWidget) { mount(); } else { const script = document.createElement('script'); script.src = 'https://api.mirac-ozdemir.com/widget.js'; script.async = true; script.addEventListener('load', mount); document.head.append(script); } return () => { if (node) window.MiracOzdemirWidget?.unmount(node); }; }, []);
return <div ref={ref} data-mo-tool={tool} />;}Sunucu bileşenlerinde doğrudan kullanmayın; widget bir istemci davranışıdır. CSP kullanıyorsanız script-src ve frame-src ekleyin (Güvenlik).
<script setup lang="ts">import { onBeforeUnmount, onMounted, ref } from 'vue';
const props = defineProps<{ tool: string; locale?: 'tr' | 'en' }>();const host = ref<HTMLElement | null>(null);
onMounted(() => { const mount = () => host.value && window.MiracOzdemirWidget?.mount(host.value); if (window.MiracOzdemirWidget) return mount(); const script = document.createElement('script'); script.src = 'https://api.mirac-ozdemir.com/widget.js'; script.async = true; script.addEventListener('load', mount); document.head.append(script);});
onBeforeUnmount(() => host.value && window.MiracOzdemirWidget?.unmount(host.value));</script>
<template> <div ref="host" :data-mo-tool="props.tool" :data-locale="props.locale ?? 'tr'"></div></template>Nuxt’ta bileşeni <ClientOnly> içinde kullanın.
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
declare global { interface Window { MiracOzdemirWidget?: { mount(el: Element): unknown; unmount(el: Element): boolean } }}
@Component({ selector: 'app-calculator', standalone: true, template: `<div #host [attr.data-mo-tool]="tool" [attr.data-locale]="locale"></div>`,})export class CalculatorComponent implements AfterViewInit, OnDestroy { @Input() tool = 'kdv'; @Input() locale: 'tr' | 'en' = 'tr'; @ViewChild('host', { static: true }) host!: ElementRef<HTMLElement>;
ngAfterViewInit(): void { const mount = () => window.MiracOzdemirWidget?.mount(this.host.nativeElement); if (window.MiracOzdemirWidget) return void mount(); const script = document.createElement('script'); script.src = 'https://api.mirac-ozdemir.com/widget.js'; script.async = true; script.addEventListener('load', mount); document.head.append(script); }
ngOnDestroy(): void { window.MiracOzdemirWidget?.unmount(this.host.nativeElement); }}<script lang="ts"> import { onDestroy, onMount } from 'svelte';
export let tool = 'kdv'; let host: HTMLElement;
onMount(() => { const mount = () => window.MiracOzdemirWidget?.mount(host); if (window.MiracOzdemirWidget) return mount(); const script = document.createElement('script'); script.src = 'https://api.mirac-ozdemir.com/widget.js'; script.async = true; script.addEventListener('load', mount); document.head.append(script); });
onDestroy(() => host && window.MiracOzdemirWidget?.unmount(host));</script>
<div bind:this={host} data-mo-tool={tool}></div>Yükleyici <mo-calculator>, <mo-search> ve <mo-category> öğelerini tanımlar; mount/unmount’u öğenin kendisi yönetir (bağlanınca mount, kopunca unmount). Svelte, Angular (CUSTOM_ELEMENTS_SCHEMA) ve Vue’da (compilerOptions.isCustomElement) doğrudan kullanılabilir:
<mo-calculator tool="kdv" locale="tr" theme="inherit" input-amount="1000" autorun></mo-calculator><script src="https://api.mirac-ozdemir.com/widget.js" async></script>Öznitelik değişince çoğu seçenek canlı güncellenir, tool/locale gibi olanlar yeniden kurulur. Ayrıntı: Özel öğeler ve SDK.
import { useRef } from 'react';import { Calculator, useWidget } from '@mirac-ozdemir/widget/react';
export function Vat({ amount }: { amount: string }) { const ref = useRef<HTMLDivElement>(null); const { ready, calculate } = useWidget(ref);
return ( <> <Calculator ref={ref} tool="kdv" locale="tr" theme="inherit" inputs={{ amount }} onResult={({ data }) => console.log(data.result)} /> <button disabled={!ready} onClick={() => calculate().then((r) => console.log(r.data.result))}>Hesapla</button> </> );}Yükleme, mount/unmount ve canlı güncelleme bileşende hazırdır. Paket henüz npm’de yayınlanmadı; bkz. SDK.
<script setup lang="ts">import { ref } from 'vue';import { Calculator, type CalculatorExposed } from '@mirac-ozdemir/widget/vue';
const calc = ref<CalculatorExposed | null>(null);</script>
<template> <Calculator ref="calc" tool="kdv" locale="tr" :inputs="{ amount: '1000' }" autorun @result="(d) => console.log(d.data.result)" /> <button @click="calc?.calculate()">Hesapla</button></template>İçerik yönetim sistemleri
Bölüm başlığı “İçerik yönetim sistemleri”| Platform | Nasıl |
|---|---|
| WordPress | Blok düzenleyicide Özel HTML bloğu ekleyin ve kurulum kodunu yapıştırın. Betik filtreleniyorsa tema footer.php’ye <script … async> ekleyin, kapsayıcıyı yazıda bırakın. |
| Webflow / Wix / Squarespace | Embed / HTML öğesine kapsayıcı ve betiği birlikte yapıştırın. Betik engelleniyorsa düz iframe kullanın. |
| Google Tag Manager | Kapsayıcıyı sayfaya yerleştirin; Özel HTML etiketine yalnızca <script src="…/widget.js" async></script> ekleyin. Etiket, sayfa yüklendikten sonra çalışsa bile yükleyici kendisi tarama yapar. |
| Markdown / statik site | HTML’e izin veriyorsa kapsayıcıyı ve betiği doğrudan yazın. Astro/Hugo/Jekyll’da şablonun sonuna betiği ekleyin. |
| E-posta | Desteklenmez (betik ve iframe e-postada çalışmaz). Bunun yerine araç sayfasına bağlantı verin. |
Ortak ipuçları
Bölüm başlığı “Ortak ipuçları”- Bir bileşen
toolveyalocaledeğiştirdiğinde widget’ıunmountedip yenidenmountedin (yukarıdaki React örneği bunu bağımlılık dizisiyle yapar) ya daupdate(el, { tool, locale })çağırın. Tema, vurgu rengi, köşe, yoğunluk, başlık veviewgibi seçenekler için yeniden kurmaya gerek yoktur:updateiframe’i yeniden yüklemeden uygular. Sayfanızın temasını izlemek içindata-theme="inherit"kullanın. - Ön değerleri bir form durumundan beslemek için
setInputs(el, değerler); sonucu istek üzerine almak içinawait calculate(el)kullanın. - Sunucu tarafı oluşturmada (SSR)
windowyoktur; mount işlemi yalnızca istemcide yapılmalıdır. - Kapsayıcının içine SSR’da yedek bir bağlantı koyabilirsiniz; hidrasyondan sonra widget bunu iframe ile değiştirir. Bazı framework’lerde bu çocuk öğeyi framework’ün kendisi yönetiyorsa uyarı verebilir; bu durumda kapsayıcıyı boş bırakıp yedek bağlantıyı yanına koyun.