@reactively/lit
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -0,16 +1,36 @@ | ||
import { Reactive, ReactivelyParams } from "@reactively/core"; | ||
import { HasReactiveInternal } from "@reactively/decorate"; | ||
import { LitElement, PropertyDeclaration } from "lit"; | ||
export declare class ReactiveLitElement extends LitElement { | ||
/** An extension to LitElement to support fine grained reactivity. | ||
* | ||
* Users should implement reactiveRender() instead of render(), so that ReactiveLitElement | ||
* can internally track reactive sources used while rendering. | ||
* | ||
* Users should use these decorations: | ||
* `@reactively` - reactive property that updates lazily if its @reactively sources change | ||
* `@reactiveProperty` - reactively property that's also a lit web component property | ||
*/ | ||
export declare abstract class ReactiveLitElement extends LitElement implements HasReactiveInternal { | ||
/** reactively (only) props */ | ||
__reactive?: Record<string, Reactive<unknown>>; | ||
/** lit+reactively combo props */ | ||
_comboProps: string[] | undefined; | ||
/** We have two modes for getPropertyDescriptor, one for building regular lit properties, and | ||
* one for building reactive lit properties. */ | ||
static _buildingReactiveProperty: boolean; | ||
constructor(); | ||
/** We have two modes for getPropertyDescriptor, one for building regular lit properties, and | ||
* one for building reactive properties. | ||
/** subclasses should implement this, returning the contents that will be render()d. | ||
* Typically, returna | ||
*/ | ||
static _buildingReactiveProperty: boolean; | ||
_reactiveProps: string[] | undefined; | ||
protected reactiveRender(): unknown; | ||
private get template(); | ||
render(): unknown; | ||
/** log if the user has implmented render() instead of reactiveRender() */ | ||
private validateRender; | ||
/** Produce a lit property descriptor, and also a reactive node for the property | ||
* if the property is tagged '@reactive' | ||
*/ | ||
* if the property is tagged '@reactiveProperty' */ | ||
static getPropertyDescriptor(name: PropertyKey, key: string | symbol, options: PropertyDeclaration<unknown, unknown>): PropertyDescriptor | undefined; | ||
} | ||
/** Mark a mutable property that can be tracked for changes. */ | ||
export declare function reactiveProperty(prototype: ReactiveLitElement, name: string): any; | ||
export declare function reactiveProperty(): (prototype: ReactiveLitElement, name: string) => any; | ||
/** Mark a lit+reactively property that is tracked for dependency changes | ||
* and triggers a component update when set */ | ||
export declare function reactiveProperty(options?: PropertyDeclaration & ReactivelyParams): ((prototype: LitElement, name: string, descriptor?: PropertyDescriptor) => void) | any; |
124
dist/lit.js
"use strict"; | ||
import { LitElement } from "lit"; | ||
import { installReactiveProperty, reactivesToInit } from "@reactively/decorate"; | ||
import { Reactive } from "@reactively/core"; | ||
export class ReactiveLitElement extends LitElement { | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __decorateClass = (decorators, target, key, kind) => { | ||
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; | ||
for (var i = decorators.length - 1, decorator; i >= 0; i--) | ||
if (decorator = decorators[i]) | ||
result = (kind ? decorator(target, key, result) : decorator(result)) || result; | ||
if (kind && result) | ||
__defProp(target, key, result); | ||
return result; | ||
}; | ||
import { | ||
createReactives, | ||
queueReactiveToInstall, | ||
reactively | ||
} from "@reactively/decorate"; | ||
import { LitElement, noChange } from "lit"; | ||
const _ReactiveLitElement = class extends LitElement { | ||
__reactive; | ||
_comboProps; | ||
static _buildingReactiveProperty = false; | ||
constructor() { | ||
super(); | ||
reactiveInit(this); | ||
createReactives(this); | ||
this.validateRender(); | ||
} | ||
static _buildingReactiveProperty = false; | ||
_reactiveProps; | ||
reactiveRender() { | ||
return noChange; | ||
} | ||
get template() { | ||
this.requestUpdate(); | ||
return this.reactiveRender(); | ||
} | ||
render() { | ||
return this.template; | ||
} | ||
validateRender() { | ||
const renderProto = hasRender(this); | ||
if (renderProto?.constructor?.name !== _ReactiveLitElement.name) { | ||
console.error( | ||
"ReactiveLitElement subclasses should not implement render(). \nImplement reactiveRender() instead.\n", | ||
"class:", | ||
this.constructor.name, | ||
"\n", | ||
"instance:", | ||
this | ||
); | ||
} | ||
function hasRender(self) { | ||
if (self === void 0) { | ||
return void 0; | ||
} | ||
if (Object.getOwnPropertyNames(self).includes("render")) { | ||
return self; | ||
} | ||
return hasRender(Object.getPrototypeOf(self)); | ||
} | ||
} | ||
static getPropertyDescriptor(name, key, options) { | ||
const litDescriptor = super.getPropertyDescriptor(name, key, options); | ||
if (!this._buildingReactiveProperty) { | ||
console.log("unmodified lit property", { name, key }); | ||
return litDescriptor; | ||
} | ||
console.log("reactive lit property", { name, key }); | ||
const reactiveNode = new Reactive(null); | ||
if (!litDescriptor) { | ||
return void 0; | ||
} else { | ||
const setter = litDescriptor.set; | ||
return { | ||
get() { | ||
reactiveNode.get(); | ||
return litDescriptor.get?.call(this); | ||
get: function() { | ||
return this.__reactive[name].get(); | ||
}, | ||
set(value) { | ||
reactiveNode.set(value); | ||
setter?.call(this, value); | ||
set: function(value) { | ||
const reactive = this.__reactive[name]; | ||
const oldValue = reactive.get(); | ||
reactive.set(value); | ||
this.requestUpdate(name, oldValue, options); | ||
}, | ||
@@ -38,30 +80,28 @@ configurable: true, | ||
} | ||
}; | ||
export let ReactiveLitElement = _ReactiveLitElement; | ||
__decorateClass([ | ||
reactively({ effect: true }) | ||
], ReactiveLitElement.prototype, "template", 1); | ||
export function reactiveProperty(options) { | ||
return function reactiveComboProp(proto, key, descriptor) { | ||
queueReactiveToInstall(proto, key, descriptor, options); | ||
installComboAccessor(proto, key, descriptor, options); | ||
return {}; | ||
}; | ||
} | ||
export function reactiveProperty(prototype, name) { | ||
if (prototype) | ||
return buildReactivePropMap(prototype, name); | ||
else | ||
return buildReactivePropMap; | ||
} | ||
function buildReactivePropMap(prototype, name) { | ||
console.log("buildReactivePropMap", prototype, { name }); | ||
if (name) { | ||
if (!prototype._reactiveProps) { | ||
prototype._reactiveProps = []; | ||
} | ||
prototype._reactiveProps.push(name); | ||
function installComboAccessor(proto, key, descriptor, options) { | ||
if (descriptor?.get) { | ||
installGetAccessor(proto, key); | ||
} | ||
} | ||
function reactiveInit(instance) { | ||
const reactiveProto = Object.getPrototypeOf(instance); | ||
ReactiveLitElement._buildingReactiveProperty = true; | ||
reactiveProto._reactiveProps?.forEach((name) => { | ||
ReactiveLitElement.createProperty(name); | ||
}); | ||
proto.constructor.createProperty(key, options); | ||
ReactiveLitElement._buildingReactiveProperty = false; | ||
reactivesToInit.get(reactiveProto)?.forEach((key) => { | ||
if (key === "doubleName") { | ||
installReactiveProperty(instance, key); | ||
} | ||
function installGetAccessor(proto, key) { | ||
Object.defineProperty(proto, key, { | ||
get: function reactiveGet() { | ||
return this.__reactive[key].get(); | ||
} | ||
}); | ||
} |
{ | ||
"name": "@reactively/lit", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "", | ||
@@ -19,7 +19,7 @@ "main": "./dist/lit.js", | ||
"devDependencies": { | ||
"lit": "^2.3.1" | ||
"lit": "^2.5.0" | ||
}, | ||
"dependencies": { | ||
"@reactively/core": "0.0.6", | ||
"@reactively/decorate": "0.0.2" | ||
"@reactively/core": "0.0.8", | ||
"@reactively/decorate": "0.0.3" | ||
}, | ||
@@ -26,0 +26,0 @@ "scripts": { |
@@ -11,8 +11,14 @@ # Reactively | ||
Here is an [example](https://github.com/modderme123/reactively/blob/main/packages/cypress-test/component-test/ReactiveLitTest1.tsx) using Lit and @reactively together. | ||
Here is an [example](https://github.com/modderme123/reactively/blob/main/packages/cypress-test/component-test/ReactiveLit.cy.ts) | ||
using Lit and @reactively together. | ||
1. Inherit from `ReactiveLitElement` in place of `LitElement` | ||
2. Choose how to annotate your properties: | ||
- `@reactiveProperty` properties are visible to lit and @reatively. | ||
- `@reactive` properties are visible to @reactively only. | ||
- `@property` properties are visible to lit only. | ||
1. Implement `reactiveRender()` instead of `render()`. | ||
(This enables `@reactively/lit` to track the reactive sources used while rendering, | ||
and to trigger re-rendering when necessary.) | ||
1. Choose how to annotate your reactive properties: | ||
- `@reactiveProperty` properties are reactive and visible as lit web component properties. | ||
- `@reactively` properties are reactive but not web component properties. | ||
1. Call `stabilizeContinously()` once when you start your application, | ||
so that all `ReactiveLitElement` instances will re-render() automatically. | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6854
142
24
1
+ Added@reactively/core@0.0.8(transitive)
+ Added@reactively/decorate@0.0.3(transitive)
- Removed@reactively/core@0.0.6(transitive)
- Removed@reactively/decorate@0.0.2(transitive)
Updated@reactively/core@0.0.8
Updated@reactively/decorate@0.0.3