@junyiacademy/ui-test 0.0.11 → 0.0.12

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.
@@ -1,4 +1,4 @@
1
- export { default as TopicFilter } from './lib/TopicFilter';
1
+ export { default as TopicFilter } from './lib/topic-filter/TopicFilter';
2
2
  export { default as SelectMenuItem } from './lib/menu-item/SelectMenuItem';
3
3
  export { default as OutlinedSelect } from './lib/select/OutlinedSelect';
4
4
  export { default as Button } from './lib/button/Button';
@@ -1,3 +1,5 @@
1
+ import { ChangeEvent } from 'react';
2
+ import { SelectProps as MuiSelectProp, InputProps as MuiInputProps, OutlinedInputProps } from '@material-ui/core';
1
3
  export interface ITopicTreeNode {
2
4
  childTopics: ITopicTreeNode[];
3
5
  id: string;
@@ -6,3 +8,19 @@ export interface ITopicTreeNode {
6
8
  tags: string[];
7
9
  title: string;
8
10
  }
11
+ export interface SelectProps extends MuiSelectProp {
12
+ placeholder: string;
13
+ helperText?: string;
14
+ InputProps?: (Partial<OutlinedInputProps> & {
15
+ onChange: (e: ChangeEvent<HTMLInputElement>) => void;
16
+ }) | (object & Partial<MuiInputProps>);
17
+ SelectProps?: object | Partial<MuiSelectProp>;
18
+ color?: 'primary' | 'secondary';
19
+ size?: 'medium' | 'small';
20
+ width?: number | 'auto';
21
+ paperMaxHeight?: number | 'auto';
22
+ error?: boolean;
23
+ hasLabel?: boolean;
24
+ hasShrink?: boolean;
25
+ disabled?: boolean;
26
+ }
@@ -5,5 +5,5 @@ export interface SelectMenuItemProps extends MenuItemProps {
5
5
  value?: any;
6
6
  disabled?: boolean;
7
7
  }
8
- declare const SelectMenuItem: React.ForwardRefExoticComponent<Pick<React.PropsWithChildren<SelectMenuItemProps>, "button" | "slot" | "style" | "title" | "color" | "width" | "alignItems" | "translate" | "hidden" | "dense" | "disabled" | "classes" | "className" | "children" | "value" | "onChange" | "onKeyUp" | "onKeyDown" | "onBlur" | "onFocus" | "defaultValue" | "defaultChecked" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "id" | "lang" | "placeholder" | "spellCheck" | "tabIndex" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlurCapture" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "autoFocus" | "innerRef" | "key" | "selected" | "ContainerComponent" | "ContainerProps" | "disableGutters" | "divider" | "focusVisibleClassName"> & React.RefAttributes<HTMLLIElement>>;
8
+ declare const SelectMenuItem: React.ForwardRefExoticComponent<Pick<React.PropsWithChildren<SelectMenuItemProps>, "classes" | "disabled" | "value" | "onChange" | "children" | "onKeyUp" | "onKeyDown" | "onBlur" | "onFocus" | "defaultValue" | "defaultChecked" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "placeholder" | "slot" | "spellCheck" | "style" | "tabIndex" | "title" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocusCapture" | "onBlurCapture" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "autoFocus" | "innerRef" | "button" | "width" | "alignItems" | "dense" | "key" | "selected" | "ContainerComponent" | "ContainerProps" | "disableGutters" | "divider" | "focusVisibleClassName"> & React.RefAttributes<HTMLLIElement>>;
9
9
  export default SelectMenuItem;
@@ -1,20 +1,3 @@
1
- import { ChangeEvent } from 'react';
2
- import { SelectProps, OutlinedInputProps } from '@material-ui/core';
3
- export interface OutlinedSelectProps extends SelectProps {
4
- color?: 'primary' | 'secondary';
5
- size?: 'medium' | 'small';
6
- width?: number | 'auto';
7
- paperMaxHeight?: number | 'auto';
8
- error?: boolean;
9
- hasLabel?: boolean;
10
- hasShrink?: boolean;
11
- placeholder: string;
12
- helperText?: string;
13
- disabled?: boolean;
14
- SelectProps?: object | Partial<SelectProps>;
15
- OutlinedInputProps?: Partial<OutlinedInputProps> & {
16
- onChange: (e: ChangeEvent<HTMLInputElement>) => void;
17
- };
18
- }
19
- declare const OutlinedSelect: ({ placeholder, SelectProps, OutlinedInputProps, children, color, size, width, paperMaxHeight, error, hasLabel, hasShrink, helperText, value, disabled, }: OutlinedSelectProps) => JSX.Element;
1
+ import { SelectProps } from '../../interfaces';
2
+ export declare const OutlinedSelect: ({ placeholder, helperText, InputProps, SelectProps, children, color, size, width, paperMaxHeight, error, hasLabel, hasShrink, value, disabled, }: SelectProps) => JSX.Element;
20
3
  export default OutlinedSelect;
@@ -0,0 +1,3 @@
1
+ import { SelectProps } from '../../interfaces';
2
+ export declare function Select({ variant, ...props }: SelectProps): JSX.Element;
3
+ export default Select;
@@ -1,16 +1,3 @@
1
- import { SelectProps, InputProps } from '@material-ui/core';
2
- export interface StandardSelectProps extends SelectProps {
3
- color?: 'primary' | 'secondary';
4
- size?: 'medium' | 'small';
5
- width?: number | 'auto';
6
- paperMaxHeight?: number | 'auto';
7
- error?: boolean;
8
- hasShrink?: boolean;
9
- placeholder: string;
10
- helperText?: string;
11
- InputProps?: object & Partial<InputProps>;
12
- disabled?: boolean;
13
- SelectProps?: object | Partial<SelectProps>;
14
- }
15
- export declare function StandardSelect({ placeholder, helperText, InputProps, SelectProps, children, color, size, width, paperMaxHeight, error, hasShrink, value, disabled, }: StandardSelectProps): JSX.Element;
1
+ import { SelectProps } from '../../interfaces';
2
+ export declare function StandardSelect({ placeholder, helperText, InputProps, SelectProps, children, color, size, width, paperMaxHeight, error, hasShrink, value, disabled, }: SelectProps): JSX.Element;
16
3
  export default StandardSelect;
@@ -0,0 +1,13 @@
1
+ import type { ITopicTreeNode } from '../../interfaces';
2
+ export interface TopicFilterProps {
3
+ topicTree: ITopicTreeNode;
4
+ onTopicSelected: (topic: ITopicTreeNode, selectedInfo: {
5
+ layerNumber: number;
6
+ selectedTopicIds: string[];
7
+ }) => void;
8
+ isLastLayer: (topic: ITopicTreeNode) => boolean;
9
+ hasArrow: boolean;
10
+ initSelectedTopicIds: string[];
11
+ }
12
+ export declare const TopicFilter: ({ topicTree, onTopicSelected, isLastLayer, hasArrow, initSelectedTopicIds, }: TopicFilterProps) => JSX.Element;
13
+ export default TopicFilter;
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.StandardSelect = exports.TextField = exports.Radio = exports.ButtonGroup = exports.Button = exports.OutlinedSelect = exports.SelectMenuItem = exports.TopicFilter = void 0;
7
- var TopicFilter_1 = require("./lib/TopicFilter");
7
+ var TopicFilter_1 = require("./lib/topic-filter/TopicFilter");
8
8
  Object.defineProperty(exports, "TopicFilter", { enumerable: true, get: function () { return __importDefault(TopicFilter_1).default; } });
9
9
  var SelectMenuItem_1 = require("./lib/menu-item/SelectMenuItem");
10
10
  Object.defineProperty(exports, "SelectMenuItem", { enumerable: true, get: function () { return __importDefault(SelectMenuItem_1).default; } });
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OutlinedSelect = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  const react_1 = tslib_1.__importDefault(require("react"));
5
6
  const styles_1 = require("@material-ui/core/styles");
@@ -14,10 +15,12 @@ const classes = {
14
15
  inputLabelError: `${PREFIX}-inputLabelError`,
15
16
  inputLabelDisabled: `${PREFIX}-inputLabelDisabled`,
16
17
  outlineInputInput: `${PREFIX}-input`,
18
+ outlineInputRoot: `${PREFIX}-inputRoot`,
17
19
  outlineInputInputMarginDense: `${PREFIX}-inputMarginDense`,
18
20
  outlineInputNotchedOutline: `${PREFIX}-notchedOutline`,
19
21
  outlineInputDisabled: `${PREFIX}-inputDisabled`,
20
22
  outlineInputError: `${PREFIX}-outlinedInputError`,
23
+ outlineInputFocused: `${PREFIX}-focused`,
21
24
  selectPaper: `${PREFIX}-menuPaper`,
22
25
  };
23
26
  const StyledFormControl = styles_1.styled((_a) => {
@@ -32,6 +35,9 @@ const StyledFormControl = styles_1.styled((_a) => {
32
35
  borderColor: theme.palette[color].main,
33
36
  },
34
37
  },
38
+ [`& .${classes.outlineInputError}.${classes.outlineInputFocused} .${classes.outlineInputNotchedOutline}`]: {
39
+ borderColor: `${theme.palette.error.main}`,
40
+ },
35
41
  }));
36
42
  const StyledInputLabel = styles_1.styled((_a) => {
37
43
  var { color: _color } = _a, props = tslib_1.__rest(_a, ["color"]);
@@ -62,14 +68,22 @@ const StyledInputLabel = styles_1.styled((_a) => {
62
68
  },
63
69
  }));
64
70
  const StyledOutlinedInput = styles_1.styled((props) => (react_1.default.createElement(core_1.OutlinedInput, Object.assign({ classes: {
71
+ root: classes.outlineInputRoot,
72
+ focused: classes.outlineInputFocused,
65
73
  input: classes.outlineInputInput,
66
74
  inputMarginDense: classes.outlineInputInputMarginDense,
67
75
  notchedOutline: classes.outlineInputNotchedOutline,
68
76
  disabled: classes.outlineInputDisabled,
69
77
  error: classes.outlineInputError,
70
78
  } }, props))))(({ theme }) => ({
79
+ [`&.${classes.outlineInputRoot}.${classes.outlineInputFocused}`]: {
80
+ backgroundColor: theme.palette.action.selected,
81
+ },
71
82
  [`& .${classes.outlineInputInput}`]: {
72
83
  color: theme.palette.text.primary,
84
+ ['&:focus']: {
85
+ background: 'rgba(0,0,0,0)',
86
+ },
73
87
  },
74
88
  [`& .${classes.outlineInputInputMarginDense}`]: {
75
89
  padding: '14.5px 15px 14.5px 12px',
@@ -88,7 +102,9 @@ const StyledSelect = styles_1.styled((_a) => {
88
102
  horizontal: 'left',
89
103
  },
90
104
  getContentAnchorEl: null,
91
- classes: { paper: className },
105
+ classes: {
106
+ paper: className,
107
+ },
92
108
  } }, props)));
93
109
  })(({ hasAdornment, paperMaxHeight }) => ({
94
110
  '&': {
@@ -96,12 +112,13 @@ const StyledSelect = styles_1.styled((_a) => {
96
112
  left: hasAdornment ? '24px !important' : '70px',
97
113
  },
98
114
  }));
99
- const OutlinedSelect = ({ placeholder, SelectProps, OutlinedInputProps, children, color = 'primary', size = 'medium', width = 'auto', paperMaxHeight = 'auto', error = false, hasLabel = true, hasShrink = false, helperText = '', value = '', disabled = false, }) => {
100
- const hasAdornment = !!(OutlinedInputProps === null || OutlinedInputProps === void 0 ? void 0 : OutlinedInputProps.startAdornment);
115
+ const OutlinedSelect = ({ placeholder, helperText, InputProps, SelectProps, children, color = 'primary', size = 'medium', width = 'auto', paperMaxHeight = 'auto', error = false, hasLabel = true, hasShrink = false, value = '', disabled = false, }) => {
116
+ const hasAdornment = !!(InputProps === null || InputProps === void 0 ? void 0 : InputProps.startAdornment);
101
117
  const hasHelperText = !!helperText;
102
118
  return (react_1.default.createElement(StyledFormControl, { size: size, width: width, disabled: disabled, error: error, color: color },
103
119
  hasLabel && (react_1.default.createElement(StyledInputLabel, { color: color, variant: 'outlined', shrink: hasShrink ? true : undefined }, placeholder)),
104
- react_1.default.createElement(StyledSelect, Object.assign({ value: value, paperMaxHeight: paperMaxHeight, hasAdornment: hasAdornment, input: react_1.default.createElement(StyledOutlinedInput, Object.assign({ color: color, label: hasLabel ? placeholder : undefined, disabled: disabled }, OutlinedInputProps)) }, SelectProps), children),
120
+ react_1.default.createElement(StyledSelect, Object.assign({ value: value, paperMaxHeight: paperMaxHeight, hasAdornment: hasAdornment, input: react_1.default.createElement(StyledOutlinedInput, Object.assign({ color: color, label: hasLabel ? placeholder : undefined, disabled: disabled }, InputProps)) }, SelectProps), children),
105
121
  hasHelperText && react_1.default.createElement(core_1.FormHelperText, null, helperText)));
106
122
  };
107
- exports.default = OutlinedSelect;
123
+ exports.OutlinedSelect = OutlinedSelect;
124
+ exports.default = exports.OutlinedSelect;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Select = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const OutlinedSelect_1 = require("./OutlinedSelect");
7
+ const StandardSelect_1 = require("./StandardSelect");
8
+ function Select(_a) {
9
+ var { variant } = _a, props = tslib_1.__rest(_a, ["variant"]);
10
+ if (variant === 'outlined') {
11
+ return react_1.default.createElement(OutlinedSelect_1.OutlinedSelect, Object.assign({}, props));
12
+ }
13
+ return react_1.default.createElement(StandardSelect_1.StandardSelect, Object.assign({}, props));
14
+ }
15
+ exports.Select = Select;
16
+ exports.default = Select;
@@ -11,6 +11,9 @@ const classes = {
11
11
  inputLabelFocused: `${PREFIX}-inputLabelFocused`,
12
12
  inputLabelMarginDense: `${PREFIX}-inputLabelMarginDense`,
13
13
  inputLabelError: `${PREFIX}-inputLabelError`,
14
+ inputRoot: `${PREFIX}-inputRoot`,
15
+ inputFocused: `${PREFIX}-inputFocused`,
16
+ inputInput: `${PREFIX}-input`,
14
17
  inputUnderline: `${PREFIX}-inputUnderline`,
15
18
  inputError: `${PREFIX}-inputError`,
16
19
  inputDisabled: `${PREFIX}-inputDisabled`,
@@ -60,12 +63,23 @@ const StyledSelect = styles_1.styled((_a) => {
60
63
  const StyledInput = styles_1.styled((_a) => {
61
64
  var { color: _color } = _a, props = tslib_1.__rest(_a, ["color"]);
62
65
  return (react_1.default.createElement(core_1.Input, Object.assign({ classes: {
66
+ root: classes.inputRoot,
67
+ focused: classes.inputFocused,
68
+ input: classes.inputInput,
63
69
  disabled: classes.inputDisabled,
64
70
  underline: classes.inputUnderline,
65
71
  error: classes.inputError,
66
72
  } }, props)));
67
73
  })(({ color, theme }) => ({
68
74
  color: theme.palette.text.primary,
75
+ [`&.${classes.inputRoot}.${classes.inputFocused}`]: {
76
+ backgroundColor: theme.palette.action.selected,
77
+ },
78
+ [`& .${classes.inputInput}`]: {
79
+ ['&:focus']: {
80
+ background: 'rgba(0,0,0,0)',
81
+ },
82
+ },
69
83
  [`&.${classes.inputUnderline}:not(.${classes.inputDisabled}):not(.${classes.inputError})`]: {
70
84
  [`&:after,&:hover:before`]: {
71
85
  borderBottomColor: theme.palette[color].main,
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TopicFilter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importStar(require("react"));
6
+ const styles_1 = require("@material-ui/core/styles");
7
+ const ArrowRightRounded_1 = tslib_1.__importDefault(require("@material-ui/icons/ArrowRightRounded"));
8
+ const OutlinedSelect_1 = tslib_1.__importDefault(require("../select/OutlinedSelect"));
9
+ const SelectMenuItem_1 = tslib_1.__importDefault(require("../menu-item/SelectMenuItem"));
10
+ // self-defined-configs
11
+ const PLACEHOLDER = '請選擇';
12
+ // self-defined-components
13
+ const PREFIX = 'JuiTopicFilter';
14
+ const FiltersWrapper = styles_1.styled('div')({
15
+ display: 'flex',
16
+ alignItems: 'center',
17
+ flexWrap: 'wrap',
18
+ });
19
+ const SelectWrapper = styles_1.styled('div')({
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ });
23
+ const StyledArrowRightRoundedIcon = styles_1.styled(ArrowRightRounded_1.default)(({ theme }) => ({
24
+ margin: theme.spacing(-1, -1.5),
25
+ fontSize: theme.spacing(7),
26
+ color: '#444',
27
+ }));
28
+ const TopicFilter = ({ topicTree, onTopicSelected, isLastLayer, hasArrow, initSelectedTopicIds, }) => {
29
+ const [selectedTopicIds, setSelectedTopicIds] = react_1.useState([]);
30
+ const [layeredTopicList, setLayeredTopicList] = react_1.useState([]);
31
+ const [isFocusedList, setIsFocusedList] = react_1.useState([]);
32
+ const initSelectedLayers = () => {
33
+ const newLayeredTopicList = initSelectedTopicIds.reduce((topicListAccumulator, topicId, index) => {
34
+ var _a, _b;
35
+ 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);
36
+ if (!selectedTopic) {
37
+ return topicListAccumulator;
38
+ }
39
+ if (isLastLayer(selectedTopic)) {
40
+ return topicListAccumulator;
41
+ }
42
+ return [...topicListAccumulator, selectedTopic];
43
+ }, [topicTree]);
44
+ setLayeredTopicList(newLayeredTopicList);
45
+ setSelectedTopicIds(initSelectedTopicIds.slice(0, newLayeredTopicList.length));
46
+ setIsFocusedList(Array(newLayeredTopicList.length).fill(false));
47
+ };
48
+ const handleChange = (e, layerNumber, layeredTopic) => {
49
+ const selectedTopic = layeredTopic.childTopics.find((childTopic) => childTopic.id === e.target.value);
50
+ const newSelectedTopicIds = [
51
+ ...selectedTopicIds.slice(0, layerNumber),
52
+ selectedTopic.id,
53
+ ];
54
+ setSelectedTopicIds(newSelectedTopicIds);
55
+ onTopicSelected(selectedTopic, {
56
+ layerNumber,
57
+ selectedTopicIds: newSelectedTopicIds,
58
+ });
59
+ if (isLastLayer(selectedTopic)) {
60
+ setLayeredTopicList((prevTopicList) => prevTopicList.slice(0, layerNumber + 1));
61
+ setIsFocusedList((prevList) => prevList.slice(0, layerNumber + 1));
62
+ }
63
+ else {
64
+ setLayeredTopicList((prevTopicList) => [
65
+ ...prevTopicList.slice(0, layerNumber + 1),
66
+ selectedTopic,
67
+ ]);
68
+ setIsFocusedList((prevList) => [
69
+ ...prevList.slice(0, layerNumber + 1),
70
+ false,
71
+ ]);
72
+ }
73
+ };
74
+ react_1.useEffect(() => {
75
+ if (!topicTree || Object.keys(topicTree).length === 0) {
76
+ return;
77
+ }
78
+ if (initSelectedTopicIds.length !== 0) {
79
+ initSelectedLayers();
80
+ return;
81
+ }
82
+ setLayeredTopicList([topicTree]);
83
+ }, [topicTree]);
84
+ if (layeredTopicList.length === 0) {
85
+ return (react_1.default.createElement(OutlinedSelect_1.default, { size: 'small', width: 220, placeholder: '\u8F09\u5165\u8CC7\u6599\u4E2D...', disabled: true }));
86
+ }
87
+ return (react_1.default.createElement(FiltersWrapper, null, layeredTopicList.map((layeredTopic, layerNumber) => {
88
+ const hasLabel = isFocusedList[layerNumber] || !selectedTopicIds[layerNumber];
89
+ return (react_1.default.createElement(SelectWrapper, { key: layeredTopic.id },
90
+ react_1.default.createElement(OutlinedSelect_1.default, { size: 'small', width: 220, paperMaxHeight: 412, hasLabel: hasLabel, placeholder: PLACEHOLDER, value: (selectedTopicIds === null || selectedTopicIds === void 0 ? void 0 : selectedTopicIds[layerNumber]) || '', SelectProps: {
91
+ 'data-testid': `layered-topic-${layerNumber}`,
92
+ }, InputProps: {
93
+ inputProps: {
94
+ 'aria-label': `layered-topic-${layerNumber}`,
95
+ },
96
+ onChange: (e) => {
97
+ handleChange(e, layerNumber, layeredTopic);
98
+ },
99
+ onFocus: () => {
100
+ setIsFocusedList((prevList) => {
101
+ const newList = [...prevList];
102
+ newList[layerNumber] = true;
103
+ return newList;
104
+ });
105
+ },
106
+ onBlur: () => {
107
+ setIsFocusedList((prevList) => {
108
+ const newList = [...prevList];
109
+ newList[layerNumber] = false;
110
+ return newList;
111
+ });
112
+ },
113
+ } },
114
+ react_1.default.createElement(SelectMenuItem_1.default, { width: 220, disabled: true }, PLACEHOLDER),
115
+ layeredTopic.childTopics.map((childTopic) => (react_1.default.createElement(SelectMenuItem_1.default, { width: 220, key: childTopic.id, value: childTopic.id, "data-testid": `layered-menuitem-${layerNumber}`, "data-is-content-topic": childTopic.isContentTopic }, childTopic.title)))),
116
+ hasArrow && layerNumber !== layeredTopicList.length - 1 && (react_1.default.createElement(StyledArrowRightRoundedIcon, { fontSize: 'large', "data-testid": 'topic-filter-arrow' }))));
117
+ })));
118
+ };
119
+ exports.TopicFilter = TopicFilter;
120
+ exports.default = exports.TopicFilter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junyiacademy/ui-test",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
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",
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { default as TopicFilter } from './lib/TopicFilter'
1
+ export { default as TopicFilter } from './lib/topic-filter/TopicFilter'
2
2
  export { default as SelectMenuItem } from './lib/menu-item/SelectMenuItem'
3
3
  export { default as OutlinedSelect } from './lib/select/OutlinedSelect'
4
4
  export { default as Button } from './lib/button/Button'
@@ -1,3 +1,10 @@
1
+ import { ChangeEvent } from 'react'
2
+ import {
3
+ SelectProps as MuiSelectProp,
4
+ InputProps as MuiInputProps,
5
+ OutlinedInputProps,
6
+ } from '@material-ui/core'
7
+
1
8
  export interface ITopicTreeNode {
2
9
  childTopics: ITopicTreeNode[]
3
10
  id: string
@@ -6,3 +13,21 @@ export interface ITopicTreeNode {
6
13
  tags: string[]
7
14
  title: string
8
15
  }
16
+ export interface SelectProps extends MuiSelectProp {
17
+ placeholder: string
18
+ helperText?: string
19
+ InputProps?:
20
+ | (Partial<OutlinedInputProps> & {
21
+ onChange: (e: ChangeEvent<HTMLInputElement>) => void
22
+ })
23
+ | (object & Partial<MuiInputProps>)
24
+ SelectProps?: object | Partial<MuiSelectProp>
25
+ color?: 'primary' | 'secondary'
26
+ size?: 'medium' | 'small'
27
+ width?: number | 'auto'
28
+ paperMaxHeight?: number | 'auto'
29
+ error?: boolean
30
+ hasLabel?: boolean
31
+ hasShrink?: boolean
32
+ disabled?: boolean
33
+ }
@@ -1,14 +1,13 @@
1
- import React, { ChangeEvent } from 'react'
1
+ import React from 'react'
2
2
  import { Theme, styled } from '@material-ui/core/styles'
3
3
  import {
4
4
  InputLabel,
5
5
  FormControl,
6
6
  Select,
7
7
  OutlinedInput,
8
- SelectProps,
9
- OutlinedInputProps,
10
8
  FormHelperText,
11
9
  } from '@material-ui/core'
10
+ import { SelectProps } from '../../interfaces'
12
11
 
13
12
  // self-defined-components
14
13
  const PREFIX = 'JuiOutlinedSelect'
@@ -21,10 +20,12 @@ const classes = {
21
20
  inputLabelError: `${PREFIX}-inputLabelError`,
22
21
  inputLabelDisabled: `${PREFIX}-inputLabelDisabled`,
23
22
  outlineInputInput: `${PREFIX}-input`,
23
+ outlineInputRoot: `${PREFIX}-inputRoot`,
24
24
  outlineInputInputMarginDense: `${PREFIX}-inputMarginDense`,
25
25
  outlineInputNotchedOutline: `${PREFIX}-notchedOutline`,
26
26
  outlineInputDisabled: `${PREFIX}-inputDisabled`,
27
27
  outlineInputError: `${PREFIX}-outlinedInputError`,
28
+ outlineInputFocused: `${PREFIX}-focused`,
28
29
  selectPaper: `${PREFIX}-menuPaper`,
29
30
  }
30
31
 
@@ -45,6 +46,9 @@ const StyledFormControl = styled(
45
46
  borderColor: theme.palette[color].main,
46
47
  },
47
48
  },
49
+ [`& .${classes.outlineInputError}.${classes.outlineInputFocused} .${classes.outlineInputNotchedOutline}`]: {
50
+ borderColor: `${theme.palette.error.main}`,
51
+ },
48
52
  }))
49
53
 
50
54
  interface StyledInputLabelProps {
@@ -90,6 +94,8 @@ interface StyledOutlinedInputProps {
90
94
  const StyledOutlinedInput = styled((props) => (
91
95
  <OutlinedInput
92
96
  classes={{
97
+ root: classes.outlineInputRoot,
98
+ focused: classes.outlineInputFocused,
93
99
  input: classes.outlineInputInput,
94
100
  inputMarginDense: classes.outlineInputInputMarginDense,
95
101
  notchedOutline: classes.outlineInputNotchedOutline,
@@ -99,8 +105,14 @@ const StyledOutlinedInput = styled((props) => (
99
105
  {...props}
100
106
  />
101
107
  ))(({ theme }: StyledOutlinedInputProps) => ({
108
+ [`&.${classes.outlineInputRoot}.${classes.outlineInputFocused}`]: {
109
+ backgroundColor: theme.palette.action.selected,
110
+ },
102
111
  [`& .${classes.outlineInputInput}`]: {
103
112
  color: theme.palette.text.primary,
113
+ ['&:focus']: {
114
+ background: 'rgba(0,0,0,0)',
115
+ },
104
116
  },
105
117
  [`& .${classes.outlineInputInputMarginDense}`]: {
106
118
  padding: '14.5px 15px 14.5px 12px',
@@ -131,7 +143,9 @@ const StyledSelect = styled(
131
143
  horizontal: 'left',
132
144
  },
133
145
  getContentAnchorEl: null,
134
- classes: { paper: className },
146
+ classes: {
147
+ paper: className,
148
+ },
135
149
  }}
136
150
  {...props}
137
151
  />
@@ -143,27 +157,11 @@ const StyledSelect = styled(
143
157
  },
144
158
  }))
145
159
 
146
- export interface OutlinedSelectProps extends SelectProps {
147
- color?: 'primary' | 'secondary'
148
- size?: 'medium' | 'small'
149
- width?: number | 'auto'
150
- paperMaxHeight?: number | 'auto'
151
- error?: boolean
152
- hasLabel?: boolean
153
- hasShrink?: boolean
154
- placeholder: string
155
- helperText?: string
156
- disabled?: boolean
157
- SelectProps?: object | Partial<SelectProps>
158
- OutlinedInputProps?: Partial<OutlinedInputProps> & {
159
- onChange: (e: ChangeEvent<HTMLInputElement>) => void
160
- }
161
- }
162
-
163
- const OutlinedSelect = ({
160
+ export const OutlinedSelect = ({
164
161
  placeholder,
162
+ helperText,
163
+ InputProps,
165
164
  SelectProps,
166
- OutlinedInputProps,
167
165
  children,
168
166
  color = 'primary',
169
167
  size = 'medium',
@@ -172,11 +170,10 @@ const OutlinedSelect = ({
172
170
  error = false,
173
171
  hasLabel = true,
174
172
  hasShrink = false,
175
- helperText = '',
176
173
  value = '',
177
174
  disabled = false,
178
- }: OutlinedSelectProps) => {
179
- const hasAdornment = !!OutlinedInputProps?.startAdornment
175
+ }: SelectProps) => {
176
+ const hasAdornment = !!InputProps?.startAdornment
180
177
  const hasHelperText = !!helperText
181
178
  return (
182
179
  <StyledFormControl
@@ -204,7 +201,7 @@ const OutlinedSelect = ({
204
201
  color={color}
205
202
  label={hasLabel ? placeholder : undefined}
206
203
  disabled={disabled}
207
- {...OutlinedInputProps}
204
+ {...InputProps}
208
205
  />
209
206
  }
210
207
  {...SelectProps}
@@ -1,16 +1,15 @@
1
1
  import React, { useState } from 'react'
2
2
  import { Story, Meta } from '@storybook/react'
3
3
  import { Theme, styled } from '@material-ui/core/styles'
4
- import { InputAdornment, OutlinedInputProps } from '@material-ui/core'
4
+ import { InputAdornment } from '@material-ui/core'
5
5
  import { Visibility } from '@material-ui/icons'
6
- import OutlinedSelect, { OutlinedSelectProps } from './OutlinedSelect'
6
+ import { Select } from './Select'
7
7
  import SelectMenuItem from '../menu-item/SelectMenuItem'
8
-
9
- const PLACEHOLDER = '請選擇'
8
+ import { SelectProps } from '../../interfaces'
10
9
 
11
10
  export default {
12
- component: OutlinedSelect,
13
- title: 'OutlinedSelect',
11
+ component: Select,
12
+ title: 'Select',
14
13
  argTypes: {
15
14
  color: {
16
15
  type: { name: 'string', required: false },
@@ -53,7 +52,8 @@ export default {
53
52
  },
54
53
  hasLabel: {
55
54
  type: { name: 'boolean', required: false },
56
- description: 'If true, the label is displayed.',
55
+ description:
56
+ 'If true, the label is displayed. Always true on StandardSelect.',
57
57
  table: {
58
58
  type: { summary: 'boolean' },
59
59
  defaultValue: { summary: true },
@@ -121,9 +121,10 @@ export default {
121
121
  type: { summary: 'any' },
122
122
  },
123
123
  },
124
- OutlinedInputProps: {
124
+ CommonInputProps: {
125
125
  type: { name: 'any', required: false },
126
- description: 'Attributes applied to to inner OutlinedInput element.',
126
+ description:
127
+ 'Attributes applied to to inner OutlinedInput element on OutlinedSelect or Input element on StandardSelect.',
127
128
  table: {
128
129
  type: { summary: 'any' },
129
130
  },
@@ -131,10 +132,12 @@ export default {
131
132
  },
132
133
  } as Meta
133
134
 
134
- const PREFIX = 'JuiOutlinedSelect'
135
+ const PLACEHOLDER = 'Please select an option'
136
+ const ERROR_PLACEHOLDER = 'Please select an option'
137
+ const PREFIX = 'JuiSelect'
135
138
 
136
139
  const classes = {
137
- outlineInputAdornmentRoot: `${PREFIX}-outlineInputAdornmentRoot`,
140
+ inputAdornmentRoot: `${PREFIX}-inputAdornmentRoot`,
138
141
  }
139
142
 
140
143
  interface StyledInputAdornmentProps {
@@ -145,18 +148,20 @@ interface StyledInputAdornmentProps {
145
148
  const StyledInputAdornment = styled(({ disabled: _disabled, ...props }) => (
146
149
  <InputAdornment
147
150
  classes={{
148
- root: classes.outlineInputAdornmentRoot,
151
+ root: classes.inputAdornmentRoot,
149
152
  }}
150
153
  {...props}
151
154
  />
152
155
  ))(({ disabled, theme }: StyledInputAdornmentProps) => ({
153
- [`&.${classes.outlineInputAdornmentRoot}`]: {
156
+ height: '100%',
157
+ [`&.${classes.inputAdornmentRoot}`]: {
154
158
  color: disabled
155
159
  ? theme.palette.action.disabled
156
160
  : theme.palette.action.active,
157
161
  },
158
162
  }))
159
163
 
164
+ // Outlined Select start with here.
160
165
  interface OutlinedSelectWithMenuProps {
161
166
  startAdornment?: React.ReactNode
162
167
  }
@@ -164,15 +169,16 @@ interface OutlinedSelectWithMenuProps {
164
169
  const OutlinedSelectWithMenu = ({
165
170
  startAdornment,
166
171
  ...props
167
- }: OutlinedSelectProps & OutlinedSelectWithMenuProps) => {
172
+ }: SelectProps & OutlinedSelectWithMenuProps) => {
168
173
  const [item, setItem] = useState<string>('')
169
174
 
170
175
  const handleChange = (event) => {
171
176
  setItem(event.target.value)
172
177
  }
173
178
  return (
174
- <OutlinedSelect
175
- OutlinedInputProps={{
179
+ <Select
180
+ variant='outlined'
181
+ InputProps={{
176
182
  onChange: (e) => {
177
183
  handleChange(e)
178
184
  },
@@ -181,38 +187,91 @@ const OutlinedSelectWithMenu = ({
181
187
  value={item}
182
188
  {...props}
183
189
  >
184
- <SelectMenuItem width={220} value='' disabled>
190
+ <SelectMenuItem width={props.width} value='' disabled>
185
191
  {PLACEHOLDER}
186
192
  </SelectMenuItem>
187
- <SelectMenuItem width={220} value='Test'>
193
+ <SelectMenuItem width={props.width} value='Test'>
188
194
  This is a select menu item
189
195
  </SelectMenuItem>
190
- <SelectMenuItem width={220} value='Example'>
196
+ <SelectMenuItem width={props.width} value='Example'>
191
197
  Example
192
198
  </SelectMenuItem>
193
- </OutlinedSelect>
199
+ </Select>
194
200
  )
195
201
  }
196
202
 
197
- const ValueOnlyStory: Story<OutlinedSelectProps> = (args) => (
203
+ const OutlinedValueOnlyStory: Story<SelectProps> = (args) => (
198
204
  <OutlinedSelectWithMenu {...args} />
199
205
  )
200
206
 
201
- export const ValueOnly = ValueOnlyStory.bind({})
207
+ export const OutlinedValueOnly = OutlinedValueOnlyStory.bind({})
202
208
 
203
- ValueOnly.args = {
209
+ OutlinedValueOnly.args = {
204
210
  color: 'primary',
205
211
  size: 'medium',
206
212
  width: 220,
207
213
  paperMaxHeight: 412,
208
214
  hasLabel: true,
209
215
  placeholder: PLACEHOLDER,
210
- helperText: 'test',
216
+ helperText: 'Pick your choice',
211
217
  disabled: false,
212
218
  SelectProps: {},
213
219
  }
214
220
 
215
- const WithPrefixStory: Story<OutlinedSelectProps> = (args) => (
221
+ const OutlinedSelectWithError = ({
222
+ startAdornment,
223
+ ...props
224
+ }: SelectProps & OutlinedSelectWithMenuProps) => {
225
+ const [item, setItem] = useState<string>('')
226
+
227
+ const handleChange = (event) => {
228
+ setItem(event.target.value)
229
+ }
230
+ return (
231
+ <Select
232
+ variant='outlined'
233
+ InputProps={{
234
+ onChange: (e) => {
235
+ handleChange(e)
236
+ },
237
+ startAdornment,
238
+ }}
239
+ value={item}
240
+ error={item === ''}
241
+ helperText={item === '' ? ERROR_PLACEHOLDER : ''}
242
+ {...props}
243
+ >
244
+ <SelectMenuItem width={props.width} value='' disabled>
245
+ {PLACEHOLDER}
246
+ </SelectMenuItem>
247
+ <SelectMenuItem width={props.width} value='Option1'>
248
+ This is a select menu item
249
+ </SelectMenuItem>
250
+ <SelectMenuItem width={props.width} value='Option2'>
251
+ This is option 2
252
+ </SelectMenuItem>
253
+ </Select>
254
+ )
255
+ }
256
+
257
+ const OutlinedWithErrorStory: Story<SelectProps> = (args) => (
258
+ <OutlinedSelectWithError {...args} />
259
+ )
260
+
261
+ export const OutlinedWithError = OutlinedWithErrorStory.bind({})
262
+
263
+ OutlinedWithError.args = {
264
+ color: 'primary',
265
+ size: 'medium',
266
+ width: 220,
267
+ paperMaxHeight: 412,
268
+ hasLabel: true,
269
+ placeholder: PLACEHOLDER,
270
+ disabled: false,
271
+ SelectProps: {},
272
+ }
273
+
274
+ const OutlinedWithPrefixStory: Story<SelectProps> = (args) => (
216
275
  <OutlinedSelectWithMenu
217
276
  startAdornment={
218
277
  <StyledInputAdornment position='start' disabled={args.disabled}>
@@ -223,16 +282,140 @@ const WithPrefixStory: Story<OutlinedSelectProps> = (args) => (
223
282
  />
224
283
  )
225
284
 
226
- export const WithPrefix = WithPrefixStory.bind({})
285
+ export const OutlinedWithPrefix = OutlinedWithPrefixStory.bind({})
227
286
 
228
- WithPrefix.args = {
287
+ OutlinedWithPrefix.args = {
229
288
  color: 'primary',
230
289
  size: 'medium',
231
290
  width: 220,
232
291
  paperMaxHeight: 412,
233
292
  hasLabel: true,
234
293
  placeholder: PLACEHOLDER,
235
- helperText: 'test',
294
+ helperText: 'Pick your choice',
236
295
  disabled: false,
237
296
  SelectProps: {},
238
297
  }
298
+
299
+ // Standard Select start with here.
300
+ const StandardSelectWithMenu = (props: SelectProps) => {
301
+ const [item, setItem] = useState<string>('')
302
+
303
+ const handleChange = (event) => {
304
+ setItem(event.target.value)
305
+ }
306
+
307
+ return (
308
+ <Select
309
+ variant='standard'
310
+ value={item}
311
+ SelectProps={{
312
+ onChange: (e) => {
313
+ handleChange(e)
314
+ },
315
+ }}
316
+ {...props}
317
+ >
318
+ <SelectMenuItem width={props.width} value='' disabled>
319
+ {PLACEHOLDER}
320
+ </SelectMenuItem>
321
+ <SelectMenuItem width={props.width} value='Option1'>
322
+ This is a select menu item
323
+ </SelectMenuItem>
324
+ <SelectMenuItem width={props.width} value='Option2'>
325
+ This is option 2
326
+ </SelectMenuItem>
327
+ </Select>
328
+ )
329
+ }
330
+
331
+ const StandardValueOnlyStory: Story<SelectProps> = (args) => (
332
+ <StandardSelectWithMenu {...args} />
333
+ )
334
+
335
+ export const StandardValueOnly = StandardValueOnlyStory.bind({})
336
+
337
+ StandardValueOnly.args = {
338
+ color: 'primary',
339
+ size: 'medium',
340
+ width: 300,
341
+ paperMaxHeight: 300,
342
+ hasShrink: false,
343
+ placeholder: PLACEHOLDER,
344
+ helperText: 'Pick your choice',
345
+ disabled: false,
346
+ }
347
+
348
+ const StandardSelectWithError = (props: SelectProps) => {
349
+ const [item, setItem] = useState<string>('')
350
+
351
+ const handleChange = (event) => {
352
+ setItem(event.target.value)
353
+ }
354
+
355
+ return (
356
+ <Select
357
+ variant='standard'
358
+ value={item}
359
+ SelectProps={{
360
+ onChange: (e) => {
361
+ handleChange(e)
362
+ },
363
+ }}
364
+ error={item === ''}
365
+ helperText={item === '' ? ERROR_PLACEHOLDER : ''}
366
+ {...props}
367
+ >
368
+ <SelectMenuItem width={props.width} value='' disabled>
369
+ {PLACEHOLDER}
370
+ </SelectMenuItem>
371
+ <SelectMenuItem width={props.width} value={'Test'}>
372
+ This is a select menu item, This is a select menu item
373
+ </SelectMenuItem>
374
+ <SelectMenuItem width={props.width} value={'Example'}>
375
+ Example
376
+ </SelectMenuItem>
377
+ </Select>
378
+ )
379
+ }
380
+
381
+ const StandardWithErrorStory: Story<SelectProps> = (args) => (
382
+ <StandardSelectWithError {...args} />
383
+ )
384
+
385
+ export const StandardWithError = StandardWithErrorStory.bind({})
386
+
387
+ StandardWithError.args = {
388
+ color: 'primary',
389
+ size: 'medium',
390
+ width: 300,
391
+ paperMaxHeight: 300,
392
+ hasShrink: false,
393
+ placeholder: PLACEHOLDER,
394
+ disabled: false,
395
+ }
396
+
397
+ const StandardWithPrefixStory: Story<SelectProps> = (args) => (
398
+ <StandardSelectWithMenu
399
+ InputProps={{
400
+ startAdornment: (
401
+ <StyledInputAdornment position='start' disabled={args.disabled}>
402
+ <Visibility />
403
+ </StyledInputAdornment>
404
+ ),
405
+ }}
406
+ {...args}
407
+ />
408
+ )
409
+
410
+ export const StandardWithPrefix = StandardWithPrefixStory.bind({})
411
+
412
+ StandardWithPrefix.args = {
413
+ color: 'primary',
414
+ size: 'medium',
415
+ width: 300,
416
+ paperMaxHeight: 300,
417
+ hasShrink: false,
418
+ placeholder: PLACEHOLDER,
419
+ helperText: 'Pick your choice',
420
+ disabled: false,
421
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react'
2
+ import { OutlinedSelect } from './OutlinedSelect'
3
+ import { StandardSelect } from './StandardSelect'
4
+ import { SelectProps } from '../../interfaces'
5
+
6
+ export function Select({ variant, ...props }: SelectProps) {
7
+ if (variant === 'outlined') {
8
+ return <OutlinedSelect {...props} />
9
+ }
10
+ return <StandardSelect {...props} />
11
+ }
12
+
13
+ export default Select
@@ -4,12 +4,10 @@ import {
4
4
  InputLabel,
5
5
  FormControl,
6
6
  Select,
7
- SelectProps,
8
7
  Input,
9
- InputProps,
10
8
  FormHelperText,
11
- InputAdornment,
12
9
  } from '@material-ui/core'
10
+ import { SelectProps } from '../../interfaces'
13
11
 
14
12
  // self-defined-components
15
13
  const PREFIX = 'JuiStandardSelect'
@@ -18,6 +16,9 @@ const classes = {
18
16
  inputLabelFocused: `${PREFIX}-inputLabelFocused`,
19
17
  inputLabelMarginDense: `${PREFIX}-inputLabelMarginDense`,
20
18
  inputLabelError: `${PREFIX}-inputLabelError`,
19
+ inputRoot: `${PREFIX}-inputRoot`,
20
+ inputFocused: `${PREFIX}-inputFocused`,
21
+ inputInput: `${PREFIX}-input`,
21
22
  inputUnderline: `${PREFIX}-inputUnderline`,
22
23
  inputError: `${PREFIX}-inputError`,
23
24
  inputDisabled: `${PREFIX}-inputDisabled`,
@@ -102,6 +103,9 @@ interface StyledInputProps {
102
103
  const StyledInput = styled(({ color: _color, ...props }) => (
103
104
  <Input
104
105
  classes={{
106
+ root: classes.inputRoot,
107
+ focused: classes.inputFocused,
108
+ input: classes.inputInput,
105
109
  disabled: classes.inputDisabled,
106
110
  underline: classes.inputUnderline,
107
111
  error: classes.inputError,
@@ -110,6 +114,14 @@ const StyledInput = styled(({ color: _color, ...props }) => (
110
114
  />
111
115
  ))(({ color, theme }: StyledInputProps) => ({
112
116
  color: theme.palette.text.primary,
117
+ [`&.${classes.inputRoot}.${classes.inputFocused}`]: {
118
+ backgroundColor: theme.palette.action.selected,
119
+ },
120
+ [`& .${classes.inputInput}`]: {
121
+ ['&:focus']: {
122
+ background: 'rgba(0,0,0,0)',
123
+ },
124
+ },
113
125
  [`&.${classes.inputUnderline}:not(.${classes.inputDisabled}):not(.${classes.inputError})`]: {
114
126
  [`&:after,&:hover:before`]: {
115
127
  borderBottomColor: theme.palette[color].main,
@@ -122,20 +134,6 @@ const StyledInput = styled(({ color: _color, ...props }) => (
122
134
  },
123
135
  }))
124
136
 
125
- export interface StandardSelectProps extends SelectProps {
126
- color?: 'primary' | 'secondary'
127
- size?: 'medium' | 'small'
128
- width?: number | 'auto'
129
- paperMaxHeight?: number | 'auto'
130
- error?: boolean
131
- hasShrink?: boolean
132
- placeholder: string
133
- helperText?: string
134
- InputProps?: object & Partial<InputProps>
135
- disabled?: boolean
136
- SelectProps?: object | Partial<SelectProps>
137
- }
138
-
139
137
  export function StandardSelect({
140
138
  placeholder,
141
139
  helperText,
@@ -150,7 +148,7 @@ export function StandardSelect({
150
148
  hasShrink = false,
151
149
  value = '',
152
150
  disabled = false,
153
- }: StandardSelectProps) {
151
+ }: SelectProps) {
154
152
  const hasAdornment = !!InputProps?.startAdornment
155
153
  const hasHelperText = !!helperText
156
154
  return (
@@ -4,7 +4,7 @@ import {
4
4
  TopicFilter as JuiTopicFilter,
5
5
  TopicFilterProps as JuiTopicFilterProps,
6
6
  } from './TopicFilter'
7
- import { topicTree } from '../utils/topicTree'
7
+ import { topicTree } from '../../utils/topicTree'
8
8
 
9
9
  export default {
10
10
  component: JuiTopicFilter,
@@ -1,9 +1,9 @@
1
1
  import React, { useState, useEffect } from 'react'
2
2
  import { Theme, styled } from '@material-ui/core/styles'
3
3
  import ArrowRightRoundedIcon from '@material-ui/icons/ArrowRightRounded'
4
- import type { ITopicTreeNode } from '../interfaces'
5
- import OutlinedSelect from './select/OutlinedSelect'
6
- import SelectMenuItem from './menu-item/SelectMenuItem'
4
+ import type { ITopicTreeNode } from '../../interfaces'
5
+ import OutlinedSelect from '../select/OutlinedSelect'
6
+ import SelectMenuItem from '../menu-item/SelectMenuItem'
7
7
 
8
8
  // self-defined-configs
9
9
  const PLACEHOLDER = '請選擇'
@@ -150,7 +150,7 @@ export const TopicFilter = ({
150
150
  SelectProps={{
151
151
  'data-testid': `layered-topic-${layerNumber}`,
152
152
  }}
153
- OutlinedInputProps={{
153
+ InputProps={{
154
154
  inputProps: {
155
155
  'aria-label': `layered-topic-${layerNumber}`,
156
156
  },
@@ -1,10 +0,0 @@
1
- import { render } from '@testing-library/react'
2
-
3
- import TopicFilter from './TopicFilter'
4
-
5
- describe('TopicFilter', () => {
6
- it('should render successfully', () => {
7
- const { baseElement } = render(<TopicFilter />)
8
- expect(baseElement).toBeTruthy()
9
- })
10
- })
@@ -1,10 +0,0 @@
1
- import { render } from '@testing-library/react'
2
-
3
- import SelectMenuItem from './SelectMenuItem'
4
-
5
- describe('SelectMenuItem', () => {
6
- it('should render successfully', () => {
7
- const { baseElement } = render(<SelectMenuItem />)
8
- expect(baseElement).toBeTruthy()
9
- })
10
- })
@@ -1,10 +0,0 @@
1
- import { render } from '@testing-library/react'
2
-
3
- import OutlinedSelect from './OutlinedSelect'
4
-
5
- describe('OutlinedSelect', () => {
6
- it('should render successfully', () => {
7
- const { baseElement } = render(<OutlinedSelect />)
8
- expect(baseElement).toBeTruthy()
9
- })
10
- })
@@ -1,221 +0,0 @@
1
- import React, { useState } from 'react'
2
- import { Story, Meta } from '@storybook/react'
3
- import { Theme, styled } from '@material-ui/core/styles'
4
- import { InputAdornment } from '@material-ui/core'
5
- import { Visibility } from '@material-ui/icons'
6
- import { StandardSelect, StandardSelectProps } from './StandardSelect'
7
- import SelectMenuItem from '../menu-item/SelectMenuItem'
8
-
9
- const PLACEHOLDER = '請選擇'
10
-
11
- export default {
12
- component: StandardSelect,
13
- title: 'StandardSelect',
14
- argTypes: {
15
- color: {
16
- type: { name: 'string', required: false },
17
- description:
18
- 'The color of the component. It supports those theme colors that make sense for this component.',
19
- table: {
20
- type: { summary: 'primary | secondary' },
21
- defaultValue: { summary: 'primary' },
22
- },
23
- options: ['primary', 'secondary'],
24
- control: { type: 'radio' },
25
- },
26
- size: {
27
- type: { name: 'string', required: false },
28
- description: `Adjust size`,
29
- table: {
30
- type: { summary: 'medium | small' },
31
- defaultValue: { summary: 'medium' },
32
- },
33
- options: ['small', 'medium'],
34
- control: { type: 'radio' },
35
- },
36
- width: {
37
- type: { name: 'number', required: false },
38
- description: `Adjust width`,
39
- table: {
40
- type: { summary: 'number' },
41
- defaultValue: { summary: 'auto' },
42
- },
43
- control: { type: 'number' },
44
- },
45
- paperMaxHeight: {
46
- type: { name: 'number', required: false },
47
- description: `Adjust select menu paper max height.`,
48
- table: {
49
- type: { summary: 'number' },
50
- defaultValue: { summary: 'auto' },
51
- },
52
- control: { type: 'number' },
53
- },
54
- hasShrink: {
55
- type: { name: 'boolean', required: false },
56
- description: 'If true, the label is displayed and shrunk.',
57
- table: {
58
- type: { summary: 'boolean' },
59
- defaultValue: { summary: true },
60
- },
61
- control: { type: 'boolean' },
62
- },
63
- placeholder: {
64
- type: { name: 'string', required: true },
65
- description: `The label title`,
66
- table: {
67
- type: { summary: 'string' },
68
- defaultValue: { summary: '請選擇' },
69
- },
70
- control: { type: 'text' },
71
- },
72
- value: {
73
- type: { name: 'any', required: false },
74
- description: `The input value. Providing an empty string will select no options. This prop is required when the native prop is false (default). Set to an empty string '' if you don't want any of the available options to be selected.
75
- If the value is an object it must have reference equality with the option in order to be selected. If the value is not an object, the string representation must match with the string representation of the option in order to be selected.`,
76
- table: {
77
- type: { summary: 'any' },
78
- defaultValue: { summary: '' },
79
- },
80
- },
81
- disabled: {
82
- type: { name: 'boolean', required: false },
83
- description: 'If true, the input element will be disabled.',
84
- table: {
85
- type: { summary: 'boolean' },
86
- defaultValue: { summary: false },
87
- },
88
- control: { type: 'boolean' },
89
- },
90
- error: {
91
- type: { name: 'boolean', required: false },
92
- description: 'If true, the label will be displayed in an error state.',
93
- table: {
94
- type: { summary: 'boolean' },
95
- defaultValue: { summary: false },
96
- },
97
- control: { type: 'boolean' },
98
- },
99
- helperText: {
100
- type: { name: 'string', required: true },
101
- description: `Display the helper text.`,
102
- table: {
103
- type: { summary: 'string' },
104
- defaultValue: { summary: '' },
105
- },
106
- control: { type: 'text' },
107
- },
108
- InputProps: {
109
- type: { name: 'any', required: false },
110
- description: 'Attributes applied to inner Input element.',
111
- table: {
112
- type: { summary: 'any' },
113
- },
114
- },
115
- SelectProps: {
116
- type: { name: 'any', required: false },
117
- description: 'Attributes applied to inner Select element.',
118
- table: {
119
- type: { summary: 'any' },
120
- },
121
- },
122
- },
123
- } as Meta
124
-
125
- const PREFIX = 'JuiStandardSelect'
126
-
127
- const classes = {
128
- inputAdornmentRoot: `${PREFIX}-inputAdornmentRoot`,
129
- }
130
- interface StyledInputAdornmentProps {
131
- theme: Theme
132
- disabled: boolean
133
- }
134
-
135
- const StyledInputAdornment = styled(({ disabled: _disabled, ...props }) => (
136
- <InputAdornment
137
- classes={{
138
- root: classes.inputAdornmentRoot,
139
- }}
140
- {...props}
141
- />
142
- ))(({ disabled, theme }: StyledInputAdornmentProps) => ({
143
- [`&.${classes.inputAdornmentRoot}`]: {
144
- color: disabled
145
- ? theme.palette.action.disabled
146
- : theme.palette.action.active,
147
- },
148
- }))
149
-
150
- const StandardSelectWithMenu = (props: StandardSelectProps) => {
151
- const [item, setItem] = useState<string>('')
152
-
153
- const handleChange = (event) => {
154
- setItem(event.target.value)
155
- }
156
-
157
- return (
158
- <StandardSelect
159
- value={item}
160
- SelectProps={{
161
- onChange: (e) => {
162
- handleChange(e)
163
- },
164
- }}
165
- {...props}
166
- >
167
- <SelectMenuItem width={300} value='' disabled>
168
- {PLACEHOLDER}
169
- </SelectMenuItem>
170
- <SelectMenuItem width={300} value={'Test'}>
171
- This is a select menu item, This is a select menu item
172
- </SelectMenuItem>
173
- <SelectMenuItem width={300} value={'Example'}>
174
- Example
175
- </SelectMenuItem>
176
- </StandardSelect>
177
- )
178
- }
179
-
180
- const ValueOnlyStory: Story<StandardSelectProps> = (args) => (
181
- <StandardSelectWithMenu {...args} />
182
- )
183
-
184
- export const ValueOnly = ValueOnlyStory.bind({})
185
-
186
- ValueOnly.args = {
187
- color: 'primary',
188
- size: 'medium',
189
- width: 220,
190
- paperMaxHeight: 300,
191
- hasShrink: false,
192
- placeholder: PLACEHOLDER,
193
- helperText: 'test',
194
- disabled: false,
195
- }
196
-
197
- const WithPrefixStory: Story<StandardSelectProps> = (args) => (
198
- <StandardSelectWithMenu
199
- InputProps={{
200
- startAdornment: (
201
- <StyledInputAdornment position='start' disabled={args.disabled}>
202
- <Visibility />
203
- </StyledInputAdornment>
204
- ),
205
- }}
206
- {...args}
207
- />
208
- )
209
-
210
- export const WithPrefix = WithPrefixStory.bind({})
211
-
212
- WithPrefix.args = {
213
- color: 'primary',
214
- size: 'medium',
215
- width: 300,
216
- paperMaxHeight: 300,
217
- hasShrink: false,
218
- placeholder: PLACEHOLDER,
219
- helperText: 'test',
220
- disabled: false,
221
- }