### Ovee.js Starter Project Setup Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Set up a new Ovee.js project using npx and degit, then install dependencies and run the development server. ```shell npx degit owlsdepartment/ovee-starter my-project cd my-project # install dependencies yarn # and run it! yarn dev # or serve ``` -------------------------------- ### Initialize and Run Ovee.js App Source: https://context7.com/owlsdepartment/ovee/llms.txt Demonstrates how to instantiate the App, register components and modules, configure options, and start the application. Includes examples of imperative registration and accessing modules via the event bus. ```javascript import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import NavMenu from './components/NavMenu'; import Slider from './components/Slider'; import AnalyticsModule from './modules/AnalyticsModule'; // Register via constructor (recommended) const app = new App({ config: { namespace: 'myapp', // CSS class prefix and event namespace productionTip: false // suppress dev tip in non-production builds }, components: [ NavMenu, // no options [Slider, { loop: true, speed: 400 }] // with per-component options ], modules: [ [OveeBarba, { transitions: [], preventRunning: true }] ] }); // Or register imperatively after creation app.registerComponent(NavMenu); app.registerComponent(Slider, { loop: true }); app.registerComponents([NavMenu, Slider]); app.use(AnalyticsModule, { trackingId: 'UA-XXXXX' }); // Boot the app — starts MutationObserver and harvests existing DOM components const root = document.getElementById('app'); app.run(root); // Access a module by class (preferred, fully typed) or by name string const analytics = app.getModule(AnalyticsModule); const analytics2 = app.getModule('AnalyticsModule'); // App-level event bus app.$on('user:login', (e) => console.log('user logged in', e.detail)); app.$emit('user:login', { userId: 42 }); app.$off('user:login', handler); // Retrieve current config (returns a copy, not the live object) const config = app.getConfig(); // { namespace: 'myapp', productionTip: false, global: window, document: document } // Tear down the entire app (destroys all components and modules) app.destroy(); ``` -------------------------------- ### Install Ovee.js Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Install Ovee.js using yarn or npm. Lit-html is a required peer dependency. ```shell yarn add ovee.js # or npm install --save ovee.js ``` ```shell yarn add lit-html # or npm install --save lit-html ``` -------------------------------- ### Barba.js Plugin Integration Source: https://github.com/owlsdepartment/ovee/blob/master/docs/addons.md Example of how to install and use the Barba.js plugin with Ovee.js, including basic configuration and hooks. ```APIDOC ## Barba.js Plugin Integration ### Description Integrates Barba.js for page transitions within an Ovee.js application. ### Installation ```shell yarn add @ovee.js/barba # or npm install --save @ovee.js/barba ``` ### Getting Started ```js import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import { defaultTransition } from 'transitions'; const root = document.body; const app = new App(); app.use(OveeBarba, { transitions: [ defaultTransition ], timeout: 20000, preventRunning: true, hooks: { after() { if (global.dataLayer !== undefined) { try { global.dataLayer.push({ event: 'content-view', 'content-name': global.location.pathname }); // eslint-disable-next-line no-empty } catch {} } } } }); app.run(root); ``` ### Available Options | Option | Default Value | Description | |:------ |:------------- |:----------- | | `plugins` | `[]` | add Barba plugins from [Plugins](https://barba.js.org/docs/plugins/). More in section [Plugins](#plugins) | | `hooks` | `{}` | you can pass methods to hook into Barba's lifecycle globally. More in section [Hooks](#hooks) | ### Methods | Method | Description | |:------ |:----------- | | `$go(href: string, trigger?: Trigger, e?: LinkEvent | PopStateEvent)` | Tell Barba to go to a specific URL | | `$prefetch(href: string)` | Prefetch the given URL | ### Hooks You can add globall hooks callbacks in module options under `hooks` option. Every hook also emits global event on `$app` instance. Available hooks and theire events are: - `before` | event: `barba:before` - `beforeLeave` | event: `barba:before-leave` - `leave` | event: `barba:leave` - `afterLeave` | event: `barba:after-leave` - `beforeEnter` | event: `barba:before-enter` - `enter` | event: `barba:enter` - `afterEnter` | event: `barba:after-enter` - `after` | event: `barba:after` ### Plugins To add Barba plugins, you need to install it in you project and pass to `plugins` option. Example: ```js import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import barbaPrefetch from '@barba/prefetch'; import barbaRouter from '@barba/router'; const root = document.body; const app = new App(); app.use(OveeBarba, { plugins: [ barbaPrefetch, [barbaRouter, { routes: [ /* barba routes here */ ] }] ], }); app.run(root); ``` ### Defining Custom Transitions To define your transitions, just pass transition definitions to `transitions` array of the module config. We don't do anything with them by any meaning, so you shall just follow the [official docs](https://barba.js.org/docs/advanced/transitions/) to get more details. ``` -------------------------------- ### Install Barba.js Plugin Source: https://github.com/owlsdepartment/ovee/blob/master/docs/addons.md Install the Barba.js plugin for Ovee.js using yarn or npm. ```shell yarn add @ovee.js/barba # or npm install --save @ovee.js/barba ``` -------------------------------- ### Initialize Ovee.js with Barba.js Plugin Source: https://github.com/owlsdepartment/ovee/blob/master/docs/addons.md Initialize your Ovee.js app and use the Barba.js plugin with custom transitions and hooks. Ensure Barba.js is installed separately if needed. ```javascript import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import { defaultTransition } from 'transitions'; const root = document.body; const app = new App(); app.use(OveeBarba, { transitions: [ defaultTransition ], timeout: 20000, preventRunning: true, hooks: { after() { if (global.dataLayer !== undefined) { try { global.dataLayer.push({ event: 'content-view', 'content-name': global.location.pathname }); // eslint-disable-next-line no-empty } catch {} } } } }); app.run(root); ``` -------------------------------- ### Configuring Ovee App Initialization Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Configure the App object by passing a `config` object to the constructor options or using the `setConfig` method. Configuration is merged with defaults. This example sets the namespace and disables production tips. ```javascript const app = new App({ options: { namespace: 'ymce', productionTip: false } }); ``` -------------------------------- ### Reactive Array Example Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Demonstrates how assigning a new array to a `ref` triggers reactivity. Useful for updating UI based on array changes. ```javascript const arr = ref([1, 2, 3]) arr.value = [1, 2, 3] // <- this will trigger a change! ``` -------------------------------- ### Integrate Barba.js Plugins with Ovee.js Source: https://github.com/owlsdepartment/ovee/blob/master/docs/addons.md Configure the Barba.js plugin within Ovee.js to include additional Barba.js plugins like prefetch and router. Ensure these plugins are installed in your project. ```javascript import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import barbaPrefetch from '@barba/prefetch'; import barbaRouter from '@barba/router'; const root = document.body; const app = new App(); app.use(OveeBarba, { plugins: [ barbaPrefetch, [barbaRouter, { routes: [ /* barba routes here */ ] }] ], }); app.run(root); ``` -------------------------------- ### Use Reactive Store with Dynamic Parameters Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md This example demonstrates how to use a computed property that accepts parameters (`getPostsByUserId`) within a `TemplateComponent`. It utilizes decorators like `@reactive()` and `@dataParam()` for component state management. ```javascript import { postsStore } from '@/store' export class PostsList extends TemplateComponent { @reactive() @dataParam() id; template(html) { return html` `; } } ``` -------------------------------- ### Registering Modules with Options in Ovee Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Pass an options object when registering a module to make it available within the module instance. This example shows how to pass transitions to OveeBarba and register a DetectBrowsers component with specific options. ```javascript const app = new App({ modules: [ [OveeBarba, { transitions: [ defaultTransition ] }] ] }); app.registerComponent(DetectBrowsers, { addClassesToHtml: true }); ``` -------------------------------- ### Use Reactive Store in a Template Component Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Import the reactive store and access its computed properties directly within a `TemplateComponent` to render dynamic data. This example shows how to display read posts. ```javascript import { postsStore } from '@/store' export class PostsList extends TemplateComponent { template(html) { return html` `; } } ``` -------------------------------- ### Ovee.js Counter Component Implementation Source: https://context7.com/owlsdepartment/ovee/llms.txt Implements a counter component with reactive properties, DOM element binding, and lifecycle hooks. Use `init()` for setup and `beforeDestroy()`/`destroy()` for cleanup. Event listeners are automatically managed. ```typescript import { Component, register, reactive, el, bind, watch } from 'ovee.js'; export interface CounterOptions { step: number; } @register('counter') export class Counter extends Component { // Reactive property — changes trigger watchers @reactive() count = 0; // Bound child element (auto-updates when DOM changes) @el('.counter__btn') button: HTMLButtonElement; // Lifecycle: called after decorators are initialized init() { console.log('Counter mounted on', this.$element); console.log('Options:', this.$options); // { step: 1 } (from defaultOptions + registered options) console.log('Refs:', this.$refs.value); // [

] — elements with ref="value" } // Lifecycle: called just before teardown beforeDestroy() { console.log('Counter about to be destroyed'); } // Lifecycle: called after teardown destroy() { console.log('Counter destroyed'); } // Event binding via decorator — auto-unbound on destroy @bind('click', { target: '.counter__btn' }) increment() { this.count += this.$options.step; } // Watcher — called whenever `count` changes @watch('count', { immediate: true }) onCountChange(newVal: number, oldVal: number) { if (this.$refs.value[0]) { this.$refs.value[0].textContent = `Count: ${newVal}`; } } // Manual event API (same as @bind, returns removal function) bindScrollListener() { const remove = this.$on('scroll', this.onScroll, { target: window, passive: true }); this.$on('click', () => remove(), { target: '.stop-scroll', root: true }); } onScroll(e: Event) { /* ... */ } // Emit a custom event up the DOM notifyParent() { this.$emit('counter:changed', { count: this.count }); } static defaultOptions(): CounterOptions { return { step: 1 }; } } ``` -------------------------------- ### App Initialization and Configuration Source: https://context7.com/owlsdepartment/ovee/llms.txt Demonstrates how to instantiate the App class, configure its settings, and register components and modules. It also shows how to imperatively register components and use modules. ```APIDOC ## App Initialization and Configuration ### Description Instantiate the `App` class, configure its settings, and register components and modules. Components can be registered with or without options, and modules can be registered with their own configurations. ### Usage ```js import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import NavMenu from './components/NavMenu'; import Slider from './components/Slider'; import AnalyticsModule from './modules/AnalyticsModule'; // Register via constructor (recommended) const app = new App({ config: { namespace: 'myapp', // CSS class prefix and event namespace productionTip: false // suppress dev tip in non-production builds }, components: [ NavMenu, // no options [Slider, { loop: true, speed: 400 }] // with per-component options ], modules: [ [OveeBarba, { transitions: [], preventRunning: true }] ] }); // Or register imperatively after creation app.registerComponent(NavMenu); app.registerComponent(Slider, { loop: true }); app.registerComponents([NavMenu, Slider]); app.use(AnalyticsModule, { trackingId: 'UA-XXXXX' }); ``` ``` -------------------------------- ### App Bootstrapping and Lifecycle Source: https://context7.com/owlsdepartment/ovee/llms.txt Shows how to run the application, access modules, use the app-level event bus, retrieve configuration, and tear down the application. ```APIDOC ## App Bootstrapping and Lifecycle ### Description Bootstraps the Ovee.js application, allowing it to scan the DOM for components. It also covers accessing registered modules, emitting and listening to application-level events, retrieving configuration, and destroying the application instance. ### Usage ```js // Boot the app — starts MutationObserver and harvests existing DOM components const root = document.getElementById('app'); app.run(root); // Access a module by class (preferred, fully typed) or by name string const analytics = app.getModule(AnalyticsModule); const analytics2 = app.getModule('AnalyticsModule'); // App-level event bus app.$on('user:login', (e) => console.log('user logged in', e.detail)); app.$emit('user:login', { userId: 42 }); app.$off('user:login', handler); // Retrieve current config (returns a copy, not the live object) const config = app.getConfig(); // { namespace: 'myapp', productionTip: false, global: window, document: document } // Tear down the entire app (destroys all components and modules) app.destroy(); ``` ``` -------------------------------- ### Registering Components with Global Options Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md Demonstrates how to provide default global options to components during App initialization or dynamic registration. These options are accessible via `this.$options` within the component. ```js // passing options via App constructor const app = new App({ components: [ [MyComponent, { option1: 'a', option2: true }] ] }) // or via dynamic registration app.registerComponent(MyComponent, { option1: 'a', option2: true }) ``` -------------------------------- ### Initialize Ovee.js App Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Initialize a new Ovee.js application by creating an App instance and running it on a root element. ```html

``` ```javascript import { App } from 'ovee.js'; const root = document.getElementById('app'); const app = new App(); app.run(root); ``` -------------------------------- ### Lazy and Cached Computed Properties with @computed Source: https://github.com/owlsdepartment/ovee/blob/master/docs/component-decorators.md Utilize the @computed decorator on a 'get' accessor to create reactive properties that cache their results. They re-evaluate only when their reactive dependencies change, similar to Vue's computed properties. ```js import { ref } from 'ovee.js' // we can use external reactive variable const counter = ref(0) @register('my-component') class MyComponent extends Component { multiplier = 2 @computed() get multipliedCounter() { return counter.value * this.multiplier; } init() { // counter: 0, multiplier: 2 console.log(this.multipliedCounter) // 0 counter.value += 1; // counter: 1, multiplier: 2 console.log(this.multipliedCounter) // 2 this.multiplier = 4; // we changed multiplier value, but computed is not reevaluated, // because multiplier is not reactive // counter: 1, multiplier: 4 console.log(this.multipliedCounter) // 2 counter.value += 1 // counter: 2, multiplier: 4 console.log(this.multipliedCounter) // 8 } } ``` -------------------------------- ### Register Components and Modules with App Constructor Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Register components and modules when creating a new App instance using an options object. ```javascript import { App } from 'ovee'; import OveeBarba from '@ovee.js/barba'; import TodoList from './components/TodoList'; import TodoListItem from './components/TodoListItem'; const app = new App({ components: [ TodoList, TodoListItem ], modules: [ OveeBarba ] }); ``` -------------------------------- ### Register Components and Modules with App Methods Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Register components and modules using `registerComponent`, `registerComponents`, and `use` methods on an App instance. ```javascript import { App } from 'ovee.js'; import OveeBarba from '@ovee.js/barba'; import TodoList from './components/TodoList'; import TodoListItem from './components/TodoListItem'; const app = new App(); app.registerComponent(TodoList); app.registerComponent(TodoListItem); // OR app.registerComponents([ TodoList, TodoListItem ]); app.use(OveeBarba); ``` -------------------------------- ### Defining Default Component Options Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md Shows how to define default options for a component using the `static defaultOptions()` method. These defaults are merged with options provided during registration. ```js @register('my-component') export class MyComponent extends Component { static defaultOptions() { return { myOption: 'custom option' } } init() { // 'myOption' will be 'custom option' by default, if not changed during registration console.log(this.$options.myOption) } } ``` -------------------------------- ### Register Module with app.use() Source: https://github.com/owlsdepartment/ovee/blob/master/docs/modules.md Register a module instance with the app.use() method, optionally providing configuration options. This is an alternative to registering modules via the App constructor. ```javascript app.use(ThirdModule, { // options }); ``` -------------------------------- ### Initialize Dialogs with Reactive Array Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Initializes the DialogSystem with a reactive array to store dialogs using `ref`. Requires `ovee.js` import. ```javascript import { ref } from 'ovee.js'; let instance; export class DialogSystem { constructor() { const root = document.createElement('div'); root.classList.add('dialog-root') document.body.appendChild(document) // store dialogs this.dialogs = ref([]) } /* ... */ } ``` -------------------------------- ### Register Modules with App Constructor Source: https://github.com/owlsdepartment/ovee/blob/master/docs/modules.md Register modules when creating a new App instance by passing an array to the 'modules' configuration. Modules can be passed directly or as an array with their configuration options. ```javascript const app = new App({ modules: [ FirstModule, [SecondModule, { // options }] ] }); ``` -------------------------------- ### Ovee.js Reactivity API Usage Source: https://context7.com/owlsdepartment/ovee/llms.txt Demonstrates the use of ref, makeReactive, makeComputed, markRaw, and doWatchEffect for managing reactive state and side effects. Use these primitives for shared state, store patterns, or utility classes outside of components. ```javascript import { ref, makeReactive, makeComputed, doWatchEffect, markRaw, toRefs, isRef } from 'ovee.js'; // --- ref: single reactive value --- const count = ref(0); count.value++; console.log(count.value); // 1 // --- makeReactive: reactive plain object --- const store = makeReactive({ users: [], loading: false, }); store.users.push({ id: 1, name: 'Alice' }); // --- makeComputed: lazy cached computation --- const activeUsers = makeComputed(() => store.users.filter(u => u.active)); console.log(activeUsers.value); // evaluated lazily // --- markRaw: prevent deep reactivity wrapping --- const socket = markRaw(new WebSocket('wss://example.com')); store.socket = socket; // won't be made reactive // --- doWatchEffect: auto-tracking effect --- const stop = doWatchEffect(() => { document.title = `Users online: ${activeUsers.value.length}`; // Automatically re-runs when activeUsers changes }); // Call stop() to cancel the effect stop(); // --- Shared state store pattern --- export const postsStore = makeReactive({ posts: [] as Post[], selectedId: null as number | null, selected: makeComputed(() => { return postsStore.posts.find(p => p.id === postsStore.selectedId) ?? null; }), }); export const postsMutations = { async fetchAll() { const res = await fetch('/api/posts'); postsStore.posts = await res.json(); }, select(id: number) { postsStore.selectedId = id; }, }; // Use in any TemplateComponent — template re-renders on store change import { TemplateComponent, register } from 'ovee.js'; @register('posts-list') class PostsList extends TemplateComponent { template() { return this.html` `; } } ``` -------------------------------- ### Declare a Custom Ovee Module Source: https://github.com/owlsdepartment/ovee/blob/master/docs/modules.md Extend the base Module class to create a custom module. Implement the init() method for initialization logic and dummyMethod() for custom functionality. The static getName() method is crucial for accessing the module instance later. ```javascript import { Module } from 'ovee.js'; import DummyLibrary from 'dummy-library'; export default class extends Module { init() { this.dummyLibrary = new DummyLibrary(this.options); } dummyMethod() { return this.dummyLibrary.someDummyCall(); } destroy() { this.dummyLibrary.destroy(); } static getName(): string { return 'DummyModule'; } } ``` -------------------------------- ### Create Dialog with markRaw Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Adds a method to create and store dialog instances using `markRaw` to prevent Ovee.js from making them reactive. Requires `ovee.js` import. ```javascript import { ref, markRaw } from 'ovee.js'; export class DialogSystem { /* ... */ // some options for dialog createDialog(options, open = false) { const dialog = new Dialog(options); this.dialogs.push(markRaw(dialog)); // <- markRaw?! if (open) { dialog.open(); } return dialog; } /* ... */ } ``` -------------------------------- ### Singleton Dialog System Class Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Implements a singleton pattern for managing dialog instances globally. Ensures only one instance of DialogSystem exists. ```javascript let instance; export class DialogSystem { constructor() { this.root = document.createElement('div'); this.root.classList.add('dialog-root') document.body.appendChild(this.root) } static getInstance() { if (!instance) { instance = new DialogSystem(); } return instance; } } ``` -------------------------------- ### Reactive Objects API Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/api.md Utilities for creating and managing reactive objects, similar to Vue 3's basic reactivity API. ```APIDOC ## Reactive Objects API - `makeReactive` - Used to create reactive objects. Alias for Vue 3: [reactive](https://v3.vuejs.org/api/basic-reactivity.html#reactive) - `makeComputed` - Used to create computed function with lazy evaluation, that reevaluates only when reactive dependencies change. Alias for Vue 3: [computed](https://v3.vuejs.org/api/computed-watch-api.html#computed) - `readonly` - Create readonly proxy object. Vue 3 docs: [readonly](https://v3.vuejs.org/api/basic-reactivity.html#readonly) - `isProxy` - Check if object is Proxy created by `makeReactive` or `readonly`. Vue 3 docs: [isProxy](https://v3.vuejs.org/api/basic-reactivity.html#isproxy) - `isReactive` - Check if object was created by `makeReactive`. Vue 3 docs: [isReactive](https://v3.vuejs.org/api/basic-reactivity.html#isreactive) - `isReadonly` - Check if object was ceated by `readonly`. Vue 3 docs: [isReadonly](https://v3.vuejs.org/api/basic-reactivity.html#isreadonly) - `toRaw` - Returns target object of `makeReactive` proxy. Vue 3 docs: [toRaw](https://v3.vuejs.org/api/basic-reactivity.html#toraw) - `markRaw` - Prevent object from converting to reactive one. Vue 3 docs: [markRaw](https://v3.vuejs.org/api/basic-reactivity.html#markraw) - `shallowReactive` - Creates a reactive proxy that tracks reactivity of its own properties but does not perform deep reactive conversion of nested objects (exposes raw values). Vue 3 docs: [shallowReactive](https://v3.vuejs.org/api/basic-reactivity.html#shallowreactive) - `shallowReadonly` - Creates a proxy that makes its own properties readonly, but does not perform deep readonly conversion of nested objects (exposes raw values). Vue 3 docs: [shallowReactive](https://v3.vuejs.org/api/basic-reactivity.html#shallowreadonly) ``` -------------------------------- ### TypeScript Options Support for Components Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md Illustrates how to add TypeScript typings to component options using a generic type parameter for enhanced type safety. ```ts export interface MyComponentOptions { myOption: string; } @register('my-component') export class MyComponent extends Component { static defaultOptions() { return { // it is now fully typed myOption: 'custom option' } } init() { // here as well! console.log(this.$options.myOption) } } ``` -------------------------------- ### Ref API Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/api.md Utilities for working with refs, which are reactive mutable objects holding a single value. ```APIDOC ## Ref API - `ref` - Creates reactive mutable object with field `.value` for single value. Vue 3 docs: [ref](https://v3.vuejs.org/api/refs-api.html#ref) - `unref` - Return inner value if argument is `ref`, else return argument untouched. Vue 3 docs: [unref](https://v3.vuejs.org/api/refs-api.html#unref) - `toRef` - Create `ref` from a `reactive` objects single property, retaining it's reactivity. Vue 3 docs: [toRef](https://v3.vuejs.org/api/refs-api.html#toref) - `toRefs` - Same as `toRef`, but for a whole object, where each field is a `ref`. Vue 3 docs: [toRefs](https://v3.vuejs.org/api/refs-api.html#torefs) - `isRef` - Check if value is `ref` object. Vue 3 docs: [isRef](https://v3.vuejs.org/api/refs-api.html#torefs) - `customRef` - Creates a customized ref with explicit control over its dependency tracking and updates triggering. Vue 3 docs: [customRef](https://v3.vuejs.org/api/refs-api.html#customref) - `shallowRef` - Creates a `ref` that tracks its own `.value` mutation but doesn't make its value reactive. Vue 3 docs: [shallowRef](https://v3.vuejs.org/api/refs-api.html#shallowref) - `triggerRef` - Execute any effects tied to a `shallowRef` manually. Vue 3 docs: [triggerRef](https://v3.vuejs.org/api/refs-api.html#triggerref) ``` -------------------------------- ### @register Source: https://github.com/owlsdepartment/ovee/blob/master/docs/component-decorators.md Adds a static method `getName()` to a component, which is required for registration. The name must be a two-word string in PascalCase, camelCase, or kebab-case. ```APIDOC ## @register Adds static method `getName()` that returns name of a component. This method is required for a component to be registered. ### Parameters - `name: string` - name of component. Must be a two word name, either in `PascalCase`, `camelCase` or `kebab-case` ### Example ```js @register('my-component') class MyComponent extends Component {} ``` ``` -------------------------------- ### Listen to Events with $on Method Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md Utilize the $on method within the init() lifecycle hook to attach event listeners. This method provides similar targeting and options as the @bind decorator. ```javascript @register('base-example') export default class extends Component { // some code init() { this.$on('click', this.onButtonClick, { target: '.counter__button' }); this.$on('focus blur', this.onFocusChange); this.$on('scroll', this.onScroll, { target: window }) this.$on('mouseover', this.onCounterValueHover. { target: '.counter__value', multiple: true }) } onButtonClick() { // handle click } onFocusChange() { // handle focus } onScroll() { // handle scroll } onCounterValueHover(e) { // handle mouse hover on all value displays } } ``` -------------------------------- ### Dialog Class with Reactive State Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Defines a simple `Dialog` class with a reactive `isOpen` state managed by `ref`. Essential for tracking dialog visibility. ```javascript export class Dialog { constructor(options) { isOpen = ref(false) // once again ref, but with boolean value this time // ... do something with options } open() { this.isOpen.value = true; } close() { this.isOpen.value = false; } } ``` -------------------------------- ### Enable lit-html 1.x Backwards Compatibility Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md To maintain behavior consistent with `ovee` versions 2.1.x and lower when using `lit-html`, set the `__clearRenderTarget` property to `true` in your component. ```javascript import { TemplateComponent, register } from 'ovee.js'; @register('counter') export class CounterComponent extends TemplateComponent { __clearRenderTarget = true template() { return this.html`
` } } ``` -------------------------------- ### Opt-In Property Reactivity with @reactive Source: https://context7.com/owlsdepartment/ovee/llms.txt Make component properties reactive using the @reactive decorator. Only decorated properties can be watched with @watch or tracked by @watchEffect and TemplateComponent.template(). Changes to these properties trigger reactivity. ```typescript import { Component, register, reactive } from 'ovee.js'; @register('form-field') class FormField extends Component { @reactive() value = ''; @reactive() isValid = true; @reactive() errors: string[] = []; @reactive() config = { required: true, maxLength: 100 }; validate() { this.errors = []; if (this.config.required && !this.value) { this.errors = ['Field is required']; this.isValid = false; } else if (this.value.length > this.config.maxLength) { this.errors = [`Max ${this.config.maxLength} characters`]; this.isValid = false; } else { this.isValid = true; } // Setting this.errors or this.isValid triggers any @watch or @watchEffect } } ``` -------------------------------- ### Pass Options to Components During Registration Source: https://github.com/owlsdepartment/ovee/blob/master/docs/guide.md Pass options objects to components when registering them, either via the constructor or using `registerComponent`. ```javascript const app = new App({ components: [ ContactForm, [Slider, { loop: true, speed: 500 }] ] }); app.registerComponent(NavToggle, { toggleClassName: 'menu__is-visible' }); ``` -------------------------------- ### Create a Reactive Store with Computed Properties Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Use `makeReactive` to create a reactive object for global state. `makeComputed` can be used to derive state based on the reactive object's properties. Access computed values directly without `.value`. ```javascript export const postsStore = makeReactive({ posts: [], lastFetched: null, getPostsByUserId: makeComputed(() => id => { return this.posts.filter(post => post.user_id === id); }), readPosts: makeComputed(() => { return this.posts.filter(post => post.status === 'read'); }) }) ``` -------------------------------- ### App-Scoped Singleton Module Registration Source: https://context7.com/owlsdepartment/ovee/llms.txt Register and initialize a singleton module that is accessible app-wide. Use for third-party libraries, global state, or shared functionality. Ensure the module's init method is called before components are initialized and its destroy method is called on app destruction. ```typescript import { Module } from 'ovee.js'; export interface RouterOptions { base: string; history: boolean; } export class RouterModule extends Module { private router: any; // your router instance init() { // Called by app.run() before any components are initialized this.router = createRouter({ base: this.options.base ?? '/', history: this.options.history ?? true, }); this.router.on('navigate', (url: string) => { this.$app.$emit('router:navigate', { url }); }); this.router.start(); } navigate(path: string) { this.router.go(path); } destroy() { // Called by app.destroy() this.router.stop(); } static getName(): string { return 'RouterModule'; } } // Registration const app = new App({ modules: [[RouterModule, { base: '/app', history: true }]] }); app.run(document.body); // Access from any component import { Component, register, module } from 'ovee.js'; @register('nav-link') class NavLink extends Component { @module(RouterModule) router: RouterModule; @bind('click') navigate() { this.router.navigate('/about'); } } ``` -------------------------------- ### HTML for TodoList Component with Data Attribute Source: https://context7.com/owlsdepartment/ovee/llms.txt This HTML shows how to use the TodoList component and synchronize its 'filter' property using the 'data-filter' attribute. The attribute value will automatically update the component's filter state. ```html ``` -------------------------------- ### Basic Component Structure and Registration Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md Defines a simple counter component with reactive state, element binding, event binding, and a watcher. Use the @register decorator to associate the class with a custom HTML tag. ```html

``` ```js import { Component, bind, el, reactive, register, watch } from 'ovee.js'; @register('counter') export default class extends Component { @reactive() counter = 0; @el('.counter__value') valueElement; @bind('click', { target: '.counter__button' }) increment() { this.counter++; } @watch('counter', { immediate: true }) update() { if (this.valueElement) { this.valueElement.innerHTML = `Current value: ${this.counter}`; } } } ``` -------------------------------- ### Create Template Component with Reactive Properties Source: https://github.com/owlsdepartment/ovee/blob/master/docs/components.md Build UI components using TemplateComponent. Reactive properties used within the template method automatically update the DOM. Use @bind for event handling and @register to define the component's tag. ```javascript import { TemplateComponent, bind, reactive, register } from 'ovee.js'; @register('counter') export default class extends TemplateComponent { @reactive() counter = 0; @bind('click', '.counter__button') increment() { this.counter++; } template() { return this.html`

Current value: ${this.counter}

` } } ``` -------------------------------- ### Render Open Dialogs with Computed and Watcher Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/overview.md Uses `makeComputed` to filter open dialogs and `watchEffect` to re-render the dialogs when their state changes. Requires `ovee.js`. ```javascript export class DialogSystem { /* ... */ constructor() { /* ... */ this.openDialogs = makeComputed(() => { return this.dialogs.filter(d => d.isOpen) }) watchEffect(() => { this.root.innerHTML = this.openDialogs.value.reduce((acc, dialog) => { return acc + dialog.render(); }, '') }) } /* ... */ } ``` -------------------------------- ### @reactive Source: https://github.com/owlsdepartment/ovee/blob/master/docs/component-decorators.md Makes a class property reactive by utilizing the `makeReactive` function. This allows for automatic updates and state management. ```APIDOC ## @reactive Makes property reactive by using [`makeReactive`](/reactivity#makeReactive). ### Example ```js @register('my-component') class MyComponent extends Component { @reactive() counter; } ``` ``` -------------------------------- ### Register Component with @register Source: https://github.com/owlsdepartment/ovee/blob/master/docs/component-decorators.md Use the @register decorator to add a static getName() method to a component, which is required for registration. The name must be a two-word string in PascalCase, camelCase, or kebab-case. ```javascript @register('my-component') class MyComponent extends Component {} ``` -------------------------------- ### Ovee.js TodoList TemplateComponent Implementation Source: https://context7.com/owlsdepartment/ovee/llms.txt Implements a todo list component using TemplateComponent for reactive DOM rendering with lit-html. Reactive properties automatically trigger re-renders. Use `dataParam` to sync attributes. ```typescript import { TemplateComponent, register, reactive, bind, dataParam } from 'ovee.js'; @register('todo-list') export class TodoList extends TemplateComponent { @reactive() items: string[] = []; @reactive() @dataParam('filter') // reads from data-filter attribute, auto-syncs filter = 'all'; @bind('click', { target: '.add-btn' }) addItem() { this.items = [...this.items, `Item ${this.items.length + 1}`]; } // Override to provide reactive HTML — re-runs automatically on reactive changes template() { const visible = this.filter === 'all' ? this.items : this.items.slice(0, 3); return this.html`
    ${visible.map(item => this.html`
  • ${item}
  • `)}

Showing ${visible.length} of ${this.items.length}

`; } async init() { // Wait for first render before accessing rendered elements await this.$requestUpdate(); console.log('First render complete'); console.log(this.$element.querySelector('.todo-list')); //
    element } } ``` -------------------------------- ### Module Instance Injection with @module Source: https://context7.com/owlsdepartment/ovee/llms.txt Injects a registered module instance into a component property, retrieving it from the application's module registry. Preferred injection method is by class for type safety. ```js import { Component, register, module, bind } from 'ovee.js'; import { RouterModule } from '../modules/RouterModule'; import { AuthModule } from '../modules/AuthModule'; @register('user-nav') class UserNav extends Component { // Inject by class — type-safe, refactor-friendly @module(RouterModule) router: RouterModule; // Inject by name string — less recommended @module('AuthModule') auth: AuthModule; // With TypeScript's emitDecoratorMetadata: true, class argument can be omitted // @module() // auth: AuthModule; @bind('click', { target: '.nav__logout' }) async logout() { await this.auth.logout(); this.router.navigate('/login'); } @bind('click', { target: '.nav__profile' }) goToProfile() { this.router.navigate('/profile'); } } ``` -------------------------------- ### Auto-tracking effects with @watchEffect Source: https://context7.com/owlsdepartment/ovee/llms.txt Use @watchEffect to run a method immediately and re-run it automatically when any accessed reactive value changes. Ovee tracks dependencies during the first execution, so no explicit source declaration is needed. ```typescript import { Component, TemplateComponent, register, reactive, watchEffect } from 'ovee.js'; @register('live-search') class LiveSearch extends Component { @reactive() query = ''; @reactive() results: string[] = []; isLoading = false; // Runs immediately; re-runs any time `this.query` changes @watchEffect() async performSearch() { if (!this.query) { this.results = []; return; } this.isLoading = true; try { const res = await fetch(`/api/search?q=${this.query}`); this.results = await res.json(); } catch (e) { this.results = []; } finally { this.isLoading = false; } } @bind('input', { target: 'input' }) onInput(e: InputEvent) { this.query = (e.target as HTMLInputElement).value; } } ``` -------------------------------- ### doWatch Source: https://github.com/owlsdepartment/ovee/blob/master/docs/reactivity/api.md Watches for changes in specified reactive sources. This function is an alias for Vue 3's `watch` API. ```APIDOC ## doWatch ### Description Watches for changes in specified reactive sources. This function is an alias for Vue 3's `watch` API. ### Method N/A (SDK function) ### Endpoint N/A (SDK function) ### Parameters * **source** (ReactiveSource | ReadonlyArray> | object) - Required - The source to watch. Can be a ref, reactive object, getter function, or an array of these. * **callback** (Function) - Required - The callback function to execute when the source changes. * **options** (object) - Optional - Configuration options for the watcher. * `immediate` (boolean) - If true, the callback is invoked immediately on initial setup. * `deep` (boolean) - If true, performs a deep watch on the source. * `flush` ('pre' | 'post' | 'sync') - Specifies when the watcher should be flushed. ### Request Example ```javascript import { ref } from 'ovee'; import { doWatch } from 'ovee/reactivity'; const count = ref(0); doWatch(count, (newValue, oldValue) => { console.log(`Count changed from ${oldValue} to ${newValue}`); }, { immediate: true }); ``` ### Response #### Success Response N/A (This function does not return a value, but triggers side effects via the callback.) #### Response Example N/A ``` -------------------------------- ### Watching Reactive Properties with @watch Source: https://github.com/owlsdepartment/ovee/blob/master/docs/component-decorators.md Use @watch to execute a method when a reactive property changes. It can watch specific paths like 'counter' or nested properties like 'data.name'. The optional `immediate` option allows for an initial execution. ```js @register('my-component') class MyComponent extends Component { @reactive() counter = 0 @reactive() data = { name: 'test name' } @watch('counter') onCounterChange(newVal, oldVal, path) { // do something on change } @watch('data.name', { immediate: true }) onNameChange() { // do something on change } } ``` -------------------------------- ### Override App class with custom properties and methods Source: https://github.com/owlsdepartment/ovee/blob/master/docs/typescript.md Extend the `App` class to make custom properties and methods available throughout your application components. This ensures type safety for your additions. ```typescript declare module 'ovee.js' { interface App { myCustomProp: string; myCustomAppMethod(name: string): void; // ... } } ```