diff --git a/src/components/Box.tsx b/src/components/Box.tsx index 972f24e..b5acbbe 100644 --- a/src/components/Box.tsx +++ b/src/components/Box.tsx @@ -1,7 +1,8 @@ import React, { CSSProperties, ReactNode } from 'react'; import styled from '@emotion/styled'; +import { AriaProps } from '../types/aria'; -export type BoxProps = { +export type BoxProps = AriaProps & { style?: CSSProperties; children?: ReactNode; display?: 'flex' | 'block' | 'inline-block' | 'inline' | 'grid' | 'inline-grid' | 'contents' | 'list-item' | 'hidden' | 'initial' | 'inherit'; diff --git a/src/components/Button.tsx b/src/components/Button.tsx index d464927..77c4f71 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -5,6 +5,7 @@ import { MdElevatedButton as MdElevatedButtonWebComponent } from '@material/web/ import { MdOutlinedButton as MdOutlinedButtonWebComponent } from '@material/web/button/outlined-button'; import { MdTextButton as MdTextButtonWebComponent } from '@material/web/button/text-button'; import React from 'react'; +import { AriaProps } from '../types/aria'; const MdFilledButton = createComponent({ tagName: 'md-filled-button', @@ -36,7 +37,7 @@ const MdTextButton = createComponent({ react: React, }); -type ButtonProps = { +type ButtonProps = AriaProps & { variant?: 'filled' | 'filled-tonal' | 'elevated' | 'outlined' | 'text'; children: React.ReactNode; disabled?: boolean; diff --git a/src/components/Checkbox.tsx b/src/components/Checkbox.tsx index ed421a7..0201ecb 100644 --- a/src/components/Checkbox.tsx +++ b/src/components/Checkbox.tsx @@ -1,6 +1,7 @@ import React, { FormEvent, MouseEvent, FocusEvent } from "react"; import { createComponent } from "@lit/react"; import { MdCheckbox as MdCheckboxWebComponent } from "@material/web/checkbox/checkbox"; +import { AriaProps } from '../types/aria'; const MdCheckbox = createComponent({ tagName: "md-checkbox", @@ -8,7 +9,7 @@ const MdCheckbox = createComponent({ elementClass: MdCheckboxWebComponent, }); -type CheckboxProps = { +type CheckboxProps = AriaProps & { checked?: boolean; indeterminate?: boolean; id?: string; diff --git a/src/components/Chip.tsx b/src/components/Chip.tsx index 10a528e..4c28a2a 100644 --- a/src/components/Chip.tsx +++ b/src/components/Chip.tsx @@ -4,6 +4,7 @@ import { MdChipSet as MdChipSetWebComponent } from "@material/web/chips/chip-set import { MdFilterChip as MdFilterChipWebComponent } from "@material/web/chips/filter-chip"; import { MdInputChip as MdInputChipWebComponent } from "@material/web/chips/input-chip"; import { createComponent } from "@lit/react"; +import { AriaProps } from '../types/aria'; const MdChipSet = createComponent({ react: React, @@ -11,7 +12,7 @@ const MdChipSet = createComponent({ elementClass: MdChipSetWebComponent, }); -type ChipSetProps = { +type ChipSetProps = AriaProps & { children: React.ReactNode; }; @@ -23,15 +24,6 @@ export const ChipSet = (props: ChipSetProps) => { ); }; -type AssistChipProps = { - label?: string; - elevated?: boolean; - href?: string; - target?: '_blank' | '_parent' | '_self' | '_top'; - disabled?: boolean; - alwaysFocusable?: boolean; -}; - const MdAssistChip = createComponent({ react: React, tagName: 'md-assist-chip', @@ -44,21 +36,20 @@ const MdAssistChip = createComponent({ }, }); +type AssistChipProps = AriaProps & { + label?: string; + elevated?: boolean; + href?: string; + target?: '_blank' | '_parent' | '_self' | '_top'; + disabled?: boolean; + alwaysFocusable?: boolean; +}; + export const AssistChip = (props: AssistChipProps) => { const { label, elevated, href, target, disabled, alwaysFocusable } = props; return ; }; -type FilterChipProps = { - elevated?: boolean; - removable?: boolean; - selected?: boolean; - hasSelectedIcon?: boolean; - disabled?: boolean; - alwaysFocusable?: boolean; - label: string; -}; - const MdFilterChip = createComponent({ react: React, tagName: 'md-filter-chip', @@ -69,22 +60,21 @@ const MdFilterChip = createComponent({ }, }); -export const FilterChip = (props: FilterChipProps) => { - const { label, elevated, removable, selected, hasSelectedIcon, disabled, alwaysFocusable } = props; - return ; -}; - -type InputChipProps = { - avatar?: boolean; - href?: string; - target?: '_blank' | '_parent' | '_self' | '_top'; - removeOnly?: boolean; +type FilterChipProps = AriaProps & { + elevated?: boolean; + removable?: boolean; selected?: boolean; + hasSelectedIcon?: boolean; disabled?: boolean; alwaysFocusable?: boolean; label: string; }; +export const FilterChip = (props: FilterChipProps) => { + const { label, elevated, removable, selected, hasSelectedIcon, disabled, alwaysFocusable } = props; + return ; +}; + const MdInputChip = createComponent({ react: React, tagName: 'md-input-chip', @@ -95,6 +85,17 @@ const MdInputChip = createComponent({ }, }); +type InputChipProps = AriaProps & { + avatar?: boolean; + href?: string; + target?: '_blank' | '_parent' | '_self' | '_top'; + removeOnly?: boolean; + selected?: boolean; + disabled?: boolean; + alwaysFocusable?: boolean; + label: string; +}; + export const InputChip = (props: InputChipProps) => { const { label, avatar, href, target, removeOnly, selected, disabled, alwaysFocusable } = props; return ; diff --git a/src/components/CircularProgress.tsx b/src/components/CircularProgress.tsx new file mode 100644 index 0000000..08304e5 --- /dev/null +++ b/src/components/CircularProgress.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import { createComponent } from '@lit/react'; +import { MdCircularProgress as MdCircularProgressWebComponent } from '@material/web/progress/circular-progress'; +import { MdLinearProgress as MdLinearProgressWebComponent } from '@material/web/progress/linear-progress'; + +const MdCircularProgress = createComponent({ + react: React, + tagName: 'md-circular-progress', + elementClass: MdCircularProgressWebComponent, +}); + +const MdLinearProgress = createComponent({ + react: React, + tagName: 'md-linear-progress', + elementClass: MdLinearProgressWebComponent, +}); + +type CircularProgressProps = { + value?: number; + max?: number; + fourColor?: boolean; + className?: string; + style?: React.CSSProperties; + id?: string; + + color?: string; + size?: string; +}; + +export const CircularProgress = (props: CircularProgressProps) => { + const { + value, + max, + fourColor, + className, + style, + id, + color, + size, + ...rest + } = props; + return ( + + ); +}; + +type LinearProgressProps = { + buffer?: number; + value?: number; + max?: number; + fourColor?: boolean; + className?: string; + style?: React.CSSProperties; + id?: string; + color?: string; + size?: string; +}; + +export const LinearProgress = (props: LinearProgressProps) => { + const { + buffer, + value, + max, + fourColor, + className, + style, + id, + color, + size, + ...rest + } = props; + return ( + + ); +}; diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx index de5f74d..5758c10 100644 --- a/src/components/Dialog.tsx +++ b/src/components/Dialog.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { createComponent } from '@lit/react'; import { MdDialog as MdDialogWebComponent } from '@material/web/dialog/dialog'; +import { AriaProps } from '../types/aria'; const MdDialog = createComponent({ react: React, @@ -16,7 +17,7 @@ const MdDialog = createComponent({ }, }); -type DialogProps = { +type DialogProps = AriaProps & { children: React.ReactNode; quick?: boolean; returnValue?: string; @@ -65,7 +66,7 @@ export const Dialog = (props: DialogProps) => { ); }; -type DialogTitleProps = { +type DialogTitleProps = AriaProps & { children: React.ReactNode; style?: React.CSSProperties; className?: string; @@ -80,7 +81,7 @@ export const DialogTitle = (props: DialogTitleProps) => { ); }; -type DialogContentProps = { +type DialogContentProps = AriaProps & { children: React.ReactNode; style?: React.CSSProperties; className?: string; @@ -95,7 +96,7 @@ export const DialogContent = (props: DialogContentProps) => { ); }; -type DialogActionsProps = { +type DialogActionsProps = AriaProps & { children: React.ReactNode; style?: React.CSSProperties; className?: string; diff --git a/src/components/Dropdown.tsx b/src/components/Dropdown.tsx new file mode 100644 index 0000000..e7de1a2 --- /dev/null +++ b/src/components/Dropdown.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { createComponent } from '@lit/react'; +import { MdFilledSelect as MdFilledSelectWebComponent } from '@material/web/select/filled-select'; +import { MdOutlinedSelect as MdOutlinedSelectWebComponent } from '@material/web/select/outlined-select'; +import {MdSelectOption as MdSelectOptionWebComponent} from '@material/web/select/select-option'; + +const MdFilledSelect = createComponent({ + tagName: 'md-select', + react: React, + elementClass: MdFilledSelectWebComponent, +}); + +const MdOutlinedSelect = createComponent({ + tagName: 'md-select', + react: React, + elementClass: MdOutlinedSelectWebComponent, +}); + +const MdSelectOption = createComponent({ + tagName: 'md-select-option', + react: React, + elementClass: MdSelectOptionWebComponent, +}); + +type SelectProps = { + variant?: 'filled' | 'outlined'; + quick?: boolean; + required?: boolean; + errorText?: string; + label?: string; + noAsterisk?: boolean; + supportingText?: string; + error?: boolean; + menuPositioning?: 'popover' | 'fixed' | 'absolute'; + clampMenuWidth?: boolean; + typeaheadDelay?: number; + menuAlign?: 'start' | 'end'; + value?: string; + selectedIndex?: number; + disabled?: boolean; + name?: string; + ariaLabel?: string; + className?: string; + style?: React.CSSProperties; + children?: React.ReactNode; +}; + +export const Select = (props: SelectProps) => { + const { variant = 'filled', ...rest } = props; + + const SelectComponent = variant === 'filled' ? MdFilledSelect : MdOutlinedSelect; + + return ; +}; \ No newline at end of file diff --git a/src/components/FloatingActionButton.tsx b/src/components/FloatingActionButton.tsx index 53e1767..1e9cfa5 100644 --- a/src/components/FloatingActionButton.tsx +++ b/src/components/FloatingActionButton.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { createComponent } from '@lit/react'; import { MdFab as MdFabWebComponent } from '@material/web/fab/fab'; import { MdBrandedFab as MdBrandedFabWebComponent } from '@material/web/fab/branded-fab'; +import { AriaProps } from '../types/aria'; const MdFab = createComponent({ react: React, @@ -9,11 +10,10 @@ const MdFab = createComponent({ elementClass: MdFabWebComponent, }); -type FABProps = { +type FABProps = AriaProps & { children: React.ReactNode; className?: string; id?: string; - ariaLabel?: string; variant?: 'surface' | 'primary' | 'secondary' | 'tertiary'; size?: 'medium' | 'large'; label?: string; @@ -41,11 +41,10 @@ const MdBrandedFab = createComponent({ elementClass: MdBrandedFabWebComponent, }); -type BrandedFABProps = { +type BrandedFABProps = AriaProps & { children: React.ReactNode; className?: string; id?: string; - ariaLabel?: string; variant?: 'surface' | 'primary' | 'secondary' | 'tertiary'; size?: 'medium' | 'large'; label?: string; diff --git a/src/components/Forms.tsx b/src/components/Forms.tsx index 44ebab0..8549384 100644 --- a/src/components/Forms.tsx +++ b/src/components/Forms.tsx @@ -16,6 +16,7 @@ export const FormLabel = (props: LabelHTMLAttributes) => { alignItems: 'center', gap: '8px', ...props.style, + fontFamily: 'var(--md-ref-typeface-plain)', }} />; }; \ No newline at end of file diff --git a/src/components/IconButton.tsx b/src/components/IconButton.tsx index 8983403..5b264a8 100644 --- a/src/components/IconButton.tsx +++ b/src/components/IconButton.tsx @@ -4,6 +4,7 @@ import { MdIconButton as MdIconButtonWebComponent } from "@material/web/iconbutt import { MdFilledIconButton as MdFilledIconButtonWebComponent } from "@material/web/iconbutton/filled-icon-button"; import { MdOutlinedIconButton as MdOutlinedIconButtonWebComponent } from "@material/web/iconbutton/outlined-icon-button"; import { MdFilledTonalIconButton as MdFilledTonalIconButtonWebComponent } from "@material/web/iconbutton/filled-tonal-icon-button"; +import { AriaProps } from '../types/aria'; const MdIconButton = createComponent({ react: React, @@ -49,7 +50,7 @@ const MdFilledTonalIconButton = createComponent({ }, }); -type IconButtonProps = { +type IconButtonProps = AriaProps & { variant?: 'filled' | 'outlined' | 'filled-tonal' | 'standard'; disabled?: boolean; flipIconInRtl?: boolean; diff --git a/src/components/List.tsx b/src/components/List.tsx index 4ea9360..5f41add 100644 --- a/src/components/List.tsx +++ b/src/components/List.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { createComponent } from '@lit/react'; import { MdList as MdListWebComponent } from '@material/web/list/list'; import { MdListItem as MdListItemWebComponent } from '@material/web/list/list-item'; +import { AriaProps } from '../types/aria'; const MdList = createComponent({ react: React, @@ -9,7 +10,7 @@ const MdList = createComponent({ elementClass: MdListWebComponent, }); -type ListProps = { +type ListProps = AriaProps & { children: React.ReactNode; } @@ -29,11 +30,10 @@ const MdListItem = createComponent({ elementClass: MdListItemWebComponent, }); -type ListItemProps = { +type ListItemProps = AriaProps & { children: React.ReactNode; className?: string; id?: string; - ariaLabel?: string; disabled?: boolean; type?: 'text' | 'link' | 'button'; href?: string; diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx new file mode 100644 index 0000000..e264dc2 --- /dev/null +++ b/src/components/Menu.tsx @@ -0,0 +1,91 @@ +import React from 'react'; +import { createComponent } from '@lit/react'; +import { MdMenu as MdMenuWebComponent } from '@material/web/menu/menu'; +import { MdMenuItem as MdMenuItemWebComponent } from '@material/web/menu/menu-item'; +import { MdSubMenu as MdSubMenuWebComponent } from '@material/web/menu/sub-menu'; +const MdMenu = createComponent({ + react: React, + tagName: 'md-menu', + elementClass: MdMenuWebComponent, +}); + +const MdMenuItem = createComponent({ + react: React, + tagName: 'md-menu-item', + elementClass: MdMenuItemWebComponent, + events: { + 'close-menu': 'onCloseMenu' + } +}); + +const MdSubMenu = createComponent({ + react: React, + tagName: 'md-sub-menu', + elementClass: MdSubMenuWebComponent, +}); + +type MenuProps = { + anchorEl?: HTMLElement | string; + positioning?: 'popover' | 'fixed' | 'absolute' | 'document'; + quick?: boolean; + hasOverflow?: boolean; + open?: boolean; + xOffset?: number; + yOffset?: number; + anchorCorner?: 'start-start' | 'start-end' | 'end-start' | 'end-end'; + menuCorner?: 'start-start' | 'start-end' | 'end-start' | 'end-end'; + noHorizontalFlip?: boolean; + noVerticalFlip?: boolean; + stayOpenOnOutsideClick?: boolean; + stayOpenOnFocusout?: boolean; + skipRestoreFocus?: boolean; + noNavigationWrap?: boolean; + className?: string; + style?: React.CSSProperties; + children?: React.ReactNode; + id?: string; +}; + +export const Menu = (props: MenuProps) => { + return ( + + ); +}; + +type SubMenuProps = { + children?: React.ReactNode; + className?: string; + style?: React.CSSProperties; + id?: string; + anchorCorner?: 'start-start' | 'start-end' | 'end-start' | 'end-end'; + menuCorner?: 'start-start' | 'start-end' | 'end-start' | 'end-end'; + hoverOpenDelay?: number; + hoverCloseDelay?: number; +}; + +export const SubMenu = (props: SubMenuProps) => { + return ( + + ); +}; + +type MenuItemProps = { + children?: React.ReactNode; + className?: string; + style?: React.CSSProperties; + id?: string; + disabled?: boolean; + href?: string; + target?: '_blank' | '_parent' | '_self' | '_top'; + keepOpen?: boolean; + selected?: boolean; + onCloseMenu?: () => void; +}; + +export const MenuItem = (props: MenuItemProps) => { + return ; +}; \ No newline at end of file diff --git a/src/components/RadioButton.tsx b/src/components/RadioButton.tsx new file mode 100644 index 0000000..62c407d --- /dev/null +++ b/src/components/RadioButton.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { createComponent } from '@lit/react'; +import { MdRadio as MdRadioWebComponent } from '@material/web/radio/radio'; +import { AriaProps } from '../types/aria'; + +const MdRadio = createComponent({ + react: React, + tagName: 'md-radio', + elementClass: MdRadioWebComponent, +}); + +type RadioProps = AriaProps & { + checked?: boolean; + value?: string; + required?: boolean; + disabled?: boolean; + name?: string; + ariaLabel?: string; + className?: string; + style?: React.CSSProperties; + id?: string; + + iconColor?: string; + selectedIconColor?: string; + iconSize?: string; +}; + +export const Radio = (props: RadioProps) => { + const { + checked, + value, + required, + disabled, + name, + ariaLabel, + className, + style, + id, + iconColor, + selectedIconColor, + iconSize, + ...rest + } = props; + return ( + + ); +}; diff --git a/src/components/Slider.tsx b/src/components/Slider.tsx new file mode 100644 index 0000000..1b06646 --- /dev/null +++ b/src/components/Slider.tsx @@ -0,0 +1,60 @@ +import React, { FormEvent } from 'react'; +import { createComponent } from "@lit/react"; +import { MdSlider as MdSliderWebComponent } from '@material/web/slider/slider'; +import { AriaProps } from '../types/aria'; + +const MdSlider = createComponent({ + react: React, + elementClass: MdSliderWebComponent, + tagName: 'md-slider' +}); + +type SliderProps = AriaProps & { + className?: string; + id?: string; + style?: React.CSSProperties; + + min?: number; + max?: number; + value?: number; + valueStart?: number; + valueEnd?: number; + valueLabel?: string; + valueLabelStart?: string; + valueLabelEnd?: string; + ariaLabelStart?: string; + ariaLabelTextStart?: string; + ariaLabelEnd?: string; + ariaLabelTextEnd?: string; + ariaLabel?: string; + step?: number; + ticks?: boolean; + labeled?: boolean; + range?: boolean; + disabled?: boolean; + name?: string; + nameStart?: string; + nameEnd?: string; + onChange?: (e: FormEvent) => void; + onInput?: (e: FormEvent) => void; + marks?: boolean; + discrete?: boolean; + withTickMarks?: boolean; + withTicks?: boolean; +}; + +export const Slider = ({ + className, + id, + style, + ...rest +}: SliderProps) => { + return ( + + ); +} \ No newline at end of file diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index 41dcb27..9829abe 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -1,6 +1,7 @@ import React, { FormEvent, MouseEvent, FocusEvent } from "react"; import { createComponent } from "@lit/react"; import { MdSwitch as MdSwitchWebComponent } from "@material/web/switch/switch"; +import { AriaProps } from '../types/aria'; const MdSwitch = createComponent({ tagName: "md-switch", @@ -8,7 +9,7 @@ const MdSwitch = createComponent({ elementClass: MdSwitchWebComponent, }); -type SwitchProps = { +type SwitchProps = AriaProps & { checked?: boolean; id?: string; disabled?: boolean; diff --git a/src/components/Tabs.tsx b/src/components/Tabs.tsx new file mode 100644 index 0000000..61376c8 --- /dev/null +++ b/src/components/Tabs.tsx @@ -0,0 +1,55 @@ +import React, { MouseEvent, FormEvent } from 'react'; +import { createComponent } from '@lit/react'; +import { MdTabs as MdTabsWebComponent } from '@material/web/tabs/tabs'; +import { MdPrimaryTab as MdPrimaryTabWebComponent } from '@material/web/tabs/primary-tab'; +import { MdSecondaryTab as MdSecondaryTabWebComponent } from '@material/web/tabs/secondary-tab'; +import { AriaProps } from '../types/aria'; + +const MdTabs = createComponent({ + react: React, + tagName: 'md-tabs', + elementClass: MdTabsWebComponent, +}); + +type TabsProps = AriaProps & { + children: React.ReactNode; + className?: string; + style?: React.CSSProperties; + id?: string; + activeTabIndex?: number; + onChange?: (e: FormEvent) => void; +}; + +const MdPrimaryTab = createComponent({ + react: React, + tagName: 'md-primary-tab', + elementClass: MdPrimaryTabWebComponent, +}); + +const MdSecondaryTab = createComponent({ + react: React, + tagName: 'md-secondary-tab', + elementClass: MdSecondaryTabWebComponent, +}); + +type TabProps = AriaProps & { + children: React.ReactNode; + className?: string; + style?: React.CSSProperties; + id?: string; + selected?: boolean; + variant?: 'primary' | 'secondary'; + onClick?: (e: MouseEvent) => void; +}; + +export const Tabs = (props: TabsProps) => { + const { children, className, style, id, activeTabIndex, onChange, ...ariaProps } = props; + return {children}; +}; + +export const Tab = (props: TabProps) => { + const { children, className, style, id, selected, variant = 'primary', onClick, ...ariaProps } = props; + const TabComponent = variant === 'primary' ? MdPrimaryTab : MdSecondaryTab; + return {children}; +}; + diff --git a/src/components/Typography.tsx b/src/components/Typography.tsx index 6bf7aac..9ca1d6a 100644 --- a/src/components/Typography.tsx +++ b/src/components/Typography.tsx @@ -1,7 +1,8 @@ import React, { useMemo } from "react"; import '../../fonts/roboto.css'; +import { AriaProps } from '../types/aria'; -type TypographyProps = { +type TypographyProps = AriaProps & { children: React.ReactNode; variant?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "label"; className?: string; @@ -11,9 +12,10 @@ type TypographyProps = { noWrap?: boolean; id?: string; size?: "small" | "medium" | "large" | "auto"; + htmlFor?: string; }; -export const Typography = ({ children, variant = "span", className, color = "", align, style, noWrap, id, size = "auto" }: TypographyProps) => { +export const Typography = ({ children, variant = "span", className, color = "", align, style, noWrap, id, size = "auto", htmlFor }: TypographyProps) => { const clr = useMemo(() => { if (color === 'primary') return 'var(--md-sys-color-primary)'; if (color === 'secondary') return 'var(--md-sys-color-secondary)'; @@ -205,7 +207,7 @@ export const Typography = ({ children, variant = "span", className, color = "", if (variant === "label") { return ( -