@ktjs/mui 0.18.9 → 0.20.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/dist/index.mjs CHANGED
@@ -1,30 +1,311 @@
1
- import { jsxs, jsx } from 'kt.js/jsx-runtime';
2
- import { ref as ref$1, createRedrawable as createRedrawable$1 } from 'kt.js';
1
+ // Cached native methods for performance optimization
2
+ const $isArray = Array.isArray;
3
+ const $isThenable = (o) => typeof o === 'object' && o !== null && typeof o.then === 'function';
3
4
 
4
- /**s
5
- * Alert component - mimics MUI Alert appearance and behavior
5
+ // Error handling utilities
6
+ const $throw = (message) => {
7
+ throw new Error('@ktjs/shared: ' + message);
8
+ };
9
+
10
+ // DOM manipulation utilities
11
+ // # dom natives
12
+ /**
13
+ * & Remove `bind` because it is shockingly slower than wrapper
14
+ * & `window.document` is safe because it is not configurable and its setter is undefined
6
15
  */
7
- function Alert(props) {
8
- const { children, style = '', severity = 'info', variant = 'standard', icon, 'kt:close': onClose } = props;
9
- const classes = `mui-alert mui-alert-${severity} mui-alert-${variant} ${props.class ? props.class : ''}`;
10
- // Convert sx object to style string
11
- let styleString = typeof style === 'string' ? style : '';
16
+ const $appendChild = HTMLElement.prototype.appendChild;
17
+ const originAppend = HTMLElement.prototype.append;
18
+ const $append = // for ie 9/10/11
19
+ typeof originAppend === 'function'
20
+ ? originAppend
21
+ : function (...nodes) {
22
+ if (nodes.length < 50) {
23
+ for (let i = 0; i < nodes.length; i++) {
24
+ const node = nodes[i];
25
+ if (typeof node === 'string') {
26
+ $appendChild.call(this, document.createTextNode(node));
27
+ }
28
+ else {
29
+ $appendChild.call(this, node);
30
+ }
31
+ }
32
+ }
33
+ else {
34
+ const fragment = document.createDocumentFragment();
35
+ for (let i = 0; i < nodes.length; i++) {
36
+ const node = nodes[i];
37
+ if (typeof node === 'string') {
38
+ $appendChild.call(fragment, document.createTextNode(node));
39
+ }
40
+ else {
41
+ $appendChild.call(fragment, node);
42
+ }
43
+ }
44
+ $appendChild.call(this, fragment);
45
+ }
46
+ };
47
+ const { get: $buttonDisabledGetter$2, set: $buttonDisabledSetter$2 } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
48
+
49
+ // Shared utilities and cached native methods for kt.js framework
50
+ // Re-export all utilities
51
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
52
+
53
+ const booleanHandler = (element, key, value) => {
54
+ if (key in element) {
55
+ element[key] = !!value;
56
+ }
57
+ else {
58
+ element.setAttribute(key, value);
59
+ }
60
+ };
61
+ const valueHandler = (element, key, value) => {
62
+ if (key in element) {
63
+ element[key] = value;
64
+ }
65
+ else {
66
+ element.setAttribute(key, value);
67
+ }
68
+ };
69
+ // Attribute handlers map for optimized lookup
70
+ const handlers = {
71
+ checked: booleanHandler,
72
+ selected: booleanHandler,
73
+ value: valueHandler,
74
+ valueAsDate: valueHandler,
75
+ valueAsNumber: valueHandler,
76
+ defaultValue: valueHandler,
77
+ defaultChecked: booleanHandler,
78
+ defaultSelected: booleanHandler,
79
+ disabled: booleanHandler,
80
+ readOnly: booleanHandler,
81
+ multiple: booleanHandler,
82
+ required: booleanHandler,
83
+ autofocus: booleanHandler,
84
+ open: booleanHandler,
85
+ controls: booleanHandler,
86
+ autoplay: booleanHandler,
87
+ loop: booleanHandler,
88
+ muted: booleanHandler,
89
+ defer: booleanHandler,
90
+ async: booleanHandler,
91
+ hidden: (element, _key, value) => (element.hidden = !!value),
92
+ };
93
+
94
+ const defaultHandler = (element, key, value) => element.setAttribute(key, value);
95
+ function attrIsObject(element, attr) {
96
+ const classValue = attr.class || attr.className;
97
+ if (classValue !== undefined) {
98
+ element.setAttribute('class', classValue);
99
+ }
100
+ const style = attr.style;
101
+ if (style) {
102
+ if (typeof style === 'string') {
103
+ element.setAttribute('style', style);
104
+ }
105
+ else if (typeof style === 'object') {
106
+ for (const key in style) {
107
+ element.style[key] = style[key];
108
+ }
109
+ }
110
+ }
111
+ for (const key in attr) {
112
+ if (key === 'class' ||
113
+ key === 'className' ||
114
+ key === 'style' ||
115
+ key === 'children' ||
116
+ key === 'k-if' ||
117
+ key === 'ref') {
118
+ continue;
119
+ }
120
+ const o = attr[key];
121
+ // normal event handler
122
+ if (key.startsWith('on:')) {
123
+ element.addEventListener(key.slice(3), o); // chop off the `on:`
124
+ }
125
+ // normal attributes
126
+ else {
127
+ (handlers[key] || defaultHandler)(element, key, o);
128
+ }
129
+ }
130
+ }
131
+ function applyAttr(element, attr) {
132
+ if (!attr) {
133
+ return;
134
+ }
135
+ if (typeof attr === 'object' && attr !== null) {
136
+ attrIsObject(element, attr);
137
+ }
138
+ else {
139
+ throw new Error('kt.js: attr must be an object.');
140
+ }
141
+ }
142
+
143
+ function apdSingle(element, c) {
144
+ // & JSX should ignore false, undefined, and null
145
+ if (c === false || c === undefined || c === null) {
146
+ return;
147
+ }
148
+ if (typeof c === 'object' && c !== null && 'isKT' in c) {
149
+ $append.call(element, c.value);
150
+ }
151
+ else {
152
+ $append.call(element, c);
153
+ // Handle KTFor anchor
154
+ const list = c.__kt_for_list__;
155
+ if ($isArray(list)) {
156
+ apd(element, list);
157
+ }
158
+ }
159
+ }
160
+ function apd(element, c) {
161
+ if ($isThenable(c)) {
162
+ c.then((r) => apd(element, r));
163
+ }
164
+ else if ($isArray(c)) {
165
+ for (let i = 0; i < c.length; i++) {
166
+ // & might be thenable here too
167
+ const ci = c[i];
168
+ if ($isThenable(ci)) {
169
+ const comment = document.createComment('ktjs-promise-placeholder');
170
+ $append.call(element, comment);
171
+ ci.then((awaited) => comment.replaceWith(awaited));
172
+ }
173
+ else {
174
+ apdSingle(element, ci);
175
+ }
176
+ }
177
+ }
178
+ else {
179
+ // & here is thened, so must be a simple elementj
180
+ apdSingle(element, c);
181
+ }
182
+ }
183
+ function applyContent(element, content) {
184
+ if ($isArray(content)) {
185
+ for (let i = 0; i < content.length; i++) {
186
+ apd(element, content[i]);
187
+ }
188
+ }
189
+ else {
190
+ apd(element, content);
191
+ }
192
+ }
193
+
194
+ const svgTempWrapper = document.createElement('div');
195
+ /**
196
+ * Create an enhanced HTMLElement.
197
+ * - Only supports HTMLElements, **NOT** SVGElements or other Elements.
198
+ * @param tag tag of an `HTMLElement`
199
+ * @param attr attribute object or className
200
+ * @param content a string or an array of HTMLEnhancedElement as child nodes
201
+ *
202
+ * ## About
203
+ * @package @ktjs/core
204
+ * @author Kasukabe Tsumugi <futami16237@gmail.com>
205
+ * @version 0.20.0 (Last Update: 2026.02.01 00:47:09.995)
206
+ * @license MIT
207
+ * @link https://github.com/baendlorel/kt.js
208
+ * @link https://baendlorel.github.io/ Welcome to my site!
209
+ * @description Core functionality for kt.js - DOM manipulation utilities with JSX/TSX support
210
+ * @copyright Copyright (c) 2026 Kasukabe Tsumugi. All rights reserved.
211
+ */
212
+ const h = (tag, attr, content) => {
213
+ if (typeof tag !== 'string') {
214
+ $throw('tagName must be a string.');
215
+ }
216
+ // * start creating the element
217
+ const element = document.createElement(tag);
218
+ // * Handle content
219
+ applyAttr(element, attr);
220
+ applyContent(element, content);
221
+ if (tag === 'svg') {
222
+ svgTempWrapper.innerHTML = element.outerHTML;
223
+ return svgTempWrapper.firstChild;
224
+ }
225
+ return element;
226
+ };
227
+
228
+ const dummyRef = { value: null };
229
+ /**
230
+ * @param tag html tag or function component
231
+ * @param props properties/attributes
232
+ */
233
+ function jsx(tag, props = {}) {
234
+ const ref = props.ref?.isKT ? props.ref : dummyRef;
235
+ let el;
236
+ if ('k-if' in props && !props['k-if']) {
237
+ // & make comment placeholder in case that ref might be redrawn later
238
+ el = document.createComment('k-if');
239
+ ref.value = el;
240
+ return el;
241
+ }
242
+ // Handle function components
243
+ if (typeof tag === 'function') {
244
+ el = tag(props);
245
+ }
246
+ else {
247
+ el = h(tag, props, props.children);
248
+ }
249
+ ref.value = el;
250
+ return el;
251
+ }
252
+ /**
253
+ * JSX runtime for React 17+ automatic runtime
254
+ * This is called when using jsx: "react-jsx" or "react-jsxdev"
255
+ */
256
+ const jsxs = jsx;
257
+
258
+ // Cached native methods for performance optimization
259
+ const $defines = Object.defineProperties;
260
+
261
+ // String manipulation utilities
262
+ /**
263
+ * Default empty function
264
+ */
265
+ const $emptyFn = (() => true);
266
+ const { get: $buttonDisabledGetter$1, set: $buttonDisabledSetter$1 } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
267
+ // # DOM utilities
268
+ const parseStyle = (style) => {
269
+ if (typeof style === 'string') {
270
+ return style;
271
+ }
12
272
  if (style && typeof style === 'object') {
13
- const sxStyles = Object.entries(style)
273
+ return Object.entries(style)
14
274
  .map(([key, value]) => {
15
275
  // Convert camelCase to kebab-case
16
276
  const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
17
277
  return `${cssKey}: ${value}`;
18
278
  })
19
279
  .join('; ');
20
- styleString = styleString ? `${styleString}; ${sxStyles}` : sxStyles;
21
280
  }
281
+ return '';
282
+ };
283
+ const generateHandler = (props, key) => {
284
+ const handler = props[key];
285
+ if (typeof handler === 'function') {
286
+ return handler;
287
+ }
288
+ else if (handler && typeof handler === 'object' && handler.isKT) {
289
+ return (value) => (handler.value = value);
290
+ }
291
+ return $emptyFn;
292
+ };
293
+
294
+ // Shared utilities and cached native methods for kt.js framework
295
+ // Re-export all utilities
296
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
297
+
298
+ function Alert(props) {
299
+ const { children, severity = 'info', variant = 'standard', icon, 'kt:close': onClose } = props;
300
+ const classes = `mui-alert mui-alert-${severity} mui-alert-${variant} ${props.class ? props.class : ''}`;
22
301
  // Icon SVG paths for different severities
23
302
  const getIcon = () => {
24
- if (icon === false)
303
+ if (icon === false) {
25
304
  return null;
26
- if (icon)
305
+ }
306
+ if (icon) {
27
307
  return icon;
308
+ }
28
309
  const iconSize = '22px';
29
310
  const iconClass = 'mui-alert-icon';
30
311
  switch (severity) {
@@ -40,55 +321,26 @@ function Alert(props) {
40
321
  }
41
322
  };
42
323
  const alertIcon = getIcon();
43
- const alert = (jsxs("div", { class: classes, style: styleString, role: "alert", children: [alertIcon && jsx("div", { class: "mui-alert-icon-wrapper", children: alertIcon }), jsx("div", { class: "mui-alert-message", children: children }), onClose && (jsx("button", { class: "mui-alert-close", "on:click": onClose, "aria-label": "Close", children: jsx("svg", { viewBox: "0 0 24 24", width: "18px", height: "18px", children: jsx("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }))] }));
324
+ const alert = (jsxs("div", { class: classes, style: parseStyle(props.style), role: "alert", children: [alertIcon && jsx("div", { class: "mui-alert-icon-wrapper", children: alertIcon }), jsx("div", { class: "mui-alert-message", children: children }), onClose && (jsx("button", { class: "mui-alert-close", "on:click": onClose, "aria-label": "Close", children: jsx("svg", { viewBox: "0 0 24 24", width: "18px", height: "18px", children: jsx("path", { fill: "currentColor", d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) }))] }));
44
325
  return alert;
45
326
  }
46
327
 
47
- const emptyFn = () => { };
48
- const generateHandler = (props, key) => {
49
- const handler = props[key];
50
- if (typeof handler === 'function') {
51
- return handler;
52
- }
53
- else if (handler && typeof handler === 'object' && handler.isKT) {
54
- return (value) => (handler.value = value);
55
- }
56
- return emptyFn;
57
- };
58
-
59
- const parseStyle = (style) => {
60
- if (typeof style === 'string') {
61
- return style;
62
- }
63
- if (style && typeof style === 'object') {
64
- return Object.entries(style)
65
- .map(([key, value]) => {
66
- // Convert camelCase to kebab-case
67
- const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
68
- return `${cssKey}: ${value}`;
69
- })
70
- .join('; ');
71
- }
72
- return '';
73
- };
74
-
75
328
  /**
76
329
  * Button component - mimics MUI Button appearance and behavior
77
330
  */
78
331
  function Button(props) {
79
- const { children, variant = 'text', color = 'primary', size = 'medium', disabled = false, fullWidth = false, iconOnly = false, startIcon, endIcon, type = 'button', 'on:click': onClick = emptyFn, } = props;
332
+ let { children, variant = 'text', color = 'primary', size = 'medium', disabled = false, fullWidth = false, iconOnly = false, startIcon, endIcon, type = 'button', 'on:click': onClick = $emptyFn, } = props;
80
333
  const classes = [
81
334
  'mui-button',
82
335
  `mui-button-${variant}`,
83
336
  `mui-button-${variant}-${color}`,
84
337
  `mui-button-size-${size}`,
85
- fullWidth && 'mui-button-fullwidth',
86
- iconOnly && 'mui-button-icon-only',
87
- disabled && 'mui-button-disabled',
338
+ fullWidth ? 'mui-button-fullwidth' : '',
339
+ iconOnly ? 'mui-button-icon-only' : '',
340
+ disabled ? 'mui-button-disabled' : '',
88
341
  props.class ? props.class : '',
89
- ]
90
- .filter(Boolean)
91
- .join(' ');
342
+ ].join(' ');
343
+ const rippleContainer = jsx("span", { class: "mui-button-ripple" });
92
344
  const handleClick = (e) => {
93
345
  if (disabled) {
94
346
  e.preventDefault();
@@ -96,7 +348,6 @@ function Button(props) {
96
348
  }
97
349
  // Create ripple effect
98
350
  const button = e.currentTarget;
99
- const rippleContainer = button.querySelector('.mui-button-ripple');
100
351
  if (rippleContainer) {
101
352
  const rect = button.getBoundingClientRect();
102
353
  const size = Math.max(rect.width, rect.height);
@@ -109,13 +360,21 @@ function Button(props) {
109
360
  ripple.classList.add('mui-button-ripple-effect');
110
361
  rippleContainer.appendChild(ripple);
111
362
  // Remove ripple after animation
112
- setTimeout(() => {
113
- ripple.remove();
114
- }, 600);
363
+ setTimeout(() => ripple.remove(), 600);
115
364
  }
116
365
  onClick(e);
117
366
  };
118
- return (jsxs("button", { class: classes, style: parseStyle(props.style), type: type, disabled: disabled, "on:click": handleClick, children: [startIcon && jsx("span", { class: "mui-button-start-icon", children: startIcon }), jsx("span", { class: "mui-button-label", children: children }), endIcon && jsx("span", { class: "mui-button-end-icon", children: endIcon }), jsx("span", { class: "mui-button-ripple" })] }));
367
+ const container = (jsxs("button", { class: classes, style: parseStyle(props.style), type: type, disabled: disabled, "on:click": handleClick, children: [startIcon && jsx("span", { class: "mui-button-start-icon", children: startIcon }), jsx("span", { class: "mui-button-label", children: children }), endIcon && jsx("span", { class: "mui-button-end-icon", children: endIcon }), rippleContainer] }));
368
+ $defines(container, {
369
+ disabled: {
370
+ get: $buttonDisabledGetter$1,
371
+ set: function (value) {
372
+ $buttonDisabledSetter$1.call(this, value);
373
+ this.classList.toggle('mui-button-disabled', value);
374
+ },
375
+ },
376
+ });
377
+ return container;
119
378
  }
120
379
 
121
380
  /**
@@ -156,7 +415,7 @@ function Checkbox(props) {
156
415
  // Initialize icon state
157
416
  toggleIcon(checked, indeterminate);
158
417
  const container = (jsxs("label", { class: `mui-checkbox-wrapper mui-checkbox-size-${size} ${disabled ? 'mui-checkbox-disabled' : ''} mui-checkbox-color-${color}`, children: [inputEl, jsxs("span", { class: "mui-checkbox-icon", children: [uncheckedIcon, checkedIcon, indeterminateIcon] }), jsx("span", { "k-if": label, class: "mui-checkbox-label", children: label })] }));
159
- Object.defineProperties(container, {
418
+ $defines(container, {
160
419
  checked: {
161
420
  get() {
162
421
  return checked;
@@ -222,7 +481,7 @@ function CheckboxGroup(props) {
222
481
  return Checkbox(o);
223
482
  });
224
483
  const container = (jsx("div", { class: `mui-checkbox-group ${row ? 'mui-checkbox-group-row' : ''} ${props.class ? props.class : ''}`, style: props.style ? props.style : '', role: "group", children: checkboxes }));
225
- Object.defineProperties(container, {
484
+ $defines(container, {
226
485
  value: {
227
486
  get() {
228
487
  return Array.from(selectedValues);
@@ -269,7 +528,7 @@ function CheckboxGroup(props) {
269
528
  * Only handles open/close state, title and content are passed as props
270
529
  */
271
530
  function Dialog(props) {
272
- let { open = false, 'kt:close': onClose = emptyFn, title, children, actions, maxWidth = 'sm', fullWidth = false, } = props;
531
+ let { open = false, 'kt:close': onClose = $emptyFn, title, children, actions, maxWidth = 'sm', fullWidth = false, } = props;
273
532
  // Handle ESC key - store handler for cleanup
274
533
  const keyDownHandler = (e) => {
275
534
  if (e.key === 'Escape') {
@@ -293,26 +552,28 @@ function Dialog(props) {
293
552
  }
294
553
  return originalRemove.call(container);
295
554
  };
296
- Object.defineProperty(container, 'open', {
297
- get: () => open,
298
- set: (isOpen) => {
299
- if (isOpen === open) {
300
- return;
301
- }
302
- open = isOpen;
303
- if (isOpen) {
304
- // Opening: set display first, then add class with double RAF for animation
305
- container.style.display = 'flex';
306
- setTimeout(() => container.classList.add('kt-dialog-backdrop-open'), 50);
307
- }
308
- else {
309
- container.classList.remove('kt-dialog-backdrop-open');
310
- setTimeout(() => {
311
- if (!open) {
312
- container.style.display = 'none';
313
- }
314
- }, 225);
315
- }
555
+ $defines(container, {
556
+ open: {
557
+ get: () => open,
558
+ set: (isOpen) => {
559
+ if (isOpen === open) {
560
+ return;
561
+ }
562
+ open = isOpen;
563
+ if (isOpen) {
564
+ // Opening: set display first, then add class with double RAF for animation
565
+ container.style.display = 'flex';
566
+ setTimeout(() => container.classList.add('kt-dialog-backdrop-open'), 50);
567
+ }
568
+ else {
569
+ container.classList.remove('kt-dialog-backdrop-open');
570
+ setTimeout(() => {
571
+ if (!open) {
572
+ container.style.display = 'none';
573
+ }
574
+ }, 225);
575
+ }
576
+ },
316
577
  },
317
578
  });
318
579
  return container;
@@ -342,54 +603,69 @@ function FormLabel(props) {
342
603
  return element;
343
604
  }
344
605
 
345
- const emptyPromiseHandler = () => ({});
346
- if (typeof Promise === 'undefined') {
347
- window.Promise = { resolve: emptyPromiseHandler, reject: emptyPromiseHandler };
348
- }
606
+ // Cached native methods for performance optimization
607
+ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
608
+
609
+ // Shared utilities and cached native methods for kt.js framework
610
+ // Re-export all utilities
611
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
349
612
 
350
613
  document.createElement('div');
351
614
 
615
+ class KTRef {
616
+ /**
617
+ * Indicates that this is a KTRef instance
618
+ */
619
+ isKT = true;
620
+ _value;
621
+ _onChanges;
622
+ constructor(_value, _onChanges) {
623
+ this._value = _value;
624
+ this._onChanges = _onChanges;
625
+ }
626
+ /**
627
+ * If new value and old value are both nodes, the old one will be replaced in the DOM
628
+ */
629
+ get value() {
630
+ return this._value;
631
+ }
632
+ set value(newValue) {
633
+ if (newValue === this._value) {
634
+ return;
635
+ }
636
+ // replace the old node with the new one in the DOM if both are nodes
637
+ if (this._value instanceof Node && newValue instanceof Node) {
638
+ if (newValue.contains(this._value)) {
639
+ this._value.remove();
640
+ }
641
+ this._value.replaceWith(newValue);
642
+ }
643
+ const oldValue = this._value;
644
+ this._value = newValue;
645
+ for (let i = 0; i < this._onChanges.length; i++) {
646
+ this._onChanges[i](newValue, oldValue);
647
+ }
648
+ }
649
+ addOnChange(callback) {
650
+ this._onChanges.push(callback);
651
+ }
652
+ removeOnChange(callback) {
653
+ for (let i = this._onChanges.length - 1; i >= 0; i--) {
654
+ if (this._onChanges[i] === callback) {
655
+ this._onChanges.splice(i, 1);
656
+ return true;
657
+ }
658
+ }
659
+ return false;
660
+ }
661
+ }
352
662
  /**
353
663
  * Reference to the created HTML element.
354
664
  * - can alse be used to store normal values, but it is not reactive.
355
665
  * @param value mostly an HTMLElement
356
666
  */
357
667
  function ref(value, onChange) {
358
- let _value = value;
359
- let _onChanges = [];
360
- return {
361
- isKT: true,
362
- get value() {
363
- return _value;
364
- },
365
- set value(newValue) {
366
- if (newValue === _value) {
367
- return;
368
- }
369
- // replace the old node with the new one in the DOM if both are nodes
370
- if (_value instanceof Node && newValue instanceof Node) {
371
- if (newValue.contains(_value)) {
372
- _value.remove();
373
- }
374
- _value.replaceWith(newValue);
375
- }
376
- const oldValue = _value;
377
- _value = newValue;
378
- for (let i = 0; i < _onChanges.length; i++) {
379
- _onChanges[i](newValue, oldValue);
380
- }
381
- },
382
- addOnChange: (callback) => _onChanges.push(callback),
383
- removeOnChange: (callback) => {
384
- for (let i = _onChanges.length - 1; i >= 0; i--) {
385
- if (_onChanges[i] === callback) {
386
- _onChanges.splice(i, 1);
387
- return true;
388
- }
389
- }
390
- return false;
391
- },
392
- };
668
+ return new KTRef(value, []);
393
669
  }
394
670
  /**
395
671
  * A helper to create redrawable elements
@@ -407,13 +683,12 @@ function ref(value, onChange) {
407
683
  */
408
684
  function createRedrawable(creator) {
409
685
  const elRef = ref();
410
- elRef.value = creator();
411
686
  const redraw = () => {
412
687
  elRef.value = creator(); // ref setter automatically calls replaceWith
413
- elRef.value.redraw = redraw;
688
+ elRef.redraw = redraw;
414
689
  return elRef.value;
415
690
  };
416
- elRef.value.redraw = redraw;
691
+ redraw();
417
692
  return elRef;
418
693
  }
419
694
 
@@ -433,15 +708,17 @@ function LinearProgress(props) {
433
708
  let progressValue = Math.min(Math.max(value, 0), 100);
434
709
  const barRef = ref();
435
710
  const container = (jsx("div", { class: classes, style: styleString, role: "progressbar", "aria-valuenow": progressValue, children: jsx("div", { ref: barRef, class: "mui-linear-progress-bar", style: variant === 'determinate' ? `width: ${progressValue}%` : '' }) }));
436
- Object.defineProperty(container, 'progress', {
437
- get() {
438
- return progressValue;
439
- },
440
- set(newValue) {
441
- progressValue = Math.min(Math.max(newValue, 0), 100);
442
- if (variant === 'determinate') {
443
- barRef.value.style.width = `${progressValue}%`;
444
- }
711
+ $defines(container, {
712
+ progress: {
713
+ get() {
714
+ return progressValue;
715
+ },
716
+ set(newValue) {
717
+ progressValue = Math.min(Math.max(newValue, 0), 100);
718
+ if (variant === 'determinate') {
719
+ barRef.value.style.width = `${progressValue}%`;
720
+ }
721
+ },
445
722
  },
446
723
  });
447
724
  return container;
@@ -514,7 +791,7 @@ function TextField(props) {
514
791
  const container = (jsxs("div", { class: 'mui-textfield-root ' + (props.class ? props.class : ''), style: parseStyle(props.style), children: [wrapperRef, helperTextEl] }));
515
792
  // Initialize classes
516
793
  setTimeout(() => updateContainerClass(), 0);
517
- Object.defineProperties(container, {
794
+ $defines(container, {
518
795
  value: {
519
796
  get() {
520
797
  return inputEl.value;
@@ -530,7 +807,7 @@ function TextField(props) {
530
807
  },
531
808
  set(newLabel) {
532
809
  label = newLabel;
533
- wrapperRef.value.redraw(); // label takes too much and should be redrawn
810
+ wrapperRef.redraw(); // label takes too much and should be redrawn
534
811
  updateContainerClass();
535
812
  },
536
813
  },
@@ -618,7 +895,7 @@ function Radio(props) {
618
895
  // initialize icon state
619
896
  toggleIcon(checked);
620
897
  const container = (jsxs("label", { class: `mui-radio-wrapper ${props.class ?? ''} mui-radio-size-${size} ${disabled ? 'mui-radio-disabled' : ''} mui-radio-color-${color}`, style: parseStyle(props.style), children: [input, jsxs("span", { class: "mui-radio-icon", children: [uncheckedIcon, checkedIcon] }), jsx("span", { class: "mui-radio-label", children: text })] }));
621
- Object.defineProperties(container, {
898
+ $defines(container, {
622
899
  value: {
623
900
  get() {
624
901
  return value;
@@ -665,7 +942,7 @@ function RadioGroup(props) {
665
942
  return Radio(o);
666
943
  });
667
944
  const container = (jsx("div", { class: `mui-radio-group ${row ? 'mui-radio-group-row' : ''} ${props.class ?? ''}`, style: parseStyle(props.style), role: "radiogroup", children: radios }));
668
- Object.defineProperties(container, {
945
+ $defines(container, {
669
946
  value: {
670
947
  get() {
671
948
  return value;
@@ -687,7 +964,8 @@ function Select(props) {
687
964
  const onChange = generateHandler(props, 'kt:change');
688
965
  let isOpen = false;
689
966
  let isFocused = false;
690
- const selectRef = ref$1();
967
+ const selectRef = ref();
968
+ const selectLabelRef = ref();
691
969
  // Toggle dropdown
692
970
  const toggleMenu = () => {
693
971
  if (disabled) {
@@ -700,12 +978,9 @@ function Select(props) {
700
978
  const updateMenu = () => {
701
979
  if (isOpen) {
702
980
  menu.value.style.display = 'block';
703
- // Trigger reflow to enable animation
704
- menu.value.offsetHeight;
705
- menu.value.classList.add('mui-select-menu-open');
981
+ void menu.value.offsetHeight; // & Trigger reflow to enable animation
706
982
  }
707
983
  else {
708
- menu.value.classList.remove('mui-select-menu-open');
709
984
  // Hide after animation completes
710
985
  setTimeout(() => {
711
986
  if (!isOpen) {
@@ -713,6 +988,7 @@ function Select(props) {
713
988
  }
714
989
  }, 200);
715
990
  }
991
+ menu.value.classList.toggle('mui-select-menu-open', isOpen);
716
992
  selectRef.value.classList.toggle('mui-select-open', isOpen);
717
993
  };
718
994
  // Handle option click
@@ -722,11 +998,8 @@ function Select(props) {
722
998
  onChange(value);
723
999
  updateMenu();
724
1000
  updateLabelState();
725
- valueDisplay.value.redraw();
726
- setTimeout(() => {
727
- // Trigger redraw of parent if needed
728
- menu.value.redraw();
729
- }, 200);
1001
+ valueDisplay.redraw();
1002
+ setTimeout(() => menu.redraw(), 200);
730
1003
  };
731
1004
  // Close menu when clicking outside
732
1005
  const handleClickOutside = (e) => {
@@ -746,17 +1019,9 @@ function Select(props) {
746
1019
  };
747
1020
  // Update label focused state
748
1021
  const updateLabelState = () => {
749
- const labelElement = selectRef.value.querySelector('.mui-select-label');
750
- if (labelElement) {
751
- if (isFocused || value) {
752
- labelElement.classList.add('focused');
753
- }
754
- else {
755
- labelElement.classList.remove('focused');
756
- }
757
- }
1022
+ selectLabelRef.value.classList?.toggle('focused', isFocused || !!value);
758
1023
  };
759
- const valueDisplay = createRedrawable$1(() => {
1024
+ const valueDisplay = createRedrawable(() => {
760
1025
  const o = options.find((opt) => opt.value === value);
761
1026
  let inner;
762
1027
  if (o === undefined) {
@@ -767,11 +1032,33 @@ function Select(props) {
767
1032
  }
768
1033
  return jsx("div", { class: "mui-select-display", children: inner });
769
1034
  });
770
- const menu = createRedrawable$1(() => {
771
- return (jsx("div", { class: "mui-select-menu", style: { display: 'none' }, children: options.map((option) => (jsx("div", { class: `mui-select-option ${option.value === value ? 'selected' : ''}`, "on:click": () => handleOptionClick(option.value), children: option.label }))) }));
1035
+ const menu = createRedrawable(() => {
1036
+ return (jsx("div", { class: "mui-select-menu", style: "display: none;", children: options.map((option) => (jsx("div", { class: `mui-select-option ${option.value === value ? 'selected' : ''}`, "on:click": () => handleOptionClick(option.value), children: option.label }))) }));
772
1037
  });
773
1038
  // Create container
774
- const container = (jsxs("div", { ref: selectRef, class: `mui-select-wrapper mui-select-size-${size} ${props.class ?? ''} ${fullWidth ? 'mui-select-fullWidth' : ''} ${disabled ? 'mui-select-disabled' : ''}`, style: parseStyle(props.style), children: [label && jsx("label", { class: `mui-select-label ${value || isFocused ? 'focused' : ''}`, children: label }), jsxs("div", { class: "mui-select-control mui-select-outlined", "on:click": toggleMenu, "on:focus": handleFocus, "on:blur": handleBlur, tabIndex: disabled ? -1 : 0, children: [valueDisplay, jsx("input", { type: "hidden", value: value }), jsx("fieldset", { class: "mui-select-fieldset", children: jsx("legend", { children: jsx("span", { children: label }) }) }), jsx("svg", { class: "mui-select-icon", focusable: "false", "aria-hidden": "true", viewBox: "0 0 24 24", width: "24", height: "24", children: jsx("path", { d: "M7 10l5 5 5-5Z", fill: "currentColor" }) })] }), menu] }));
1039
+ const container = (jsxs("div", { ref: selectRef, class: `mui-select-wrapper mui-select-size-${size} ${props.class ?? ''} ${fullWidth ? 'mui-select-fullWidth' : ''} ${disabled ? 'mui-select-disabled' : ''}`, style: parseStyle(props.style), children: [jsx("label", { "k-if": label, ref: selectLabelRef, class: `mui-select-label ${value || isFocused ? 'focused' : ''}`, children: label }), jsxs("div", { class: "mui-select-control mui-select-outlined", "on:click": toggleMenu, "on:focus": handleFocus, "on:blur": handleBlur, tabIndex: disabled ? -1 : 0, children: [valueDisplay, jsx("input", { type: "hidden", value: value }), jsx("fieldset", { class: "mui-select-fieldset", children: jsx("legend", { children: jsx("span", { children: label }) }) }), jsx("svg", { class: "mui-select-icon", focusable: "false", "aria-hidden": "true", viewBox: "0 0 24 24", width: "24", height: "24", children: jsx("path", { d: "M7 10l5 5 5-5Z", fill: "currentColor" }) })] }), menu] }));
1040
+ $defines(container, {
1041
+ value: {
1042
+ get: () => value,
1043
+ set: (newValue) => {
1044
+ value = newValue;
1045
+ updateLabelState();
1046
+ valueDisplay.redraw();
1047
+ menu.redraw();
1048
+ },
1049
+ },
1050
+ disabled: {
1051
+ get: () => disabled,
1052
+ set: (newDisabled) => {
1053
+ disabled = newDisabled;
1054
+ if (disabled) {
1055
+ isOpen = false;
1056
+ updateMenu();
1057
+ }
1058
+ container.classList.toggle('mui-select-disabled', disabled);
1059
+ },
1060
+ },
1061
+ });
775
1062
  // Add global click listener
776
1063
  setTimeout(() => {
777
1064
  document.removeEventListener('click', handleClickOutside);
@@ -869,4 +1156,4 @@ function SelectAllIcon(props) {
869
1156
  return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z" }) }));
870
1157
  }
871
1158
 
872
- export { Alert, Button, Checkbox, CheckboxGroup, ColorLensIcon, CompressIcon, ContentCopyIcon, ContentPasteIcon, DeleteIcon, Dialog, DownloadIcon, ExpandMoreIcon, FileOpenIcon as FileOpen, FileOpenIcon, FolderOpenIcon, FormLabel, HomeIcon, LinearProgress, MenuIcon, NewReleasesIcon, PlayArrowIcon, QueuePlayNextIcon, Radio, RadioGroup, SaveIcon, Select, SelectAllIcon, SettingsIcon, StopIcon, SubtitlesIcon, TextField, UploadFileIcon, VideoFileIcon, WallpaperIcon };
1159
+ export { Alert, Button, Checkbox, CheckboxGroup, ColorLensIcon, CompressIcon, ContentCopyIcon, ContentPasteIcon, DeleteIcon, Dialog, DownloadIcon, ExpandMoreIcon, FileOpenIcon, FolderOpenIcon, FormLabel, HomeIcon, LinearProgress, MenuIcon, NewReleasesIcon, PlayArrowIcon, QueuePlayNextIcon, Radio, RadioGroup, SaveIcon, Select, SelectAllIcon, SettingsIcon, StopIcon, SubtitlesIcon, TextField, UploadFileIcon, VideoFileIcon, WallpaperIcon };