@junyiacademy/ui-test 1.5.16 → 1.6.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/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { default as TopicFilter } from './lib/topic-filter/TopicFilter';
2
+ export { default as SelectMenuItem } from './lib/menu-item/SelectMenuItem';
3
+ export { default as Button } from './lib/button/Button';
4
+ export { default as ButtonGroup } from './lib/button-group/ButtonGroup';
5
+ export { default as Radio } from './lib/radio/Radio';
6
+ export { default as TextField } from './lib/text-field/TextField';
7
+ export { default as Select } from './lib/select/Select';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { styled, alpha } from '@mui/material/styles';
14
+ import { Button as MuiButton, } from '@mui/material';
15
+ import { buttonClasses } from '@mui/material/Button';
16
+ // utils
17
+ import capitalize from '../../utils/Capitalize';
18
+ const StyledButton = styled(MuiButton, {
19
+ shouldForwardProp: (prop) => prop !== 'active',
20
+ })(({ active, color = 'primary', theme }) => ({
21
+ // For variant: outlined
22
+ [`&.${buttonClasses.outlined}${capitalize(color)}`]: {
23
+ backgroundColor: active
24
+ ? theme.palette[color].main
25
+ : theme.palette.common.white,
26
+ color: active ? theme.palette.common.white : theme.palette[color].main,
27
+ borderColor: theme.palette[color].main,
28
+ '&:hover': {
29
+ backgroundColor: active
30
+ ? theme.palette[color].main
31
+ : alpha(theme.palette[color].main, 0.1),
32
+ },
33
+ [`&.${buttonClasses.disabled}`]: {
34
+ backgroundColor: theme.palette.common.white,
35
+ borderColor: theme.palette.action.disabledBackground,
36
+ color: theme.palette.action.disabled,
37
+ },
38
+ },
39
+ // For variant: text
40
+ [`&.${buttonClasses.text}${capitalize(color)}`]: {
41
+ '&:hover': {
42
+ backgroundColor: alpha(theme.palette[color].main, 0.1),
43
+ },
44
+ },
45
+ }));
46
+ export const Button = (_a) => {
47
+ var { active, children } = _a, otherProps = __rest(_a, ["active", "children"]);
48
+ return (React.createElement(StyledButton, Object.assign({ active: active }, otherProps), children));
49
+ };
50
+ export default Button;
@@ -0,0 +1,29 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { styled, alpha } from '@mui/material/styles';
14
+ import { ButtonGroup as MuiButtonGroup, } from '@mui/material';
15
+ import { buttonGroupClasses } from '@mui/material/ButtonGroup';
16
+ // utils
17
+ import capitalize from '../../utils/Capitalize';
18
+ // self-defined-components
19
+ const StyledButtonGroup = styled(MuiButtonGroup)(({ color = 'primary', theme }) => ({
20
+ [`& .${buttonGroupClasses.groupedOutlined}${capitalize(color)}.${buttonGroupClasses.grouped}.${buttonGroupClasses.disabled}`]: {
21
+ borderColor: alpha(theme.palette[color].main, 0.5),
22
+ color: alpha(theme.palette[color].main, 0.5),
23
+ },
24
+ }));
25
+ export const ButtonGroup = (_a) => {
26
+ var { children } = _a, otherProps = __rest(_a, ["children"]);
27
+ return (React.createElement(StyledButtonGroup, Object.assign({}, otherProps), children));
28
+ };
29
+ export default ButtonGroup;
@@ -0,0 +1,32 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { MenuItem } from '@mui/material';
14
+ import { menuItemClasses } from '@mui/material/MenuItem';
15
+ const SelectMenuItem = (_a) => {
16
+ var { children, value = '' } = _a, otherProps = __rest(_a, ["children", "value"]);
17
+ const { sx: menuItemSx } = otherProps, otherMenuItemProps = __rest(otherProps, ["sx"]);
18
+ return (React.createElement(MenuItem, Object.assign({ sx: [
19
+ (theme) => ({
20
+ whiteSpace: 'unset',
21
+ color: theme.palette.text.primary,
22
+ [`&.${menuItemClasses.selected}`]: {
23
+ backgroundColor: theme.palette.grey[300],
24
+ '&:hover': {
25
+ backgroundColor: theme.palette.grey[200],
26
+ },
27
+ },
28
+ }),
29
+ ...(Array.isArray(menuItemSx) ? menuItemSx : [menuItemSx]),
30
+ ], value: value }, otherMenuItemProps), children));
31
+ };
32
+ export default SelectMenuItem;
@@ -0,0 +1,47 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { styled } from '@mui/material/styles';
14
+ import { Radio as MuiRadio, FormControlLabel, Typography, } from '@mui/material';
15
+ import { formControlLabelClasses } from '@mui/material/FormControlLabel';
16
+ import { radioClasses } from '@mui/material/Radio';
17
+ // self-defined-components
18
+ const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
19
+ [`& .${formControlLabelClasses.label}`]: {
20
+ color: theme.palette.text.secondary,
21
+ [`&.${formControlLabelClasses.disabled}`]: {
22
+ color: theme.palette.text.disabled,
23
+ },
24
+ },
25
+ [`& .${radioClasses.checked} + .${formControlLabelClasses.label}`]: {
26
+ color: theme.palette.text.primary,
27
+ },
28
+ }));
29
+ export const Radio = ({ checked, disabled, label, labelPlacement, value, FormControlLabelProps = {}, RadioProps = {}, TypographyProps = {}, color = 'secondary', size = 'medium', caption = '', }) => {
30
+ const { sx: radioSx = [] } = RadioProps, otherRadioProps = __rest(RadioProps, ["sx"]);
31
+ const { sx: typographySx = [] } = TypographyProps, otherTypographyProps = __rest(TypographyProps, ["sx"]);
32
+ return (React.createElement(React.Fragment, null,
33
+ React.createElement(StyledFormControlLabel, Object.assign({ control: React.createElement(MuiRadio, Object.assign({ sx: [
34
+ (theme) => ({
35
+ color: theme.palette.text.primary,
36
+ }),
37
+ ...(Array.isArray(radioSx) ? radioSx : [radioSx]),
38
+ ], color: color, size: size }, otherRadioProps)), checked: checked, disabled: disabled, label: label, labelPlacement: labelPlacement, value: value }, FormControlLabelProps)),
39
+ caption && (React.createElement(Typography, Object.assign({ sx: [
40
+ (theme) => ({
41
+ color: theme.palette.text.disabled,
42
+ margin: '0 0 0 30px',
43
+ }),
44
+ ...(Array.isArray(typographySx) ? typographySx : [typographySx]),
45
+ ], variant: "body2" }, otherTypographyProps), caption))));
46
+ };
47
+ export default Radio;
@@ -0,0 +1,95 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { styled } from '@mui/material/styles';
14
+ import { InputLabel, FormControl, Select, OutlinedInput, FormHelperText, } from '@mui/material';
15
+ import { formHelperTextClasses } from '@mui/material/FormHelperText';
16
+ import { inputLabelClasses } from '@mui/material/InputLabel';
17
+ import { outlinedInputClasses } from '@mui/material/OutlinedInput';
18
+ import { inputBaseClasses } from '@mui/material/InputBase';
19
+ const StyledInputLabel = styled(InputLabel, {
20
+ shouldForwardProp: (prop) => prop !== 'color',
21
+ })(({ color, theme }) => ({
22
+ color: theme.palette.text.secondary,
23
+ [`&.${inputLabelClasses.outlined}`]: {
24
+ [`&:not(.${inputLabelClasses.disabled}) .${inputLabelClasses.focused}`]: {
25
+ color: theme.palette.action.active,
26
+ },
27
+ [`&.${inputLabelClasses.sizeSmall}:not(.${inputLabelClasses.shrink})`]: {
28
+ transform: 'translate(12px, 12px) scale(1)',
29
+ },
30
+ },
31
+ // eslint-disable-next-line
32
+ [`&.${inputLabelClasses.shrink}:not(.${inputLabelClasses.error}):not(.${inputLabelClasses.disabled}).${inputLabelClasses.focused}`]: {
33
+ color: theme.palette[color].main,
34
+ },
35
+ [`&.${inputLabelClasses.shrink}`]: {
36
+ backgroundColor: '#ffffff',
37
+ padding: '0 2px',
38
+ },
39
+ }));
40
+ const StyledOutlinedInput = styled(OutlinedInput)(({ theme }) => ({
41
+ [`&.${outlinedInputClasses.root}`]: {
42
+ [`&.${outlinedInputClasses.error}.${outlinedInputClasses.focused} .${outlinedInputClasses.notchedOutline}`]: {
43
+ borderColor: `${theme.palette.error.main}`,
44
+ },
45
+ [`& .${inputBaseClasses.inputSizeSmall}`]: {
46
+ padding: '12.5px 15px 12.5px 12px',
47
+ },
48
+ },
49
+ [`& .${outlinedInputClasses.input}`]: {
50
+ color: theme.palette.text.primary,
51
+ '&:focus': {
52
+ background: 'rgba(0,0,0,0)',
53
+ },
54
+ },
55
+ }));
56
+ export const OutlinedSelect = ({ label, helperText, FormControlProps = {}, InputLabelProps = {}, InputProps = {}, SelectProps = {}, FormHelperTextProps = {}, className, children, color = 'primary', size = 'small', paperMaxHeight = 'auto', error = false, hasLabel = true, hasShrink = false, value = '', disabled = false, }) => {
57
+ const hasHelperText = !!helperText;
58
+ const { sx: formControlSx = [] } = FormControlProps, otherFormControlProps = __rest(FormControlProps, ["sx"]);
59
+ const { sx: formHelperTextSx = [] } = FormHelperTextProps, otherFormHelperTextProps = __rest(FormHelperTextProps, ["sx"]);
60
+ return (React.createElement(FormControl, Object.assign({ sx: [
61
+ (theme) => ({
62
+ backgroundColor: 'white',
63
+ '&:hover': {
64
+ // eslint-disable-next-line
65
+ [`& :not(.${outlinedInputClasses.disabled}):not(.${outlinedInputClasses.error}) .${outlinedInputClasses.notchedOutline}`]: {
66
+ borderColor: theme.palette[color].main,
67
+ },
68
+ },
69
+ }),
70
+ ...(Array.isArray(formControlSx) ? formControlSx : [formControlSx]),
71
+ ], size: size, disabled: disabled, error: error, color: color, className: className }, otherFormControlProps),
72
+ hasLabel && (React.createElement(StyledInputLabel, Object.assign({ color: color, shrink: hasShrink ? true : undefined }, InputLabelProps), label)),
73
+ React.createElement(Select, Object.assign({ value: value, label: hasLabel ? label : undefined, MenuProps: {
74
+ PaperProps: {
75
+ sx: {
76
+ maxHeight: paperMaxHeight,
77
+ },
78
+ },
79
+ disableAutoFocusItem: true,
80
+ anchorOrigin: {
81
+ vertical: 2,
82
+ horizontal: 'left',
83
+ },
84
+ transformOrigin: {
85
+ vertical: 'top',
86
+ horizontal: 'left',
87
+ },
88
+ }, input: React.createElement(StyledOutlinedInput, Object.assign({ color: color, label: hasLabel ? label : undefined, disabled: disabled }, InputProps)) }, SelectProps), children),
89
+ hasHelperText && (React.createElement(FormHelperText, Object.assign({ sx: Object.assign({ [`&.${formHelperTextClasses.root}`]: {
90
+ marginLeft: 0,
91
+ } }, (Array.isArray(formHelperTextSx)
92
+ ? formHelperTextSx
93
+ : [formHelperTextSx])) }, otherFormHelperTextProps), helperText))));
94
+ };
95
+ export default OutlinedSelect;
@@ -0,0 +1,22 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { OutlinedSelect } from './OutlinedSelect';
14
+ import { StandardSelect } from './StandardSelect';
15
+ export function Select(_a) {
16
+ var { variant } = _a, props = __rest(_a, ["variant"]);
17
+ if (variant === 'outlined') {
18
+ return React.createElement(OutlinedSelect, Object.assign({}, props));
19
+ }
20
+ return React.createElement(StandardSelect, Object.assign({}, props));
21
+ }
22
+ export default Select;
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import { styled } from '@mui/material/styles';
3
+ import { InputLabel, FormControl, Select, Input, FormHelperText, } from '@mui/material';
4
+ import { inputLabelClasses } from '@mui/material/InputLabel';
5
+ import { inputClasses } from '@mui/material/Input';
6
+ const StyledInputLabel = styled(InputLabel, {
7
+ shouldForwardProp: (prop) => prop !== 'color',
8
+ })(({ color, theme }) => ({
9
+ [`&.${inputLabelClasses.root}`]: {
10
+ color: theme.palette.text.disabled,
11
+ },
12
+ [`&.${inputLabelClasses.focused}`]: {
13
+ color: theme.palette[color].main,
14
+ },
15
+ [`&.${inputLabelClasses.error}`]: {
16
+ color: theme.palette.error.main,
17
+ },
18
+ }));
19
+ const StyledInput = styled(Input, {
20
+ shouldForwardProp: (prop) => prop !== 'color',
21
+ })(({ color, theme }) => ({
22
+ color: theme.palette.text.primary,
23
+ [`& .${inputClasses.input}`]: {
24
+ '&:focus': {
25
+ background: 'rgba(0,0,0,0)',
26
+ },
27
+ },
28
+ [`&.${inputClasses.underline}:not(.${inputClasses.disabled}):not(.${inputClasses.error})`]: {
29
+ '&:after,&:hover:before': {
30
+ borderBottomColor: theme.palette[color].main,
31
+ },
32
+ },
33
+ [`&.${inputClasses.underline}.${inputClasses.error}:not(.${inputClasses.disabled})`]: {
34
+ '&:after,&:hover:before': {
35
+ borderBottomColor: theme.palette.error.main,
36
+ },
37
+ },
38
+ }));
39
+ export function StandardSelect({ label, helperText, FormControlProps = {}, InputLabelProps = {}, InputProps = {}, SelectProps = {}, FormHelperTextProps = {}, className, children, color = 'primary', size = 'small', paperMaxHeight = 'auto', error = false, hasShrink = false, value = '', disabled = false, }) {
40
+ const hasHelperText = !!helperText;
41
+ return (React.createElement(FormControl, Object.assign({ variant: "standard", color: color, size: size, disabled: disabled, error: error, className: className }, FormControlProps),
42
+ React.createElement(StyledInputLabel, Object.assign({ color: color, shrink: hasShrink ? true : undefined }, InputLabelProps), label),
43
+ React.createElement(Select, Object.assign({ label: label, value: value, MenuProps: {
44
+ PaperProps: {
45
+ sx: {
46
+ maxHeight: paperMaxHeight,
47
+ },
48
+ },
49
+ anchorOrigin: {
50
+ vertical: 2,
51
+ horizontal: 'left',
52
+ },
53
+ transformOrigin: {
54
+ vertical: 'top',
55
+ horizontal: 'left',
56
+ },
57
+ }, input: React.createElement(StyledInput, Object.assign({ color: color }, InputProps)) }, SelectProps), children),
58
+ hasHelperText && (React.createElement(FormHelperText, Object.assign({}, FormHelperTextProps), helperText))));
59
+ }
60
+ export default StandardSelect;
@@ -0,0 +1,78 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { styled } from '@mui/material/styles';
14
+ import { TextField as MuiTextField, } from '@mui/material';
15
+ import { textFieldClasses } from '@mui/material/TextField';
16
+ import { inputClasses } from '@mui/material/Input';
17
+ import { inputLabelClasses } from '@mui/material/InputLabel';
18
+ import { outlinedInputClasses } from '@mui/material/OutlinedInput';
19
+ import { formHelperTextClasses } from '@mui/material/FormHelperText';
20
+ // utils
21
+ import capitalize from '../../utils/Capitalize';
22
+ // self-defined-components
23
+ const StyledTextField = styled(MuiTextField)(({ label, color = 'primary', theme }) => ({
24
+ [`& .${inputLabelClasses.error}`]: {
25
+ [`&:not(.${inputLabelClasses.shrink})`]: {
26
+ color: theme.palette.text.secondary,
27
+ },
28
+ [`&.${inputLabelClasses.disabled}`]: {
29
+ color: theme.palette.text.disabled,
30
+ },
31
+ },
32
+ [`& .${inputLabelClasses.error}.${inputLabelClasses.focused}`]: {
33
+ color: theme.palette.error.main,
34
+ },
35
+ // For variant: standard | filled
36
+ [`& .${inputClasses.underline}:not(.${inputClasses.disabled})`]: {
37
+ [`&.MuiInputBase-color${capitalize(color)}:hover:before`]: {
38
+ borderColor: theme.palette[color].main,
39
+ },
40
+ },
41
+ // For variant: outlined
42
+ [`& .${inputClasses.disabled} .${outlinedInputClasses.notchedOutline}`]: {
43
+ borderStyle: 'dotted',
44
+ },
45
+ [`& .${inputClasses.error}.${inputClasses.focused} .${outlinedInputClasses.notchedOutline}`]: {
46
+ borderColor: theme.palette.error.main,
47
+ },
48
+ [`&.${textFieldClasses.root} :not(.${inputClasses.disabled}):not(.${inputClasses.error})`]: {
49
+ [`&.MuiInputBase-color${capitalize(color)}:hover .${outlinedInputClasses.notchedOutline}`]: {
50
+ borderColor: theme.palette[color].main,
51
+ },
52
+ },
53
+ [`& .${outlinedInputClasses.notchedOutline}`]: {
54
+ '& > legend': {
55
+ maxWidth: label === '' && 0,
56
+ },
57
+ },
58
+ }));
59
+ export const TextField = (props) => {
60
+ var _a;
61
+ const hasEndAdornment = !!((_a = props === null || props === void 0 ? void 0 : props.InputProps) === null || _a === void 0 ? void 0 : _a.endAdornment);
62
+ const { InputLabelProps, InputProps, FormHelperTextProps = {} } = props, otherProps = __rest(props, ["InputLabelProps", "InputProps", "FormHelperTextProps"]);
63
+ const { sx: formHelperTextSx = [] } = FormHelperTextProps, otherFormHelperTextProps = __rest(FormHelperTextProps, ["sx"]);
64
+ return (React.createElement(StyledTextField, Object.assign({ InputLabelProps: Object.assign(Object.assign({}, InputLabelProps), { shrink: hasEndAdornment ? true : undefined }), FormHelperTextProps: Object.assign({ sx: [
65
+ (theme) => ({
66
+ [`&.${formHelperTextClasses.root}`]: {
67
+ marginLeft: 0,
68
+ [`&.${inputClasses.error}`]: {
69
+ color: theme.palette.error.main,
70
+ },
71
+ },
72
+ }),
73
+ ...(Array.isArray(formHelperTextSx)
74
+ ? formHelperTextSx
75
+ : [formHelperTextSx]),
76
+ ] }, otherFormHelperTextProps), InputProps: Object.assign({}, InputProps) }, otherProps)));
77
+ };
78
+ export default TextField;
@@ -0,0 +1,115 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { styled } from '@mui/material/styles';
3
+ import ArrowRightRoundedIcon from '@mui/icons-material/ArrowRightRounded';
4
+ import { Box } from '@mui/material';
5
+ import Select from '../select/Select';
6
+ import SelectMenuItem from '../menu-item/SelectMenuItem';
7
+ // self-defined-configs
8
+ const LABEL = '請選擇';
9
+ const StyledSelect = styled(Select)(({ theme }) => ({
10
+ width: 220,
11
+ margin: theme.spacing(1),
12
+ }));
13
+ export const TopicFilter = ({ topicTree, onTopicSelected, isLastLayer, hasArrow, initSelectedTopicIds, }) => {
14
+ const [selectedTopicIds, setSelectedTopicIds] = useState([]);
15
+ const [layeredTopicList, setLayeredTopicList] = useState([]);
16
+ const [isFocusedList, setIsFocusedList] = useState([]);
17
+ const initSelectedLayers = () => {
18
+ const newLayeredTopicList = initSelectedTopicIds.reduce((topicListAccumulator, topicId, index) => {
19
+ var _a, _b;
20
+ const selectedTopic = (_b = (_a = topicListAccumulator[index]) === null || _a === void 0 ? void 0 : _a.childTopics) === null || _b === void 0 ? void 0 : _b.find((childTopic) => childTopic.id === topicId);
21
+ if (!selectedTopic) {
22
+ return topicListAccumulator;
23
+ }
24
+ if (isLastLayer(selectedTopic)) {
25
+ return topicListAccumulator;
26
+ }
27
+ return [...topicListAccumulator, selectedTopic];
28
+ }, [topicTree]);
29
+ setLayeredTopicList(newLayeredTopicList);
30
+ setSelectedTopicIds(initSelectedTopicIds.slice(0, newLayeredTopicList.length));
31
+ setIsFocusedList(Array(newLayeredTopicList.length).fill(false));
32
+ };
33
+ const handleChange = (e, layerNumber, layeredTopic) => {
34
+ const selectedTopic = layeredTopic.childTopics.find((childTopic) => childTopic.id === e.target.value);
35
+ const newSelectedTopicIds = [
36
+ ...selectedTopicIds.slice(0, layerNumber),
37
+ selectedTopic.id,
38
+ ];
39
+ setSelectedTopicIds(newSelectedTopicIds);
40
+ onTopicSelected(selectedTopic, {
41
+ layerNumber,
42
+ selectedTopicIds: newSelectedTopicIds,
43
+ });
44
+ if (isLastLayer(selectedTopic)) {
45
+ setLayeredTopicList((prevTopicList) => prevTopicList.slice(0, layerNumber + 1));
46
+ setIsFocusedList((prevList) => prevList.slice(0, layerNumber + 1));
47
+ }
48
+ else {
49
+ setLayeredTopicList((prevTopicList) => [
50
+ ...prevTopicList.slice(0, layerNumber + 1),
51
+ selectedTopic,
52
+ ]);
53
+ setIsFocusedList((prevList) => [
54
+ ...prevList.slice(0, layerNumber + 1),
55
+ false,
56
+ ]);
57
+ }
58
+ };
59
+ useEffect(() => {
60
+ if (!topicTree || Object.keys(topicTree).length === 0) {
61
+ return;
62
+ }
63
+ if (initSelectedTopicIds.length !== 0) {
64
+ initSelectedLayers();
65
+ return;
66
+ }
67
+ setLayeredTopicList([topicTree]);
68
+ }, [topicTree]);
69
+ if (layeredTopicList.length === 0) {
70
+ return (React.createElement(StyledSelect, { variant: "outlined", size: "small", label: "\u8F09\u5165\u8CC7\u6599\u4E2D...", disabled: true }));
71
+ }
72
+ return (React.createElement(Box, { sx: {
73
+ display: 'flex',
74
+ alignItems: 'center',
75
+ flexWrap: 'wrap',
76
+ } }, layeredTopicList.map((layeredTopic, layerNumber) => {
77
+ const hasLabel = isFocusedList[layerNumber] || !selectedTopicIds[layerNumber];
78
+ return (React.createElement(Box, { sx: {
79
+ display: 'flex',
80
+ alignItems: 'center',
81
+ }, key: layeredTopic.id },
82
+ React.createElement(StyledSelect, { variant: "outlined", size: "small", label: LABEL, paperMaxHeight: 412, hasLabel: hasLabel, value: (selectedTopicIds === null || selectedTopicIds === void 0 ? void 0 : selectedTopicIds[layerNumber]) || '', SelectProps: {
83
+ 'data-testid': `layered-topic-${layerNumber}`,
84
+ }, InputProps: {
85
+ inputProps: {
86
+ 'aria-label': `layered-topic-${layerNumber}`,
87
+ },
88
+ onChange: (e) => {
89
+ handleChange(e, layerNumber, layeredTopic);
90
+ },
91
+ onFocus: () => {
92
+ setIsFocusedList((prevList) => {
93
+ const newList = [...prevList];
94
+ newList[layerNumber] = true;
95
+ return newList;
96
+ });
97
+ },
98
+ onBlur: () => {
99
+ setIsFocusedList((prevList) => {
100
+ const newList = [...prevList];
101
+ newList[layerNumber] = false;
102
+ return newList;
103
+ });
104
+ },
105
+ } },
106
+ React.createElement(SelectMenuItem, { disabled: true, value: "" }, LABEL),
107
+ layeredTopic.childTopics.map((childTopic) => (React.createElement(SelectMenuItem, { key: childTopic.id, value: childTopic.id, "data-testid": `layered-menuitem-${layerNumber}`, "data-is-content-topic": childTopic.isContentTopic }, childTopic.title)))),
108
+ hasArrow && layerNumber !== layeredTopicList.length - 1 && (React.createElement(ArrowRightRoundedIcon, { sx: (theme) => ({
109
+ margin: theme.spacing(-1, -1.5),
110
+ fontSize: theme.spacing(7),
111
+ color: '#444',
112
+ }), fontSize: "large", "data-testid": "topic-filter-arrow" }))));
113
+ })));
114
+ };
115
+ export default TopicFilter;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright (c) 2020 Junyi Academy.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { createTheme } from '@mui/material/styles';
8
+ // Create a theme instance.
9
+ const theme = createTheme({
10
+ typography: {
11
+ fontFamily: ['Noto Sans TC', 'Helvetica', 'Arial', 'sans-serif'].join(','),
12
+ },
13
+ palette: {
14
+ primary: {
15
+ light: '#82C0FF',
16
+ main: '#4990E2',
17
+ dark: '#0063B0',
18
+ },
19
+ secondary: {
20
+ light: '#FFD759',
21
+ main: '#F5A623',
22
+ dark: '#BD7700',
23
+ contrastText: '#FFFFFF',
24
+ },
25
+ green: {
26
+ primary: {
27
+ light: '#9DD49E',
28
+ main: '#5CB85D',
29
+ dark: '#218838',
30
+ },
31
+ blueGreen: {
32
+ main: '#19A696',
33
+ },
34
+ grassGreen: {
35
+ main: '#80BB5A',
36
+ },
37
+ },
38
+ },
39
+ });
40
+ export default theme;
@@ -0,0 +1,3 @@
1
+ export default function capitalize(string) {
2
+ return `${string.charAt(0).toUpperCase()}${string.slice(1)}`;
3
+ }
@@ -0,0 +1,174 @@
1
+ export const topicTree = {
2
+ childTopics: [
3
+ {
4
+ childTopics: [
5
+ {
6
+ childTopics: [
7
+ {
8
+ childTopics: [
9
+ {
10
+ childTopics: [],
11
+ id: 'j-m1ach1',
12
+ isContentTopic: true,
13
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKFlWUkdyck1reDdXU3lSb3pQYXU4RDlDTnZ4Ukx3MjhYU2ZCcTF0LTEM',
14
+ tags: [],
15
+ title: '【一上】數到 10',
16
+ },
17
+ {
18
+ childTopics: [],
19
+ id: 'j-m1ach2',
20
+ isContentTopic: true,
21
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
22
+ tags: [],
23
+ title: '【一上】比長短1',
24
+ },
25
+ {
26
+ childTopics: [],
27
+ id: 'j-m1ach3',
28
+ isContentTopic: true,
29
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
30
+ tags: [],
31
+ title: '【一上】比長短2',
32
+ },
33
+ {
34
+ childTopics: [],
35
+ id: 'j-m1ach4',
36
+ isContentTopic: true,
37
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
38
+ tags: [],
39
+ title: '【一上】比長短3',
40
+ },
41
+ {
42
+ childTopics: [],
43
+ id: 'j-m1ach5',
44
+ isContentTopic: true,
45
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
46
+ tags: [],
47
+ title: '【一上】比長短4',
48
+ },
49
+ {
50
+ childTopics: [],
51
+ id: 'j-m1ach6',
52
+ isContentTopic: true,
53
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
54
+ tags: [],
55
+ title: '【一上】比長短5',
56
+ },
57
+ {
58
+ childTopics: [],
59
+ id: 'j-m1ach7',
60
+ isContentTopic: true,
61
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
62
+ tags: [],
63
+ title: '【一上】比長短6',
64
+ },
65
+ {
66
+ childTopics: [],
67
+ id: 'j-m1ach8',
68
+ isContentTopic: true,
69
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
70
+ tags: [],
71
+ title: '【一上】比長短7',
72
+ },
73
+ {
74
+ childTopics: [],
75
+ id: 'j-m1ach9',
76
+ isContentTopic: true,
77
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
78
+ tags: [],
79
+ title: '【一上】比長短8',
80
+ },
81
+ {
82
+ childTopics: [],
83
+ id: 'j-m1ach10',
84
+ isContentTopic: true,
85
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
86
+ tags: [],
87
+ title: '【一上】比長短9',
88
+ },
89
+ {
90
+ childTopics: [],
91
+ id: 'j-m1ach11',
92
+ isContentTopic: true,
93
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
94
+ tags: [],
95
+ title: '【一上】比長短10',
96
+ },
97
+ {
98
+ childTopics: [],
99
+ id: 'j-m1ach12',
100
+ isContentTopic: true,
101
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHRXZlVrTHNpSjRYcHlMTGFDa2QtVTRDWkRjcjMwZ3JSTGtSUUNNazgM',
102
+ tags: [],
103
+ title: '【一上】比長短11',
104
+ },
105
+ ],
106
+ id: 'math-grade-1-a',
107
+ isContentTopic: false,
108
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHN2MlIzS0VwaXlVeWdJQnhyYzBYakZ0RDZhU0JraGFJbGctU19qZFoM',
109
+ tags: [],
110
+ title: '均一版',
111
+ },
112
+ ],
113
+ id: 'math-1',
114
+ isContentTopic: false,
115
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKEVzRnVINFdtalZBRmdQUkpjeWtaWFVnSlR2OEc2RzVsWnA1a0ZEVV8M',
116
+ tags: ['grouping_eleme'],
117
+ title: '一年級',
118
+ },
119
+ {
120
+ childTopics: [
121
+ {
122
+ childTopics: [
123
+ {
124
+ childTopics: [],
125
+ id: 'n-m2ach1',
126
+ isContentTopic: true,
127
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKExzUnEyWUgzUEduZmVzWm1oVXdxLU5tdmxjZmx4aWJXbkVKN0JVcXYM',
128
+ tags: [],
129
+ title: '【二上】第一單元 數到 300',
130
+ },
131
+ {
132
+ childTopics: [],
133
+ id: 'n-m2ach2',
134
+ isContentTopic: true,
135
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKFJuTDZLWXhxS0xNQ3VPU3BkUXZBOVN6YkRrVTNqdVNRSFdjbTEwc2UM',
136
+ tags: [],
137
+ title: '【二上】第二單元 二位數的加法',
138
+ },
139
+ {
140
+ childTopics: [],
141
+ id: 'n-m2ach3',
142
+ isContentTopic: true,
143
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHpYUWFzZXNPbS16V1BVeG9qeVFRQXlfZzA5Wm44ajdVZnM1dU85UWkM',
144
+ tags: [],
145
+ title: '【二上】第三單元 幾公分',
146
+ },
147
+ ],
148
+ id: 'n-m2a',
149
+ isContentTopic: false,
150
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKHl3QXRqNW1xMmk2QTRfR0JzWlpXQnVRQW1fYW5ZTEV4MkJ2ZUlYSmUM',
151
+ tags: [],
152
+ title: '南一版',
153
+ },
154
+ ],
155
+ id: 'math-2',
156
+ isContentTopic: false,
157
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKE92cm9EU1N4c3FZM2J6MzMzZ05XWFR6RGFLMDJudHlIaHFtN1VRcXIM',
158
+ tags: ['grouping_eleme'],
159
+ title: '二年級',
160
+ },
161
+ ],
162
+ id: 'course-compare',
163
+ isContentTopic: false,
164
+ key: 'ag5zfmp1bnlpYWNhZGVteXJmCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoMCxIFVG9waWMiKDFCSmFuVjVsTWlUUWZaU21MeE9FU3BZbVlmcktkNHJWN3Q5WU1VWjQM',
165
+ tags: ['has-pre-exam', 'has-post-exam'],
166
+ title: '數學',
167
+ },
168
+ ],
169
+ id: 'root',
170
+ isContentTopic: false,
171
+ key: 'ag5zfmp1bnlpYWNhZGVteXIzCxIFVG9waWMiKHpWQ01BOGpXQTU5SW1zSi1sdWJSQTJlV0QzbHpuZUZiY1BwMUZWOVoM',
172
+ tags: [],
173
+ title: '知識樹',
174
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junyiacademy/ui-test",
3
- "version": "1.5.16",
3
+ "version": "1.6.0",
4
4
  "description": "junyiacademy ui library",
5
5
  "main": "./dist/libs/ui/src/index.js",
6
6
  "typings": "./declarations/libs/ui/src/index.d.ts",
Binary file
Binary file
Binary file