Перейти к содержимому
GitHubXDiscord

@triggery/vue

Биндинги Vue 3 для Triggery. Та же форма useEvent / useCondition / useAction, что в @triggery/react, нативно для Composition API и effectScope. Без рантайм-зависимостей — тонкая прослойка над жизненным циклом поверх @triggery/core.

npm bundle

pnpm add @triggery/core @triggery/vue vue

Peer-зависимости: vue >= 3.0.0.

ЭкспортНазначение
useEventТипизированный эмиттер событий со стабильной идентичностью функции.
useConditionРегистрирует pull-only геттер условия. Естественно читает рефы.
useActionРегистрирует обработчик действия. Автоочистка через onScopeDispose.
useInlineTriggerОдноразовые триггеры внутри <script setup>.
<TriggerRuntimeProvider> / provideTriggerRuntimeВнедрить рантайм через provide/inject.
<TriggerScope> / provideTriggerScopeОграничить регистрации поддеревом-фичей.

Три небольших компонента. Триггер читается как спецификация, каждый компонент знает только о своём порту.

src/triggers/messageTrigger.ts
import { createTrigger } from '@triggery/core';

export type Settings = { sound: boolean; notifications: boolean };

export const messageTrigger = createTrigger<{
  events: { 'new-message': { text: string; author: string } };
  conditions: { settings: Settings };
  actions: { showToast: { title: string; body: string } };
}>({
  id: 'message-received',
  events: ['new-message'],
  required: ['settings'],
  handler({ event, conditions, actions }) {
    if (!conditions.settings.notifications) return;
    actions.showToast?.({
      title: event.payload.author,
      body:  event.payload.text,
    });
  },
});
src/App.vue
<script setup lang="ts">
import { createRuntime } from '@triggery/core';
import { TriggerRuntimeProvider } from '@triggery/vue';
import SettingsProvider from './SettingsProvider.vue';
import Chat from './Chat.vue';
import Toast from './Toast.vue';

const runtime = createRuntime();
</script>

<template>
  <TriggerRuntimeProvider :runtime="runtime">
    <SettingsProvider />
    <Chat />
    <Toast />
  </TriggerRuntimeProvider>
</template>
src/SettingsProvider.vue
<script setup lang="ts">
import { ref } from 'vue';
import { useCondition } from '@triggery/vue';
import { messageTrigger, type Settings } from './triggers/messageTrigger';

const settings = ref<Settings>({ sound: true, notifications: true });
useCondition(messageTrigger, 'settings', () => settings.value);
</script>

<template></template>
src/Chat.vue
<script setup lang="ts">
import { useEvent } from '@triggery/vue';
import { messageTrigger } from './triggers/messageTrigger';

const fire = useEvent(messageTrigger, 'new-message');
</script>

<template>
  <button @click="fire({ text: 'hi', author: 'Alice' })">send</button>
</template>
src/Toast.vue
<script setup lang="ts">
import { useAction } from '@triggery/vue';
import { messageTrigger } from './triggers/messageTrigger';

useAction(messageTrigger, 'showToast', ({ title, body }) => {
  console.log(`[${title}] ${body}`);
});
</script>

<template></template>

Нажми на кнопку — Toast залогирует. Переключи settings.value.notifications в false — тишина.

Composables работают и внутри setup(), и внутри отдельного effectScope(). useCondition не подписывается через watch — он pull-only, поэтому диспатчи никогда не перерендеривают хост-компонент. Если тому же компоненту нужно отрендерить те же данные — используй обычный computed или ref параллельно.

Всё автоматически очищается через onScopeDispose — корректно работает в setup-скоупе, отдельных скоупах и внутри <KeepAlive>.