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.umd.js
CHANGED
|
@@ -10715,6 +10715,302 @@
|
|
|
10715
10715
|
};
|
|
10716
10716
|
};
|
|
10717
10717
|
|
|
10718
|
+
/**
|
|
10719
|
+
* ToggleButton component.
|
|
10720
|
+
*
|
|
10721
|
+
* A button that can be toggled on/off. Typically used within a ToggleGroup
|
|
10722
|
+
* to create grouped button controls where one or more buttons can be selected.
|
|
10723
|
+
*
|
|
10724
|
+
* @example
|
|
10725
|
+
* ```typescript
|
|
10726
|
+
* m(ToggleButton, {
|
|
10727
|
+
* value: 'bold',
|
|
10728
|
+
* iconName: 'format_bold',
|
|
10729
|
+
* checked: true,
|
|
10730
|
+
* tooltip: 'Bold',
|
|
10731
|
+
* onchange: () => console.log('Toggled')
|
|
10732
|
+
* })
|
|
10733
|
+
* ```
|
|
10734
|
+
*/
|
|
10735
|
+
const ToggleButton = () => {
|
|
10736
|
+
return {
|
|
10737
|
+
view: ({ attrs }) => {
|
|
10738
|
+
const { checked, iconName, icon, label, onchange, className, tooltip } = attrs, rest = __rest(attrs, ["checked", "iconName", "icon", "label", "onchange", "className", "tooltip"]);
|
|
10739
|
+
const classes = [className, checked ? 'checked' : ''].filter(Boolean).join(' ');
|
|
10740
|
+
return m('button.btn-flat.waves-effect.toggle-button', Object.assign(Object.assign({}, rest), { className: classes, title: tooltip, onclick: () => {
|
|
10741
|
+
if (onchange) {
|
|
10742
|
+
onchange();
|
|
10743
|
+
}
|
|
10744
|
+
}, onmousedown: WavesEffect.onMouseDown, onmouseup: WavesEffect.onMouseUp, onmouseleave: WavesEffect.onMouseLeave, ontouchstart: WavesEffect.onTouchStart, ontouchend: WavesEffect.onTouchEnd }), [icon, iconName && m(Icon, { iconName, className: attrs.iconClass }), label]);
|
|
10745
|
+
},
|
|
10746
|
+
};
|
|
10747
|
+
};
|
|
10748
|
+
|
|
10749
|
+
/**
|
|
10750
|
+
* ToggleGroup component.
|
|
10751
|
+
*
|
|
10752
|
+
* A group of toggle buttons that can operate in single-select or multi-select mode.
|
|
10753
|
+
* The component supports both controlled and uncontrolled modes.
|
|
10754
|
+
*
|
|
10755
|
+
* **Controlled mode**: Manage the state externally using the `value` prop.
|
|
10756
|
+
* **Uncontrolled mode**: Let the component manage its own state using `defaultValue`.
|
|
10757
|
+
*
|
|
10758
|
+
* @example
|
|
10759
|
+
* ```typescript
|
|
10760
|
+
* // Single-select, controlled mode
|
|
10761
|
+
* let selected = 'left';
|
|
10762
|
+
* m(ToggleGroup, {
|
|
10763
|
+
* value: selected,
|
|
10764
|
+
* onchange: (v) => selected = v,
|
|
10765
|
+
* items: [
|
|
10766
|
+
* { value: 'left', iconName: 'format_align_left', tooltip: 'Align Left' },
|
|
10767
|
+
* { value: 'center', iconName: 'format_align_center', tooltip: 'Align Center' },
|
|
10768
|
+
* { value: 'right', iconName: 'format_align_right', tooltip: 'Align Right' }
|
|
10769
|
+
* ]
|
|
10770
|
+
* });
|
|
10771
|
+
*
|
|
10772
|
+
* // Multi-select, controlled mode
|
|
10773
|
+
* let selected = ['bold', 'italic'];
|
|
10774
|
+
* m(ToggleGroup, {
|
|
10775
|
+
* multiple: true,
|
|
10776
|
+
* value: selected,
|
|
10777
|
+
* onchange: (v) => selected = v,
|
|
10778
|
+
* items: [
|
|
10779
|
+
* { value: 'bold', iconName: 'format_bold', tooltip: 'Bold' },
|
|
10780
|
+
* { value: 'italic', iconName: 'format_italic', tooltip: 'Italic' },
|
|
10781
|
+
* { value: 'underline', iconName: 'format_underlined', tooltip: 'Underline' }
|
|
10782
|
+
* ]
|
|
10783
|
+
* });
|
|
10784
|
+
*
|
|
10785
|
+
* // Uncontrolled mode
|
|
10786
|
+
* m(ToggleGroup, {
|
|
10787
|
+
* defaultValue: 'left',
|
|
10788
|
+
* onchange: (v) => console.log('Changed to:', v),
|
|
10789
|
+
* items: [...]
|
|
10790
|
+
* });
|
|
10791
|
+
* ```
|
|
10792
|
+
*/
|
|
10793
|
+
const ToggleGroup = () => {
|
|
10794
|
+
let internalValue;
|
|
10795
|
+
const handleSelect = (attrs, item, currentValue) => {
|
|
10796
|
+
if (attrs.disabled || item.disabled) {
|
|
10797
|
+
return;
|
|
10798
|
+
}
|
|
10799
|
+
const { value, multiple, onchange } = attrs;
|
|
10800
|
+
const isControlled = value !== undefined;
|
|
10801
|
+
if (multiple) {
|
|
10802
|
+
const currentValues = (Array.isArray(currentValue) ? currentValue : currentValue !== undefined ? [currentValue] : []);
|
|
10803
|
+
const newValues = currentValues.includes(item.value)
|
|
10804
|
+
? currentValues.filter((v) => v !== item.value)
|
|
10805
|
+
: [...currentValues, item.value];
|
|
10806
|
+
if (!isControlled) {
|
|
10807
|
+
internalValue = newValues;
|
|
10808
|
+
}
|
|
10809
|
+
if (onchange) {
|
|
10810
|
+
onchange(newValues);
|
|
10811
|
+
}
|
|
10812
|
+
}
|
|
10813
|
+
else {
|
|
10814
|
+
const newValue = item.value;
|
|
10815
|
+
if (!isControlled) {
|
|
10816
|
+
internalValue = newValue;
|
|
10817
|
+
}
|
|
10818
|
+
if (onchange) {
|
|
10819
|
+
onchange(newValue);
|
|
10820
|
+
}
|
|
10821
|
+
}
|
|
10822
|
+
};
|
|
10823
|
+
return {
|
|
10824
|
+
oninit: ({ attrs }) => {
|
|
10825
|
+
internalValue = attrs.defaultValue;
|
|
10826
|
+
},
|
|
10827
|
+
view: ({ attrs }) => {
|
|
10828
|
+
const { value, items, multiple } = attrs;
|
|
10829
|
+
const isControlled = value !== undefined;
|
|
10830
|
+
const currentValue = isControlled ? value : internalValue;
|
|
10831
|
+
return m('.toggle-group', items.map((item) => m(ToggleButton, Object.assign(Object.assign({}, item), { checked: multiple && Array.isArray(currentValue)
|
|
10832
|
+
? currentValue.includes(item.value)
|
|
10833
|
+
: currentValue === item.value, onchange: () => handleSelect(attrs, item, currentValue) }))));
|
|
10834
|
+
},
|
|
10835
|
+
};
|
|
10836
|
+
};
|
|
10837
|
+
|
|
10838
|
+
/** Size dimensions in pixels */
|
|
10839
|
+
const SIZE_MAP = {
|
|
10840
|
+
small: 36,
|
|
10841
|
+
medium: 50,
|
|
10842
|
+
large: 64,
|
|
10843
|
+
};
|
|
10844
|
+
/** Stroke width in pixels */
|
|
10845
|
+
const STROKE_WIDTH = 3;
|
|
10846
|
+
/** Create a CircularProgress component */
|
|
10847
|
+
const CircularProgress = () => {
|
|
10848
|
+
const state = {
|
|
10849
|
+
id: uniqueId(),
|
|
10850
|
+
};
|
|
10851
|
+
/**
|
|
10852
|
+
* Calculate SVG stroke properties for determinate progress
|
|
10853
|
+
*/
|
|
10854
|
+
const calculateStrokeProperties = (size, value, max) => {
|
|
10855
|
+
const radius = (size - STROKE_WIDTH) / 2;
|
|
10856
|
+
const circumference = 2 * Math.PI * radius;
|
|
10857
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
10858
|
+
const strokeDashoffset = circumference - (percentage / 100) * circumference;
|
|
10859
|
+
return {
|
|
10860
|
+
radius,
|
|
10861
|
+
circumference,
|
|
10862
|
+
strokeDashoffset,
|
|
10863
|
+
percentage,
|
|
10864
|
+
};
|
|
10865
|
+
};
|
|
10866
|
+
/**
|
|
10867
|
+
* Get size class name
|
|
10868
|
+
*/
|
|
10869
|
+
const getSizeClass = (size = 'medium') => {
|
|
10870
|
+
return `circular-progress--${size}`;
|
|
10871
|
+
};
|
|
10872
|
+
/**
|
|
10873
|
+
* Get color class name
|
|
10874
|
+
*/
|
|
10875
|
+
const getColorClass = (color, intensity) => {
|
|
10876
|
+
if (!color)
|
|
10877
|
+
return '';
|
|
10878
|
+
return intensity ? `circular-progress--${color} circular-progress--${intensity}` : `circular-progress--${color}`;
|
|
10879
|
+
};
|
|
10880
|
+
return {
|
|
10881
|
+
view: ({ attrs }) => {
|
|
10882
|
+
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']);
|
|
10883
|
+
const isDeterminate = mode === 'determinate';
|
|
10884
|
+
const sizePixels = SIZE_MAP[size];
|
|
10885
|
+
const { radius, circumference, strokeDashoffset, percentage } = isDeterminate
|
|
10886
|
+
? calculateStrokeProperties(sizePixels, value, max)
|
|
10887
|
+
: { radius: 0, circumference: 0, strokeDashoffset: 0, percentage: 0 };
|
|
10888
|
+
// Determine label content
|
|
10889
|
+
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
10890
|
+
// Build class names
|
|
10891
|
+
const classNames = [
|
|
10892
|
+
'circular-progress',
|
|
10893
|
+
getSizeClass(size),
|
|
10894
|
+
getColorClass(color, colorIntensity),
|
|
10895
|
+
`circular-progress--${mode}`,
|
|
10896
|
+
className,
|
|
10897
|
+
]
|
|
10898
|
+
.filter(Boolean)
|
|
10899
|
+
.join(' ');
|
|
10900
|
+
// ARIA attributes
|
|
10901
|
+
const ariaAttrs = isDeterminate
|
|
10902
|
+
? {
|
|
10903
|
+
'aria-valuenow': ariaValueNow !== undefined ? ariaValueNow : value,
|
|
10904
|
+
'aria-valuemin': ariaValueMin,
|
|
10905
|
+
'aria-valuemax': ariaValueMax,
|
|
10906
|
+
'aria-valuetext': ariaValueText || `${Math.round(percentage)}%`,
|
|
10907
|
+
}
|
|
10908
|
+
: {
|
|
10909
|
+
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
10910
|
+
};
|
|
10911
|
+
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), [
|
|
10912
|
+
// SVG circle
|
|
10913
|
+
m('svg.circular-progress__svg', {
|
|
10914
|
+
viewBox: `0 0 ${sizePixels} ${sizePixels}`,
|
|
10915
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
10916
|
+
}, [
|
|
10917
|
+
// Background track circle
|
|
10918
|
+
m('circle.circular-progress__circle.circular-progress__circle--track', {
|
|
10919
|
+
cx: sizePixels / 2,
|
|
10920
|
+
cy: sizePixels / 2,
|
|
10921
|
+
r: radius || (sizePixels - STROKE_WIDTH) / 2,
|
|
10922
|
+
fill: 'none',
|
|
10923
|
+
stroke: 'currentColor',
|
|
10924
|
+
'stroke-width': STROKE_WIDTH,
|
|
10925
|
+
}),
|
|
10926
|
+
// Progress indicator circle
|
|
10927
|
+
m('circle.circular-progress__circle.circular-progress__circle--indicator', {
|
|
10928
|
+
cx: sizePixels / 2,
|
|
10929
|
+
cy: sizePixels / 2,
|
|
10930
|
+
r: radius || (sizePixels - STROKE_WIDTH) / 2,
|
|
10931
|
+
fill: 'none',
|
|
10932
|
+
stroke: 'currentColor',
|
|
10933
|
+
'stroke-width': STROKE_WIDTH,
|
|
10934
|
+
'stroke-dasharray': isDeterminate ? circumference : undefined,
|
|
10935
|
+
'stroke-dashoffset': isDeterminate ? strokeDashoffset : undefined,
|
|
10936
|
+
'stroke-linecap': 'round',
|
|
10937
|
+
}),
|
|
10938
|
+
]),
|
|
10939
|
+
// Label inside circle
|
|
10940
|
+
labelContent &&
|
|
10941
|
+
m('.circular-progress__label', {
|
|
10942
|
+
'aria-hidden': 'true',
|
|
10943
|
+
}, labelContent),
|
|
10944
|
+
]);
|
|
10945
|
+
},
|
|
10946
|
+
};
|
|
10947
|
+
};
|
|
10948
|
+
|
|
10949
|
+
/** Create a LinearProgress component */
|
|
10950
|
+
const LinearProgress = () => {
|
|
10951
|
+
const state = {
|
|
10952
|
+
id: uniqueId(),
|
|
10953
|
+
};
|
|
10954
|
+
/**
|
|
10955
|
+
* Get size class name
|
|
10956
|
+
*/
|
|
10957
|
+
const getSizeClass = (size = 'medium') => {
|
|
10958
|
+
return `linear-progress__track--${size}`;
|
|
10959
|
+
};
|
|
10960
|
+
/**
|
|
10961
|
+
* Get color class name
|
|
10962
|
+
*/
|
|
10963
|
+
const getColorClass = (color, intensity) => {
|
|
10964
|
+
if (!color)
|
|
10965
|
+
return '';
|
|
10966
|
+
return intensity ? `linear-progress--${color} linear-progress--${intensity}` : `linear-progress--${color}`;
|
|
10967
|
+
};
|
|
10968
|
+
return {
|
|
10969
|
+
view: ({ attrs }) => {
|
|
10970
|
+
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']);
|
|
10971
|
+
const isDeterminate = mode === 'determinate';
|
|
10972
|
+
const percentage = Math.min(100, Math.max(0, (value / max) * 100));
|
|
10973
|
+
// Determine label content
|
|
10974
|
+
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
10975
|
+
// Build class names
|
|
10976
|
+
const classNames = [
|
|
10977
|
+
'linear-progress',
|
|
10978
|
+
getColorClass(color, colorIntensity),
|
|
10979
|
+
className,
|
|
10980
|
+
]
|
|
10981
|
+
.filter(Boolean)
|
|
10982
|
+
.join(' ');
|
|
10983
|
+
// ARIA attributes
|
|
10984
|
+
const ariaAttrs = isDeterminate
|
|
10985
|
+
? {
|
|
10986
|
+
'aria-valuenow': ariaValueNow !== undefined ? ariaValueNow : value,
|
|
10987
|
+
'aria-valuemin': ariaValueMin,
|
|
10988
|
+
'aria-valuemax': ariaValueMax,
|
|
10989
|
+
'aria-valuetext': ariaValueText || `${Math.round(percentage)}%`,
|
|
10990
|
+
}
|
|
10991
|
+
: {
|
|
10992
|
+
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
10993
|
+
};
|
|
10994
|
+
return m('.linear-progress', Object.assign(Object.assign({}, params), { className: classNames, style,
|
|
10995
|
+
id }), [
|
|
10996
|
+
// Progress track container
|
|
10997
|
+
m('.linear-progress__track', Object.assign({ className: `linear-progress__track ${getSizeClass(size)}`, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }, ariaAttrs), [
|
|
10998
|
+
// Progress bar
|
|
10999
|
+
m('.linear-progress__bar', {
|
|
11000
|
+
className: `linear-progress__bar ${isDeterminate ? '' : 'linear-progress__bar--indeterminate'}`,
|
|
11001
|
+
style: isDeterminate ? { width: `${percentage}%` } : undefined,
|
|
11002
|
+
}),
|
|
11003
|
+
]),
|
|
11004
|
+
// Label at the end (right side)
|
|
11005
|
+
labelContent &&
|
|
11006
|
+
m('.linear-progress__label', {
|
|
11007
|
+
'aria-hidden': 'true',
|
|
11008
|
+
}, labelContent),
|
|
11009
|
+
]);
|
|
11010
|
+
},
|
|
11011
|
+
};
|
|
11012
|
+
};
|
|
11013
|
+
|
|
10718
11014
|
/**
|
|
10719
11015
|
* @fileoverview Core TypeScript utility types for mithril-materialized library
|
|
10720
11016
|
* These types improve type safety and developer experience across all components
|
|
@@ -10746,6 +11042,7 @@
|
|
|
10746
11042
|
exports.Carousel = Carousel;
|
|
10747
11043
|
exports.CharacterCounter = CharacterCounter;
|
|
10748
11044
|
exports.Chips = Chips;
|
|
11045
|
+
exports.CircularProgress = CircularProgress;
|
|
10749
11046
|
exports.CodeBlock = CodeBlock;
|
|
10750
11047
|
exports.Collapsible = Collapsible;
|
|
10751
11048
|
exports.CollapsibleItem = CollapsibleItem;
|
|
@@ -10768,6 +11065,7 @@
|
|
|
10768
11065
|
exports.InputCheckbox = InputCheckbox;
|
|
10769
11066
|
exports.Label = Label;
|
|
10770
11067
|
exports.LargeButton = LargeButton;
|
|
11068
|
+
exports.LinearProgress = LinearProgress;
|
|
10771
11069
|
exports.ListItem = ListItem;
|
|
10772
11070
|
exports.Mandatory = Mandatory;
|
|
10773
11071
|
exports.Masonry = Masonry;
|
|
@@ -10810,6 +11108,7 @@
|
|
|
10810
11108
|
exports.Timeline = Timeline;
|
|
10811
11109
|
exports.Toast = Toast;
|
|
10812
11110
|
exports.ToastComponent = ToastComponent;
|
|
11111
|
+
exports.ToggleGroup = ToggleGroup;
|
|
10813
11112
|
exports.Tooltip = Tooltip;
|
|
10814
11113
|
exports.TooltipComponent = TooltipComponent;
|
|
10815
11114
|
exports.TreeView = TreeView;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { FactoryComponent, Attributes } from 'mithril';
|
|
2
|
+
import { MaterialColor, ColorIntensity } from './types';
|
|
3
|
+
import { ProgressMode, ProgressSize } from './circular-progress';
|
|
4
|
+
/** LinearProgress component attributes */
|
|
5
|
+
export interface LinearProgressAttrs extends Attributes {
|
|
6
|
+
/** Progress mode (default: 'indeterminate') */
|
|
7
|
+
mode?: ProgressMode;
|
|
8
|
+
/** Current progress value (0-100) for determinate mode */
|
|
9
|
+
value?: number;
|
|
10
|
+
/** Maximum progress value (default: 100) */
|
|
11
|
+
max?: number;
|
|
12
|
+
/** Size variant (default: 'medium') */
|
|
13
|
+
size?: ProgressSize;
|
|
14
|
+
/** Materialize color (default: 'teal') */
|
|
15
|
+
color?: MaterialColor;
|
|
16
|
+
/** Color intensity modifier */
|
|
17
|
+
colorIntensity?: ColorIntensity;
|
|
18
|
+
/** Label to display at the end (right side) */
|
|
19
|
+
label?: string | number;
|
|
20
|
+
/** Auto-show percentage at the end for determinate mode (default: false) */
|
|
21
|
+
showPercentage?: boolean;
|
|
22
|
+
/** Additional CSS class names */
|
|
23
|
+
className?: string;
|
|
24
|
+
/** Additional CSS styles */
|
|
25
|
+
style?: any;
|
|
26
|
+
/** HTML ID for the component */
|
|
27
|
+
id?: string;
|
|
28
|
+
/** ARIA label for accessibility */
|
|
29
|
+
'aria-label'?: string;
|
|
30
|
+
/** ARIA valuemin (default: 0) */
|
|
31
|
+
'aria-valuemin'?: number;
|
|
32
|
+
/** ARIA valuemax (default: 100) */
|
|
33
|
+
'aria-valuemax'?: number;
|
|
34
|
+
/** ARIA valuenow (current value) */
|
|
35
|
+
'aria-valuenow'?: number;
|
|
36
|
+
/** ARIA valuetext (custom text description) */
|
|
37
|
+
'aria-valuetext'?: string;
|
|
38
|
+
}
|
|
39
|
+
/** Create a LinearProgress component */
|
|
40
|
+
export declare const LinearProgress: FactoryComponent<LinearProgressAttrs>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { FactoryComponent, Attributes, Vnode } from 'mithril';
|
|
2
|
+
/**
|
|
3
|
+
* Attributes for the ToggleButton component.
|
|
4
|
+
*
|
|
5
|
+
* A toggle button is a button that can be in a checked or unchecked state.
|
|
6
|
+
* It is typically used within a ToggleGroup to create button groups where
|
|
7
|
+
* one or more buttons can be selected.
|
|
8
|
+
*/
|
|
9
|
+
export interface ToggleButtonAttrs extends Attributes {
|
|
10
|
+
/** The value of the button. This is returned when the button is selected. */
|
|
11
|
+
value: string | number;
|
|
12
|
+
/** The label text to display next to the icon. */
|
|
13
|
+
label?: string;
|
|
14
|
+
/** The name of the Material Design icon to display. */
|
|
15
|
+
iconName?: string;
|
|
16
|
+
/** A custom SVG icon vnode to display instead of a Material icon. */
|
|
17
|
+
icon?: Vnode<any, any>;
|
|
18
|
+
/** Additional CSS class for the icon element. */
|
|
19
|
+
iconClass?: string;
|
|
20
|
+
/** Whether the button is in a checked/selected state. */
|
|
21
|
+
checked?: boolean;
|
|
22
|
+
/** Whether the button is disabled and cannot be interacted with. */
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/** Optional tooltip text to display on hover. */
|
|
25
|
+
tooltip?: string;
|
|
26
|
+
/** Callback function invoked when the button is clicked. */
|
|
27
|
+
onchange?: () => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* ToggleButton component.
|
|
31
|
+
*
|
|
32
|
+
* A button that can be toggled on/off. Typically used within a ToggleGroup
|
|
33
|
+
* to create grouped button controls where one or more buttons can be selected.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* m(ToggleButton, {
|
|
38
|
+
* value: 'bold',
|
|
39
|
+
* iconName: 'format_bold',
|
|
40
|
+
* checked: true,
|
|
41
|
+
* tooltip: 'Bold',
|
|
42
|
+
* onchange: () => console.log('Toggled')
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare const ToggleButton: FactoryComponent<ToggleButtonAttrs>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { FactoryComponent, Attributes } from 'mithril';
|
|
2
|
+
import { ToggleButtonAttrs } from './toggle-button';
|
|
3
|
+
/**
|
|
4
|
+
* Attributes for the ToggleGroup component.
|
|
5
|
+
*
|
|
6
|
+
* A toggle group is a container for multiple toggle buttons that manages their
|
|
7
|
+
* selection state. It can operate in single-select or multi-select mode.
|
|
8
|
+
*/
|
|
9
|
+
export interface ToggleGroupAttrs extends Attributes {
|
|
10
|
+
/**
|
|
11
|
+
* The current value(s) of the toggle group (controlled mode).
|
|
12
|
+
* - Single-select: a single value
|
|
13
|
+
* - Multi-select: an array of values
|
|
14
|
+
*/
|
|
15
|
+
value?: string | number | Array<string | number>;
|
|
16
|
+
/**
|
|
17
|
+
* The default value(s) for uncontrolled mode.
|
|
18
|
+
* Use this when you want the component to manage its own state.
|
|
19
|
+
*/
|
|
20
|
+
defaultValue?: string | number | Array<string | number>;
|
|
21
|
+
/** Whether all buttons in the group are disabled. */
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Callback invoked when the selection changes.
|
|
25
|
+
* @param value - The new value (single value or array depending on `multiple`)
|
|
26
|
+
*/
|
|
27
|
+
onchange?: (value: string | number | Array<string | number>) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Array of button configurations to display in the group.
|
|
30
|
+
* Each item can have its own icon, label, tooltip, and disabled state.
|
|
31
|
+
*/
|
|
32
|
+
items: Array<ToggleButtonAttrs>;
|
|
33
|
+
/**
|
|
34
|
+
* Whether to allow multiple buttons to be selected simultaneously.
|
|
35
|
+
* - false (default): only one button can be selected at a time
|
|
36
|
+
* - true: multiple buttons can be selected
|
|
37
|
+
*/
|
|
38
|
+
multiple?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* ToggleGroup component.
|
|
42
|
+
*
|
|
43
|
+
* A group of toggle buttons that can operate in single-select or multi-select mode.
|
|
44
|
+
* The component supports both controlled and uncontrolled modes.
|
|
45
|
+
*
|
|
46
|
+
* **Controlled mode**: Manage the state externally using the `value` prop.
|
|
47
|
+
* **Uncontrolled mode**: Let the component manage its own state using `defaultValue`.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // Single-select, controlled mode
|
|
52
|
+
* let selected = 'left';
|
|
53
|
+
* m(ToggleGroup, {
|
|
54
|
+
* value: selected,
|
|
55
|
+
* onchange: (v) => selected = v,
|
|
56
|
+
* items: [
|
|
57
|
+
* { value: 'left', iconName: 'format_align_left', tooltip: 'Align Left' },
|
|
58
|
+
* { value: 'center', iconName: 'format_align_center', tooltip: 'Align Center' },
|
|
59
|
+
* { value: 'right', iconName: 'format_align_right', tooltip: 'Align Right' }
|
|
60
|
+
* ]
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* // Multi-select, controlled mode
|
|
64
|
+
* let selected = ['bold', 'italic'];
|
|
65
|
+
* m(ToggleGroup, {
|
|
66
|
+
* multiple: true,
|
|
67
|
+
* value: selected,
|
|
68
|
+
* onchange: (v) => selected = v,
|
|
69
|
+
* items: [
|
|
70
|
+
* { value: 'bold', iconName: 'format_bold', tooltip: 'Bold' },
|
|
71
|
+
* { value: 'italic', iconName: 'format_italic', tooltip: 'Italic' },
|
|
72
|
+
* { value: 'underline', iconName: 'format_underlined', tooltip: 'Underline' }
|
|
73
|
+
* ]
|
|
74
|
+
* });
|
|
75
|
+
*
|
|
76
|
+
* // Uncontrolled mode
|
|
77
|
+
* m(ToggleGroup, {
|
|
78
|
+
* defaultValue: 'left',
|
|
79
|
+
* onchange: (v) => console.log('Changed to:', v),
|
|
80
|
+
* items: [...]
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare const ToggleGroup: FactoryComponent<ToggleGroupAttrs>;
|