assign-gingerly 0.0.45 → 0.0.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/assignFeatures.js CHANGED
@@ -420,7 +420,7 @@ export function assignFeatures(ctr, features, featuresRegistry) {
420
420
  if (SpawnClass && !isAsyncSpawn(SpawnClass) &&
421
421
  Object.hasOwn(SpawnClass, 'onAssigned') &&
422
422
  typeof SpawnClass.onAssigned === 'function') {
423
- const result = SpawnClass.onAssigned(ctr, featureConfig);
423
+ const result = SpawnClass.onAssigned(ctr, featureConfig, key);
424
424
  if (result && typeof result.then === 'function') {
425
425
  onAssignedPromises.push(result);
426
426
  }
package/assignFeatures.ts CHANGED
@@ -10,159 +10,9 @@
10
10
  */
11
11
 
12
12
  import { parseWithAttrs } from './parseWithAttrs.js';
13
+ import { FeatureSpawnContext, SupportedFeatureConfig, FeaturesClassConfig, FeatureConfig, SupportedFeaturesMap, FeatureConfigsMap } from './types/assign-gingerly/types.js';
13
14
 
14
- /**
15
- * Context passed to feature spawn constructors
16
- */
17
- export interface FeatureSpawnContext {
18
- /** The feature key (e.g., 'photoTaker') */
19
- key: string;
20
- /** The SupportedFeatureConfig from static supportedFeatures */
21
- optIn: SupportedFeatureConfig;
22
- /** The FeatureConfig from assignFeatures */
23
- injection: FeatureConfig;
24
- /** The features registry reference */
25
- featuresRegistry: FeaturesRegistry;
26
- /** Shared context from the host element (via getSharedContext callback) */
27
- shared?: any;
28
- }
29
-
30
- export interface SupportedFeatureConfig {
31
- /**
32
- * Optional fallback class (or async spawner) to use if no implementation is injected.
33
- */
34
- fallbackSpawn?:
35
- | { new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }
36
- | (() => Promise<{ new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }>);
37
-
38
- /**
39
- * Optional runtime shape validation for the spawned instance.
40
- * Return true if the instance is valid, false to throw.
41
- */
42
- validateShape?: (spawnedInstance: any) => boolean;
43
-
44
- /**
45
- * Optional callback to provide shared context (e.g., ElementInternals, private state)
46
- * to the feature at construction time.
47
- *
48
- * Defined in the class body, this callback has access to #private fields
49
- * because static methods/properties of a class can access private fields
50
- * of instances of that class.
51
- *
52
- * The returned object is passed to the feature constructor as `ctx.shared`.
53
- *
54
- * @param instance - The host element instance
55
- * @returns An object containing shared data for the feature
56
- *
57
- * @example
58
- * static supportedFeatures = {
59
- * ariaManager: {
60
- * fallbackSpawn: AriaManagerImpl,
61
- * getSharedContext(instance) {
62
- * return { internals: instance.#internals };
63
- * }
64
- * }
65
- * }
66
- */
67
- getSharedContext?: (instance: any) => any;
68
-
69
- /**
70
- * Lifecycle callbacks that this feature requires.
71
- * Serves as the default — the consumer can add more via FeatureConfig.callbackForwarding
72
- * but cannot remove these.
73
- *
74
- * Supported: 'connectedCallback', 'disconnectedCallback',
75
- * 'attributeChangedCallback', 'adoptedCallback'
76
- */
77
- callbackForwarding?: string[];
78
- }
79
-
80
- /**
81
- * Class-level configuration for the features system.
82
- * Declared as `static featuresConfig` on the class.
83
- *
84
- * @example
85
- * class ClubMember extends HTMLElement {
86
- * static supportedFeatures = { photoTaker: { fallbackSpawn: PhotoTakerImpl } }
87
- * static featuresConfig = { lifecycleKeys: true }
88
- * }
89
- */
90
- export interface FeaturesClassConfig {
91
- /**
92
- * Lifecycle method configuration.
93
- *
94
- * If set to `true`, installs a method named 'whenFeatureReady' on the prototype.
95
- * If set to an object, allows customizing the method name.
96
- *
97
- * The installed method accepts a feature key and returns a Promise that resolves
98
- * with the feature instance once it's ready (useful for async spawners).
99
- * For synchronous spawners, the Promise resolves immediately.
100
- *
101
- * Suggested default name: 'whenFeatureReady'
102
- *
103
- * @example
104
- * static featuresConfig = { lifecycleKeys: true }
105
- * // await el.whenFeatureReady('photoTaker')
106
- *
107
- * @example
108
- * static featuresConfig = { lifecycleKeys: { whenFeatureReady: 'awaitFeature' } }
109
- * // await el.awaitFeature('photoTaker')
110
- */
111
- lifecycleKeys?: true | {
112
- /** Method name for awaiting feature readiness. Defaults to 'whenFeatureReady'. */
113
- whenFeatureReady?: string;
114
- };
115
- }
116
-
117
- export interface FeatureConfig {
118
- /**
119
- * The class to instantiate for this feature, or an async function that
120
- * resolves to such a class (for lazy-loading).
121
- *
122
- * Synchronous: Constructor receives the host element as its first argument,
123
- * a FeatureSpawnContext as second, and optional initVals as third.
124
- *
125
- * Asynchronous: A function (arrow or async) that returns a Promise resolving
126
- * to a constructor. The getter returns a placeholder object immediately and
127
- * instantiates the real class once the Promise resolves.
128
- */
129
- spawn?:
130
- | { new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }
131
- | (() => Promise<{ new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }>);
132
-
133
- /**
134
- * Attribute patterns for parsing element attributes into initVals.
135
- * Attributes are the "base layer" — programmatic values override them.
136
- * Always unprefixed for features (no enh- prefix).
137
- */
138
- withAttrs?: any; // AttrPatterns<any> — imported type from types
139
-
140
- /**
141
- * Reserved field for custom configuration data.
142
- * Not interpreted by the library — available to the feature class
143
- * via ctx.injection.customData in the constructor.
144
- */
145
- customData?: any;
146
-
147
- /**
148
- * Custom element lifecycle callbacks to forward to this feature.
149
- * The feature class must implement the listed methods.
150
- *
151
- * On first `connectedCallback` forwarding, the getter is triggered (spawning
152
- * the feature if needed). For async features, forwarding is skipped until
153
- * the real instance is available.
154
- *
155
- * Supported values: 'connectedCallback', 'disconnectedCallback',
156
- * 'attributeChangedCallback', 'adoptedCallback'
157
- *
158
- * Note: `attributeChangedCallback` only receives events for attributes
159
- * listed in the element's `static observedAttributes`.
160
- */
161
- callbackForwarding?: string[];
162
- }
163
-
164
- export type SupportedFeaturesMap = Record<string, SupportedFeatureConfig>;
165
- export type FeatureConfigsMap = Record<string, FeatureConfig>;
15
+ export type { FeatureSpawnContext, SupportedFeatureConfig, FeaturesClassConfig, FeatureConfig, SupportedFeaturesMap, FeatureConfigsMap };
166
16
 
167
17
  /**
168
18
  * WeakMap storing per-instance feature caches.
@@ -667,7 +517,7 @@ export function assignFeatures(
667
517
  if (SpawnClass && !isAsyncSpawn(SpawnClass) &&
668
518
  Object.hasOwn(SpawnClass as any, 'onAssigned') &&
669
519
  typeof (SpawnClass as any).onAssigned === 'function') {
670
- const result = (SpawnClass as any).onAssigned(ctr, featureConfig);
520
+ const result = (SpawnClass as any).onAssigned(ctr, featureConfig, key);
671
521
  if (result && typeof result.then === 'function') {
672
522
  onAssignedPromises.push(result);
673
523
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assign-gingerly",
3
- "version": "0.0.45",
3
+ "version": "0.0.46",
4
4
  "description": "This package provides a utility function for carefully merging one object into another.",
5
5
  "homepage": "https://github.com/bahrus/assign-gingerly#readme",
6
6
  "bugs": {
@@ -326,3 +326,151 @@ export interface ElementEnhancement{
326
326
  dispose(registryItem: EnhancementConfig | string | symbol): void;
327
327
  whenResolved(registryItem: EnhancementConfig | string | symbol, mountCtx?: any): Promise<any>;
328
328
  }
329
+
330
+ // =============================================================================
331
+ // Custom Element Features types
332
+ // =============================================================================
333
+
334
+ /**
335
+ * Context passed to feature spawn constructors
336
+ */
337
+ export interface FeatureSpawnContext {
338
+ /** The feature key (e.g., 'photoTaker') */
339
+ key: string;
340
+ /** The SupportedFeatureConfig from static supportedFeatures */
341
+ optIn: SupportedFeatureConfig;
342
+ /** The FeatureConfig from assignFeatures */
343
+ injection: FeatureConfig;
344
+ /** The features registry reference */
345
+ featuresRegistry: FeaturesRegistry;
346
+ /** Shared context from the host element (via getSharedContext callback) */
347
+ shared?: any;
348
+ }
349
+
350
+ /**
351
+ * Configuration for a supported feature slot declared via static supportedFeatures
352
+ */
353
+ export interface SupportedFeatureConfig {
354
+ /**
355
+ * Optional fallback class (or async spawner) to use if no implementation is injected.
356
+ */
357
+ fallbackSpawn?:
358
+ | { new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }
359
+ | (() => Promise<{ new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }>);
360
+
361
+ /**
362
+ * Optional runtime shape validation for the spawned instance.
363
+ * Return true if the instance is valid, false to throw.
364
+ */
365
+ validateShape?: (spawnedInstance: any) => boolean;
366
+
367
+ /**
368
+ * Optional callback to provide shared context (e.g., ElementInternals, private state)
369
+ * to the feature at construction time.
370
+ */
371
+ getSharedContext?: (instance: any) => any;
372
+
373
+ /**
374
+ * Lifecycle callbacks that this feature requires.
375
+ * Serves as the default — the consumer can add more via FeatureConfig.callbackForwarding.
376
+ */
377
+ callbackForwarding?: string[];
378
+ }
379
+
380
+ /**
381
+ * Class-level configuration for the features system.
382
+ * Declared as `static featuresConfig` on the class.
383
+ */
384
+ export interface FeaturesClassConfig {
385
+ /**
386
+ * Lifecycle method configuration.
387
+ * true = install 'whenFeatureReady' method.
388
+ * Object = custom method name.
389
+ */
390
+ lifecycleKeys?: true | {
391
+ whenFeatureReady?: string;
392
+ };
393
+ }
394
+
395
+ /**
396
+ * Configuration for a feature passed to assignFeatures.
397
+ */
398
+ export interface FeatureConfig {
399
+ /**
400
+ * The class to instantiate, or an async function returning one.
401
+ */
402
+ spawn?:
403
+ | { new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }
404
+ | (() => Promise<{ new(hostElement: any, ctx: FeatureSpawnContext, initVals?: any): any }>);
405
+
406
+ /** Attribute patterns for parsing element attributes into initVals. */
407
+ withAttrs?: AttrPatterns<any>;
408
+
409
+ /** Pass-through custom configuration data (accessible via ctx.injection.customData). */
410
+ customData?: any;
411
+
412
+ /** Lifecycle callbacks to forward to this feature. */
413
+ callbackForwarding?: string[];
414
+ }
415
+
416
+ export type SupportedFeaturesMap = Record<string, SupportedFeatureConfig>;
417
+ export type FeatureConfigsMap = Record<string, FeatureConfig>;
418
+
419
+ /**
420
+ * Registry for feature configs, keyed by constructor.
421
+ */
422
+ export declare class FeaturesRegistry {
423
+ has(ctr: Function): boolean;
424
+ get(ctr: Function): Map<string, FeatureConfig> | undefined;
425
+ set(ctr: Function, key: string, config: FeatureConfig): void;
426
+ hasKey(ctr: Function, key: string): boolean;
427
+ }
428
+
429
+ /**
430
+ * A suggestion from one feature to another.
431
+ */
432
+ export interface FeatureInfoSuggestion {
433
+ from: Function;
434
+ withAttrs?: any;
435
+ customData?: any;
436
+ }
437
+
438
+ /**
439
+ * Core assignFeatures function.
440
+ */
441
+ export declare function assignFeatures(
442
+ ctr: Function,
443
+ features: FeatureConfigsMap,
444
+ featuresRegistry: FeaturesRegistry
445
+ ): Promise<void> | undefined;
446
+
447
+ /**
448
+ * Captures own-properties that shadow feature getters.
449
+ */
450
+ export declare function captureFeatureInitVals(instance: any): void;
451
+
452
+ /**
453
+ * Suggest configuration to another feature during registration.
454
+ */
455
+ export declare function suggestFeatureInfo(
456
+ fromFeatureCtr: Function,
457
+ toFeatureSymbol: symbol,
458
+ featureInfo: { withAttrs?: any; customData?: any },
459
+ targetClass: Function
460
+ ): void;
461
+
462
+ /**
463
+ * Retrieve suggestions made to a feature by other features.
464
+ */
465
+ export declare function getFeatureInfoSuggestions(
466
+ toFeatureSymbol: symbol,
467
+ targetClass: Function
468
+ ): FeatureInfoSuggestion[];
469
+
470
+ /**
471
+ * Base class for nested feature containers.
472
+ */
473
+ export declare class PropertyBag {
474
+ customElementRegistry: any;
475
+ constructor(hostElement: any, ctx?: FeatureSpawnContext, initVals?: any);
476
+ }