assign-gingerly 0.0.30 → 0.0.32

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,45 @@
1
+ /**
2
+ * Resolve RHS path strings in a pattern object against a source object.
3
+ *
4
+ * Any value that is a string starting with `?.` is treated as a path
5
+ * and resolved against the source object using optional chaining semantics.
6
+ * Non-string values and strings not starting with `?.` pass through unchanged.
7
+ *
8
+ * @param pattern - Object whose RHS values may contain `?.` path strings
9
+ * @param source - Object to resolve paths against
10
+ * @returns New object with path strings replaced by resolved values
11
+ *
12
+ * @example
13
+ * const pattern = {
14
+ * hello: '?.myPropContainer?.stringProp',
15
+ * foo: '?.myFooString',
16
+ * literal: 42
17
+ * };
18
+ * const source = {
19
+ * myPropContainer: { stringProp: 'Venus' },
20
+ * myFooString: 'bar'
21
+ * };
22
+ * const result = resolveValues(pattern, source);
23
+ * // { hello: 'Venus', foo: 'bar', literal: 42 }
24
+ */
25
+ export function resolveValues(
26
+ pattern: Record<string, any>,
27
+ source: any
28
+ ): Record<string, any> {
29
+ const result: Record<string, any> = {};
30
+ for (const [key, value] of Object.entries(pattern)) {
31
+ if (typeof value === 'string' && value.startsWith('?.')) {
32
+ // Parse path: split by '.', strip '?', filter empties
33
+ const parts = value.split('.').map(p => p.replace(/\?/g, '')).filter(p => p.length > 0);
34
+ let current = source;
35
+ for (const part of parts) {
36
+ if (current == null) break;
37
+ current = current[part];
38
+ }
39
+ result[key] = current;
40
+ } else {
41
+ result[key] = value;
42
+ }
43
+ }
44
+ return result;
45
+ }
@@ -226,6 +226,14 @@ export interface IAssignGingerlyOptions {
226
226
  registry?: typeof EnhancementRegistry | EnhancementRegistry;
227
227
  bypassChecks?: boolean;
228
228
  withMethods?: string[] | Set<string>;
229
+ aka?: Record<string, string>;
230
+
231
+ /**
232
+ * AbortSignal for cleaning up reactive subscriptions (@eachTime)
233
+ * Required when using @eachTime symbol for reactive iteration
234
+ * When the signal is aborted, all event listeners are automatically removed
235
+ */
236
+ signal?: AbortSignal;
229
237
  }
230
238
 
231
239
  /**
@@ -242,7 +250,6 @@ export declare class EnhancementRegisteredEvent extends Event {
242
250
  * Extends EventTarget to dispatch events when configs are registered
243
251
  */
244
252
  export declare class EnhancementRegistry extends EventTarget {
245
- private items;
246
253
  push(items: EnhancementConfig | EnhancementConfig[]): void;
247
254
  getItems(): EnhancementConfig[];
248
255
  findBySymbol(symbol: symbol | string): EnhancementConfig | undefined;
@@ -298,9 +305,12 @@ export declare function assignGingerly(
298
305
  export default assignGingerly;
299
306
 
300
307
  export declare class ElementEnhancementGateway{
308
+ //TODO: this isn't right
301
309
  enh: ElementEnhancement;
302
310
  }
303
311
 
304
312
  export interface ElementEnhancement{
305
- dispose(regItem: EnhancementConfig): void;
313
+ get(registryItem: EnhancementConfig | string | symbol, mountCtx?: any): any;
314
+ dispose(registryItem: EnhancementConfig | string | symbol): void;
315
+ whenResolved(registryItem: EnhancementConfig | string | symbol, mountCtx?: any): Promise<any>;
306
316
  }
package/Infer.js DELETED
@@ -1,154 +0,0 @@
1
- /**
2
- * Symbol for smart value assignment
3
- * When used with element.set[value], it infers and sets the appropriate value property
4
- */
5
- export const value = Symbol.for('assign-gingerly:value');
6
- /**
7
- * Symbol for smart display assignment
8
- * When used with element.set[display], it infers and sets the appropriate display property
9
- */
10
- export const display = Symbol.for('assign-gingerly:display');
11
- /**
12
- * Enhancement class that provides smart value and display property inference
13
- * Automatically determines the correct property to set based on element type
14
- */
15
- export class Infer {
16
- #weakRef;
17
- get enhancedElement() {
18
- return this.#weakRef.deref();
19
- }
20
- constructor(enhancedElement) {
21
- this.#weakRef = new WeakRef(enhancedElement);
22
- }
23
- #value;
24
- get value() {
25
- return this.#value;
26
- }
27
- set value(nv) {
28
- this.#value = nv;
29
- const { enhancedElement } = this;
30
- enhancedElement[inferValueProperty(enhancedElement)] = nv;
31
- }
32
- #display;
33
- get display() {
34
- return this.#display;
35
- }
36
- set display(nv) {
37
- this.#display = nv;
38
- const { enhancedElement } = this;
39
- enhancedElement[inferDisplayProperty(enhancedElement)] = nv;
40
- }
41
- /**
42
- * Get the inferred event type for the element
43
- * @returns The most appropriate event type for this element
44
- */
45
- get eventType() {
46
- return inferEventType(this.enhancedElement);
47
- }
48
- }
49
- /**
50
- * Registry item for the Infer enhancement
51
- * Register this with customElements.enhancementRegistry to enable smart value/display assignment
52
- */
53
- export const registryItem = {
54
- spawn: Infer,
55
- enhKey: 'infer',
56
- symlinks: {
57
- [value]: 'value',
58
- [display]: 'display'
59
- }
60
- };
61
- /**
62
- * Infer the most appropriate value property for an element
63
- * @param element - The element to infer the property for
64
- * @returns The property name to use for value assignment
65
- */
66
- export function inferValueProperty(element) {
67
- const tagName = element.localName;
68
- // Input elements - check type attribute
69
- if (tagName === 'input') {
70
- const type = element.getAttribute('type')?.toLowerCase();
71
- if (type === 'checkbox' || type === 'radio') {
72
- return 'checked';
73
- }
74
- return 'value';
75
- }
76
- // Form controls with value property
77
- if (tagName === 'textarea' || tagName === 'select') {
78
- return 'value';
79
- }
80
- // Semantic HTML elements with specific properties
81
- if (tagName === 'time') {
82
- return 'dateTime';
83
- }
84
- if (tagName === 'data') {
85
- return 'value';
86
- }
87
- if (tagName === 'meter' || tagName === 'progress') {
88
- return 'value';
89
- }
90
- if (tagName === 'output') {
91
- return 'value';
92
- }
93
- // Check for itemprop attribute as a hint
94
- const itemprop = element.getAttribute('itemprop');
95
- if (itemprop) {
96
- return itemprop;
97
- }
98
- // Default fallback
99
- return 'textContent';
100
- }
101
- /**
102
- * Infer the most appropriate display property for an element
103
- * @param element - The element to infer the property for
104
- * @returns The property name to use for display assignment
105
- */
106
- export function inferDisplayProperty(element) {
107
- const tagName = element.localName;
108
- // Form controls display their value
109
- if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') {
110
- return 'value';
111
- }
112
- // Time elements display formatted time
113
- if (tagName === 'time') {
114
- return 'textContent';
115
- }
116
- // Data elements display human-readable content
117
- if (tagName === 'data') {
118
- return 'textContent';
119
- }
120
- // Progress/meter elements use ARIA for display
121
- if (tagName === 'meter' || tagName === 'progress') {
122
- return 'ariaValueText';
123
- }
124
- // Default fallback
125
- return 'textContent';
126
- }
127
- /**
128
- * Infer the most appropriate event type for an element
129
- * Used when no explicit event type is provided
130
- * @param element - The element to infer the event type for
131
- * @returns The event type name like 'input', 'change', 'click', 'submit'
132
- */
133
- export function inferEventType(element) {
134
- const tagName = element.localName;
135
- // Form controls that support input event
136
- if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') {
137
- return 'input';
138
- }
139
- // Form submission
140
- if (tagName === 'form') {
141
- return 'submit';
142
- }
143
- // Details element
144
- if (tagName === 'details') {
145
- return 'toggle';
146
- }
147
- // Dialog element
148
- if (tagName === 'dialog') {
149
- return 'close';
150
- }
151
- // Default fallback for interactive elements
152
- return 'click';
153
- }
154
- export default registryItem;
package/Infer.ts DELETED
@@ -1,190 +0,0 @@
1
- import type { EnhancementConfig } from "./types/assign-gingerly/types";
2
-
3
- /**
4
- * Symbol for smart value assignment
5
- * When used with element.set[value], it infers and sets the appropriate value property
6
- */
7
- export const value = Symbol.for('assign-gingerly:value');
8
-
9
- /**
10
- * Symbol for smart display assignment
11
- * When used with element.set[display], it infers and sets the appropriate display property
12
- */
13
- export const display = Symbol.for('assign-gingerly:display');
14
-
15
- /**
16
- * Enhancement class that provides smart value and display property inference
17
- * Automatically determines the correct property to set based on element type
18
- */
19
- export class Infer<TValue = any, TDisplay = any> {
20
- #weakRef: WeakRef<Element>;
21
-
22
- get enhancedElement(){
23
- return this.#weakRef.deref()!;
24
- }
25
-
26
- constructor(enhancedElement?: Element){
27
- this.#weakRef = new WeakRef(enhancedElement!);
28
- }
29
-
30
- #value: TValue | undefined;
31
-
32
- get value(): TValue | undefined {
33
- return this.#value;
34
- }
35
-
36
- set value(nv: TValue){
37
- this.#value = nv;
38
- const {enhancedElement} = this;
39
- (enhancedElement as any)[inferValueProperty(enhancedElement)] = nv;
40
- }
41
-
42
- #display: TDisplay | undefined;
43
-
44
- get display(): TDisplay | undefined {
45
- return this.#display;
46
- }
47
-
48
- set display(nv: TDisplay){
49
- this.#display = nv;
50
- const {enhancedElement} = this;
51
- (enhancedElement as any)[inferDisplayProperty(enhancedElement)] = nv;
52
- }
53
-
54
- /**
55
- * Get the inferred event type for the element
56
- * @returns The most appropriate event type for this element
57
- */
58
- get eventType(): string {
59
- return inferEventType(this.enhancedElement);
60
- }
61
- }
62
-
63
- /**
64
- * Registry item for the Infer enhancement
65
- * Register this with customElements.enhancementRegistry to enable smart value/display assignment
66
- */
67
- export const registryItem: EnhancementConfig = {
68
- spawn: Infer,
69
- enhKey: 'infer',
70
- symlinks: {
71
- [value]: 'value',
72
- [display]: 'display'
73
- }
74
- }
75
-
76
- /**
77
- * Infer the most appropriate value property for an element
78
- * @param element - The element to infer the property for
79
- * @returns The property name to use for value assignment
80
- */
81
- export function inferValueProperty(element: Element): string {
82
- const tagName = element.localName;
83
-
84
- // Input elements - check type attribute
85
- if (tagName === 'input') {
86
- const type = element.getAttribute('type')?.toLowerCase();
87
- if (type === 'checkbox' || type === 'radio') {
88
- return 'checked';
89
- }
90
- return 'value';
91
- }
92
-
93
- // Form controls with value property
94
- if (tagName === 'textarea' || tagName === 'select') {
95
- return 'value';
96
- }
97
-
98
- // Semantic HTML elements with specific properties
99
- if (tagName === 'time') {
100
- return 'dateTime';
101
- }
102
-
103
- if (tagName === 'data') {
104
- return 'value';
105
- }
106
-
107
- if (tagName === 'meter' || tagName === 'progress') {
108
- return 'value';
109
- }
110
-
111
- if (tagName === 'output') {
112
- return 'value';
113
- }
114
-
115
- // Check for itemprop attribute as a hint
116
- const itemprop = element.getAttribute('itemprop');
117
- if (itemprop) {
118
- return itemprop;
119
- }
120
-
121
- // Default fallback
122
- return 'textContent';
123
- }
124
-
125
- /**
126
- * Infer the most appropriate display property for an element
127
- * @param element - The element to infer the property for
128
- * @returns The property name to use for display assignment
129
- */
130
- export function inferDisplayProperty(element: Element): string {
131
- const tagName = element.localName;
132
-
133
- // Form controls display their value
134
- if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') {
135
- return 'value';
136
- }
137
-
138
- // Time elements display formatted time
139
- if (tagName === 'time') {
140
- return 'textContent';
141
- }
142
-
143
- // Data elements display human-readable content
144
- if (tagName === 'data') {
145
- return 'textContent';
146
- }
147
-
148
- // Progress/meter elements use ARIA for display
149
- if (tagName === 'meter' || tagName === 'progress') {
150
- return 'ariaValueText';
151
- }
152
-
153
- // Default fallback
154
- return 'textContent';
155
- }
156
-
157
- /**
158
- * Infer the most appropriate event type for an element
159
- * Used when no explicit event type is provided
160
- * @param element - The element to infer the event type for
161
- * @returns The event type name like 'input', 'change', 'click', 'submit'
162
- */
163
- export function inferEventType(element: Element): string {
164
- const tagName = element.localName;
165
-
166
- // Form controls that support input event
167
- if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') {
168
- return 'input';
169
- }
170
-
171
- // Form submission
172
- if (tagName === 'form') {
173
- return 'submit';
174
- }
175
-
176
- // Details element
177
- if (tagName === 'details') {
178
- return 'toggle';
179
- }
180
-
181
- // Dialog element
182
- if (tagName === 'dialog') {
183
- return 'close';
184
- }
185
-
186
- // Default fallback for interactive elements
187
- return 'click';
188
- }
189
-
190
- export default registryItem;