@smilodon/core 1.1.9 → 1.2.1

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.
@@ -29,6 +29,7 @@ export declare class EnhancedSelect extends HTMLElement {
29
29
  private _errorMessage;
30
30
  private _boundArrowClick;
31
31
  private _arrowContainer?;
32
+ private _optionRenderer?;
32
33
  constructor();
33
34
  connectedCallback(): void;
34
35
  disconnectedCallback(): void;
@@ -43,6 +44,7 @@ export declare class EnhancedSelect extends HTMLElement {
43
44
  private _initializeStyles;
44
45
  private _attachEventListeners;
45
46
  private _initializeObservers;
47
+ private _initializeOptionRenderer;
46
48
  private _loadInitialSelectedItems;
47
49
  private _handleOpen;
48
50
  private _handleClose;
@@ -26,6 +26,25 @@ export declare class NativeSelectElement extends HTMLElement {
26
26
  get selectedItems(): unknown[];
27
27
  set optionTemplate(template: OptionTemplate | undefined);
28
28
  set optionRenderer(renderer: OptionRenderer | undefined);
29
+ /**
30
+ * Public API: setItems() method for compatibility with EnhancedSelect
31
+ * Accepts an array of items which can be:
32
+ * - Simple primitives (string, number)
33
+ * - Objects with {label, value} structure
34
+ * - Objects with {label, value, optionComponent} for custom rendering (v1.2.0+)
35
+ */
36
+ setItems(items: unknown[]): void;
37
+ /**
38
+ * Public API: setValue() method to programmatically select an item
39
+ * For single select: clears selection and selects the item matching the value
40
+ * For multi-select: adds to selection if not already selected
41
+ */
42
+ setValue(value: unknown): void;
43
+ /**
44
+ * Public API: getValue() method to get currently selected value(s)
45
+ * Returns single value for single-select, array for multi-select
46
+ */
47
+ getValue(): unknown | unknown[];
29
48
  render(): void;
30
49
  private _applyOptionAttrs;
31
50
  private _applyAriaToAll;
@@ -1,9 +1,9 @@
1
1
  export * from './types.js';
2
2
  export type { SelectEventDetail, OpenEventDetail, CloseEventDetail, SearchEventDetail, ChangeEventDetail, LoadMoreEventDetail, RemoveEventDetail, ErrorEventDetail, PageLoadedEventDetail, GroupedItem, RemoteConfig, Placement, Strategy, NativeSelectOptions, RendererHelpers, SelectEventsDetailMap, SelectEventName } from './types.js';
3
+ export type { CustomOptionContract, CustomOptionContext, CustomOptionFactory, ExtendedSelectItem, OptionRendererMode, CustomOptionConfig, CustomOptionEvents } from './types/custom-option.js';
3
4
  export * from './renderers/contracts.js';
4
5
  export * from './components/native-select.js';
5
6
  export * from './components/enhanced-select.js';
6
- export { AngularEnhancedSelect } from './components/angular-enhanced-select.js';
7
7
  export * from './components/select-option.js';
8
8
  export * from './config/global-config.js';
9
9
  export { FenwickTree } from './utils/fenwick-tree.js';
@@ -11,6 +11,8 @@ export { DOMPool } from './utils/dom-pool.js';
11
11
  export { WorkerManager, getWorkerManager } from './utils/worker-manager.js';
12
12
  export { PerformanceTelemetry, getTelemetry, measureAsync, measureSync } from './utils/telemetry.js';
13
13
  export { Virtualizer } from './utils/virtualizer.js';
14
+ export { OptionRenderer } from './utils/option-renderer.js';
15
+ export { CustomOptionPool } from './utils/custom-option-pool.js';
14
16
  export { setHTMLSanitizer, getHTMLSanitizer, sanitizeHTML, createElement, setCSSProperties, CSPFeatures, detectEnvironment, containsSuspiciousPatterns, escapeHTML, escapeAttribute, validateTemplate, createTextNode, setTextContent } from './utils/security.js';
15
17
  export { applyClasses, toggleClass, setCustomProperties, getCustomProperty, removeCustomProperty, defaultTheme, applyDefaultTheme, shadowDOMStyles, injectShadowStyles, hasOverflowHiddenAncestor, warnCSPViolation } from './utils/csp-styles.js';
16
18
  export type { HTMLSanitizer, EnvironmentCapabilities } from './utils/security.js';
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Custom Option Rendering System
3
+ *
4
+ * This module provides types and contracts for rendering custom framework components
5
+ * as select options, enabling deep customization while maintaining performance and cohesion.
6
+ */
7
+ /**
8
+ * Contract that custom option components must implement
9
+ *
10
+ * Custom components must expose these methods to integrate with the select system:
11
+ * - `mountOption()`: Called when the option is added to DOM
12
+ * - `unmountOption()`: Called when the option is removed from DOM
13
+ * - `updateSelected()`: Called when selection state changes
14
+ * - `getElement()`: Returns the root DOM element
15
+ */
16
+ export interface CustomOptionContract {
17
+ /**
18
+ * Mount the component into the provided container
19
+ * @param container - The DOM element to mount into
20
+ * @param context - Context data including selection state and callbacks
21
+ */
22
+ mountOption(container: HTMLElement, context: CustomOptionContext): void;
23
+ /**
24
+ * Unmount and cleanup the component
25
+ */
26
+ unmountOption(): void;
27
+ /**
28
+ * Update the component when selection state changes
29
+ * @param selected - Whether this option is currently selected
30
+ */
31
+ updateSelected(selected: boolean): void;
32
+ /**
33
+ * Get the root DOM element of the component
34
+ * @returns The root element that receives click events
35
+ */
36
+ getElement(): HTMLElement;
37
+ /**
38
+ * Optional: Handle when the option becomes focused (keyboard navigation)
39
+ * @param focused - Whether this option has keyboard focus
40
+ */
41
+ updateFocused?(focused: boolean): void;
42
+ /**
43
+ * Optional: Handle when the option becomes disabled
44
+ * @param disabled - Whether this option is disabled
45
+ */
46
+ updateDisabled?(disabled: boolean): void;
47
+ }
48
+ /**
49
+ * Context provided to custom option components
50
+ */
51
+ export interface CustomOptionContext {
52
+ /** The item data */
53
+ item: unknown;
54
+ /** The index of this option in the list */
55
+ index: number;
56
+ /** The value extracted from the item */
57
+ value: unknown;
58
+ /** The label extracted from the item */
59
+ label: string;
60
+ /** Whether this option is currently selected */
61
+ isSelected: boolean;
62
+ /** Whether this option currently has keyboard focus */
63
+ isFocused: boolean;
64
+ /** Whether the option is disabled */
65
+ isDisabled: boolean;
66
+ /** Callback to notify the select that this option was clicked */
67
+ onSelect: (index: number) => void;
68
+ /** Callback to notify custom events from the option */
69
+ onCustomEvent?: (eventName: string, data: unknown) => void;
70
+ }
71
+ /**
72
+ * Factory function signature for creating custom option instances
73
+ *
74
+ * @param item - The data item for this option
75
+ * @param index - The index in the list
76
+ * @returns A new instance implementing CustomOptionContract
77
+ */
78
+ export type CustomOptionFactory = (item: unknown, index: number) => CustomOptionContract;
79
+ /**
80
+ * Extended item type supporting custom components
81
+ *
82
+ * Items can now include:
83
+ * - Traditional: { label: string, value: any }
84
+ * - Custom Component: { label: string, value: any, optionComponent: CustomOptionFactory }
85
+ */
86
+ export interface ExtendedSelectItem {
87
+ /** Display label (still required for accessibility and fallback) */
88
+ label: string;
89
+ /** Value used for selection */
90
+ value: unknown;
91
+ /** Optional: Custom component factory for rendering this option */
92
+ optionComponent?: CustomOptionFactory;
93
+ /** Optional: Whether this option is disabled */
94
+ disabled?: boolean;
95
+ /** Any additional data */
96
+ [key: string]: unknown;
97
+ }
98
+ /**
99
+ * Renderer mode for the select component
100
+ */
101
+ export type OptionRendererMode = 'lightweight' | 'component';
102
+ /**
103
+ * Configuration for custom option rendering
104
+ */
105
+ export interface CustomOptionConfig {
106
+ /** Default renderer mode when no component specified */
107
+ defaultMode: OptionRendererMode;
108
+ /** Enable performance optimizations for component rendering */
109
+ enableVirtualization: boolean;
110
+ /** Recycle component instances when scrolling (for large lists) */
111
+ enableComponentRecycling: boolean;
112
+ /** Maximum component instances to keep in pool */
113
+ maxComponentPoolSize: number;
114
+ }
115
+ /**
116
+ * Events emitted by custom option components
117
+ */
118
+ export interface CustomOptionEvents {
119
+ /** Custom component emitted an event */
120
+ 'option:custom-event': {
121
+ index: number;
122
+ eventName: string;
123
+ data: unknown;
124
+ };
125
+ /** Component failed to mount */
126
+ 'option:mount-error': {
127
+ index: number;
128
+ error: Error;
129
+ };
130
+ /** Component lifecycle event for debugging */
131
+ 'option:lifecycle': {
132
+ index: number;
133
+ phase: 'mount' | 'unmount' | 'update';
134
+ };
135
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Custom Option Component Pool
3
+ *
4
+ * Manages lifecycle and recycling of custom option components for optimal performance.
5
+ * Uses object pooling pattern to minimize allocation/deallocation overhead.
6
+ */
7
+ import type { CustomOptionContract, CustomOptionContext, CustomOptionFactory } from '../types/custom-option';
8
+ /**
9
+ * Manages a pool of reusable custom option component instances
10
+ */
11
+ export declare class CustomOptionPool {
12
+ private _pool;
13
+ private _maxPoolSize;
14
+ private _activeComponents;
15
+ constructor(maxPoolSize?: number);
16
+ /**
17
+ * Get or create a component instance for the given index
18
+ *
19
+ * @param factory - Factory function to create new instances
20
+ * @param item - The data item
21
+ * @param index - The option index
22
+ * @param context - Context for mounting
23
+ * @param container - DOM container for mounting
24
+ * @returns Component instance
25
+ */
26
+ acquire(factory: CustomOptionFactory, item: unknown, index: number, context: CustomOptionContext, container: HTMLElement): CustomOptionContract;
27
+ /**
28
+ * Release a component back to the pool
29
+ *
30
+ * @param index - The index of the component to release
31
+ */
32
+ release(index: number): void;
33
+ /**
34
+ * Release all active components
35
+ */
36
+ releaseAll(): void;
37
+ /**
38
+ * Update selection state for a component
39
+ *
40
+ * @param index - The index of the component
41
+ * @param selected - Whether it's selected
42
+ */
43
+ updateSelection(index: number, selected: boolean): void;
44
+ /**
45
+ * Update focused state for a component
46
+ *
47
+ * @param index - The index of the component
48
+ * @param focused - Whether it has keyboard focus
49
+ */
50
+ updateFocused(index: number, focused: boolean): void;
51
+ /**
52
+ * Get active component at index
53
+ *
54
+ * @param index - The option index
55
+ * @returns The component instance or undefined
56
+ */
57
+ getComponent(index: number): CustomOptionContract | undefined;
58
+ /**
59
+ * Clear the entire pool
60
+ */
61
+ clear(): void;
62
+ /**
63
+ * Get pool statistics for debugging
64
+ */
65
+ getStats(): {
66
+ totalPooled: number;
67
+ activeComponents: number;
68
+ availableComponents: number;
69
+ };
70
+ /**
71
+ * Find an available component in the pool
72
+ */
73
+ private _findAvailableComponent;
74
+ /**
75
+ * Generate a unique key for a factory function
76
+ */
77
+ private _getFactoryKey;
78
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Option Renderer
3
+ *
4
+ * Unified renderer that handles both lightweight (label/value) and
5
+ * custom component rendering with consistent performance characteristics.
6
+ */
7
+ export interface OptionRendererConfig {
8
+ enableRecycling: boolean;
9
+ maxPoolSize: number;
10
+ getValue: (item: unknown) => unknown;
11
+ getLabel: (item: unknown) => string;
12
+ getDisabled?: (item: unknown) => boolean;
13
+ onSelect: (index: number) => void;
14
+ onCustomEvent?: (index: number, eventName: string, data: unknown) => void;
15
+ onError?: (index: number, error: Error) => void;
16
+ }
17
+ /**
18
+ * Manages rendering of both lightweight and custom component options
19
+ */
20
+ export declare class OptionRenderer {
21
+ private _config;
22
+ private _pool;
23
+ private _mountedElements;
24
+ constructor(config: OptionRendererConfig);
25
+ /**
26
+ * Render an option (lightweight or custom component)
27
+ *
28
+ * @param item - The data item
29
+ * @param index - The option index
30
+ * @param isSelected - Whether the option is selected
31
+ * @param isFocused - Whether the option has keyboard focus
32
+ * @param uniqueId - Unique ID for the select instance
33
+ * @returns The rendered DOM element
34
+ */
35
+ render(item: unknown, index: number, isSelected: boolean, isFocused: boolean, uniqueId: string): HTMLElement;
36
+ /**
37
+ * Update selection state for an option
38
+ *
39
+ * @param index - The option index
40
+ * @param selected - Whether it's selected
41
+ */
42
+ updateSelection(index: number, selected: boolean): void;
43
+ /**
44
+ * Update focused state for an option
45
+ *
46
+ * @param index - The option index
47
+ * @param focused - Whether it has keyboard focus
48
+ */
49
+ updateFocused(index: number, focused: boolean): void;
50
+ /**
51
+ * Unmount and cleanup an option
52
+ *
53
+ * @param index - The option index
54
+ */
55
+ unmount(index: number): void;
56
+ /**
57
+ * Unmount all options
58
+ */
59
+ unmountAll(): void;
60
+ /**
61
+ * Get pool statistics
62
+ */
63
+ getStats(): {
64
+ totalPooled: number;
65
+ activeComponents: number;
66
+ availableComponents: number;
67
+ };
68
+ /**
69
+ * Render a lightweight option (traditional label/value)
70
+ */
71
+ private _renderLightweightOption;
72
+ /**
73
+ * Render a custom component option
74
+ */
75
+ private _renderCustomComponent;
76
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smilodon/core",
3
- "version": "1.1.9",
3
+ "version": "1.2.1",
4
4
  "description": "High-performance native select component with extreme-scale virtualization",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",