assign-gingerly 0.0.16 → 0.0.18

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/README.md CHANGED
@@ -23,8 +23,14 @@ One can achieve the same functionality with a little more work, and "playing nic
23
23
 
24
24
  Not only does this polyfill package allow merging data properties onto objects that are expecting them, this polyfill also provides the ability to merge *augmented behavior* onto run-time objects without sub classing all such objects of the same type. This includes the ability to spawn an instance of a class and "merge" it into the API of the original object in an elegant way that is easy to wrap one's brain around, without ever blocking access to the original object or breaking it.
25
25
 
26
+
27
+
26
28
  So we are providing a form of the ["Decorator Pattern"](https://en.wikipedia.org/wiki/Decorator_pattern) or perhaps more accurately the [Extension Object Pattern](https://swiftorial.com/swiftlessons/design-patterns/structural-patterns/extension-object-pattern) as tailored for the quirks of the web.
27
29
 
30
+ ## Custom Enhancement Registry
31
+
32
+ On top of that, this polyfill package builds on the newly minted Custom Element Registry, adding an additional EnhancementRegistry object on top of the customElementRegistry object associated with all elements, to be able to manage namespace conflicts, and, importantly, as a basis for defining custom attributes associated with the enhancements.
33
+
28
34
  So in our view this package helps fill the void left by not supporting the "is" attribute for built-in elements (but is not a complete solution, just a critical building block). Mount-observer, mount-observer-script-element, and custom enhancements builds on top of the critical role that assign-gingerly plays.
29
35
 
30
36
  Anyway, let's start out detailing the more innocent features of this package / polyfill.
@@ -33,7 +39,7 @@ The two utility functions are:
33
39
 
34
40
  ## assignGingerly
35
41
 
36
- assignGingerly builds on Object.assign. Like Object.assign, the object getting assigned can be a JSON stringified object. Some of the unusual syntax we see with assignGingerly is there to continue to support JSON deserialized objects as a viable argument to be passed.
42
+ assignGingerly builds on Object.assign. Like Object.assign, the object getting assigned can often be a JSON stringified object. Some of the unusual syntax we see with assignGingerly is there to continue to support JSON deserialized objects as a viable argument to be passed.
37
43
 
38
44
  assign-gingerly adds support for:
39
45
 
@@ -96,7 +102,9 @@ console.log(obj);
96
102
 
97
103
  When the right hand side of an expression is an object, assignGingerly is recursively applied (passing the third argument in if applicable, which will be discussed below).
98
104
 
99
- While we are in the business of passing values of object A into object B, we might as well add some extremely common behavior that allows updating properties of object B based on the current values of object B -- things like incrementing, toggling, and deleting. Deleting is critical for assignTentatively, but is included with both functions
105
+ Of course, just as Object.assign led to object spread notation, assignGingerly could lead to some sort of deep structural JavaScript syntax, but that is outside the scope of this polyfill package.
106
+
107
+ While we are in the business of passing values of object A into object B, we might as well add some extremely common behavior that allows updating properties of object B based on the current values of object B -- things like incrementing, toggling, and deleting. Deleting is critical for assignTentatively, but is included with both functions.
100
108
 
101
109
  ## Example 4 - Incrementing values with += command
102
110
 
@@ -213,8 +221,7 @@ console.log(obj);
213
221
  - Non-existent properties are silently skipped
214
222
  - If the parent path doesn't exist, the command is silently skipped
215
223
  - For root-level deletion, use ` -=` (space before -=)
216
- // }
217
- // }
224
+
218
225
 
219
226
 
220
227
 
@@ -285,9 +292,9 @@ This guarantees that applying the reversal object restores the object to its exa
285
292
  ## Dependency injection based on a registry object and a Symbolic reference mapping
286
293
 
287
294
  ```Typescript
288
- interface IBaseRegistryItem<T = any> {
289
- spawn: {new(): T} | Promise<{new(): T}>
290
- symlinks: {[key: symbol]: keyof T}
295
+ interface IBaseRegistryItem<T = any, TObjToExtend = any> {
296
+ spawn: {new(objToExtend: TObjToExtend, ctx: SpawnContext, initVals: Partial<T>): T}
297
+ symlinks?: {[key: symbol]: keyof T}
291
298
  // Optional: for element enhancement access
292
299
  enhKey?: string
293
300
  // Optional: automatic attribute parsing
@@ -508,6 +515,9 @@ The prototype extensions are non-enumerable and won't appear in `Object.keys()`
508
515
 
509
516
  This package includes support for Chrome's scoped custom element registries, which automatically integrates dependency injection in harmony with scoped custom elements DOM sections or ShadowRoots.
510
517
 
518
+ > [!NOTE]
519
+ > Safari/WebKit played a critical role in pushing scoped custom element registries forward, and announced with little fanfare or documentation that [Safari 26 supports it](https://developer.apple.com/documentation/safari-release-notes/safari-26-release-notes). However, the Playwright test machinery's cross platform Safari test browser doesn't yet support it.
520
+
511
521
  <details>
512
522
  <summary>Automatic Registry Population</summary>
513
523
 
@@ -515,7 +525,6 @@ When `assignGingerly` or `assignTentatively` is called on an Element instance wi
515
525
 
516
526
  ```TypeScript
517
527
  import 'assign-gingerly/object-extension.js';
518
- import { BaseRegistry } from 'assign-gingerly';
519
528
 
520
529
  // Set up a registry on the custom element registry
521
530
  const myElement = document.createElement('div');
@@ -649,7 +658,7 @@ This approach is part of a proposal to WHATWG for standardizing element enhancem
649
658
 
650
659
  ### Constructor Signature
651
660
 
652
- Enhancement classes should follow this constructor signature:
661
+ Element enhancement classes should follow this constructor signature:
653
662
 
654
663
  ```TypeScript
655
664
  interface SpawnContext<T, TMountContext = any> {
@@ -657,7 +666,7 @@ interface SpawnContext<T, TMountContext = any> {
657
666
  mountCtx?: TMountContext; // Optional custom context passed by caller
658
667
  }
659
668
 
660
- class Enhancement {
669
+ class Enhancement<T> {
661
670
  constructor(
662
671
  oElement?: Element, // The element being enhanced
663
672
  ctx?: SpawnContext, // Context with registry item info and optional mountCtx
@@ -671,6 +680,8 @@ class Enhancement {
671
680
 
672
681
  All parameters are optional for backward compatibility with existing code.
673
682
 
683
+ Note that the class need not extend any base class or leverage any mixins. In fact, ES5 prototype functions can be used, and in both cases are instanted using new .... Arrow functions cannot be used.
684
+
674
685
  <details>
675
686
  <summary>Passing Custom Context</summary>
676
687
 
@@ -705,10 +716,10 @@ This is useful for:
705
716
  In addition to spawn and symlinks, registry items support optional properties `enhKey`, `withAttrs`, `canSpawn`, and `lifecycleKeys`:
706
717
 
707
718
  ```TypeScript
708
- interface IBaseRegistryItem<T> {
719
+ interface IBaseRegistryItem<T, TObj = Element> {
709
720
  spawn: {
710
- new (oElement?: Element, ctx?: SpawnContext<T>, initVals?: Partial<T>): T;
711
- canSpawn?: (obj: any, ctx?: SpawnContext<T>) => boolean; // Optional spawn guard
721
+ new (obj?: TObj, ctx?: SpawnContext<T>, initVals?: Partial<T>): T;
722
+ canSpawn?: (obj: TObj, ctx?: SpawnContext<T>) => boolean; // Optional spawn guard
712
723
  };
713
724
  symlinks?: { [key: string | symbol]: keyof T };
714
725
  enhKey?: string; // String identifier for set proxy access
@@ -818,7 +829,7 @@ console.log(item.enhKey); // 'myEnh'
818
829
 
819
830
  ### Programmatic Instance Spawning with `enh.get()`
820
831
 
821
- The `enh.get(registryItem)` method provides a programmatic way to spawn or retrieve enhancement instances:
832
+ The `enh.get(registryItem)` method provides a programmatic way to spawn or retrieve previously instantiated enhancement instances:
822
833
 
823
834
  ```TypeScript
824
835
  const registryItem = {
@@ -948,9 +959,9 @@ Note: Symbol event names are not yet supported by the platform but have been req
948
959
 
949
960
  </details>
950
961
 
951
- ### Disposing Enhancement Instances with `enh.dispose()`
962
+ ### Disposing Enhancement Instances with `enh.dispose(regItem)`
952
963
 
953
- The `enh.dispose()` method provides a way to clean up and remove enhancement instances:
964
+ The `enh.dispose(regItem)` method provides a way to clean up and remove enhancement instances:
954
965
 
955
966
  ```TypeScript
956
967
  class MyEnhancement {
@@ -991,7 +1002,7 @@ const instance = element.enh.get(registryItem);
991
1002
  element.enh.dispose(registryItem);
992
1003
  ```
993
1004
 
994
- **How `enh.dispose()` works:**
1005
+ **How `enh.dispose(regItem)` works:**
995
1006
 
996
1007
  1. **Retrieves instance**: Gets the spawned instance from the global instance map
997
1008
  2. **Calls lifecycle method**: If `lifecycleKeys.dispose` is specified, calls that method on the instance (passing the registry item)
@@ -1043,9 +1054,9 @@ element.enh.dispose(registryItem); // Stops timer and cleans up
1043
1054
  - Calling `enh.get()` again will create a new instance
1044
1055
  - The enhancement property is removed from the enh container
1045
1056
 
1046
- ### Waiting for Async Initialization with `enh.whenResolved()`
1057
+ ### Waiting for Async Initialization with `enh.whenResolved(regItem)`
1047
1058
 
1048
- The `enh.whenResolved()` method provides a way to wait for asynchronous enhancement initialization:
1059
+ The `enh.whenResolved(regItem)` method provides a way to wait for asynchronous enhancement initialization:
1049
1060
 
1050
1061
  ```TypeScript
1051
1062
  class AsyncEnhancement extends EventTarget {
@@ -1351,11 +1362,11 @@ assignGingerly(element, { [enhSymbol]: 'test' }, { registry });
1351
1362
 
1352
1363
  ## Parsing Attributes with `parseWithAttrs`
1353
1364
 
1354
- The `parseWithAttrs` function provides a declarative way to read and parse HTML attributes into structured data objects. It's particularly useful for custom elements and web components that need to extract configuration from attributes.
1365
+ The `parseWithAttrs` function provides a declarative way to read and parse HTML attributes and pass the parsed values into the spawned enhancement constructor.
1355
1366
 
1356
1367
  ### Automatic Integration with Enhancement Spawning
1357
1368
 
1358
- **Important**: When using the `enh.get()`, `enh.set`, or `assignGingerly()` methods with registry items, you typically **do not need to call `parseWithAttrs()` manually**. The attribute parsing happens automatically during enhancement spawning when you include a `withAttrs` property in your registry item.
1369
+ **Important**: When using the `enh.get()`, `enh.set`, or `assignGingerly()` methods with registry items, you typically **do not need to call `parseWithAttrs()` manually**. The attribute parsing happens automatically during enhancement spawning when you include a `withAttrs` property in your registry item configuration.
1359
1370
 
1360
1371
  ```html
1361
1372
  <my-element my-enhancement-count="42" my-enhancement-theme="dark"></my-element>
@@ -1747,6 +1758,8 @@ const result = parseWithAttrs(element, config);
1747
1758
 
1748
1759
  **Built-in Named Parsers:**
1749
1760
 
1761
+ [TODO]: Check if this is all needed
1762
+
1750
1763
  The following parsers are pre-registered in `globalParserRegistry`:
1751
1764
 
1752
1765
  - `'timestamp'` - Parses ISO date string to Unix timestamp (milliseconds)
@@ -2206,6 +2219,21 @@ console.log(query);
2206
2219
  const elements = document.querySelectorAll(query);
2207
2220
  ```
2208
2221
 
2222
+ **Without selectors (matches any element):**
2223
+
2224
+ ```TypeScript
2225
+ // Omit the selectors parameter
2226
+ const query = buildCSSQuery(config);
2227
+ // or explicitly pass empty string
2228
+ const query = buildCSSQuery(config, '');
2229
+
2230
+ console.log(query);
2231
+ // '[my-component], [enh-my-component], [my-component-theme], [enh-my-component-theme]'
2232
+
2233
+ // Matches any element with these attributes
2234
+ const elements = document.querySelectorAll(query);
2235
+ ```
2236
+
2209
2237
  ### How It Works
2210
2238
 
2211
2239
  `buildCSSQuery` creates a cross-product of:
@@ -2289,11 +2317,27 @@ buildCSSQuery(config, 'div');
2289
2317
 
2290
2318
  ### Edge Cases
2291
2319
 
2292
- **Empty inputs return empty string:**
2320
+ **Omitting or empty selectors return attribute-only selectors:**
2321
+ ```TypeScript
2322
+ const config = {
2323
+ spawn: MyClass,
2324
+ withAttrs: {
2325
+ base: 'my-attr',
2326
+ theme: '${base}-theme'
2327
+ }
2328
+ };
2329
+
2330
+ buildCSSQuery(config); // Omit selectors parameter
2331
+ // or
2332
+ buildCSSQuery(config, ''); // Empty string
2333
+ // Both return: '[my-attr], [enh-my-attr], [my-attr-theme], [enh-my-attr-theme]'
2334
+ // Matches any element with these attributes
2335
+ ```
2336
+
2337
+ **Empty withAttrs returns empty string:**
2293
2338
  ```TypeScript
2294
2339
  buildCSSQuery({ spawn: MyClass }, 'div'); // '' (no withAttrs)
2295
2340
  buildCSSQuery({ spawn: MyClass, withAttrs: {} }, 'div'); // '' (empty withAttrs)
2296
- buildCSSQuery({ spawn: MyClass, withAttrs: { base: 'x' } }, ''); // '' (empty selectors)
2297
2341
  ```
2298
2342
 
2299
2343
  **Deduplication:**
@@ -2312,14 +2356,15 @@ buildCSSQuery(config, ' div , span , p ');
2312
2356
 
2313
2357
  1. **Mount Observer Integration**: Find elements that need enhancement
2314
2358
  ```TypeScript
2315
- const query = buildCSSQuery(enhancementConfig, '*');
2359
+ // Match any element with the attributes
2360
+ const query = buildCSSQuery(enhancementConfig);
2316
2361
  const observer = new MutationObserver(() => {
2317
2362
  const elements = document.querySelectorAll(query);
2318
2363
  elements.forEach(el => enhance(el));
2319
2364
  });
2320
2365
  ```
2321
2366
 
2322
- 2. **Batch Enhancement**: Enhance all matching elements at once
2367
+ 2. **Specific Element Types**: Enhance only certain element types
2323
2368
  ```TypeScript
2324
2369
  const query = buildCSSQuery(config, 'template, script');
2325
2370
  document.querySelectorAll(query).forEach(el => {
@@ -2338,17 +2383,20 @@ buildCSSQuery(config, ' div , span , p ');
2338
2383
  ```TypeScript
2339
2384
  function buildCSSQuery(
2340
2385
  config: EnhancementConfig,
2341
- selectors: string
2386
+ selectors?: string
2342
2387
  ): string
2343
2388
  ```
2344
2389
 
2345
2390
  **Parameters:**
2346
2391
  - `config`: Enhancement configuration with `withAttrs` property
2347
- - `selectors`: Comma-separated CSS selectors (e.g., `'div, span'`)
2392
+ - `selectors` (optional): Comma-separated CSS selectors (e.g., `'div, span'`)
2393
+ - If omitted or empty string, returns attribute selectors without element prefix
2394
+ - This matches any element with the specified attributes
2348
2395
 
2349
2396
  **Returns:**
2350
2397
  - CSS query string with cross-product of selectors and attributes
2351
- - Empty string if `withAttrs` is missing or empty
2398
+ - If selectors is omitted or empty: returns attribute-only selectors (e.g., `'[attr], [enh-attr]'`)
2399
+ - If withAttrs is missing or empty: returns empty string
2352
2400
 
2353
2401
  **Throws:**
2354
2402
  - Error if template variables have circular references
package/buildCSSQuery.js CHANGED
@@ -64,7 +64,8 @@ function extractAttributeNames(withAttrs) {
64
64
  * Creates a cross-product of selectors and attribute names (both prefixed and unprefixed)
65
65
  *
66
66
  * @param config - Enhancement configuration with withAttrs
67
- * @param selectors - Comma-separated CSS selectors to match (e.g., 'template, script')
67
+ * @param selectors - Optional comma-separated CSS selectors to match (e.g., 'template, script')
68
+ * If omitted or empty, returns just the attribute selectors without element prefix
68
69
  * @returns CSS query string with cross-product of selectors and attributes
69
70
  *
70
71
  * @example
@@ -76,36 +77,49 @@ function extractAttributeNames(withAttrs) {
76
77
  * }
77
78
  * };
78
79
  *
80
+ * // With selectors
79
81
  * buildCSSQuery(config, 'div, span');
80
82
  * // Returns: 'div[my-attr], span[my-attr], div[enh-my-attr], span[enh-my-attr],
81
83
  * // div[my-attr-theme], span[my-attr-theme], div[enh-my-attr-theme], span[enh-my-attr-theme]'
84
+ *
85
+ * // Without selectors (matches any element)
86
+ * buildCSSQuery(config);
87
+ * // or
88
+ * buildCSSQuery(config, '');
89
+ * // Returns: '[my-attr], [enh-my-attr], [my-attr-theme], [enh-my-attr-theme]'
82
90
  */
83
91
  export function buildCSSQuery(config, selectors) {
84
92
  // Validate inputs
85
- if (!config.withAttrs || !selectors) {
86
- return '';
87
- }
88
- // Parse and normalize selectors
89
- const selectorList = selectors
90
- .split(',')
91
- .map(s => s.trim())
92
- .filter(s => s.length > 0);
93
- if (selectorList.length === 0) {
93
+ if (!config.withAttrs) {
94
94
  return '';
95
95
  }
96
- // Extract and resolve attribute names
96
+ // Extract and resolve attribute names first
97
97
  const attrNames = extractAttributeNames(config.withAttrs);
98
98
  if (attrNames.length === 0) {
99
99
  return '';
100
100
  }
101
- // Build cross-product of selectors × attributes × prefixes
101
+ // Parse and normalize selectors
102
+ const selectorList = selectors
103
+ ? selectors.split(',').map(s => s.trim()).filter(s => s.length > 0)
104
+ : [];
105
+ // Build queries
102
106
  const queries = [];
103
- for (const selector of selectorList) {
107
+ if (selectorList.length === 0) {
108
+ // No selectors provided - return just attribute selectors
104
109
  for (const attrName of attrNames) {
105
- // Unprefixed version
106
- queries.push(`${selector}[${attrName}]`);
107
- // enh- prefixed version
108
- queries.push(`${selector}[enh-${attrName}]`);
110
+ queries.push(`[${attrName}]`);
111
+ queries.push(`[enh-${attrName}]`);
112
+ }
113
+ }
114
+ else {
115
+ // Build cross-product of selectors × attributes × prefixes
116
+ for (const selector of selectorList) {
117
+ for (const attrName of attrNames) {
118
+ // Unprefixed version
119
+ queries.push(`${selector}[${attrName}]`);
120
+ // enh- prefixed version
121
+ queries.push(`${selector}[enh-${attrName}]`);
122
+ }
109
123
  }
110
124
  }
111
125
  // Deduplicate and join
package/buildCSSQuery.ts CHANGED
@@ -82,7 +82,8 @@ function extractAttributeNames(withAttrs: AttrPatterns<any>): string[] {
82
82
  * Creates a cross-product of selectors and attribute names (both prefixed and unprefixed)
83
83
  *
84
84
  * @param config - Enhancement configuration with withAttrs
85
- * @param selectors - Comma-separated CSS selectors to match (e.g., 'template, script')
85
+ * @param selectors - Optional comma-separated CSS selectors to match (e.g., 'template, script')
86
+ * If omitted or empty, returns just the attribute selectors without element prefix
86
87
  * @returns CSS query string with cross-product of selectors and attributes
87
88
  *
88
89
  * @example
@@ -94,45 +95,56 @@ function extractAttributeNames(withAttrs: AttrPatterns<any>): string[] {
94
95
  * }
95
96
  * };
96
97
  *
98
+ * // With selectors
97
99
  * buildCSSQuery(config, 'div, span');
98
100
  * // Returns: 'div[my-attr], span[my-attr], div[enh-my-attr], span[enh-my-attr],
99
101
  * // div[my-attr-theme], span[my-attr-theme], div[enh-my-attr-theme], span[enh-my-attr-theme]'
102
+ *
103
+ * // Without selectors (matches any element)
104
+ * buildCSSQuery(config);
105
+ * // or
106
+ * buildCSSQuery(config, '');
107
+ * // Returns: '[my-attr], [enh-my-attr], [my-attr-theme], [enh-my-attr-theme]'
100
108
  */
101
109
  export function buildCSSQuery(
102
110
  config: EnhancementConfig,
103
- selectors: string
111
+ selectors?: string
104
112
  ): string {
105
113
  // Validate inputs
106
- if (!config.withAttrs || !selectors) {
114
+ if (!config.withAttrs) {
107
115
  return '';
108
116
  }
109
117
 
110
- // Parse and normalize selectors
111
- const selectorList = selectors
112
- .split(',')
113
- .map(s => s.trim())
114
- .filter(s => s.length > 0);
115
-
116
- if (selectorList.length === 0) {
117
- return '';
118
- }
119
-
120
- // Extract and resolve attribute names
118
+ // Extract and resolve attribute names first
121
119
  const attrNames = extractAttributeNames(config.withAttrs);
122
120
 
123
121
  if (attrNames.length === 0) {
124
122
  return '';
125
123
  }
126
124
 
127
- // Build cross-product of selectors × attributes × prefixes
125
+ // Parse and normalize selectors
126
+ const selectorList = selectors
127
+ ? selectors.split(',').map(s => s.trim()).filter(s => s.length > 0)
128
+ : [];
129
+
130
+ // Build queries
128
131
  const queries: string[] = [];
129
132
 
130
- for (const selector of selectorList) {
133
+ if (selectorList.length === 0) {
134
+ // No selectors provided - return just attribute selectors
131
135
  for (const attrName of attrNames) {
132
- // Unprefixed version
133
- queries.push(`${selector}[${attrName}]`);
134
- // enh- prefixed version
135
- queries.push(`${selector}[enh-${attrName}]`);
136
+ queries.push(`[${attrName}]`);
137
+ queries.push(`[enh-${attrName}]`);
138
+ }
139
+ } else {
140
+ // Build cross-product of selectors × attributes × prefixes
141
+ for (const selector of selectorList) {
142
+ for (const attrName of attrNames) {
143
+ // Unprefixed version
144
+ queries.push(`${selector}[${attrName}]`);
145
+ // enh- prefixed version
146
+ queries.push(`${selector}[enh-${attrName}]`);
147
+ }
136
148
  }
137
149
  }
138
150
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assign-gingerly",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
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": {
@@ -25,16 +25,18 @@ type DisposeEvent =
25
25
  //reference count outside any enhancements goes to zero
26
26
  | 'dispose'
27
27
 
28
+ export type Spawner<T = any, Obj = Element> = {
29
+ new (obj?: Obj, ctx?: SpawnContext<T>, initVals?: Partial<T>): T;
30
+ canSpawn?: (obj: any, ctx?: SpawnContext<T>) => boolean;
31
+ }
32
+
28
33
  /**
29
34
  * Configuration for enhancing elements with class instances
30
35
  * Defines how to spawn and initialize enhancement classes
31
36
  */
32
- export interface EnhancementConfig<T = any> {
37
+ export interface EnhancementConfig<T = any, Obj = Element> {
33
38
 
34
- spawn: {
35
- new (obj?: any, ctx?: SpawnContext<T>, initVals?: Partial<T>): T;
36
- canSpawn?: (obj: any, ctx?: SpawnContext<T>) => boolean;
37
- };
39
+ spawn: Spawner<T, Obj>;
38
40
 
39
41
  //Applicable to passing in the initVals during the spawn lifecycle event
40
42
  withAttrs?: AttrPatterns<T>;
@@ -180,3 +182,11 @@ export declare function assignGingerly(
180
182
  ): any;
181
183
 
182
184
  export default assignGingerly;
185
+
186
+ export declare class ElementEnhancementGateway{
187
+ enh: ElementEnhancement;
188
+ }
189
+
190
+ export interface ElementEnhancement{
191
+ dispose(regItem: EnhancementConfig): void;
192
+ }