mithril-materialized 3.7.0 → 3.9.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/circular-progress.d.ts +43 -0
- package/dist/index.css +504 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.esm.js +297 -1
- package/dist/index.js +299 -0
- package/dist/index.min.css +1 -1
- package/dist/index.umd.js +299 -0
- package/dist/linear-progress.d.ts +40 -0
- package/dist/toggle-button.d.ts +46 -0
- package/dist/toggle-group.d.ts +84 -0
- package/package.json +1 -1
- package/sass/components/_circular-progress.scss +220 -0
- package/sass/components/_linear-progress.scss +183 -0
- package/sass/components/_toggle-group.scss +36 -0
- package/sass/materialize.scss +3 -0
package/dist/index.esm.js
CHANGED
|
@@ -10711,6 +10711,302 @@ const Rating = () => {
|
|
|
10711
10711
|
};
|
|
10712
10712
|
};
|
|
10713
10713
|
|
|
10714
|
+
/**
|
|
10715
|
+
* ToggleButton component.
|
|
10716
|
+
*
|
|
10717
|
+
* A button that can be toggled on/off. Typically used within a ToggleGroup
|
|
10718
|
+
* to create grouped button controls where one or more buttons can be selected.
|
|
10719
|
+
*
|
|
10720
|
+
* @example
|
|
10721
|
+
* ```typescript
|
|
10722
|
+
* m(ToggleButton, {
|
|
10723
|
+
* value: 'bold',
|
|
10724
|
+
* iconName: 'format_bold',
|
|
10725
|
+
* checked: true,
|
|
10726
|
+
* tooltip: 'Bold',
|
|
10727
|
+
* onchange: () => console.log('Toggled')
|
|
10728
|
+
* })
|
|
10729
|
+
* ```
|
|
10730
|
+
*/
|
|
10731
|
+
const ToggleButton = () => {
|
|
10732
|
+
return {
|
|
10733
|
+
view: ({ attrs }) => {
|
|
10734
|
+
const { checked, iconName, icon, label, onchange, className, tooltip } = attrs, rest = __rest(attrs, ["checked", "iconName", "icon", "label", "onchange", "className", "tooltip"]);
|
|
10735
|
+
const classes = [className, checked ? 'checked' : ''].filter(Boolean).join(' ');
|
|
10736
|
+
return m('button.btn-flat.waves-effect.toggle-button', Object.assign(Object.assign({}, rest), { className: classes, title: tooltip, onclick: () => {
|
|
10737
|
+
if (onchange) {
|
|
10738
|
+
onchange();
|
|
10739
|
+
}
|
|
10740
|
+
}, onmousedown: WavesEffect.onMouseDown, onmouseup: WavesEffect.onMouseUp, onmouseleave: WavesEffect.onMouseLeave, ontouchstart: WavesEffect.onTouchStart, ontouchend: WavesEffect.onTouchEnd }), [icon, iconName && m(Icon, { iconName, className: attrs.iconClass }), label]);
|
|
10741
|
+
},
|
|
10742
|
+
};
|
|
10743
|
+
};
|
|
10744
|
+
|
|
10745
|
+
/**
|
|
10746
|
+
* ToggleGroup component.
|
|
10747
|
+
*
|
|
10748
|
+
* A group of toggle buttons that can operate in single-select or multi-select mode.
|
|
10749
|
+
* The component supports both controlled and uncontrolled modes.
|
|
10750
|
+
*
|
|
10751
|
+
* **Controlled mode**: Manage the state externally using the `value` prop.
|
|
10752
|
+
* **Uncontrolled mode**: Let the component manage its own state using `defaultValue`.
|
|
10753
|
+
*
|
|
10754
|
+
* @example
|
|
10755
|
+
* ```typescript
|
|
10756
|
+
* // Single-select, controlled mode
|
|
10757
|
+
* let selected = 'left';
|
|
10758
|
+
* m(ToggleGroup, {
|
|
10759
|
+
* value: selected,
|
|
10760
|
+
* onchange: (v) => selected = v,
|
|
10761
|
+
* items: [
|
|
10762
|
+
* { value: 'left', iconName: 'format_align_left', tooltip: 'Align Left' },
|
|
10763
|
+
* { value: 'center', iconName: 'format_align_center', tooltip: 'Align Center' },
|
|
10764
|
+
* { value: 'right', iconName: 'format_align_right', tooltip: 'Align Right' }
|
|
10765
|
+
* ]
|
|
10766
|
+
* });
|
|
10767
|
+
*
|
|
10768
|
+
* // Multi-select, controlled mode
|
|
10769
|
+
* let selected = ['bold', 'italic'];
|
|
10770
|
+
* m(ToggleGroup, {
|
|
10771
|
+
* multiple: true,
|
|
10772
|
+
* value: selected,
|
|
10773
|
+
* onchange: (v) => selected = v,
|
|
10774
|
+
* items: [
|
|
10775
|
+
* { value: 'bold', iconName: 'format_bold', tooltip: 'Bold' },
|
|
10776
|
+
* { value: 'italic', iconName: 'format_italic', tooltip: 'Italic' },
|
|
10777
|
+
* { value: 'underline', iconName: 'format_underlined', tooltip: 'Underline' }
|
|
10778
|
+
* ]
|
|
10779
|
+
* });
|
|
10780
|
+
*
|
|
10781
|
+
* // Uncontrolled mode
|
|
10782
|
+
* m(ToggleGroup, {
|
|
10783
|
+
* defaultValue: 'left',
|
|
10784
|
+
* onchange: (v) => console.log('Changed to:', v),
|
|
10785
|
+
* items: [...]
|
|
10786
|
+
* });
|
|
10787
|
+
* ```
|
|
10788
|
+
*/
|
|
10789
|
+
const ToggleGroup = () => {
|
|
10790
|
+
let internalValue;
|
|
10791
|
+
const handleSelect = (attrs, item, currentValue) => {
|
|
10792
|
+
if (attrs.disabled || item.disabled) {
|
|
10793
|
+
return;
|
|
10794
|
+
}
|
|
10795
|
+
const { value, multiple, onchange } = attrs;
|
|
10796
|
+
const isControlled = value !== undefined;
|
|
10797
|
+
if (multiple) {
|
|
10798
|
+
const currentValues = (Array.isArray(currentValue) ? currentValue : currentValue !== undefined ? [currentValue] : []);
|
|
10799
|
+
const newValues = currentValues.includes(item.value)
|
|
10800
|
+
? currentValues.filter((v) => v !== item.value)
|
|
10801
|
+
: [...currentValues, item.value];
|
|
10802
|
+
if (!isControlled) {
|
|
10803
|
+
internalValue = newValues;
|
|
10804
|
+
}
|
|
10805
|
+
if (onchange) {
|
|
10806
|
+
onchange(newValues);
|
|
10807
|
+
}
|
|
10808
|
+
}
|
|
10809
|
+
else {
|
|
10810
|
+
const newValue = item.value;
|
|
10811
|
+
if (!isControlled) {
|
|
10812
|
+
internalValue = newValue;
|
|
10813
|
+
}
|
|
10814
|
+
if (onchange) {
|
|
10815
|
+
onchange(newValue);
|
|
10816
|
+
}
|
|
10817
|
+
}
|
|
10818
|
+
};
|
|
10819
|
+
return {
|
|
10820
|
+
oninit: ({ attrs }) => {
|
|
10821
|
+
internalValue = attrs.defaultValue;
|
|
10822
|
+
},
|
|
10823
|
+
view: ({ attrs }) => {
|
|
10824
|
+
const { value, items, multiple } = attrs;
|
|
10825
|
+
const isControlled = value !== undefined;
|
|
10826
|
+
const currentValue = isControlled ? value : internalValue;
|
|
10827
|
+
return m('.toggle-group', items.map((item) => m(ToggleButton, Object.assign(Object.assign({}, item), { checked: multiple && Array.isArray(currentValue)
|
|
10828
|
+
? currentValue.includes(item.value)
|
|
10829
|
+
: currentValue === item.value, onchange: () => handleSelect(attrs, item, currentValue) }))));
|
|
10830
|
+
},
|
|
10831
|
+
};
|
|
10832
|
+
};
|
|
10833
|
+
|
|
10834
|
+
/** Size dimensions in pixels */
|
|
10835
|
+
const SIZE_MAP = {
|
|
10836
|
+
small: 36,
|
|
10837
|
+
medium: 50,
|
|
10838
|
+
large: 64,
|
|
10839
|
+
};
|
|
10840
|
+
/** Stroke width in pixels */
|
|
10841
|
+
const STROKE_WIDTH = 3;
|
|
10842
|
+
/** Create a CircularProgress component */
|
|
10843
|
+
const CircularProgress = () => {
|
|
10844
|
+
const state = {
|
|
10845
|
+
id: uniqueId(),
|
|
10846
|
+
};
|
|
10847
|
+
/**
|
|
10848
|
+
* Calculate SVG stroke properties for determinate progress
|
|
10849
|
+
*/
|
|
10850
|
+
const calculateStrokeProperties = (size, value, max) => {
|
|
10851
|
+
const radius = (size - STROKE_WIDTH) / 2;
|
|
10852
|
+
const circumference = 2 * Math.PI * radius;
|
|
10853
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
10854
|
+
const strokeDashoffset = circumference - (percentage / 100) * circumference;
|
|
10855
|
+
return {
|
|
10856
|
+
radius,
|
|
10857
|
+
circumference,
|
|
10858
|
+
strokeDashoffset,
|
|
10859
|
+
percentage,
|
|
10860
|
+
};
|
|
10861
|
+
};
|
|
10862
|
+
/**
|
|
10863
|
+
* Get size class name
|
|
10864
|
+
*/
|
|
10865
|
+
const getSizeClass = (size = 'medium') => {
|
|
10866
|
+
return `circular-progress--${size}`;
|
|
10867
|
+
};
|
|
10868
|
+
/**
|
|
10869
|
+
* Get color class name
|
|
10870
|
+
*/
|
|
10871
|
+
const getColorClass = (color, intensity) => {
|
|
10872
|
+
if (!color)
|
|
10873
|
+
return '';
|
|
10874
|
+
return intensity ? `circular-progress--${color} circular-progress--${intensity}` : `circular-progress--${color}`;
|
|
10875
|
+
};
|
|
10876
|
+
return {
|
|
10877
|
+
view: ({ attrs }) => {
|
|
10878
|
+
const { mode = 'indeterminate', value = 0, max = 100, size = 'medium', color = 'teal', colorIntensity, label, showPercentage = false, className = '', style = {}, id = state.id, 'aria-label': ariaLabel, 'aria-valuemin': ariaValueMin = 0, 'aria-valuemax': ariaValueMax = max, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText } = attrs, params = __rest(attrs, ["mode", "value", "max", "size", "color", "colorIntensity", "label", "showPercentage", "className", "style", "id", 'aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow', 'aria-valuetext']);
|
|
10879
|
+
const isDeterminate = mode === 'determinate';
|
|
10880
|
+
const sizePixels = SIZE_MAP[size];
|
|
10881
|
+
const { radius, circumference, strokeDashoffset, percentage } = isDeterminate
|
|
10882
|
+
? calculateStrokeProperties(sizePixels, value, max)
|
|
10883
|
+
: { radius: 0, circumference: 0, strokeDashoffset: 0, percentage: 0 };
|
|
10884
|
+
// Determine label content
|
|
10885
|
+
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
10886
|
+
// Build class names
|
|
10887
|
+
const classNames = [
|
|
10888
|
+
'circular-progress',
|
|
10889
|
+
getSizeClass(size),
|
|
10890
|
+
getColorClass(color, colorIntensity),
|
|
10891
|
+
`circular-progress--${mode}`,
|
|
10892
|
+
className,
|
|
10893
|
+
]
|
|
10894
|
+
.filter(Boolean)
|
|
10895
|
+
.join(' ');
|
|
10896
|
+
// ARIA attributes
|
|
10897
|
+
const ariaAttrs = isDeterminate
|
|
10898
|
+
? {
|
|
10899
|
+
'aria-valuenow': ariaValueNow !== undefined ? ariaValueNow : value,
|
|
10900
|
+
'aria-valuemin': ariaValueMin,
|
|
10901
|
+
'aria-valuemax': ariaValueMax,
|
|
10902
|
+
'aria-valuetext': ariaValueText || `${Math.round(percentage)}%`,
|
|
10903
|
+
}
|
|
10904
|
+
: {
|
|
10905
|
+
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
10906
|
+
};
|
|
10907
|
+
return m('.circular-progress', Object.assign(Object.assign(Object.assign({}, params), { className: classNames, style: Object.assign({ width: `${sizePixels}px`, height: `${sizePixels}px` }, style), id, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }), ariaAttrs), [
|
|
10908
|
+
// SVG circle
|
|
10909
|
+
m('svg.circular-progress__svg', {
|
|
10910
|
+
viewBox: `0 0 ${sizePixels} ${sizePixels}`,
|
|
10911
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
10912
|
+
}, [
|
|
10913
|
+
// Background track circle
|
|
10914
|
+
m('circle.circular-progress__circle.circular-progress__circle--track', {
|
|
10915
|
+
cx: sizePixels / 2,
|
|
10916
|
+
cy: sizePixels / 2,
|
|
10917
|
+
r: radius || (sizePixels - STROKE_WIDTH) / 2,
|
|
10918
|
+
fill: 'none',
|
|
10919
|
+
stroke: 'currentColor',
|
|
10920
|
+
'stroke-width': STROKE_WIDTH,
|
|
10921
|
+
}),
|
|
10922
|
+
// Progress indicator circle
|
|
10923
|
+
m('circle.circular-progress__circle.circular-progress__circle--indicator', {
|
|
10924
|
+
cx: sizePixels / 2,
|
|
10925
|
+
cy: sizePixels / 2,
|
|
10926
|
+
r: radius || (sizePixels - STROKE_WIDTH) / 2,
|
|
10927
|
+
fill: 'none',
|
|
10928
|
+
stroke: 'currentColor',
|
|
10929
|
+
'stroke-width': STROKE_WIDTH,
|
|
10930
|
+
'stroke-dasharray': isDeterminate ? circumference : undefined,
|
|
10931
|
+
'stroke-dashoffset': isDeterminate ? strokeDashoffset : undefined,
|
|
10932
|
+
'stroke-linecap': 'round',
|
|
10933
|
+
}),
|
|
10934
|
+
]),
|
|
10935
|
+
// Label inside circle
|
|
10936
|
+
labelContent &&
|
|
10937
|
+
m('.circular-progress__label', {
|
|
10938
|
+
'aria-hidden': 'true',
|
|
10939
|
+
}, labelContent),
|
|
10940
|
+
]);
|
|
10941
|
+
},
|
|
10942
|
+
};
|
|
10943
|
+
};
|
|
10944
|
+
|
|
10945
|
+
/** Create a LinearProgress component */
|
|
10946
|
+
const LinearProgress = () => {
|
|
10947
|
+
const state = {
|
|
10948
|
+
id: uniqueId(),
|
|
10949
|
+
};
|
|
10950
|
+
/**
|
|
10951
|
+
* Get size class name
|
|
10952
|
+
*/
|
|
10953
|
+
const getSizeClass = (size = 'medium') => {
|
|
10954
|
+
return `linear-progress__track--${size}`;
|
|
10955
|
+
};
|
|
10956
|
+
/**
|
|
10957
|
+
* Get color class name
|
|
10958
|
+
*/
|
|
10959
|
+
const getColorClass = (color, intensity) => {
|
|
10960
|
+
if (!color)
|
|
10961
|
+
return '';
|
|
10962
|
+
return intensity ? `linear-progress--${color} linear-progress--${intensity}` : `linear-progress--${color}`;
|
|
10963
|
+
};
|
|
10964
|
+
return {
|
|
10965
|
+
view: ({ attrs }) => {
|
|
10966
|
+
const { mode = 'indeterminate', value = 0, max = 100, size = 'medium', color = 'teal', colorIntensity, label, showPercentage = false, className = '', style = {}, id = state.id, 'aria-label': ariaLabel, 'aria-valuemin': ariaValueMin = 0, 'aria-valuemax': ariaValueMax = max, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText } = attrs, params = __rest(attrs, ["mode", "value", "max", "size", "color", "colorIntensity", "label", "showPercentage", "className", "style", "id", 'aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow', 'aria-valuetext']);
|
|
10967
|
+
const isDeterminate = mode === 'determinate';
|
|
10968
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
10969
|
+
// Determine label content
|
|
10970
|
+
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
10971
|
+
// Build class names
|
|
10972
|
+
const classNames = [
|
|
10973
|
+
'linear-progress',
|
|
10974
|
+
getColorClass(color, colorIntensity),
|
|
10975
|
+
className,
|
|
10976
|
+
]
|
|
10977
|
+
.filter(Boolean)
|
|
10978
|
+
.join(' ');
|
|
10979
|
+
// ARIA attributes
|
|
10980
|
+
const ariaAttrs = isDeterminate
|
|
10981
|
+
? {
|
|
10982
|
+
'aria-valuenow': ariaValueNow !== undefined ? ariaValueNow : value,
|
|
10983
|
+
'aria-valuemin': ariaValueMin,
|
|
10984
|
+
'aria-valuemax': ariaValueMax,
|
|
10985
|
+
'aria-valuetext': ariaValueText || `${Math.round(percentage)}%`,
|
|
10986
|
+
}
|
|
10987
|
+
: {
|
|
10988
|
+
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
10989
|
+
};
|
|
10990
|
+
return m('.linear-progress', Object.assign(Object.assign({}, params), { className: classNames, style,
|
|
10991
|
+
id }), [
|
|
10992
|
+
// Progress track container
|
|
10993
|
+
m('.linear-progress__track', Object.assign({ className: `linear-progress__track ${getSizeClass(size)}`, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }, ariaAttrs), [
|
|
10994
|
+
// Progress bar
|
|
10995
|
+
m('.linear-progress__bar', {
|
|
10996
|
+
className: `linear-progress__bar ${isDeterminate ? '' : 'linear-progress__bar--indeterminate'}`,
|
|
10997
|
+
style: isDeterminate ? { width: `${percentage}%` } : undefined,
|
|
10998
|
+
}),
|
|
10999
|
+
]),
|
|
11000
|
+
// Label at the end (right side)
|
|
11001
|
+
labelContent &&
|
|
11002
|
+
m('.linear-progress__label', {
|
|
11003
|
+
'aria-hidden': 'true',
|
|
11004
|
+
}, labelContent),
|
|
11005
|
+
]);
|
|
11006
|
+
},
|
|
11007
|
+
};
|
|
11008
|
+
};
|
|
11009
|
+
|
|
10714
11010
|
/**
|
|
10715
11011
|
* @fileoverview Core TypeScript utility types for mithril-materialized library
|
|
10716
11012
|
* These types improve type safety and developer experience across all components
|
|
@@ -10732,4 +11028,4 @@ const isValidationError = (result) => !isValidationSuccess(result);
|
|
|
10732
11028
|
// ============================================================================
|
|
10733
11029
|
// All types are already exported via individual export declarations above
|
|
10734
11030
|
|
|
10735
|
-
export { AnalogClock, AnchorItem, Autocomplete, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DataTable, DatePicker, DigitalClock, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, IconButton, ImageList, InputCheckbox, Label, LargeButton, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, TimeRangePicker, Timeline, Toast, ToastComponent, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, addLeadingZero, clearPortal, createBreadcrumb, formatTime, generateHourOptions, generateMinuteOptions, getDropdownStyles, getPortalContainer, initPushpins, initTooltips, isNumeric, isTimeDisabled, isValidationError, isValidationSuccess, padLeft, parseTime, range, releasePortalContainer, renderToPortal, scrollToValue, snapToNearestItem, sortOptions, timeToMinutes, toast, uniqueId, uuid4 };
|
|
11031
|
+
export { AnalogClock, AnchorItem, Autocomplete, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CircularProgress, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, DataTable, DatePicker, DigitalClock, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, IconButton, ImageList, InputCheckbox, Label, LargeButton, LinearProgress, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, TimeRangePicker, Timeline, Toast, ToastComponent, ToggleGroup, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, addLeadingZero, clearPortal, createBreadcrumb, formatTime, generateHourOptions, generateMinuteOptions, getDropdownStyles, getPortalContainer, initPushpins, initTooltips, isNumeric, isTimeDisabled, isValidationError, isValidationSuccess, padLeft, parseTime, range, releasePortalContainer, renderToPortal, scrollToValue, snapToNearestItem, sortOptions, timeToMinutes, toast, uniqueId, uuid4 };
|
package/dist/index.js
CHANGED
|
@@ -10713,6 +10713,302 @@ const Rating = () => {
|
|
|
10713
10713
|
};
|
|
10714
10714
|
};
|
|
10715
10715
|
|
|
10716
|
+
/**
|
|
10717
|
+
* ToggleButton component.
|
|
10718
|
+
*
|
|
10719
|
+
* A button that can be toggled on/off. Typically used within a ToggleGroup
|
|
10720
|
+
* to create grouped button controls where one or more buttons can be selected.
|
|
10721
|
+
*
|
|
10722
|
+
* @example
|
|
10723
|
+
* ```typescript
|
|
10724
|
+
* m(ToggleButton, {
|
|
10725
|
+
* value: 'bold',
|
|
10726
|
+
* iconName: 'format_bold',
|
|
10727
|
+
* checked: true,
|
|
10728
|
+
* tooltip: 'Bold',
|
|
10729
|
+
* onchange: () => console.log('Toggled')
|
|
10730
|
+
* })
|
|
10731
|
+
* ```
|
|
10732
|
+
*/
|
|
10733
|
+
const ToggleButton = () => {
|
|
10734
|
+
return {
|
|
10735
|
+
view: ({ attrs }) => {
|
|
10736
|
+
const { checked, iconName, icon, label, onchange, className, tooltip } = attrs, rest = __rest(attrs, ["checked", "iconName", "icon", "label", "onchange", "className", "tooltip"]);
|
|
10737
|
+
const classes = [className, checked ? 'checked' : ''].filter(Boolean).join(' ');
|
|
10738
|
+
return m('button.btn-flat.waves-effect.toggle-button', Object.assign(Object.assign({}, rest), { className: classes, title: tooltip, onclick: () => {
|
|
10739
|
+
if (onchange) {
|
|
10740
|
+
onchange();
|
|
10741
|
+
}
|
|
10742
|
+
}, onmousedown: WavesEffect.onMouseDown, onmouseup: WavesEffect.onMouseUp, onmouseleave: WavesEffect.onMouseLeave, ontouchstart: WavesEffect.onTouchStart, ontouchend: WavesEffect.onTouchEnd }), [icon, iconName && m(Icon, { iconName, className: attrs.iconClass }), label]);
|
|
10743
|
+
},
|
|
10744
|
+
};
|
|
10745
|
+
};
|
|
10746
|
+
|
|
10747
|
+
/**
|
|
10748
|
+
* ToggleGroup component.
|
|
10749
|
+
*
|
|
10750
|
+
* A group of toggle buttons that can operate in single-select or multi-select mode.
|
|
10751
|
+
* The component supports both controlled and uncontrolled modes.
|
|
10752
|
+
*
|
|
10753
|
+
* **Controlled mode**: Manage the state externally using the `value` prop.
|
|
10754
|
+
* **Uncontrolled mode**: Let the component manage its own state using `defaultValue`.
|
|
10755
|
+
*
|
|
10756
|
+
* @example
|
|
10757
|
+
* ```typescript
|
|
10758
|
+
* // Single-select, controlled mode
|
|
10759
|
+
* let selected = 'left';
|
|
10760
|
+
* m(ToggleGroup, {
|
|
10761
|
+
* value: selected,
|
|
10762
|
+
* onchange: (v) => selected = v,
|
|
10763
|
+
* items: [
|
|
10764
|
+
* { value: 'left', iconName: 'format_align_left', tooltip: 'Align Left' },
|
|
10765
|
+
* { value: 'center', iconName: 'format_align_center', tooltip: 'Align Center' },
|
|
10766
|
+
* { value: 'right', iconName: 'format_align_right', tooltip: 'Align Right' }
|
|
10767
|
+
* ]
|
|
10768
|
+
* });
|
|
10769
|
+
*
|
|
10770
|
+
* // Multi-select, controlled mode
|
|
10771
|
+
* let selected = ['bold', 'italic'];
|
|
10772
|
+
* m(ToggleGroup, {
|
|
10773
|
+
* multiple: true,
|
|
10774
|
+
* value: selected,
|
|
10775
|
+
* onchange: (v) => selected = v,
|
|
10776
|
+
* items: [
|
|
10777
|
+
* { value: 'bold', iconName: 'format_bold', tooltip: 'Bold' },
|
|
10778
|
+
* { value: 'italic', iconName: 'format_italic', tooltip: 'Italic' },
|
|
10779
|
+
* { value: 'underline', iconName: 'format_underlined', tooltip: 'Underline' }
|
|
10780
|
+
* ]
|
|
10781
|
+
* });
|
|
10782
|
+
*
|
|
10783
|
+
* // Uncontrolled mode
|
|
10784
|
+
* m(ToggleGroup, {
|
|
10785
|
+
* defaultValue: 'left',
|
|
10786
|
+
* onchange: (v) => console.log('Changed to:', v),
|
|
10787
|
+
* items: [...]
|
|
10788
|
+
* });
|
|
10789
|
+
* ```
|
|
10790
|
+
*/
|
|
10791
|
+
const ToggleGroup = () => {
|
|
10792
|
+
let internalValue;
|
|
10793
|
+
const handleSelect = (attrs, item, currentValue) => {
|
|
10794
|
+
if (attrs.disabled || item.disabled) {
|
|
10795
|
+
return;
|
|
10796
|
+
}
|
|
10797
|
+
const { value, multiple, onchange } = attrs;
|
|
10798
|
+
const isControlled = value !== undefined;
|
|
10799
|
+
if (multiple) {
|
|
10800
|
+
const currentValues = (Array.isArray(currentValue) ? currentValue : currentValue !== undefined ? [currentValue] : []);
|
|
10801
|
+
const newValues = currentValues.includes(item.value)
|
|
10802
|
+
? currentValues.filter((v) => v !== item.value)
|
|
10803
|
+
: [...currentValues, item.value];
|
|
10804
|
+
if (!isControlled) {
|
|
10805
|
+
internalValue = newValues;
|
|
10806
|
+
}
|
|
10807
|
+
if (onchange) {
|
|
10808
|
+
onchange(newValues);
|
|
10809
|
+
}
|
|
10810
|
+
}
|
|
10811
|
+
else {
|
|
10812
|
+
const newValue = item.value;
|
|
10813
|
+
if (!isControlled) {
|
|
10814
|
+
internalValue = newValue;
|
|
10815
|
+
}
|
|
10816
|
+
if (onchange) {
|
|
10817
|
+
onchange(newValue);
|
|
10818
|
+
}
|
|
10819
|
+
}
|
|
10820
|
+
};
|
|
10821
|
+
return {
|
|
10822
|
+
oninit: ({ attrs }) => {
|
|
10823
|
+
internalValue = attrs.defaultValue;
|
|
10824
|
+
},
|
|
10825
|
+
view: ({ attrs }) => {
|
|
10826
|
+
const { value, items, multiple } = attrs;
|
|
10827
|
+
const isControlled = value !== undefined;
|
|
10828
|
+
const currentValue = isControlled ? value : internalValue;
|
|
10829
|
+
return m('.toggle-group', items.map((item) => m(ToggleButton, Object.assign(Object.assign({}, item), { checked: multiple && Array.isArray(currentValue)
|
|
10830
|
+
? currentValue.includes(item.value)
|
|
10831
|
+
: currentValue === item.value, onchange: () => handleSelect(attrs, item, currentValue) }))));
|
|
10832
|
+
},
|
|
10833
|
+
};
|
|
10834
|
+
};
|
|
10835
|
+
|
|
10836
|
+
/** Size dimensions in pixels */
|
|
10837
|
+
const SIZE_MAP = {
|
|
10838
|
+
small: 36,
|
|
10839
|
+
medium: 50,
|
|
10840
|
+
large: 64,
|
|
10841
|
+
};
|
|
10842
|
+
/** Stroke width in pixels */
|
|
10843
|
+
const STROKE_WIDTH = 3;
|
|
10844
|
+
/** Create a CircularProgress component */
|
|
10845
|
+
const CircularProgress = () => {
|
|
10846
|
+
const state = {
|
|
10847
|
+
id: uniqueId(),
|
|
10848
|
+
};
|
|
10849
|
+
/**
|
|
10850
|
+
* Calculate SVG stroke properties for determinate progress
|
|
10851
|
+
*/
|
|
10852
|
+
const calculateStrokeProperties = (size, value, max) => {
|
|
10853
|
+
const radius = (size - STROKE_WIDTH) / 2;
|
|
10854
|
+
const circumference = 2 * Math.PI * radius;
|
|
10855
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
10856
|
+
const strokeDashoffset = circumference - (percentage / 100) * circumference;
|
|
10857
|
+
return {
|
|
10858
|
+
radius,
|
|
10859
|
+
circumference,
|
|
10860
|
+
strokeDashoffset,
|
|
10861
|
+
percentage,
|
|
10862
|
+
};
|
|
10863
|
+
};
|
|
10864
|
+
/**
|
|
10865
|
+
* Get size class name
|
|
10866
|
+
*/
|
|
10867
|
+
const getSizeClass = (size = 'medium') => {
|
|
10868
|
+
return `circular-progress--${size}`;
|
|
10869
|
+
};
|
|
10870
|
+
/**
|
|
10871
|
+
* Get color class name
|
|
10872
|
+
*/
|
|
10873
|
+
const getColorClass = (color, intensity) => {
|
|
10874
|
+
if (!color)
|
|
10875
|
+
return '';
|
|
10876
|
+
return intensity ? `circular-progress--${color} circular-progress--${intensity}` : `circular-progress--${color}`;
|
|
10877
|
+
};
|
|
10878
|
+
return {
|
|
10879
|
+
view: ({ attrs }) => {
|
|
10880
|
+
const { mode = 'indeterminate', value = 0, max = 100, size = 'medium', color = 'teal', colorIntensity, label, showPercentage = false, className = '', style = {}, id = state.id, 'aria-label': ariaLabel, 'aria-valuemin': ariaValueMin = 0, 'aria-valuemax': ariaValueMax = max, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText } = attrs, params = __rest(attrs, ["mode", "value", "max", "size", "color", "colorIntensity", "label", "showPercentage", "className", "style", "id", 'aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow', 'aria-valuetext']);
|
|
10881
|
+
const isDeterminate = mode === 'determinate';
|
|
10882
|
+
const sizePixels = SIZE_MAP[size];
|
|
10883
|
+
const { radius, circumference, strokeDashoffset, percentage } = isDeterminate
|
|
10884
|
+
? calculateStrokeProperties(sizePixels, value, max)
|
|
10885
|
+
: { radius: 0, circumference: 0, strokeDashoffset: 0, percentage: 0 };
|
|
10886
|
+
// Determine label content
|
|
10887
|
+
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
10888
|
+
// Build class names
|
|
10889
|
+
const classNames = [
|
|
10890
|
+
'circular-progress',
|
|
10891
|
+
getSizeClass(size),
|
|
10892
|
+
getColorClass(color, colorIntensity),
|
|
10893
|
+
`circular-progress--${mode}`,
|
|
10894
|
+
className,
|
|
10895
|
+
]
|
|
10896
|
+
.filter(Boolean)
|
|
10897
|
+
.join(' ');
|
|
10898
|
+
// ARIA attributes
|
|
10899
|
+
const ariaAttrs = isDeterminate
|
|
10900
|
+
? {
|
|
10901
|
+
'aria-valuenow': ariaValueNow !== undefined ? ariaValueNow : value,
|
|
10902
|
+
'aria-valuemin': ariaValueMin,
|
|
10903
|
+
'aria-valuemax': ariaValueMax,
|
|
10904
|
+
'aria-valuetext': ariaValueText || `${Math.round(percentage)}%`,
|
|
10905
|
+
}
|
|
10906
|
+
: {
|
|
10907
|
+
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
10908
|
+
};
|
|
10909
|
+
return m('.circular-progress', Object.assign(Object.assign(Object.assign({}, params), { className: classNames, style: Object.assign({ width: `${sizePixels}px`, height: `${sizePixels}px` }, style), id, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }), ariaAttrs), [
|
|
10910
|
+
// SVG circle
|
|
10911
|
+
m('svg.circular-progress__svg', {
|
|
10912
|
+
viewBox: `0 0 ${sizePixels} ${sizePixels}`,
|
|
10913
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
10914
|
+
}, [
|
|
10915
|
+
// Background track circle
|
|
10916
|
+
m('circle.circular-progress__circle.circular-progress__circle--track', {
|
|
10917
|
+
cx: sizePixels / 2,
|
|
10918
|
+
cy: sizePixels / 2,
|
|
10919
|
+
r: radius || (sizePixels - STROKE_WIDTH) / 2,
|
|
10920
|
+
fill: 'none',
|
|
10921
|
+
stroke: 'currentColor',
|
|
10922
|
+
'stroke-width': STROKE_WIDTH,
|
|
10923
|
+
}),
|
|
10924
|
+
// Progress indicator circle
|
|
10925
|
+
m('circle.circular-progress__circle.circular-progress__circle--indicator', {
|
|
10926
|
+
cx: sizePixels / 2,
|
|
10927
|
+
cy: sizePixels / 2,
|
|
10928
|
+
r: radius || (sizePixels - STROKE_WIDTH) / 2,
|
|
10929
|
+
fill: 'none',
|
|
10930
|
+
stroke: 'currentColor',
|
|
10931
|
+
'stroke-width': STROKE_WIDTH,
|
|
10932
|
+
'stroke-dasharray': isDeterminate ? circumference : undefined,
|
|
10933
|
+
'stroke-dashoffset': isDeterminate ? strokeDashoffset : undefined,
|
|
10934
|
+
'stroke-linecap': 'round',
|
|
10935
|
+
}),
|
|
10936
|
+
]),
|
|
10937
|
+
// Label inside circle
|
|
10938
|
+
labelContent &&
|
|
10939
|
+
m('.circular-progress__label', {
|
|
10940
|
+
'aria-hidden': 'true',
|
|
10941
|
+
}, labelContent),
|
|
10942
|
+
]);
|
|
10943
|
+
},
|
|
10944
|
+
};
|
|
10945
|
+
};
|
|
10946
|
+
|
|
10947
|
+
/** Create a LinearProgress component */
|
|
10948
|
+
const LinearProgress = () => {
|
|
10949
|
+
const state = {
|
|
10950
|
+
id: uniqueId(),
|
|
10951
|
+
};
|
|
10952
|
+
/**
|
|
10953
|
+
* Get size class name
|
|
10954
|
+
*/
|
|
10955
|
+
const getSizeClass = (size = 'medium') => {
|
|
10956
|
+
return `linear-progress__track--${size}`;
|
|
10957
|
+
};
|
|
10958
|
+
/**
|
|
10959
|
+
* Get color class name
|
|
10960
|
+
*/
|
|
10961
|
+
const getColorClass = (color, intensity) => {
|
|
10962
|
+
if (!color)
|
|
10963
|
+
return '';
|
|
10964
|
+
return intensity ? `linear-progress--${color} linear-progress--${intensity}` : `linear-progress--${color}`;
|
|
10965
|
+
};
|
|
10966
|
+
return {
|
|
10967
|
+
view: ({ attrs }) => {
|
|
10968
|
+
const { mode = 'indeterminate', value = 0, max = 100, size = 'medium', color = 'teal', colorIntensity, label, showPercentage = false, className = '', style = {}, id = state.id, 'aria-label': ariaLabel, 'aria-valuemin': ariaValueMin = 0, 'aria-valuemax': ariaValueMax = max, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText } = attrs, params = __rest(attrs, ["mode", "value", "max", "size", "color", "colorIntensity", "label", "showPercentage", "className", "style", "id", 'aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow', 'aria-valuetext']);
|
|
10969
|
+
const isDeterminate = mode === 'determinate';
|
|
10970
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
10971
|
+
// Determine label content
|
|
10972
|
+
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
10973
|
+
// Build class names
|
|
10974
|
+
const classNames = [
|
|
10975
|
+
'linear-progress',
|
|
10976
|
+
getColorClass(color, colorIntensity),
|
|
10977
|
+
className,
|
|
10978
|
+
]
|
|
10979
|
+
.filter(Boolean)
|
|
10980
|
+
.join(' ');
|
|
10981
|
+
// ARIA attributes
|
|
10982
|
+
const ariaAttrs = isDeterminate
|
|
10983
|
+
? {
|
|
10984
|
+
'aria-valuenow': ariaValueNow !== undefined ? ariaValueNow : value,
|
|
10985
|
+
'aria-valuemin': ariaValueMin,
|
|
10986
|
+
'aria-valuemax': ariaValueMax,
|
|
10987
|
+
'aria-valuetext': ariaValueText || `${Math.round(percentage)}%`,
|
|
10988
|
+
}
|
|
10989
|
+
: {
|
|
10990
|
+
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
10991
|
+
};
|
|
10992
|
+
return m('.linear-progress', Object.assign(Object.assign({}, params), { className: classNames, style,
|
|
10993
|
+
id }), [
|
|
10994
|
+
// Progress track container
|
|
10995
|
+
m('.linear-progress__track', Object.assign({ className: `linear-progress__track ${getSizeClass(size)}`, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }, ariaAttrs), [
|
|
10996
|
+
// Progress bar
|
|
10997
|
+
m('.linear-progress__bar', {
|
|
10998
|
+
className: `linear-progress__bar ${isDeterminate ? '' : 'linear-progress__bar--indeterminate'}`,
|
|
10999
|
+
style: isDeterminate ? { width: `${percentage}%` } : undefined,
|
|
11000
|
+
}),
|
|
11001
|
+
]),
|
|
11002
|
+
// Label at the end (right side)
|
|
11003
|
+
labelContent &&
|
|
11004
|
+
m('.linear-progress__label', {
|
|
11005
|
+
'aria-hidden': 'true',
|
|
11006
|
+
}, labelContent),
|
|
11007
|
+
]);
|
|
11008
|
+
},
|
|
11009
|
+
};
|
|
11010
|
+
};
|
|
11011
|
+
|
|
10716
11012
|
/**
|
|
10717
11013
|
* @fileoverview Core TypeScript utility types for mithril-materialized library
|
|
10718
11014
|
* These types improve type safety and developer experience across all components
|
|
@@ -10744,6 +11040,7 @@ exports.ButtonFactory = ButtonFactory;
|
|
|
10744
11040
|
exports.Carousel = Carousel;
|
|
10745
11041
|
exports.CharacterCounter = CharacterCounter;
|
|
10746
11042
|
exports.Chips = Chips;
|
|
11043
|
+
exports.CircularProgress = CircularProgress;
|
|
10747
11044
|
exports.CodeBlock = CodeBlock;
|
|
10748
11045
|
exports.Collapsible = Collapsible;
|
|
10749
11046
|
exports.CollapsibleItem = CollapsibleItem;
|
|
@@ -10766,6 +11063,7 @@ exports.ImageList = ImageList;
|
|
|
10766
11063
|
exports.InputCheckbox = InputCheckbox;
|
|
10767
11064
|
exports.Label = Label;
|
|
10768
11065
|
exports.LargeButton = LargeButton;
|
|
11066
|
+
exports.LinearProgress = LinearProgress;
|
|
10769
11067
|
exports.ListItem = ListItem;
|
|
10770
11068
|
exports.Mandatory = Mandatory;
|
|
10771
11069
|
exports.Masonry = Masonry;
|
|
@@ -10808,6 +11106,7 @@ exports.TimeRangePicker = TimeRangePicker;
|
|
|
10808
11106
|
exports.Timeline = Timeline;
|
|
10809
11107
|
exports.Toast = Toast;
|
|
10810
11108
|
exports.ToastComponent = ToastComponent;
|
|
11109
|
+
exports.ToggleGroup = ToggleGroup;
|
|
10811
11110
|
exports.Tooltip = Tooltip;
|
|
10812
11111
|
exports.TooltipComponent = TooltipComponent;
|
|
10813
11112
|
exports.TreeView = TreeView;
|