Skip to content

Commit

Permalink
add CustomSelect component and fix fonts
Browse files Browse the repository at this point in the history
  • Loading branch information
Ali Sasani Babak committed Aug 14, 2023
1 parent 4793676 commit e52550c
Show file tree
Hide file tree
Showing 7 changed files with 583 additions and 51 deletions.
228 changes: 216 additions & 12 deletions docs/data/base/components/select/UnstyledSelectBasic/tailwind/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { Select } from '@mui/base/Select';
import { Option as BaseOption } from '@mui/base/Option';
import { useTheme } from '@mui/system';
import clsx from 'clsx';

const getOptionColorClasses = ({ selected, highlighted, disabled }) => {
let classes = '';
Expand Down Expand Up @@ -48,26 +50,228 @@ export default function UnstyledSelectBasic() {

return (
<div className={isDarkMode ? 'dark' : ''}>
<Select
<CustomSelect
slotProps={{
root: ({ focusVisible, open }) => ({
className: `text-sm box-border w-80 px-3 py-2 rounded-lg text-left bg-white dark:bg-slate-800 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 transition-all hover:bg-slate-50 dark:hover:bg-slate-700 outline-0 shadow shadow-slate-200 dark:shadow-slate-900 ${
focusVisible ? 'border-purple-400 shadow-outline-purple' : ''
} ${
open ? 'after:content-["▴"]' : 'after:content-["▾"]'
} after:float-right`,
}),
listbox: {
className: `text-sm p-1.5 my-3 w-80 rounded-xl overflow-auto outline-0 bg-white dark:bg-slate-900 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 shadow shadow-slate-200 dark:shadow-slate-900`,
},
popper: { className: `${isDarkMode ? 'dark' : ''} z-10` },
}}
defaultValue={10}
>
<Option value={10}>Ten</Option>
<Option value={20}>Twenty</Option>
<Option value={30}>Thirty</Option>
</Select>
</CustomSelect>
</div>
);
}

const resolveSlotProps = (fn, args) => (typeof fn === 'function' ? fn(args) : fn);

const CustomSelect = React.forwardRef(function CustomSelect(props, ref) {
return (
<Select
ref={ref}
className={clsx('CustomSelect', props.className)}
slotProps={{
...props.slotProps,
root: (ownerState) => {
const resolvedSlotProps = resolveSlotProps(
props.slotProps?.root,
ownerState,
);
return {
...resolvedSlotProps,
className: clsx(
`text-sm box-border w-80 px-3 py-2 rounded-lg text-left bg-white dark:bg-slate-800 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 transition-all hover:bg-slate-50 dark:hover:bg-slate-700 outline-0 shadow shadow-slate-200 dark:shadow-slate-900 ${
ownerState.focusVisible
? 'border-purple-400 shadow-outline-purple'
: ''
} ${
ownerState.open ? 'after:content-["▴"]' : 'after:content-["▾"]'
} after:float-right`,
resolvedSlotProps?.className,
),
};
},
listbox: (ownerState) => {
const resolvedSlotProps = resolveSlotProps(
props.slotProps?.listbox,
ownerState,
);
return {
...resolvedSlotProps,
className: clsx(
`text-sm font-sans p-1.5 my-3 w-80 rounded-xl overflow-auto outline-0 bg-white dark:bg-slate-900 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 shadow shadow-slate-200 dark:shadow-slate-900`,
resolvedSlotProps?.className,
),
};
},
popper: (ownerState) => {
const resolvedSlotProps = resolveSlotProps(
props.slotProps?.popper,
ownerState,
);
return {
...resolvedSlotProps,
className: clsx(resolvedSlotProps?.className),
};
},
}}
{...props}
/>
);
});

CustomSelect.propTypes = {
className: PropTypes.string,
/**
* The props used for each slot inside the Input.
* @default {}
*/
slotProps: PropTypes.shape({
listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
popper: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({
anchorEl: PropTypes.oneOfType([
function (props, propName) {
if (props[propName] == null) {
return new Error(
"Prop '" + propName + "' is required but wasn't specified",
);
} else if (
typeof props[propName] !== 'object' ||
props[propName].nodeType !== 1
) {
return new Error(
"Expected prop '" + propName + "' to be of type Element",
);
}
},
PropTypes.func,
PropTypes.shape({
contextElement: function (props, propName) {
if (props[propName] == null) {
return null;
} else if (
typeof props[propName] !== 'object' ||
props[propName].nodeType !== 1
) {
return new Error(
"Expected prop '" + propName + "' to be of type Element",
);
}
},
getBoundingClientRect: PropTypes.func.isRequired,
}),
]),
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.func,
PropTypes.number,
PropTypes.shape({
'__@iterator@62': PropTypes.func.isRequired,
}),
PropTypes.string,
PropTypes.bool,
]),
container: PropTypes.oneOfType([
function (props, propName) {
if (props[propName] == null) {
return new Error(
"Prop '" + propName + "' is required but wasn't specified",
);
} else if (
typeof props[propName] !== 'object' ||
props[propName].nodeType !== 1
) {
return new Error(
"Expected prop '" + propName + "' to be of type Element",
);
}
},
PropTypes.func,
]),
direction: PropTypes.oneOf(['ltr', 'rtl']),
disablePortal: PropTypes.bool,
keepMounted: PropTypes.bool,
modifiers: PropTypes.arrayOf(
PropTypes.shape({
data: PropTypes.object,
effect: PropTypes.func,
enabled: PropTypes.bool,
fn: PropTypes.func,
name: PropTypes.any,
options: PropTypes.object,
phase: PropTypes.oneOf([
'afterMain',
'afterRead',
'afterWrite',
'beforeMain',
'beforeRead',
'beforeWrite',
'main',
'read',
'write',
]),
requires: PropTypes.arrayOf(PropTypes.string),
requiresIfExists: PropTypes.arrayOf(PropTypes.string),
}),
),
open: PropTypes.bool,
placement: PropTypes.oneOf([
'auto-end',
'auto-start',
'auto',
'bottom-end',
'bottom-start',
'bottom',
'left-end',
'left-start',
'left',
'right-end',
'right-start',
'right',
'top-end',
'top-start',
'top',
]),
popperOptions: PropTypes.shape({
modifiers: PropTypes.array,
onFirstUpdate: PropTypes.func,
placement: PropTypes.oneOf([
'auto-end',
'auto-start',
'auto',
'bottom-end',
'bottom-start',
'bottom',
'left-end',
'left-start',
'left',
'right-end',
'right-start',
'right',
'top-end',
'top-start',
'top',
]),
strategy: PropTypes.oneOf(['absolute', 'fixed']),
}),
popperRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.shape({
current: PropTypes.object,
}),
]),
slotProps: PropTypes.shape({
root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
}),
slots: PropTypes.shape({
root: PropTypes.elementType,
}),
transition: PropTypes.bool,
}),
]),
root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
}),
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as React from 'react';
import { Select } from '@mui/base/Select';
import { Select, SelectProps } from '@mui/base/Select';
import {
Option as BaseOption,
OptionProps,
OptionOwnerState,
} from '@mui/base/Option';
import { useTheme } from '@mui/system';
import clsx from 'clsx';

const getOptionColorClasses = ({
selected,
Expand Down Expand Up @@ -56,26 +57,77 @@ export default function UnstyledSelectBasic() {

return (
<div className={isDarkMode ? 'dark' : ''}>
<Select
<CustomSelect
slotProps={{
root: ({ focusVisible, open }) => ({
className: `text-sm box-border w-80 px-3 py-2 rounded-lg text-left bg-white dark:bg-slate-800 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 transition-all hover:bg-slate-50 dark:hover:bg-slate-700 outline-0 shadow shadow-slate-200 dark:shadow-slate-900 ${
focusVisible ? 'border-purple-400 shadow-outline-purple' : ''
} ${
open ? 'after:content-["▴"]' : 'after:content-["▾"]'
} after:float-right`,
}),
listbox: {
className: `text-sm p-1.5 my-3 w-80 rounded-xl overflow-auto outline-0 bg-white dark:bg-slate-900 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 shadow shadow-slate-200 dark:shadow-slate-900`,
},
popper: { className: `${isDarkMode ? 'dark' : ''} z-10` },
}}
defaultValue={10}
>
<Option value={10}>Ten</Option>
<Option value={20}>Twenty</Option>
<Option value={30}>Thirty</Option>
</Select>
</CustomSelect>
</div>
);
}

const resolveSlotProps = (fn: any, args: any) =>
typeof fn === 'function' ? fn(args) : fn;

const CustomSelect = React.forwardRef(function CustomSelect<
TValue extends {},
Multiple extends boolean,
>(props: SelectProps<TValue, Multiple>, ref: React.ForwardedRef<HTMLButtonElement>) {
return (
<Select
ref={ref}
className={clsx('CustomSelect', props.className)}
slotProps={{
...props.slotProps,
root: (ownerState) => {
const resolvedSlotProps = resolveSlotProps(
props.slotProps?.root,
ownerState,
);
return {
...resolvedSlotProps,
className: clsx(
`text-sm box-border w-80 px-3 py-2 rounded-lg text-left bg-white dark:bg-slate-800 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 transition-all hover:bg-slate-50 dark:hover:bg-slate-700 outline-0 shadow shadow-slate-200 dark:shadow-slate-900 ${
ownerState.focusVisible
? 'border-purple-400 shadow-outline-purple'
: ''
} ${
ownerState.open ? 'after:content-["▴"]' : 'after:content-["▾"]'
} after:float-right`,
resolvedSlotProps?.className,
),
};
},
listbox: (ownerState) => {
const resolvedSlotProps = resolveSlotProps(
props.slotProps?.listbox,
ownerState,
);
return {
...resolvedSlotProps,
className: clsx(
`text-sm font-sans p-1.5 my-3 w-80 rounded-xl overflow-auto outline-0 bg-white dark:bg-slate-900 border border-solid border-slate-200 dark:border-slate-700 text-slate-900 dark:text-slate-300 shadow shadow-slate-200 dark:shadow-slate-900`,
resolvedSlotProps?.className,
),
};
},
popper: (ownerState) => {
const resolvedSlotProps = resolveSlotProps(
props.slotProps?.popper,
ownerState,
);
return {
...resolvedSlotProps,
className: clsx(resolvedSlotProps?.className),
};
},
}}
{...props}
/>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<CustomSelect
slotProps={{
popper: { className: `${isDarkMode ? 'dark' : ''} z-10` },
}}
defaultValue={10}
>
<Option value={10}>Ten</Option>
<Option value={20}>Twenty</Option>
<Option value={30}>Thirty</Option>
</CustomSelect>
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ function Styles() {
border: 1px solid ${isDarkMode ? grey[700] : grey[200]};
color: ${isDarkMode ? grey[300] : grey[900]};
position: relative;
box-shadow: 0px 2px 24px ${isDarkMode ? cyan[900] : cyan[100]};
box-shadow: 0px 2px 24px ${isDarkMode ? cyan[800] : cyan[100]};
transition-property: all;
Expand Down
Loading

0 comments on commit e52550c

Please sign in to comment.