react-icons/fa#FaEyeSlash TypeScript Examples
The following examples show how to use
react-icons/fa#FaEyeSlash.
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: ScannerDisabledRepositoryBadge.tsx From hub with Apache License 2.0 | 6 votes |
ScannerDisabledRepositoryBadge = (props: Props) => {
if (!props.scannerDisabled && !props.allContainersImagesWhitelisted) return null;
return (
<ElementWithTooltip
active
className={props.className}
element={<Label text="Security scanner disabled" labelStyle="warning" icon={<FaEyeSlash />} />}
tooltipMessage="Security scanning of this package has been disabled by the publisher."
visibleTooltip={!isUndefined(props.withTooltip) && props.withTooltip}
/>
);
}
Example #2
Source File: AnnotationList.tsx From slim with Apache License 2.0 | 6 votes |
render (): React.ReactNode {
const items = this.props.rois.map((roi, index) => (
<AnnotationItem
key={roi.uid}
roi={roi}
index={index}
isVisible={this.props.visibleRoiUIDs.includes(roi.uid)}
onVisibilityChange={this.props.onVisibilityChange}
/>
))
return (
<>
<div style={{ paddingLeft: '14px', paddingTop: '7px', paddingBottom: '7px' }}>
<Switch
size='small'
onChange={this.handleVisibilityChange}
checked={this.props.visibleRoiUIDs.length > 0}
checkedChildren={<FaEye />}
unCheckedChildren={<FaEyeSlash />}
/>
</div>
<Menu
selectedKeys={this.props.selectedRoiUIDs}
onSelect={this.handleMenuItemSelection}
onClick={this.handleMenuItemSelection}
>
{items}
</Menu>
</>
)
}
Example #3
Source File: DisabledRepositoryBadge.tsx From hub with Apache License 2.0 | 5 votes |
DisabledRepositoryBadge = (props: Props) => {
if (!props.disabled) return null;
return <Label text="Disabled" labelStyle="warning" className={props.className} icon={<FaEyeSlash />} />;
}
Example #4
Source File: IPMenu.tsx From iplocate with MIT License | 5 votes |
IPMenu: React.FC<Props> = (props) => {
const { ips, onSetCurrentIp, onToggleIpVisible, onRemoveIp } = props;
if (ips.length === 0) return null;
return (
<Wrapper>
{ips.map((ip) => (
<Row key={ip.traits.ipAddress}>
<RowText onClick={() => onSetCurrentIp(ip)}>
{ip.traits.ipAddress}
</RowText>
<div>
<RowAction
onClick={() => onRemoveIp(ip)}
aria-label="remove ip address"
>
<FaTrash />
</RowAction>
{ip.hidden ? (
<RowAction
onClick={() => onToggleIpVisible(ip)}
aria-label="toggle ip visibility on"
>
<FaEyeSlash />
</RowAction>
) : (
<RowAction
onClick={() => onToggleIpVisible(ip)}
aria-label="toggle ip visibility off"
>
<FaEye />
</RowAction>
)}
</div>
</Row>
))}
</Wrapper>
);
}
Example #5
Source File: InputField.tsx From hub with Apache License 2.0 | 4 votes |
InputField = forwardRef((props: Props, ref: Ref<RefInputField>) => {
const input = useRef<HTMLInputElement>(null);
const [isValid, setIsValid] = useState<boolean | null>(null);
const [inputValue, setInputValue] = useState(props.value || '');
const [invalidText, setInvalidText] = useState(!isUndefined(props.invalidText) ? props.invalidText.default : '');
const [isCheckingAvailability, setIsCheckingAvailability] = useState(false);
const [isCheckingPwdStrength, setIsCheckingPwdStrength] = useState(false);
const [pwdStrengthError, setPwdStrengthError] = useState<string | null>(null);
const [activeType, setActiveType] = useState<string>(props.type);
const [validateTimeout, setValidateTimeout] = useState<NodeJS.Timeout | null>(null);
useImperativeHandle(ref, () => ({
checkIsValid(): Promise<boolean> {
return isValidField();
},
reset: () => {
setInputValue('');
},
getValue(): string {
return inputValue;
},
checkValidity(): boolean {
return input.current ? input.current!.checkValidity() : true;
},
updateValue(newValue: string): void {
setInputValue(newValue);
},
}));
const checkValidity = (): boolean => {
let isInputValid = true;
if (input.current) {
isInputValid = input.current!.checkValidity();
if (!isInputValid && !isUndefined(props.invalidText)) {
let errorTxt = props.invalidText.default;
const validityState: ValidityState | undefined = input.current.validity;
if (!isUndefined(validityState)) {
if (validityState.typeMismatch && !isUndefined(props.invalidText.typeMismatch)) {
errorTxt = props.invalidText.typeMismatch;
} else if (validityState.tooShort && !isUndefined(props.invalidText.tooShort)) {
errorTxt = props.invalidText.tooShort;
} else if (validityState.patternMismatch && !isUndefined(props.invalidText.patternMismatch)) {
errorTxt = props.invalidText.patternMismatch;
} else if (validityState.typeMismatch && !isUndefined(props.invalidText.typeMismatch)) {
errorTxt = props.invalidText.typeMismatch;
} else if (validityState.rangeUnderflow && !isUndefined(props.invalidText.rangeUnderflow)) {
errorTxt = props.invalidText.rangeUnderflow;
} else if (validityState.rangeOverflow && !isUndefined(props.invalidText.rangeOverflow)) {
errorTxt = props.invalidText.rangeOverflow;
} else if (validityState.customError && !isUndefined(props.invalidText.customError)) {
if (!isUndefined(props.excludedValues) && props.excludedValues.includes(input.current.value)) {
errorTxt = props.invalidText.excluded;
} else {
errorTxt = props.invalidText.customError;
}
}
}
setInvalidText(errorTxt);
}
setIsValid(isInputValid);
if (!isUndefined(props.setValidationStatus)) {
props.setValidationStatus(false);
}
}
return isInputValid;
};
const isValidField = async (): Promise<boolean> => {
if (input.current) {
const value = input.current!.value;
if (value !== '') {
if (!isUndefined(props.excludedValues) && props.excludedValues.includes(value)) {
input.current!.setCustomValidity('Value is excluded');
} else if (!isUndefined(props.checkAvailability) && !props.checkAvailability.excluded.includes(value)) {
setIsCheckingAvailability(true);
try {
const isAvailable = await API.checkAvailability({
resourceKind: props.checkAvailability.resourceKind,
value: value,
});
if (!isNull(input.current)) {
if (isAvailable) {
input.current!.setCustomValidity(props.checkAvailability!.isAvailable ? 'Already taken' : '');
} else {
input.current!.setCustomValidity(props.checkAvailability!.isAvailable ? '' : 'Resource is not valid');
}
}
} catch {
if (!isNull(input.current)) {
input.current!.setCustomValidity(props.checkAvailability!.isAvailable ? 'Already taken' : '');
}
}
setIsCheckingAvailability(false);
} else if (props.checkPasswordStrength) {
setIsCheckingPwdStrength(true);
try {
await API.checkPasswordStrength(value);
if (!isNull(input.current)) {
input.current!.setCustomValidity('');
setPwdStrengthError(null);
}
} catch (e: any) {
if (!isNull(input.current) && e.message) {
setPwdStrengthError(e.message);
input.current!.setCustomValidity(e.message);
}
}
setIsCheckingPwdStrength(false);
} else {
if (!isNull(input.current)) {
input.current!.setCustomValidity('');
}
}
}
}
return checkValidity();
};
const handleOnBlur = (): void => {
if (!isUndefined(props.validateOnBlur) && props.validateOnBlur && input.current) {
cleanTimeout(); // On blur we clean timeout if it's necessary
isValidField();
}
};
const handleOnChange = (e: ChangeEvent<HTMLInputElement>): void => {
setInputValue(e.target.value);
if (!isUndefined(props.onChange)) {
props.onChange(e);
}
};
const cleanTimeout = () => {
if (!isNull(validateTimeout)) {
clearTimeout(validateTimeout);
setValidateTimeout(null);
}
};
useEffect(() => {
const isInputFocused = input.current === document.activeElement;
if (isInputFocused && !isUndefined(props.validateOnChange) && props.validateOnChange) {
cleanTimeout();
setValidateTimeout(
setTimeout(() => {
isValidField();
}, VALIDATION_DELAY)
);
}
return () => {
if (validateTimeout) {
clearTimeout(validateTimeout);
}
};
}, [inputValue]); /* eslint-disable-line react-hooks/exhaustive-deps */
return (
<div className={`${props.smallBottomMargin ? 'mb-3' : 'mb-4'} position-relative ${props.className}`}>
{!isUndefined(props.label) && (
<label htmlFor={props.name} className={`form-label fw-bold ${styles.label}`}>
<span className="fw-bold">{props.label}</span>
{!isUndefined(props.labelLegend) && <>{props.labelLegend}</>}
</label>
)}
<input
data-testid={`${props.name}Input`}
ref={input}
type={activeType}
id={props.name}
name={props.name}
value={inputValue}
className={classnames('form-control', props.inputClassName, { 'is-invalid': !isNull(isValid) && !isValid })}
placeholder={props.placeholder}
required={props.required}
minLength={props.minLength}
maxLength={props.maxLength}
min={props.min}
max={props.max}
pattern={props.pattern}
autoComplete={props.autoComplete}
readOnly={props.readOnly || false}
onChange={handleOnChange}
onBlur={handleOnBlur}
onKeyDown={props.onKeyDown}
autoFocus={props.autoFocus}
disabled={props.disabled}
spellCheck="false"
/>
{props.type === 'password' && props.visiblePassword && (
<button
type="button"
className={classnames('btn btn-link position-absolute bottom-0', styles.revealBtn, {
'text-muted': activeType === 'password',
'text-secondary': activeType !== 'password',
})}
onClick={() => setActiveType(activeType === 'password' ? 'text' : 'password')}
aria-label={`${activeType === 'password' ? 'Hide' : 'Show'} password`}
>
{activeType === 'password' ? <FaEyeSlash /> : <FaEye />}
</button>
)}
{(isCheckingAvailability || isCheckingPwdStrength) && (
<div className={`position-absolute ${styles.spinner}`}>
<span className="spinner-border spinner-border-sm text-primary" />
</div>
)}
{!isUndefined(props.validText) && (
<div className={`valid-feedback mt-0 ${styles.inputFeedback}`}>{props.validText}</div>
)}
{!isUndefined(invalidText) && isNull(pwdStrengthError) && (
<div className={`invalid-feedback mt-0 ${styles.inputFeedback}`}>{invalidText}</div>
)}
{!isNull(pwdStrengthError) && (
<div className={`invalid-feedback mt-0 ${styles.inputPwdStrengthError}`}>
{capitalizeFirstLetter(pwdStrengthError)}
</div>
)}
{!isUndefined(props.additionalInfo) && <div className="alert p-0 mt-4">{props.additionalInfo}</div>}
</div>
);
})
Example #6
Source File: AnnotationGroupItem.tsx From slim with Apache License 2.0 | 4 votes |
render (): React.ReactNode {
const identifier = `Annotation Group ${this.props.annotationGroup.number}`
const attributes: Array<{ name: string, value: string }> = [
{
name: 'Label',
value: this.props.annotationGroup.label
},
{
name: 'Algorithm Name',
value: this.props.annotationGroup.algorithmName
},
{
name: 'Property category',
value: this.props.annotationGroup.propertyCategory.CodeMeaning
},
{
name: 'Property type',
value: this.props.annotationGroup.propertyType.CodeMeaning
}
]
const index = this.props.metadata.AnnotationGroupSequence.findIndex(
item => (item.AnnotationGroupUID === this.props.annotationGroup.uid)
)
const item = this.props.metadata.AnnotationGroupSequence[index]
const measurementsSequence = item.MeasurementsSequence ?? []
const measurementOptions = measurementsSequence.map(measurementItem => {
const name = measurementItem.ConceptNameCodeSequence[0]
const key = `${name.CodingSchemeDesignator}-${name.CodeValue}`
return (
<Select.Option
key={key}
value={key}
dropdownMatchSelectWidth={false}
size='small'
disabled={!this.props.isVisible}
>
{name.CodeMeaning}
</Select.Option>
)
})
const settings = (
<div>
<Row justify='start' align='middle' gutter={[8, 8]}>
<Col span={6}>
Opacity
</Col>
<Col span={12}>
<Slider
range={false}
min={0}
max={1}
step={0.01}
value={this.state.currentStyle.opacity}
onChange={this.handleOpacityChange}
/>
</Col>
<Col span={6}>
<InputNumber
min={0}
max={1}
size='small'
step={0.1}
style={{ width: '65px' }}
value={this.state.currentStyle.opacity}
onChange={this.handleOpacityChange}
/>
</Col>
</Row>
<Divider plain>
Exploration
</Divider>
<Row justify='start' align='middle' gutter={[8, 8]}>
<Col span={8}>
Measurement
</Col>
<Col span={16}>
<Select
style={{ minWidth: '65px', width: '90%' }}
onSelect={this.handleMeasurementSelection}
key='annotation-group-measurements'
defaultValue={undefined}
>
{measurementOptions}
</Select>
</Col>
</Row>
</div>
)
const {
annotationGroup,
defaultStyle,
isVisible,
metadata,
onVisibilityChange,
onStyleChange,
...otherProps
} = this.props
return (
<Menu.Item
style={{ height: '100%', paddingLeft: '3px' }}
key={this.props.annotationGroup.uid}
{...otherProps}
>
<Space align='start'>
<div style={{ paddingLeft: '14px' }}>
<Space direction='vertical' align='end'>
<Switch
size='small'
onChange={this.handleVisibilityChange}
checked={this.props.isVisible}
checkedChildren={<FaEye />}
unCheckedChildren={<FaEyeSlash />}
/>
<Popover
placement='left'
content={settings}
overlayStyle={{ width: '350px' }}
title='Display Settings'
>
<Button
type='primary'
shape='circle'
icon={<SettingOutlined />}
/>
</Popover>
</Space>
</div>
<Description
header={identifier}
attributes={attributes}
selectable
hasLongValues
/>
</Space>
</Menu.Item>
)
}
Example #7
Source File: AnnotationItem.tsx From slim with Apache License 2.0 | 4 votes |
render (): React.ReactNode {
const identifier = `ROI ${this.props.index + 1}`
const attributes: Array<{ name: string, value: string }> = []
/**
* This hack is required for Menu.Item to work properly:
* https://github.com/react-component/menu/issues/142
*/
const { isVisible, onVisibilityChange, ...otherProps } = this.props
this.props.roi.evaluations.forEach((
item: (
dcmjs.sr.valueTypes.TextContentItem |
dcmjs.sr.valueTypes.CodeContentItem
)
) => {
const nameValue = item.ConceptNameCodeSequence[0].CodeValue
const nameMeaning = item.ConceptNameCodeSequence[0].CodeMeaning
const name = `${nameMeaning}`
if (item.ValueType === dcmjs.sr.valueTypes.ValueTypes.CODE) {
const codeContentItem = item as dcmjs.sr.valueTypes.CodeContentItem
const valueMeaning = codeContentItem.ConceptCodeSequence[0].CodeMeaning
// For consistency with Segment and Annotation Group
if (nameValue === '276214006') {
attributes.push({
name: 'Property category',
value: `${valueMeaning}`
})
} else if (nameValue === '121071') {
attributes.push({
name: 'Property type',
value: `${valueMeaning}`
})
} else if (nameValue === '111001') {
attributes.push({
name: 'Algorithm Name',
value: `${valueMeaning}`
})
} else {
attributes.push({
name: name,
value: `${valueMeaning}`
})
}
} else if (item.ValueType === dcmjs.sr.valueTypes.ValueTypes.TEXT) {
const textContentItem = item as dcmjs.sr.valueTypes.TextContentItem
attributes.push({
name: name,
value: textContentItem.TextValue
})
}
})
this.props.roi.measurements.forEach(item => {
const nameMeaning = item.ConceptNameCodeSequence[0].CodeMeaning
const name = `${nameMeaning}`
const seq = item.MeasuredValueSequence[0]
const value = seq.NumericValue.toPrecision(6)
const unit = seq.MeasurementUnitsCodeSequence[0].CodeValue
attributes.push({
name: name,
value: `${value} ${unit}`
})
})
return (
<Space align='start'>
<div style={{ paddingLeft: '14px' }}>
<Switch
size='small'
onChange={this.handleVisibilityChange}
checked={this.props.isVisible}
checkedChildren={<FaEye />}
unCheckedChildren={<FaEyeSlash />}
/>
</div>
<Menu.Item
style={{ height: '100%', paddingLeft: '3px' }}
key={this.props.roi.uid}
{...otherProps}
>
<Description
header={identifier}
attributes={attributes}
selectable
hasLongValues
/>
</Menu.Item>
</Space>
)
}
Example #8
Source File: MappingItem.tsx From slim with Apache License 2.0 | 4 votes |
render (): React.ReactNode {
const identifier = `Mapping ${this.props.mapping.number}`
const attributes: Array<{ name: string, value: string }> = [
{
name: 'Label',
value: this.props.mapping.label
}
]
const settings = (
<div>
<Row justify='center' align='middle'>
<Col span={6}>
Opacity
</Col>
<Col span={12}>
<Slider
range={false}
min={0}
max={1}
step={0.01}
value={this.state.currentStyle.opacity}
onChange={this.handleOpacityChange}
/>
</Col>
<Col span={6}>
<InputNumber
min={0}
max={1}
size='small'
step={0.1}
style={{ width: '65px' }}
value={this.state.currentStyle.opacity}
onChange={this.handleOpacityChange}
/>
</Col>
</Row>
</div>
)
/**
* This hack is required for Menu.Item to work properly:
* https://github.com/react-component/menu/issues/142
*/
const {
defaultStyle,
isVisible,
mapping,
metadata,
onVisibilityChange,
onStyleChange,
...otherProps
} = this.props
return (
<Menu.Item
style={{ height: '100%', paddingLeft: '3px' }}
key={this.props.mapping.uid}
{...otherProps}
>
<Space align='start'>
<div style={{ paddingLeft: '14px' }}>
<Space direction='vertical' align='end' size={100}>
<Space direction='vertical' align='end'>
<Switch
size='small'
onChange={this.handleVisibilityChange}
checked={this.props.isVisible}
checkedChildren={<FaEye />}
unCheckedChildren={<FaEyeSlash />}
/>
<Popover
placement='left'
content={settings}
overlayStyle={{ width: '350px' }}
title='Display Settings'
>
<Button
type='primary'
shape='circle'
icon={<SettingOutlined />}
/>
</Popover>
</Space>
</Space>
</div>
<Description
header={identifier}
attributes={attributes}
selectable
hasLongValues
/>
</Space>
</Menu.Item>
)
}
Example #9
Source File: SegmentItem.tsx From slim with Apache License 2.0 | 4 votes |
render (): React.ReactNode {
const attributes: Array<{ name: string, value: string }> = [
{
name: 'Property Category',
value: this.props.segment.propertyCategory.CodeMeaning
},
{
name: 'Property Type',
value: this.props.segment.propertyType.CodeMeaning
},
{
name: 'Algorithm Name',
value: this.props.segment.algorithmName
}
]
const settings = (
<div>
<Row justify='center' align='middle'>
<Col span={6}>
Opacity
</Col>
<Col span={12}>
<Slider
range={false}
min={0}
max={1}
step={0.01}
value={this.state.currentStyle.opacity}
onChange={this.handleOpacityChange}
/>
</Col>
<Col span={6}>
<InputNumber
min={0}
max={1}
size='small'
step={0.1}
style={{ width: '65px' }}
value={this.state.currentStyle.opacity}
onChange={this.handleOpacityChange}
/>
</Col>
</Row>
</div>
)
/**
* This hack is required for Menu.Item to work properly:
* https://github.com/react-component/menu/issues/142
*/
const {
defaultStyle,
isVisible,
segment,
metadata,
onVisibilityChange,
onStyleChange,
...otherProps
} = this.props
return (
<Menu.Item
style={{ height: '100%', paddingLeft: '3px' }}
key={this.props.segment.uid}
{...otherProps}
>
<Space align='start'>
<div style={{ paddingLeft: '14px' }}>
<Space direction='vertical' align='end'>
<Switch
size='small'
onChange={this.handleVisibilityChange}
checked={this.props.isVisible}
checkedChildren={<FaEye />}
unCheckedChildren={<FaEyeSlash />}
/>
<Popover
placement='left'
content={settings}
overlayStyle={{ width: '350px' }}
title='Display Settings'
>
<Button
type='primary'
shape='circle'
icon={<SettingOutlined />}
/>
</Popover>
</Space>
</div>
<Description
header={this.props.segment.label}
attributes={attributes}
selectable
hasLongValues
/>
</Space>
</Menu.Item>
)
}
Example #10
Source File: SlideViewer.tsx From slim with Apache License 2.0 | 4 votes |
render (): React.ReactNode {
const rois: dmv.roi.ROI[] = []
const segments: dmv.segment.Segment[] = []
const mappings: dmv.mapping.ParameterMapping[] = []
const annotationGroups: dmv.annotation.AnnotationGroup[] = []
rois.push(...this.volumeViewer.getAllROIs())
segments.push(...this.volumeViewer.getAllSegments())
mappings.push(...this.volumeViewer.getAllParameterMappings())
annotationGroups.push(...this.volumeViewer.getAllAnnotationGroups())
const openSubMenuItems = ['specimens', 'opticalpaths', 'annotations']
let report: React.ReactNode
const dataset = this.state.generatedReport
if (dataset !== undefined) {
report = <Report dataset={dataset} />
}
let annotationMenuItems: React.ReactNode
if (rois.length > 0) {
annotationMenuItems = (
<AnnotationList
rois={rois}
selectedRoiUIDs={this.state.selectedRoiUIDs}
visibleRoiUIDs={this.state.visibleRoiUIDs}
onSelection={this.handleAnnotationSelection}
onVisibilityChange={this.handleAnnotationVisibilityChange}
/>
)
}
const findingOptions = this.findingOptions.map(finding => {
return (
<Select.Option
key={finding.CodeValue}
value={finding.CodeValue}
>
{finding.CodeMeaning}
</Select.Option>
)
})
const geometryTypeOptionsMapping: { [key: string]: React.ReactNode } = {
point: <Select.Option key='point' value='point'>Point</Select.Option>,
circle: <Select.Option key='circle' value='circle'>Circle</Select.Option>,
box: <Select.Option key='box' value='box'>Box</Select.Option>,
polygon: <Select.Option key='polygon' value='polygon'>Polygon</Select.Option>,
line: <Select.Option key='line' value='line'>Line</Select.Option>,
freehandpolygon: (
<Select.Option key='freehandpolygon' value='freehandpolygon'>
Polygon (freehand)
</Select.Option>
),
freehandline: (
<Select.Option key='freehandline' value='freehandline'>
Line (freehand)
</Select.Option>
)
}
const selections: React.ReactNode[] = [
(
<Select
style={{ minWidth: 130 }}
onSelect={this.handleAnnotationFindingSelection}
key='annotation-finding'
defaultActiveFirstOption
>
{findingOptions}
</Select>
)
]
const selectedFinding = this.state.selectedFinding
if (selectedFinding !== undefined) {
const key = _buildKey(selectedFinding)
this.evaluationOptions[key].forEach(evaluation => {
const evaluationOptions = evaluation.values.map(code => {
return (
<Select.Option
key={code.CodeValue}
value={code.CodeValue}
label={evaluation.name}
>
{code.CodeMeaning}
</Select.Option>
)
})
selections.push(
<>
{evaluation.name.CodeMeaning}
<Select
style={{ minWidth: 130 }}
onSelect={this.handleAnnotationEvaluationSelection}
allowClear
onClear={this.handleAnnotationEvaluationClearance}
defaultActiveFirstOption={false}
>
{evaluationOptions}
</Select>
</>
)
})
const geometryTypeOptions = this.geometryTypeOptions[key].map(name => {
return geometryTypeOptionsMapping[name]
})
selections.push(
<Select
style={{ minWidth: 130 }}
onSelect={this.handleAnnotationGeometryTypeSelection}
key='annotation-geometry-type'
>
{geometryTypeOptions}
</Select>
)
selections.push(
<Checkbox
onChange={this.handleAnnotationMeasurementActivation}
key='annotation-measurement'
>
measure
</Checkbox>
)
}
const specimenMenu = (
<Menu.SubMenu key='specimens' title='Specimens'>
<SpecimenList
metadata={this.props.slide.volumeImages[0]}
showstain={false}
/>
</Menu.SubMenu>
)
const equipmentMenu = (
<Menu.SubMenu key='equipment' title='Equipment'>
<Equipment metadata={this.props.slide.volumeImages[0]} />
</Menu.SubMenu>
)
const defaultOpticalPathStyles: {
[identifier: string]: {
opacity: number
color?: number[]
limitValues?: number[]
}
} = {}
const opticalPathMetadata: {
[identifier: string]: dmv.metadata.VLWholeSlideMicroscopyImage[]
} = {}
const opticalPaths = this.volumeViewer.getAllOpticalPaths()
opticalPaths.sort((a, b) => {
if (a.identifier < b.identifier) {
return -1
} else if (a.identifier > b.identifier) {
return 1
}
return 0
})
opticalPaths.forEach(opticalPath => {
const identifier = opticalPath.identifier
const metadata = this.volumeViewer.getOpticalPathMetadata(identifier)
opticalPathMetadata[identifier] = metadata
const style = this.volumeViewer.getOpticalPathStyle(identifier)
defaultOpticalPathStyles[identifier] = style
})
const opticalPathMenu = (
<Menu.SubMenu key='opticalpaths' title='Optical Paths'>
<OpticalPathList
metadata={opticalPathMetadata}
opticalPaths={opticalPaths}
defaultOpticalPathStyles={defaultOpticalPathStyles}
visibleOpticalPathIdentifiers={this.state.visibleOpticalPathIdentifiers}
activeOpticalPathIdentifiers={this.state.activeOpticalPathIdentifiers}
onOpticalPathVisibilityChange={this.handleOpticalPathVisibilityChange}
onOpticalPathStyleChange={this.handleOpticalPathStyleChange}
onOpticalPathActivityChange={this.handleOpticalPathActivityChange}
selectedPresentationStateUID={this.state.selectedPresentationStateUID}
/>
</Menu.SubMenu>
)
let presentationStateMenu
console.log('DEBUG: ', this.state.presentationStates)
if (this.state.presentationStates.length > 0) {
const presentationStateOptions = this.state.presentationStates.map(
presentationState => {
return (
<Select.Option
key={presentationState.SOPInstanceUID}
value={presentationState.SOPInstanceUID}
dropdownMatchSelectWidth={false}
size='small'
>
{presentationState.ContentDescription}
</Select.Option>
)
}
)
presentationStateMenu = (
<Menu.SubMenu key='presentationStates' title='Presentation States'>
<Space align='center' size={20} style={{ padding: '14px' }}>
<Select
style={{ minWidth: 200, maxWidth: 200 }}
onSelect={this.handlePresentationStateSelection}
key='presentation-states'
defaultValue={this.props.selectedPresentationStateUID}
value={this.state.selectedPresentationStateUID}
>
{presentationStateOptions}
</Select>
<Tooltip title='Reset'>
<Btn
icon={<UndoOutlined />}
type='primary'
onClick={this.handlePresentationStateReset}
/>
</Tooltip>
</Space>
</Menu.SubMenu>
)
}
let segmentationMenu
if (segments.length > 0) {
const defaultSegmentStyles: {
[segmentUID: string]: {
opacity: number
}
} = {}
const segmentMetadata: {
[segmentUID: string]: dmv.metadata.Segmentation[]
} = {}
const segments = this.volumeViewer.getAllSegments()
segments.forEach(segment => {
defaultSegmentStyles[segment.uid] = this.volumeViewer.getSegmentStyle(
segment.uid
)
segmentMetadata[segment.uid] = this.volumeViewer.getSegmentMetadata(
segment.uid
)
})
segmentationMenu = (
<Menu.SubMenu key='segmentations' title='Segmentations'>
<SegmentList
segments={segments}
metadata={segmentMetadata}
defaultSegmentStyles={defaultSegmentStyles}
visibleSegmentUIDs={this.state.visibleSegmentUIDs}
onSegmentVisibilityChange={this.handleSegmentVisibilityChange}
onSegmentStyleChange={this.handleSegmentStyleChange}
/>
</Menu.SubMenu>
)
openSubMenuItems.push('segmentations')
}
let parametricMapMenu
if (mappings.length > 0) {
const defaultMappingStyles: {
[mappingUID: string]: {
opacity: number
}
} = {}
const mappingMetadata: {
[mappingUID: string]: dmv.metadata.ParametricMap[]
} = {}
mappings.forEach(mapping => {
defaultMappingStyles[mapping.uid] = this.volumeViewer.getParameterMappingStyle(
mapping.uid
)
mappingMetadata[mapping.uid] = this.volumeViewer.getParameterMappingMetadata(
mapping.uid
)
})
parametricMapMenu = (
<Menu.SubMenu key='parmetricmaps' title='Parametric Maps'>
<MappingList
mappings={mappings}
metadata={mappingMetadata}
defaultMappingStyles={defaultMappingStyles}
visibleMappingUIDs={this.state.visibleMappingUIDs}
onMappingVisibilityChange={this.handleMappingVisibilityChange}
onMappingStyleChange={this.handleMappingStyleChange}
/>
</Menu.SubMenu>
)
openSubMenuItems.push('parametricmaps')
}
let annotationGroupMenu
if (annotationGroups.length > 0) {
const defaultAnnotationGroupStyles: {
[annotationGroupUID: string]: {
opacity: number
}
} = {}
const annotationGroupMetadata: {
[annotationGroupUID: string]: dmv.metadata.MicroscopyBulkSimpleAnnotations
} = {}
const annotationGroups = this.volumeViewer.getAllAnnotationGroups()
annotationGroups.forEach(annotationGroup => {
defaultAnnotationGroupStyles[annotationGroup.uid] = this.volumeViewer.getAnnotationGroupStyle(
annotationGroup.uid
)
annotationGroupMetadata[annotationGroup.uid] = this.volumeViewer.getAnnotationGroupMetadata(
annotationGroup.uid
)
})
annotationGroupMenu = (
<Menu.SubMenu key='annotationGroups' title='Annotation Groups'>
<AnnotationGroupList
annotationGroups={annotationGroups}
metadata={annotationGroupMetadata}
defaultAnnotationGroupStyles={defaultAnnotationGroupStyles}
visibleAnnotationGroupUIDs={this.state.visibleAnnotationGroupUIDs}
onAnnotationGroupVisibilityChange={this.handleAnnotationGroupVisibilityChange}
onAnnotationGroupStyleChange={this.handleAnnotationGroupStyleChange}
/>
</Menu.SubMenu>
)
openSubMenuItems.push('annotationGroups')
}
let toolbar
let toolbarHeight = '0px'
if (this.props.enableAnnotationTools) {
toolbar = (
<Row>
<Button
tooltip='Draw ROI [d]'
icon={FaDrawPolygon}
onClick={this.handleRoiDrawing}
isSelected={this.state.isRoiDrawingActive}
/>
<Button
tooltip='Modify ROIs [m]'
icon={FaHandPointer}
onClick={this.handleRoiModification}
isSelected={this.state.isRoiModificationActive}
/>
<Button
tooltip='Translate ROIs [t]'
icon={FaHandPaper}
onClick={this.handleRoiTranslation}
isSelected={this.state.isRoiTranslationActive}
/>
<Button
tooltip='Remove selected ROI [r]'
onClick={this.handleRoiRemoval}
icon={FaTrash}
/>
<Button
tooltip='Show/Hide ROIs [v]'
icon={this.state.areRoisHidden ? FaEye : FaEyeSlash}
onClick={this.handleRoiVisibilityChange}
isSelected={this.state.areRoisHidden}
/>
<Button
tooltip='Save ROIs [s]'
icon={FaSave}
onClick={this.handleReportGeneration}
/>
</Row>
)
toolbarHeight = '50px'
}
/* It would be nicer to use the ant Spin component, but that causes issues
* with the positioning of the viewport.
*/
let loadingDisplay = 'none'
if (this.state.isLoading) {
loadingDisplay = 'block'
}
return (
<Layout style={{ height: '100%' }} hasSider>
<Layout.Content style={{ height: '100%' }}>
{toolbar}
<div className='dimmer' style={{ display: loadingDisplay }} />
<div className='spinner' style={{ display: loadingDisplay }} />
<div
style={{
height: `calc(100% - ${toolbarHeight})`,
overflow: 'hidden'
}}
ref={this.volumeViewportRef}
/>
<Modal
visible={this.state.isAnnotationModalVisible}
title='Configure annotations'
onOk={this.handleAnnotationConfigurationCompletion}
onCancel={this.handleAnnotationConfigurationCancellation}
okText='Select'
>
<Space align='start' direction='vertical'>
{selections}
</Space>
</Modal>
<Modal
visible={this.state.isReportModalVisible}
title='Verify and save report'
onOk={this.handleReportVerification}
onCancel={this.handleReportCancellation}
okText='Save'
>
{report}
</Modal>
</Layout.Content>
<Layout.Sider
width={300}
reverseArrow
style={{
borderLeft: 'solid',
borderLeftWidth: 0.25,
overflow: 'hidden',
background: 'none'
}}
>
<Menu
mode='inline'
defaultOpenKeys={openSubMenuItems}
style={{ height: '100%' }}
inlineIndent={14}
forceSubMenuRender
>
<Menu.SubMenu key='label' title='Slide label'>
<Menu.Item style={{ height: '100%' }}>
<div
style={{ height: '220px' }}
ref={this.labelViewportRef}
/>
</Menu.Item>
</Menu.SubMenu>
{specimenMenu}
{equipmentMenu}
{opticalPathMenu}
{presentationStateMenu}
<Menu.SubMenu key='annotations' title='Annotations'>
{annotationMenuItems}
</Menu.SubMenu>
{annotationGroupMenu}
{segmentationMenu}
{parametricMapMenu}
</Menu>
</Layout.Sider>
</Layout>
)
}
Example #11
Source File: Builder.tsx From crosshare with GNU Affero General Public License v3.0 | 4 votes |
GridMode = ({
getMostConstrainedEntry,
reRunAutofill,
state,
dispatch,
setClueMode,
...props
}: GridModeProps) => {
const [muted, setMuted] = usePersistedBoolean('muted', false);
const [toggleKeyboard, setToggleKeyboard] = usePersistedBoolean(
'keyboard',
false
);
const { showSnackbar } = useSnackbar();
const gridRef = useRef<HTMLDivElement | null>(null);
const focusGrid = useCallback(() => {
if (gridRef.current) {
gridRef.current.focus();
}
}, []);
const physicalKeyboardHandler = useCallback(
(e: KeyboardEvent) => {
const mkey = fromKeyboardEvent(e);
if (isSome(mkey)) {
e.preventDefault();
if (mkey.value.k === KeyK.Enter && !state.isEnteringRebus) {
reRunAutofill();
return;
}
if (mkey.value.k === KeyK.Exclamation) {
const entry = getMostConstrainedEntry();
if (entry !== null) {
const ca: ClickedEntryAction = {
type: 'CLICKEDENTRY',
entryIndex: entry,
};
dispatch(ca);
}
return;
}
if (mkey.value.k === KeyK.Octothorp) {
const a: ToggleHiddenAction = { type: 'TOGGLEHIDDEN' };
dispatch(a);
}
const kpa: KeypressAction = { type: 'KEYPRESS', key: mkey.value };
dispatch(kpa);
}
},
[dispatch, reRunAutofill, state.isEnteringRebus, getMostConstrainedEntry]
);
useEventListener(
'keydown',
physicalKeyboardHandler,
gridRef.current || undefined
);
const pasteHandler = useCallback(
(e: ClipboardEvent) => {
const tagName = (e.target as HTMLElement)?.tagName?.toLowerCase();
if (tagName === 'textarea' || tagName === 'input') {
return;
}
const pa: PasteAction = {
type: 'PASTE',
content: e.clipboardData?.getData('Text') || '',
};
dispatch(pa);
e.preventDefault();
},
[dispatch]
);
useEventListener('paste', pasteHandler);
const fillLists = useMemo(() => {
let left = <></>;
let right = <></>;
const [entry, cross] = entryAndCrossAtPosition(state.grid, state.active);
let crossMatches = cross && potentialFill(cross, state.grid);
let entryMatches = entry && potentialFill(entry, state.grid);
if (
crossMatches !== null &&
entryMatches !== null &&
entry !== null &&
cross !== null
) {
/* If we have both entry + cross we now filter for only matches that'd work for both. */
const entryActiveIndex = activeIndex(state.grid, state.active, entry);
const crossActiveIndex = activeIndex(state.grid, state.active, cross);
const entryValidLetters = lettersAtIndex(entryMatches, entryActiveIndex);
const crossValidLetters = lettersAtIndex(crossMatches, crossActiveIndex);
const validLetters = (
entryValidLetters.match(
new RegExp('[' + crossValidLetters + ']', 'g')
) || []
).join('');
entryMatches = entryMatches.filter(([word]) => {
const l = word[entryActiveIndex];
return l && validLetters.indexOf(l) !== -1;
});
crossMatches = crossMatches.filter(([word]) => {
const l = word[crossActiveIndex];
return l && validLetters.indexOf(l) !== -1;
});
}
if (cross && crossMatches !== null) {
if (cross.direction === Direction.Across) {
left = (
<PotentialFillList
selected={false}
gridRef={gridRef}
header="Across"
values={crossMatches}
entryIndex={cross.index}
dispatch={dispatch}
/>
);
} else {
right = (
<PotentialFillList
selected={false}
gridRef={gridRef}
header="Down"
values={crossMatches}
entryIndex={cross.index}
dispatch={dispatch}
/>
);
}
}
if (entry && entryMatches !== null) {
if (entry.direction === Direction.Across) {
left = (
<PotentialFillList
selected={true}
gridRef={gridRef}
header="Across"
values={entryMatches}
entryIndex={entry.index}
dispatch={dispatch}
/>
);
} else {
right = (
<PotentialFillList
selected={true}
gridRef={gridRef}
header="Down"
values={entryMatches}
entryIndex={entry.index}
dispatch={dispatch}
/>
);
}
}
return { left, right };
}, [state.grid, state.active, dispatch]);
const { autofillEnabled, setAutofillEnabled } = props;
const toggleAutofillEnabled = useCallback(() => {
if (autofillEnabled) {
showSnackbar('Autofill Disabled');
}
setAutofillEnabled(!autofillEnabled);
}, [autofillEnabled, setAutofillEnabled, showSnackbar]);
const stats = useMemo(() => {
let totalLength = 0;
const lengthHistogram: Array<number> = new Array(
Math.max(state.grid.width, state.grid.height) - 1
).fill(0);
const lengthHistogramNames = lengthHistogram.map((_, i) =>
(i + 2).toString()
);
state.grid.entries.forEach((e) => {
totalLength += e.cells.length;
lengthHistogram[e.cells.length - 2] += 1;
});
const numEntries = state.grid.entries.length;
const averageLength = totalLength / numEntries;
const lettersHistogram: Array<number> = new Array(26).fill(0);
const lettersHistogramNames = lettersHistogram.map((_, i) =>
String.fromCharCode(i + 65)
);
let numBlocks = 0;
const numTotal = state.grid.width * state.grid.height;
state.grid.cells.forEach((s) => {
if (s === '.') {
numBlocks += 1;
} else {
const index = lettersHistogramNames.indexOf(s);
if (index !== -1) {
lettersHistogram[index] += 1;
}
}
});
return {
numBlocks,
numTotal,
lengthHistogram,
lengthHistogramNames,
numEntries,
averageLength,
lettersHistogram,
lettersHistogramNames,
};
}, [
state.grid.entries,
state.grid.height,
state.grid.width,
state.grid.cells,
]);
const keyboardHandler = useCallback(
(key: string) => {
const mkey = fromKeyString(key);
if (isSome(mkey)) {
const kpa: KeypressAction = { type: 'KEYPRESS', key: mkey.value };
dispatch(kpa);
}
},
[dispatch]
);
const topBarChildren = useMemo(() => {
let autofillIcon = <SpinnerDisabled />;
let autofillReverseIcon = <SpinnerWorking />;
let autofillReverseText = 'Enable Autofill';
let autofillText = 'Autofill disabled';
if (props.autofillEnabled) {
autofillReverseIcon = <SpinnerDisabled />;
autofillReverseText = 'Disable Autofill';
if (props.autofillInProgress) {
autofillIcon = <SpinnerWorking />;
autofillText = 'Autofill in progress';
} else if (props.autofilledGrid.length) {
autofillIcon = <SpinnerFinished />;
autofillText = 'Autofill complete';
} else {
autofillIcon = <SpinnerFailed />;
autofillText = "Couldn't autofill this grid";
}
}
return (
<>
<TopBarDropDown
onClose={focusGrid}
icon={autofillIcon}
text="Autofill"
hoverText={autofillText}
>
{() => (
<>
<TopBarDropDownLink
icon={autofillReverseIcon}
text={autofillReverseText}
onClick={toggleAutofillEnabled}
/>
<TopBarDropDownLink
icon={<FaSignInAlt />}
text="Jump to Most Constrained"
shortcutHint={<ExclamationKey />}
onClick={() => {
const entry = getMostConstrainedEntry();
if (entry !== null) {
const ca: ClickedEntryAction = {
type: 'CLICKEDENTRY',
entryIndex: entry,
};
dispatch(ca);
}
}}
/>
<TopBarDropDownLink
icon={<MdRefresh />}
text="Rerun Autofiller"
shortcutHint={<EnterKey />}
onClick={() => {
reRunAutofill();
}}
/>
</>
)}
</TopBarDropDown>
<TopBarLink
icon={<FaListOl />}
text="Clues"
onClick={() => setClueMode(true)}
/>
<TopBarLink
icon={<FaRegNewspaper />}
text="Publish"
onClick={() => {
const a: PublishAction = {
type: 'PUBLISH',
publishTimestamp: TimestampClass.now(),
};
dispatch(a);
}}
/>
<TopBarDropDown onClose={focusGrid} icon={<FaEllipsisH />} text="More">
{(closeDropdown) => (
<>
<NestedDropDown
onClose={focusGrid}
closeParent={closeDropdown}
icon={<FaRegPlusSquare />}
text="New Puzzle"
>
{() => <NewPuzzleForm dispatch={dispatch} />}
</NestedDropDown>
<NestedDropDown
onClose={focusGrid}
closeParent={closeDropdown}
icon={<FaFileImport />}
text="Import .puz File"
>
{() => <ImportPuzForm dispatch={dispatch} />}
</NestedDropDown>
<TopBarDropDownLink
icon={<FaRegFile />}
text="Export .puz File"
onClick={() => {
const a: SetShowDownloadLink = {
type: 'SETSHOWDOWNLOAD',
value: true,
};
dispatch(a);
}}
/>
<NestedDropDown
onClose={focusGrid}
closeParent={closeDropdown}
icon={<IoMdStats />}
text="Stats"
>
{() => (
<>
<h2>Grid</h2>
<div>
{state.gridIsComplete ? (
<FaRegCheckCircle />
) : (
<FaRegCircle />
)}{' '}
All cells should be filled
</div>
<div>
{state.hasNoShortWords ? (
<FaRegCheckCircle />
) : (
<FaRegCircle />
)}{' '}
All words should be at least three letters
</div>
<div>
{state.repeats.size > 0 ? (
<>
<FaRegCircle /> (
{Array.from(state.repeats).sort().join(', ')})
</>
) : (
<FaRegCheckCircle />
)}{' '}
No words should be repeated
</div>
<h2 css={{ marginTop: '1.5em' }}>Fill</h2>
<div>Number of words: {stats.numEntries}</div>
<div>
Mean word length: {stats.averageLength.toPrecision(3)}
</div>
<div>
Number of blocks: {stats.numBlocks} (
{((100 * stats.numBlocks) / stats.numTotal).toFixed(1)}%)
</div>
<div
css={{
marginTop: '1em',
textDecoration: 'underline',
textAlign: 'center',
}}
>
Word Lengths
</div>
<Histogram
data={stats.lengthHistogram}
names={stats.lengthHistogramNames}
/>
<div
css={{
marginTop: '1em',
textDecoration: 'underline',
textAlign: 'center',
}}
>
Letter Counts
</div>
<Histogram
data={stats.lettersHistogram}
names={stats.lettersHistogramNames}
/>
</>
)}
</NestedDropDown>
<NestedDropDown
onClose={focusGrid}
closeParent={closeDropdown}
icon={<SymmetryIcon type={state.symmetry} />}
text="Change Symmetry"
>
{() => (
<>
<TopBarDropDownLink
icon={<SymmetryRotational />}
text="Use Rotational Symmetry"
onClick={() => {
const a: SymmetryAction = {
type: 'CHANGESYMMETRY',
symmetry: Symmetry.Rotational,
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<SymmetryHorizontal />}
text="Use Horizontal Symmetry"
onClick={() => {
const a: SymmetryAction = {
type: 'CHANGESYMMETRY',
symmetry: Symmetry.Horizontal,
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<SymmetryVertical />}
text="Use Vertical Symmetry"
onClick={() => {
const a: SymmetryAction = {
type: 'CHANGESYMMETRY',
symmetry: Symmetry.Vertical,
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<SymmetryNone />}
text="Use No Symmetry"
onClick={() => {
const a: SymmetryAction = {
type: 'CHANGESYMMETRY',
symmetry: Symmetry.None,
};
dispatch(a);
}}
/>
{state.grid.width === state.grid.height ? (
<>
<TopBarDropDownLink
icon={<SymmetryIcon type={Symmetry.DiagonalNESW} />}
text="Use NE/SW Diagonal Symmetry"
onClick={() => {
const a: SymmetryAction = {
type: 'CHANGESYMMETRY',
symmetry: Symmetry.DiagonalNESW,
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<SymmetryIcon type={Symmetry.DiagonalNWSE} />}
text="Use NW/SE Diagonal Symmetry"
onClick={() => {
const a: SymmetryAction = {
type: 'CHANGESYMMETRY',
symmetry: Symmetry.DiagonalNWSE,
};
dispatch(a);
}}
/>
</>
) : (
''
)}
</>
)}
</NestedDropDown>
<TopBarDropDownLink
icon={<FaSquare />}
text="Toggle Block"
shortcutHint={<PeriodKey />}
onClick={() => {
const a: KeypressAction = {
type: 'KEYPRESS',
key: { k: KeyK.Dot },
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<CgSidebarRight />}
text="Toggle Bar"
shortcutHint={<CommaKey />}
onClick={() => {
const a: KeypressAction = {
type: 'KEYPRESS',
key: { k: KeyK.Comma },
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<FaEyeSlash />}
text="Toggle Cell Visibility"
shortcutHint={<KeyIcon text="#" />}
onClick={() => {
const a: ToggleHiddenAction = {
type: 'TOGGLEHIDDEN',
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={<Rebus />}
text="Enter Rebus"
shortcutHint={<EscapeKey />}
onClick={() => {
const a: KeypressAction = {
type: 'KEYPRESS',
key: { k: KeyK.Escape },
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={
state.grid.highlight === 'circle' ? (
<FaRegCircle />
) : (
<FaFillDrip />
)
}
text="Toggle Square Highlight"
shortcutHint={<BacktickKey />}
onClick={() => {
const a: KeypressAction = {
type: 'KEYPRESS',
key: { k: KeyK.Backtick },
};
dispatch(a);
}}
/>
<TopBarDropDownLink
icon={
state.grid.highlight === 'circle' ? (
<FaFillDrip />
) : (
<FaRegCircle />
)
}
text={
state.grid.highlight === 'circle'
? 'Use Shade for Highlights'
: 'Use Circle for Highlights'
}
onClick={() => {
const a: SetHighlightAction = {
type: 'SETHIGHLIGHT',
highlight:
state.grid.highlight === 'circle' ? 'shade' : 'circle',
};
dispatch(a);
}}
/>
{muted ? (
<TopBarDropDownLink
icon={<FaVolumeUp />}
text="Unmute"
onClick={() => setMuted(false)}
/>
) : (
<TopBarDropDownLink
icon={<FaVolumeMute />}
text="Mute"
onClick={() => setMuted(true)}
/>
)}
<TopBarDropDownLink
icon={<FaKeyboard />}
text="Toggle Keyboard"
onClick={() => setToggleKeyboard(!toggleKeyboard)}
/>
{props.isAdmin ? (
<>
<TopBarDropDownLinkA
href="/admin"
icon={<FaUserLock />}
text="Admin"
/>
</>
) : (
''
)}
<TopBarDropDownLinkA
href="/dashboard"
icon={<FaHammer />}
text="Constructor Dashboard"
/>
<TopBarDropDownLinkA
href="/account"
icon={<FaUser />}
text="Account"
/>
</>
)}
</TopBarDropDown>
</>
);
}, [
focusGrid,
getMostConstrainedEntry,
props.autofillEnabled,
props.autofillInProgress,
props.autofilledGrid.length,
stats,
props.isAdmin,
setClueMode,
setMuted,
state.grid.highlight,
state.grid.width,
state.grid.height,
state.gridIsComplete,
state.hasNoShortWords,
state.repeats,
state.symmetry,
toggleAutofillEnabled,
reRunAutofill,
dispatch,
muted,
toggleKeyboard,
setToggleKeyboard,
]);
return (
<>
<Global styles={FULLSCREEN_CSS} />
<div
css={{
display: 'flex',
flexDirection: 'column',
height: '100%',
}}
>
<div css={{ flex: 'none' }}>
<TopBar>{topBarChildren}</TopBar>
</div>
{state.showDownloadLink ? (
<PuzDownloadOverlay
state={state}
cancel={() => {
const a: SetShowDownloadLink = {
type: 'SETSHOWDOWNLOAD',
value: false,
};
dispatch(a);
}}
/>
) : (
''
)}
{state.toPublish ? (
<PublishOverlay
id={state.id}
toPublish={state.toPublish}
warnings={state.publishWarnings}
user={props.user}
cancelPublish={() => dispatch({ type: 'CANCELPUBLISH' })}
/>
) : (
''
)}
{state.publishErrors.length ? (
<Overlay
closeCallback={() => dispatch({ type: 'CLEARPUBLISHERRORS' })}
>
<>
<div>
Please fix the following errors and try publishing again:
</div>
<ul>
{state.publishErrors.map((s, i) => (
<li key={i}>{s}</li>
))}
</ul>
{state.publishWarnings.length ? (
<>
<div>Warnings:</div>
<ul>
{state.publishWarnings.map((s, i) => (
<li key={i}>{s}</li>
))}
</ul>
</>
) : (
''
)}
</>
</Overlay>
) : (
''
)}
<div
css={{ flex: '1 1 auto', overflow: 'scroll', position: 'relative' }}
>
<SquareAndCols
leftIsActive={state.active.dir === Direction.Across}
ref={gridRef}
aspectRatio={state.grid.width / state.grid.height}
square={(width: number, _height: number) => {
return (
<GridView
isEnteringRebus={state.isEnteringRebus}
rebusValue={state.rebusValue}
squareWidth={width}
grid={state.grid}
active={state.active}
dispatch={dispatch}
allowBlockEditing={true}
autofill={props.autofillEnabled ? props.autofilledGrid : []}
/>
);
}}
left={fillLists.left}
right={fillLists.right}
dispatch={dispatch}
/>
</div>
<div css={{ flex: 'none', width: '100%' }}>
<Keyboard
toggleKeyboard={toggleKeyboard}
keyboardHandler={keyboardHandler}
muted={muted}
showExtraKeyLayout={state.showExtraKeyLayout}
includeBlockKey={true}
/>
</div>
</div>
</>
);
}