@triggery/vue
Vue 3 bindings for Triggery. Same useEvent / useCondition / useAction shape as @triggery/react, native to Vue’s Composition API and effectScope. Zero runtime dependencies — a thin lifecycle layer over @triggery/core.
Install
Section titled “Install”pnpm add @triggery/core @triggery/vue vue npm install @triggery/core @triggery/vue vue yarn add @triggery/core @triggery/vue vue bun add @triggery/core @triggery/vue vue Peer deps: vue >= 3.0.0.
What’s inside
Section titled “What’s inside”| Export | Purpose |
|---|---|
useEvent | Typed event emitter, stable function identity. |
useCondition | Register a pull-only condition getter. Reads refs naturally. |
useAction | Register an action handler. Auto-cleans via onScopeDispose. |
useInlineTrigger | One-off triggers inside a <script setup>. |
<TriggerRuntimeProvider> / provideTriggerRuntime | Inject a runtime via provide/inject. |
<TriggerScope> / provideTriggerScope | Scope registrations to a feature subtree. |
Quick start
Section titled “Quick start”Three small components. The trigger reads like a spec, each component only knows about its own port.
1. Define the trigger
Section titled “1. Define the trigger”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,
});
},
});2. Wrap the tree
Section titled “2. Wrap the tree”<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>3. Wire components
Section titled “3. Wire components”<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><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><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>Click the button — Toast logs. Toggle settings.value.notifications to false — silent.
How Vue integration works
Section titled “How Vue integration works”Composables work both inside component setup() and inside detached effectScope()s. useCondition does not subscribe via watch — it’s pull-only, so dispatches never re-render the host component. If a component also needs to render the same data, use a normal computed or ref alongside.
Cleanup
Section titled “Cleanup”Everything auto-cleans via onScopeDispose — works in setup scope, detached scopes, and inside <KeepAlive> correctly.