@ktjs/mui 0.19.0 → 0.20.2

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
@@ -8,6 +8,7 @@ const $throw = (message) => {
8
8
  };
9
9
 
10
10
  // DOM manipulation utilities
11
+ // # dom natives
11
12
  /**
12
13
  * & Remove `bind` because it is shockingly slower than wrapper
13
14
  * & `window.document` is safe because it is not configurable and its setter is undefined
@@ -43,10 +44,11 @@ const $append = // for ie 9/10/11
43
44
  $appendChild.call(this, fragment);
44
45
  }
45
46
  };
47
+ const { get: $buttonDisabledGetter$2, set: $buttonDisabledSetter$2 } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
46
48
 
47
49
  // Shared utilities and cached native methods for kt.js framework
48
50
  // Re-export all utilities
49
- Object.defineProperty(window, '@ktjs/shared', { value: '0.19.0' });
51
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
50
52
 
51
53
  const booleanHandler = (element, key, value) => {
52
54
  if (key in element) {
@@ -189,7 +191,14 @@ function applyContent(element, content) {
189
191
  }
190
192
  }
191
193
 
192
- const svgTempWrapper = document.createElement('div');
194
+ document.createElement('div');
195
+ const htmlCreator = (tag) => document.createElement(tag);
196
+ const svgCreator = (tag) => document.createElementNS('http://www.w3.org/2000/svg', tag);
197
+ const mathMLCreator = (tag) => document.createElementNS('http://www.w3.org/1998/Math/MathML', tag);
198
+ let creator = htmlCreator;
199
+ // # consts
200
+ const SVG_ATTR_FLAG = '__kt_svg__';
201
+ const MATHML_ATTR_FLAG = '__kt_mathml__';
193
202
  /**
194
203
  * Create an enhanced HTMLElement.
195
204
  * - Only supports HTMLElements, **NOT** SVGElements or other Elements.
@@ -200,7 +209,7 @@ const svgTempWrapper = document.createElement('div');
200
209
  * ## About
201
210
  * @package @ktjs/core
202
211
  * @author Kasukabe Tsumugi <futami16237@gmail.com>
203
- * @version 0.19.0 (Last Update: 2026.01.31 22:50:55.987)
212
+ * @version 0.20.3 (Last Update: 2026.02.01 18:38:02.198)
204
213
  * @license MIT
205
214
  * @link https://github.com/baendlorel/kt.js
206
215
  * @link https://baendlorel.github.io/ Welcome to my site!
@@ -211,15 +220,32 @@ const h = (tag, attr, content) => {
211
220
  if (typeof tag !== 'string') {
212
221
  $throw('tagName must be a string.');
213
222
  }
223
+ if (attr) {
224
+ if (SVG_ATTR_FLAG in attr) {
225
+ delete attr[SVG_ATTR_FLAG];
226
+ creator = svgCreator;
227
+ }
228
+ else if (MATHML_ATTR_FLAG in attr) {
229
+ delete attr[MATHML_ATTR_FLAG];
230
+ creator = mathMLCreator;
231
+ }
232
+ else {
233
+ creator = htmlCreator;
234
+ }
235
+ }
214
236
  // * start creating the element
215
- const element = document.createElement(tag);
237
+ const element = creator(tag);
216
238
  // * Handle content
217
239
  applyAttr(element, attr);
218
240
  applyContent(element, content);
219
- if (tag === 'svg') {
220
- svgTempWrapper.innerHTML = element.outerHTML;
221
- return svgTempWrapper.firstChild;
222
- }
241
+ // if (tag === 'svg') {
242
+ // tempWrapper.innerHTML = element.outerHTML;
243
+ // return tempWrapper.firstChild as HTML<T>;
244
+ // }
245
+ // if (tag === 'math') {
246
+ // tempWrapper.innerHTML = element.outerHTML;
247
+ // return tempWrapper.firstChild as HTML<T>;
248
+ // }
223
249
  return element;
224
250
  };
225
251
 
@@ -228,21 +254,13 @@ const dummyRef = { value: null };
228
254
  * @param tag html tag or function component
229
255
  * @param props properties/attributes
230
256
  */
231
- function jsx(tag, props = {}) {
257
+ function jsx(tag, props) {
232
258
  const ref = props.ref?.isKT ? props.ref : dummyRef;
233
259
  let el;
234
- const redraw = (newProps) => {
235
- props = newProps ? { ...props, ...newProps } : props;
236
- el = jsx(tag, props);
237
- if (ref !== dummyRef) {
238
- ref.value = el; // & ref setter automatically replaces old element in DOM
239
- }
240
- return el;
241
- };
242
260
  if ('k-if' in props && !props['k-if']) {
261
+ // & make comment placeholder in case that ref might be redrawn later
243
262
  el = document.createComment('k-if');
244
- ref.value = el; // & ref setter automatically replaces old element in DOM
245
- el.redraw = redraw;
263
+ ref.value = el;
246
264
  return el;
247
265
  }
248
266
  // Handle function components
@@ -252,7 +270,6 @@ function jsx(tag, props = {}) {
252
270
  else {
253
271
  el = h(tag, props, props.children);
254
272
  }
255
- el.redraw ??= redraw;
256
273
  ref.value = el;
257
274
  return el;
258
275
  }
@@ -262,57 +279,16 @@ function jsx(tag, props = {}) {
262
279
  */
263
280
  const jsxs = jsx;
264
281
 
265
- /**s
266
- * Alert component - mimics MUI Alert appearance and behavior
267
- */
268
- function Alert(props) {
269
- const { children, style = '', severity = 'info', variant = 'standard', icon, 'kt:close': onClose } = props;
270
- const classes = `mui-alert mui-alert-${severity} mui-alert-${variant} ${props.class ? props.class : ''}`;
271
- // Convert sx object to style string
272
- let styleString = typeof style === 'string' ? style : '';
273
- if (style && typeof style === 'object') {
274
- const sxStyles = Object.entries(style)
275
- .map(([key, value]) => {
276
- // Convert camelCase to kebab-case
277
- const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
278
- return `${cssKey}: ${value}`;
279
- })
280
- .join('; ');
281
- styleString = styleString ? `${styleString}; ${sxStyles}` : sxStyles;
282
- }
283
- // Icon SVG paths for different severities
284
- const getIcon = () => {
285
- if (icon === false)
286
- return null;
287
- if (icon)
288
- return icon;
289
- const iconSize = '22px';
290
- const iconClass = 'mui-alert-icon';
291
- switch (severity) {
292
- case 'success':
293
- return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) }));
294
- case 'error':
295
- return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" }) }));
296
- case 'warning':
297
- return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" }) }));
298
- case 'info':
299
- default:
300
- return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" }) }));
301
- }
302
- };
303
- const alertIcon = getIcon();
304
- 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" }) }) }))] }));
305
- return alert;
306
- }
307
-
308
282
  // Cached native methods for performance optimization
283
+ const $defines = Object.defineProperties;
309
284
 
310
285
  // String manipulation utilities
311
286
  /**
312
287
  * Default empty function
313
288
  */
314
289
  const $emptyFn = (() => true);
315
- // Style parsing utilities
290
+ const { get: $buttonDisabledGetter$1, set: $buttonDisabledSetter$1 } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
291
+ // # DOM utilities
316
292
  const parseStyle = (style) => {
317
293
  if (typeof style === 'string') {
318
294
  return style;
@@ -341,25 +317,54 @@ const generateHandler = (props, key) => {
341
317
 
342
318
  // Shared utilities and cached native methods for kt.js framework
343
319
  // Re-export all utilities
344
- Object.defineProperty(window, '@ktjs/shared', { value: '0.19.0' });
320
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
321
+
322
+ function Alert(props) {
323
+ const { children, severity = 'info', variant = 'standard', icon, 'kt:close': onClose } = props;
324
+ const classes = `mui-alert mui-alert-${severity} mui-alert-${variant} ${props.class ? props.class : ''}`;
325
+ // Icon SVG paths for different severities
326
+ const getIcon = () => {
327
+ if (icon === false) {
328
+ return null;
329
+ }
330
+ if (icon) {
331
+ return icon;
332
+ }
333
+ const iconSize = '22px';
334
+ const iconClass = 'mui-alert-icon';
335
+ switch (severity) {
336
+ case 'success':
337
+ return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" }) }));
338
+ case 'error':
339
+ return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" }) }));
340
+ case 'warning':
341
+ return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" }) }));
342
+ case 'info':
343
+ default:
344
+ return (jsx("svg", { class: iconClass, viewBox: "0 0 24 24", width: iconSize, height: iconSize, children: jsx("path", { fill: "currentColor", d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" }) }));
345
+ }
346
+ };
347
+ const alertIcon = getIcon();
348
+ 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 }), jsx("button", { "k-if": onClose, 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" }) }) })] }));
349
+ return alert;
350
+ }
345
351
 
346
352
  /**
347
353
  * Button component - mimics MUI Button appearance and behavior
348
354
  */
349
355
  function Button(props) {
350
- const { children, variant = 'text', color = 'primary', size = 'medium', disabled = false, fullWidth = false, iconOnly = false, startIcon, endIcon, type = 'button', 'on:click': onClick = $emptyFn, } = props;
356
+ let { children, variant = 'text', color = 'primary', size = 'medium', disabled = false, fullWidth = false, iconOnly = false, startIcon, endIcon, type = 'button', 'on:click': onClick = $emptyFn, } = props;
351
357
  const classes = [
352
358
  'mui-button',
353
359
  `mui-button-${variant}`,
354
360
  `mui-button-${variant}-${color}`,
355
361
  `mui-button-size-${size}`,
356
- fullWidth && 'mui-button-fullwidth',
357
- iconOnly && 'mui-button-icon-only',
358
- disabled && 'mui-button-disabled',
362
+ fullWidth ? 'mui-button-fullwidth' : '',
363
+ iconOnly ? 'mui-button-icon-only' : '',
364
+ disabled ? 'mui-button-disabled' : '',
359
365
  props.class ? props.class : '',
360
- ]
361
- .filter(Boolean)
362
- .join(' ');
366
+ ].join(' ');
367
+ const rippleContainer = jsx("span", { class: "mui-button-ripple" });
363
368
  const handleClick = (e) => {
364
369
  if (disabled) {
365
370
  e.preventDefault();
@@ -367,7 +372,6 @@ function Button(props) {
367
372
  }
368
373
  // Create ripple effect
369
374
  const button = e.currentTarget;
370
- const rippleContainer = button.querySelector('.mui-button-ripple');
371
375
  if (rippleContainer) {
372
376
  const rect = button.getBoundingClientRect();
373
377
  const size = Math.max(rect.width, rect.height);
@@ -380,13 +384,21 @@ function Button(props) {
380
384
  ripple.classList.add('mui-button-ripple-effect');
381
385
  rippleContainer.appendChild(ripple);
382
386
  // Remove ripple after animation
383
- setTimeout(() => {
384
- ripple.remove();
385
- }, 600);
387
+ setTimeout(() => ripple.remove(), 600);
386
388
  }
387
389
  onClick(e);
388
390
  };
389
- 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" })] }));
391
+ 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] }));
392
+ $defines(container, {
393
+ disabled: {
394
+ get: $buttonDisabledGetter$1,
395
+ set: function (value) {
396
+ $buttonDisabledSetter$1.call(this, value);
397
+ this.classList.toggle('mui-button-disabled', value);
398
+ },
399
+ },
400
+ });
401
+ return container;
390
402
  }
391
403
 
392
404
  /**
@@ -427,7 +439,7 @@ function Checkbox(props) {
427
439
  // Initialize icon state
428
440
  toggleIcon(checked, indeterminate);
429
441
  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 })] }));
430
- Object.defineProperties(container, {
442
+ $defines(container, {
431
443
  checked: {
432
444
  get() {
433
445
  return checked;
@@ -493,7 +505,7 @@ function CheckboxGroup(props) {
493
505
  return Checkbox(o);
494
506
  });
495
507
  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 }));
496
- Object.defineProperties(container, {
508
+ $defines(container, {
497
509
  value: {
498
510
  get() {
499
511
  return Array.from(selectedValues);
@@ -564,26 +576,28 @@ function Dialog(props) {
564
576
  }
565
577
  return originalRemove.call(container);
566
578
  };
567
- Object.defineProperty(container, 'open', {
568
- get: () => open,
569
- set: (isOpen) => {
570
- if (isOpen === open) {
571
- return;
572
- }
573
- open = isOpen;
574
- if (isOpen) {
575
- // Opening: set display first, then add class with double RAF for animation
576
- container.style.display = 'flex';
577
- setTimeout(() => container.classList.add('kt-dialog-backdrop-open'), 50);
578
- }
579
- else {
580
- container.classList.remove('kt-dialog-backdrop-open');
581
- setTimeout(() => {
582
- if (!open) {
583
- container.style.display = 'none';
584
- }
585
- }, 225);
586
- }
579
+ $defines(container, {
580
+ open: {
581
+ get: () => open,
582
+ set: (isOpen) => {
583
+ if (isOpen === open) {
584
+ return;
585
+ }
586
+ open = isOpen;
587
+ if (isOpen) {
588
+ // Opening: set display first, then add class with double RAF for animation
589
+ container.style.display = 'flex';
590
+ setTimeout(() => container.classList.add('kt-dialog-backdrop-open'), 50);
591
+ }
592
+ else {
593
+ container.classList.remove('kt-dialog-backdrop-open');
594
+ setTimeout(() => {
595
+ if (!open) {
596
+ container.style.display = 'none';
597
+ }
598
+ }, 225);
599
+ }
600
+ },
587
601
  },
588
602
  });
589
603
  return container;
@@ -614,10 +628,11 @@ function FormLabel(props) {
614
628
  }
615
629
 
616
630
  // Cached native methods for performance optimization
631
+ const { get: $buttonDisabledGetter, set: $buttonDisabledSetter } = Object.getOwnPropertyDescriptor(HTMLButtonElement.prototype, 'disabled');
617
632
 
618
633
  // Shared utilities and cached native methods for kt.js framework
619
634
  // Re-export all utilities
620
- Object.defineProperty(window, '@ktjs/shared', { value: '0.19.0' });
635
+ Object.defineProperty(window, '@ktjs/shared', { value: '0.20.0' });
621
636
 
622
637
  document.createElement('div');
623
638
 
@@ -626,7 +641,13 @@ class KTRef {
626
641
  * Indicates that this is a KTRef instance
627
642
  */
628
643
  isKT = true;
644
+ /**
645
+ * @internal
646
+ */
629
647
  _value;
648
+ /**
649
+ * @internal
650
+ */
630
651
  _onChanges;
631
652
  constructor(_value, _onChanges) {
632
653
  this._value = _value;
@@ -692,13 +713,12 @@ function ref(value, onChange) {
692
713
  */
693
714
  function createRedrawable(creator) {
694
715
  const elRef = ref();
695
- elRef.value = creator();
696
716
  const redraw = () => {
697
717
  elRef.value = creator(); // ref setter automatically calls replaceWith
698
- elRef.value.redraw = redraw;
718
+ elRef.redraw = redraw;
699
719
  return elRef.value;
700
720
  };
701
- elRef.value.redraw = redraw;
721
+ redraw();
702
722
  return elRef;
703
723
  }
704
724
 
@@ -718,15 +738,17 @@ function LinearProgress(props) {
718
738
  let progressValue = Math.min(Math.max(value, 0), 100);
719
739
  const barRef = ref();
720
740
  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}%` : '' }) }));
721
- Object.defineProperty(container, 'progress', {
722
- get() {
723
- return progressValue;
724
- },
725
- set(newValue) {
726
- progressValue = Math.min(Math.max(newValue, 0), 100);
727
- if (variant === 'determinate') {
728
- barRef.value.style.width = `${progressValue}%`;
729
- }
741
+ $defines(container, {
742
+ progress: {
743
+ get() {
744
+ return progressValue;
745
+ },
746
+ set(newValue) {
747
+ progressValue = Math.min(Math.max(newValue, 0), 100);
748
+ if (variant === 'determinate') {
749
+ barRef.value.style.width = `${progressValue}%`;
750
+ }
751
+ },
730
752
  },
731
753
  });
732
754
  return container;
@@ -789,17 +811,27 @@ function TextField(props) {
789
811
  updateContainerClass();
790
812
  onBlur(inputEl.value);
791
813
  };
814
+ const handleWrapperMouseDown = (e) => {
815
+ if (disabled) {
816
+ return;
817
+ }
818
+ const target = e.target;
819
+ if (!target || target === inputEl) {
820
+ return;
821
+ }
822
+ setTimeout(() => inputEl.focus(), 0);
823
+ };
792
824
  const getPlaceholder = () => (label && !isFocused && !value ? '' : placeholder);
793
825
  let isFocused = false;
794
826
  const inputEl = multiline
795
827
  ? (jsx("textarea", { class: "mui-textfield-input", placeholder: getPlaceholder(), value: value, disabled: disabled, readOnly: readonly, required: required, rows: rows, "on:input": handleInput, "on:change": handleChange, "on:focus": handleFocus, "on:blur": handleBlur }))
796
828
  : (jsx("input", { type: type, class: "mui-textfield-input", placeholder: getPlaceholder(), value: value, disabled: disabled, readOnly: readonly, required: required, "on:input": handleInput, "on:change": handleChange, "on:focus": handleFocus, "on:blur": handleBlur }));
797
829
  const helperTextEl = jsx("p", { class: "mui-textfield-helper-text", children: helperText });
798
- const wrapperRef = createRedrawable(() => (jsxs("div", { class: "mui-textfield-wrapper", children: [jsxs("label", { "k-if": label, class: "mui-textfield-label", children: [label, required && jsx("span", { class: "mui-textfield-required", children: "*" })] }), jsx("div", { class: "mui-textfield-input-wrapper", children: inputEl }), jsx("fieldset", { class: "mui-textfield-fieldset", children: jsx("legend", { "k-if": label, class: "mui-textfield-legend", children: jsxs("span", { children: [label, required && '*'] }) }) })] })));
830
+ const wrapperRef = createRedrawable(() => (jsxs("div", { class: "mui-textfield-wrapper", "on:mousedown": handleWrapperMouseDown, children: [jsxs("label", { "k-if": label, class: "mui-textfield-label", children: [label, required && jsx("span", { class: "mui-textfield-required", children: "*" })] }), jsx("div", { class: "mui-textfield-input-wrapper", children: inputEl }), jsx("fieldset", { class: "mui-textfield-fieldset", children: jsx("legend", { "k-if": label, class: "mui-textfield-legend", children: jsxs("span", { children: [label, required && '*'] }) }) })] })));
799
831
  const container = (jsxs("div", { class: 'mui-textfield-root ' + (props.class ? props.class : ''), style: parseStyle(props.style), children: [wrapperRef, helperTextEl] }));
800
832
  // Initialize classes
801
833
  setTimeout(() => updateContainerClass(), 0);
802
- Object.defineProperties(container, {
834
+ $defines(container, {
803
835
  value: {
804
836
  get() {
805
837
  return inputEl.value;
@@ -815,7 +847,7 @@ function TextField(props) {
815
847
  },
816
848
  set(newLabel) {
817
849
  label = newLabel;
818
- wrapperRef.value.redraw(); // label takes too much and should be redrawn
850
+ wrapperRef.redraw(); // label takes too much and should be redrawn
819
851
  updateContainerClass();
820
852
  },
821
853
  },
@@ -903,7 +935,7 @@ function Radio(props) {
903
935
  // initialize icon state
904
936
  toggleIcon(checked);
905
937
  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 })] }));
906
- Object.defineProperties(container, {
938
+ $defines(container, {
907
939
  value: {
908
940
  get() {
909
941
  return value;
@@ -950,7 +982,7 @@ function RadioGroup(props) {
950
982
  return Radio(o);
951
983
  });
952
984
  const container = (jsx("div", { class: `mui-radio-group ${row ? 'mui-radio-group-row' : ''} ${props.class ?? ''}`, style: parseStyle(props.style), role: "radiogroup", children: radios }));
953
- Object.defineProperties(container, {
985
+ $defines(container, {
954
986
  value: {
955
987
  get() {
956
988
  return value;
@@ -973,6 +1005,7 @@ function Select(props) {
973
1005
  let isOpen = false;
974
1006
  let isFocused = false;
975
1007
  const selectRef = ref();
1008
+ const selectLabelRef = ref();
976
1009
  // Toggle dropdown
977
1010
  const toggleMenu = () => {
978
1011
  if (disabled) {
@@ -985,12 +1018,9 @@ function Select(props) {
985
1018
  const updateMenu = () => {
986
1019
  if (isOpen) {
987
1020
  menu.value.style.display = 'block';
988
- // Trigger reflow to enable animation
989
- void menu.value.offsetHeight;
990
- menu.value.classList.add('mui-select-menu-open');
1021
+ void menu.value.offsetHeight; // & Trigger reflow to enable animation
991
1022
  }
992
1023
  else {
993
- menu.value.classList.remove('mui-select-menu-open');
994
1024
  // Hide after animation completes
995
1025
  setTimeout(() => {
996
1026
  if (!isOpen) {
@@ -998,6 +1028,7 @@ function Select(props) {
998
1028
  }
999
1029
  }, 200);
1000
1030
  }
1031
+ menu.value.classList.toggle('mui-select-menu-open', isOpen);
1001
1032
  selectRef.value.classList.toggle('mui-select-open', isOpen);
1002
1033
  };
1003
1034
  // Handle option click
@@ -1007,11 +1038,8 @@ function Select(props) {
1007
1038
  onChange(value);
1008
1039
  updateMenu();
1009
1040
  updateLabelState();
1010
- valueDisplay.value.redraw();
1011
- setTimeout(() => {
1012
- // Trigger redraw of parent if needed
1013
- menu.value.redraw();
1014
- }, 200);
1041
+ valueDisplay.redraw();
1042
+ setTimeout(() => menu.redraw(), 200);
1015
1043
  };
1016
1044
  // Close menu when clicking outside
1017
1045
  const handleClickOutside = (e) => {
@@ -1031,15 +1059,7 @@ function Select(props) {
1031
1059
  };
1032
1060
  // Update label focused state
1033
1061
  const updateLabelState = () => {
1034
- const labelElement = selectRef.value.querySelector('.mui-select-label');
1035
- if (labelElement) {
1036
- if (isFocused || value) {
1037
- labelElement.classList.add('focused');
1038
- }
1039
- else {
1040
- labelElement.classList.remove('focused');
1041
- }
1042
- }
1062
+ selectLabelRef.value.classList?.toggle('focused', isFocused || !!value);
1043
1063
  };
1044
1064
  const valueDisplay = createRedrawable(() => {
1045
1065
  const o = options.find((opt) => opt.value === value);
@@ -1053,10 +1073,32 @@ function Select(props) {
1053
1073
  return jsx("div", { class: "mui-select-display", children: inner });
1054
1074
  });
1055
1075
  const menu = createRedrawable(() => {
1056
- 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 }))) }));
1076
+ 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 }))) }));
1057
1077
  });
1058
1078
  // Create container
1059
- 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] }));
1079
+ 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] }));
1080
+ $defines(container, {
1081
+ value: {
1082
+ get: () => value,
1083
+ set: (newValue) => {
1084
+ value = newValue;
1085
+ updateLabelState();
1086
+ valueDisplay.redraw();
1087
+ menu.redraw();
1088
+ },
1089
+ },
1090
+ disabled: {
1091
+ get: () => disabled,
1092
+ set: (newDisabled) => {
1093
+ disabled = newDisabled;
1094
+ if (disabled) {
1095
+ isOpen = false;
1096
+ updateMenu();
1097
+ }
1098
+ container.classList.toggle('mui-select-disabled', disabled);
1099
+ },
1100
+ },
1101
+ });
1060
1102
  // Add global click listener
1061
1103
  setTimeout(() => {
1062
1104
  document.removeEventListener('click', handleClickOutside);
@@ -1154,4 +1196,4 @@ function SelectAllIcon(props) {
1154
1196
  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" }) }));
1155
1197
  }
1156
1198
 
1157
- 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 };
1199
+ 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/mui",
3
- "version": "0.19.0",
3
+ "version": "0.20.2",
4
4
  "description": "Material-UI inspired components for kt.js - pre-styled UI components",
5
5
  "type": "module",
6
6
  "module": "./dist/index.mjs",
@@ -35,8 +35,8 @@
35
35
  "directory": "packages/mui"
36
36
  },
37
37
  "dependencies": {
38
- "@ktjs/shared": "0.19.0",
39
- "@ktjs/core": "0.19.0"
38
+ "@ktjs/core": "0.20.3",
39
+ "@ktjs/shared": "0.20.0"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "rollup -c rollup.config.mjs",