@xaendar/core 0.4.1 → 0.4.2
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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xaendar-core.es.js","names":[],"sources":["../../../../packages/core/src/decorators/event.decorator.ts","../../../../packages/core/src/costants.ts","../../../../packages/core/src/signals/input/input-set.symbol.ts","../../../../packages/core/src/signals/input/input.model.ts","../../../../packages/core/src/decorators/property.decorator.ts","../../../../packages/core/src/decorators/web-component/web-component.decorator.ts","../../../../packages/core/src/directives/base-web-component.ts"],"sourcesContent":["import { AccessorDecorator, ClassAccessorDecoratorValue } from '@xaendar/types';\r\nimport { BaseWebComponent } from '../directives/base-web-component';\r\nimport { EventOptions } from '../types/event/event-options.type';\r\nimport { Output } from '../types/event/output.type';\r\n\r\nfunction isEventOptions(value: EventOptions | unknown): value is EventOptions {\r\n return !!value && typeof value === 'object' && ('bubbles' in value || 'cancelable' in value || 'composed' in value);\r\n}\r\n\r\nexport function Event<\r\n Class extends BaseWebComponent,\r\n Data = void,\r\n>(options?: EventOptions): AccessorDecorator<Class, Output<Data>> {\r\n return (_value: ClassAccessorDecoratorValue<Output<Data>>, context: ClassAccessorDecoratorContext<Class, Output<Data>>): ReturnType<AccessorDecorator<Class, Output<Data>>> => {\r\n const name = context.name;\r\n let dispatchEvent: EventTarget['dispatchEvent'];\r\n\r\n context.addInitializer(function (this: Class) {\r\n dispatchEvent = this.dispatchEvent.bind(this);\r\n });\r\n\r\n if (typeof name === 'symbol') {\r\n throw new Error('Symbol properties are not supported as event names');\r\n }\r\n\r\n const output: Output<Data> = {\r\n emit: (_valueOrOverrideOptions?: Data | EventOptions, _overrideOptions?: EventOptions) => { }\r\n };\r\n\r\n return {\r\n get(): Output<Data> {\r\n output.emit = function (this: Class, valueOrOverrideOptions?: Data | EventOptions, overrideOptions?: EventOptions) {\r\n let eventOptions: CustomEventInit<Data> = {};\r\n\r\n eventOptions = isEventOptions(valueOrOverrideOptions)\r\n ? { ...options, ...valueOrOverrideOptions }\r\n : { ...options, ...overrideOptions, detail: valueOrOverrideOptions }\r\n\r\n const event = new CustomEvent(name, eventOptions);\r\n dispatchEvent(event);\r\n };\r\n return output;\r\n }\r\n }\r\n }\r\n}\r\n","export const INTERNAL_OBSERVED_ATTRIBUTES = `observedAttributes`;","/**\r\n * This symbol is used to call the set method of the InputSignal\r\n * Normally the set method is permitted internally and should not be called\r\n * by the User\r\n */\r\nexport const INPUT_SIGNAL_SET_SYMBOL = Symbol(`InputSignalSet`);\r\n\r\n/**\r\n * Asserts that the provided symbol matches the internal {@link INPUT_SIGNAL_SET_SYMBOL} symbol,\r\n * ensuring the caller has access to internal APIs.\r\n *\r\n * Throws if the symbol does not match, preventing external code from\r\n * invoking methods intended for internal use only.\r\n *\r\n * @param symbol - The symbol to validate against {@link INPUT_SIGNAL_SET_SYMBOL}.\r\n * @throws {Error} If `symbol` does not match {@link INPUT_SIGNAL_SET_SYMBOL}.\r\n * @internal\r\n */\r\nexport function assertPrivateContext(symbol: symbol): void {\r\n if (symbol !== INPUT_SIGNAL_SET_SYMBOL) {\r\n throw new Error('Invalid symbol for InputSignal set method');\r\n }\r\n}","import { SignalOptions } from '@xaendar/signals';\r\nimport { assertPrivateContext } from './input-set.symbol';\r\n\r\n/**\r\n * An `InputSignal` is a specialized `Signal.State` designed for use as a property signal in web components. \r\n * It extends the base `State` signal with additional functionality to handle incoming values, such as those from HTML attributes or external sources, \r\n * and allows for optional transformation of these values before they are stored in the signal.\r\n */\r\nexport class InputSignal<ActualValue = unknown, IncomingValue = ActualValue> extends Signal.State<ActualValue>{\r\n /**\r\n * Optional transform function to convert incoming values to the actual type stored in the signal.\r\n */\r\n private _transform?: (value: IncomingValue) => ActualValue;\r\n\r\n /**\r\n * Creates a new `InputSignal` instance.\r\n *\r\n * @param initialValue - The initial value of the signal.\r\n * @param options - Optional configuration:\r\n * - `equals` — custom equality function; defaults to `Object.is`.\r\n * - `watched` — called when the signal gains its first sink.\r\n * - `unwatched` — called when the signal loses its last sink.\r\n * - `transform` — function to transform incoming values before setting the signal's value.\r\n */\r\n constructor(value?: ActualValue, options?: SignalOptions<ActualValue> & { transform?: (value: IncomingValue) => ActualValue }) {\r\n const transform = options?.transform;\r\n /* \r\n Ensure transform field is not passed to super constructor\r\n since it's not part of SignalOptions and would cause an error\r\n */\r\n delete options?.transform;\r\n\r\n super(value as ActualValue, options);\r\n this._transform = transform;\r\n }\r\n\r\n /**\r\n * Set a new value to the signal, applying the transform function if provided.\r\n * @param newValue - The new value to set.\r\n * @throws If `frozen` is `true` — writes are forbidden while a protected\r\n * callback is executing.\r\n */\r\n // @ts-expect-error\r\n public override set(newValue: IncomingValue, symbol: symbol): void {\r\n assertPrivateContext(symbol);\r\n const transformedValue = this._transform ? this._transform(newValue) : newValue;\r\n super.set(transformedValue as ActualValue);\r\n }\r\n}\r\n","import { AccessorDecorator, ClassAccessorDecoratorValue } from '@xaendar/types';\r\nimport { INTERNAL_OBSERVED_ATTRIBUTES } from '../costants';\r\nimport { BaseWebComponent } from '../directives/base-web-component';\r\nimport { InputSignal } from '../signals/input/input.model';\r\nimport { PropertyDecoratorOptions, PropertyDecoratorOptionsWithRequired, } from '../types/property-decorator-options.type';\r\n\r\nconst propertyDecoratorOptionsWithRequiredBrand = Symbol('PropertyDecoratorOptionsWithRequiredBrand');\r\ntype PropertyDecoratoprOptionsWithRequiredBrandType<ActualValue = unknown, IncomingValue = ActualValue> = PropertyDecoratorOptionsWithRequired<ActualValue, IncomingValue> & { \r\n [propertyDecoratorOptionsWithRequiredBrand]: 'PropertyDecoratorOptionsWithRequired' \r\n};\r\n\r\nfunction createPropertyDecorator<\r\n Class extends BaseWebComponent,\r\n Value extends InputSignal<ActualValue, IncomingValue>,\r\n ActualValue = unknown,\r\n IncomingValue = ActualValue\r\n>(value?: ActualValue | PropertyDecoratoprOptionsWithRequiredBrandType<ActualValue, IncomingValue>, options?: PropertyDecoratorOptions<ActualValue, IncomingValue>): AccessorDecorator<Class, Value> {\r\n return function (\r\n _target: ClassAccessorDecoratorValue<Value>,\r\n context: ClassAccessorDecoratorContext<Class, Value>\r\n ): ReturnType<AccessorDecorator<Class, Value>> {\r\n const propertyKey = context.name;\r\n\r\n if (typeof propertyKey === 'symbol') {\r\n throw new Error('Symbol properties are not supported');\r\n }\r\n\r\n const metadata = context.metadata as { [INTERNAL_OBSERVED_ATTRIBUTES]?: string[] };\r\n metadata[INTERNAL_OBSERVED_ATTRIBUTES] ??= [];\r\n metadata[INTERNAL_OBSERVED_ATTRIBUTES].push(propertyKey);\r\n\r\n let actualValue: ActualValue | undefined;\r\n let actualOptions: PropertyDecoratorOptions<ActualValue, IncomingValue> | undefined | PropertyDecoratoprOptionsWithRequiredBrandType<ActualValue, IncomingValue> | undefined;\r\n if (!value || typeof value !== 'object' || !(propertyDecoratorOptionsWithRequiredBrand in value)) {\r\n actualValue = value;\r\n actualOptions = options;\r\n } else {\r\n actualOptions = value;\r\n }\r\n\r\n const signal = new InputSignal<ActualValue, IncomingValue>(actualValue, {\r\n equals: actualOptions?.equals,\r\n watched: actualOptions?.watched,\r\n unwatched: actualOptions?.unwatched,\r\n transform: actualOptions?.transform\r\n });\r\n\r\n return {\r\n get() {\r\n return signal as Value;\r\n },\r\n init(_?: InputSignal<ActualValue, IncomingValue>) {\r\n return signal as Value;\r\n },\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Decoratore per proprietà opzionale.\r\n *\r\n * @example\r\n * @Property()\r\n * accessor label: InputSignal<string>;\r\n *\r\n * @Property({ value: 0 })\r\n * accessor count: InputSignal<number>;\r\n *\r\n * @Property({ value: { required: true, foo: 'bar' }, alias: 'cfg' })\r\n * accessor config: InputSignal<Config>;\r\n */\r\nexport function Property<\r\n Class extends BaseWebComponent,\r\n Value extends InputSignal<ActualValue, IncomingValue>,\r\n ActualValue = Value extends InputSignal<infer U, any> ? U : unknown,\r\n IncomingValue = Value extends InputSignal<any, infer V> ? V : ActualValue\r\n>(\r\n value?: ActualValue,\r\n options?: PropertyDecoratorOptions<ActualValue, IncomingValue>\r\n): AccessorDecorator<Class, InputSignal<ActualValue, IncomingValue>> {\r\n return createPropertyDecorator<Class, InputSignal<ActualValue, IncomingValue>, ActualValue, IncomingValue>(value, options);\r\n}\r\n\r\n/**\r\n * Decoratore per proprietà obbligatoria.\r\n * Il consumer deve fornire il valore; non accetta un valore di default.\r\n *\r\n * @example\r\n * @Property.required()\r\n * accessor userId: InputSignal<string>;\r\n *\r\n * @Property.required({ alias: 'user-id' })\r\n * accessor userId: InputSignal<string>;\r\n */\r\nProperty.required = function required<\r\n Class extends BaseWebComponent,\r\n ActualValue = unknown,\r\n IncomingValue = ActualValue\r\n>(\r\n options?: Omit<PropertyDecoratorOptionsWithRequired<ActualValue, IncomingValue>, 'required'>\r\n): AccessorDecorator<Class, InputSignal<ActualValue, IncomingValue>> {\r\n return createPropertyDecorator<Class, InputSignal<ActualValue, IncomingValue>, ActualValue, IncomingValue>({\r\n ...options,\r\n [propertyDecoratorOptionsWithRequiredBrand]: 'PropertyDecoratorOptionsWithRequired',\r\n required: true,\r\n });\r\n};","import { ClassDecorator, Constructor } from '@xaendar/types';\r\nimport { INTERNAL_OBSERVED_ATTRIBUTES } from '../../costants';\r\nimport { BaseWebComponent } from '../../directives/base-web-component';\r\nimport { WebComponentDecoratorParams } from '../../types/web-component/web-component-decorator-params.type';\r\n\r\n/**\r\n * Decorator to define a web component\r\n * @param selector Name or names of the custom element\r\n */\r\nexport function WebComponent<T extends BaseWebComponent>(options: WebComponentDecoratorParams): ClassDecorator<T> {\r\n return function (klass: Constructor<T>, context: ClassDecoratorContext<Constructor<T>>): void {\r\n defineObservedAttributes(klass, context);\r\n setSelectors(klass, options.selector);\r\n };\r\n}\r\n\r\n/**\r\n * Function to define the observedAttributes static property on the class.\r\n * We define static get observedAttributes programmatically\r\n * to abstract the manual definition from the user.\r\n *\r\n * We could not define the property in the base class due to the fact\r\n * that is static and each derived class would override the value of the others\r\n * @param klass The class to set the observedAttributes on\r\n * @param attributes The attributes to observe\r\n */\r\nfunction defineObservedAttributes<T extends BaseWebComponent>(klass: Constructor<T>, context: ClassDecoratorContext<Constructor<T>>): void {\r\n Object.defineProperty(klass, 'observedAttributes', {\r\n get: () => context.metadata![INTERNAL_OBSERVED_ATTRIBUTES],\r\n configurable: false,\r\n enumerable: false\r\n });\r\n}\r\n\r\n/**\r\n * Function to add the custom element definition to the browser using the passed selectors.\r\n * @param klass The class to define as a web component\r\n * @param selectors The selector or selectors to reference the web component in HTML\r\n */\r\nfunction setSelectors<T extends BaseWebComponent>(klass: Constructor<T>, selectors: string | string[]): void {\r\n Array.isArray(selectors)\r\n ? selectors.forEach(selector => customElements.define(selector, klass))\r\n : customElements.define(selectors, klass);\r\n}","import { INPUT_SIGNAL_SET_SYMBOL } from \"../signals/input/input-set.symbol\";\r\nimport { InputSignal } from \"../signals/input/input.model\";\r\n\r\n/**\r\n * Base class for all Web Components in the framework\r\n * \r\n * This class internally has an `observedAttributes` property\r\n * add programmaticaly by the @WebComponent decorator. \r\n * It won't appear by intellisense but it's there.\r\n */\r\nexport class BaseWebComponent extends HTMLElement {\r\n /**\r\n * The root of the Web Component, where the content is rendered\r\n */\r\n private readonly _root: ShadowRoot;\r\n\r\n constructor() {\r\n super();\r\n this._root = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n /**\r\n * Method called by the @Property decorator to\r\n * update the rendering of the component\r\n * @internal \r\n */\r\n private _render(): void { }\r\n\r\n /**\r\n * Method automatically called by the JavascriptEngine when an attribute\r\n * on the host element is changed\r\n * \r\n * This method runs before the connectedCallback method if any observed attribute\r\n * is specified on the CustomElement tag in the HTML\r\n * \r\n * @param name Name of the attribute changed\r\n * @param _oldValue Old value of the attribute\r\n * @param newValue New value of the attribute\r\n */\r\n private attributeChangedCallback(name: string, _oldValue: unknown, newValue: unknown): void {\r\n /*\r\n Since the 'Property Decorator add the property key to the ObservedAttributes\r\n We are sure that the property with the given name exists on the instance of the subclass\r\n */\r\n const context = this as BaseWebComponent & Record<string, unknown>;\r\n if (!(name in context)) {\r\n throw new Error(`Attribute ${name} is not associated to any property`);\r\n }\r\n\r\n\r\n /*\r\n @Property decorator types ensure that the property associated to the attribute is an InputSignal\r\n but i prefer to check it at runtime anyway to avoid any possible error in the future \r\n if the decorator is used wrong or if the types are not respected for some reason \r\n */\r\n if (!(context[name] instanceof InputSignal)) {\r\n throw new Error(`Property ${name} is not an InputSignal`);\r\n }\r\n\r\n context[name].set(newValue, INPUT_SIGNAL_SET_SYMBOL);\r\n }\r\n\r\n /**\r\n * Method automatically called by the JavascriptEngine when a CustomElement\r\n * is added to the DOM\r\n * \r\n * This method is called EVERY time the element is added\r\n */\r\n private connectedCallback(): void {\r\n this._render();\r\n }\r\n\r\n /**\r\n * Method automatically called by the JavascriptEngine when a CustomElement\r\n * is removed from the DOM\r\n * \r\n * This method is called EVERY time the element is removed\r\n * \r\n * We use this method to reset the _initialized flag\r\n * so that if the element is re-added to the DOM\r\n * the properties initialization won't call the render method\r\n */\r\n private disconnectedCallback(): void {\r\n }\r\n}"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "A library containing core utils such as webcomponent base classes and theming support",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "./xaendar-core.es.js",
|
|
8
|
-
"module": "./xaendar-core.es.js",
|
|
9
|
-
"types": "./xaendar-core.es.d.ts",
|
|
7
|
+
"main": "./dist/xaendar-core.es.js",
|
|
8
|
+
"module": "./dist/xaendar-core.es.js",
|
|
9
|
+
"types": "./dist/xaendar-core.es.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
12
|
"import": {
|
|
13
|
-
"types": "./xaendar-core.es.d.ts",
|
|
14
|
-
"default": "./xaendar-core.es.js"
|
|
13
|
+
"types": "./dist/xaendar-core.es.d.ts",
|
|
14
|
+
"default": "./dist/xaendar-core.es.js"
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@xaendar/signals": "0.4.
|
|
20
|
-
"@xaendar/types": "0.4.
|
|
19
|
+
"@xaendar/signals": "0.4.2",
|
|
20
|
+
"@xaendar/types": "0.4.2"
|
|
21
21
|
}
|
|
22
22
|
}
|
package/xaendar-core.es.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"xaendar-core.es.js","names":[],"sources":["src/decorators/event.decorator.ts","src/costants.ts","src/signals/input/input-set.symbol.ts","src/signals/input/input.model.ts","src/decorators/property.decorator.ts","src/decorators/web-component/web-component.decorator.ts","src/directives/base-web-component.ts"],"sourcesContent":["import { AccessorDecorator, ClassAccessorDecoratorValue } from '@xaendar/types';\r\nimport { BaseWebComponent } from '../directives/base-web-component';\r\nimport { EventOptions } from '../types/event/event-options.type';\r\nimport { Output } from '../types/event/output.type';\r\n\r\nfunction isEventOptions(value: EventOptions | unknown): value is EventOptions {\r\n return !!value && typeof value === 'object' && ('bubbles' in value || 'cancelable' in value || 'composed' in value);\r\n}\r\n\r\nexport function Event<\r\n Class extends BaseWebComponent,\r\n Data = void,\r\n>(options?: EventOptions): AccessorDecorator<Class, Output<Data>> {\r\n return (_value: ClassAccessorDecoratorValue<Output<Data>>, context: ClassAccessorDecoratorContext<Class, Output<Data>>): ReturnType<AccessorDecorator<Class, Output<Data>>> => {\r\n const name = context.name;\r\n let dispatchEvent: EventTarget['dispatchEvent'];\r\n\r\n context.addInitializer(function (this: Class) {\r\n dispatchEvent = this.dispatchEvent.bind(this);\r\n });\r\n\r\n if (typeof name === 'symbol') {\r\n throw new Error('Symbol properties are not supported as event names');\r\n }\r\n\r\n const output: Output<Data> = {\r\n emit: (_valueOrOverrideOptions?: Data | EventOptions, _overrideOptions?: EventOptions) => { }\r\n };\r\n\r\n return {\r\n get(): Output<Data> {\r\n output.emit = function (this: Class, valueOrOverrideOptions?: Data | EventOptions, overrideOptions?: EventOptions) {\r\n let eventOptions: CustomEventInit<Data> = {};\r\n\r\n eventOptions = isEventOptions(valueOrOverrideOptions)\r\n ? { ...options, ...valueOrOverrideOptions }\r\n : { ...options, ...overrideOptions, detail: valueOrOverrideOptions }\r\n\r\n const event = new CustomEvent(name, eventOptions);\r\n dispatchEvent(event);\r\n };\r\n return output;\r\n }\r\n }\r\n }\r\n}\r\n","export const INTERNAL_OBSERVED_ATTRIBUTES = `observedAttributes`;","/**\r\n * This symbol is used to call the set method of the InputSignal\r\n * Normally the set method is permitted internally and should not be called\r\n * by the User\r\n */\r\nexport const INPUT_SIGNAL_SET_SYMBOL = Symbol(`InputSignalSet`);\r\n\r\n/**\r\n * Asserts that the provided symbol matches the internal {@link INPUT_SIGNAL_SET_SYMBOL} symbol,\r\n * ensuring the caller has access to internal APIs.\r\n *\r\n * Throws if the symbol does not match, preventing external code from\r\n * invoking methods intended for internal use only.\r\n *\r\n * @param symbol - The symbol to validate against {@link INPUT_SIGNAL_SET_SYMBOL}.\r\n * @throws {Error} If `symbol` does not match {@link INPUT_SIGNAL_SET_SYMBOL}.\r\n * @internal\r\n */\r\nexport function assertPrivateContext(symbol: symbol): void {\r\n if (symbol !== INPUT_SIGNAL_SET_SYMBOL) {\r\n throw new Error('Invalid symbol for InputSignal set method');\r\n }\r\n}","import { SignalOptions } from '@xaendar/signals';\r\nimport { assertPrivateContext } from './input-set.symbol';\r\n\r\n/**\r\n * An `InputSignal` is a specialized `Signal.State` designed for use as a property signal in web components. \r\n * It extends the base `State` signal with additional functionality to handle incoming values, such as those from HTML attributes or external sources, \r\n * and allows for optional transformation of these values before they are stored in the signal.\r\n */\r\nexport class InputSignal<ActualValue = unknown, IncomingValue = ActualValue> extends Signal.State<ActualValue>{\r\n /**\r\n * Optional transform function to convert incoming values to the actual type stored in the signal.\r\n */\r\n private _transform?: (value: IncomingValue) => ActualValue;\r\n\r\n /**\r\n * Creates a new `InputSignal` instance.\r\n *\r\n * @param initialValue - The initial value of the signal.\r\n * @param options - Optional configuration:\r\n * - `equals` — custom equality function; defaults to `Object.is`.\r\n * - `watched` — called when the signal gains its first sink.\r\n * - `unwatched` — called when the signal loses its last sink.\r\n * - `transform` — function to transform incoming values before setting the signal's value.\r\n */\r\n constructor(value?: ActualValue, options?: SignalOptions<ActualValue> & { transform?: (value: IncomingValue) => ActualValue }) {\r\n const transform = options?.transform;\r\n /* \r\n Ensure transform field is not passed to super constructor\r\n since it's not part of SignalOptions and would cause an error\r\n */\r\n delete options?.transform;\r\n\r\n super(value as ActualValue, options);\r\n this._transform = transform;\r\n }\r\n\r\n /**\r\n * Set a new value to the signal, applying the transform function if provided.\r\n * @param newValue - The new value to set.\r\n * @throws If `frozen` is `true` — writes are forbidden while a protected\r\n * callback is executing.\r\n */\r\n // @ts-expect-error\r\n public override set(newValue: IncomingValue, symbol: symbol): void {\r\n assertPrivateContext(symbol);\r\n const transformedValue = this._transform ? this._transform(newValue) : newValue;\r\n super.set(transformedValue as ActualValue);\r\n }\r\n}\r\n","import { AccessorDecorator, ClassAccessorDecoratorValue } from '@xaendar/types';\r\nimport { INTERNAL_OBSERVED_ATTRIBUTES } from '../costants';\r\nimport { BaseWebComponent } from '../directives/base-web-component';\r\nimport { InputSignal } from '../signals/input/input.model';\r\nimport { PropertyDecoratorOptions, PropertyDecoratorOptionsWithRequired, } from '../types/property-decorator-options.type';\r\n\r\nconst propertyDecoratorOptionsWithRequiredBrand = Symbol('PropertyDecoratorOptionsWithRequiredBrand');\r\ntype PropertyDecoratoprOptionsWithRequiredBrandType<ActualValue = unknown, IncomingValue = ActualValue> = PropertyDecoratorOptionsWithRequired<ActualValue, IncomingValue> & { \r\n [propertyDecoratorOptionsWithRequiredBrand]: 'PropertyDecoratorOptionsWithRequired' \r\n};\r\n\r\nfunction createPropertyDecorator<\r\n Class extends BaseWebComponent,\r\n Value extends InputSignal<ActualValue, IncomingValue>,\r\n ActualValue = unknown,\r\n IncomingValue = ActualValue\r\n>(value?: ActualValue | PropertyDecoratoprOptionsWithRequiredBrandType<ActualValue, IncomingValue>, options?: PropertyDecoratorOptions<ActualValue, IncomingValue>): AccessorDecorator<Class, Value> {\r\n return function (\r\n _target: ClassAccessorDecoratorValue<Value>,\r\n context: ClassAccessorDecoratorContext<Class, Value>\r\n ): ReturnType<AccessorDecorator<Class, Value>> {\r\n const propertyKey = context.name;\r\n\r\n if (typeof propertyKey === 'symbol') {\r\n throw new Error('Symbol properties are not supported');\r\n }\r\n\r\n const metadata = context.metadata as { [INTERNAL_OBSERVED_ATTRIBUTES]?: string[] };\r\n metadata[INTERNAL_OBSERVED_ATTRIBUTES] ??= [];\r\n metadata[INTERNAL_OBSERVED_ATTRIBUTES].push(propertyKey);\r\n\r\n let actualValue: ActualValue | undefined;\r\n let actualOptions: PropertyDecoratorOptions<ActualValue, IncomingValue> | undefined | PropertyDecoratoprOptionsWithRequiredBrandType<ActualValue, IncomingValue> | undefined;\r\n if (!value || typeof value !== 'object' || !(propertyDecoratorOptionsWithRequiredBrand in value)) {\r\n actualValue = value;\r\n actualOptions = options;\r\n } else {\r\n actualOptions = value;\r\n }\r\n\r\n const signal = new InputSignal<ActualValue, IncomingValue>(actualValue, {\r\n equals: actualOptions?.equals,\r\n watched: actualOptions?.watched,\r\n unwatched: actualOptions?.unwatched,\r\n transform: actualOptions?.transform\r\n });\r\n\r\n return {\r\n get() {\r\n return signal as Value;\r\n },\r\n init(_?: InputSignal<ActualValue, IncomingValue>) {\r\n return signal as Value;\r\n },\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Decoratore per proprietà opzionale.\r\n *\r\n * @example\r\n * @Property()\r\n * accessor label: InputSignal<string>;\r\n *\r\n * @Property({ value: 0 })\r\n * accessor count: InputSignal<number>;\r\n *\r\n * @Property({ value: { required: true, foo: 'bar' }, alias: 'cfg' })\r\n * accessor config: InputSignal<Config>;\r\n */\r\nexport function Property<\r\n Class extends BaseWebComponent,\r\n Value extends InputSignal<ActualValue, IncomingValue>,\r\n ActualValue = Value extends InputSignal<infer U, any> ? U : unknown,\r\n IncomingValue = Value extends InputSignal<any, infer V> ? V : ActualValue\r\n>(\r\n value?: ActualValue,\r\n options?: PropertyDecoratorOptions<ActualValue, IncomingValue>\r\n): AccessorDecorator<Class, InputSignal<ActualValue, IncomingValue>> {\r\n return createPropertyDecorator<Class, InputSignal<ActualValue, IncomingValue>, ActualValue, IncomingValue>(value, options);\r\n}\r\n\r\n/**\r\n * Decoratore per proprietà obbligatoria.\r\n * Il consumer deve fornire il valore; non accetta un valore di default.\r\n *\r\n * @example\r\n * @Property.required()\r\n * accessor userId: InputSignal<string>;\r\n *\r\n * @Property.required({ alias: 'user-id' })\r\n * accessor userId: InputSignal<string>;\r\n */\r\nProperty.required = function required<\r\n Class extends BaseWebComponent,\r\n ActualValue = unknown,\r\n IncomingValue = ActualValue\r\n>(\r\n options?: Omit<PropertyDecoratorOptionsWithRequired<ActualValue, IncomingValue>, 'required'>\r\n): AccessorDecorator<Class, InputSignal<ActualValue, IncomingValue>> {\r\n return createPropertyDecorator<Class, InputSignal<ActualValue, IncomingValue>, ActualValue, IncomingValue>({\r\n ...options,\r\n [propertyDecoratorOptionsWithRequiredBrand]: 'PropertyDecoratorOptionsWithRequired',\r\n required: true,\r\n });\r\n};","import { ClassDecorator, Constructor } from '@xaendar/types';\r\nimport { INTERNAL_OBSERVED_ATTRIBUTES } from '../../costants';\r\nimport { BaseWebComponent } from '../../directives/base-web-component';\r\nimport { WebComponentDecoratorParams } from '../../types/web-component/web-component-decorator-params.type';\r\n\r\n/**\r\n * Decorator to define a web component\r\n * @param selector Name or names of the custom element\r\n */\r\nexport function WebComponent<T extends BaseWebComponent>(options: WebComponentDecoratorParams): ClassDecorator<T> {\r\n return function (klass: Constructor<T>, context: ClassDecoratorContext<Constructor<T>>): void {\r\n defineObservedAttributes(klass, context);\r\n setSelectors(klass, options.selector);\r\n };\r\n}\r\n\r\n/**\r\n * Function to define the observedAttributes static property on the class.\r\n * We define static get observedAttributes programmatically\r\n * to abstract the manual definition from the user.\r\n *\r\n * We could not define the property in the base class due to the fact\r\n * that is static and each derived class would override the value of the others\r\n * @param klass The class to set the observedAttributes on\r\n * @param attributes The attributes to observe\r\n */\r\nfunction defineObservedAttributes<T extends BaseWebComponent>(klass: Constructor<T>, context: ClassDecoratorContext<Constructor<T>>): void {\r\n Object.defineProperty(klass, 'observedAttributes', {\r\n get: () => context.metadata![INTERNAL_OBSERVED_ATTRIBUTES],\r\n configurable: false,\r\n enumerable: false\r\n });\r\n}\r\n\r\n/**\r\n * Function to add the custom element definition to the browser using the passed selectors.\r\n * @param klass The class to define as a web component\r\n * @param selectors The selector or selectors to reference the web component in HTML\r\n */\r\nfunction setSelectors<T extends BaseWebComponent>(klass: Constructor<T>, selectors: string | string[]): void {\r\n Array.isArray(selectors)\r\n ? selectors.forEach(selector => customElements.define(selector, klass))\r\n : customElements.define(selectors, klass);\r\n}","import { INPUT_SIGNAL_SET_SYMBOL } from \"../signals/input/input-set.symbol\";\r\nimport { InputSignal } from \"../signals/input/input.model\";\r\n\r\n/**\r\n * Base class for all Web Components in the framework\r\n * \r\n * This class internally has an `observedAttributes` property\r\n * add programmaticaly by the @WebComponent decorator. \r\n * It won't appear by intellisense but it's there.\r\n */\r\nexport class BaseWebComponent extends HTMLElement {\r\n /**\r\n * The root of the Web Component, where the content is rendered\r\n */\r\n private readonly _root: ShadowRoot;\r\n\r\n constructor() {\r\n super();\r\n this._root = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n /**\r\n * Method called by the @Property decorator to\r\n * update the rendering of the component\r\n * @internal \r\n */\r\n private _render(): void { }\r\n\r\n /**\r\n * Method automatically called by the JavascriptEngine when an attribute\r\n * on the host element is changed\r\n * \r\n * This method runs before the connectedCallback method if any observed attribute\r\n * is specified on the CustomElement tag in the HTML\r\n * \r\n * @param name Name of the attribute changed\r\n * @param _oldValue Old value of the attribute\r\n * @param newValue New value of the attribute\r\n */\r\n private attributeChangedCallback(name: string, _oldValue: unknown, newValue: unknown): void {\r\n /*\r\n Since the 'Property Decorator add the property key to the ObservedAttributes\r\n We are sure that the property with the given name exists on the instance of the subclass\r\n */\r\n const context = this as BaseWebComponent & Record<string, unknown>;\r\n if (!(name in context)) {\r\n throw new Error(`Attribute ${name} is not associated to any property`);\r\n }\r\n\r\n\r\n /*\r\n @Property decorator types ensure that the property associated to the attribute is an InputSignal\r\n but i prefer to check it at runtime anyway to avoid any possible error in the future \r\n if the decorator is used wrong or if the types are not respected for some reason \r\n */\r\n if (!(context[name] instanceof InputSignal)) {\r\n throw new Error(`Property ${name} is not an InputSignal`);\r\n }\r\n\r\n context[name].set(newValue, INPUT_SIGNAL_SET_SYMBOL);\r\n }\r\n\r\n /**\r\n * Method automatically called by the JavascriptEngine when a CustomElement\r\n * is added to the DOM\r\n * \r\n * This method is called EVERY time the element is added\r\n */\r\n private connectedCallback(): void {\r\n this._render();\r\n }\r\n\r\n /**\r\n * Method automatically called by the JavascriptEngine when a CustomElement\r\n * is removed from the DOM\r\n * \r\n * This method is called EVERY time the element is removed\r\n * \r\n * We use this method to reset the _initialized flag\r\n * so that if the element is re-added to the DOM\r\n * the properties initialization won't call the render method\r\n */\r\n private disconnectedCallback(): void {\r\n }\r\n}"],"mappings":"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"}
|
|
File without changes
|
|
File without changes
|