Skip to content

Commit

Permalink
Simplified element creation in mithril
Browse files Browse the repository at this point in the history
  • Loading branch information
driver-deploy-2 committed Jan 13, 2025
1 parent 49026af commit d2baaf1
Show file tree
Hide file tree
Showing 24 changed files with 317 additions and 291 deletions.
2 changes: 2 additions & 0 deletions packages/example/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ import { dashboardSvc } from './services/dashboard-service';
// import '@materializecss/materialize/dist/css/materialize.min.css';
// import '/home/erik/dev/mithril-materialized/node_modules/.pnpm/@materializecss+materialize@2.0.1-alpha/node_modules/@materializecss/materialize/dist/css/materialize.min.css';

document.documentElement.setAttribute('lang', 'en');

m.route(document.body, dashboardSvc.defaultRoute, dashboardSvc.routingTable);
20 changes: 16 additions & 4 deletions packages/example/src/components/buttons/button-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,27 @@ export const ButtonPage = () => {
m(Button, { label: 'First Button', onclick }),
m(Button, { label: 'Second Button', iconName: 'cloud', onclick }),
m(Button, { label: 'Third Button', iconName: 'cloud', iconClass: 'right', onclick }),
m(Button, {
label: 'Fourth Button',
iconName: 'cloud',
attr: { disabled: true },
onclick,
}),
]),
m(CodeBlock, {
code: [
`const onclick = () => alert('Button clicked');
m('div', [
m(Button, { label: 'Button', onclick }),
m(Button, { label: 'Button', iconName: 'cloud', onclick }),
m(Button, { label: 'Button', iconName: 'cloud', iconClass: 'right', onclick }),
]),`,
m(Button, { label: 'First Button', onclick }),
m(Button, { label: 'Second Button', iconName: 'cloud', onclick }),
m(Button, { label: 'Third Button', iconName: 'cloud', iconClass: 'right', onclick }),
m(Button, {
label: 'Fourth Button',
iconName: 'cloud',
attr: { disabled: true },
onclick,
}),
])`,
],
}),
m('h3.header[id=flatbutton]', 'FlatButton'),
Expand Down
15 changes: 9 additions & 6 deletions packages/example/src/components/inputs/input-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import m from 'mithril';

export const InputPage = () => {
const onchange = (v: unknown) => alert(`Input changed. New value: ${v}`);
const onchange = (v: unknown) => console.log(`Input changed. New value: ${v}`);
let value = 'click_clear_to_remove.me';
return {
view: () =>
Expand All @@ -28,6 +28,7 @@ export const InputPage = () => {
'.row',
m(TextInput, {
label: 'What is your name?',
required: true,
helperText: 'Please, be honest!',
onchange,
autocomplete: 'off',
Expand All @@ -39,6 +40,7 @@ export const InputPage = () => {
m(CodeBlock, {
code: ` m(TextInput, {
label: 'What is your name?',
required: true,
helperText: 'Please, be honest!',
onchange,
onkeyup: (ev, value) => console.log(value),
Expand Down Expand Up @@ -93,8 +95,9 @@ export const InputPage = () => {
Apple: null,
Google: null,
Facebook: null,
PHILIPS: 'http://hdlighting-suriname.com/wp-content/uploads/2013/12/philips.png',
TNO: 'https://github.com/TNOCS/spec-tool/raw/master/src/assets/tno.png',
PHILIPS:
'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Philips_logo.svg/800px-Philips_logo.svg.png',
TNO: 'https://tno.github.io/crime_scripts/f418cfa539199976.svg',
},
onchange,
})
Expand All @@ -107,8 +110,8 @@ export const InputPage = () => {
Apple: null,
Google: null,
Facebook: null,
PHILIPS: 'http://hdlighting-suriname.com/wp-content/uploads/2013/12/philips.png',
TNO: 'https://github.com/TNOCS/spec-tool/raw/master/src/assets/tno.png',
PHILIPS: 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/8c/Philips_logo.svg/800px-Philips_logo.svg.png',
TNO: 'https://tno.github.io/crime_scripts/f418cfa539199976.svg',
},
onchange,
} as IInputOptions)`,
Expand All @@ -118,7 +121,7 @@ export const InputPage = () => {
m(
'.row',
m(TextArea, {
label: 'Please, could you describe yourself',
label: 'Please, describe yourself',
helperText: `Don't be shy`,
maxLength: 100,
onchange,
Expand Down
20 changes: 10 additions & 10 deletions packages/example/src/components/misc/misc-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,21 @@ export const MiscPage = () => {
'.row',
m(Carousel, {
items: [
{ href: '#!/one!', src: 'https://lorempixel.com/250/250/nature/1' },
{ href: '#!/two!', src: 'https://lorempixel.com/250/250/nature/2' },
{ href: '#!/three!', src: 'https://lorempixel.com/250/250/nature/3' },
{ href: '#!/four!', src: 'https://lorempixel.com/250/250/nature/4' },
{ href: '#!/five!', src: 'https://lorempixel.com/250/250/nature/5' },
{ href: '#!/one!', src: 'https://picsum.photos/id/301/200/300' },
{ href: '#!/two!', src: 'https://picsum.photos/id/302/200/300' },
{ href: '#!/three!', src: 'https://picsum.photos/id/306/200/300' },
{ href: '#!/four!', src: 'https://picsum.photos/id/304/200/300' },
{ href: '#!/five!', src: 'https://picsum.photos/id/305/200/300' },
],
})
),
m(CodeBlock, {
code: ` m(Carousel, { items: [
{ href: '#!/one!', src: 'https://lorempixel.com/250/250/nature/1' },
{ href: '#!/two!', src: 'https://lorempixel.com/250/250/nature/2' },
{ href: '#!/three!', src: 'https://lorempixel.com/250/250/nature/3' },
{ href: '#!/four!', src: 'https://lorempixel.com/250/250/nature/4' },
{ href: '#!/five!', src: 'https://lorempixel.com/250/250/nature/5' },
{ href: '#!/one!', src: 'https://picsum.photos/id/301/200/300' },
{ href: '#!/two!', src: 'https://picsum.photos/id/302/200/300' },
{ href: '#!/three!', src: 'https://picsum.photos/id/306/200/300' },
{ href: '#!/four!', src: 'https://picsum.photos/id/304/200/300' },
{ href: '#!/five!', src: 'https://picsum.photos/id/305/200/300' },
] })`,
}),

Expand Down
6 changes: 3 additions & 3 deletions packages/example/src/components/pickers/picker-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const PickerPage = () => {
label: 'Disable pickers',
left: 'enable',
right: 'disable',
onchange: v => (state.disabled = v),
onchange: (v) => (state.disabled = v),
})
),
m('h3.header', 'DatePicker'),
Expand All @@ -25,7 +25,7 @@ export const PickerPage = () => {
disabled: state.disabled,
format: 'mmmm d, yyyy',
label: 'What is your birthday?',
yearRange: [1900, new Date().getFullYear() - 17],
yearRange: [1970, new Date().getFullYear() + 20],
initialValue: new Date(),
onchange,
})
Expand All @@ -34,7 +34,7 @@ export const PickerPage = () => {
code: ` m(DatePicker, {
format: 'mmmm d, yyyy',
label: 'What is your birthday?',
yearRange: [1900, new Date().getFullYear() - 17],
yearRange: [1970, new Date().getFullYear() + 20],
initialValue: new Date().toDateString(),
onchange,
})`,
Expand Down
11 changes: 8 additions & 3 deletions packages/lib/src/autocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import m, { FactoryComponent } from 'mithril';
import { uniqueId, toAttrs } from './utils';
import { uniqueId } from './utils';
import { IInputOptions } from './input-options';
import { Label, HelperText } from './label';

Expand All @@ -11,7 +11,7 @@ export const Autocomplete: FactoryComponent<IAutoCompleteOptions> = () => {
return {
view: ({ attrs }) => {
const id = attrs.id || state.id;
const attributes = toAttrs(attrs);
// const attributes = toAttrs(attrs);
const {
label,
helperText,
Expand All @@ -22,11 +22,16 @@ export const Autocomplete: FactoryComponent<IAutoCompleteOptions> = () => {
style,
iconName,
isMandatory,
...params
} = attrs;
const cn = newRow ? className + ' clear' : className;
return m(`.input-field${newRow ? '.clear' : ''}`, { className: cn, style }, [
iconName ? m('i.material-icons.prefix', iconName) : '',
m(`input.autocomplete[type=text][tabindex=0]${attributes}`, {
m('input', {
...params,
className: 'autocomplete',
type: 'text',
tabindex: 0,
id,
oncreate: ({ dom }) => {
M.Autocomplete.init(dom, attrs);
Expand Down
47 changes: 31 additions & 16 deletions packages/lib/src/button.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import m, { FactoryComponent, Attributes } from 'mithril';
import { toAttributeString } from './utils';
import { Icon } from './icon';

export interface IHtmlAttributes {
Expand Down Expand Up @@ -36,28 +35,44 @@ export interface IMaterialButton extends Attributes {
*
* @example FlatButton = ButtonFactory('a.waves-effect.waves-teal.btn-flat');
*/
export const ButtonFactory =
(defaultClassNames: string, attributes: string = ''): FactoryComponent<IMaterialButton> =>
() => {
const dca = `${defaultClassNames}${attributes}`;
export const ButtonFactory = (
element: string,
defaultClassNames: string,
type: string = ''
): FactoryComponent<IMaterialButton> => {
return () => {
return {
view: ({ attrs }) => {
const { modalId, tooltip, tooltipPostion, iconName, iconClass, label, attr, ...passThrough } = attrs;
const { modalId, tooltip, tooltipPostion, iconName, iconClass, label, attr, ...params } = attrs;
const cn = [modalId ? 'modal-trigger' : '', tooltip ? 'tooltipped' : '', defaultClassNames]
.filter(Boolean)
.join(' ')
.trim();
return m(
`${dca}${modalId ? `.modal-trigger[href=#${modalId}]` : ''}${
tooltip ? `.tooltipped[data-position=${tooltipPostion || 'top'}][data-tooltip=${tooltip}]` : ''
}${toAttributeString(attr)}`,
passThrough,
element,
{
...params,
...attr,
className: cn,
href: modalId ? `#${modalId}` : undefined,
'data-position': tooltip ? tooltipPostion || 'top' : undefined,
'data-tooltip': tooltip || undefined,
type,
},
// `${dca}${modalId ? `.modal-trigger[href=#${modalId}]` : ''}${
// tooltip ? `.tooltipped[data-position=${tooltipPostion || 'top'}][data-tooltip=${tooltip}]` : ''
// }${toAttributeString(attr)}`, {}
iconName ? m(Icon, { iconName, className: iconClass || 'left' }) : undefined,
label ? label : undefined
);
},
};
};
};

export const Button = ButtonFactory('a.waves-effect.waves-light.btn', '[type=button]');
export const LargeButton = ButtonFactory('a.waves-effect.waves-light.btn-large', '[type=button]');
export const SmallButton = ButtonFactory('a.waves-effect.waves-light.btn-small', '[type=button]');
export const FlatButton = ButtonFactory('a.waves-effect.waves-teal.btn-flat', '[type=button]');
export const RoundIconButton = ButtonFactory('button.btn-floating.btn-large.waves-effect.waves-light', '[type=button]');
export const SubmitButton = ButtonFactory('button.btn.waves-effect.waves-light', '[type=submit]');
export const Button = ButtonFactory('a', 'waves-effect waves-light btn', 'button');
export const LargeButton = ButtonFactory('a', 'waves-effect waves-light btn-large', 'button');
export const SmallButton = ButtonFactory('a', 'waves-effect waves-light btn-small', 'button');
export const FlatButton = ButtonFactory('a', 'waves-effect waves-teal btn-flat', 'button');
export const RoundIconButton = ButtonFactory('button', 'btn-floating btn-large waves-effect waves-light', 'button');
export const SubmitButton = ButtonFactory('button', 'btn waves-effect waves-light', 'submit');
8 changes: 5 additions & 3 deletions packages/lib/src/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export interface ICarouselItem extends Attributes {
href: string;
/** Image source */
src: string;
/** Alternative name */
alt?: string;
}

export interface ICarousel extends Partial<M.CarouselOptions>, Attributes {
Expand All @@ -14,8 +16,8 @@ export interface ICarousel extends Partial<M.CarouselOptions>, Attributes {

export const CarouselItem: FactoryComponent<ICarouselItem> = () => {
return {
view: ({ attrs: { href, src } }) => {
return m('a.carousel-item', { href }, m(`img[src=${src}]`));
view: ({ attrs: { href, src, alt, ...params } }) => {
return m('a.carousel-item', { ...params, href }, m('img', { src, alt }));
},
};
};
Expand All @@ -36,7 +38,7 @@ export const Carousel: FactoryComponent<ICarousel> = () => {
M.Carousel.init(dom, attrs);
},
},
items.map(item => m(CarouselItem, item))
items.map((item) => m(CarouselItem, item))
)
: undefined;
},
Expand Down
91 changes: 57 additions & 34 deletions packages/lib/src/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,66 @@ export interface IChipsOptions extends Partial<M.ChipsOptions>, Attributes {
/** Chips and tags */
export const Chips: FactoryComponent<IChipsOptions> = () => {
return {
oncreate: ({ attrs, dom }) => {
const { onchange, onChipAdd, onChipDelete } = attrs;
const chips = M.Chips.getInstance(dom.children[0]) as M.Chips;
const onChipAddBound = onChipAdd ? (onChipAdd.bind(chips) as (el: Element, chip: Element) => void) : undefined;
attrs.onChipAdd = function (this: M.Chips, el: Element, chip: Element) {
if (onchange) {
onchange(this.chipsData);
}
if (onChipAddBound) {
onChipAddBound(el, chip);
}
};
const onChipDeleteBound = onChipDelete
? (onChipDelete.bind(chips) as (el: Element, chip: Element) => void)
: undefined;
attrs.onChipDelete = function (this: M.Chips, el: Element, chip: Element) {
if (onchange) {
onchange(this.chipsData);
}
if (onChipDeleteBound) {
onChipDeleteBound(el, chip);
}
};
M.Chips.init(dom.children[0], attrs);
},
onupdate: ({ dom, attrs: { data } }) => {
if (!data || data.length === 0) {
return;
}
const chips = M.Chips.getInstance(dom.children[0]) as M.Chips;
data.forEach((d) => chips.addChip(d));
},
view: ({
attrs: { placeholder, required, isMandatory = required, data, className = 'col s12', label, helperText },
attrs: {
placeholder,
required,
isMandatory = required,
// data = [],
className = 'col s12',
label,
helperText,
onchange,
...params
},
}) => {
const cn = [
'chips chips-autocomplete',
placeholder ? 'chips-placeholder' : '',
params.data ? 'chips-initial' : '',
]
.filter(Boolean)
.join(' ')
.trim();
return m('.input-field', { className }, [
m(`.chips.chips-autocomplete${placeholder ? '.chips-placeholder' : ''}${data ? '.chips-initial' : ''}`),
m('div', {
className: cn,
oncreate: ({ dom }) => {
const { onChipAdd, onChipDelete } = params;
const chips = M.Chips.getInstance(dom) as M.Chips;
const onChipAddBound = onChipAdd
? (onChipAdd.bind(chips) as (el: Element, chip: Element) => void)
: undefined;
params.onChipAdd = function (this: M.Chips, el: Element, chip: Element) {
if (onchange) {
onchange(this.chipsData);
}
if (onChipAddBound) {
onChipAddBound(el, chip);
}
};
const onChipDeleteBound = onChipDelete
? (onChipDelete.bind(chips) as (el: Element, chip: Element) => void)
: undefined;
params.onChipDelete = function (this: M.Chips, el: Element, chip: Element) {
if (onchange) {
onchange(this.chipsData);
}
if (onChipDeleteBound) {
onChipDeleteBound(el, chip);
}
};
M.Chips.init(dom, params);
// data.forEach((d) => chips.addChip(d));
},
onupdate: ({ dom }) => {
if (!params.data || params.data.length === 0) {
return;
}
const chips = M.Chips.getInstance(dom);
params.data.forEach((d) => chips.addChip(d));
},
}),
label ? m(Label, { label, isMandatory, className: 'active' }) : undefined,
helperText ? m(HelperText, { helperText }) : undefined,
]);
Expand Down
Loading

0 comments on commit d2baaf1

Please sign in to comment.