@triggery/react 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,18 +1,62 @@
|
|
|
1
1
|
# @triggery/react
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- d920da6: ### `@triggery/core`
|
|
8
|
+
- Inline conditions on `createTrigger({ conditions: { ... } })` plus a typed `trigger.setCondition(name, value)` setter (B1).
|
|
9
|
+
- `trigger.action(name).subscribe(cb)` action channels — typed multi-subscriber fan-out that coexists with `runtime.registerAction` (B2).
|
|
10
|
+
- New `Runtime.subscribeAction(triggerId, name, cb, options?)` — the additive, non-last-mount-wins subscription path used by the channel API.
|
|
11
|
+
- Builder API: `createTrigger<S>()` (no args) returns a `TriggerBuilder<S>` with `.id`, `.events`, `.require`, `.conditions`, `.schedule`, `.concurrency`, `.scope`, `.handle`. `.require(...)` narrows handler `conditions` to `NonNullable<...>` — no more `!` or `if (!conditions.x) return;` (B3).
|
|
12
|
+
- New subpath `@triggery/core/inspect` exports `createInspector`, `createNoopInspector`, `createInspectorFactory`. Pass `inspector: createInspectorFactory()` to `createRuntime` for the bundle-friendly opt-in pattern (A1).
|
|
13
|
+
- New public types: `ActionChannel<P>`, `TriggerBuilder<S, R>`, `InspectorFactory`.
|
|
14
|
+
|
|
15
|
+
### `@triggery/react`, `@triggery/solid`, `@triggery/vue`
|
|
16
|
+
- `useAction` now uses the additive `subscribeAction` path — multiple components mounting the same `useAction(trigger, name, ...)` all run on every emit (instead of the v0.9 last-mount-wins behaviour). Switch to `runtime.registerAction(trigger.id, name, fn)` if you relied on the old semantics.
|
|
17
|
+
- React adds `useSetCondition(trigger, name, value)` — a thin wrapper over `useEffect(() => trigger.setCondition(...), [value])`.
|
|
18
|
+
|
|
19
|
+
### `@triggery/eslint-plugin`
|
|
20
|
+
- 4 new rules:
|
|
21
|
+
- `no-non-null-assertion-in-handler` (autofix) — flags `conditions.X!` inside a `createTrigger` handler.
|
|
22
|
+
- `prefer-builder-trigger` — suggests the v0.10 builder form when `required: [...]` is used.
|
|
23
|
+
- `prefer-trigger-conditions` — suggests inline `conditions:` config when a `registerCondition` getter reads a local `let`.
|
|
24
|
+
- `prefer-action-channel` — flags hand-rolled `Set + for-of` fan-out and suggests `t.action(name).subscribe(cb)`.
|
|
25
|
+
- `no-non-null-assertion-in-handler` is `warn` in `recommended`; the three `prefer-*` rules are `warn` in `strict`.
|
|
26
|
+
|
|
27
|
+
### `@triggery/codemod`
|
|
28
|
+
- New codemod `migrate-to-v010` — ts-morph based. Folds `let + registerCondition` pairs into the `conditions:` config, removes `conditions.X!` assertions inside handlers, leaves review markers for fan-out patterns. CLI: `npx @triggery/codemod migrate-to-v010 'src/**/*.ts'`.
|
|
29
|
+
|
|
30
|
+
### Bundle (A1 + A2 + A3)
|
|
31
|
+
- **DEV warnings tree-shake-able** — every console.warn / warnedCollisions cache lives under `if (process.env.NODE_ENV !== 'production')` so the bundler's production build drops them entirely. Helper functions live in their own `dev-warn.ts` module that gets eliminated cross-module.
|
|
32
|
+
- **Production-only bundle** — `dist/index.prod.js` and `dist/inspect.prod.js` ship with DEV blocks stripped at our build time; picked automatically through the `"production"` export condition by Webpack / Vite / esbuild prod modes.
|
|
33
|
+
- **Timer + dispatch helpers extracted** — `timers.ts` (debounce/throttle/defer) and `dispatch-helpers.ts` (genRunId, invokeAction) live in their own modules.
|
|
34
|
+
- **Last-write-wins** for `runtime.registerCondition` / `runtime.registerAction` — the previous stack-based fallback was removed, simplifying the hot path. StrictMode safety preserved because the mount→unmount→mount cycle clears the unmount token before the second mount runs.
|
|
35
|
+
- **Builder API moved to a subpath** — chainable `createTrigger<S>()` (no args) now lives in `@triggery/core/builder`; the imperative `createTrigger({ id, events, handler })` form stays in `@triggery/core`.
|
|
36
|
+
- **Result**: `@triggery/core` main entry shrinks from **~5.2 KB gz to ~4.2 KB gz** when bundled by a production-configured downstream (—19%). Combined with `@triggery/core/builder` deduped via the bundler the total is **~3.8 KB gz** — below the 4 KB target.
|
|
37
|
+
|
|
38
|
+
### Backwards compatibility
|
|
39
|
+
|
|
40
|
+
All v0.9 APIs continue to work. The legacy paths (`runtime.registerCondition`, `runtime.registerAction`, `createTrigger({ required: [...], handler })`, `createRuntime({ inspector: true })`) will gain `@deprecated` JSDoc in v0.11 and be removed in v1.0.
|
|
41
|
+
|
|
42
|
+
See the [Upgrading from v0.9 guide](https://triggeryjs.github.io/migration/from-v0.9/).
|
|
43
|
+
|
|
44
|
+
### Patch Changes
|
|
45
|
+
|
|
46
|
+
- Updated dependencies [d920da6]
|
|
47
|
+
- @triggery/core@0.10.0
|
|
48
|
+
|
|
3
49
|
## 0.1.2
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
|
6
52
|
|
|
7
53
|
- f23e155: Filled out the quick-start sections in the npm package READMEs that adopters land on first.
|
|
8
|
-
|
|
9
54
|
- `@triggery/core` README now contains a three-tab quick-start (React / Solid / Vue) with concrete `pnpm add` commands and runnable code, plus pointers to the per-binding README for the full walkthrough.
|
|
10
55
|
- `@triggery/react` README — was a stub. Now has the full four-file scenario (trigger + provider + Chat + Toast) ready to copy-paste, exactly mirroring the Solid and Vue examples.
|
|
11
56
|
|
|
12
57
|
Linked-bundle bump so the binding READMEs stay aligned with the core release; no code or API changes.
|
|
13
58
|
|
|
14
59
|
- 3385f5b: Every package README now ends with a tailored **Related packages** section and a consistent `## License` footer.
|
|
15
|
-
|
|
16
60
|
- Adapter packages (`zustand`, `redux`, `jotai`, `mobx`, `reatom`, `signals`, `query`) link to `core` + `react` (required peers) plus 2-3 alternative adapters so adopters can swap them out without re-reading the whole repo.
|
|
17
61
|
- Event-source packages (`dom`, `socket`) cross-link.
|
|
18
62
|
- DevTools packages (`devtools-redux`, `devtools-panel`, `devtools-bridge`) cross-link.
|
|
@@ -31,7 +75,6 @@
|
|
|
31
75
|
### Patch Changes
|
|
32
76
|
|
|
33
77
|
- 35936d1: Polished package metadata for framework-agnostic positioning.
|
|
34
|
-
|
|
35
78
|
- `@triggery/core` description corrected: it is **framework-agnostic** (React, Solid, Vue, or any binding you write), not React-only. Keywords now include `solid`, `vue`, `framework-agnostic`, `zero-dependencies`. README expanded to spell out what runs where.
|
|
36
79
|
- `@triggery/testing` README + description now mention **zero runtime dependencies** and that the kit works under Vitest, Jest, and `node:test` alike (no `vi.useFakeTimers` coupling).
|
|
37
80
|
- `@triggery/devtools-bridge`, `@triggery/devtools-redux`, `@triggery/vite` descriptions clarified as framework-agnostic / runtime-pure.
|
package/dist/index.d.ts
CHANGED
|
@@ -41,11 +41,35 @@ declare function useEvent<S extends TriggerSchema, K extends EventKey<S>>(_trigg
|
|
|
41
41
|
* ```tsx
|
|
42
42
|
* useCondition(messageTrigger, 'user', () => currentUser, [currentUser]);
|
|
43
43
|
* ```
|
|
44
|
+
*
|
|
45
|
+
* For triggers that declare their conditions inline via `conditions:` config
|
|
46
|
+
* (v0.10+), {@link useSetCondition} is usually preferable: it pushes the value
|
|
47
|
+
* through the trigger's typed setter and pairs cleanly with React state.
|
|
44
48
|
*/
|
|
45
49
|
declare function useCondition<S extends TriggerSchema, K extends ConditionKey<S>>(trigger: Trigger<S>, name: K, getter: () => ConditionMap<S>[K], deps?: readonly unknown[]): void;
|
|
46
50
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
51
|
+
* Push a value into a condition declared inline via `createTrigger({ conditions: { ... } })`
|
|
52
|
+
* (v0.10+). The hook calls `trigger.setCondition(name, value)` on every change
|
|
53
|
+
* and again on mount. Use it when the value lives in a React state / prop and
|
|
54
|
+
* the trigger declared the condition with an explicit initial value.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```tsx
|
|
58
|
+
* const [user, setUser] = useState<User | null>(null);
|
|
59
|
+
* useSetCondition(messageTrigger, 'user', user);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function useSetCondition<S extends TriggerSchema, K extends ConditionKey<S>>(trigger: Trigger<S>, name: K, value: ConditionMap<S>[K] | null): void;
|
|
63
|
+
/**
|
|
64
|
+
* Subscribe to a trigger's action channel. The handler runs every time the
|
|
65
|
+
* trigger body calls `actions.<name>(...)`. Multiple components can subscribe
|
|
66
|
+
* to the same action — every subscriber is invoked on each emit.
|
|
67
|
+
*
|
|
68
|
+
* **v0.10 semantics change**: in v0.9 multiple `useAction` calls for the same
|
|
69
|
+
* `(trigger, name)` followed last-mount-wins (only the most-recently-mounted
|
|
70
|
+
* handler ran). Starting in v0.10 every subscriber is invoked — the more
|
|
71
|
+
* useful default. If you want exclusive-handler behaviour, use
|
|
72
|
+
* `runtime.registerAction(trigger.id, name, fn)` directly.
|
|
49
73
|
*
|
|
50
74
|
* @example
|
|
51
75
|
* ```tsx
|
|
@@ -187,6 +211,11 @@ type UseInlineTriggerConfig<S extends TriggerSchema> = {
|
|
|
187
211
|
* });
|
|
188
212
|
* ```
|
|
189
213
|
*/
|
|
214
|
+
/**
|
|
215
|
+
* Shorter alias for {@link useInlineTrigger} introduced in v0.10. Pick whichever
|
|
216
|
+
* name you prefer — both share the same implementation.
|
|
217
|
+
*/
|
|
218
|
+
declare function useTrigger<S extends TriggerSchema>(config: UseInlineTriggerConfig<S>): void;
|
|
190
219
|
declare function useInlineTrigger<S extends TriggerSchema>(config: UseInlineTriggerConfig<S>): void;
|
|
191
220
|
|
|
192
|
-
export { TriggerRuntimeContext, TriggerRuntimeProvider, type TriggerRuntimeProviderProps, TriggerScope, TriggerScopeContext, type TriggerScopeProps, type UseInlineTriggerConfig, createNamedHooks, useAction, useCondition, useEvent, useInlineTrigger, useInspect, useInspectHistory, useRuntime, useScope };
|
|
221
|
+
export { TriggerRuntimeContext, TriggerRuntimeProvider, type TriggerRuntimeProviderProps, TriggerScope, TriggerScopeContext, type TriggerScopeProps, type UseInlineTriggerConfig, createNamedHooks, useAction, useCondition, useEvent, useInlineTrigger, useInspect, useInspectHistory, useRuntime, useScope, useSetCondition, useTrigger };
|
package/dist/index.js
CHANGED
|
@@ -32,13 +32,18 @@ function useCondition(trigger, name, getter, deps = []) {
|
|
|
32
32
|
return () => token.unregister();
|
|
33
33
|
}, [runtime, trigger.id, name, stableGetter, scope]);
|
|
34
34
|
}
|
|
35
|
+
function useSetCondition(trigger, name, value) {
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
trigger.setCondition(name, value);
|
|
38
|
+
}, [trigger, name, value]);
|
|
39
|
+
}
|
|
35
40
|
function useAction(trigger, name, handler) {
|
|
36
41
|
const runtime = useRuntime();
|
|
37
42
|
const scope = useScope();
|
|
38
43
|
const handlerRef = useRef(handler);
|
|
39
44
|
handlerRef.current = handler;
|
|
40
45
|
useEffect(() => {
|
|
41
|
-
const token = runtime.
|
|
46
|
+
const token = runtime.subscribeAction(
|
|
42
47
|
trigger.id,
|
|
43
48
|
name,
|
|
44
49
|
(payload) => handlerRef.current(payload),
|
|
@@ -127,6 +132,9 @@ function TriggerScope({ id, children }) {
|
|
|
127
132
|
return /* @__PURE__ */ jsx(TriggerScopeContext.Provider, { value: id, children });
|
|
128
133
|
}
|
|
129
134
|
var inlineCounter = 0;
|
|
135
|
+
function useTrigger(config) {
|
|
136
|
+
useInlineTrigger(config);
|
|
137
|
+
}
|
|
130
138
|
function useInlineTrigger(config) {
|
|
131
139
|
const runtime = useRuntime();
|
|
132
140
|
const scope = useScope();
|
|
@@ -164,6 +172,6 @@ function useInlineTrigger(config) {
|
|
|
164
172
|
}, [runtime, stableHandler, scope]);
|
|
165
173
|
}
|
|
166
174
|
|
|
167
|
-
export { TriggerRuntimeContext, TriggerRuntimeProvider, TriggerScope, TriggerScopeContext, createNamedHooks, useAction, useCondition, useEvent, useInlineTrigger, useInspect, useInspectHistory, useRuntime, useScope };
|
|
175
|
+
export { TriggerRuntimeContext, TriggerRuntimeProvider, TriggerScope, TriggerScopeContext, createNamedHooks, useAction, useCondition, useEvent, useInlineTrigger, useInspect, useInspectHistory, useRuntime, useScope, useSetCondition, useTrigger };
|
|
168
176
|
//# sourceMappingURL=index.js.map
|
|
169
177
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.ts","../src/hooks.ts","../src/namedHooks.ts","../src/TriggerRuntimeProvider.tsx","../src/TriggerScope.tsx","../src/useInlineTrigger.ts"],"names":["jsx","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { getDefaultRuntime, type Runtime } from '@triggery/core';\nimport { createContext, useContext } from 'react';\n\n/**\n * React context used to inject a custom runtime. When no provider is present,\n * hooks fall back to the global default runtime.\n */\nexport const TriggerRuntimeContext = createContext<Runtime | undefined>(undefined);\n\n/** Read the active runtime from context, or return the default runtime. */\nexport function useRuntime(): Runtime {\n const ctxRuntime = useContext(TriggerRuntimeContext);\n return ctxRuntime ?? getDefaultRuntime();\n}\n\n/**\n * Scope context — string id provided by `<TriggerScope id=\"…\">`. Default is\n * `''` (global). Hooks pass it through to `registerCondition`/`registerAction`\n * so the runtime can match the registration against a trigger's `scope`.\n */\nexport const TriggerScopeContext = createContext<string>('');\n\n/** Read the active scope from context. `''` means \"global / no scope\". */\nexport function useScope(): string {\n return useContext(TriggerScopeContext);\n}\n","import type {\n ActionKey,\n ActionMap,\n ConditionKey,\n ConditionMap,\n EventKey,\n EventMap,\n Trigger,\n TriggerInspectSnapshot,\n TriggerSchema,\n} from '@triggery/core';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useRuntime, useScope } from './context.ts';\n\n/**\n * Return an event emitter. Its identity is stable across renders (`useCallback`\n * under the hood). The trigger must list this event in its `events: [...]` schema\n * passed to `createTrigger`.\n *\n * @example\n * ```tsx\n * const fireNewMessage = useEvent(messageTrigger, 'new-message');\n * useEffect(() => socket.on('msg', fireNewMessage), [fireNewMessage]);\n * ```\n */\nexport function useEvent<S extends TriggerSchema, K extends EventKey<S>>(\n _trigger: Trigger<S>,\n eventName: K,\n): EventMap<S>[K] extends void ? () => void : (payload: EventMap<S>[K]) => void {\n const runtime = useRuntime();\n return useCallback(\n ((payload?: unknown) => {\n runtime.fire(eventName, payload);\n }) as EventMap<S>[K] extends void ? () => void : (payload: EventMap<S>[K]) => void,\n [runtime, eventName],\n );\n}\n\n/**\n * Register a condition getter for a trigger. The runtime calls `getter()` at\n * fire-time only — there are no subscriptions and no re-renders.\n *\n * `deps` only invalidate the closure cache (same semantics as `useCallback`).\n *\n * @example\n * ```tsx\n * useCondition(messageTrigger, 'user', () => currentUser, [currentUser]);\n * ```\n */\nexport function useCondition<S extends TriggerSchema, K extends ConditionKey<S>>(\n trigger: Trigger<S>,\n name: K,\n getter: () => ConditionMap<S>[K],\n deps: readonly unknown[] = [],\n): void {\n const runtime = useRuntime();\n const scope = useScope();\n // Keep the latest getter in a ref — the runtime reads through a stable wrapper.\n const getterRef = useRef(getter);\n getterRef.current = getter;\n // biome-ignore lint/correctness/useExhaustiveDependencies: deps managed by caller\n const stableGetter = useCallback(() => getterRef.current(), deps);\n\n useEffect(() => {\n const token = runtime.registerCondition(trigger.id, name, stableGetter, { scope });\n return () => token.unregister();\n }, [runtime, trigger.id, name, stableGetter, scope]);\n}\n\n/**\n * Register an action handler for a trigger. The runtime invokes the handler whenever\n * the trigger body calls `actions.<name>(...)`.\n *\n * @example\n * ```tsx\n * useAction(messageTrigger, 'showToast', (payload) => toast.success(payload.title));\n * ```\n */\nexport function useAction<S extends TriggerSchema, K extends ActionKey<S>>(\n trigger: Trigger<S>,\n name: K,\n handler: ActionMap<S>[K] extends void\n ? () => void | Promise<void>\n : (payload: ActionMap<S>[K]) => void | Promise<void>,\n): void {\n const runtime = useRuntime();\n const scope = useScope();\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n const token = runtime.registerAction(\n trigger.id,\n name,\n (payload) => (handlerRef.current as (payload: unknown) => void | Promise<void>)(payload),\n { scope },\n );\n return () => token.unregister();\n }, [runtime, trigger.id, name, scope]);\n}\n\n/**\n * Return the latest snapshot of a trigger (for in-app debug panels).\n */\nexport function useInspect<S extends TriggerSchema>(trigger: Trigger<S>) {\n return trigger.inspect();\n}\n\n/**\n * Subscribe to the active runtime's inspector buffer and return the most\n * recent `limit` snapshots (newest first). Re-renders whenever a new run is\n * recorded.\n *\n * Use this for in-app devtools panels, custom run lists, or any \"show me the\n * last N runs\" UI. Combine with `<TriggerSnapshotView>` from\n * `@triggery/devtools-panel` for a turnkey UI.\n *\n * @example\n * ```tsx\n * function DebugPanel() {\n * const history = useInspectHistory(50);\n * return <ul>{history.map((s) => <li key={s.runId}>{s.triggerId}: {s.status}</li>)}</ul>;\n * }\n * ```\n */\nexport function useInspectHistory(limit = 20): readonly TriggerInspectSnapshot[] {\n const runtime = useRuntime();\n const [history, setHistory] = useState<readonly TriggerInspectSnapshot[]>(() =>\n runtime.getInspectorBuffer().slice(0, limit),\n );\n\n useEffect(() => {\n // Re-seed on mount in case fires happened between the initial render and\n // the effect (the runtime may have new entries already).\n setHistory(runtime.getInspectorBuffer().slice(0, limit));\n const token = runtime.subscribe(() => {\n setHistory(runtime.getInspectorBuffer().slice(0, limit));\n });\n return () => token.unregister();\n }, [runtime, limit]);\n\n return history;\n}\n","import type { NamedHooks, Trigger, TriggerSchema } from '@triggery/core';\nimport { useAction, useCondition, useEvent } from './hooks.ts';\n\n/**\n * Build the named-hooks proxy for a trigger.\n *\n * For a schema with `events: { 'new-message' }`, `conditions: { user }` and\n * `actions: { showToast }` this returns:\n *\n * useNewMessageEvent -> () => fire\n * useUserCondition -> (getter, deps?) => void\n * useShowToastAction -> (handler) => void\n *\n * Names are derived from string keys via `kebab-case -> PascalCase`:\n * - `'new-message'` -> `useNewMessageEvent`\n * - `'user'` -> `useUserCondition`\n * - `'showToast'` -> `useShowToastAction`\n *\n * Use it like:\n *\n * export const { useNewMessageEvent, useUserCondition, useShowToastAction } =\n * createNamedHooks(messageTrigger);\n *\n * Implementation detail: the underlying object is a `Proxy` keyed by the hook\n * name. Each lookup synthesizes a hook that delegates to `useEvent` /\n * `useCondition` / `useAction` with the right port name.\n */\nexport function createNamedHooks<S extends TriggerSchema>(trigger: Trigger<S>): NamedHooks<S> {\n // Cache hooks per identifier so React doesn't see a new function reference\n // every render (which would break hook-rules + cause unnecessary churn).\n const cache = new Map<string, unknown>();\n\n return new Proxy({} as NamedHooks<S>, {\n get(_target, prop) {\n if (typeof prop !== 'string') return undefined;\n const cached = cache.get(prop);\n if (cached) return cached;\n\n const parsed = parseHookName(prop);\n if (!parsed) return undefined;\n\n const { kind, portName } = parsed;\n // biome-ignore lint/suspicious/noExplicitAny: bridge layer\n let hook: any;\n if (kind === 'event') {\n hook = () =>\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n useEvent(trigger as Trigger<S>, portName as any);\n } else if (kind === 'condition') {\n hook = (\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n getter: any,\n deps?: readonly unknown[],\n ) =>\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n useCondition(trigger as Trigger<S>, portName as any, getter, deps);\n } else {\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n hook = (handler: any) =>\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n useAction(trigger as Trigger<S>, portName as any, handler);\n }\n cache.set(prop, hook);\n return hook;\n },\n has(_target, prop) {\n return typeof prop === 'string' && parseHookName(prop) !== null;\n },\n });\n}\n\ntype ParsedHook = {\n kind: 'event' | 'condition' | 'action';\n /** Port name back in original camelCase/kebab-case form (best-effort). */\n portName: string;\n};\n\nconst SUFFIXES = {\n event: 'Event',\n condition: 'Condition',\n action: 'Action',\n} as const;\n\nfunction parseHookName(hookName: string): ParsedHook | null {\n if (!hookName.startsWith('use')) return null;\n for (const [kind, suffix] of Object.entries(SUFFIXES) as [\n keyof typeof SUFFIXES,\n (typeof SUFFIXES)[keyof typeof SUFFIXES],\n ][]) {\n if (!hookName.endsWith(suffix)) continue;\n const middle = hookName.slice(3, hookName.length - suffix.length);\n if (middle.length === 0) continue;\n return { kind, portName: pascalToCamel(middle) };\n }\n return null;\n}\n\n/**\n * Convert PascalCase back to camelCase. We don't try to round-trip kebab-case\n * (`'new-message'` -> `'newMessage'`) because keys in `createTrigger` schemas\n * can be either form, and the runtime stores them as the original string.\n *\n * For kebab-case keys, the user can fall back to the universal `useEvent(t, 'kebab-key')`\n * hook — named-hooks support is best-effort for camelCase keys.\n */\nfunction pascalToCamel(s: string): string {\n if (s.length === 0) return s;\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","import type { Runtime } from '@triggery/core';\nimport type { ReactNode } from 'react';\nimport { TriggerRuntimeContext } from './context.ts';\n\nexport type TriggerRuntimeProviderProps = {\n readonly runtime: Runtime;\n readonly children: ReactNode;\n};\n\n/**\n * Provide a custom runtime to all descendants. Without a provider, hooks use the\n * global `defaultRuntime`.\n *\n * @example\n * ```tsx\n * const isolated = createRuntime();\n * <TriggerRuntimeProvider runtime={isolated}>\n * <MyApp />\n * </TriggerRuntimeProvider>\n * ```\n */\nexport function TriggerRuntimeProvider({ runtime, children }: TriggerRuntimeProviderProps) {\n return (\n <TriggerRuntimeContext.Provider value={runtime}>{children}</TriggerRuntimeContext.Provider>\n );\n}\n","import type { ReactNode } from 'react';\nimport { TriggerScopeContext } from './context.ts';\n\nexport type TriggerScopeProps = {\n /**\n * Scope id. Triggers created with `scope: <this id>` in their config will see\n * the conditions/actions registered inside this subtree; triggers without a\n * matching scope will not.\n *\n * Nested scopes replace the outer one (last writer wins) — there is no\n * implicit composition.\n */\n readonly id: string;\n readonly children: ReactNode;\n};\n\n/**\n * Provide a scope id to descendants. Registrations made by `useCondition` /\n * `useAction` inside this subtree are tagged with the scope, and only triggers\n * declared with the same `scope` will receive them.\n *\n * For full isolation (separate inspector / scheduler / middleware), prefer\n * `<TriggerRuntimeProvider>` — `TriggerScope` is a lighter, in-runtime\n * partitioning.\n *\n * @example\n * ```tsx\n * const chatTrigger = createTrigger<...>({\n * id: 'message',\n * scope: 'chat',\n * events: ['new-message'],\n * handler: ({ event, actions }) => actions.showToast?.({ title: event.payload.author }),\n * });\n *\n * // useCondition / useAction inside the scope register with scope='chat'.\n * <TriggerScope id=\"chat\">\n * <UserProvider />\n * <ChatToaster />\n * </TriggerScope>\n * ```\n */\nexport function TriggerScope({ id, children }: TriggerScopeProps) {\n return <TriggerScopeContext.Provider value={id}>{children}</TriggerScopeContext.Provider>;\n}\n","import { createTrigger, type Trigger, type TriggerSchema } from '@triggery/core';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { useRuntime, useScope } from './context.ts';\n\nlet inlineCounter = 0;\n\nexport type UseInlineTriggerConfig<S extends TriggerSchema> = {\n /** Event name to react to. Required. */\n readonly on: keyof NonNullable<S['events']> & string;\n /** Handler body. Receives the same context as a full `createTrigger` handler. */\n readonly do: Parameters<typeof createTrigger<S>>[0]['handler'];\n /** Optional debug id (defaults to a stable auto-generated one). */\n readonly id?: string;\n};\n\n/**\n * Define a trigger inline inside a component — an escape hatch for one-off\n * reactions where pulling them into a separate `*.trigger.ts` file would be\n * overkill. The trigger lives for the lifetime of the component (created on\n * mount, disposed on unmount).\n *\n * Use cases: tiny analytics taps, modal-stack coordination scoped to one screen,\n * keyboard shortcuts that only matter while a panel is open.\n *\n * For anything reusable across the app — prefer `createTrigger` in a dedicated\n * `*.trigger.ts` file.\n *\n * @example\n * ```tsx\n * useInlineTrigger<{ events: { 'cta:click': { id: string } } }>({\n * on: 'cta:click',\n * do: ({ event }) => track('cta', event.payload),\n * });\n * ```\n */\nexport function useInlineTrigger<S extends TriggerSchema>(config: UseInlineTriggerConfig<S>): void {\n const runtime = useRuntime();\n const scope = useScope();\n // Stable id — auto-generated unless the caller pinned one.\n const idRef = useRef<string | undefined>(undefined);\n if (idRef.current === undefined) {\n idRef.current = config.id ?? `inline:${(++inlineCounter).toString(36)}`;\n }\n\n // Keep the latest handler in a ref so the runtime always calls the freshest\n // body (closure capture without re-creating the trigger on every render).\n const handlerRef = useRef(config.do);\n handlerRef.current = config.do;\n\n const stableHandler = useMemo(\n () => ((ctx: Parameters<typeof config.do>[0]) => handlerRef.current(ctx)) as typeof config.do,\n [],\n );\n\n // Capture event-name at first render — runtime needs the index built upfront.\n const eventNameRef = useRef(config.on);\n if (eventNameRef.current !== config.on) {\n // DEV-only sanity: changing `on` between renders is a misuse.\n const env = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env\n ?.NODE_ENV;\n if (env !== 'production') {\n // eslint-disable-next-line no-console -- DEV warn\n console.warn(\n `[triggery] useInlineTrigger(${idRef.current}): \"on\" must be stable between renders ` +\n `(got \"${String(config.on)}\" but was \"${String(eventNameRef.current)}\")`,\n );\n }\n }\n\n useEffect(() => {\n const trigger = createTrigger<S>(\n {\n id: idRef.current as string,\n // biome-ignore lint/suspicious/noExplicitAny: inline trigger has runtime-only schema\n events: [eventNameRef.current] as any,\n handler: stableHandler,\n ...(scope !== '' && { scope }),\n },\n runtime,\n ) as Trigger<S>;\n return () => trigger.dispose();\n }, [runtime, stableHandler, scope]);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/hooks.ts","../src/namedHooks.ts","../src/TriggerRuntimeProvider.tsx","../src/TriggerScope.tsx","../src/useInlineTrigger.ts"],"names":["jsx","useRef","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { getDefaultRuntime, type Runtime } from '@triggery/core';\nimport { createContext, useContext } from 'react';\n\n/**\n * React context used to inject a custom runtime. When no provider is present,\n * hooks fall back to the global default runtime.\n */\nexport const TriggerRuntimeContext = createContext<Runtime | undefined>(undefined);\n\n/** Read the active runtime from context, or return the default runtime. */\nexport function useRuntime(): Runtime {\n const ctxRuntime = useContext(TriggerRuntimeContext);\n return ctxRuntime ?? getDefaultRuntime();\n}\n\n/**\n * Scope context — string id provided by `<TriggerScope id=\"…\">`. Default is\n * `''` (global). Hooks pass it through to `registerCondition`/`registerAction`\n * so the runtime can match the registration against a trigger's `scope`.\n */\nexport const TriggerScopeContext = createContext<string>('');\n\n/** Read the active scope from context. `''` means \"global / no scope\". */\nexport function useScope(): string {\n return useContext(TriggerScopeContext);\n}\n","import type {\n ActionKey,\n ActionMap,\n ConditionKey,\n ConditionMap,\n EventKey,\n EventMap,\n Trigger,\n TriggerInspectSnapshot,\n TriggerSchema,\n} from '@triggery/core';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useRuntime, useScope } from './context.ts';\n\n/**\n * Return an event emitter. Its identity is stable across renders (`useCallback`\n * under the hood). The trigger must list this event in its `events: [...]` schema\n * passed to `createTrigger`.\n *\n * @example\n * ```tsx\n * const fireNewMessage = useEvent(messageTrigger, 'new-message');\n * useEffect(() => socket.on('msg', fireNewMessage), [fireNewMessage]);\n * ```\n */\nexport function useEvent<S extends TriggerSchema, K extends EventKey<S>>(\n _trigger: Trigger<S>,\n eventName: K,\n): EventMap<S>[K] extends void ? () => void : (payload: EventMap<S>[K]) => void {\n const runtime = useRuntime();\n return useCallback(\n ((payload?: unknown) => {\n runtime.fire(eventName, payload);\n }) as EventMap<S>[K] extends void ? () => void : (payload: EventMap<S>[K]) => void,\n [runtime, eventName],\n );\n}\n\n/**\n * Register a condition getter for a trigger. The runtime calls `getter()` at\n * fire-time only — there are no subscriptions and no re-renders.\n *\n * `deps` only invalidate the closure cache (same semantics as `useCallback`).\n *\n * @example\n * ```tsx\n * useCondition(messageTrigger, 'user', () => currentUser, [currentUser]);\n * ```\n *\n * For triggers that declare their conditions inline via `conditions:` config\n * (v0.10+), {@link useSetCondition} is usually preferable: it pushes the value\n * through the trigger's typed setter and pairs cleanly with React state.\n */\nexport function useCondition<S extends TriggerSchema, K extends ConditionKey<S>>(\n trigger: Trigger<S>,\n name: K,\n getter: () => ConditionMap<S>[K],\n deps: readonly unknown[] = [],\n): void {\n const runtime = useRuntime();\n const scope = useScope();\n // Keep the latest getter in a ref — the runtime reads through a stable wrapper.\n const getterRef = useRef(getter);\n getterRef.current = getter;\n // biome-ignore lint/correctness/useExhaustiveDependencies: deps managed by caller\n const stableGetter = useCallback(() => getterRef.current(), deps);\n\n useEffect(() => {\n const token = runtime.registerCondition(trigger.id, name, stableGetter, { scope });\n return () => token.unregister();\n }, [runtime, trigger.id, name, stableGetter, scope]);\n}\n\n/**\n * Push a value into a condition declared inline via `createTrigger({ conditions: { ... } })`\n * (v0.10+). The hook calls `trigger.setCondition(name, value)` on every change\n * and again on mount. Use it when the value lives in a React state / prop and\n * the trigger declared the condition with an explicit initial value.\n *\n * @example\n * ```tsx\n * const [user, setUser] = useState<User | null>(null);\n * useSetCondition(messageTrigger, 'user', user);\n * ```\n */\nexport function useSetCondition<S extends TriggerSchema, K extends ConditionKey<S>>(\n trigger: Trigger<S>,\n name: K,\n value: ConditionMap<S>[K] | null,\n): void {\n useEffect(() => {\n trigger.setCondition(name, value);\n }, [trigger, name, value]);\n}\n\n/**\n * Subscribe to a trigger's action channel. The handler runs every time the\n * trigger body calls `actions.<name>(...)`. Multiple components can subscribe\n * to the same action — every subscriber is invoked on each emit.\n *\n * **v0.10 semantics change**: in v0.9 multiple `useAction` calls for the same\n * `(trigger, name)` followed last-mount-wins (only the most-recently-mounted\n * handler ran). Starting in v0.10 every subscriber is invoked — the more\n * useful default. If you want exclusive-handler behaviour, use\n * `runtime.registerAction(trigger.id, name, fn)` directly.\n *\n * @example\n * ```tsx\n * useAction(messageTrigger, 'showToast', (payload) => toast.success(payload.title));\n * ```\n */\nexport function useAction<S extends TriggerSchema, K extends ActionKey<S>>(\n trigger: Trigger<S>,\n name: K,\n handler: ActionMap<S>[K] extends void\n ? () => void | Promise<void>\n : (payload: ActionMap<S>[K]) => void | Promise<void>,\n): void {\n const runtime = useRuntime();\n const scope = useScope();\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n // Subscribe via the additive `subscribeAction` runtime path so multiple\n // components can react to the same action. Scope is honoured: a scoped\n // trigger only receives subscriptions from the matching scope (or a\n // global trigger from a global scope) — mismatches are no-ops with a\n // DEV warn-once.\n const token = runtime.subscribeAction(\n trigger.id,\n name as string,\n (payload) => (handlerRef.current as (payload: unknown) => void | Promise<void>)(payload),\n { scope },\n );\n return () => token.unregister();\n }, [runtime, trigger.id, name, scope]);\n}\n\n/**\n * Return the latest snapshot of a trigger (for in-app debug panels).\n */\nexport function useInspect<S extends TriggerSchema>(trigger: Trigger<S>) {\n return trigger.inspect();\n}\n\n/**\n * Subscribe to the active runtime's inspector buffer and return the most\n * recent `limit` snapshots (newest first). Re-renders whenever a new run is\n * recorded.\n *\n * Use this for in-app devtools panels, custom run lists, or any \"show me the\n * last N runs\" UI. Combine with `<TriggerSnapshotView>` from\n * `@triggery/devtools-panel` for a turnkey UI.\n *\n * @example\n * ```tsx\n * function DebugPanel() {\n * const history = useInspectHistory(50);\n * return <ul>{history.map((s) => <li key={s.runId}>{s.triggerId}: {s.status}</li>)}</ul>;\n * }\n * ```\n */\nexport function useInspectHistory(limit = 20): readonly TriggerInspectSnapshot[] {\n const runtime = useRuntime();\n const [history, setHistory] = useState<readonly TriggerInspectSnapshot[]>(() =>\n runtime.getInspectorBuffer().slice(0, limit),\n );\n\n useEffect(() => {\n // Re-seed on mount in case fires happened between the initial render and\n // the effect (the runtime may have new entries already).\n setHistory(runtime.getInspectorBuffer().slice(0, limit));\n const token = runtime.subscribe(() => {\n setHistory(runtime.getInspectorBuffer().slice(0, limit));\n });\n return () => token.unregister();\n }, [runtime, limit]);\n\n return history;\n}\n","import type { NamedHooks, Trigger, TriggerSchema } from '@triggery/core';\nimport { useAction, useCondition, useEvent } from './hooks.ts';\n\n/**\n * Build the named-hooks proxy for a trigger.\n *\n * For a schema with `events: { 'new-message' }`, `conditions: { user }` and\n * `actions: { showToast }` this returns:\n *\n * useNewMessageEvent -> () => fire\n * useUserCondition -> (getter, deps?) => void\n * useShowToastAction -> (handler) => void\n *\n * Names are derived from string keys via `kebab-case -> PascalCase`:\n * - `'new-message'` -> `useNewMessageEvent`\n * - `'user'` -> `useUserCondition`\n * - `'showToast'` -> `useShowToastAction`\n *\n * Use it like:\n *\n * export const { useNewMessageEvent, useUserCondition, useShowToastAction } =\n * createNamedHooks(messageTrigger);\n *\n * Implementation detail: the underlying object is a `Proxy` keyed by the hook\n * name. Each lookup synthesizes a hook that delegates to `useEvent` /\n * `useCondition` / `useAction` with the right port name.\n */\nexport function createNamedHooks<S extends TriggerSchema>(trigger: Trigger<S>): NamedHooks<S> {\n // Cache hooks per identifier so React doesn't see a new function reference\n // every render (which would break hook-rules + cause unnecessary churn).\n const cache = new Map<string, unknown>();\n\n return new Proxy({} as NamedHooks<S>, {\n get(_target, prop) {\n if (typeof prop !== 'string') return undefined;\n const cached = cache.get(prop);\n if (cached) return cached;\n\n const parsed = parseHookName(prop);\n if (!parsed) return undefined;\n\n const { kind, portName } = parsed;\n // biome-ignore lint/suspicious/noExplicitAny: bridge layer\n let hook: any;\n if (kind === 'event') {\n hook = () =>\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n useEvent(trigger as Trigger<S>, portName as any);\n } else if (kind === 'condition') {\n hook = (\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n getter: any,\n deps?: readonly unknown[],\n ) =>\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n useCondition(trigger as Trigger<S>, portName as any, getter, deps);\n } else {\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n hook = (handler: any) =>\n // biome-ignore lint/suspicious/noExplicitAny: passthrough\n useAction(trigger as Trigger<S>, portName as any, handler);\n }\n cache.set(prop, hook);\n return hook;\n },\n has(_target, prop) {\n return typeof prop === 'string' && parseHookName(prop) !== null;\n },\n });\n}\n\ntype ParsedHook = {\n kind: 'event' | 'condition' | 'action';\n /** Port name back in original camelCase/kebab-case form (best-effort). */\n portName: string;\n};\n\nconst SUFFIXES = {\n event: 'Event',\n condition: 'Condition',\n action: 'Action',\n} as const;\n\nfunction parseHookName(hookName: string): ParsedHook | null {\n if (!hookName.startsWith('use')) return null;\n for (const [kind, suffix] of Object.entries(SUFFIXES) as [\n keyof typeof SUFFIXES,\n (typeof SUFFIXES)[keyof typeof SUFFIXES],\n ][]) {\n if (!hookName.endsWith(suffix)) continue;\n const middle = hookName.slice(3, hookName.length - suffix.length);\n if (middle.length === 0) continue;\n return { kind, portName: pascalToCamel(middle) };\n }\n return null;\n}\n\n/**\n * Convert PascalCase back to camelCase. We don't try to round-trip kebab-case\n * (`'new-message'` -> `'newMessage'`) because keys in `createTrigger` schemas\n * can be either form, and the runtime stores them as the original string.\n *\n * For kebab-case keys, the user can fall back to the universal `useEvent(t, 'kebab-key')`\n * hook — named-hooks support is best-effort for camelCase keys.\n */\nfunction pascalToCamel(s: string): string {\n if (s.length === 0) return s;\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","import type { Runtime } from '@triggery/core';\nimport type { ReactNode } from 'react';\nimport { TriggerRuntimeContext } from './context.ts';\n\nexport type TriggerRuntimeProviderProps = {\n readonly runtime: Runtime;\n readonly children: ReactNode;\n};\n\n/**\n * Provide a custom runtime to all descendants. Without a provider, hooks use the\n * global `defaultRuntime`.\n *\n * @example\n * ```tsx\n * const isolated = createRuntime();\n * <TriggerRuntimeProvider runtime={isolated}>\n * <MyApp />\n * </TriggerRuntimeProvider>\n * ```\n */\nexport function TriggerRuntimeProvider({ runtime, children }: TriggerRuntimeProviderProps) {\n return (\n <TriggerRuntimeContext.Provider value={runtime}>{children}</TriggerRuntimeContext.Provider>\n );\n}\n","import type { ReactNode } from 'react';\nimport { TriggerScopeContext } from './context.ts';\n\nexport type TriggerScopeProps = {\n /**\n * Scope id. Triggers created with `scope: <this id>` in their config will see\n * the conditions/actions registered inside this subtree; triggers without a\n * matching scope will not.\n *\n * Nested scopes replace the outer one (last writer wins) — there is no\n * implicit composition.\n */\n readonly id: string;\n readonly children: ReactNode;\n};\n\n/**\n * Provide a scope id to descendants. Registrations made by `useCondition` /\n * `useAction` inside this subtree are tagged with the scope, and only triggers\n * declared with the same `scope` will receive them.\n *\n * For full isolation (separate inspector / scheduler / middleware), prefer\n * `<TriggerRuntimeProvider>` — `TriggerScope` is a lighter, in-runtime\n * partitioning.\n *\n * @example\n * ```tsx\n * const chatTrigger = createTrigger<...>({\n * id: 'message',\n * scope: 'chat',\n * events: ['new-message'],\n * handler: ({ event, actions }) => actions.showToast?.({ title: event.payload.author }),\n * });\n *\n * // useCondition / useAction inside the scope register with scope='chat'.\n * <TriggerScope id=\"chat\">\n * <UserProvider />\n * <ChatToaster />\n * </TriggerScope>\n * ```\n */\nexport function TriggerScope({ id, children }: TriggerScopeProps) {\n return <TriggerScopeContext.Provider value={id}>{children}</TriggerScopeContext.Provider>;\n}\n","import { createTrigger, type Trigger, type TriggerSchema } from '@triggery/core';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { useRuntime, useScope } from './context.ts';\n\nlet inlineCounter = 0;\n\nexport type UseInlineTriggerConfig<S extends TriggerSchema> = {\n /** Event name to react to. Required. */\n readonly on: keyof NonNullable<S['events']> & string;\n /** Handler body. Receives the same context as a full `createTrigger` handler. */\n readonly do: Parameters<typeof createTrigger<S>>[0]['handler'];\n /** Optional debug id (defaults to a stable auto-generated one). */\n readonly id?: string;\n};\n\n/**\n * Define a trigger inline inside a component — an escape hatch for one-off\n * reactions where pulling them into a separate `*.trigger.ts` file would be\n * overkill. The trigger lives for the lifetime of the component (created on\n * mount, disposed on unmount).\n *\n * Use cases: tiny analytics taps, modal-stack coordination scoped to one screen,\n * keyboard shortcuts that only matter while a panel is open.\n *\n * For anything reusable across the app — prefer `createTrigger` in a dedicated\n * `*.trigger.ts` file.\n *\n * @example\n * ```tsx\n * useInlineTrigger<{ events: { 'cta:click': { id: string } } }>({\n * on: 'cta:click',\n * do: ({ event }) => track('cta', event.payload),\n * });\n * ```\n */\n/**\n * Shorter alias for {@link useInlineTrigger} introduced in v0.10. Pick whichever\n * name you prefer — both share the same implementation.\n */\nexport function useTrigger<S extends TriggerSchema>(config: UseInlineTriggerConfig<S>): void {\n useInlineTrigger<S>(config);\n}\n\nexport function useInlineTrigger<S extends TriggerSchema>(config: UseInlineTriggerConfig<S>): void {\n const runtime = useRuntime();\n const scope = useScope();\n // Stable id — auto-generated unless the caller pinned one.\n const idRef = useRef<string | undefined>(undefined);\n if (idRef.current === undefined) {\n idRef.current = config.id ?? `inline:${(++inlineCounter).toString(36)}`;\n }\n\n // Keep the latest handler in a ref so the runtime always calls the freshest\n // body (closure capture without re-creating the trigger on every render).\n const handlerRef = useRef(config.do);\n handlerRef.current = config.do;\n\n const stableHandler = useMemo(\n () => ((ctx: Parameters<typeof config.do>[0]) => handlerRef.current(ctx)) as typeof config.do,\n [],\n );\n\n // Capture event-name at first render — runtime needs the index built upfront.\n const eventNameRef = useRef(config.on);\n if (eventNameRef.current !== config.on) {\n // DEV-only sanity: changing `on` between renders is a misuse.\n const env = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env\n ?.NODE_ENV;\n if (env !== 'production') {\n // eslint-disable-next-line no-console -- DEV warn\n console.warn(\n `[triggery] useInlineTrigger(${idRef.current}): \"on\" must be stable between renders ` +\n `(got \"${String(config.on)}\" but was \"${String(eventNameRef.current)}\")`,\n );\n }\n }\n\n useEffect(() => {\n const trigger = createTrigger<S>(\n {\n id: idRef.current as string,\n // biome-ignore lint/suspicious/noExplicitAny: inline trigger has runtime-only schema\n events: [eventNameRef.current] as any,\n handler: stableHandler,\n ...(scope !== '' && { scope }),\n },\n runtime,\n ) as Trigger<S>;\n return () => trigger.dispose();\n }, [runtime, stableHandler, scope]);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triggery/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "React 18+/19 bindings for Triggery — useEvent / useCondition / useAction / useInlineTrigger / useInspect hooks + <TriggerRuntimeProvider> / <TriggerScope>. Zero runtime dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Aleksey Skhomenko",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"react": ">=18.0.0",
|
|
57
|
-
"@triggery/core": "0.
|
|
57
|
+
"@triggery/core": "0.10.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@testing-library/react": "^16.3.2",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"tsup": "^8.5.1",
|
|
66
66
|
"typescript": "^6.0.3",
|
|
67
67
|
"vitest": "^4.1.6",
|
|
68
|
-
"@triggery/core": "0.
|
|
68
|
+
"@triggery/core": "0.10.0"
|
|
69
69
|
},
|
|
70
70
|
"llms": "https://triggeryjs.github.io/llms.txt",
|
|
71
71
|
"llmsFull": "https://triggeryjs.github.io/llms-full.txt",
|