@material-ui/core#Input TypeScript Examples
The following examples show how to use
@material-ui/core#Input.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SelectAndTextInputContainer.stories.tsx From anchor-web-app with Apache License 2.0 | 6 votes |
Basic = () => {
const [selectedItem, setSelectedItem] = useState<Item>(() => items[0]);
return (
<SelectAndTextInputContainer gridColumns={[120, '1fr']}>
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
</SelectAndTextInputContainer>
);
}
Example #2
Source File: SaveAsMissionForm.tsx From project-tauntaun with GNU Lesser General Public License v3.0 | 6 votes |
export function SaveAsMissionForm() {
const { setShowSaveAsMissionForm } = AppStateContainer.useContainer();
const [filename, setFilename] = useState('');
const onSaveClick = () => {
gameService.sendSaveMission(filename);
console.log(`Saving mission ${filename}`);
setShowSaveAsMissionForm(false);
};
return (
<div className="PopupBig">
<span>Filename:</span>
<Input onChange={e => setFilename(e.target.value)}></Input>
<button onClick={onSaveClick}>Save</button>
<button onClick={() => setShowSaveAsMissionForm(false)}>Close</button>
</div>
);
}
Example #3
Source File: NumberMuiInput.tsx From anchor-web-app with Apache License 2.0 | 6 votes |
export function NumberMuiInput({
type = 'decimal',
maxDecimalPoints,
maxIntegerPoinsts,
onChange,
inputMode = type === 'decimal' ? 'decimal' : 'numeric',
pattern = '[0-9.]*',
...props
}: NumberMuiInputProps) {
const handlers = useRestrictedNumberInput({
type,
maxIntegerPoinsts,
maxDecimalPoints,
onChange,
});
return (
<Input
{...props}
type="text"
inputProps={{
inputMode,
pattern,
}}
{...handlers}
/>
);
}
Example #4
Source File: SelectAndTextInputContainer.stories.tsx From anchor-web-app with Apache License 2.0 | 6 votes |
Disabled = () => {
const [selectedItem, setSelectedItem] = useState<Item>(() => items[0]);
return (
<SelectAndTextInputContainer gridColumns={[120, '1fr']} aria-disabled>
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
</SelectAndTextInputContainer>
);
}
Example #5
Source File: SelectAndTextInputContainer.stories.tsx From anchor-web-app with Apache License 2.0 | 6 votes |
Readonly = () => {
const [selectedItem, setSelectedItem] = useState<Item>(() => items[0]);
return (
<SelectAndTextInputContainer gridColumns={[120, '1fr']} aria-readonly>
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
</SelectAndTextInputContainer>
);
}
Example #6
Source File: SelectAndTextInputContainer.stories.tsx From anchor-web-app with Apache License 2.0 | 6 votes |
HelperText = () => {
const [selectedItem, setSelectedItem] = useState<Item>(() => items[0]);
return (
<SelectAndTextInputContainer
gridColumns={[120, '1fr']}
leftHelperText="LEFT"
rightHelperText="RIGHT"
>
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
</SelectAndTextInputContainer>
);
}
Example #7
Source File: PasswordForm.tsx From project-tauntaun with GNU Lesser General Public License v3.0 | 6 votes |
export function PasswordForm(props: PasswordFormProps) {
const { onOk, onCancel } = props;
const [password, setPassword] = useState('');
return (
<div className="Popup">
<p>Enter password</p>
<Input
type="password"
onChange={(event: React.ChangeEvent<HTMLInputElement>) => setPassword(event.target.value)}
/>
<div>
<button onClick={() => onOk(password)}>OK</button>
<button onClick={() => onCancel()}>Cancel</button>
</div>
</div>
);
}
Example #8
Source File: StationSelectInput.tsx From metro-fare with MIT License | 6 votes |
StationSelectInput = ({
title,
value,
onFocus,
}: StationSelectInputProps) => {
const { i18n } = useTranslation();
const stationElementId = `${title}-native-required`;
const station = STATIONS.find((station) => station.id === value);
const getStationLabel = (station: Station | undefined) => {
if (!station) return "";
const lineType = getLineTypeLabel(station.lineType);
const stationName = getStationName(station, i18n.language);
return station ? `${lineType} [${station.id}] ${stationName}` : "";
};
const label = getStationLabel(station);
return (
<div className="station-select-input" onFocus={onFocus}>
<InputLabel htmlFor={stationElementId}>{title}</InputLabel>
<Input className="station-input" value={label} />
</div>
);
}
Example #9
Source File: CalendarSelect.tsx From backstage with Apache License 2.0 | 5 votes |
CalendarSelect = ({
disabled,
selectedCalendars = [],
setSelectedCalendars,
calendars,
}: CalendarSelectProps) => {
const classes = useStyles();
return (
<FormControl className={classes.formControl}>
<Select
labelId="calendars-label"
disabled={disabled || calendars.length === 0}
multiple
value={selectedCalendars}
onChange={async e => setSelectedCalendars(e.target.value as string[])}
input={<Input />}
renderValue={selected => (
<Typography className={classes.selectedCalendars} variant="body2">
{calendars
.filter(c => c.id && (selected as string[]).includes(c.id))
.map(c => c.summary)
.join(', ')}
</Typography>
)}
MenuProps={{
PaperProps: {
style: {
width: 350,
},
},
}}
>
{sortBy(calendars, 'summary').map(c => (
<MenuItem key={c.id} value={c.id}>
<Checkbox checked={selectedCalendars.includes(c.id!)} />
<ListItemText primary={c.summary} />
</MenuItem>
))}
</Select>
</FormControl>
);
}
Example #10
Source File: RadarPage.tsx From backstage with Apache License 2.0 | 5 votes |
/**
* Main Page of Tech Radar
*/
export function RadarPage(props: TechRadarPageProps) {
const {
title = 'Tech Radar',
subtitle = 'Pick the recommended technologies for your projects',
pageTitle = 'Company Radar',
...componentProps
} = props;
const classes = useStyles();
const [searchText, setSearchText] = React.useState('');
return (
<Page themeId="tool">
<Header title={title} subtitle={subtitle} />
<Content className={classes.overflowXScroll}>
<ContentHeader title={pageTitle}>
<Input
id="tech-radar-filter"
type="search"
placeholder="Filter"
onChange={e => setSearchText(e.target.value)}
/>
<SupportButton>
<p>
This is used for visualizing the official guidelines of different
areas of software development such as languages, frameworks,
infrastructure and processes. You can find an explanation for the
radar at{' '}
<Link to="https://opensource.zalando.com/tech-radar/">
Zalando Tech Radar
</Link>
.
</p>
</SupportButton>
</ContentHeader>
<Grid container spacing={3} direction="row">
<Grid item xs={12} sm={6} md={4}>
<RadarComponent searchText={searchText} {...componentProps} />
</Grid>
</Grid>
</Content>
</Page>
);
}
Example #11
Source File: MapSearch.tsx From covid19testing-map with GNU General Public License v3.0 | 5 votes |
MapSearch = ({ map }: SearchProps) => {
const classes = useStyles();
const [searchBox, setSearchBox] = useState<any>();
const onLoad = (ref: any) => {
setSearchBox(ref);
};
const onPlacesChanged = () => {
if (searchBox.getPlaces()[0] !== undefined) {
map.fitBounds(searchBox.getPlaces()[0].geometry.viewport);
}
};
const { isLoaded, loadError } = useLoadScript({
googleMapsApiKey: REACT_APP_GCP_MAPS_API_KEY,
libraries,
});
const handleSearchClick = React.useCallback(() => {
trackUiClick('Search');
}, []);
const renderSearchBox = () => {
return (
<div id="search-input">
<StandaloneSearchBox onLoad={onLoad} onPlacesChanged={onPlacesChanged}>
<Input
placeholder='Search places like "Albany", "NYU", or "94025"'
className={classes.input}
inputProps={{ 'aria-label': 'search google maps' }}
onClick={handleSearchClick}
startAdornment={
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
}
/>
</StandaloneSearchBox>
</div>
);
};
if (loadError) {
return <div>Search bar cannot be loaded right now, sorry.</div>;
}
return isLoaded ? renderSearchBox() : <div />;
}
Example #12
Source File: ColorPicker.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
ColorPicker: React.SFC<Props> = ({ ...props }) => {
const [displayPicker, setDisplayPicker] = useState(false);
const [colorHex, setColorHex] = useState('');
const { t } = useTranslation();
const { colorCode, name, helperText } = props;
useEffect(() => {
setColorHex(colorCode);
}, [colorCode]);
const handleChangeComplete = (color: any) => {
setColorHex(color.hex);
props.form.setFieldValue(props.field.name, color.hex);
};
const onClickAway = () => {
setDisplayPicker(false);
};
return (
<div className={styles.Container}>
<div className={styles.ColorPicker} data-testid="ColorPicker">
<div className={styles.ColorInput}>
<Input type="text" placeholder={t('Select color')} name={name} value={colorHex} />
</div>
<ClickAwayListener onClickAway={onClickAway}>
<div className={styles.ContainListener}>
<div
role="button"
tabIndex={0}
data-testid="ChooseColor"
className={styles.ChooseColor}
style={{
backgroundColor: colorHex,
}}
onClick={() => setDisplayPicker(!displayPicker)}
onKeyDown={() => setDisplayPicker(!displayPicker)}
>
</div>
{helperText ? (
<FormHelperText className={styles.HelperText}>{helperText}</FormHelperText>
) : null}
{displayPicker ? (
<TwitterPicker
className={styles.PickerPanel}
triangle="hide"
onChangeComplete={handleChangeComplete}
/>
) : null}
</div>
</ClickAwayListener>
</div>
</div>
);
}
Example #13
Source File: SelectAndTextInputContainer.stories.tsx From anchor-web-app with Apache License 2.0 | 5 votes |
Multiline = () => {
const [selectedItem, setSelectedItem] = useState<Item>(() => items[0]);
return (
<SelectAndTextInputContainer
gridColumns={[120, '1fr', '1fr']}
gridRows={[60, 60, 60, 60]}
>
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
<Input placeholder="PLACEHOLDER" />
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
<Input placeholder="PLACEHOLDER" />
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
<Input placeholder="PLACEHOLDER" />
<MuiNativeSelect
value={selectedItem.value}
onChange={({ target }) =>
setSelectedItem(
items.find(({ value }) => target.value === value) ?? items[0],
)
}
>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
<Input placeholder="PLACEHOLDER" />
</SelectAndTextInputContainer>
);
}
Example #14
Source File: EntitySearchBar.tsx From backstage with Apache License 2.0 | 5 votes |
EntitySearchBar = () => {
const classes = useStyles();
const { filters, updateFilters } = useEntityList();
const [search, setSearch] = useState(filters.text?.value ?? '');
useDebounce(
() => {
updateFilters({
text: search.length ? new EntityTextFilter(search) : undefined,
});
},
250,
[search, updateFilters],
);
return (
<Toolbar className={classes.searchToolbar}>
<FormControl>
<Input
aria-label="search"
id="input-with-icon-adornment"
className={classes.input}
placeholder="Search"
autoComplete="off"
onChange={event => setSearch(event.target.value)}
value={search}
startAdornment={
<InputAdornment position="start">
<Search />
</InputAdornment>
}
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="clear search"
onClick={() => setSearch('')}
edge="end"
disabled={search.length === 0}
>
<Clear />
</IconButton>
</InputAdornment>
}
/>
</FormControl>
</Toolbar>
);
}
Example #15
Source File: settings_button.tsx From jupyter-extensions with Apache License 2.0 | 5 votes |
render() {
return (
<React.Fragment>
<IconButton
title="Settings"
color="inherit"
onClick={() => this._onClick()}
>
<SettingsIcon fontSize="small" />
</IconButton>
<Dialog
open={this.state.open}
onClose={() => this._onClose()}
fullWidth
>
<DialogTitle>Settings</DialogTitle>
<DialogContent>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={11}>
<Typography id="input-slider">Sync Frequency</Typography>
</Grid>
<Grid item xs={1}>
<Tooltip title="Time between each sync with remote repository. After each sync, the extension will wait before syncing again.">
<HelpOutlineIcon color="disabled" />
</Tooltip>
</Grid>
<Grid item xs={1}>
<TimerIcon />
</Grid>
<Grid item xs={7}>
<Slider
value={
typeof this.state.value === 'number'
? this.state.value / (this.maxInterval / 100)
: 0
}
onChange={(event, value) =>
this._onSliderChange(event, value)
}
aria-labelledby="sync-interval-slider"
/>
</Grid>
<Grid item xs={4}>
<Input
value={this.state.value}
onChange={event => this._onInputChange(event)}
onBlur={() => this._onBlur()}
margin="dense"
inputProps={{
step: 1,
min: 0,
max: this.maxInterval,
type: 'number',
'aria-labelledby': 'sync-interval-slider',
}}
endAdornment={
<InputAdornment position="end">seconds</InputAdornment>
}
/>
</Grid>
</Grid>
</DialogContent>
<DialogActions>
<Button onClick={() => this._onClose()} color="primary">
Cancel
</Button>
<Button
onClick={() => this._onSave()}
color="primary"
variant="contained"
>
Save
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
);
}
Example #16
Source File: SQFormMultiSelect.tsx From SQForm with MIT License | 4 votes |
function SQFormMultiSelect({
children,
isDisabled = false,
label,
name,
onChange,
size = 'auto',
useSelectAll = true,
toolTipPlacement = 'bottom',
muiFieldProps = {},
showTooltip = true,
tooltipText,
}: SQFormMultiSelectProps): React.ReactElement {
const classes = useStyles();
const {setFieldValue} = useFormikContext();
const [toolTipEnabled, setToolTipEnabled] = React.useState(true);
const {
formikField: {field},
fieldState: {isFieldError, isFieldRequired},
fieldHelpers: {handleBlur, HelperTextComponent},
} = useForm<SQFormOption['value'][], unknown>({name});
React.useEffect(() => {
if (!children) {
console.warn(getUndefinedChildrenWarning('SQFormMultiSelect', name));
}
if (field.value === undefined || field.value === null) {
console.warn(getUndefinedValueWarning('SQFormMultiSelect', name));
}
}, [children, field.value, name]);
const labelID = label.toLowerCase();
const toolTipTitle = getToolTipTitle(field.value, children);
const getIsSelectAllChecked = (value: SQFormOption['value'][]) =>
value.includes('ALL');
const getIsSelectNoneChecked = (value: SQFormOption['value'][]) =>
value.includes('NONE');
const getValues = (
children: SQFormMultiSelectProps['children'],
isSelectAllChecked: boolean,
isSelectNoneChecked: boolean,
value: SQFormOption['value'][]
) => {
if (isSelectAllChecked) {
return children?.map((option) => option.value);
}
if (isSelectNoneChecked) {
return [];
}
return value;
};
const handleMultiSelectChange = (
event: React.ChangeEvent<{name?: string; value: unknown}>,
_child: ReactNode
) => {
const value = event.target.value as unknown as SQFormOption['value'][];
const isSelectAllChecked = getIsSelectAllChecked(value);
const isSelectNoneChecked = getIsSelectNoneChecked(value);
const values = getValues(
children,
isSelectAllChecked,
isSelectNoneChecked,
value
);
setFieldValue(name, values);
onChange && onChange(event, value);
};
const toggleTooltip = () => {
setToolTipEnabled(!toolTipEnabled);
};
/**
* this handles scenarios where label and value are not the same,
* e.g., if value is an "ID"
*/
const getRenderValue = (selected: unknown) => {
const getValue = (selectedValues: SQFormOption['value'][]) => {
if (!selectedValues?.length) {
return EMPTY_LABEL;
}
return selectedDisplayValue(selectedValues, children, name);
};
return getValue(selected as SQFormOption['value'][]);
};
const renderTooltip = () => {
if (!showTooltip || !toolTipEnabled) {
return '';
}
return tooltipText || toolTipTitle;
};
return (
<Grid item sm={size}>
<FormControl
error={isFieldError}
disabled={isDisabled}
required={isFieldRequired}
fullWidth={true}
>
<InputLabel shrink={true} id={labelID}>
{label}
</InputLabel>
<Tooltip
placement={toolTipPlacement}
arrow={true}
enterDelay={1000}
leaveDelay={100}
title={renderTooltip()}
>
<Select
className={classes.selectHeight}
multiple
displayEmpty
input={<Input disabled={isDisabled} name={name} />}
value={(field.value as SQFormOption['value'][]) || []}
onBlur={handleBlur}
onChange={handleMultiSelectChange}
fullWidth={true}
labelId={labelID}
renderValue={getRenderValue}
MenuProps={MenuProps}
onOpen={toggleTooltip}
onClose={toggleTooltip}
{...muiFieldProps}
>
{useSelectAll && (
<MenuItem
value={
children?.length === field.value?.length ? 'NONE' : 'ALL'
}
>
<Checkbox checked={children?.length === field.value?.length} />
<ListItemText
primary="Select All"
primaryTypographyProps={{variant: 'body2'}}
/>
</MenuItem>
)}
{children?.map((option) => {
return (
<MenuItem key={`${name}_${option.value}`} value={option.value}>
<Checkbox checked={field.value?.includes(option.value)} />
<ListItemText
primary={option.label}
primaryTypographyProps={{variant: 'body2'}}
/>
</MenuItem>
);
})}
</Select>
</Tooltip>
{!isDisabled && <FormHelperText>{HelperTextComponent}</FormHelperText>}
</FormControl>
</Grid>
);
}
Example #17
Source File: start_thread.tsx From jupyter-extensions with Apache License 2.0 | 4 votes |
export function CommentEditor(props) {
const [comment, setComment] = useState('');
const [lineNumber, setLineNumber] = useState(0);
const [showLineInput, setShowLineInput] = useState(false);
const handleSubmit = event => {
event.preventDefault();
switch (props.commentType) {
case 'review':
newReviewCommentThread(
props.currFilePath,
props.serverRoot,
comment,
props.reviewHash,
lineNumber
);
break;
case 'detached':
newDetachedCommentThread(
props.currFilePath,
props.serverRoot,
comment,
lineNumber
);
break;
}
setComment(''); //clear comment editor field
setLineNumber(0);
setShowLineInput(false);
};
return (
<form
onSubmit={handleSubmit}
style={style.editor}
className="commentSubmit"
>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
<Grid container direction="column">
<Grid item>
<TextField
multiline
rows={3}
label="Start a new comment thread"
value={comment}
onChange={e => setComment(e.target.value)}
variant="outlined"
size="medium"
style={style.textField}
className="newThreadTextField"
/>
</Grid>
<Grid container direction="row" style={style.submitOptions}>
{showLineInput ? (
<Input
type="number"
value={lineNumber}
onChange={e => setLineNumber(parseInt(e.target.value))}
name="line number"
margin="none"
inputProps={{
style: {
width: '40px',
},
min: 0,
}}
/>
) : (
<Button size="small" onClick={() => setShowLineInput(true)}>
{'Set line #'}
</Button>
)}
<Grid item style={style.submit}>
<SendButton type="sendThread" />
</Grid>
</Grid>
</Grid>
</form>
);
}
Example #18
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function Analyser({ extent, classes }: AnalyserProps) {
const dispatch = useDispatch();
const map = useSelector(mapSelector);
const selectedLayers = useSelector(layersSelector);
const {
updateHistory,
removeKeyFromUrl,
resetAnalysisParams,
updateAnalysisParams,
getAnalysisParams,
} = useUrlHistory();
const availableDates = useSelector(availableDatesSelector);
const analysisResult = useSelector(analysisResultSelector);
const isAnalysisLoading = useSelector(isAnalysisLoadingSelector);
const isMapLayerActive = useSelector(isAnalysisLayerActiveSelector);
const {
analysisHazardLayerId: hazardLayerIdFromUrl,
analysisBaselineLayerId: baselineLayerIdFromUrl,
analysisDate: selectedDateFromUrl,
analysisStatistic: selectedStatisticFromUrl,
analysisThresholdAbove: aboveThresholdFromUrl,
analysisThresholdBelow: belowThresholdFromUrl,
analysisAdminLevel: adminLevelFromUrl,
analysisStartDate: selectedStartDateFromUrl,
analysisEndDate: selectedEndDateFromUrl,
} = getAnalysisParams();
// form elements
const [hazardLayerId, setHazardLayerId] = useState<LayerKey | undefined>(
hazardLayerIdFromUrl,
);
const [statistic, setStatistic] = useState(
(selectedStatisticFromUrl as AggregationOperations) ||
AggregationOperations.Mean,
);
const [baselineLayerId, setBaselineLayerId] = useState<LayerKey | undefined>(
baselineLayerIdFromUrl,
);
const [selectedDate, setSelectedDate] = useState<number | null>(null);
const [belowThreshold, setBelowThreshold] = useState(
belowThresholdFromUrl || '',
);
const [aboveThreshold, setAboveThreshold] = useState(
aboveThresholdFromUrl || '',
);
const [thresholdError, setThresholdError] = useState<string | null>(null);
const [isAnalyserFormOpen, setIsAnalyserFormOpen] = useState<boolean>(
hazardLayerIdFromUrl !== undefined,
);
const [isTableViewOpen, setIsTableViewOpen] = useState(true);
// for polygon intersection analysis
const [adminLevel, setAdminLevel] = useState<AdminLevelType>(
Number(adminLevelFromUrl || '1') as AdminLevelType,
);
const [startDate, setStartDate] = useState<number | null>(null);
const [endDate, setEndDate] = useState<number | null>(null);
// find layer for the given adminLevel
const adminLevelLayer = getAdminLevelLayer(adminLevel);
const adminLevelLayerData = useSelector(
// if we couldn't find an admin layer, just return undefined
adminLevelLayer ? layerDataSelector(adminLevelLayer.id) : () => undefined,
) as LayerData<BoundaryLayerProps> | undefined;
// get variables derived from state
const selectedHazardLayer = hazardLayerId
? (LayerDefinitions[hazardLayerId] as WMSLayerProps)
: null;
const hazardDataType: HazardDataType | null = selectedHazardLayer
? selectedHazardLayer.geometry || RasterType.Raster
: null;
const availableHazardDates = selectedHazardLayer
? getPossibleDatesForLayer(selectedHazardLayer, availableDates)?.map(
d => new Date(d),
) || []
: undefined;
const BASELINE_URL_LAYER_KEY = 'baselineLayerId';
const preSelectedBaselineLayer = selectedLayers.find(
l => l.type === 'admin_level_data',
);
const [previousBaselineId, setPreviousBaselineId] = useState<
LayerKey | undefined
>(preSelectedBaselineLayer?.id);
const { t } = useSafeTranslation();
// check if there is any available date from the url, otherwise use last available date for the selected hazard layer
const lastAvailableHazardDate = availableHazardDates
? getDateFromList(
selectedDateFromUrl ? new Date(selectedDateFromUrl) : null,
availableHazardDates,
)?.getTime() || null
: null;
const lastAvailableHazardStartDate = availableHazardDates
? getDateFromList(
selectedStartDateFromUrl ? new Date(selectedStartDateFromUrl) : null,
availableHazardDates,
)?.getTime() || null
: null;
const lastAvailableHazardEndDate = availableHazardDates
? getDateFromList(
selectedEndDateFromUrl ? new Date(selectedEndDateFromUrl) : null,
availableHazardDates,
)?.getTime() || null
: null;
const { translatedColumns } = useAnalysisTableColumns(analysisResult);
// set default date after dates finish loading and when hazard layer changes
useEffect(() => {
if (isNil(lastAvailableHazardDate)) {
setSelectedDate(null);
} else {
setSelectedDate(lastAvailableHazardDate);
}
if (isNil(lastAvailableHazardStartDate)) {
setStartDate(null);
} else {
setStartDate(lastAvailableHazardStartDate);
}
if (isNil(lastAvailableHazardEndDate)) {
setEndDate(null);
} else {
setEndDate(lastAvailableHazardEndDate);
}
}, [
availableDates,
hazardLayerId,
lastAvailableHazardDate,
lastAvailableHazardStartDate,
lastAvailableHazardEndDate,
]);
const onOptionChange = <T extends string>(
setterFunc: Dispatch<SetStateAction<T>>,
) => (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value as T;
setterFunc(value);
return value;
};
// specially for threshold values, also does error checking
const onThresholdOptionChange = (thresholdType: 'above' | 'below') => (
event: React.ChangeEvent<HTMLInputElement>,
) => {
const setterFunc =
thresholdType === 'above' ? setAboveThreshold : setBelowThreshold;
const changedOption = onOptionChange(setterFunc)(event);
// setting a value doesn't update the existing value until next render, therefore we must decide whether to access the old one or the newly change one here.
const aboveThresholdValue = parseFloat(
thresholdType === 'above' ? changedOption : aboveThreshold,
);
const belowThresholdValue = parseFloat(
thresholdType === 'below' ? changedOption : belowThreshold,
);
if (belowThresholdValue > aboveThresholdValue) {
setThresholdError('Below threshold is larger than above threshold!');
} else {
setThresholdError(null);
}
};
const statisticOptions = Object.entries(AggregationOperations)
.filter(([, value]) => value !== AggregationOperations.Sum) // sum is used only for exposure analysis.
.map(([key, value]) => (
<FormControlLabel
key={key}
value={value}
control={
<Radio
className={classes.radioOptions}
color="default"
size="small"
/>
}
label={t(key)}
/>
));
const activateUniqueBoundary = (forceAdminLevel?: BoundaryLayerProps) => {
if (forceAdminLevel) {
// remove displayed boundaries
getDisplayBoundaryLayers().forEach(l => {
if (l.id !== forceAdminLevel.id) {
safeDispatchRemoveLayer(map, l, dispatch);
}
});
safeDispatchAddLayer(
map,
{ ...forceAdminLevel, isPrimary: true },
dispatch,
);
return;
}
if (!baselineLayerId) {
throw new Error('Layer should be selected to run analysis');
}
const baselineLayer = LayerDefinitions[
baselineLayerId
] as AdminLevelDataLayerProps;
if (baselineLayer.boundary) {
const boundaryLayer = LayerDefinitions[
baselineLayer.boundary
] as BoundaryLayerProps;
// remove displayed boundaries
getDisplayBoundaryLayers().forEach(l => {
if (l.id !== boundaryLayer.id) {
safeDispatchRemoveLayer(map, l, dispatch);
}
});
safeDispatchAddLayer(
map,
{ ...boundaryLayer, isPrimary: true },
dispatch,
);
} else {
getDisplayBoundaryLayers().forEach(l => {
safeDispatchAddLayer(map, l, dispatch);
});
}
};
const deactivateUniqueBoundary = () => {
if (!baselineLayerId) {
throw new Error('Layer should be selected to run analysis');
}
const baselineLayer = LayerDefinitions[
baselineLayerId
] as AdminLevelDataLayerProps;
if (baselineLayer.boundary) {
const boundaryLayer = LayerDefinitions[
baselineLayer.boundary
] as BoundaryLayerProps;
if (!getDisplayBoundaryLayers().includes(boundaryLayer)) {
safeDispatchRemoveLayer(map, boundaryLayer, dispatch);
}
}
getDisplayBoundaryLayers().forEach(l => {
safeDispatchAddLayer(map, l, dispatch);
});
};
const clearAnalysis = () => {
dispatch(clearAnalysisResult());
resetAnalysisParams();
if (previousBaselineId) {
const previousBaseline = LayerDefinitions[
previousBaselineId
] as AdminLevelDataLayerProps;
updateHistory(BASELINE_URL_LAYER_KEY, previousBaselineId);
safeDispatchAddLayer(map, previousBaseline, dispatch);
// check isMapLayerActive on analysis clear
// to avoid miss behaviour on boundary layers
dispatch(setIsMapLayerActive(true));
}
};
const shareAnalysis = () => {
copyTextToClipboard(window.location.href).then(() => {
dispatch(
addNotification({
message: 'Link to this analysis copied to clipboard!',
type: 'success',
}),
);
});
};
const onMapSwitchChange = (e: ChangeEvent<HTMLInputElement>) => {
dispatch(setIsMapLayerActive(e.target.checked));
// hazard layer doesn't needs a display boundary
// because it is already a vector
if (hazardDataType === GeometryType.Polygon) {
return;
}
if (isMapLayerActive) {
deactivateUniqueBoundary();
// check for previous baseline and bring it back
if (previousBaselineId) {
const previousBaseline = LayerDefinitions[
previousBaselineId
] as AdminLevelDataLayerProps;
updateHistory(BASELINE_URL_LAYER_KEY, previousBaselineId);
safeDispatchAddLayer(map, previousBaseline, dispatch);
}
} else {
// check for previous baseline and remove it before...
if (previousBaselineId) {
const previousBaseline = LayerDefinitions[
previousBaselineId
] as AdminLevelDataLayerProps;
removeKeyFromUrl(BASELINE_URL_LAYER_KEY);
safeDispatchRemoveLayer(map, previousBaseline, dispatch);
}
// activating the unique boundary layer
activateUniqueBoundary();
}
};
const runAnalyser = async () => {
if (preSelectedBaselineLayer) {
setPreviousBaselineId(preSelectedBaselineLayer.id);
removeKeyFromUrl(BASELINE_URL_LAYER_KEY);
// no need to safely dispatch remove we are sure
dispatch(removeLayer(preSelectedBaselineLayer));
}
if (analysisResult) {
clearAnalysis();
}
if (!extent) {
return;
} // hasn't been calculated yet
if (!selectedHazardLayer) {
throw new Error('Hazard layer should be selected to run analysis');
}
if (hazardDataType === GeometryType.Polygon) {
if (!startDate) {
throw new Error('Date Range must be given to run analysis');
}
if (!endDate) {
throw new Error('Date Range must be given to run analysis');
}
if (!adminLevelLayer || !adminLevelLayerData) {
// technically we can't get here because the run analaysis button
// is disabled while the admin level data loads
// but we have to put this in so the typescript compiler
// doesn't throw an error when we try to access the data
// property of adminLevelLayerData
throw new Error('Admin level data is still loading');
}
const params: PolygonAnalysisDispatchParams = {
hazardLayer: selectedHazardLayer,
adminLevel,
adminLevelLayer,
adminLevelData: adminLevelLayerData.data,
startDate,
endDate,
extent,
};
activateUniqueBoundary(adminLevelLayer);
// update history
updateAnalysisParams({
analysisHazardLayerId: hazardLayerId,
analysisAdminLevel: adminLevel.toString(),
analysisStartDate: moment(startDate).format(DEFAULT_DATE_FORMAT),
analysisEndDate: moment(endDate).format(DEFAULT_DATE_FORMAT),
analysisStatistic: statistic,
});
dispatch(requestAndStorePolygonAnalysis(params));
} else {
if (!selectedDate) {
throw new Error('Date must be given to run analysis');
}
if (!baselineLayerId) {
throw new Error('Baseline layer should be selected to run analysis');
}
const selectedBaselineLayer = LayerDefinitions[
baselineLayerId
] as AdminLevelDataLayerProps;
activateUniqueBoundary();
const params: AnalysisDispatchParams = {
hazardLayer: selectedHazardLayer,
baselineLayer: selectedBaselineLayer,
date: selectedDate,
statistic,
extent,
threshold: {
above: parseFloat(aboveThreshold) || undefined,
below: parseFloat(belowThreshold) || undefined,
},
};
// update history
updateAnalysisParams({
analysisHazardLayerId: hazardLayerId,
analysisBaselineLayerId: baselineLayerId,
analysisDate: moment(selectedDate).format(DEFAULT_DATE_FORMAT),
analysisStatistic: statistic,
analysisThresholdAbove: aboveThreshold || undefined,
analysisThresholdBelow: belowThreshold || undefined,
});
dispatch(requestAndStoreAnalysis(params));
}
};
return (
<div className={classes.analyser}>
<Button
variant="contained"
color="primary"
onClick={() => {
setIsAnalyserFormOpen(!isAnalyserFormOpen);
}}
>
<BarChart fontSize="small" />
<Typography variant="body2" className={classes.analyserLabel}>
{t('Run Analysis')}
</Typography>
<ArrowDropDown fontSize="small" />
</Button>
<Box
className={classes.analyserMenu}
width={isAnalyserFormOpen ? 'min-content' : 0}
padding={isAnalyserFormOpen ? '10px' : 0}
>
{isAnalyserFormOpen ? (
<div>
<div className={classes.newAnalyserContainer}>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Hazard Layer')}</Typography>
<LayerDropdown
type="wms"
value={hazardLayerId}
setValue={setHazardLayerId}
className={classes.selector}
placeholder="Choose hazard layer"
/>
</div>
{hazardDataType === GeometryType.Polygon && (
<>
<div className={classes.analyserOptions}>
<Typography variant="body2">Admin Level</Typography>
<SimpleDropdown
value={adminLevel}
options={range(getAdminLevelCount()).map(i => [
(i + 1) as AdminLevelType,
`Admin ${i + 1}`,
])}
onChange={setAdminLevel}
/>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Date Range')}</Typography>
<div className={classes.dateRangePicker}>
<Typography variant="body2">{t('Start')}</Typography>
<DatePicker
selected={startDate ? new Date(startDate) : null}
onChange={date =>
setStartDate(date?.getTime() || startDate)
}
maxDate={new Date()}
todayButton="Today"
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
popperClassName={classes.calendarPopper}
includeDates={availableHazardDates}
/>
</div>
<div className={classes.dateRangePicker}>
<Typography variant="body2">{t('End')}</Typography>
<DatePicker
selected={endDate ? new Date(endDate) : null}
onChange={date =>
setEndDate(date?.getTime() || endDate)
}
maxDate={new Date()}
todayButton="Today"
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
popperClassName={classes.calendarPopper}
includeDates={availableHazardDates}
/>
</div>
</div>
</>
)}
{hazardDataType === RasterType.Raster && (
<>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Statistic')}</Typography>
<FormControl component="div">
<RadioGroup
name="statistics"
value={statistic}
onChange={onOptionChange(setStatistic)}
row
>
{statisticOptions}
</RadioGroup>
</FormControl>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">
{t('Baseline Layer')}
</Typography>
<LayerDropdown
type="admin_level_data"
value={baselineLayerId || undefined}
setValue={setBaselineLayerId}
className={classes.selector}
placeholder="Choose baseline layer"
/>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Threshold')}</Typography>
<TextField
id="filled-number"
error={!!thresholdError}
helperText={thresholdError}
className={classes.numberField}
label={t('Below')}
type="number"
value={belowThreshold}
onChange={onThresholdOptionChange('below')}
variant="filled"
/>
<TextField
id="filled-number"
label={t('Above')}
className={classes.numberField}
value={aboveThreshold}
onChange={onThresholdOptionChange('above')}
type="number"
variant="filled"
/>
</div>
<div className={classes.analyserOptions}>
<Typography variant="body2">{t('Date')}</Typography>
<DatePicker
locale={t('date_locale')}
dateFormat="PP"
selected={selectedDate ? new Date(selectedDate) : null}
onChange={date =>
setSelectedDate(date?.getTime() || selectedDate)
}
maxDate={new Date()}
todayButton={t('Today')}
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
popperClassName={classes.calendarPopper}
includeDates={availableHazardDates}
/>
</div>
</>
)}
</div>
{!isAnalysisLoading &&
analysisResult &&
(analysisResult instanceof BaselineLayerResult ||
analysisResult instanceof PolygonAnalysisResult) && (
<>
<FormGroup>
<FormControlLabel
control={
<Switch
color="default"
checked={isMapLayerActive}
onChange={onMapSwitchChange}
/>
}
label={t('Map View')}
/>
<FormControlLabel
control={
<Switch
color="default"
checked={isTableViewOpen}
onChange={e => setIsTableViewOpen(e.target.checked)}
/>
}
label={t('Table View')}
/>
</FormGroup>
{isTableViewOpen && (
<AnalysisTable
tableData={analysisResult.tableData}
columns={translatedColumns}
/>
)}
<Button
className={classes.innerAnalysisButton}
onClick={() =>
downloadCSVFromTableData(
analysisResult,
translatedColumns,
selectedDate,
)
}
>
<Typography variant="body2">{t('Download')}</Typography>
</Button>
<Button
className={classes.innerAnalysisButton}
onClick={clearAnalysis}
>
<Typography variant="body2">
{t('Clear Analysis')}
</Typography>
</Button>
<Button
className={classes.innerAnalysisButton}
onClick={shareAnalysis}
>
<Typography variant="body2">
{t('Share Analysis')}
</Typography>
</Button>
</>
)}
{(!analysisResult ||
analysisResult instanceof ExposedPopulationResult) && (
<Button
className={classes.innerAnalysisButton}
onClick={runAnalyser}
disabled={
!!thresholdError || // if there is a threshold error
isAnalysisLoading || // or analysis is currently loading
!hazardLayerId || // or hazard layer hasn't been selected
(hazardDataType === GeometryType.Polygon
? !startDate || !endDate || !adminLevelLayerData
: !selectedDate || !baselineLayerId) // or date hasn't been selected // or baseline layer hasn't been selected
}
>
<Typography variant="body2">{t('Run Analysis')}</Typography>
</Button>
)}
{isAnalysisLoading ? <LinearProgress /> : null}
</div>
) : null}
</Box>
</div>
);
}
Example #19
Source File: ProjectsComponent.tsx From backstage with Apache License 2.0 | 4 votes |
ProjectsComponent = () => {
const routeRef = useRouteRef(rootRouteRef);
const codesceneApi = useApi(codesceneApiRef);
const classes = useStyles();
const [searchText, setSearchText] = React.useState('');
const {
value: projectsWithAnalyses,
loading,
error,
} = useAsync(async (): Promise<Record<number, ProjectAndAnalysis>> => {
const projects = (await codesceneApi.fetchProjects()).projects;
const promises = projects.map(project =>
codesceneApi.fetchLatestAnalysis(project.id),
);
// analyses associates project IDs with their latests analysis
const analyses: Record<number, Analysis> = await Promise.allSettled(
promises,
).then(results => {
return results
.filter(result => result.status === 'fulfilled')
.map(result => result as PromiseFulfilledResult<Analysis>)
.map(result => result.value)
.reduce(
(acc, analysis) => ({ ...acc, [analysis.project_id]: analysis }),
{},
);
});
return projects.reduce(
(acc, project) => ({
...acc,
[project.id]: {
project: project,
analysis: analyses[project.id],
},
}),
{},
);
}, []);
if (loading) {
return <Progress />;
} else if (error) {
return <Alert severity="error">{error.message}</Alert>;
} else if (
!projectsWithAnalyses ||
Object.keys(projectsWithAnalyses).length === 0
) {
return <Alert severity="error">No projects found!</Alert>;
}
const projects = Object.values(projectsWithAnalyses)
.map(p => p.project)
.sort((a, b) => a.name.localeCompare(b.name));
const cards = projects.filter(matchFilter(searchText)).map(project => {
const analysis = projectsWithAnalyses[project.id].analysis;
const subtitle = analysis
? `Last analysis: ${analysis.readable_analysis_time} · Score: ${analysis.high_level_metrics.current_score} · Active authors: ${analysis.high_level_metrics.active_developers}`
: undefined;
const chips = analysis
? topLanguages(analysis, 3).map(lang => (
<Chip label={lang} key={lang} size="small" />
))
: undefined;
return (
<Grid key={project.id} item xs={3}>
<Card>
<CardActionArea
style={{
height: '100%',
overflow: 'hidden',
width: '100%',
}}
component={RouterLink}
to={`${routeRef()}/${project.id}`}
>
<ItemCardHeader title={project.name} />
<CardContent>{subtitle}</CardContent>
<CardActions disableSpacing>{chips}</CardActions>
</CardActionArea>
</Card>
</Grid>
);
});
return (
<Content className={classes.overflowXScroll}>
<ContentHeader title="Projects">
<Input
id="projects-filter"
type="search"
placeholder="Filter"
onChange={e => setSearchText(e.target.value)}
/>
</ContentHeader>
<Grid container>{cards}</Grid>
</Content>
);
}
Example #20
Source File: EditServerDialog.tsx From shadowsocks-electron with GNU General Public License v3.0 | 4 votes |
EditServerDialog: React.FC<EditServerDialogProps> = props => {
const styles = useStyles();
const { t } = useTranslation();
const dispatch = useDispatch();
const { open, onClose, defaultValues, onValues } = props;
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));
const enqueueSnackbar = (message: SnackbarMessage, options: Notification) => {
dispatch(enqueueSnackbarAction(message, options))
};
const [values, setValues] = useState<Partial<Config>>(
defaultValues ?? {
timeout: 60,
encryptMethod: "none",
type: 'ss'
}
);
useLayoutEffect(() => {
setValues(
defaultValues ?? {
timeout: 60,
encryptMethod: "none",
type: 'ss'
}
);
}, [defaultValues]);
const handleValueChange = (
key: keyof Config,
value: boolean | string | number
) => {
setValues({
...values,
// [key]: e.target[attr || 'value'].trim()
[key]: value
});
};
const handleCancel = () => {
onValues(null);
};
const handleAdd = () => {
if (!values.serverHost) {
enqueueSnackbar(t("invalid_server_address"), { variant: "warning" });
return;
}
if (
!(
values.serverPort &&
values.serverPort > 0 &&
values.serverPort <= 65535
)
) {
enqueueSnackbar(t("invalid_server_port"), { variant: "warning" });
return;
}
if (!values.password) {
enqueueSnackbar(t("invalid_password"), { variant: "warning" });
return;
}
if (!values.timeout) {
enqueueSnackbar(t("invalid_timeout"), { variant: "warning" });
return;
}
onValues(values as Config);
};
const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => {
setShowPassword(v => !v);
};
const handleMouseDownPassword = (
event: React.MouseEvent<HTMLButtonElement>
) => {
event.preventDefault();
};
const isSSR = values.type === 'ssr';
const isSS = values.type === 'ss';
return (
<StyledDialog
fullScreen={fullScreen}
open={open}
onClose={onClose}
>
<AdaptiveAppBar className={fullScreen ? styles.appBar : styles.appBarRelative}>
<Toolbar>
<IconButton edge="start" color="inherit" onClick={handleCancel}>
<CloseIcon />
</IconButton>
<Typography variant="h6" className={styles.title}>
{ t('edit_server') }
</Typography>
<Button color="inherit" onClick={handleAdd}>
{ t('save') }
</Button>
</Toolbar>
</AdaptiveAppBar>
<Container className={`${styles.container}`}>
{fullScreen && <div className={`${styles.toolbar}`} />}
<InputLabel required style={{ marginBottom: 0 }}>
{t('server_type')}
</InputLabel>
<Select
required
label={t('server_type')}
displayEmpty
fullWidth
value={values.type ?? "ss"}
onChange={(e: any) => handleValueChange("type", e.target.value.trim())}
>
{serverTypes.map(serverType => (
<MenuItem key={serverType} value={serverType}>
{serverType}
</MenuItem>
))}
</Select>
<TextField
fullWidth
label={t('remark')}
value={values.remark ?? ""}
onChange={e => handleValueChange("remark", e.target.value.trim())}
/>
<TextField
required
fullWidth
label={t('server_address')}
value={values.serverHost ?? ""}
onChange={e => handleValueChange("serverHost", e.target.value.trim())}
/>
<TextField
required
fullWidth
type="number"
label={t('server_port')}
value={values.serverPort ?? ""}
onChange={e => handleValueChange("serverPort", e.target.value.trim())}
/>
<FormControl required fullWidth>
<InputLabel htmlFor="password">{t('password')}</InputLabel>
<Input
id="password"
type={showPassword ? "text" : "password"}
value={values.password ?? ""}
onChange={e => handleValueChange("password", e.target.value.trim())}
endAdornment={
<InputAdornment position="end">
<IconButton
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
/>
</FormControl>
<InputLabel required style={{ marginBottom: 0 }}>
{t('encryption')}
</InputLabel>
<Select
required
label={t('encryption')}
displayEmpty
fullWidth
value={values.encryptMethod ?? "none"}
onChange={(e: any) => handleValueChange("encryptMethod", e.target.value.trim())}
>
{encryptMethods.map(method => (
<MenuItem key={method} value={method}>
{method}
</MenuItem>
))}
</Select>
{
isSSR && (
<>
<InputLabel required style={{ marginBottom: 0 }}>
{t('protocol')}
</InputLabel>
<Select
required
label={t('protocol')}
displayEmpty
fullWidth
value={values.protocol ?? "origin"}
onChange={(e: any) => handleValueChange("protocol", e.target.value.trim())}
>
{protocols.map(protocol => (
<MenuItem key={protocol} value={protocol}>
{protocol}
</MenuItem>
))}
</Select>
<TextField
fullWidth
label={t('protocolParam')}
value={values.protocolParam ?? ""}
onChange={e => handleValueChange("protocolParam", e.target.value.trim())}
/>
</>
)
}
{
isSSR && (
<>
<InputLabel required style={{ marginBottom: 0 }}>
{t('obfs')}
</InputLabel>
<Select
required
label={t('obfs')}
displayEmpty
fullWidth
value={values.obfs ?? "plain"}
onChange={(e: any) => handleValueChange("obfs", e.target.value.trim())}
>
{obfs.map(value => (
<MenuItem key={value} value={value}>
{value}
</MenuItem>
))}
</Select>
<TextField
fullWidth
label={t('obfsParam')}
value={values.obfsParam ?? ""}
onChange={e => handleValueChange("obfsParam", e.target.value.trim())}
/>
</>
)
}
<TextField
required
fullWidth
label={t('timeout')}
value={values.timeout ?? 60}
onChange={e => handleValueChange("timeout", e.target.value)}
/>
<List>
<ListItem>
<ListItemText primary="TCP Fast Open" />
<ListItemSecondaryAction>
<Switch checked={!!values.fastOpen} edge="end" color="primary" onChange={(e) => handleValueChange('fastOpen', e.target.checked)} />
</ListItemSecondaryAction>
</ListItem>
{
isSS && (
<ListItem>
<ListItemText primary="TCP No Delay" />
<ListItemSecondaryAction>
<Switch checked={!!values.noDelay} edge="end" color="primary" onChange={(e) => handleValueChange('noDelay', e.target.checked)} />
</ListItemSecondaryAction>
</ListItem>
)
}
<ListItem>
<ListItemText primary="UDP Relay" />
<ListItemSecondaryAction>
<Switch checked={!!values.udp} edge="end" color="primary" onChange={(e) => handleValueChange('udp', e.target.checked)} />
</ListItemSecondaryAction>
</ListItem>
</List>
<InputLabel style={{ marginBottom: 0 }}><TextWithTooltip text={t('plugin')} tooltip={t('readme')} /></InputLabel>
{
isSS && (
<>
<Select
label={t('plugin')}
displayEmpty
fullWidth
value={values.plugin ?? ""}
onChange={(e: any) => handleValueChange("plugin", e.target.value.trim())}
>
<MenuItem key="none" value="">
<em>{t('none')}</em>
</MenuItem>
{plugins.map(plugin => (
<MenuItem key={plugin.name} value={plugin.name}>
{plugin.name} {plugin.tips ? `(${t(plugin.tips)})` : ""}
</MenuItem>
))}
</Select>
<TextField
fullWidth
multiline
label={t('plugin_options')}
value={values.pluginOpts ?? ""}
onChange={e => handleValueChange("pluginOpts", e.target.value.trim())}
/>
</>
)
}
</Container>
</StyledDialog>
);
}
Example #21
Source File: SQFormDropdown.tsx From SQForm with MIT License | 4 votes |
function SQFormDropdown({
children,
displayEmpty = false,
isDisabled = false,
label,
name,
onBlur,
onChange,
size = 'auto',
muiFieldProps = {},
}: SQFormDropdownProps): React.ReactElement {
const classes = useStyles();
const {
formikField: {field},
fieldState: {isFieldError, isFieldRequired},
fieldHelpers: {handleBlur, handleChange, HelperTextComponent},
} = useForm({
name,
onBlur,
onChange,
});
const labelID = label.toLowerCase();
const options = React.useMemo(() => {
if (!children) {
console.warn(getUndefinedChildrenWarning('SQFormDropdown', name));
return [];
}
if (!displayEmpty) return children;
const [firstOption] = children;
if (
firstOption?.label === EMPTY_LABEL ||
firstOption?.label === EMPTY_VALUE
) {
return children;
}
return [EMPTY_OPTION, ...children];
}, [children, displayEmpty, name]);
const renderValue = (value: unknown) => {
const getValue = (selectedValue: SQFormOption['value']) => {
if (selectedValue === undefined || selectedValue === null) {
console.warn(getUndefinedValueWarning('SQFormDropdown', name));
return EMPTY_LABEL;
}
if (selectedValue === EMPTY_VALUE) {
return EMPTY_LABEL;
}
const valueToRender = options.find(
(option) => option.value === selectedValue
)?.label;
if (!valueToRender) {
console.warn(
getOutOfRangeValueWarning(
'SQFormDropdown',
name,
selectedValue.toString()
)
);
return undefined;
}
return valueToRender;
};
return getValue(value as SQFormOption['value']);
};
return (
<Grid item sm={size}>
<FormControl
error={isFieldError}
required={isFieldRequired}
disabled={isDisabled}
fullWidth={true}
>
<InputLabel shrink={true} id={labelID}>
{label}
</InputLabel>
<Select
className={classes.selectHeight}
displayEmpty={true}
input={<Input name={name} />}
value={field.value}
onBlur={handleBlur}
onChange={handleChange}
labelId={labelID}
renderValue={renderValue}
{...muiFieldProps}
>
{options.map((option) => {
return (
<MenuItem
key={`${name}_${option.value}`}
disabled={option.isDisabled}
value={option.value}
>
{option.label}
</MenuItem>
);
})}
</Select>
{!isDisabled && <FormHelperText>{HelperTextComponent}</FormHelperText>}
</FormControl>
</Grid>
);
}
Example #22
Source File: CreateRoom.tsx From cards-against-formality-pwa with BSD 2-Clause "Simplified" License | 4 votes |
export default function CreateRoom({ onJoin, decksData, user }: any) {
const { openSnack } = useContext(SnackbarContext);
const [isProtected, setIsProtected] = useState(false);
const [passcode, setPasscode] = useState('');
const [name, setName] = useState('');
const [roundTime, setRoundTime] = useState(60);
const [target, setTarget] = useState(10);
const limitedSetTarget = useCallback((event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
setTarget(rangeLimit(event, { min: 5, max: 100 }));
}, []);
const [maxPlayers, setMaxPlayers] = useState(10);
const limitedSetMaxPlayers = useCallback((event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
setMaxPlayers(rangeLimit(event, { min: 2, max: 50 }));
}, []);
const [, isLoading, , createRoom] = useFetchData(`/api/rooms`, FetchType.POST);
const [decks, setDecks] = useState([]);
const [errorField, setErrorField] = useState<string | null>(null);
function rangeLimit(
event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,
{ min, max }: { min: number; max: number } = { min: 4, max: 10 }
): number {
const value = parseInt(event.target.value, 10);
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
function handleSubmit() {
const room = {
name: name?.length ? name : user?.username,
options: {
target,
maxPlayers,
maxSpectators: 10,
decks,
roundTime
},
}
if (isProtected && passcode.length) {
(room as any).passcode = passcode;
}
createRoom(room)
.then((axiosRes) => {
onJoin(axiosRes.data._id, passcode);
(window as any)?.gtag('event', 'create_room', { value: passcode?.length ? 'private' : 'public' });
})
.catch((err) => {
if (err?.response?.data.type === 'VALIDATION_ERROR') {
const errObj = err?.response?.data.data[0];
setErrorField(errObj.field as string);
}
openSnack({ text: 'Something went wrong...', severity: 'error' });
});
}
function onKeyPress(e: any) {
if (e.charCode === 13) {
handleSubmit();
}
}
function renderPasswordForm() {
if (!isProtected) {
return null;
}
return <FormControl error={errorField === 'passcode'}>
<InputLabel htmlFor="passcode">Password</InputLabel>
<Input id="passcode" aria-describedby="password-helper" required={false} value={passcode} onChange={e => setPasscode(e.target.value)} />
<FormHelperText id="password-helper">
{errorField !== 'passcode' ? 'People will need this password to enter your game.' : 'Password must be between 4-12 characters long with no special characters.'}
</FormHelperText>
</FormControl>;
}
function renderCardContent() {
return <CardContent className="create-form-card-content">
<form className="create-room-form" onKeyPress={onKeyPress}>
<FormControl required={true} error={errorField === 'name'}>
<Input id="name" aria-describedby="game-name-helper" value={name} onChange={e => { setName(e.target.value); }} placeholder={user?.username} />
<FormHelperText id="score-helper">{errorField === 'name' ? "Game name must be between 2-16 characters long with no special characters!" : "Game name"}</FormHelperText>
</FormControl>
<FormControl>
<InputLabel htmlFor="target">Target Score</InputLabel>
<Input id="target" type="number" aria-describedby="score-helper" value={target} onChange={limitedSetTarget} />
<FormHelperText id="score-helper">Number of points required to end the game.</FormHelperText>
</FormControl>
<FormControl>
<InputLabel htmlFor="max-players">Max Players</InputLabel>
<Input id="max-players" type="number" aria-describedby="max-players-helper" value={maxPlayers} onChange={limitedSetMaxPlayers} />
</FormControl>
<FormControl>
<InputLabel id="roundTime-label">Round time (seconds)</InputLabel>
<Select
labelId="roundTime-label"
id="roundTime"
value={roundTime}
onChange={(e: any) => setRoundTime(parseInt(e.target.value, 10))}
>
<MenuItem value={15}>15</MenuItem>
<MenuItem value={30}>30</MenuItem>
<MenuItem value={45}>45</MenuItem>
<MenuItem value={60}>60</MenuItem>
</Select>
<FormHelperText>How you have to select your answers</FormHelperText>
</FormControl>
{!decksData?.rows ? null : <DeckSelector decks={decksData.rows} onChange={setDecks as any} />}
<FormControlLabel
control={<Switch checked={isProtected} onChange={e => setIsProtected(e.target.checked)} name="checkedA" />}
label="Private"
/>
{renderPasswordForm()}
</form>
</CardContent>
}
const Submit = <CardActions>
{!isLoading ? <Button variant="contained" color="primary" size="small" onClick={handleSubmit}>Create</Button> : <CircularProgress />}
</CardActions>;
return <Card className="form-container" variant="elevation">
{Submit}
{renderCardContent()}
{Submit}
</Card>
}
Example #23
Source File: index.tsx From vscode-crossnote with GNU Affero General Public License v3.0 | 4 votes |
function AudioWidget(props: WidgetArgs) {
const attributes = props.attributes;
const classes = useStyles(props);
const { t } = useTranslation();
const [source, setSource] = useState<string>(attributes["source"] || "");
const [autoplay, setAutoplay] = useState<boolean>(
attributes["autoplay"] || false
);
const [controls, setControls] = useState<boolean>(
attributes["controls"] || true
);
const [loop, setLoop] = useState<boolean>(attributes["loop"] || false);
const [muted, setMuted] = useState<boolean>(attributes["muted"] || false);
if (attributes["src"]) {
return (
<span style={{ cursor: "default" }}>
<audio
autoPlay={attributes["autoplay"] || attributes["autoPlay"]}
controls={attributes["controls"]}
loop={attributes["loop"]}
muted={attributes["muted"]}
style={attributes["style"]}
>
{t("widget/crossnote.audio/audio_element_fail")}
<source src={attributes["src"]} type={attributes["type"]}></source>
</audio>
{!props.isPreview && !attributes["controls"] && "?"}
</span>
);
}
if (props.isPreview) {
return <span></span>;
}
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("general/Audio")}</Typography>
<Box className={clsx(classes.actionButtons)}>
<Tooltip title={t("general/Delete")}>
<IconButton onClick={() => props.removeSelf()}>
<TrashCan></TrashCan>
</IconButton>
</Tooltip>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("general/source-url")}
</Typography>
<Input
margin={"dense"}
placeholder={t("widget/crossnote.audio/source-url-placeholder")}
value={source}
onChange={(event) => {
setSource(event.target.value);
}}
onKeyDown={(event) => {
if (event.which === 13) {
if (source) {
const attrs = {
autoplay,
controls,
loop,
muted,
src: source,
};
props.setAttributes(attrs);
}
}
}}
fullWidth={true}
></Input>
</Box>
<Box className={clsx(classes.section)}>
<FormControlLabel
label={t("widget/autoplay")}
control={
<Switch
checked={autoplay}
onChange={() => setAutoplay(!autoplay)}
color={"primary"}
></Switch>
}
></FormControlLabel>
<FormControlLabel
label={t("widget/controls")}
control={
<Switch
checked={controls}
onChange={() => setControls(!controls)}
color={"primary"}
></Switch>
}
></FormControlLabel>
<FormControlLabel
label={t("widget/loop")}
control={
<Switch
checked={loop}
onChange={() => setLoop(!loop)}
color={"primary"}
></Switch>
}
></FormControlLabel>
<FormControlLabel
label={t("widget/muted")}
control={
<Switch
checked={muted}
onChange={() => setMuted(!muted)}
color={"primary"}
></Switch>
}
></FormControlLabel>
</Box>
</Card>
);
}
Example #24
Source File: AccountManagementPage.tsx From clarity with Apache License 2.0 | 4 votes |
AccountManagementPage = observer((props: Props) => {
const [openDialog, setOpenDialog] = React.useState(false);
const [openKeyDialog, setOpenKeyDialog] = React.useState(false);
const [
selectedAccount,
setSelectedAccount
] = React.useState<SignKeyPairWithAlias | null>(null);
const [name, setName] = React.useState('');
const [publicKey64, setPublicKey64] = React.useState('');
const [publicKeyHex, setPublicKeyHex] = React.useState('');
/* Note: 01 prefix denotes algorithm used in key generation */
const address = '01' + publicKeyHex;
const [copyStatus, setCopyStatus] = React.useState(false);
const handleClickOpen = (account: SignKeyPairWithAlias) => {
setOpenDialog(true);
setSelectedAccount(account);
setName(account.name);
};
const handleViewKey = async (accountName: string) => {
let publicKey64 = await props.authContainer.getSelectedAccountKey(
accountName
);
let publicKeyHex = await props.authContainer.getPublicKeyHex(accountName);
setName(accountName);
setPublicKey64(publicKey64);
setPublicKeyHex(publicKeyHex);
setOpenKeyDialog(true);
};
const handleCopyMessage = (event?: React.SyntheticEvent, reason?: string) => {
if (reason === 'clickaway') {
return;
}
setCopyStatus(false);
};
const handleClose = () => {
setOpenDialog(false);
setOpenKeyDialog(false);
setSelectedAccount(null);
};
const handleUpdateName = () => {
if (selectedAccount) {
props.authContainer.renameUserAccount(selectedAccount.name, name);
handleClose();
}
};
const onDragEnd = (result: DropResult) => {
// dropped outside the list
if (!result.destination) {
return;
}
props.authContainer.reorderAccount(
result.source.index,
result.destination.index
);
};
const handleClickRemove = (name: string) => {
confirm(
<div className="text-danger">Remove account</div>,
'Are you sure you want to remove this account?'
).then(() => props.authContainer.removeUserAccount(name));
};
return (
<React.Fragment>
<DragDropContext onDragEnd={result => onDragEnd(result)}>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<Observer>
{() => (
<RootRef rootRef={provided.innerRef}>
<List>
{props.authContainer.userAccounts.map((item, index) => (
<Draggable
key={item.name}
draggableId={item.name}
index={index}
>
{(provided, snapshot) => (
<ListItem
innerRef={provided.innerRef}
ContainerProps={{
...provided.draggableProps,
...provided.dragHandleProps,
style: getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)
}}
>
<ListItemText primary={item.name} />
<ListItemSecondaryAction>
<IconButton
edge={'end'}
onClick={() => {
handleClickOpen(item);
}}
>
<EditIcon />
</IconButton>
<IconButton
edge={'end'}
onClick={() => {
handleClickRemove(item.name);
}}
>
<DeleteIcon />
</IconButton>
<IconButton
edge={'end'}
onClick={() => {
handleViewKey(item.name);
}}
>
<VpnKeyIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
)}
</Draggable>
))}
{provided.placeholder}
</List>
</RootRef>
)}
</Observer>
)}
</Droppable>
</DragDropContext>
<Dialog
open={openDialog}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">Rename</DialogTitle>
<DialogContent>
<Input
autoFocus
margin="dense"
id="name"
type="text"
fullWidth
value={name}
onChange={e => {
setName(e.target.value);
}}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleUpdateName} color="primary">
Update
</Button>
</DialogActions>
</Dialog>
<Dialog
fullScreen
open={openKeyDialog}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">Account Details</DialogTitle>
<DialogContent>
<List>
<ListSubheader>
<Typography variant={'h6'}>{name}</Typography>
</ListSubheader>
<ListItem>
<IconButton
edge={'start'}
onClick={() => {
copy(address);
setCopyStatus(true);
}}
>
<FilterNoneIcon />
</IconButton>
<ListItemText
primary={'Address: ' + address}
style={{ overflowWrap: 'break-word' }}
/>
</ListItem>
<ListItem>
<IconButton
edge={'start'}
onClick={() => {
copy(publicKey64);
setCopyStatus(true);
}}
>
<FilterNoneIcon />
</IconButton>
<ListItemText
primary={'Public Key: ' + publicKey64}
style={{ overflowWrap: 'break-word' }}
/>
</ListItem>
</List>
<Snackbar
open={copyStatus}
message="Copied!"
autoHideDuration={1500}
onClose={handleCopyMessage}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Close
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
);
})
Example #25
Source File: AncUstLpWithdraw.tsx From anchor-web-app with Apache License 2.0 | 4 votes |
export function AncUstLpWithdraw() {
// ---------------------------------------------
// dependencies
// ---------------------------------------------
const { availablePost, connected } = useAccount();
const fixedFee = useFixedFee();
const [withdraw, withdrawResult] = useAncAncUstLpWithdrawTx();
// ---------------------------------------------
// states
// ---------------------------------------------
const [lpAmount, setLpAmount] = useState<AncUstLP>('' as AncUstLP);
const [simulation, setSimulation] = useState<AncUstLpSimulation<Big> | null>(
null,
);
// ---------------------------------------------
// queries
// ---------------------------------------------
const bank = useAnchorBank();
const { data: { ancPrice } = {} } = useAncPriceQuery();
const { data: { userLPBalance } = {} } = useRewardsAncUstLpRewardsQuery();
// ---------------------------------------------
// logics
// ---------------------------------------------
const invalidTxFee = useMemo(
() => connected && validateTxFee(bank.tokenBalances.uUST, fixedFee),
[connected, bank, fixedFee],
);
const invalidLpAmount = useMemo(() => {
if (lpAmount.length === 0 || !connected) return undefined;
return big(microfy(lpAmount)).gt(bank.tokenBalances.uAncUstLP)
? 'Not enough assets'
: undefined;
}, [bank.tokenBalances.uAncUstLP, lpAmount, connected]);
const updateLpAmount = useCallback(
(nextLpAmount: string) => {
if (!ancPrice || nextLpAmount.length === 0) {
setLpAmount('' as AncUstLP);
setSimulation(null);
return;
} else if (isZero(nextLpAmount)) {
setLpAmount(nextLpAmount as AncUstLP);
setSimulation(null);
return;
}
const nextSimulation = ancUstLpLpSimulation(
ancPrice,
userLPBalance,
nextLpAmount as AncUstLP,
fixedFee,
bank,
);
setLpAmount(nextLpAmount as AncUstLP);
setSimulation(nextSimulation);
},
[ancPrice, bank, fixedFee, userLPBalance],
);
const init = useCallback(() => {
setLpAmount('' as AncUstLP);
setSimulation(null);
}, []);
const proceed = useCallback(
(lpAmount: AncUstLP) => {
if (!connected || !withdraw) {
return;
}
withdraw({
lpAmount,
onTxSucceed: () => {
init();
},
});
},
[connected, init, withdraw],
);
// ---------------------------------------------
// presentation
// ---------------------------------------------
if (
withdrawResult?.status === StreamStatus.IN_PROGRESS ||
withdrawResult?.status === StreamStatus.DONE
) {
return (
<TxResultRenderer
resultRendering={withdrawResult.value}
onExit={() => {
init();
switch (withdrawResult.status) {
case StreamStatus.IN_PROGRESS:
withdrawResult.abort();
break;
case StreamStatus.DONE:
withdrawResult.clear();
break;
}
}}
/>
);
}
return (
<>
{!!invalidTxFee && <MessageBox>{invalidTxFee}</MessageBox>}
{/* ANC */}
<div className="description">
<p>Input</p>
<p />
</div>
<NumberInput
className="amount"
value={lpAmount}
maxIntegerPoinsts={ANC_INPUT_MAXIMUM_INTEGER_POINTS}
maxDecimalPoints={ANC_INPUT_MAXIMUM_DECIMAL_POINTS}
error={!!invalidLpAmount}
placeholder="0.00"
onChange={({ target }: ChangeEvent<HTMLInputElement>) =>
updateLpAmount(target.value)
}
InputProps={{
endAdornment: <InputAdornment position="end">LP</InputAdornment>,
}}
/>
<div className="wallet" aria-invalid={!!invalidLpAmount}>
<span>{invalidLpAmount}</span>
<span>
ANC-UST LP Balance:{' '}
<span
style={{
textDecoration: 'underline',
cursor: 'pointer',
}}
onClick={() =>
updateLpAmount(
formatLPInput(demicrofy(bank.tokenBalances.uAncUstLP)),
)
}
>
{formatLP(demicrofy(bank.tokenBalances.uAncUstLP))} LP
</span>
</span>
</div>
<IconLineSeparator className="separator" />
{/* UST */}
<div className="description">
<p>Output</p>
<p />
</div>
<SelectAndTextInputContainer
gridColumns={[120, '1fr']}
gridRows={[60, 60]}
aria-readonly
>
<Input readOnly value="ANC" />
<Input
readOnly
value={simulation?.ancAmount ? formatANC(simulation.ancAmount) : ''}
/>
<Input readOnly value="UST" />
<Input
readOnly
value={simulation?.ustAmount ? formatUST(simulation.ustAmount) : ''}
/>
</SelectAndTextInputContainer>
<TxFeeList className="receipt">
{simulation && (
<>
<SwapListItem
label="Pool Price"
currencyA="UST"
currencyB="ANC"
exchangeRateAB={demicrofy(simulation.poolPrice)}
formatExchangeRate={(ratio, direction) =>
direction === 'a/b'
? formatANC(ratio as ANC<Big>)
: formatUST(ratio as UST<Big>)
}
/>
<TxFeeListItem label="LP after Tx">
{formatLP(simulation.lpFromTx)} LP
</TxFeeListItem>
<TxFeeListItem label="Pool Share after Tx">
{formatShareOfPool(simulation.shareOfPool)} %
</TxFeeListItem>
<TxFeeListItem label="Tx Fee">
{formatUST(demicrofy(simulation.txFee))} UST
</TxFeeListItem>
</>
)}
</TxFeeList>
{/* Submit */}
<ViewAddressWarning>
<ActionButton
className="submit"
disabled={
!availablePost ||
!connected ||
!withdraw ||
lpAmount.length === 0 ||
big(lpAmount).lte(0) ||
!simulation ||
!!invalidTxFee ||
!!invalidLpAmount
}
onClick={() => proceed(lpAmount)}
>
Remove Liquidity
</ActionButton>
</ViewAddressWarning>
</>
);
}
Example #26
Source File: Index.stories.tsx From anchor-web-app with Apache License 2.0 | 4 votes |
Component = styled(({ className }: { className?: string }) => {
const [dialogOpen, setDialogOpen] = useState<Record<MessageColor, boolean>>(
() => ({
normal: false,
warning: false,
error: false,
success: false,
}),
);
const [selectedItem, setSelectedItem] = useState<Record<string, Item | null>>(
() => ({}),
);
return (
<div className={className}>
<div className="styles">
<section className="flat">FLAT</section>
<section className="concave">CONCAVE</section>
<section className="convex">CONVEX</section>
<section className="pressed">PRESSED</section>
</div>
<Section className="components">
<article className="buttons">
<TextButton>BUTTON</TextButton>
<ActionButton>BUTTON</ActionButton>
</article>
<HorizontalRuler />
<article className="text-fields">
<TextInput label="TEXT FIELD" />
<TextInput
label="ERROR"
error={true}
InputProps={textFieldInputProps}
helperText="Error Content"
/>
</article>
<HorizontalRuler />
<article className="text-fields">
<TextInput />
<TextInput
error={true}
InputProps={textFieldInputProps}
helperText="Error Content"
/>
</article>
<HorizontalRuler />
<article className="buttons">
{messageColors.map((color) => (
<Fragment key={color}>
<ActionButton
onClick={() =>
setDialogOpen((prev) => ({ ...prev, [color]: true }))
}
>
OPEN {color.toUpperCase()} DIALOG
</ActionButton>
<Modal
open={dialogOpen[color]}
onClose={() =>
setDialogOpen((prev) => ({ ...prev, [color]: false }))
}
>
<Dialog
color={color}
style={{ width: 600, height: 400 }}
onClose={() =>
setDialogOpen((prev) => ({ ...prev, [color]: false }))
}
>
<h1 style={{ textAlign: 'center', fontWeight: 300 }}>
Title
</h1>
</Dialog>
</Modal>
</Fragment>
))}
</article>
<HorizontalRuler />
<article className="buttons">
{messageColors.map((color) => (
<Tooltip key={color} title={color} color={color} placement="top">
<TextButton>{color.toUpperCase()} TOOLTIP</TextButton>
</Tooltip>
))}
</article>
<HorizontalRuler />
<article className="buttons">
<NativeSelect
value={
selectedItem['nativeSelect']?.value ?? selectorItems[0].value
}
onChange={(evt: ChangeEvent<HTMLSelectElement>) =>
setSelectedItem((prev) => ({
...prev,
nativeSelect:
selectorItems.find(
({ value }) => evt.target.value === value,
) ?? null,
}))
}
>
{selectorItems.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</NativeSelect>
<SelectAndTextInputContainer gridColumns={[100, '1fr']}>
<MuiNativeSelect
value={
selectedItem['selectAndTextInput']?.value ??
selectorItems[0].value
}
onChange={(evt) =>
setSelectedItem((prev) => ({
...prev,
selectAndTextInput:
selectorItems.find(
({ value }) => evt.target.value === value,
) ?? null,
}))
}
>
{selectorItems.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</MuiNativeSelect>
<Input placeholder="PLACEHOLDER" />
</SelectAndTextInputContainer>
<Selector
items={selectorItems}
selectedItem={selectedItem['selector']}
onChange={(next) =>
setSelectedItem((prev) => ({ ...prev, selector: next }))
}
labelFunction={(item) => item?.label ?? 'None'}
keyFunction={(item) => item.value}
/>
</article>
<HorizontalRuler />
<article>
<Tab
items={tabItems}
selectedItem={selectedItem['tab'] ?? tabItems[0]}
onChange={(next) =>
setSelectedItem((prev) => ({ ...prev, tab: next }))
}
labelFunction={(item) => item.label}
keyFunction={(item) => item.value}
/>
</article>
<HorizontalRuler />
<article>
<HorizontalGraphBar<{ value: number; color: string }>
style={{ margin: '50px 0' }}
min={-100}
max={100}
data={[
{ value: 50, color: '#4da3ee' },
{ value: 0, color: '#ffffff' },
{ value: -50, color: '#ff8a4b' },
]}
colorFunction={({ color }) => color}
valueFunction={({ value }) => value}
labelRenderer={({ value }, rect) => {
return (
<span
style={{
top: -25,
left: rect.x + rect.width,
transform: 'translateX(-50%)',
}}
>
{value}
</span>
);
}}
>
<span style={{ top: 25, left: 0 }}>Borrow Limit</span>
<span style={{ top: 25, right: 0 }}>$246k</span>
</HorizontalGraphBar>
</article>
</Section>
<Section className="table">
<HorizontalScrollTable minWidth={800}>
<colgroup>
<col style={{ width: 300 }} />
<col style={{ width: 300 }} />
<col style={{ width: 300 }} />
<col style={{ width: 300 }} />
</colgroup>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th style={{ textAlign: 'right' }}>C</th>
<th style={{ textAlign: 'right' }}>D</th>
</tr>
</thead>
<tbody>
{Array.from({ length: 5 }, (_, i) => (
<tr key={`row-${i}`}>
<td>{'A'.repeat(i * 3 + 1)}</td>
<td>{'B'.repeat(i * 3 + 1)}</td>
<td style={{ textAlign: 'right' }}>
{'C'.repeat(i * 3 + 1)}
<br />
{'C'.repeat(i * 2 + 1)}
</td>
<td style={{ textAlign: 'right' }}>{'D'.repeat(i * 3 + 1)}</td>
</tr>
))}
</tbody>
<tfoot>
<tr>
<td>A</td>
<td>B</td>
<td style={{ textAlign: 'right' }}>C</td>
<td style={{ textAlign: 'right' }}>D</td>
</tr>
</tfoot>
</HorizontalScrollTable>
</Section>
</div>
);
})`
// ---------------------------------------------
// style
// ---------------------------------------------
background-color: ${({ theme }) => theme.backgroundColor};
color: ${({ theme }) => theme.textColor};
.styles {
section {
border-radius: 20px;
padding: 20px;
text-align: center;
color: ${({ theme }) => theme.textColor};
&.flat {
${({ theme }) =>
flat({
color: theme.backgroundColor,
distance: 6,
intensity: theme.intensity,
})};
}
&.concave {
${({ theme }) =>
concave({
color: theme.backgroundColor,
distance: 6,
intensity: theme.intensity,
})};
}
&.convex {
${({ theme }) =>
convex({
color: theme.backgroundColor,
distance: 6,
intensity: theme.intensity,
})};
}
&.pressed {
${({ theme }) =>
pressed({
color: theme.backgroundColor,
distance: 6,
intensity: theme.intensity,
})};
}
}
}
margin-bottom: 1px;
// ---------------------------------------------
// layout
// ---------------------------------------------
.styles {
display: flex;
margin-bottom: 30px;
}
.components {
hr {
margin: 30px 0;
}
margin-bottom: 30px;
}
.table {
margin-bottom: 30px;
}
// pc
@media (min-width: ${screen.pc.min}px) {
padding: 100px;
.styles {
section {
flex: 1;
&:not(:last-child) {
margin-right: 30px;
}
}
}
.components {
.buttons,
.text-fields {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 15px;
}
}
}
// tablet
@media (min-width: ${screen.tablet.min}px) and (max-width: ${screen.tablet
.max}px) {
padding: 30px;
.styles {
section {
flex: 1;
&:not(:last-child) {
margin-right: 10px;
}
}
}
.components {
.buttons,
.text-fields {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 15px;
}
}
.NeuSection-content {
padding: 30px;
}
}
// mobile
@media (max-width: ${screen.mobile.max}px) {
padding: 30px 20px;
.styles {
flex-direction: column;
section {
&:not(:last-child) {
margin-bottom: 20px;
}
}
}
.components {
.buttons,
.text-fields {
display: grid;
grid-template-columns: repeat(1, 1fr);
grid-gap: 15px;
}
.text-fields {
grid-gap: 40px;
}
}
.NeuSection-content {
padding: 20px;
}
}
`
Example #27
Source File: index.tsx From vscode-crossnote with GNU Affero General Public License v3.0 | 4 votes |
function YoutubeWidget(props: WidgetArgs) {
const attributes = props.attributes;
const classes = useStyles(props);
const { t } = useTranslation();
const [url, setURL] = useState<string>("");
const [error, setError] = useState<string>("");
if (attributes["videoID"]) {
if (!props.isPreview) {
return (
<span style={{ cursor: "default" }}>
<img
alt={"Youtube: " + attributes["videoID"]}
src={`https://img.youtube.com/vi/${attributes["videoID"]}/0.jpg`}
onClick={() => {
window.open(
`https://www.youtube.com/watch?v=${attributes["videoID"]}`,
"_blank"
);
}}
style={{
cursor: "pointer",
width: "100%",
}}
></img>
</span>
);
} else {
return (
<span style={{ cursor: "default" }}>
<Box className={clsx(classes.videoWrapper)}>
<iframe
title={"youtube_" + attributes["videoID"]}
className={clsx(classes.video)}
src={`https://www.youtube.com/embed/${attributes["videoID"]}`}
scrolling={"no"}
frameBorder={"no"}
allowFullScreen={true}
></iframe>
</Box>
</span>
);
}
}
if (props.isPreview) {
return <span></span>;
}
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("Youtube")}</Typography>
<Box className={clsx(classes.actionButtons)}>
<Tooltip title={t("general/Delete")}>
<IconButton onClick={() => props.removeSelf()}>
<TrashCan></TrashCan>
</IconButton>
</Tooltip>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("Youtube video URL")}
</Typography>
<Input
margin={"dense"}
placeholder={t(
"widget/crossnote.youtube/youtube-video-url-placeholder"
)}
value={url}
onChange={(event) => {
setURL(event.target.value);
setError("");
}}
onKeyDown={(event) => {
if (event.which === 13) {
if (url && url.match(/\?v=(.+?)(&|$)/)) {
const videoID = url.match(/\?v=(.+?)(&|$)/)[1];
const attrs = {
videoID,
};
props.setAttributes(attrs);
} else if (url && url.match(/\/youtu\.be\/(.+?)(\?|$)/)) {
const videoID = url.match(/\/youtu\.be\/(.+?)(\?|$)/)[1];
const attrs = {
videoID,
};
props.setAttributes(attrs);
} else {
setError(t("widget/crossnote.youtube/error_message"));
}
}
}}
fullWidth={true}
></Input>
<Typography className={clsx(classes.errorMessage)}>{error}</Typography>
</Box>
</Card>
);
}
Example #28
Source File: index.tsx From vscode-crossnote with GNU Affero General Public License v3.0 | 4 votes |
function VideoWidget(props: WidgetArgs) {
const attributes = props.attributes;
const classes = useStyles(props);
const { t } = useTranslation();
const [source, setSource] = useState<string>(attributes["source"] || "");
const [autoplay, setAutoplay] = useState<boolean>(
attributes["autoplay"] || false
);
const [controls, setControls] = useState<boolean>(
attributes["controls"] || true
);
const [loop, setLoop] = useState<boolean>(attributes["loop"] || false);
const [muted, setMuted] = useState<boolean>(attributes["muted"] || false);
const [poster, setPoster] = useState<string>(attributes["poster"] || "");
if (attributes["src"]) {
return (
<span style={{ cursor: "default" }}>
<Box className={clsx(classes.videoWrapper)}>
<video
className={clsx(classes.video)}
autoPlay={attributes["autoplay"] || attributes["autoPlay"]}
controls={attributes["controls"]}
loop={attributes["loop"]}
muted={attributes["muted"]}
style={attributes["style"]}
poster={attributes["poster"]}
>
{t("widget/crossnote.video/video_element_fail")}
<source src={attributes["src"]} type={attributes["type"]}></source>
</video>
</Box>
</span>
);
}
if (props.isPreview) {
return <span></span>;
}
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("general/Video")}</Typography>
<Box className={clsx(classes.actionButtons)}>
<Tooltip title={t("general/Delete")}>
<IconButton onClick={() => props.removeSelf()}>
<TrashCan></TrashCan>
</IconButton>
</Tooltip>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("general/source-url")}
</Typography>
<Input
margin={"dense"}
placeholder={t("widget/crossnote.video/video-url-placeholder")}
value={source}
onChange={(event) => {
setSource(event.target.value);
}}
onKeyDown={(event) => {
if (event.which === 13) {
if (source) {
const attrs = {
autoplay,
controls,
loop,
muted,
src: source,
poster,
};
props.setAttributes(attrs);
}
}
}}
fullWidth={true}
></Input>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.video/poster-url")}
</Typography>
<Input
margin={"dense"}
placeholder={t("widget/crossnote.video/poster-url-placeholder")}
value={poster}
onChange={(event) => {
setPoster(event.target.value);
}}
fullWidth={true}
></Input>
</Box>
<Box className={clsx(classes.section)}>
<FormControlLabel
label={t("widget/autoplay")}
control={
<Switch
checked={autoplay}
onChange={() => setAutoplay(!autoplay)}
color={"primary"}
></Switch>
}
></FormControlLabel>
<FormControlLabel
label={t("widget/controls")}
control={
<Switch
checked={controls}
onChange={() => setControls(!controls)}
color={"primary"}
></Switch>
}
></FormControlLabel>
<FormControlLabel
label={t("widget/loop")}
control={
<Switch
checked={loop}
onChange={() => setLoop(!loop)}
color={"primary"}
></Switch>
}
></FormControlLabel>
<FormControlLabel
label={t("widget/muted")}
control={
<Switch
checked={muted}
onChange={() => setMuted(!muted)}
color={"primary"}
></Switch>
}
></FormControlLabel>
</Box>
</Card>
);
}
Example #29
Source File: index.tsx From vscode-crossnote with GNU Affero General Public License v3.0 | 4 votes |
function OCRWidget(props: WidgetArgs) {
const classes = useStyles(props);
const { t } = useTranslation();
const [canvas, setCanvas] = useState<HTMLCanvasElement>(null);
// https://github.com/tesseract-ocr/tesseract/wiki/Data-Files#data-files-for-version-400-november-29-2016
const [link, setLink] = useState<string>("");
const [imageDataURL, setImageDataURL] = useState<string>("");
const [ocrDataURL, setOCRDataURL] = useState<string>("");
const [imageDropAreaElement, setImageDropAreaElement] = useState<
HTMLInputElement
>(null);
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const [ocrProgresses, setOCRProgresses] = useState<OCRProgress[]>([]);
const [selectedLanguages, setSelectedLanguages] = useState<string[]>(
getInitialLanguages()
);
const [grayscaleChecked, setGrayscaleChecked] = useState<boolean>(true);
useEffect(() => {
if (canvas && imageDataURL) {
const imageObject = new Image();
const context = canvas.getContext("2d");
imageObject.onload = function () {
canvas.width = imageObject.width;
canvas.height = imageObject.height;
context.clearRect(0, 0, canvas.width, canvas.height);
if (grayscaleChecked) {
context.fillStyle = "#FFF";
context.fillRect(0, 0, canvas.width, canvas.height);
context.globalCompositeOperation = "luminosity";
}
context.drawImage(imageObject, 0, 0);
setOCRDataURL(canvas.toDataURL());
};
imageObject.onerror = (error) => {
throw error;
};
imageObject.setAttribute("crossOrigin", "anonymous");
imageObject.src = imageDataURL;
}
}, [canvas, imageDataURL, grayscaleChecked]);
function clickDropArea(e: any) {
e.preventDefault();
e.stopPropagation();
if (!imageDropAreaElement || isProcessing) return;
imageDropAreaElement.onchange = function (event) {
const target = event.target as any;
const files = target.files || [];
if (files.length) {
try {
const file = files[0] as File;
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
setImageDataURL(reader.result as string);
};
reader.onerror = (error) => {
throw error;
};
} catch (error) {}
}
};
imageDropAreaElement.click();
}
function startOCRFromLink() {
try {
setImageDataURL(link);
} catch (error) {}
}
function ocr(input: File | string | HTMLCanvasElement) {
const worker = createWorker({
logger: (m: OCRProgress) => {
setOCRProgresses((ocrProgresses) => {
if (
ocrProgresses.length &&
ocrProgresses[ocrProgresses.length - 1].status === m.status
) {
return [...ocrProgresses.slice(0, ocrProgresses.length - 1), m];
} else {
return [...ocrProgresses, m];
}
});
},
});
(async () => {
setIsProcessing(true);
let languagesArr = selectedLanguages;
if (languagesArr.length === 0) {
languagesArr = ["eng"];
}
await worker.load();
await worker.loadLanguage(languagesArr.join("+"));
await worker.initialize(languagesArr.join("+"));
const {
data: { text },
} = await worker.recognize(input);
props.replaceSelf("\n" + text);
await worker.terminate();
setIsProcessing(false);
})();
}
function toggleLanguage(lang: string) {
setSelectedLanguages((selectedLanguages) => {
const offset = selectedLanguages.indexOf(lang);
if (offset >= 0) {
selectedLanguages.splice(offset, 1);
selectedLanguages = [...selectedLanguages];
} else {
selectedLanguages = [...selectedLanguages, lang];
}
return selectedLanguages;
});
}
if (props.isPreview) {
return <span></span>;
}
if (isProcessing) {
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("general/Processing")}</Typography>
{/*<Typography variant={"body1"}>{t("general/please-wait")}</Typography>*/}
<List>
{ocrProgresses.length > 0 && (
<ListItem>
<ListItemText>
{t(
"tesseract/" + ocrProgresses[ocrProgresses.length - 1].status
)}
</ListItemText>
<ListItemSecondaryAction>
{Math.floor(
ocrProgresses[ocrProgresses.length - 1].progress * 100
).toString() + "%"}
</ListItemSecondaryAction>
</ListItem>
)}
</List>
</Card>
);
}
if (imageDataURL) {
return (
<Card elevation={2} className={clsx(classes.card)}>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.ocr/recognize-text-in-languages")}
</Typography>
<FormGroup>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("eng") >= 0}
onChange={() => toggleLanguage("eng")}
value="eng"
/>
}
label="English"
/>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("chi_sim") >= 0}
onChange={() => toggleLanguage("chi_sim")}
value="chi_sim"
/>
}
label="简体中文"
/>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("chi_tra") >= 0}
onChange={() => toggleLanguage("chi_tra")}
value="chi_tra"
/>
}
label="繁體中文"
/>
<FormControlLabel
control={
<Checkbox
checked={selectedLanguages.indexOf("jpn") >= 0}
onChange={() => toggleLanguage("jpn")}
value="jpn"
/>
}
label="日本語"
/>
</FormGroup>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.ocr/extra-settings")}
</Typography>
<FormControlLabel
control={
<Switch
checked={grayscaleChecked}
onChange={() => {
setGrayscaleChecked(!grayscaleChecked);
}}
color={"primary"}
></Switch>
}
label={t("widget/crossnote.ocr/grayscale")}
></FormControlLabel>
</Box>
<Box className={clsx(classes.canvasWrapper)}>
<canvas
className={clsx(classes.canvas)}
ref={(element) => setCanvas(element)}
></canvas>
</Box>
<ButtonGroup>
<Button
onClick={() => {
setImageDataURL("");
setOCRDataURL("");
}}
>
{t("general/go-back")}
</Button>
<Button
color={"primary"}
onClick={() => ocr(ocrDataURL)}
disabled={!ocrDataURL}
>
{t("widget/crossnote.ocr/start-ocr")}
</Button>
</ButtonGroup>
</Card>
);
}
return (
<Card elevation={2} className={clsx(classes.card)}>
<Typography variant={"h5"}>{t("widget/crossnote.ocr/ocr")}</Typography>
<Box className={clsx(classes.actionButtons)}>
<Tooltip title={t("general/Delete")}>
<IconButton onClick={() => props.removeSelf()}>
<TrashCan></TrashCan>
</IconButton>
</Tooltip>
</Box>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("general/Link")}
</Typography>
<Input
margin={"dense"}
placeholder={t("widget/crossnote.image/image-url-placeholder")}
value={link}
onChange={(event) => {
setLink(event.target.value);
}}
onKeyDown={(event) => {
if (event.which === 13) {
startOCRFromLink();
}
}}
fullWidth={true}
></Input>
</Box>
<Typography
variant={"subtitle1"}
style={{ marginTop: "16px", textAlign: "center" }}
>
{t("widget/crossnote.auth/Or")}
</Typography>
<Box className={clsx(classes.section)}>
<Typography variant={"subtitle1"} style={{ marginBottom: "8px" }}>
{t("widget/crossnote.ocr/local-image")}
</Typography>
<Box
className={clsx(
classes.dropArea,
isProcessing ? classes.disabled : null
)}
onClick={clickDropArea}
>
<Typography>
{isProcessing
? t("utils/uploading-image")
: t("widget/crossnote.image/click-here-to-browse-image-file")}
</Typography>
</Box>
</Box>
<input
type="file"
// multiple
style={{ display: "none" }}
ref={(element: HTMLInputElement) => {
setImageDropAreaElement(element);
}}
></input>
</Card>
);
}