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.
Files changed (145) hide show
  1. package/README.md +22 -0
  2. package/dist/components/builtinRegistry.d.ts +2 -0
  3. package/dist/components/builtinRegistry.js +72 -0
  4. package/dist/components/index.d.ts +59 -0
  5. package/dist/components/index.js +59 -0
  6. package/dist/components/loading-spinner.d.ts +5 -0
  7. package/dist/components/loading-spinner.js +48 -0
  8. package/dist/components/nc-a.d.ts +45 -0
  9. package/dist/components/nc-a.js +290 -0
  10. package/dist/components/nc-accordion.d.ts +36 -0
  11. package/dist/components/nc-accordion.js +186 -0
  12. package/dist/components/nc-alert.d.ts +11 -0
  13. package/dist/components/nc-alert.js +127 -0
  14. package/dist/components/nc-animation.d.ts +117 -0
  15. package/dist/components/nc-animation.js +1053 -0
  16. package/dist/components/nc-autocomplete.d.ts +41 -0
  17. package/dist/components/nc-autocomplete.js +275 -0
  18. package/dist/components/nc-avatar-group.d.ts +7 -0
  19. package/dist/components/nc-avatar-group.js +85 -0
  20. package/dist/components/nc-avatar.d.ts +9 -0
  21. package/dist/components/nc-avatar.js +127 -0
  22. package/dist/components/nc-badge.d.ts +7 -0
  23. package/dist/components/nc-badge.js +63 -0
  24. package/dist/components/nc-bottom-nav.d.ts +53 -0
  25. package/dist/components/nc-bottom-nav.js +198 -0
  26. package/dist/components/nc-breadcrumb.d.ts +10 -0
  27. package/dist/components/nc-breadcrumb.js +71 -0
  28. package/dist/components/nc-button.d.ts +38 -0
  29. package/dist/components/nc-button.js +293 -0
  30. package/dist/components/nc-card.d.ts +11 -0
  31. package/dist/components/nc-card.js +74 -0
  32. package/dist/components/nc-checkbox.d.ts +16 -0
  33. package/dist/components/nc-checkbox.js +194 -0
  34. package/dist/components/nc-chip.d.ts +8 -0
  35. package/dist/components/nc-chip.js +89 -0
  36. package/dist/components/nc-code.d.ts +37 -0
  37. package/dist/components/nc-code.js +315 -0
  38. package/dist/components/nc-collapsible.d.ts +33 -0
  39. package/dist/components/nc-collapsible.js +148 -0
  40. package/dist/components/nc-color-picker.d.ts +33 -0
  41. package/dist/components/nc-color-picker.js +265 -0
  42. package/dist/components/nc-copy-button.d.ts +10 -0
  43. package/dist/components/nc-copy-button.js +94 -0
  44. package/dist/components/nc-date-picker.d.ts +41 -0
  45. package/dist/components/nc-date-picker.js +443 -0
  46. package/dist/components/nc-div.d.ts +53 -0
  47. package/dist/components/nc-div.js +270 -0
  48. package/dist/components/nc-divider.d.ts +7 -0
  49. package/dist/components/nc-divider.js +57 -0
  50. package/dist/components/nc-drawer.d.ts +40 -0
  51. package/dist/components/nc-drawer.js +217 -0
  52. package/dist/components/nc-dropdown.d.ts +41 -0
  53. package/dist/components/nc-dropdown.js +170 -0
  54. package/dist/components/nc-empty-state.d.ts +5 -0
  55. package/dist/components/nc-empty-state.js +76 -0
  56. package/dist/components/nc-file-upload.d.ts +40 -0
  57. package/dist/components/nc-file-upload.js +336 -0
  58. package/dist/components/nc-form.d.ts +70 -0
  59. package/dist/components/nc-form.js +273 -0
  60. package/dist/components/nc-image.d.ts +10 -0
  61. package/dist/components/nc-image.js +139 -0
  62. package/dist/components/nc-input.d.ts +25 -0
  63. package/dist/components/nc-input.js +302 -0
  64. package/dist/components/nc-kbd.d.ts +5 -0
  65. package/dist/components/nc-kbd.js +34 -0
  66. package/dist/components/nc-menu-item.d.ts +43 -0
  67. package/dist/components/nc-menu-item.js +182 -0
  68. package/dist/components/nc-menu.d.ts +76 -0
  69. package/dist/components/nc-menu.js +360 -0
  70. package/dist/components/nc-modal.d.ts +51 -0
  71. package/dist/components/nc-modal.js +231 -0
  72. package/dist/components/nc-nav-item.d.ts +35 -0
  73. package/dist/components/nc-nav-item.js +142 -0
  74. package/dist/components/nc-number-input.d.ts +22 -0
  75. package/dist/components/nc-number-input.js +270 -0
  76. package/dist/components/nc-otp-input.d.ts +41 -0
  77. package/dist/components/nc-otp-input.js +227 -0
  78. package/dist/components/nc-pagination.d.ts +28 -0
  79. package/dist/components/nc-pagination.js +171 -0
  80. package/dist/components/nc-popover.d.ts +58 -0
  81. package/dist/components/nc-popover.js +301 -0
  82. package/dist/components/nc-progress-circular.d.ts +7 -0
  83. package/dist/components/nc-progress-circular.js +67 -0
  84. package/dist/components/nc-progress.d.ts +7 -0
  85. package/dist/components/nc-progress.js +109 -0
  86. package/dist/components/nc-radio.d.ts +13 -0
  87. package/dist/components/nc-radio.js +169 -0
  88. package/dist/components/nc-rating.d.ts +19 -0
  89. package/dist/components/nc-rating.js +187 -0
  90. package/dist/components/nc-rich-text.d.ts +43 -0
  91. package/dist/components/nc-rich-text.js +310 -0
  92. package/dist/components/nc-scroll-top.d.ts +28 -0
  93. package/dist/components/nc-scroll-top.js +103 -0
  94. package/dist/components/nc-select.d.ts +51 -0
  95. package/dist/components/nc-select.js +425 -0
  96. package/dist/components/nc-skeleton.d.ts +7 -0
  97. package/dist/components/nc-skeleton.js +90 -0
  98. package/dist/components/nc-slider.d.ts +41 -0
  99. package/dist/components/nc-slider.js +268 -0
  100. package/dist/components/nc-snackbar.d.ts +51 -0
  101. package/dist/components/nc-snackbar.js +200 -0
  102. package/dist/components/nc-splash.d.ts +25 -0
  103. package/dist/components/nc-splash.js +296 -0
  104. package/dist/components/nc-stepper.d.ts +50 -0
  105. package/dist/components/nc-stepper.js +236 -0
  106. package/dist/components/nc-switch.d.ts +14 -0
  107. package/dist/components/nc-switch.js +194 -0
  108. package/dist/components/nc-tab-item.d.ts +39 -0
  109. package/dist/components/nc-tab-item.js +127 -0
  110. package/dist/components/nc-table.d.ts +44 -0
  111. package/dist/components/nc-table.js +265 -0
  112. package/dist/components/nc-tabs.d.ts +79 -0
  113. package/dist/components/nc-tabs.js +519 -0
  114. package/dist/components/nc-tag-input.d.ts +49 -0
  115. package/dist/components/nc-tag-input.js +268 -0
  116. package/dist/components/nc-textarea.d.ts +15 -0
  117. package/dist/components/nc-textarea.js +164 -0
  118. package/dist/components/nc-time-picker.d.ts +51 -0
  119. package/dist/components/nc-time-picker.js +452 -0
  120. package/dist/components/nc-timeline.d.ts +53 -0
  121. package/dist/components/nc-timeline.js +171 -0
  122. package/dist/components/nc-tooltip.d.ts +27 -0
  123. package/dist/components/nc-tooltip.js +135 -0
  124. package/dist/core/component.d.ts +33 -0
  125. package/dist/core/component.js +208 -0
  126. package/dist/core/gpu-animation.d.ts +141 -0
  127. package/dist/core/gpu-animation.js +474 -0
  128. package/dist/core/lazyComponents.d.ts +13 -0
  129. package/dist/core/lazyComponents.js +73 -0
  130. package/dist/core/router.d.ts +55 -0
  131. package/dist/core/router.js +424 -0
  132. package/dist/core/state.d.ts +18 -0
  133. package/dist/core/state.js +153 -0
  134. package/dist/index.d.ts +14 -0
  135. package/dist/index.js +11 -0
  136. package/dist/utils/cacheBuster.d.ts +9 -0
  137. package/dist/utils/cacheBuster.js +12 -0
  138. package/dist/utils/dom.d.ts +16 -0
  139. package/dist/utils/dom.js +70 -0
  140. package/dist/utils/events.d.ts +20 -0
  141. package/dist/utils/events.js +80 -0
  142. package/dist/utils/templates.d.ts +2 -0
  143. package/dist/utils/templates.js +2 -0
  144. package/package.json +53 -0
  145. package/src/styles/base.css +40 -0
@@ -0,0 +1,198 @@
1
+ /**
2
+ * NcBottomNav Component - mobile bottom navigation bar
3
+ *
4
+ * Container for nc-nav-bottom-item children. Handles active state management.
5
+ * Designed for mobile viewports but works on all sizes.
6
+ *
7
+ * Attributes:
8
+ * value - currently active tab value
9
+ * variant - 'default'|'labeled'|'icon-only' (default: 'labeled')
10
+ * elevated - boolean - add drop shadow / elevated appearance
11
+ * bordered - boolean - top border (default: true)
12
+ *
13
+ * Slots:
14
+ * (default) - nc-bottom-nav-item elements
15
+ *
16
+ * Events:
17
+ * change - CustomEvent<{ value: string }> - tab changed
18
+ *
19
+ * Usage:
20
+ * <nc-bottom-nav value="home">
21
+ * <nc-bottom-nav-item value="home" icon="home" label="Home"></nc-bottom-nav-item>
22
+ * <nc-bottom-nav-item value="search" icon="search" label="Search"></nc-bottom-nav-item>
23
+ * <nc-bottom-nav-item value="inbox" icon="inbox" label="Inbox" badge="3"></nc-bottom-nav-item>
24
+ * <nc-bottom-nav-item value="me" icon="users" label="Me"></nc-bottom-nav-item>
25
+ * </nc-bottom-nav>
26
+ */
27
+ /**
28
+ * NcBottomNavItem Component - individual tab in a bottom nav bar
29
+ *
30
+ * Attributes:
31
+ * value - unique identifier for this tab
32
+ * label - tab label text
33
+ * icon - icon name (same set as nc-nav-item)
34
+ * badge - numeric badge count
35
+ * disabled - boolean
36
+ * active - boolean (managed by parent nc-bottom-nav)
37
+ */
38
+ import { Component, defineComponent } from '../core/component.js';
39
+ // Shared icon paths with nc-nav-item
40
+ const NAV_ICONS = {
41
+ home: `<path d="M3 9.5L12 3l9 6.5V20a1 1 0 0 1-1 1H14v-5h-4v5H4a1 1 0 0 1-1-1V9.5z"/>`,
42
+ search: `<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>`,
43
+ inbox: `<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>`,
44
+ users: `<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>`,
45
+ heart: `<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/>`,
46
+ bookmark: `<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/>`,
47
+ settings: `<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>`,
48
+ chart: `<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>`,
49
+ bell: `<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>`,
50
+ };
51
+ const svgWrap = (p) => `<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${p}</svg>`;
52
+ // ── NcBottomNavItem ───────────────────────────────────────────────────────────
53
+ export class NcBottomNavItem extends Component {
54
+ static useShadowDOM = true;
55
+ static get observedAttributes() { return ['active', 'badge', 'disabled']; }
56
+ template() {
57
+ const value = this.getAttribute('value') ?? '';
58
+ const label = this.getAttribute('label') ?? '';
59
+ const iconName = this.getAttribute('icon') ?? '';
60
+ const active = this.hasAttribute('active');
61
+ const disabled = this.hasAttribute('disabled');
62
+ const badge = this.getAttribute('badge') ?? '';
63
+ const iconOnly = this.closest('nc-bottom-nav')?.getAttribute('variant') === 'icon-only';
64
+ const iconHtml = NAV_ICONS[iconName] ? svgWrap(NAV_ICONS[iconName]) : '';
65
+ return `
66
+ <style>
67
+ :host { display: flex; flex: 1; }
68
+ button {
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ justify-content: center;
73
+ gap: 2px;
74
+ flex: 1;
75
+ padding: 6px 4px 8px;
76
+ background: none;
77
+ border: none;
78
+ cursor: ${disabled ? 'not-allowed' : 'pointer'};
79
+ opacity: ${disabled ? 0.4 : 1};
80
+ font-family: var(--nc-font-family);
81
+ font-size: 10px;
82
+ font-weight: var(--nc-font-weight-medium);
83
+ color: ${active ? 'var(--nc-primary)' : 'var(--nc-text-muted)'};
84
+ outline: none;
85
+ transition: color var(--nc-transition-fast);
86
+ position: relative;
87
+ min-width: 48px;
88
+ user-select: none;
89
+ }
90
+ button:focus-visible { color: var(--nc-primary); }
91
+ .icon-wrap {
92
+ position: relative;
93
+ display: flex;
94
+ }
95
+ .icon-wrap svg {
96
+ transition: transform var(--nc-transition-fast);
97
+ ${active ? 'transform: translateY(-1px) scale(1.05);' : ''}
98
+ }
99
+ .badge {
100
+ position: absolute;
101
+ top: -5px;
102
+ right: -8px;
103
+ background: var(--nc-danger);
104
+ color: #fff;
105
+ font-size: 9px;
106
+ font-weight: 700;
107
+ min-width: 16px;
108
+ height: 16px;
109
+ border-radius: 99px;
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ padding: 0 4px;
114
+ line-height: 1;
115
+ border: 1.5px solid var(--nc-bg-elevated, #fff);
116
+ }
117
+ </style>
118
+ <button type="button" ${disabled ? 'disabled' : ''} aria-label="${label}" aria-current="${active ? 'page' : 'false'}" data-value="${value}">
119
+ <span class="icon-wrap">
120
+ ${iconHtml}
121
+ <slot name="icon"></slot>
122
+ ${badge ? `<span class="badge">${badge}</span>` : ''}
123
+ </span>
124
+ ${!iconOnly && label ? `<span>${label}</span>` : ''}
125
+ </button>
126
+ `;
127
+ }
128
+ onMount() {
129
+ this.shadowRoot.addEventListener('click', () => {
130
+ if (this.hasAttribute('disabled'))
131
+ return;
132
+ this.dispatchEvent(new CustomEvent('_item-click', {
133
+ detail: { value: this.getAttribute('value') },
134
+ bubbles: true, composed: true,
135
+ }));
136
+ });
137
+ }
138
+ attributeChangedCallback(n, o, v) {
139
+ if (o !== v && this._mounted)
140
+ this.render();
141
+ }
142
+ }
143
+ defineComponent('nc-bottom-nav-item', NcBottomNavItem);
144
+ // ── NcBottomNav ───────────────────────────────────────────────────────────────
145
+ export class NcBottomNav extends Component {
146
+ static useShadowDOM = true;
147
+ static get observedAttributes() { return ['value']; }
148
+ template() {
149
+ const elevated = this.hasAttribute('elevated');
150
+ const bordered = !this.hasAttribute('no-border');
151
+ return `
152
+ <style>
153
+ :host { display: block; }
154
+ nav {
155
+ display: flex;
156
+ align-items: stretch;
157
+ background: var(--nc-bg-elevated, var(--nc-bg));
158
+ ${bordered ? 'border-top: 1px solid var(--nc-border);' : ''}
159
+ ${elevated ? 'box-shadow: 0 -2px 12px rgba(0,0,0,.08);' : ''}
160
+ safe-area-inset-bottom: env(safe-area-inset-bottom);
161
+ padding-bottom: env(safe-area-inset-bottom);
162
+ }
163
+ </style>
164
+ <nav role="navigation" aria-label="Bottom navigation">
165
+ <slot></slot>
166
+ </nav>
167
+ `;
168
+ }
169
+ onMount() {
170
+ this.addEventListener('_item-click', (e) => {
171
+ const ce = e;
172
+ const newValue = ce.detail.value;
173
+ this._setActive(newValue);
174
+ this.dispatchEvent(new CustomEvent('change', {
175
+ detail: { value: newValue }, bubbles: true, composed: true,
176
+ }));
177
+ });
178
+ // Set initial active state
179
+ const initial = this.getAttribute('value');
180
+ if (initial)
181
+ this._setActive(initial);
182
+ }
183
+ _setActive(value) {
184
+ this.setAttribute('value', value);
185
+ const items = this.querySelectorAll('nc-bottom-nav-item');
186
+ items.forEach(item => {
187
+ if (item.getAttribute('value') === value)
188
+ item.setAttribute('active', '');
189
+ else
190
+ item.removeAttribute('active');
191
+ });
192
+ }
193
+ attributeChangedCallback(n, o, v) {
194
+ if (n === 'value' && o !== v && this._mounted)
195
+ this._setActive(v);
196
+ }
197
+ }
198
+ defineComponent('nc-bottom-nav', NcBottomNav);
@@ -0,0 +1,10 @@
1
+ import { Component } from '../core/component.js';
2
+ export declare class NcBreadcrumb extends Component {
3
+ static useShadowDOM: boolean;
4
+ static get observedAttributes(): string[];
5
+ template(): string;
6
+ onMount(): void;
7
+ onUnmount(): void;
8
+ private insertSeparators;
9
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
10
+ }
@@ -0,0 +1,71 @@
1
+ import { Component, defineComponent } from '../core/component.js';
2
+ export class NcBreadcrumb extends Component {
3
+ static useShadowDOM = true;
4
+ static get observedAttributes() {
5
+ return ['separator'];
6
+ }
7
+ template() {
8
+ return `
9
+ <style>
10
+ :host { display: block; font-family: var(--nc-font-family); }
11
+
12
+ nav { display: flex; align-items: center; flex-wrap: wrap; gap: 2px; }
13
+
14
+ .sep {
15
+ color: var(--nc-text-muted, #6b7280);
16
+ font-size: var(--nc-font-size-sm, 0.875rem);
17
+ padding: 0 4px;
18
+ user-select: none;
19
+ }
20
+
21
+ ::slotted(*) {
22
+ font-size: var(--nc-font-size-sm, 0.875rem);
23
+ color: var(--nc-text-muted, #6b7280);
24
+ text-decoration: none;
25
+ white-space: nowrap;
26
+ }
27
+
28
+ ::slotted(*:last-child) {
29
+ color: var(--nc-text, #111827);
30
+ font-weight: var(--nc-font-weight-medium, 500);
31
+ pointer-events: none;
32
+ }
33
+
34
+ ::slotted(*:not(:last-child):hover) {
35
+ color: var(--nc-primary, #10b981);
36
+ }
37
+ </style>
38
+ <nav aria-label="Breadcrumb">
39
+ <slot></slot>
40
+ </nav>
41
+ `;
42
+ }
43
+ onMount() {
44
+ this.insertSeparators();
45
+ const observer = new MutationObserver(() => this.insertSeparators());
46
+ observer.observe(this, { childList: true });
47
+ this._breadcrumbObserver = observer;
48
+ }
49
+ onUnmount() {
50
+ this._breadcrumbObserver?.disconnect();
51
+ }
52
+ insertSeparators() {
53
+ const separator = this.getAttribute('separator') || '/';
54
+ const existing = Array.from(this.querySelectorAll('.nc-breadcrumb-sep'));
55
+ existing.forEach(node => node.remove());
56
+ const children = Array.from(this.children).filter(element => !element.classList.contains('nc-breadcrumb-sep'));
57
+ children.slice(0, -1).forEach(child => {
58
+ const span = document.createElement('span');
59
+ span.className = 'nc-breadcrumb-sep';
60
+ span.setAttribute('aria-hidden', 'true');
61
+ span.textContent = separator;
62
+ child.after(span);
63
+ });
64
+ }
65
+ attributeChangedCallback(name, oldValue, newValue) {
66
+ if (oldValue !== newValue && this._mounted) {
67
+ this.insertSeparators();
68
+ }
69
+ }
70
+ }
71
+ defineComponent('nc-breadcrumb', NcBreadcrumb);
@@ -0,0 +1,38 @@
1
+ /**
2
+ * NativeCore Button Component
3
+ *
4
+ * Framework core component using Shadow DOM and --nc- variables.
5
+ *
6
+ * Attributes:
7
+ * - variant: 'primary' | 'secondary' | 'tertiary' | 'success' | 'danger' | 'outline' (default: 'primary')
8
+ * - size: 'sm' | 'md' | 'lg' (default: 'md')
9
+ * - icon: URL to icon/image (optional, e.g., '/icons/delete.svg' or 'assets/logo.png')
10
+ * - icon-position: 'left' | 'right' | 'top' | 'bottom' (default: 'left')
11
+ * - alt: Alt text for icon (optional, for accessibility)
12
+ * - disabled: boolean
13
+ * - loading: boolean
14
+ * - full-width: boolean
15
+ *
16
+ * Usage:
17
+ *
18
+ *
19
+ *
20
+ */
21
+ import { Component } from '../core/component.js';
22
+ export declare class NcButton extends Component {
23
+ static useShadowDOM: boolean;
24
+ static attributeOptions: {
25
+ variant: string[];
26
+ size: string[];
27
+ 'icon-position': string[];
28
+ };
29
+ static attributePlaceholders: {
30
+ icon: string;
31
+ alt: string;
32
+ };
33
+ static get observedAttributes(): string[];
34
+ constructor();
35
+ template(): string;
36
+ onMount(): void;
37
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
38
+ }
@@ -0,0 +1,293 @@
1
+ /**
2
+ * NativeCore Button Component
3
+ *
4
+ * Framework core component using Shadow DOM and --nc- variables.
5
+ *
6
+ * Attributes:
7
+ * - variant: 'primary' | 'secondary' | 'tertiary' | 'success' | 'danger' | 'outline' (default: 'primary')
8
+ * - size: 'sm' | 'md' | 'lg' (default: 'md')
9
+ * - icon: URL to icon/image (optional, e.g., '/icons/delete.svg' or 'assets/logo.png')
10
+ * - icon-position: 'left' | 'right' | 'top' | 'bottom' (default: 'left')
11
+ * - alt: Alt text for icon (optional, for accessibility)
12
+ * - disabled: boolean
13
+ * - loading: boolean
14
+ * - full-width: boolean
15
+ *
16
+ * Usage:
17
+ *
18
+ *
19
+ *
20
+ */
21
+ import { Component, defineComponent } from '../core/component.js';
22
+ export class NcButton extends Component {
23
+ static useShadowDOM = true;
24
+ // Dev tools will auto-detect these dropdown options
25
+ static attributeOptions = {
26
+ variant: ['primary', 'secondary', 'tertiary', 'success', 'danger', 'outline'],
27
+ size: ['sm', 'md', 'lg'],
28
+ 'icon-position': ['left', 'right', 'top', 'bottom']
29
+ };
30
+ // Add placeholders for text inputs in dev tools
31
+ static attributePlaceholders = {
32
+ icon: '/icons/my-icon.svg or assets/image.png',
33
+ alt: 'Icon description for accessibility'
34
+ };
35
+ static get observedAttributes() {
36
+ return ['variant', 'size', 'icon', 'icon-position', 'alt', 'disabled', 'loading', 'full-width'];
37
+ }
38
+ constructor() {
39
+ super();
40
+ }
41
+ template() {
42
+ const icon = this.getAttribute('icon');
43
+ const iconPosition = this.getAttribute('icon-position') || 'left';
44
+ const alt = this.getAttribute('alt') || '';
45
+ const disabled = this.hasAttribute('disabled');
46
+ const loading = this.hasAttribute('loading');
47
+ const fullWidth = this.hasAttribute('full-width');
48
+ const iconHTML = icon ? `<img class="nc-button-icon" src="${icon}" alt="${alt}" />` : '';
49
+ return `
50
+ <style>
51
+ :host {
52
+ display: ${fullWidth ? 'block' : 'inline-flex'};
53
+ align-items: center;
54
+ justify-content: center;
55
+ gap: var(--nc-spacing-sm);
56
+ font-family: var(--nc-font-family);
57
+ font-weight: var(--nc-font-weight-semibold);
58
+ border: none;
59
+ border-radius: var(--nc-button-radius);
60
+ cursor: ${disabled || loading ? 'not-allowed' : 'pointer'};
61
+ transition: all var(--nc-transition-fast);
62
+ text-decoration: none;
63
+ outline: none;
64
+ position: relative;
65
+ overflow: ${loading ? 'visible' : 'hidden'};
66
+ user-select: none;
67
+ box-sizing: border-box !important;
68
+ margin: 0 !important;
69
+ flex-direction: ${iconPosition === 'top' ? 'column' : iconPosition === 'bottom' ? 'column-reverse' : iconPosition === 'right' ? 'row-reverse' : 'row'};
70
+
71
+ /* Default size (md) */
72
+ padding: var(--nc-spacing-sm) var(--nc-spacing-xl) !important;
73
+ font-size: var(--nc-font-size-base);
74
+ min-height: 40px;
75
+
76
+ /* Default variant (primary) */
77
+ background: var(--nc-gradient-primary);
78
+ color: var(--nc-white);
79
+ }
80
+
81
+ .nc-button-icon {
82
+ width: 1.2em;
83
+ height: 1.2em;
84
+ object-fit: contain;
85
+ flex-shrink: 0;
86
+ }
87
+
88
+ :host(:focus-visible) {
89
+ outline: 2px solid var(--nc-primary);
90
+ outline-offset: 2px;
91
+ }
92
+
93
+ /* Size Variants */
94
+ :host([size="sm"]) {
95
+ padding: var(--nc-spacing-xs) var(--nc-spacing-lg) !important;
96
+ font-size: var(--nc-font-size-sm);
97
+ min-height: 32px;
98
+ }
99
+
100
+ :host([size="md"]) {
101
+ padding: var(--nc-spacing-sm) var(--nc-spacing-xl) !important;
102
+ font-size: var(--nc-font-size-base);
103
+ min-height: 40px;
104
+ }
105
+
106
+ :host([size="lg"]) {
107
+ padding: var(--nc-spacing-md) var(--nc-spacing-2xl) !important;
108
+ font-size: var(--nc-font-size-lg);
109
+ min-height: 48px;
110
+ }
111
+
112
+ /* Variant: Primary */
113
+ :host([variant="primary"]) {
114
+ background: #10b981;
115
+ color: white;
116
+ box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
117
+ }
118
+
119
+ :host([variant="primary"]:hover:not([disabled]):not([loading])) {
120
+ transform: translateY(-1px);
121
+ box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);
122
+ background: #059669;
123
+ }
124
+
125
+ :host([variant="primary"]:active:not([disabled]):not([loading])) {
126
+ transform: translateY(0);
127
+ }
128
+
129
+ /* Variant: Secondary */
130
+ :host([variant="secondary"]) {
131
+ background: var(--nc-gray-200);
132
+ color: var(--nc-text);
133
+ border: none;
134
+ }
135
+
136
+ :host([variant="secondary"]:hover:not([disabled]):not([loading])) {
137
+ background: var(--nc-gray-300);
138
+ transform: translateY(-1px);
139
+ }
140
+
141
+ /* Variant: Success */
142
+ :host([variant="success"]) {
143
+ background: var(--nc-gradient-success);
144
+ color: var(--nc-white);
145
+ }
146
+
147
+ :host([variant="success"]:hover:not([disabled]):not([loading])) {
148
+ transform: translateY(-2px);
149
+ box-shadow: var(--nc-shadow-success);
150
+ }
151
+
152
+ :host([variant="success"]:active:not([disabled]):not([loading])) {
153
+ transform: translateY(0);
154
+ }
155
+
156
+ /* Variant: Danger */
157
+ :host([variant="danger"]) {
158
+ background: var(--nc-gradient-danger);
159
+ color: var(--nc-white);
160
+ }
161
+
162
+ :host([variant="danger"]:hover:not([disabled]):not([loading])) {
163
+ transform: translateY(-2px);
164
+ box-shadow: var(--nc-shadow-danger);
165
+ }
166
+
167
+ :host([variant="danger"]:active:not([disabled]):not([loading])) {
168
+ transform: translateY(0);
169
+ }
170
+
171
+ /* Variant: Tertiary (dark) */
172
+ :host([variant="tertiary"]) {
173
+ background: var(--nc-gray-900);
174
+ color: var(--nc-white);
175
+ }
176
+
177
+ :host([variant="tertiary"]:hover:not([disabled]):not([loading])) {
178
+ background: var(--nc-gray-800);
179
+ transform: translateY(-2px);
180
+ }
181
+
182
+ :host([variant="tertiary"]:active:not([disabled]):not([loading])) {
183
+ transform: translateY(0);
184
+ }
185
+
186
+ /* Variant: Outline */
187
+ :host([variant="outline"]) {
188
+ background: transparent;
189
+ color: var(--nc-primary);
190
+ border: 2px solid var(--nc-primary);
191
+ }
192
+
193
+ :host([variant="outline"]:hover:not([disabled]):not([loading])) {
194
+ background: var(--nc-primary);
195
+ color: var(--nc-white);
196
+ }
197
+
198
+ /* Full Width */
199
+ :host([full-width]) {
200
+ width: 100%;
201
+ }
202
+
203
+ /* Disabled State */
204
+ :host([disabled]) {
205
+ opacity: 0.5;
206
+ pointer-events: none;
207
+ }
208
+
209
+ /* Loading State */
210
+ :host([loading]) {
211
+ pointer-events: none;
212
+ position: relative;
213
+ }
214
+
215
+ :host([loading])::after {
216
+ content: '';
217
+ position: absolute;
218
+ width: 16px;
219
+ height: 16px;
220
+ border: 2px solid currentColor;
221
+ border-top-color: transparent;
222
+ border-radius: 50%;
223
+ animation: spin 0.6s linear infinite;
224
+ margin-left: var(--nc-spacing-sm);
225
+ }
226
+
227
+ @keyframes spin {
228
+ to { transform: rotate(360deg); }
229
+ }
230
+
231
+ /* Ripple Effect */
232
+ :host::before {
233
+ content: '';
234
+ position: absolute;
235
+ top: 50%;
236
+ left: 50%;
237
+ width: 0;
238
+ height: 0;
239
+ border-radius: 50%;
240
+ background: rgba(255, 255, 255, 0.5);
241
+ transform: translate(-50%, -50%);
242
+ transition: width 0.6s, height 0.6s;
243
+ }
244
+
245
+ :host(:active:not([disabled]):not([loading]))::before {
246
+ width: 300px;
247
+ height: 300px;
248
+ opacity: 0;
249
+ }
250
+
251
+ /* Anchor tags inside button */
252
+ ::slotted(a) {
253
+ color: white;
254
+ text-decoration: none;
255
+ display: flex;
256
+ align-items: center;
257
+ justify-content: center;
258
+ }
259
+ </style>
260
+ ${iconHTML}
261
+ <slot></slot>
262
+ `;
263
+ }
264
+ onMount() {
265
+ // Set button role and tab index for accessibility
266
+ this.setAttribute('role', 'button');
267
+ if (!this.hasAttribute('tabindex')) {
268
+ this.setAttribute('tabindex', '0');
269
+ }
270
+ // Handle keyboard navigation (Enter and Space)
271
+ this.addEventListener('keydown', (e) => {
272
+ if ((e.key === 'Enter' || e.key === ' ') &&
273
+ !this.hasAttribute('disabled') &&
274
+ !this.hasAttribute('loading')) {
275
+ e.preventDefault();
276
+ this.click();
277
+ }
278
+ });
279
+ // Handle click - prevent when disabled/loading
280
+ this.addEventListener('click', (e) => {
281
+ if (this.hasAttribute('disabled') || this.hasAttribute('loading')) {
282
+ e.stopPropagation();
283
+ e.preventDefault();
284
+ }
285
+ });
286
+ }
287
+ attributeChangedCallback(name, oldValue, newValue) {
288
+ if (oldValue !== newValue) {
289
+ this.render();
290
+ }
291
+ }
292
+ }
293
+ defineComponent('nc-button', NcButton);
@@ -0,0 +1,11 @@
1
+ import { Component } from '../core/component.js';
2
+ export declare class NcCard extends Component {
3
+ static useShadowDOM: boolean;
4
+ static attributeOptions: {
5
+ variant: string[];
6
+ size: string[];
7
+ };
8
+ static get observedAttributes(): string[];
9
+ template(): string;
10
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
11
+ }