@ktjs/mui 0.17.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +204 -0
- package/dist/index.iife.css +1 -0
- package/dist/index.iife.js +524 -0
- package/dist/index.mjs +489 -0
- package/package.json +44 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'kt.js/jsx-runtime';
|
|
2
|
+
import { ref, createRedrawable } from 'kt.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Alert component - mimics MUI Alert appearance and behavior
|
|
6
|
+
*/
|
|
7
|
+
function Alert(props) {
|
|
8
|
+
const { children, severity = 'info', variant = 'standard', icon, onClose, sx } = props;
|
|
9
|
+
const classes = ['mui-alert', `mui-alert-${severity}`, `mui-alert-${variant}`, props.class ? props.class : '']
|
|
10
|
+
.filter(Boolean)
|
|
11
|
+
.join(' ');
|
|
12
|
+
// Convert sx object to style string
|
|
13
|
+
let styleString = props.style || '';
|
|
14
|
+
if (sx) {
|
|
15
|
+
const sxStyles = Object.entries(sx)
|
|
16
|
+
.map(([key, value]) => {
|
|
17
|
+
// Convert camelCase to kebab-case
|
|
18
|
+
const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
19
|
+
return `${cssKey}: ${value}`;
|
|
20
|
+
})
|
|
21
|
+
.join('; ');
|
|
22
|
+
styleString = styleString ? `${styleString}; ${sxStyles}` : sxStyles;
|
|
23
|
+
}
|
|
24
|
+
// Icon SVG paths for different severities
|
|
25
|
+
const getIcon = () => {
|
|
26
|
+
if (icon === false)
|
|
27
|
+
return null;
|
|
28
|
+
if (icon)
|
|
29
|
+
return icon;
|
|
30
|
+
const iconSize = '22px';
|
|
31
|
+
const iconClass = 'mui-alert-icon';
|
|
32
|
+
switch (severity) {
|
|
33
|
+
case 'success':
|
|
34
|
+
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" }) }));
|
|
35
|
+
case 'error':
|
|
36
|
+
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" }) }));
|
|
37
|
+
case 'warning':
|
|
38
|
+
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" }) }));
|
|
39
|
+
case 'info':
|
|
40
|
+
default:
|
|
41
|
+
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" }) }));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const alertIcon = getIcon();
|
|
45
|
+
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" }) }) }))] }));
|
|
46
|
+
return alert;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const emptyFn$3 = () => { };
|
|
50
|
+
/**
|
|
51
|
+
* Button component - mimics MUI Button appearance and behavior
|
|
52
|
+
*/
|
|
53
|
+
function Button(props) {
|
|
54
|
+
const { children, variant = 'text', color = 'primary', size = 'medium', disabled = false, fullWidth = false, iconOnly = false, startIcon, endIcon, type = 'button', 'on:click': onClick = emptyFn$3, } = props;
|
|
55
|
+
const classes = [
|
|
56
|
+
'mui-button',
|
|
57
|
+
`mui-button-${variant}`,
|
|
58
|
+
`mui-button-${variant}-${color}`,
|
|
59
|
+
`mui-button-size-${size}`,
|
|
60
|
+
fullWidth && 'mui-button-fullwidth',
|
|
61
|
+
iconOnly && 'mui-button-icon-only',
|
|
62
|
+
disabled && 'mui-button-disabled',
|
|
63
|
+
props.class ? props.class : '',
|
|
64
|
+
]
|
|
65
|
+
.filter(Boolean)
|
|
66
|
+
.join(' ');
|
|
67
|
+
const handleClick = (e) => {
|
|
68
|
+
if (disabled) {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Create ripple effect
|
|
73
|
+
const button = e.currentTarget;
|
|
74
|
+
const rippleContainer = button.querySelector('.mui-button-ripple');
|
|
75
|
+
if (rippleContainer) {
|
|
76
|
+
const rect = button.getBoundingClientRect();
|
|
77
|
+
const size = Math.max(rect.width, rect.height);
|
|
78
|
+
const x = e.clientX - rect.left - size / 2;
|
|
79
|
+
const y = e.clientY - rect.top - size / 2;
|
|
80
|
+
const ripple = document.createElement('span');
|
|
81
|
+
ripple.style.width = ripple.style.height = `${size}px`;
|
|
82
|
+
ripple.style.left = `${x}px`;
|
|
83
|
+
ripple.style.top = `${y}px`;
|
|
84
|
+
ripple.classList.add('mui-button-ripple-effect');
|
|
85
|
+
rippleContainer.appendChild(ripple);
|
|
86
|
+
// Remove ripple after animation
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
ripple.remove();
|
|
89
|
+
}, 600);
|
|
90
|
+
}
|
|
91
|
+
onClick(e);
|
|
92
|
+
};
|
|
93
|
+
return (jsxs("button", { class: classes, style: props.style ? 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" })] }));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Dialog component - mimics MUI Dialog appearance and behavior
|
|
98
|
+
* Only handles open/close state, title and content are passed as props
|
|
99
|
+
*/
|
|
100
|
+
function Dialog(props) {
|
|
101
|
+
const { open = false, onClose, title, children, actions, maxWidth = 'sm', fullWidth = false } = props;
|
|
102
|
+
// Handle backdrop click
|
|
103
|
+
const handleBackdropClick = (e) => {
|
|
104
|
+
if (e.target === backdrop) {
|
|
105
|
+
onClose?.();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
// Handle ESC key
|
|
109
|
+
const handleKeyDown = (e) => {
|
|
110
|
+
if (e.key === 'Escape' && open) {
|
|
111
|
+
onClose?.();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
// Backdrop element
|
|
115
|
+
const backdrop = (jsx("div", { class: `kt-dialog-backdrop ${open ? 'kt-dialog-backdrop-open' : ''}`, "on:click": handleBackdropClick, style: { display: open ? 'flex' : 'none' }, children: jsxs("div", { class: `kt-dialog-paper ${maxWidth ? `kt-dialog-maxWidth-${maxWidth}` : ''} ${fullWidth ? 'kt-dialog-fullWidth' : ''}`, "on:click": (e) => e.stopPropagation(), children: [title && (jsx("div", { class: "kt-dialog-title", children: jsx("h2", { children: title }) })), children && jsx("div", { class: "kt-dialog-content", children: children }), actions && jsx("div", { class: "kt-dialog-actions", children: actions })] }) }));
|
|
116
|
+
// Add/remove ESC key listener
|
|
117
|
+
if (open) {
|
|
118
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
122
|
+
}
|
|
123
|
+
return backdrop;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* FormLabel component - mimics MUI FormLabel appearance and behavior
|
|
128
|
+
*/
|
|
129
|
+
function FormLabel(props) {
|
|
130
|
+
const { children, required = false, error = false, disabled = false, focused = false, filled = false, component = 'label', htmlFor, } = props;
|
|
131
|
+
const classes = [
|
|
132
|
+
'mui-form-label',
|
|
133
|
+
error && 'mui-form-label-error',
|
|
134
|
+
disabled && 'mui-form-label-disabled',
|
|
135
|
+
focused && 'mui-form-label-focused',
|
|
136
|
+
filled && 'mui-form-label-filled',
|
|
137
|
+
]
|
|
138
|
+
.filter(Boolean)
|
|
139
|
+
.join(' ');
|
|
140
|
+
const labelProps = {
|
|
141
|
+
class: classes,
|
|
142
|
+
};
|
|
143
|
+
if (htmlFor) {
|
|
144
|
+
labelProps.for = htmlFor;
|
|
145
|
+
}
|
|
146
|
+
const element = component === 'legend' ? (jsxs("legend", { ...labelProps, children: [children, required && jsx("span", { class: "mui-form-label-asterisk", children: " *" })] })) : (jsxs("label", { ...labelProps, children: [children, required && jsx("span", { class: "mui-form-label-asterisk", children: " *" })] }));
|
|
147
|
+
return element;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* LinearProgress component - mimics MUI LinearProgress appearance and behavior
|
|
152
|
+
*/
|
|
153
|
+
function LinearProgress(props) {
|
|
154
|
+
const { variant = 'indeterminate', progress: value = 0, color = 'primary', sx } = props;
|
|
155
|
+
const classes = [
|
|
156
|
+
'mui-linear-progress',
|
|
157
|
+
`mui-linear-progress-${color}`,
|
|
158
|
+
`mui-linear-progress-${variant}`,
|
|
159
|
+
props.class ? props.class : '',
|
|
160
|
+
]
|
|
161
|
+
.filter(Boolean)
|
|
162
|
+
.join(' ');
|
|
163
|
+
// Convert sx object to style string
|
|
164
|
+
let styleString = props.style || '';
|
|
165
|
+
if (sx) {
|
|
166
|
+
const sxStyles = Object.entries(sx)
|
|
167
|
+
.map(([key, value]) => {
|
|
168
|
+
// Convert camelCase to kebab-case
|
|
169
|
+
const cssKey = key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
170
|
+
return `${cssKey}: ${value}`;
|
|
171
|
+
})
|
|
172
|
+
.join('; ');
|
|
173
|
+
styleString = styleString ? `${styleString}; ${sxStyles}` : sxStyles;
|
|
174
|
+
}
|
|
175
|
+
// Calculate progress percentage
|
|
176
|
+
const progressValue = Math.min(Math.max(value, 0), 100);
|
|
177
|
+
const barStyle = variant === 'determinate' ? `width: ${progressValue}%` : '';
|
|
178
|
+
return (jsx("div", { class: classes, style: styleString, role: "progressbar", "aria-valuenow": progressValue, children: jsx("div", { class: "mui-linear-progress-bar", style: barStyle }) }));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const emptyFn$2 = () => { };
|
|
182
|
+
/**
|
|
183
|
+
* TextField component - mimics MUI TextField appearance and behavior
|
|
184
|
+
*/
|
|
185
|
+
function TextField(props) {
|
|
186
|
+
const { label = '', placeholder = '', value = '', type = 'text', disabled = false, required = false, error = false, helperText = '', fullWidth = false, multiline = false, rows = 3, maxRows = 10, size = 'medium', 'mui:input': onInput = emptyFn$2, 'mui:change': onChange = emptyFn$2, 'mui:blur': onBlur = emptyFn$2, 'mui:focus': onFocus = emptyFn$2, } = props;
|
|
187
|
+
let isFocused = false;
|
|
188
|
+
const inputRef = ref();
|
|
189
|
+
// Update container classes
|
|
190
|
+
const updateClasses = () => {
|
|
191
|
+
const hasValue = inputRef.value?.value || '';
|
|
192
|
+
const classes = [
|
|
193
|
+
'mui-textfield-root',
|
|
194
|
+
`mui-textfield-size-${size}`,
|
|
195
|
+
isFocused && 'mui-textfield-focused',
|
|
196
|
+
error && 'mui-textfield-error',
|
|
197
|
+
disabled && 'mui-textfield-disabled',
|
|
198
|
+
fullWidth && 'mui-textfield-fullwidth',
|
|
199
|
+
(isFocused || hasValue) && 'mui-textfield-has-value',
|
|
200
|
+
]
|
|
201
|
+
.filter(Boolean)
|
|
202
|
+
.join(' ');
|
|
203
|
+
container.className = classes;
|
|
204
|
+
};
|
|
205
|
+
const handleInput = (e) => {
|
|
206
|
+
const target = e.target;
|
|
207
|
+
updateClasses();
|
|
208
|
+
onInput(target.value, e);
|
|
209
|
+
};
|
|
210
|
+
const handleChange = (e) => {
|
|
211
|
+
const target = e.target;
|
|
212
|
+
onChange(target.value, e);
|
|
213
|
+
};
|
|
214
|
+
const handleFocus = (e) => {
|
|
215
|
+
isFocused = true;
|
|
216
|
+
updateClasses();
|
|
217
|
+
const target = e.target;
|
|
218
|
+
onFocus(target.value, e);
|
|
219
|
+
};
|
|
220
|
+
const handleBlur = (e) => {
|
|
221
|
+
isFocused = false;
|
|
222
|
+
updateClasses();
|
|
223
|
+
const target = e.target;
|
|
224
|
+
onBlur(target.value, e);
|
|
225
|
+
};
|
|
226
|
+
// Create input or textarea element
|
|
227
|
+
// Only show placeholder when label is floating (focused or has value)
|
|
228
|
+
const getPlaceholder = () => (label && !isFocused && !value ? '' : placeholder);
|
|
229
|
+
const inputElement = multiline ? (jsx("textarea", { ref: inputRef, class: "mui-textfield-input", placeholder: getPlaceholder(), value: value, disabled: disabled, required: required, rows: rows, "on:input": handleInput, "on:change": handleChange, "on:focus": handleFocus, "on:blur": handleBlur })) : (jsx("input", { ref: inputRef, type: type, class: "mui-textfield-input", placeholder: getPlaceholder(), value: value, disabled: disabled, required: required, "on:input": handleInput, "on:change": handleChange, "on:focus": handleFocus, "on:blur": handleBlur }));
|
|
230
|
+
const container = (jsxs("div", { class: 'mui-textfield-root ' + (props.class ? props.class : ''), style: props.style ? props.style : '', children: [jsxs("div", { class: "mui-textfield-wrapper", children: [label && (jsxs("label", { class: "mui-textfield-label", children: [label, required && jsx("span", { class: "mui-textfield-required", children: "*" })] })), jsx("div", { class: "mui-textfield-input-wrapper", children: inputElement }), jsx("fieldset", { class: "mui-textfield-fieldset", children: jsx("legend", { class: "mui-textfield-legend", children: jsxs("span", { children: [label, required && '*'] }) }) })] }), helperText && jsx("p", { class: "mui-textfield-helper-text", children: helperText })] }));
|
|
231
|
+
// Initialize classes
|
|
232
|
+
setTimeout(() => updateClasses(), 0);
|
|
233
|
+
return container;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const emptyFn$1 = () => { };
|
|
237
|
+
/**
|
|
238
|
+
* Radio component - mimics MUI Radio appearance and behavior
|
|
239
|
+
*/
|
|
240
|
+
function Radio(props) {
|
|
241
|
+
const toggleIcon = (checked) => {
|
|
242
|
+
uncheckedIcon.style.display = checked ? 'none' : '';
|
|
243
|
+
checkedIcon.style.display = checked ? '' : 'none';
|
|
244
|
+
};
|
|
245
|
+
// Handle change
|
|
246
|
+
const handleChange = () => {
|
|
247
|
+
if (disabled) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
checked = inputRef.value.checked;
|
|
251
|
+
toggleIcon(checked);
|
|
252
|
+
onChange(checked, value);
|
|
253
|
+
};
|
|
254
|
+
const { checked: initChecked = false, value = '', text = '', size = 'small', 'mui:change': onChange = emptyFn$1, disabled: initDisabled = false, color = 'primary', } = props;
|
|
255
|
+
const inputRef = ref();
|
|
256
|
+
let checked = initChecked;
|
|
257
|
+
let disabled = initDisabled;
|
|
258
|
+
const uncheckedIcon = (jsx("span", { class: "mui-radio-icon-unchecked", children: jsx("svg", { viewBox: "0 0 24 24", children: jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" }) }) }));
|
|
259
|
+
const checkedIcon = (jsx("span", { class: "mui-radio-icon-checked", children: jsx("svg", { viewBox: "0 0 24 24", children: jsx("path", { d: "M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" }) }) }));
|
|
260
|
+
// initialize icon state
|
|
261
|
+
toggleIcon(checked);
|
|
262
|
+
const container = (jsxs("label", { class: `mui-radio-wrapper mui-radio-size-${size} ${disabled ? 'mui-radio-disabled' : ''} mui-radio-color-${color}`, children: [jsx("input", { ref: inputRef, type: "radio", class: "mui-radio-input", checked: checked, value: value, disabled: disabled, "on:change": handleChange }), jsxs("span", { class: "mui-radio-icon", children: [uncheckedIcon, checkedIcon] }), jsx("span", { class: "mui-radio-label", children: text })] }));
|
|
263
|
+
container.redrawIcon = (newValue) => {
|
|
264
|
+
checked = newValue === value;
|
|
265
|
+
inputRef.value.checked = checked;
|
|
266
|
+
toggleIcon(checked);
|
|
267
|
+
};
|
|
268
|
+
return container;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* RadioGroup component - groups multiple radios together
|
|
272
|
+
*/
|
|
273
|
+
function RadioGroup(props) {
|
|
274
|
+
const { value = '', size = 'small', 'mui:change': onChange = emptyFn$1, row = false } = props;
|
|
275
|
+
const changeHandler = (checked, value) => {
|
|
276
|
+
if (checked) {
|
|
277
|
+
onChange(value);
|
|
278
|
+
}
|
|
279
|
+
radios.forEach((radio) => radio.redrawIcon(value));
|
|
280
|
+
};
|
|
281
|
+
const radios = props.options.map((o) => {
|
|
282
|
+
o.size = size;
|
|
283
|
+
o.checked = value === o.value;
|
|
284
|
+
const originalChange = o['mui:change'];
|
|
285
|
+
if (originalChange) {
|
|
286
|
+
o['mui:change'] = (checked, newValue) => {
|
|
287
|
+
originalChange(checked, newValue);
|
|
288
|
+
changeHandler(checked, newValue);
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
o['mui:change'] = changeHandler;
|
|
293
|
+
}
|
|
294
|
+
return Radio(o);
|
|
295
|
+
});
|
|
296
|
+
return (jsx("div", { class: `mui-radio-group ${row ? 'mui-radio-group-row' : ''} ${props.class ? props.class : ''}`, style: props.style ? props.style : '', role: "radiogroup", children: radios }));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const emptyFn = () => { };
|
|
300
|
+
/**
|
|
301
|
+
* Select component - mimics MUI Select appearance and behavior
|
|
302
|
+
*/
|
|
303
|
+
function Select(props) {
|
|
304
|
+
let { value = '', options = [], label = '', placeholder = '', size = 'medium', 'mui:change': onChange = emptyFn, fullWidth = false, disabled = false, } = props;
|
|
305
|
+
let isOpen = false;
|
|
306
|
+
let isFocused = false;
|
|
307
|
+
const selectRef = ref();
|
|
308
|
+
// Toggle dropdown
|
|
309
|
+
const toggleMenu = () => {
|
|
310
|
+
if (disabled) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
isOpen = !isOpen;
|
|
314
|
+
updateMenu();
|
|
315
|
+
};
|
|
316
|
+
// Update menu visibility
|
|
317
|
+
const updateMenu = () => {
|
|
318
|
+
if (isOpen) {
|
|
319
|
+
menu.value.style.display = 'block';
|
|
320
|
+
// Trigger reflow to enable animation
|
|
321
|
+
menu.value.offsetHeight;
|
|
322
|
+
menu.value.classList.add('mui-select-menu-open');
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
menu.value.classList.remove('mui-select-menu-open');
|
|
326
|
+
// Hide after animation completes
|
|
327
|
+
setTimeout(() => {
|
|
328
|
+
if (!isOpen) {
|
|
329
|
+
menu.value.style.display = 'none';
|
|
330
|
+
}
|
|
331
|
+
}, 200);
|
|
332
|
+
}
|
|
333
|
+
selectRef.value.classList.toggle('mui-select-open', isOpen);
|
|
334
|
+
};
|
|
335
|
+
// Handle option click
|
|
336
|
+
const handleOptionClick = (newValue) => {
|
|
337
|
+
value = newValue;
|
|
338
|
+
isOpen = false;
|
|
339
|
+
onChange(value);
|
|
340
|
+
updateMenu();
|
|
341
|
+
updateLabelState();
|
|
342
|
+
valueDisplay.value.redraw();
|
|
343
|
+
setTimeout(() => {
|
|
344
|
+
// Trigger redraw of parent if needed
|
|
345
|
+
menu.value.redraw();
|
|
346
|
+
}, 200);
|
|
347
|
+
};
|
|
348
|
+
// Close menu when clicking outside
|
|
349
|
+
const handleClickOutside = (e) => {
|
|
350
|
+
if (!selectRef.value.contains(e.target)) {
|
|
351
|
+
isOpen = false;
|
|
352
|
+
updateMenu();
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
// Handle focus
|
|
356
|
+
const handleFocus = () => {
|
|
357
|
+
isFocused = true;
|
|
358
|
+
updateLabelState();
|
|
359
|
+
};
|
|
360
|
+
const handleBlur = () => {
|
|
361
|
+
isFocused = false;
|
|
362
|
+
updateLabelState();
|
|
363
|
+
};
|
|
364
|
+
// Update label focused state
|
|
365
|
+
const updateLabelState = () => {
|
|
366
|
+
const labelElement = selectRef.value.querySelector('.mui-select-label');
|
|
367
|
+
if (labelElement) {
|
|
368
|
+
if (isFocused || value) {
|
|
369
|
+
labelElement.classList.add('focused');
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
labelElement.classList.remove('focused');
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
const valueDisplay = createRedrawable(() => {
|
|
377
|
+
const o = options.find((opt) => opt.value === value);
|
|
378
|
+
let inner;
|
|
379
|
+
if (o === undefined) {
|
|
380
|
+
inner = jsx("span", { class: "mui-select-placeholder", children: placeholder || '\u00a0' });
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
inner = o.label;
|
|
384
|
+
}
|
|
385
|
+
return jsx("div", { class: "mui-select-display", children: inner });
|
|
386
|
+
});
|
|
387
|
+
const menu = createRedrawable(() => {
|
|
388
|
+
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 }))) }));
|
|
389
|
+
});
|
|
390
|
+
// Create container
|
|
391
|
+
const container = (jsxs("div", { ref: selectRef, class: `mui-select-wrapper mui-select-size-${size} ${props.class ? props.class : ''} ${fullWidth ? 'mui-select-fullWidth' : ''} ${disabled ? 'mui-select-disabled' : ''}`, style: props.style ? 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] }));
|
|
392
|
+
// Add global click listener
|
|
393
|
+
setTimeout(() => {
|
|
394
|
+
document.removeEventListener('click', handleClickOutside);
|
|
395
|
+
document.addEventListener('click', handleClickOutside);
|
|
396
|
+
updateLabelState();
|
|
397
|
+
}, 0);
|
|
398
|
+
return container;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function DownloadIcon(props) {
|
|
402
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" }) }));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function CompressIcon(props) {
|
|
406
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M4 9h16v2H4zm0 4h16v2H4zm8-9 4 4H8zm0 14 4-4H8z" }) }));
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function SubtitlesIcon(props) {
|
|
410
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM4 12h4v2H4v-2zm10 6H4v-2h10v2zm6 0h-4v-2h4v2zm0-4H10v-2h10v2z" }) }));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function SettingsIcon(props) {
|
|
414
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.07.62-.07.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z" }) }));
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function NewReleasesIcon(props) {
|
|
418
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "m23 12-2.44-2.79.34-3.69-3.61-.82-1.89-3.2L12 2.96 8.6 1.5 6.71 4.69 3.1 5.5l.34 3.7L1 12l2.44 2.79-.34 3.7 3.61.82L8.6 22.5l3.4-1.47 3.4 1.46 1.89-3.19 3.61-.82-.34-3.69L23 12zm-12.91 4.72-3.8-3.81 1.48-1.48 2.32 2.33 5.85-5.87 1.48 1.48-7.33 7.35z" }) }));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function FolderOpenIcon(props) {
|
|
422
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z" }) }));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function PlayArrowIcon(props) {
|
|
426
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M8 5v14l11-7z" }) }));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function ContentPasteIcon(props) {
|
|
430
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z" }) }));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function DeleteIcon(props) {
|
|
434
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }) }));
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function StopIcon(props) {
|
|
438
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M6 6h12v12H6z" }) }));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function FileOpenIcon(props) {
|
|
442
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H15l6-6V4c0-1.1-.9-2-2-2zm-1 7V3.5L18.5 9H13z" }) }));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function ColorLensIcon(props) {
|
|
446
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" }) }));
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function WallpaperIcon(props) {
|
|
450
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M4 4h7V2H4c-1.1 0-2 .9-2 2v7h2V4zm6 9-4 5h12l-3-4-2.03 2.71L10 13zm7-4.5c0-.83-.67-1.5-1.5-1.5S14 7.67 14 8.5s.67 1.5 1.5 1.5S17 9.33 17 8.5zM20 2h-7v2h7v7h2V4c0-1.1-.9-2-2-2zm0 18h-7v2h7c1.1 0 2-.9 2-2v-7h-2v7zM4 13H2v7c0 1.1.9 2 2 2h7v-2H4v-7z" }) }));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function ExpandMoreIcon(props) {
|
|
454
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z" }) }));
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function SaveIcon(props) {
|
|
458
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z" }) }));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function UploadFileIcon(props) {
|
|
462
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11zM8 15.01l1.41 1.41L11 14.84V19h2v-4.16l1.59 1.59L16 15.01 12.01 11z" }) }));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function VideoFileIcon(props) {
|
|
466
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6zm10-7v-1.5l2 1.5-2 1.5V13H8v-2h8z" }) }));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function QueuePlayNextIcon(props) {
|
|
470
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h2v-2H3V5h18v8h2V5c0-1.11-.9-2-2-2zm-8 7V7h-2v3H8v2h3v3h2v-3h3v-2h-3zm11 8-4.5 4.5L18 21l3-3-3-3 1.5-1.5L24 18z" }) }));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function MenuIcon(props) {
|
|
474
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" }) }));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function HomeIcon(props) {
|
|
478
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" }) }));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function ContentCopyIcon(props) {
|
|
482
|
+
return (jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "1em", height: "1em", ...props, children: jsx("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }) }));
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function SelectAllIcon(props) {
|
|
486
|
+
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" }) }));
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export { Alert, Button, 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 };
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ktjs/mui",
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"description": "Material-UI inspired components for kt.js - pre-styled UI components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./kt-mui-styles": "./dist/kt-mui-styles"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"kt.js",
|
|
21
|
+
"ui",
|
|
22
|
+
"components",
|
|
23
|
+
"material-ui",
|
|
24
|
+
"mui",
|
|
25
|
+
"web"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"author": {
|
|
29
|
+
"name": "Kasukabe Tsumugi",
|
|
30
|
+
"email": "futami16237@gmail.com"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/baendlorel/kt.js",
|
|
35
|
+
"directory": "packages/mui"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@ktjs/core": "0.17.2"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "rollup -c rollup.config.mjs",
|
|
42
|
+
"dev": "rollup -c rollup.config.mjs -w"
|
|
43
|
+
}
|
|
44
|
+
}
|