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,270 @@
1
+ /**
2
+ * NcDiv Component - Responsive Container
3
+ *
4
+ * A flexible container component with built-in responsive grid/flex layouts
5
+ *
6
+ * Attributes:
7
+ * - layout: 'grid' | 'flex' | 'grid-auto' | 'block' (default: 'grid-auto')
8
+ * - cols: '1' | '2' | '3' | '4' (for grid layout)
9
+ * - direction: 'row' | 'column' (for flex layout)
10
+ * - gap: 'sm' | 'md' | 'lg' | 'xl' (default: 'md')
11
+ * - width: 'full' | 'three-quarters' | 'half' | 'quarter' (default: 'full')
12
+ * - justify: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly' (for flex/grid)
13
+ * - align: 'start' | 'center' | 'end' | 'stretch' | 'baseline' (for flex/grid)
14
+ *
15
+ * Usage:
16
+ * <nc-div layout="grid-auto">
17
+ * Card 1</nc-card>
18
+ * Card 2</nc-card>
19
+ * </nc-div>
20
+ *
21
+ * <nc-div layout="grid" cols="3">
22
+ * Card 1</nc-card>
23
+ * Card 2</nc-card>
24
+ * Card 3</nc-card>
25
+ * </nc-div>
26
+ *
27
+ * <nc-div layout="flex" direction="row" gap="lg" justify="center" align="center">
28
+ * Flexbox Item 1</nc-card>
29
+ * Flexbox Item 2</nc-card>
30
+ * </nc-div>
31
+ */
32
+ import { Component, defineComponent } from '../core/component.js';
33
+ export class NcDiv extends Component {
34
+ static useShadowDOM = true;
35
+ // ═══ Define dropdown options for dev tools ═══
36
+ static attributeOptions = {
37
+ layout: ['grid-auto', 'grid', 'flex', 'block'],
38
+ cols: ['1', '2', '3', '4'],
39
+ direction: ['row', 'column'],
40
+ gap: ['sm', 'md', 'lg', 'xl'],
41
+ width: ['full', 'three-quarters', 'half', 'quarter'],
42
+ justify: ['start', 'center', 'end', 'between', 'around', 'evenly'],
43
+ align: ['start', 'center', 'end', 'stretch', 'baseline']
44
+ };
45
+ // ═══ Conditional visibility for attributes based on layout ═══
46
+ static attributeConditions = {
47
+ cols: (element) => {
48
+ const layout = element.getAttribute('layout') || 'grid-auto';
49
+ return layout === 'grid';
50
+ },
51
+ direction: (element) => {
52
+ const layout = element.getAttribute('layout') || 'grid-auto';
53
+ return layout === 'flex';
54
+ }
55
+ };
56
+ // ═══ Attributes become editable in dev tools sidebar ═══
57
+ static get observedAttributes() {
58
+ return ['layout', 'cols', 'direction', 'gap', 'width', 'justify', 'align'];
59
+ }
60
+ constructor() {
61
+ super();
62
+ }
63
+ template() {
64
+ return `
65
+ <style>
66
+ :host {
67
+ display: block;
68
+ width: 100%;
69
+ box-sizing: border-box;
70
+ margin: var(--nc-spacing-lg) 0 !important;
71
+ }
72
+
73
+ /* Layout: Auto-fit Grid (Recommended) */
74
+ :host([layout="grid-auto"]) {
75
+ display: grid;
76
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
77
+ }
78
+
79
+ /* Layout: Fixed Grid */
80
+ :host([layout="grid"]) {
81
+ display: grid;
82
+ }
83
+
84
+ :host([layout="grid"][cols="1"]) {
85
+ grid-template-columns: repeat(1, minmax(0, 1fr));
86
+ }
87
+
88
+ :host([layout="grid"][cols="2"]) {
89
+ grid-template-columns: repeat(2, minmax(0, 1fr));
90
+ }
91
+
92
+ :host([layout="grid"][cols="3"]) {
93
+ grid-template-columns: repeat(3, minmax(0, 1fr));
94
+ }
95
+
96
+ :host([layout="grid"][cols="4"]) {
97
+ grid-template-columns: repeat(4, minmax(0, 1fr));
98
+ }
99
+
100
+ /* Layout: Flexbox */
101
+ :host([layout="flex"]) {
102
+ display: flex;
103
+ flex-wrap: wrap;
104
+ flex-direction: column; /* Default to column (vertical stack) */
105
+ }
106
+
107
+ /* Flex Direction */
108
+ :host([layout="flex"][direction="row"]) {
109
+ flex-direction: row;
110
+ }
111
+
112
+ :host([layout="flex"][direction="column"]) {
113
+ flex-direction: column;
114
+ }
115
+
116
+ /* Row layout: children can grow with 300px basis */
117
+ :host([layout="flex"][direction="row"]) ::slotted(*) {
118
+ flex: 1 1 300px;
119
+ min-width: 0;
120
+ }
121
+
122
+ /* Column layout (default): children size to content */
123
+ :host([layout="flex"]) ::slotted(*),
124
+ :host([layout="flex"][direction="column"]) ::slotted(*) {
125
+ flex: 0 1 auto;
126
+ min-width: 0;
127
+ }
128
+
129
+ /* Layout: Block */
130
+ :host([layout="block"]) {
131
+ display: block;
132
+ }
133
+
134
+ /* Gap Sizes */
135
+ :host([gap="sm"]) {
136
+ gap: var(--nc-spacing-sm);
137
+ }
138
+
139
+ :host([gap="md"]) {
140
+ gap: var(--nc-spacing-md);
141
+ }
142
+
143
+ :host([gap="lg"]) {
144
+ gap: var(--nc-spacing-lg);
145
+ }
146
+
147
+ :host([gap="xl"]) {
148
+ gap: var(--nc-spacing-xl);
149
+ }
150
+
151
+ /* Justify Content - Works for both Flex & Grid */
152
+ :host([justify="start"]) {
153
+ justify-content: flex-start;
154
+ justify-items: start;
155
+ }
156
+
157
+ :host([justify="center"]) {
158
+ justify-content: center;
159
+ justify-items: center;
160
+ }
161
+
162
+ :host([justify="end"]) {
163
+ justify-content: flex-end;
164
+ justify-items: end;
165
+ }
166
+
167
+ :host([justify="between"]) {
168
+ justify-content: space-between;
169
+ }
170
+
171
+ :host([justify="around"]) {
172
+ justify-content: space-around;
173
+ }
174
+
175
+ :host([justify="evenly"]) {
176
+ justify-content: space-evenly;
177
+ }
178
+
179
+ /* Align Items - Works for both Flex & Grid */
180
+ :host([align="start"]) {
181
+ align-items: flex-start;
182
+ align-content: flex-start;
183
+ }
184
+
185
+ :host([align="center"]) {
186
+ align-items: center;
187
+ align-content: center;
188
+ }
189
+
190
+ :host([align="end"]) {
191
+ align-items: flex-end;
192
+ align-content: flex-end;
193
+ }
194
+
195
+ :host([align="stretch"]) {
196
+ align-items: stretch;
197
+ align-content: stretch;
198
+ }
199
+
200
+ :host([align="baseline"]) {
201
+ align-items: baseline;
202
+ align-content: baseline;
203
+ }
204
+
205
+ /* Width Options */
206
+ :host([width="full"]) {
207
+ width: 100%;
208
+ }
209
+
210
+ :host([width="three-quarters"]) {
211
+ width: 75%;
212
+ margin-left: auto;
213
+ margin-right: auto;
214
+ }
215
+
216
+ :host([width="half"]) {
217
+ width: 50%;
218
+ margin-left: auto;
219
+ margin-right: auto;
220
+ }
221
+
222
+ :host([width="quarter"]) {
223
+ width: 25%;
224
+ margin-left: auto;
225
+ margin-right: auto;
226
+ }
227
+
228
+ /* Responsive: Mobile */
229
+ @media (max-width: 768px) {
230
+ :host([layout="grid"][cols="2"]),
231
+ :host([layout="grid"][cols="3"]),
232
+ :host([layout="grid"][cols="4"]) {
233
+ grid-template-columns: repeat(1, minmax(0, 1fr));
234
+ }
235
+
236
+ :host([layout="grid-auto"]) {
237
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
238
+ }
239
+
240
+ /* Full width on mobile for better UX */
241
+ :host([width="three-quarters"]),
242
+ :host([width="half"]),
243
+ :host([width="quarter"]) {
244
+ width: 100% !important;
245
+ }
246
+ }
247
+
248
+ /* Responsive: Tablet */
249
+ @media (min-width: 769px) and (max-width: 1024px) {
250
+ :host([layout="grid"][cols="3"]),
251
+ :host([layout="grid"][cols="4"]) {
252
+ grid-template-columns: repeat(2, minmax(0, 1fr));
253
+ }
254
+ }
255
+ </style>
256
+
257
+ <slot></slot>
258
+ `;
259
+ }
260
+ onMount() {
261
+ // Component logic here
262
+ }
263
+ // ═══ Makes changes instant in dev tools preview ═══
264
+ attributeChangedCallback(name, oldValue, newValue) {
265
+ if (oldValue !== newValue && this._mounted) {
266
+ this.render();
267
+ }
268
+ }
269
+ }
270
+ defineComponent('nc-div', NcDiv);
@@ -0,0 +1,7 @@
1
+ import { Component } from '../core/component.js';
2
+ export declare class NcDivider extends Component {
3
+ static useShadowDOM: boolean;
4
+ static get observedAttributes(): string[];
5
+ template(): string;
6
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
7
+ }
@@ -0,0 +1,57 @@
1
+ import { Component, defineComponent } from '../core/component.js';
2
+ export class NcDivider extends Component {
3
+ static useShadowDOM = true;
4
+ static get observedAttributes() {
5
+ return ['orientation', 'variant', 'label', 'thickness', 'color', 'spacing'];
6
+ }
7
+ template() {
8
+ const orientation = this.getAttribute('orientation') || 'horizontal';
9
+ const variant = this.getAttribute('variant') || 'solid';
10
+ const label = this.getAttribute('label') || '';
11
+ const thickness = this.getAttribute('thickness') || '1px';
12
+ const color = this.getAttribute('color') || 'var(--nc-border, #e5e7eb)';
13
+ const spacing = this.getAttribute('spacing') || (orientation === 'horizontal' ? 'var(--nc-spacing-md, 1rem) 0' : '0 var(--nc-spacing-md, 1rem)');
14
+ const isHorizontal = orientation === 'horizontal';
15
+ return `
16
+ <style>
17
+ :host {
18
+ display: ${isHorizontal ? 'block' : 'inline-flex'};
19
+ align-self: ${isHorizontal ? 'auto' : 'stretch'};
20
+ }
21
+
22
+ .divider {
23
+ display: flex;
24
+ align-items: center;
25
+ margin: ${spacing};
26
+ ${isHorizontal ? 'width: 100%;' : 'flex-direction: column; height: 100%;'}
27
+ font-family: var(--nc-font-family);
28
+ }
29
+
30
+ .line {
31
+ ${isHorizontal ? 'flex: 1; height: 0;' : 'flex: 1; width: 0;'}
32
+ border: none;
33
+ border-${isHorizontal ? 'top' : 'left'}: ${thickness} ${variant} ${color};
34
+ }
35
+
36
+ .label {
37
+ padding: ${isHorizontal ? '0 var(--nc-spacing-sm, 0.5rem)' : 'var(--nc-spacing-sm, 0.5rem) 0'};
38
+ font-size: var(--nc-font-size-xs, 0.75rem);
39
+ color: var(--nc-text-muted, #6b7280);
40
+ white-space: nowrap;
41
+ font-weight: var(--nc-font-weight-medium, 500);
42
+ text-transform: uppercase;
43
+ letter-spacing: 0.05em;
44
+ }
45
+ </style>
46
+ <div class="divider" role="separator" aria-orientation="${orientation}">
47
+ <span class="line"></span>
48
+ ${label ? `<span class="label">${label}</span><span class="line"></span>` : ''}
49
+ </div>
50
+ `;
51
+ }
52
+ attributeChangedCallback(name, oldValue, newValue) {
53
+ if (oldValue !== newValue && this._mounted)
54
+ this.render();
55
+ }
56
+ }
57
+ defineComponent('nc-divider', NcDivider);
@@ -0,0 +1,40 @@
1
+ /**
2
+ * NcDrawer Component
3
+ *
4
+ * Attributes:
5
+ * - open: boolean - visible state
6
+ * - placement: 'left'|'right'|'top'|'bottom' (default: 'right')
7
+ * - size: string - CSS width/height of the panel (default: '320px')
8
+ * - overlay: boolean - show backdrop overlay (default: true)
9
+ * - close-on-overlay: boolean - click overlay to close (default: true)
10
+ * - no-close-btn: boolean - hide the built-in close button
11
+ *
12
+ * Slots:
13
+ * - header - drawer header area
14
+ * - (default) - drawer body content
15
+ * - footer - drawer footer area
16
+ *
17
+ * Events:
18
+ * - open: CustomEvent - after drawer opens
19
+ * - close: CustomEvent - after drawer closes
20
+ *
21
+ * Usage:
22
+ * <nc-drawer id="nav-drawer" placement="left">
23
+ * <span slot="header">Navigation</span>
24
+ * <p>Links go here</p>
25
+ * </nc-drawer>
26
+ *
27
+ * document.getElementById('nav-drawer').setAttribute('open', '');
28
+ */
29
+ import { Component } from '../core/component.js';
30
+ export declare class NcDrawer extends Component {
31
+ static useShadowDOM: boolean;
32
+ static get observedAttributes(): string[];
33
+ template(): string;
34
+ onMount(): void;
35
+ private _bindEvents;
36
+ private _onKeydown;
37
+ private _close;
38
+ onUnmount(): void;
39
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
40
+ }
@@ -0,0 +1,217 @@
1
+ /**
2
+ * NcDrawer Component
3
+ *
4
+ * Attributes:
5
+ * - open: boolean - visible state
6
+ * - placement: 'left'|'right'|'top'|'bottom' (default: 'right')
7
+ * - size: string - CSS width/height of the panel (default: '320px')
8
+ * - overlay: boolean - show backdrop overlay (default: true)
9
+ * - close-on-overlay: boolean - click overlay to close (default: true)
10
+ * - no-close-btn: boolean - hide the built-in close button
11
+ *
12
+ * Slots:
13
+ * - header - drawer header area
14
+ * - (default) - drawer body content
15
+ * - footer - drawer footer area
16
+ *
17
+ * Events:
18
+ * - open: CustomEvent - after drawer opens
19
+ * - close: CustomEvent - after drawer closes
20
+ *
21
+ * Usage:
22
+ * <nc-drawer id="nav-drawer" placement="left">
23
+ * <span slot="header">Navigation</span>
24
+ * <p>Links go here</p>
25
+ * </nc-drawer>
26
+ *
27
+ * document.getElementById('nav-drawer').setAttribute('open', '');
28
+ */
29
+ import { Component, defineComponent } from '../core/component.js';
30
+ export class NcDrawer extends Component {
31
+ static useShadowDOM = true;
32
+ static get observedAttributes() {
33
+ return ['open', 'placement', 'size', 'overlay', 'close-on-overlay', 'no-close-btn'];
34
+ }
35
+ template() {
36
+ const open = this.hasAttribute('open');
37
+ const placement = this.getAttribute('placement') || 'right';
38
+ const size = this.getAttribute('size') || '320px';
39
+ const showOverlay = !this.hasAttribute('overlay') || this.getAttribute('overlay') !== 'false';
40
+ const noCloseBtn = this.hasAttribute('no-close-btn');
41
+ const isHorizontal = placement === 'left' || placement === 'right';
42
+ const panelSize = isHorizontal
43
+ ? `width: ${size}; height: 100%;`
44
+ : `height: ${size}; width: 100%;`;
45
+ const translateClosed = {
46
+ left: 'translateX(-100%)',
47
+ right: 'translateX(100%)',
48
+ top: 'translateY(-100%)',
49
+ bottom: 'translateY(100%)',
50
+ }[placement];
51
+ return `
52
+ <style>
53
+ :host { display: contents; }
54
+
55
+ .overlay {
56
+ position: fixed;
57
+ inset: 0;
58
+ background: rgba(0,0,0,.45);
59
+ z-index: 900;
60
+ opacity: ${open ? '1' : '0'};
61
+ pointer-events: ${open && showOverlay ? 'auto' : 'none'};
62
+ transition: opacity var(--nc-transition-base);
63
+ display: ${showOverlay ? 'block' : 'none'};
64
+ }
65
+
66
+ .panel {
67
+ position: fixed;
68
+ ${placement}: 0;
69
+ ${placement === 'left' || placement === 'right' ? 'top: 0;' : 'left: 0;'}
70
+ ${panelSize}
71
+ background: var(--nc-bg);
72
+ box-shadow: var(--nc-shadow-xl, 0 20px 60px rgba(0,0,0,.3));
73
+ z-index: 901;
74
+ display: flex;
75
+ flex-direction: column;
76
+ transform: ${open ? 'none' : translateClosed};
77
+ transition: transform var(--nc-transition-base);
78
+ overflow: hidden;
79
+ }
80
+
81
+ .panel__header {
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: space-between;
85
+ padding: var(--nc-spacing-md) var(--nc-spacing-lg);
86
+ border-bottom: 1px solid var(--nc-border);
87
+ font-family: var(--nc-font-family);
88
+ font-weight: var(--nc-font-weight-semibold);
89
+ font-size: var(--nc-font-size-lg);
90
+ color: var(--nc-text);
91
+ flex-shrink: 0;
92
+ }
93
+
94
+ .panel__body {
95
+ flex: 1;
96
+ overflow-y: auto;
97
+ padding: var(--nc-spacing-lg);
98
+ }
99
+
100
+ .panel__footer {
101
+ padding: var(--nc-spacing-md) var(--nc-spacing-lg);
102
+ border-top: 1px solid var(--nc-border);
103
+ flex-shrink: 0;
104
+ }
105
+
106
+ .panel__footer:empty { display: none; }
107
+
108
+ .close-btn {
109
+ background: none;
110
+ border: none;
111
+ cursor: pointer;
112
+ padding: 4px;
113
+ color: var(--nc-text-muted);
114
+ border-radius: var(--nc-radius-sm, 4px);
115
+ display: flex;
116
+ transition: color var(--nc-transition-fast), background var(--nc-transition-fast);
117
+ }
118
+ .close-btn:hover { color: var(--nc-text); background: var(--nc-bg-secondary); }
119
+ </style>
120
+
121
+ ${showOverlay ? `<div class="overlay" aria-hidden="true"></div>` : ''}
122
+
123
+ <div
124
+ class="panel"
125
+ role="dialog"
126
+ aria-modal="true"
127
+ aria-hidden="${!open}"
128
+ tabindex="-1"
129
+ >
130
+ <div class="panel__header">
131
+ <slot name="header"></slot>
132
+ ${!noCloseBtn ? `
133
+ <button class="close-btn" type="button" aria-label="Close drawer">
134
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" width="18" height="18">
135
+ <path d="M3 3l10 10M13 3L3 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
136
+ </svg>
137
+ </button>` : ''}
138
+ </div>
139
+ <div class="panel__body">
140
+ <slot></slot>
141
+ </div>
142
+ <div class="panel__footer">
143
+ <slot name="footer"></slot>
144
+ </div>
145
+ </div>
146
+ `;
147
+ }
148
+ onMount() {
149
+ this._bindEvents();
150
+ }
151
+ _bindEvents() {
152
+ const closeBtn = this.$('.close-btn');
153
+ if (closeBtn) {
154
+ closeBtn.addEventListener('click', () => this._close());
155
+ }
156
+ const overlay = this.$('.overlay');
157
+ if (overlay) {
158
+ overlay.addEventListener('click', () => {
159
+ if (!this.hasAttribute('close-on-overlay') || this.getAttribute('close-on-overlay') !== 'false') {
160
+ this._close();
161
+ }
162
+ });
163
+ }
164
+ // Close on Escape
165
+ this._onKeydown = (e) => {
166
+ if (e.key === 'Escape' && this.hasAttribute('open'))
167
+ this._close();
168
+ };
169
+ document.addEventListener('keydown', this._onKeydown);
170
+ }
171
+ _onKeydown = null;
172
+ _close() {
173
+ this.removeAttribute('open');
174
+ this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
175
+ }
176
+ onUnmount() {
177
+ if (this._onKeydown)
178
+ document.removeEventListener('keydown', this._onKeydown);
179
+ }
180
+ attributeChangedCallback(name, oldValue, newValue) {
181
+ if (oldValue === newValue)
182
+ return;
183
+ if (name === 'open' && this._mounted) {
184
+ const open = this.hasAttribute('open');
185
+ const panel = this.$('.panel');
186
+ const overlay = this.$('.overlay');
187
+ const placement = this.getAttribute('placement') || 'right';
188
+ const translateClosed = {
189
+ left: 'translateX(-100%)',
190
+ right: 'translateX(100%)',
191
+ top: 'translateY(-100%)',
192
+ bottom: 'translateY(100%)',
193
+ }[placement];
194
+ if (panel) {
195
+ panel.style.transform = open ? 'none' : (translateClosed ?? 'translateX(100%)');
196
+ panel.setAttribute('aria-hidden', String(!open));
197
+ if (open)
198
+ panel.focus();
199
+ }
200
+ if (overlay) {
201
+ overlay.style.opacity = open ? '1' : '0';
202
+ overlay.style.pointerEvents = open ? 'auto' : 'none';
203
+ }
204
+ // Lock body scroll while open
205
+ document.body.style.overflow = open ? 'hidden' : '';
206
+ this.dispatchEvent(new CustomEvent(open ? 'open' : 'close', {
207
+ bubbles: true, composed: true
208
+ }));
209
+ return;
210
+ }
211
+ if (this._mounted) {
212
+ this.render();
213
+ this._bindEvents();
214
+ }
215
+ }
216
+ }
217
+ defineComponent('nc-drawer', NcDrawer);
@@ -0,0 +1,41 @@
1
+ /**
2
+ * NcDropdown Component
3
+ *
4
+ * A generic trigger + floating-panel component. The trigger is whatever
5
+ * is in slot[name="trigger"]; the content panel is the default slot.
6
+ *
7
+ * Attributes:
8
+ * - open: boolean - visible state
9
+ * - placement: 'bottom-start'|'bottom-end'|'bottom'|'top-start'|'top-end'|'top' (default: 'bottom-start')
10
+ * - close-on-select: boolean - close when a [data-value] child is clicked (default: true)
11
+ * - disabled: boolean
12
+ * - offset: number - gap in px between trigger and panel (default: 6)
13
+ * - width: string - CSS width of panel (default: 'auto'; use 'trigger' to match trigger width)
14
+ *
15
+ * Events:
16
+ * - open: CustomEvent
17
+ * - close: CustomEvent
18
+ * - select: CustomEvent<{ value: string; label: string }> - when a [data-value] child is clicked
19
+ *
20
+ * Usage:
21
+ * <nc-dropdown>
22
+ * <nc-button slot="trigger">Options</nc-button>
23
+ * <nc-menu>
24
+ * <nc-menu-item data-value="edit">Edit</nc-menu-item>
25
+ * <nc-menu-item data-value="delete">Delete</nc-menu-item>
26
+ * </nc-menu>
27
+ * </nc-dropdown>
28
+ */
29
+ import { Component } from '../core/component.js';
30
+ export declare class NcDropdown extends Component {
31
+ static useShadowDOM: boolean;
32
+ static get observedAttributes(): string[];
33
+ private _outsideClick;
34
+ template(): string;
35
+ onMount(): void;
36
+ private _bindEvents;
37
+ private _hookTrigger;
38
+ private _setOpen;
39
+ onUnmount(): void;
40
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
41
+ }