nativecorejs 0.1.0
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 +22 -0
- package/dist/components/builtinRegistry.d.ts +2 -0
- package/dist/components/builtinRegistry.js +72 -0
- package/dist/components/index.d.ts +59 -0
- package/dist/components/index.js +59 -0
- package/dist/components/loading-spinner.d.ts +5 -0
- package/dist/components/loading-spinner.js +48 -0
- package/dist/components/nc-a.d.ts +45 -0
- package/dist/components/nc-a.js +290 -0
- package/dist/components/nc-accordion.d.ts +36 -0
- package/dist/components/nc-accordion.js +186 -0
- package/dist/components/nc-alert.d.ts +11 -0
- package/dist/components/nc-alert.js +127 -0
- package/dist/components/nc-animation.d.ts +117 -0
- package/dist/components/nc-animation.js +1053 -0
- package/dist/components/nc-autocomplete.d.ts +41 -0
- package/dist/components/nc-autocomplete.js +275 -0
- package/dist/components/nc-avatar-group.d.ts +7 -0
- package/dist/components/nc-avatar-group.js +85 -0
- package/dist/components/nc-avatar.d.ts +9 -0
- package/dist/components/nc-avatar.js +127 -0
- package/dist/components/nc-badge.d.ts +7 -0
- package/dist/components/nc-badge.js +63 -0
- package/dist/components/nc-bottom-nav.d.ts +53 -0
- package/dist/components/nc-bottom-nav.js +198 -0
- package/dist/components/nc-breadcrumb.d.ts +10 -0
- package/dist/components/nc-breadcrumb.js +71 -0
- package/dist/components/nc-button.d.ts +38 -0
- package/dist/components/nc-button.js +293 -0
- package/dist/components/nc-card.d.ts +11 -0
- package/dist/components/nc-card.js +74 -0
- package/dist/components/nc-checkbox.d.ts +16 -0
- package/dist/components/nc-checkbox.js +194 -0
- package/dist/components/nc-chip.d.ts +8 -0
- package/dist/components/nc-chip.js +89 -0
- package/dist/components/nc-code.d.ts +37 -0
- package/dist/components/nc-code.js +315 -0
- package/dist/components/nc-collapsible.d.ts +33 -0
- package/dist/components/nc-collapsible.js +148 -0
- package/dist/components/nc-color-picker.d.ts +33 -0
- package/dist/components/nc-color-picker.js +265 -0
- package/dist/components/nc-copy-button.d.ts +10 -0
- package/dist/components/nc-copy-button.js +94 -0
- package/dist/components/nc-date-picker.d.ts +41 -0
- package/dist/components/nc-date-picker.js +443 -0
- package/dist/components/nc-div.d.ts +53 -0
- package/dist/components/nc-div.js +270 -0
- package/dist/components/nc-divider.d.ts +7 -0
- package/dist/components/nc-divider.js +57 -0
- package/dist/components/nc-drawer.d.ts +40 -0
- package/dist/components/nc-drawer.js +217 -0
- package/dist/components/nc-dropdown.d.ts +41 -0
- package/dist/components/nc-dropdown.js +170 -0
- package/dist/components/nc-empty-state.d.ts +5 -0
- package/dist/components/nc-empty-state.js +76 -0
- package/dist/components/nc-file-upload.d.ts +40 -0
- package/dist/components/nc-file-upload.js +336 -0
- package/dist/components/nc-form.d.ts +70 -0
- package/dist/components/nc-form.js +273 -0
- package/dist/components/nc-image.d.ts +10 -0
- package/dist/components/nc-image.js +139 -0
- package/dist/components/nc-input.d.ts +25 -0
- package/dist/components/nc-input.js +302 -0
- package/dist/components/nc-kbd.d.ts +5 -0
- package/dist/components/nc-kbd.js +34 -0
- package/dist/components/nc-menu-item.d.ts +43 -0
- package/dist/components/nc-menu-item.js +182 -0
- package/dist/components/nc-menu.d.ts +76 -0
- package/dist/components/nc-menu.js +360 -0
- package/dist/components/nc-modal.d.ts +51 -0
- package/dist/components/nc-modal.js +231 -0
- package/dist/components/nc-nav-item.d.ts +35 -0
- package/dist/components/nc-nav-item.js +142 -0
- package/dist/components/nc-number-input.d.ts +22 -0
- package/dist/components/nc-number-input.js +270 -0
- package/dist/components/nc-otp-input.d.ts +41 -0
- package/dist/components/nc-otp-input.js +227 -0
- package/dist/components/nc-pagination.d.ts +28 -0
- package/dist/components/nc-pagination.js +171 -0
- package/dist/components/nc-popover.d.ts +58 -0
- package/dist/components/nc-popover.js +301 -0
- package/dist/components/nc-progress-circular.d.ts +7 -0
- package/dist/components/nc-progress-circular.js +67 -0
- package/dist/components/nc-progress.d.ts +7 -0
- package/dist/components/nc-progress.js +109 -0
- package/dist/components/nc-radio.d.ts +13 -0
- package/dist/components/nc-radio.js +169 -0
- package/dist/components/nc-rating.d.ts +19 -0
- package/dist/components/nc-rating.js +187 -0
- package/dist/components/nc-rich-text.d.ts +43 -0
- package/dist/components/nc-rich-text.js +310 -0
- package/dist/components/nc-scroll-top.d.ts +28 -0
- package/dist/components/nc-scroll-top.js +103 -0
- package/dist/components/nc-select.d.ts +51 -0
- package/dist/components/nc-select.js +425 -0
- package/dist/components/nc-skeleton.d.ts +7 -0
- package/dist/components/nc-skeleton.js +90 -0
- package/dist/components/nc-slider.d.ts +41 -0
- package/dist/components/nc-slider.js +268 -0
- package/dist/components/nc-snackbar.d.ts +51 -0
- package/dist/components/nc-snackbar.js +200 -0
- package/dist/components/nc-splash.d.ts +25 -0
- package/dist/components/nc-splash.js +296 -0
- package/dist/components/nc-stepper.d.ts +50 -0
- package/dist/components/nc-stepper.js +236 -0
- package/dist/components/nc-switch.d.ts +14 -0
- package/dist/components/nc-switch.js +194 -0
- package/dist/components/nc-tab-item.d.ts +39 -0
- package/dist/components/nc-tab-item.js +127 -0
- package/dist/components/nc-table.d.ts +44 -0
- package/dist/components/nc-table.js +265 -0
- package/dist/components/nc-tabs.d.ts +79 -0
- package/dist/components/nc-tabs.js +519 -0
- package/dist/components/nc-tag-input.d.ts +49 -0
- package/dist/components/nc-tag-input.js +268 -0
- package/dist/components/nc-textarea.d.ts +15 -0
- package/dist/components/nc-textarea.js +164 -0
- package/dist/components/nc-time-picker.d.ts +51 -0
- package/dist/components/nc-time-picker.js +452 -0
- package/dist/components/nc-timeline.d.ts +53 -0
- package/dist/components/nc-timeline.js +171 -0
- package/dist/components/nc-tooltip.d.ts +27 -0
- package/dist/components/nc-tooltip.js +135 -0
- package/dist/core/component.d.ts +33 -0
- package/dist/core/component.js +208 -0
- package/dist/core/gpu-animation.d.ts +141 -0
- package/dist/core/gpu-animation.js +474 -0
- package/dist/core/lazyComponents.d.ts +13 -0
- package/dist/core/lazyComponents.js +73 -0
- package/dist/core/router.d.ts +55 -0
- package/dist/core/router.js +424 -0
- package/dist/core/state.d.ts +18 -0
- package/dist/core/state.js +153 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +11 -0
- package/dist/utils/cacheBuster.d.ts +9 -0
- package/dist/utils/cacheBuster.js +12 -0
- package/dist/utils/dom.d.ts +16 -0
- package/dist/utils/dom.js +70 -0
- package/dist/utils/events.d.ts +20 -0
- package/dist/utils/events.js +80 -0
- package/dist/utils/templates.d.ts +2 -0
- package/dist/utils/templates.js +2 -0
- package/package.json +53 -0
- package/src/styles/base.css +40 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NcTooltip Component
|
|
3
|
+
*
|
|
4
|
+
* Wraps any element and shows a tooltip on hover/focus.
|
|
5
|
+
*
|
|
6
|
+
* Attributes:
|
|
7
|
+
* - tip: string - tooltip text (required)
|
|
8
|
+
* - placement: 'top'|'bottom'|'left'|'right' (default: 'top')
|
|
9
|
+
* - delay: number - ms before showing (default: 200)
|
|
10
|
+
* - variant: 'default'|'light' (default: 'default')
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* <nc-tooltip tip="Save your changes">
|
|
14
|
+
* <nc-button>Save</nc-button>
|
|
15
|
+
* </nc-tooltip>
|
|
16
|
+
*/
|
|
17
|
+
import { Component } from '../core/component.js';
|
|
18
|
+
export declare class NcTooltip extends Component {
|
|
19
|
+
static useShadowDOM: boolean;
|
|
20
|
+
static get observedAttributes(): string[];
|
|
21
|
+
private _showTimer;
|
|
22
|
+
private _visible;
|
|
23
|
+
template(): string;
|
|
24
|
+
onMount(): void;
|
|
25
|
+
onUnmount(): void;
|
|
26
|
+
attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NcTooltip Component
|
|
3
|
+
*
|
|
4
|
+
* Wraps any element and shows a tooltip on hover/focus.
|
|
5
|
+
*
|
|
6
|
+
* Attributes:
|
|
7
|
+
* - tip: string - tooltip text (required)
|
|
8
|
+
* - placement: 'top'|'bottom'|'left'|'right' (default: 'top')
|
|
9
|
+
* - delay: number - ms before showing (default: 200)
|
|
10
|
+
* - variant: 'default'|'light' (default: 'default')
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* <nc-tooltip tip="Save your changes">
|
|
14
|
+
* <nc-button>Save</nc-button>
|
|
15
|
+
* </nc-tooltip>
|
|
16
|
+
*/
|
|
17
|
+
import { Component, defineComponent } from '../core/component.js';
|
|
18
|
+
export class NcTooltip extends Component {
|
|
19
|
+
static useShadowDOM = true;
|
|
20
|
+
static get observedAttributes() {
|
|
21
|
+
return ['tip', 'placement', 'delay', 'variant'];
|
|
22
|
+
}
|
|
23
|
+
_showTimer = null;
|
|
24
|
+
_visible = false;
|
|
25
|
+
template() {
|
|
26
|
+
const placement = this.getAttribute('placement') || 'top';
|
|
27
|
+
const variant = this.getAttribute('variant') || 'default';
|
|
28
|
+
const tip = this.getAttribute('tip') || '';
|
|
29
|
+
return `
|
|
30
|
+
<style>
|
|
31
|
+
:host { display: inline-flex; position: relative; }
|
|
32
|
+
|
|
33
|
+
.tip {
|
|
34
|
+
position: absolute;
|
|
35
|
+
z-index: 9999;
|
|
36
|
+
padding: 5px 10px;
|
|
37
|
+
border-radius: var(--nc-radius-sm, 4px);
|
|
38
|
+
font-family: var(--nc-font-family);
|
|
39
|
+
font-size: var(--nc-font-size-xs);
|
|
40
|
+
line-height: 1.4;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
pointer-events: none;
|
|
43
|
+
opacity: 0;
|
|
44
|
+
transform: ${placement === 'top' ? 'translateY(4px)' : placement === 'bottom' ? 'translateY(-4px)' : placement === 'left' ? 'translateX(4px)' : 'translateX(-4px)'};
|
|
45
|
+
transition: opacity var(--nc-transition-fast), transform var(--nc-transition-fast);
|
|
46
|
+
max-width: 220px;
|
|
47
|
+
overflow-wrap: break-word;
|
|
48
|
+
white-space: normal;
|
|
49
|
+
text-align: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.tip--default { background: var(--nc-gray-900, #111); color: #fff; }
|
|
53
|
+
.tip--light { background: var(--nc-bg); color: var(--nc-text); border: 1px solid var(--nc-border); box-shadow: var(--nc-shadow-md); }
|
|
54
|
+
|
|
55
|
+
/* Placement */
|
|
56
|
+
.tip[data-placement="top"] { bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(4px); }
|
|
57
|
+
.tip[data-placement="bottom"] { top: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(-4px); }
|
|
58
|
+
.tip[data-placement="left"] { right: calc(100% + 8px); top: 50%; transform: translateY(-50%) translateX(4px); }
|
|
59
|
+
.tip[data-placement="right"] { left: calc(100% + 8px); top: 50%; transform: translateY(-50%) translateX(-4px); }
|
|
60
|
+
|
|
61
|
+
.tip.visible {
|
|
62
|
+
opacity: 1;
|
|
63
|
+
}
|
|
64
|
+
.tip[data-placement="top"].visible { transform: translateX(-50%) translateY(0); }
|
|
65
|
+
.tip[data-placement="bottom"].visible { transform: translateX(-50%) translateY(0); }
|
|
66
|
+
.tip[data-placement="left"].visible { transform: translateY(-50%) translateX(0); }
|
|
67
|
+
.tip[data-placement="right"].visible { transform: translateY(-50%) translateX(0); }
|
|
68
|
+
|
|
69
|
+
/* Arrow */
|
|
70
|
+
.tip::after {
|
|
71
|
+
content: '';
|
|
72
|
+
position: absolute;
|
|
73
|
+
border: 5px solid transparent;
|
|
74
|
+
}
|
|
75
|
+
.tip--default[data-placement="top"]::after { top: 100%; left: 50%; transform: translateX(-50%); border-top-color: var(--nc-gray-900, #111); }
|
|
76
|
+
.tip--default[data-placement="bottom"]::after { bottom: 100%; left: 50%; transform: translateX(-50%); border-bottom-color: var(--nc-gray-900, #111); }
|
|
77
|
+
.tip--default[data-placement="left"]::after { left: 100%; top: 50%; transform: translateY(-50%); border-left-color: var(--nc-gray-900, #111); }
|
|
78
|
+
.tip--default[data-placement="right"]::after { right: 100%; top: 50%; transform: translateY(-50%); border-right-color: var(--nc-gray-900, #111); }
|
|
79
|
+
|
|
80
|
+
.tip--light[data-placement="top"]::after { display: none; }
|
|
81
|
+
|
|
82
|
+
::slotted(*) { display: inline-flex; }
|
|
83
|
+
</style>
|
|
84
|
+
<slot></slot>
|
|
85
|
+
<div
|
|
86
|
+
class="tip tip--${variant}"
|
|
87
|
+
data-placement="${placement}"
|
|
88
|
+
role="tooltip"
|
|
89
|
+
aria-hidden="true"
|
|
90
|
+
>${tip}</div>
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
onMount() {
|
|
94
|
+
const tip = this.$('.tip');
|
|
95
|
+
const delay = Number(this.getAttribute('delay') ?? 200);
|
|
96
|
+
const show = () => {
|
|
97
|
+
if (this._showTimer)
|
|
98
|
+
clearTimeout(this._showTimer);
|
|
99
|
+
this._showTimer = setTimeout(() => {
|
|
100
|
+
tip.classList.add('visible');
|
|
101
|
+
tip.setAttribute('aria-hidden', 'false');
|
|
102
|
+
this._visible = true;
|
|
103
|
+
}, delay);
|
|
104
|
+
};
|
|
105
|
+
const hide = () => {
|
|
106
|
+
if (this._showTimer) {
|
|
107
|
+
clearTimeout(this._showTimer);
|
|
108
|
+
this._showTimer = null;
|
|
109
|
+
}
|
|
110
|
+
tip.classList.remove('visible');
|
|
111
|
+
tip.setAttribute('aria-hidden', 'true');
|
|
112
|
+
this._visible = false;
|
|
113
|
+
};
|
|
114
|
+
this.addEventListener('mouseenter', show);
|
|
115
|
+
this.addEventListener('mouseleave', hide);
|
|
116
|
+
this.addEventListener('focusin', show);
|
|
117
|
+
this.addEventListener('focusout', hide);
|
|
118
|
+
// Hide on Escape
|
|
119
|
+
this.addEventListener('keydown', (e) => {
|
|
120
|
+
if (e.key === 'Escape' && this._visible)
|
|
121
|
+
hide();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
onUnmount() {
|
|
125
|
+
if (this._showTimer)
|
|
126
|
+
clearTimeout(this._showTimer);
|
|
127
|
+
}
|
|
128
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
129
|
+
if (oldValue !== newValue && this._mounted) {
|
|
130
|
+
this.render();
|
|
131
|
+
this.onMount();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
defineComponent('nc-tooltip', NcTooltip);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface ComponentState {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
}
|
|
4
|
+
export interface ComponentConstructor {
|
|
5
|
+
useShadowDOM?: boolean;
|
|
6
|
+
observedAttributes?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare class Component extends HTMLElement {
|
|
9
|
+
state: ComponentState;
|
|
10
|
+
protected _mounted: boolean;
|
|
11
|
+
shadowRoot: ShadowRoot | null;
|
|
12
|
+
static useShadowDOM?: boolean;
|
|
13
|
+
static observedAttributes?: string[];
|
|
14
|
+
constructor();
|
|
15
|
+
connectedCallback(): void;
|
|
16
|
+
disconnectedCallback(): void;
|
|
17
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
18
|
+
setState(newState: Partial<ComponentState>): void;
|
|
19
|
+
getState(): ComponentState;
|
|
20
|
+
render(): void;
|
|
21
|
+
template(): string;
|
|
22
|
+
onMount(): void;
|
|
23
|
+
onUnmount(): void;
|
|
24
|
+
onAttributeChange(_name: string, _oldValue: string | null, _newValue: string | null): void;
|
|
25
|
+
$<E extends Element = Element>(selector: string): E | null;
|
|
26
|
+
$$<E extends Element = Element>(selector: string): NodeListOf<E>;
|
|
27
|
+
on<K extends keyof HTMLElementEventMap>(event: K, handler: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): void;
|
|
28
|
+
on<K extends keyof HTMLElementEventMap>(event: K, selector: string, handler: (this: Element, ev: HTMLElementEventMap[K]) => any): void;
|
|
29
|
+
emitEvent<T = any>(eventName: string, detail?: T, options?: Partial<CustomEventInit<T>>): boolean;
|
|
30
|
+
attr(name: string, defaultValue?: string | null): string | null;
|
|
31
|
+
setAttr(name: string, value: string): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function defineComponent<T extends CustomElementConstructor>(tagName: string, componentClass: T): void;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
export class Component extends HTMLElement {
|
|
2
|
+
state;
|
|
3
|
+
_mounted;
|
|
4
|
+
shadowRoot;
|
|
5
|
+
static useShadowDOM;
|
|
6
|
+
static observedAttributes;
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
this.state = {};
|
|
10
|
+
this._mounted = false;
|
|
11
|
+
const constructor = this.constructor;
|
|
12
|
+
if (constructor.useShadowDOM) {
|
|
13
|
+
this.attachShadow({ mode: 'open' });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
connectedCallback() {
|
|
17
|
+
try {
|
|
18
|
+
this.render();
|
|
19
|
+
this.onMount();
|
|
20
|
+
this._mounted = true;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error(`Error rendering ${this.tagName.toLowerCase()}:`, error);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
disconnectedCallback() {
|
|
27
|
+
this.onUnmount();
|
|
28
|
+
this._mounted = false;
|
|
29
|
+
}
|
|
30
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
31
|
+
if (oldValue !== newValue && this._mounted) {
|
|
32
|
+
this.onAttributeChange(name, oldValue, newValue);
|
|
33
|
+
this.render();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
setState(newState) {
|
|
37
|
+
this.state = { ...this.state, ...newState };
|
|
38
|
+
if (this._mounted) {
|
|
39
|
+
this.render();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
getState() {
|
|
43
|
+
return { ...this.state };
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
const html = this.template();
|
|
47
|
+
const target = this.shadowRoot ?? this;
|
|
48
|
+
patchHTML(target, html);
|
|
49
|
+
}
|
|
50
|
+
template() {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
onMount() {
|
|
54
|
+
}
|
|
55
|
+
onUnmount() {
|
|
56
|
+
}
|
|
57
|
+
onAttributeChange(_name, _oldValue, _newValue) {
|
|
58
|
+
}
|
|
59
|
+
$(selector) {
|
|
60
|
+
return this.shadowRoot
|
|
61
|
+
? this.shadowRoot.querySelector(selector)
|
|
62
|
+
: this.querySelector(selector);
|
|
63
|
+
}
|
|
64
|
+
$$(selector) {
|
|
65
|
+
return this.shadowRoot
|
|
66
|
+
? this.shadowRoot.querySelectorAll(selector)
|
|
67
|
+
: this.querySelectorAll(selector);
|
|
68
|
+
}
|
|
69
|
+
on(event, selectorOrHandler, handler) {
|
|
70
|
+
if (typeof selectorOrHandler === 'function') {
|
|
71
|
+
this.addEventListener(event, selectorOrHandler);
|
|
72
|
+
}
|
|
73
|
+
else if (handler) {
|
|
74
|
+
this.addEventListener(event, ((e) => {
|
|
75
|
+
const target = e.target;
|
|
76
|
+
if (target.matches(selectorOrHandler)) {
|
|
77
|
+
handler.call(target, e);
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
emitEvent(eventName, detail = {}, options = {}) {
|
|
83
|
+
const event = new CustomEvent(eventName, {
|
|
84
|
+
detail,
|
|
85
|
+
bubbles: options.bubbles !== undefined ? options.bubbles : true,
|
|
86
|
+
composed: options.composed !== undefined ? options.composed : true,
|
|
87
|
+
cancelable: options.cancelable !== undefined ? options.cancelable : false
|
|
88
|
+
});
|
|
89
|
+
return this.dispatchEvent(event);
|
|
90
|
+
}
|
|
91
|
+
attr(name, defaultValue = null) {
|
|
92
|
+
return this.getAttribute(name) || defaultValue;
|
|
93
|
+
}
|
|
94
|
+
setAttr(name, value) {
|
|
95
|
+
this.setAttribute(name, value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function patchHTML(target, html) {
|
|
99
|
+
const range = document.createRange();
|
|
100
|
+
range.selectNodeContents(target);
|
|
101
|
+
const fragment = range.createContextualFragment(html);
|
|
102
|
+
reconcileChildren(target, fragment);
|
|
103
|
+
}
|
|
104
|
+
function reconcileChildren(target, source) {
|
|
105
|
+
const currentNodes = Array.from(target.childNodes);
|
|
106
|
+
const nextNodes = Array.from(source.childNodes);
|
|
107
|
+
const maxLength = Math.max(currentNodes.length, nextNodes.length);
|
|
108
|
+
for (let index = 0; index < maxLength; index++) {
|
|
109
|
+
const currentNode = currentNodes[index];
|
|
110
|
+
const nextNode = nextNodes[index];
|
|
111
|
+
if (!currentNode && nextNode) {
|
|
112
|
+
target.appendChild(nextNode);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (currentNode && !nextNode) {
|
|
116
|
+
currentNode.remove();
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (currentNode && nextNode) {
|
|
120
|
+
reconcileNode(currentNode, nextNode);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function reconcileNode(currentNode, nextNode) {
|
|
125
|
+
const parent = currentNode.parentNode;
|
|
126
|
+
if (!parent)
|
|
127
|
+
return;
|
|
128
|
+
if (!canPatchNode(currentNode, nextNode)) {
|
|
129
|
+
parent.replaceChild(nextNode, currentNode);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (currentNode.nodeType === Node.TEXT_NODE || currentNode.nodeType === Node.COMMENT_NODE) {
|
|
133
|
+
if (currentNode.textContent !== nextNode.textContent) {
|
|
134
|
+
currentNode.textContent = nextNode.textContent;
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const currentElement = currentNode;
|
|
139
|
+
const nextElement = nextNode;
|
|
140
|
+
syncAttributes(currentElement, nextElement);
|
|
141
|
+
syncFormControlState(currentElement, nextElement);
|
|
142
|
+
reconcileChildren(currentElement, nextElement);
|
|
143
|
+
}
|
|
144
|
+
function canPatchNode(currentNode, nextNode) {
|
|
145
|
+
if (currentNode.nodeType !== nextNode.nodeType) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
if (currentNode.nodeType !== Node.ELEMENT_NODE) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
return currentNode.tagName === nextNode.tagName;
|
|
152
|
+
}
|
|
153
|
+
function syncAttributes(currentElement, nextElement) {
|
|
154
|
+
const currentAttributes = Array.from(currentElement.attributes);
|
|
155
|
+
const nextAttributes = Array.from(nextElement.attributes);
|
|
156
|
+
currentAttributes.forEach(attribute => {
|
|
157
|
+
if (!nextElement.hasAttribute(attribute.name)) {
|
|
158
|
+
currentElement.removeAttribute(attribute.name);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
nextAttributes.forEach(attribute => {
|
|
162
|
+
if (currentElement.getAttribute(attribute.name) !== attribute.value) {
|
|
163
|
+
currentElement.setAttribute(attribute.name, attribute.value);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function syncFormControlState(currentElement, nextElement) {
|
|
168
|
+
if (currentElement instanceof HTMLInputElement && nextElement instanceof HTMLInputElement) {
|
|
169
|
+
syncInputElement(currentElement, nextElement);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (currentElement instanceof HTMLTextAreaElement && nextElement instanceof HTMLTextAreaElement) {
|
|
173
|
+
if (!isFocusedElement(currentElement) && currentElement.value !== nextElement.value) {
|
|
174
|
+
currentElement.value = nextElement.value;
|
|
175
|
+
}
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (currentElement instanceof HTMLSelectElement && nextElement instanceof HTMLSelectElement) {
|
|
179
|
+
if (!isFocusedElement(currentElement) && currentElement.value !== nextElement.value) {
|
|
180
|
+
currentElement.value = nextElement.value;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function syncInputElement(currentElement, nextElement) {
|
|
185
|
+
if (currentElement.type === 'checkbox' || currentElement.type === 'radio') {
|
|
186
|
+
currentElement.checked = nextElement.checked;
|
|
187
|
+
}
|
|
188
|
+
if (!isFocusedElement(currentElement) && currentElement.value !== nextElement.value) {
|
|
189
|
+
currentElement.value = nextElement.value;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function isFocusedElement(element) {
|
|
193
|
+
const root = element.getRootNode();
|
|
194
|
+
if (root instanceof ShadowRoot) {
|
|
195
|
+
return root.activeElement === element;
|
|
196
|
+
}
|
|
197
|
+
return element.ownerDocument?.activeElement === element;
|
|
198
|
+
}
|
|
199
|
+
export function defineComponent(tagName, componentClass) {
|
|
200
|
+
try {
|
|
201
|
+
if (!customElements.get(tagName)) {
|
|
202
|
+
customElements.define(tagName, componentClass);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
console.error(`Error defining ${tagName}:`, error);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GPU Animation Utilities
|
|
3
|
+
*
|
|
4
|
+
* High-performance animation primitives that leverage:
|
|
5
|
+
* - CSS transforms (GPU composited)
|
|
6
|
+
* - CSS custom properties for dynamic values
|
|
7
|
+
* - Web Animations API for smooth interpolation
|
|
8
|
+
* - RequestAnimationFrame with delta time
|
|
9
|
+
* - Passive event listeners
|
|
10
|
+
* - will-change optimization
|
|
11
|
+
* - contain property for layout isolation
|
|
12
|
+
*
|
|
13
|
+
* These utilities make NativeCore animations outperform other frameworks
|
|
14
|
+
* by maximizing GPU utilization and minimizing main thread work.
|
|
15
|
+
*/
|
|
16
|
+
export interface AnimationOptions {
|
|
17
|
+
duration?: number;
|
|
18
|
+
easing?: string;
|
|
19
|
+
delay?: number;
|
|
20
|
+
fill?: FillMode;
|
|
21
|
+
iterations?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ParticleConfig {
|
|
24
|
+
count: number;
|
|
25
|
+
colors?: string[];
|
|
26
|
+
size?: {
|
|
27
|
+
min: number;
|
|
28
|
+
max: number;
|
|
29
|
+
};
|
|
30
|
+
speed?: {
|
|
31
|
+
min: number;
|
|
32
|
+
max: number;
|
|
33
|
+
};
|
|
34
|
+
type?: 'shower' | 'burst' | 'float' | 'spiral' | 'explode' | 'converge' | 'electricity' | 'fire' | 'ripple' | 'firework' | 'explosion';
|
|
35
|
+
}
|
|
36
|
+
export interface Particle {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
vx: number;
|
|
40
|
+
vy: number;
|
|
41
|
+
size: number;
|
|
42
|
+
color: string;
|
|
43
|
+
alpha: number;
|
|
44
|
+
angle: number;
|
|
45
|
+
life: number;
|
|
46
|
+
maxLife: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Apply GPU-accelerated transform using translate3d
|
|
50
|
+
* translate3d forces GPU layer creation even for 2D transforms
|
|
51
|
+
*/
|
|
52
|
+
export declare function setGPUTransform(element: HTMLElement, x: number, y: number, z?: number, scale?: number, rotate?: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Apply transform using CSS custom properties
|
|
55
|
+
* This allows CSS transitions to handle the animation on GPU
|
|
56
|
+
*/
|
|
57
|
+
export declare function setTransformVars(element: HTMLElement, vars: Record<string, string | number>): void;
|
|
58
|
+
/**
|
|
59
|
+
* Prepare element for GPU animation with proper hints
|
|
60
|
+
*/
|
|
61
|
+
export declare function prepareForAnimation(element: HTMLElement, properties?: string[]): void;
|
|
62
|
+
/**
|
|
63
|
+
* Clean up animation hints to free GPU memory
|
|
64
|
+
*/
|
|
65
|
+
export declare function cleanupAnimation(element: HTMLElement): void;
|
|
66
|
+
/**
|
|
67
|
+
* Animate using Web Animations API (GPU accelerated)
|
|
68
|
+
* Returns a Promise that resolves when animation completes
|
|
69
|
+
*/
|
|
70
|
+
export declare function animate(element: HTMLElement, keyframes: Keyframe[], options?: AnimationOptions): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* GPU-accelerated fade animation
|
|
73
|
+
*/
|
|
74
|
+
export declare function fadeIn(element: HTMLElement, duration?: number): Promise<void>;
|
|
75
|
+
export declare function fadeOut(element: HTMLElement, duration?: number): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* GPU-accelerated slide animation
|
|
78
|
+
*/
|
|
79
|
+
export declare function slideIn(element: HTMLElement, direction?: 'up' | 'down' | 'left' | 'right', distance?: number, duration?: number): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* GPU-accelerated scale animation
|
|
82
|
+
*/
|
|
83
|
+
export declare function scaleIn(element: HTMLElement, duration?: number): Promise<void>;
|
|
84
|
+
export interface AnimationLoop {
|
|
85
|
+
start: () => void;
|
|
86
|
+
stop: () => void;
|
|
87
|
+
isRunning: () => boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Create a high-performance animation loop with delta time
|
|
91
|
+
* Automatically handles frame timing and cleanup
|
|
92
|
+
*/
|
|
93
|
+
export declare function createAnimationLoop(callback: (deltaTime: number, elapsed: number) => boolean | void): AnimationLoop;
|
|
94
|
+
/**
|
|
95
|
+
* Create a WebGL-based particle system for thousands of particles
|
|
96
|
+
* Uses vertex shaders for GPU-computed positions
|
|
97
|
+
*/
|
|
98
|
+
export declare function createWebGLParticleSystem(canvas: HTMLCanvasElement, config: ParticleConfig): {
|
|
99
|
+
start: () => void;
|
|
100
|
+
stop: () => void;
|
|
101
|
+
destroy: () => void;
|
|
102
|
+
} | null;
|
|
103
|
+
/**
|
|
104
|
+
* Inject keyframe animation into document (once)
|
|
105
|
+
* These run entirely on GPU via compositor
|
|
106
|
+
*/
|
|
107
|
+
export declare function injectKeyframes(name: string, keyframes: string): void;
|
|
108
|
+
/**
|
|
109
|
+
* Common GPU-accelerated keyframe animations
|
|
110
|
+
*/
|
|
111
|
+
export declare function injectCommonAnimations(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Add passive event listener for scroll/touch performance
|
|
114
|
+
*/
|
|
115
|
+
export declare function addPassiveListener(element: HTMLElement | Window, event: string, handler: EventListener): () => void;
|
|
116
|
+
/**
|
|
117
|
+
* Throttle function for scroll/resize handlers
|
|
118
|
+
*/
|
|
119
|
+
export declare function throttle<T extends (...args: any[]) => void>(fn: T, limit: number): T;
|
|
120
|
+
/**
|
|
121
|
+
* RAF-based throttle for smooth animations
|
|
122
|
+
*/
|
|
123
|
+
export declare function rafThrottle<T extends (...args: any[]) => void>(fn: T): T;
|
|
124
|
+
export declare const GPUAnimation: {
|
|
125
|
+
setGPUTransform: typeof setGPUTransform;
|
|
126
|
+
setTransformVars: typeof setTransformVars;
|
|
127
|
+
prepareForAnimation: typeof prepareForAnimation;
|
|
128
|
+
cleanupAnimation: typeof cleanupAnimation;
|
|
129
|
+
animate: typeof animate;
|
|
130
|
+
fadeIn: typeof fadeIn;
|
|
131
|
+
fadeOut: typeof fadeOut;
|
|
132
|
+
slideIn: typeof slideIn;
|
|
133
|
+
scaleIn: typeof scaleIn;
|
|
134
|
+
createAnimationLoop: typeof createAnimationLoop;
|
|
135
|
+
createWebGLParticleSystem: typeof createWebGLParticleSystem;
|
|
136
|
+
injectKeyframes: typeof injectKeyframes;
|
|
137
|
+
injectCommonAnimations: typeof injectCommonAnimations;
|
|
138
|
+
addPassiveListener: typeof addPassiveListener;
|
|
139
|
+
throttle: typeof throttle;
|
|
140
|
+
rafThrottle: typeof rafThrottle;
|
|
141
|
+
};
|