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,268 @@
1
+ /**
2
+ * NcTagInput Component - text input that creates dismissible tag chips
3
+ *
4
+ * Attributes:
5
+ * placeholder - input placeholder text
6
+ * value - comma-separated initial tags (e.g. "react,vue,svelte")
7
+ * max - maximum number of tags allowed
8
+ * min-length - minimum character length for a tag (default: 1)
9
+ * max-length - maximum character length per tag
10
+ * delimiter - character(s) that trigger tag creation in addition to Enter (default: ',')
11
+ * disabled - boolean
12
+ * readonly - boolean - show tags but cannot add/remove
13
+ * duplicate - boolean - allow duplicate tags (default: false)
14
+ * variant - 'default'|'filled' (default: 'default')
15
+ * label - visible label text
16
+ * hint - helper text below input
17
+ * error - error message (shown in red)
18
+ *
19
+ * Events:
20
+ * change - CustomEvent<{ tags: string[] }> - tag list changed
21
+ * add - CustomEvent<{ tag: string }>
22
+ * remove - CustomEvent<{ tag: string; index: number }>
23
+ * max-reached - CustomEvent - fired when max is exceeded
24
+ *
25
+ * Methods:
26
+ * el.getTags() - string[]
27
+ * el.setTags(tags) - replace all tags
28
+ * el.addTag(tag) - programmatic add
29
+ * el.removeTag(index) - programmatic remove
30
+ * el.clear() - remove all tags
31
+ */
32
+ import { Component, defineComponent } from '../core/component.js';
33
+ export class NcTagInput extends Component {
34
+ static useShadowDOM = true;
35
+ _tags = [];
36
+ static get observedAttributes() {
37
+ return ['value', 'disabled', 'readonly', 'error'];
38
+ }
39
+ connectedCallback() {
40
+ super.connectedCallback?.();
41
+ const raw = this.getAttribute('value') ?? '';
42
+ if (raw)
43
+ this._tags = raw.split(',').map(t => t.trim()).filter(Boolean);
44
+ }
45
+ template() {
46
+ const placeholder = this.getAttribute('placeholder') ?? 'Add tag...';
47
+ const label = this.getAttribute('label') ?? '';
48
+ const hint = this.getAttribute('hint') ?? '';
49
+ const error = this.getAttribute('error') ?? '';
50
+ const disabled = this.hasAttribute('disabled');
51
+ const readonly = this.hasAttribute('readonly');
52
+ const variant = this.getAttribute('variant') ?? 'default';
53
+ const bg = variant === 'filled' ? 'var(--nc-bg-secondary)' : 'var(--nc-bg)';
54
+ const border = error ? 'var(--nc-danger)' : 'var(--nc-border)';
55
+ const tagsHtml = this._tags.map((tag, i) => `
56
+ <span class="tag" data-index="${i}">
57
+ <span class="tag-text">${this._escape(tag)}</span>
58
+ ${!disabled && !readonly
59
+ ? `<button class="tag-remove" type="button" data-index="${i}" aria-label="Remove ${this._escape(tag)}">
60
+ <svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 12 12" fill="none">
61
+ <path d="M2 2l8 8M10 2l-8 8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
62
+ </svg>
63
+ </button>`
64
+ : ''}
65
+ </span>
66
+ `).join('');
67
+ return `
68
+ <style>
69
+ :host { display: block; font-family: var(--nc-font-family); }
70
+ .label {
71
+ display: block;
72
+ font-size: var(--nc-font-size-sm);
73
+ font-weight: var(--nc-font-weight-medium);
74
+ color: var(--nc-text);
75
+ margin-bottom: 6px;
76
+ }
77
+ .field {
78
+ display: flex;
79
+ flex-wrap: wrap;
80
+ align-items: center;
81
+ gap: 6px;
82
+ padding: 8px 10px;
83
+ background: ${bg};
84
+ border: 1px solid ${border};
85
+ border-radius: var(--nc-radius-md);
86
+ min-height: 42px;
87
+ cursor: ${disabled ? 'not-allowed' : 'text'};
88
+ transition: border-color var(--nc-transition-fast), box-shadow var(--nc-transition-fast);
89
+ opacity: ${disabled ? 0.5 : 1};
90
+ }
91
+ .field:focus-within {
92
+ border-color: var(--nc-primary);
93
+ box-shadow: 0 0 0 3px rgba(var(--nc-primary-rgb, 99,102,241),.15);
94
+ }
95
+ .tag {
96
+ display: inline-flex;
97
+ align-items: center;
98
+ gap: 4px;
99
+ background: var(--nc-primary);
100
+ color: var(--nc-white);
101
+ border-radius: var(--nc-radius-sm);
102
+ padding: 2px 8px;
103
+ font-size: var(--nc-font-size-xs);
104
+ font-weight: var(--nc-font-weight-medium);
105
+ line-height: 1.6;
106
+ white-space: nowrap;
107
+ max-width: 200px;
108
+ }
109
+ .tag-text {
110
+ overflow: hidden;
111
+ text-overflow: ellipsis;
112
+ white-space: nowrap;
113
+ }
114
+ .tag-remove {
115
+ background: none;
116
+ border: none;
117
+ padding: 0;
118
+ cursor: pointer;
119
+ color: inherit;
120
+ opacity: 0.7;
121
+ display: flex;
122
+ align-items: center;
123
+ line-height: 1;
124
+ flex-shrink: 0;
125
+ }
126
+ .tag-remove:hover { opacity: 1; }
127
+ input {
128
+ flex: 1 1 80px;
129
+ min-width: 80px;
130
+ border: none;
131
+ outline: none;
132
+ background: transparent;
133
+ font-family: inherit;
134
+ font-size: var(--nc-font-size-sm);
135
+ color: var(--nc-text);
136
+ padding: 0;
137
+ caret-color: var(--nc-primary);
138
+ }
139
+ input::placeholder { color: var(--nc-text-muted); }
140
+ input:disabled { cursor: not-allowed; }
141
+ .hint { font-size: var(--nc-font-size-xs); color: var(--nc-text-muted); margin-top: 5px; }
142
+ .error { font-size: var(--nc-font-size-xs); color: var(--nc-danger); margin-top: 5px; }
143
+ </style>
144
+ ${label ? `<label class="label">${label}</label>` : ''}
145
+ <div class="field" id="field">
146
+ ${tagsHtml}
147
+ ${!readonly
148
+ ? `<input
149
+ type="text"
150
+ id="input"
151
+ placeholder="${this._tags.length === 0 ? placeholder : ''}"
152
+ ${disabled ? 'disabled' : ''}
153
+ autocomplete="off"
154
+ spellcheck="false"
155
+ />`
156
+ : ''}
157
+ </div>
158
+ ${error ? `<p class="error">${error}</p>` : hint ? `<p class="hint">${hint}</p>` : ''}
159
+ `;
160
+ }
161
+ onMount() {
162
+ this._bindEvents();
163
+ }
164
+ _bindEvents() {
165
+ const input = this.$('#input');
166
+ if (!input)
167
+ return;
168
+ const delimiter = this.getAttribute('delimiter') ?? ',';
169
+ input.addEventListener('keydown', (e) => {
170
+ if (e.key === 'Enter' || (delimiter && e.key === delimiter)) {
171
+ e.preventDefault();
172
+ const val = input.value.trim();
173
+ if (val) {
174
+ this.addTag(val);
175
+ input.value = '';
176
+ }
177
+ }
178
+ else if (e.key === 'Backspace' && input.value === '' && this._tags.length > 0) {
179
+ this.removeTag(this._tags.length - 1);
180
+ }
181
+ });
182
+ input.addEventListener('input', () => {
183
+ const val = input.value;
184
+ const delim = this.getAttribute('delimiter') ?? ',';
185
+ if (delim && val.endsWith(delim)) {
186
+ const tag = val.slice(0, -delim.length).trim();
187
+ if (tag) {
188
+ this.addTag(tag);
189
+ input.value = '';
190
+ }
191
+ }
192
+ });
193
+ // Clicking the field focuses the input
194
+ this.$('#field')?.addEventListener('click', (e) => {
195
+ if (e.target.closest('.tag-remove'))
196
+ return;
197
+ input.focus();
198
+ });
199
+ this.shadowRoot.addEventListener('click', (e) => {
200
+ const btn = e.target.closest('.tag-remove');
201
+ if (btn) {
202
+ const idx = parseInt(btn.dataset.index ?? '-1', 10);
203
+ if (idx >= 0)
204
+ this.removeTag(idx);
205
+ }
206
+ });
207
+ }
208
+ // ── Public API ─────────────────────────────────────────────────────────────
209
+ getTags() { return [...this._tags]; }
210
+ setTags(tags) {
211
+ this._tags = [...tags];
212
+ this.render();
213
+ this._bindEvents();
214
+ this._emit('change');
215
+ }
216
+ addTag(tag) {
217
+ const maxAttr = this.getAttribute('max');
218
+ const minLen = parseInt(this.getAttribute('min-length') ?? '1', 10);
219
+ const maxLen = this.getAttribute('max-length');
220
+ const allowDup = this.hasAttribute('duplicate');
221
+ tag = tag.trim();
222
+ if (!tag || tag.length < minLen)
223
+ return;
224
+ if (maxLen && tag.length > parseInt(maxLen, 10))
225
+ return;
226
+ if (!allowDup && this._tags.includes(tag))
227
+ return;
228
+ if (maxAttr && this._tags.length >= parseInt(maxAttr, 10)) {
229
+ this.dispatchEvent(new CustomEvent('max-reached', { bubbles: true, composed: true }));
230
+ return;
231
+ }
232
+ this._tags.push(tag);
233
+ this.render();
234
+ this._bindEvents();
235
+ this.dispatchEvent(new CustomEvent('add', { detail: { tag }, bubbles: true, composed: true }));
236
+ this._emit('change');
237
+ }
238
+ removeTag(index) {
239
+ const tag = this._tags[index];
240
+ if (tag === undefined)
241
+ return;
242
+ this._tags.splice(index, 1);
243
+ this.render();
244
+ this._bindEvents();
245
+ this.dispatchEvent(new CustomEvent('remove', { detail: { tag, index }, bubbles: true, composed: true }));
246
+ this._emit('change');
247
+ this.$('#input')?.focus();
248
+ }
249
+ clear() { this.setTags([]); }
250
+ _emit(event) {
251
+ this.dispatchEvent(new CustomEvent(event, {
252
+ detail: { tags: [...this._tags] }, bubbles: true, composed: true,
253
+ }));
254
+ }
255
+ _escape(s) {
256
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
257
+ }
258
+ attributeChangedCallback(name, oldVal, newVal) {
259
+ if (oldVal === newVal || !this._mounted)
260
+ return;
261
+ if (name === 'value') {
262
+ this._tags = (newVal ?? '').split(',').map(t => t.trim()).filter(Boolean);
263
+ }
264
+ this.render();
265
+ this._bindEvents();
266
+ }
267
+ }
268
+ defineComponent('nc-tag-input', NcTagInput);
@@ -0,0 +1,15 @@
1
+ import { Component } from '../core/component.js';
2
+ export declare class NcTextarea 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
+ onMount(): void;
11
+ private bindEvents;
12
+ private autoResize;
13
+ private updateCounter;
14
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
15
+ }
@@ -0,0 +1,164 @@
1
+ import { Component, defineComponent } from '../core/component.js';
2
+ export class NcTextarea extends Component {
3
+ static useShadowDOM = true;
4
+ static attributeOptions = {
5
+ variant: ['default', 'filled'],
6
+ size: ['sm', 'md', 'lg']
7
+ };
8
+ static get observedAttributes() {
9
+ return ['name', 'value', 'placeholder', 'rows', 'disabled', 'readonly', 'maxlength', 'autoresize', 'size', 'variant'];
10
+ }
11
+ template() {
12
+ const value = this.getAttribute('value') || '';
13
+ const placeholder = this.getAttribute('placeholder') || '';
14
+ const rows = this.getAttribute('rows') || '4';
15
+ const disabled = this.hasAttribute('disabled');
16
+ const readonly = this.hasAttribute('readonly');
17
+ const maxlength = this.getAttribute('maxlength');
18
+ const autoresize = this.hasAttribute('autoresize');
19
+ const charCount = value.length;
20
+ return `
21
+ <style>
22
+ :host {
23
+ display: block;
24
+ font-family: var(--nc-font-family);
25
+ width: 100%;
26
+ }
27
+ .wrap {
28
+ position: relative;
29
+ display: flex;
30
+ flex-direction: column;
31
+ gap: var(--nc-spacing-xs, 0.25rem);
32
+ }
33
+ textarea {
34
+ width: 100%;
35
+ box-sizing: border-box;
36
+ padding: var(--nc-spacing-sm, 0.5rem) var(--nc-spacing-md, 0.75rem);
37
+ background: var(--nc-bg, #ffffff);
38
+ border: var(--nc-input-border, 1px solid #d1d5db);
39
+ border-radius: var(--nc-input-radius, 0.5rem);
40
+ color: var(--nc-text, #111827);
41
+ font-size: var(--nc-font-size-base, 1rem);
42
+ font-family: var(--nc-font-family);
43
+ line-height: var(--nc-line-height-normal, 1.5);
44
+ resize: ${autoresize ? 'none' : 'vertical'};
45
+ transition: border-color var(--nc-transition-fast, 160ms ease), box-shadow var(--nc-transition-fast, 160ms ease);
46
+ outline: none;
47
+ min-height: 80px;
48
+ opacity: ${disabled ? '0.5' : '1'};
49
+ cursor: ${disabled ? 'not-allowed' : 'auto'};
50
+ }
51
+ :host([size="sm"]) textarea {
52
+ padding: var(--nc-spacing-xs, 0.25rem) var(--nc-spacing-sm, 0.5rem);
53
+ font-size: var(--nc-font-size-sm, 0.875rem);
54
+ }
55
+ :host([size="lg"]) textarea {
56
+ padding: var(--nc-spacing-md, 1rem) var(--nc-spacing-lg, 1.5rem);
57
+ font-size: var(--nc-font-size-lg, 1.125rem);
58
+ }
59
+ :host([variant="filled"]) textarea {
60
+ background: var(--nc-bg-tertiary, #f3f4f6);
61
+ border-color: transparent;
62
+ }
63
+ :host([variant="filled"]) textarea:hover:not(:disabled) {
64
+ background: var(--nc-bg-secondary, #f8fafc);
65
+ }
66
+ textarea:hover:not(:disabled) {
67
+ border-color: var(--nc-input-focus-border, #10b981);
68
+ }
69
+ textarea:focus {
70
+ border-color: var(--nc-input-focus-border, #10b981);
71
+ box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.15);
72
+ }
73
+ textarea::placeholder { color: var(--nc-text-muted, #6b7280); }
74
+ .counter {
75
+ align-self: flex-end;
76
+ font-size: var(--nc-font-size-xs, 0.75rem);
77
+ color: var(--nc-text-muted, #6b7280);
78
+ line-height: 1;
79
+ }
80
+ .counter.over {
81
+ color: var(--nc-danger, #ef4444);
82
+ font-weight: var(--nc-font-weight-semibold, 600);
83
+ }
84
+ </style>
85
+
86
+ <div class="wrap">
87
+ <textarea
88
+ rows="${rows}"
89
+ ${maxlength ? `maxlength="${maxlength}"` : ''}
90
+ ${disabled ? 'disabled' : ''}
91
+ ${readonly ? 'readonly' : ''}
92
+ placeholder="${placeholder}"
93
+ name="${this.getAttribute('name') || ''}"
94
+ aria-multiline="true"
95
+ >${value}</textarea>
96
+ ${maxlength ? `<span class="counter${charCount > Number(maxlength) ? ' over' : ''}">${charCount} / ${maxlength}</span>` : ''}
97
+ </div>
98
+ `;
99
+ }
100
+ onMount() {
101
+ this.bindEvents();
102
+ }
103
+ bindEvents() {
104
+ const textarea = this.shadowRoot?.querySelector('textarea');
105
+ if (!textarea)
106
+ return;
107
+ if (this.hasAttribute('autoresize')) {
108
+ this.autoResize(textarea);
109
+ }
110
+ textarea.addEventListener('input', () => {
111
+ if (this.hasAttribute('autoresize'))
112
+ this.autoResize(textarea);
113
+ this.updateCounter(textarea.value);
114
+ this.dispatchEvent(new CustomEvent('input', {
115
+ bubbles: true,
116
+ composed: true,
117
+ detail: { value: textarea.value, name: this.getAttribute('name') || '' }
118
+ }));
119
+ });
120
+ textarea.addEventListener('change', () => {
121
+ this.setAttribute('value', textarea.value);
122
+ this.dispatchEvent(new CustomEvent('change', {
123
+ bubbles: true,
124
+ composed: true,
125
+ detail: { value: textarea.value, name: this.getAttribute('name') || '' }
126
+ }));
127
+ });
128
+ }
129
+ autoResize(textarea) {
130
+ textarea.style.height = 'auto';
131
+ textarea.style.height = `${textarea.scrollHeight}px`;
132
+ }
133
+ updateCounter(value) {
134
+ const maxlength = this.getAttribute('maxlength');
135
+ if (!maxlength)
136
+ return;
137
+ const counter = this.shadowRoot?.querySelector('.counter');
138
+ if (!counter)
139
+ return;
140
+ const count = value.length;
141
+ const max = Number(maxlength);
142
+ counter.textContent = `${count} / ${maxlength}`;
143
+ counter.classList.toggle('over', count > max);
144
+ }
145
+ attributeChangedCallback(name, oldValue, newValue) {
146
+ if (oldValue === newValue)
147
+ return;
148
+ if (name === 'value' && this._mounted) {
149
+ const textarea = this.shadowRoot?.querySelector('textarea');
150
+ if (textarea) {
151
+ textarea.value = newValue || '';
152
+ this.updateCounter(textarea.value);
153
+ if (this.hasAttribute('autoresize'))
154
+ this.autoResize(textarea);
155
+ }
156
+ return;
157
+ }
158
+ if (this._mounted) {
159
+ this.render();
160
+ this.bindEvents();
161
+ }
162
+ }
163
+ }
164
+ defineComponent('nc-textarea', NcTextarea);
@@ -0,0 +1,51 @@
1
+ /**
2
+ * NcTimePicker Component
3
+ *
4
+ * Attributes:
5
+ * - name: string
6
+ * - value: string - HH:MM or HH:MM:SS (24-hour)
7
+ * - format: '12'|'24' (default: '24')
8
+ * - show-seconds: boolean - include seconds column (default: false)
9
+ * - min: string - minimum time HH:MM
10
+ * - max: string - maximum time HH:MM
11
+ * - step: number - minute step interval (default: 1)
12
+ * - placeholder: string (default: '--:--')
13
+ * - disabled: boolean
14
+ * - readonly: boolean
15
+ * - size: 'sm'|'md'|'lg' (default: 'md')
16
+ *
17
+ * Events:
18
+ * - change: CustomEvent<{ value: string; name: string }>
19
+ *
20
+ * Usage:
21
+ * <nc-time-picker name="start" value="09:30"></nc-time-picker>
22
+ * <nc-time-picker name="alarm" format="12" show-seconds></nc-time-picker>
23
+ */
24
+ import { Component } from '../core/component.js';
25
+ export declare class NcTimePicker extends Component {
26
+ static useShadowDOM: boolean;
27
+ static get observedAttributes(): string[];
28
+ private _open;
29
+ private _h;
30
+ private _m;
31
+ private _s;
32
+ private _ampm;
33
+ private _initialized;
34
+ private _outsideClick;
35
+ constructor();
36
+ private _initFromAttr;
37
+ private _is12;
38
+ private _showSec;
39
+ private _displayValue;
40
+ template(): string;
41
+ onMount(): void;
42
+ private _bindEvents;
43
+ private _handleColSelect;
44
+ private _updateDisplay;
45
+ private _apply;
46
+ private _clear;
47
+ private _setNow;
48
+ private _scrollToSelected;
49
+ onUnmount(): void;
50
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
51
+ }