react-bootstrap#Overlay TypeScript Examples

The following examples show how to use react-bootstrap#Overlay. 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: AddYearPopup.tsx    From peterportal-client with MIT License 5 votes vote down vote up
AddYearPopup: FC<AddYearPopupProps> = ({ placeholderYear }) => {
  const dispatch = useAppDispatch();
  const [year, setYear] = useState(placeholderYear);
  const [show, setShow] = useState(false);
  const target = useRef(null);

  useEffect(() => { setYear(placeholderYear) }, [placeholderYear]);

  const handleClick = (event: React.MouseEvent) => {
    setShow(!show);
  };

  return (
    <div>
      <Button variant="light" ref={target} className="add-year-btn" onClick={handleClick}>
        <PlusCircleFill className="add-year-icon" />
        <div className="add-year-text">Add year</div>
      </Button>
      <Overlay show={show} target={target} placement="top">
        <Popover id=''>
          <Popover.Content>
            <Form>
              <Form.Group>
                <Form.Label className="add-year-form-label">
                  Start Year
                </Form.Label>
                <Form.Control
                  type="number"
                  name="year"
                  value={year}
                  onChange={(e) => {
                    setYear(parseInt(e.target.value));
                  }}
                  onKeyDown={(e: React.KeyboardEvent) => {
                    // prevent submitting form (reloads the page)
                    if (e.key === 'Enter') {
                      e.preventDefault();
                    }
                  }}
                  min={1000}
                  max={9999}
                  placeholder={placeholderYear.toString()}
                ></Form.Control>
              </Form.Group>
              <Button
                className="popup-btn"
                onClick={() => {
                  setShow(!show);
                  dispatch(addYear(
                    {
                      yearData: {
                        startYear: year,
                        quarters: ['fall', 'winter', 'spring'].map(quarter => { return { name: quarter, courses: [] } })
                      }
                    }
                  ));
                  setYear(placeholderYear);
                }}
              >
                Add Year
              </Button>
            </Form>
          </Popover.Content>
        </Popover>
      </Overlay>
    </div >
  );
}
Example #2
Source File: Header.tsx    From peterportal-client with MIT License 5 votes vote down vote up
Header: FC<HeaderProps> = ({ courseCount, unitCount, saveRoadmap }) => {
  const dispatch = useAppDispatch();
  const [target, setTarget] = useState<any>(null!);
  const [showMenu, setShowMenu] = useState(false);

  const buttons = <>
    <Button variant={isMobile ? "primary" : 'light'} className={isMobile ? 'my-1' : "header-btn"} onClick={() => dispatch(setShowTransfer(true))}>
      Transfer Credits
      <ArrowLeftRight className="header-icon" />
    </Button>
    <Button variant={isMobile ? "primary" : 'light'} className={isMobile ? 'my-1' : "header-btn"} onClick={saveRoadmap}>
      Save
      <Save className="header-icon" />
    </Button>
    <Button variant={isMobile ? "primary" : 'light'} className={isMobile ? 'my-1' : "header-btn"} onClick={() => dispatch(clearPlanner())}>
      Clear
      <Trash className="header-icon" />
    </Button>
  </>

  const onMenuClick = (event: React.MouseEvent) => {
    setShowMenu(!showMenu);
    setTarget(event.target);
  };

  return (
    <div className="header">
      <Transfer />
      <div>
        <div id="title">
          Peter's Roadmap
        </div>
        <span id="planner-stats">
          Total: <span id="course-count">{courseCount}</span>{" "}
          {courseCount === 1 ? "course" : "courses"},{" "}
          <span id="unit-count">{unitCount}</span>{" "}
          {unitCount === 1 ? "unit" : "units"}
        </span>
      </div>
      <div>
        {
          isMobile && <>
            <Button variant="light" className="header-btn add-course" onClick={() => { dispatch(setShowSearch(true)) }}>
              <Plus className="header-icon mr-1" />
              Add Course
            </Button>
            <List className='mx-3' onClick={onMenuClick} />
            <Overlay show={showMenu} target={target} placement="left">
              <Popover id='roadmap-header-buttons'>
                <Popover.Content>
                  <div className='d-flex flex-column'>
                    {buttons}
                  </div>
                </Popover.Content>
              </Popover>
            </Overlay>
          </>
        }
        {
          isBrowser && <ButtonGroup>
            {buttons}
          </ButtonGroup>
        }
      </div>
    </div >
  )
}
Example #3
Source File: Quarter.tsx    From peterportal-client with MIT License 4 votes vote down vote up
Quarter: FC<QuarterProps> = ({ year, yearIndex, quarterIndex, data }) => {
  const dispatch = useAppDispatch();
  let quarterTitle = data.name.charAt(0).toUpperCase() + data.name.slice(1);
  const invalidCourses = useAppSelector(state => state.roadmap.invalidCourses);

  const [showQuarterMenu, setShowQuarterMenu] = useState(false);
  const [target, setTarget] = useState<any>(null!);

  const handleQuarterMenuClick = (event: React.MouseEvent) => {
    setShowQuarterMenu(!showQuarterMenu);
    setTarget(event.target);
  }

  const calculateQuarterStats = () => {
    let unitCount = 0;
    let courseCount = 0;
    data.courses.forEach(course => {
      unitCount += course.units[0];
      courseCount += 1;
    })
    return [unitCount, courseCount];
  };

  let unitCount = calculateQuarterStats()[0];

  const renderCourses = () => {
    return data.courses.map((course, index) => {
      return <Draggable key={`quarter-course-${index}`} draggableId={`${yearIndex}-${quarterIndex}-${course.id}-${index}`} index={index}>
        {(provided, snapshot) => {
          let requiredCourses: string[] = null!;
          // if this is an invalid course, set the required courses
          invalidCourses.forEach(ic => {
            let loc = ic.location;
            if (loc.courseIndex == index && loc.quarterIndex == quarterIndex && loc.yearIndex == yearIndex) {
              requiredCourses = ic.required;
            }
          });

          const onDelete = () => {
            dispatch(deleteCourse({
              yearIndex,
              quarterIndex,
              courseIndex: index,
            }));
          };

          return (
            <div
              ref={provided.innerRef}
              {...provided.draggableProps}
              {...provided.dragHandleProps}
              style={{
                margin: '0rem 2rem 1rem 2rem',
                ...provided.draggableProps.style
              }}
            >
              <Course key={course.id} {...course}
                requiredCourses={requiredCourses}
                onDelete={onDelete} />
            </div>
          );
        }}
      </Draggable>
    })
  }

  return <div className="quarter">
    <span className="quarter-header">
      <h2 className="quarter-title">
        {quarterTitle} {year}
      </h2>
      <ThreeDots onClick={handleQuarterMenuClick} className="edit-btn" />
      <Overlay show={showQuarterMenu} target={target} placement="bottom">
        <Popover id={`quarter-menu-${yearIndex}-${quarterIndex}`}>
          <Popover.Content>
            <div>
              <Button variant="light" className="quarter-menu-btn red-menu-btn" onClick={() => dispatch(clearQuarter({ yearIndex: yearIndex, quarterIndex: quarterIndex }))}>
                Clear
              </Button>
              <Button variant="light" className="quarter-menu-btn red-menu-btn" onClick={() => {
                dispatch(deleteQuarter({ yearIndex: yearIndex, quarterIndex: quarterIndex }));
                setShowQuarterMenu(false)
              }}>
                Delete
              </Button>
            </div>
          </Popover.Content>
        </Popover>
      </Overlay>
    </span>
    <div className="quarter-units">
      {unitCount} {unitCount === 1 ? "unit" : "units"}
    </div>
    <Droppable droppableId={yearIndex + "-" + quarterIndex} type="COURSE">
      {(provided) => {
        return (
          <div
            ref={provided.innerRef}
            {...provided.droppableProps}
            style={{ paddingBottom: '1rem' }}>
            {renderCourses()}
            {provided.placeholder}
          </div>
        );
      }}
    </Droppable>
  </div>
}
Example #4
Source File: Year.tsx    From peterportal-client with MIT License 4 votes vote down vote up
Year: FC<YearProps> = ({ yearIndex, data }) => {
  const dispatch = useAppDispatch();
  const [showContent, setShowContent] = useState(true);
  const [show, setShow] = useState(false);
  const [showAddQuarter, setShowAddQuarter] = useState(false);
  const [showEditYear, setShowEditYear] = useState(false);
  const [target, setTarget] = useState<any>(null!);
  const [addQuarterTarget, setAddQuarterTarget] = useState<any>(null!);
  const [editYearTarget, setEditYearTarget] = useState<any>(null!);
  const [placeholderYear, setPlaceholderYear] = useState(data.startYear);

  const handleEditClick = (event: React.MouseEvent) => {
    if (showAddQuarter) {
      /* hide both overlays */
      setShowAddQuarter(!showAddQuarter);
      setShow(!show);
    } else if (showEditYear) {
      setShowEditYear(!showEditYear);
      setShow(!show);
    } else {
      setShow(!show);
      setTarget(event.target);
    }
  };

  const handleShowAddQuarterClick = (event: React.MouseEvent) => {
    setShowEditYear(false); // hide any other currently displayed menu bar options
    setShowAddQuarter(!showAddQuarter);
    setAddQuarterTarget(event.target);
  }

  const handleAddQuarterClick = (year: number, quarter: string) => {
    dispatch(addQuarter({ startYear: year, quarterData: { name: quarter, courses: [] } }));
  }

  const handleEditYearClick = (event: React.MouseEvent) => {
    setShowAddQuarter(false);           // hide any other currently displayed menu bar options
    setPlaceholderYear(data.startYear); // set default year to current year
    setShowEditYear(!showEditYear);
    setEditYearTarget(event.target);
  }

  const calculateYearStats = () => {
    let unitCount = 0;
    let courseCount = 0;
    data.quarters.forEach(quarter => {
      quarter.courses.forEach(course => {
        unitCount += course.units[0];
        courseCount += 1;
      })
    })
    return { unitCount, courseCount };
  };

  let { unitCount, courseCount } = calculateYearStats();

  return (
    <div className="year">
      <div className="yearTitleBar">
        <Button
          variant="link"
          className="year-accordion"
          onClick={() => {
            setShowContent(!showContent);
          }}
        >
          <span className="year-accordion-title">
            <span id="year-title">
              {showContent ? (
                <CaretDownFill className="caret-icon" />
              ) : (
                <CaretRightFill className="caret-icon" />
              )}
              <span id="year-number">Year {yearIndex + 1} </span>
              <span id="year-range">
                ({data.startYear} - {data.startYear + 1})
              </span>
            </span>
            <span id="year-stats">
              <span id="course-count">{courseCount}</span>{" "}
              {courseCount === 1 ? "course" : "courses"},{" "}
              <span id="unit-count">{unitCount}</span>{" "}
              {unitCount === 1 ? "unit" : "units"}
            </span>
          </span>
        </Button>
        <ThreeDots onClick={handleEditClick} className="edit-btn" />
        <Overlay show={show} target={target} placement="bottom">
          <Popover id={`year-menu-${yearIndex}`}>
            <Popover.Content className="year-settings-popup">
              <div>
                <Button disabled={!(data.quarters && data.quarters.length < 6)} onClick={handleShowAddQuarterClick} variant="light" className="year-settings-btn">
                  Add Quarter
                </Button>
                <Button onClick={handleEditYearClick} variant="light" className="year-settings-btn">
                  Edit Year
                </Button>
                <Button
                  variant="light"
                  className="year-settings-btn"
                  id="clear-btn"
                  onClick={() => {
                    dispatch(clearYear({
                      yearIndex: yearIndex
                    }));
                  }}
                >
                  Clear
                </Button>
                <Button
                  variant="light"
                  className="year-settings-btn"
                  id="remove-btn"
                  onClick={() => {
                    dispatch(deleteYear({
                      yearIndex: yearIndex
                    }));
                  }}
                >
                  Remove
                </Button>
              </div>
            </Popover.Content>
          </Popover>
        </Overlay>
        <Overlay show={showAddQuarter && data.quarters && data.quarters.length < 6} target={addQuarterTarget} placement="left">
          <Popover id={`add-quarter-menu-${yearIndex}`}>
            <Popover.Content>
              <div>
                {!data.quarters.map(quarter => quarter.name).includes("fall") && <Button onClick={() => handleAddQuarterClick(data.startYear, "fall")} variant="light" className="year-settings-btn">Fall</Button>}
                {!data.quarters.map(quarter => quarter.name).includes("winter") && <Button onClick={() => handleAddQuarterClick(data.startYear, "winter")} variant="light" className="year-settings-btn">Winter</Button>}
                {!data.quarters.map(quarter => quarter.name).includes("spring") && <Button onClick={() => handleAddQuarterClick(data.startYear, "spring")} variant="light" className="year-settings-btn">Spring</Button>}
                {!data.quarters.map(quarter => quarter.name).includes("summer I") && <Button onClick={() => handleAddQuarterClick(data.startYear, "summer I")} variant="light" className="year-settings-btn">Summer I</Button>}
                {!data.quarters.map(quarter => quarter.name).includes("summer II") && <Button onClick={() => handleAddQuarterClick(data.startYear, "summer II")} variant="light" className="year-settings-btn">Summer II</Button>}
                {!data.quarters.map(quarter => quarter.name).includes("summer 10 Week") && <Button onClick={() => handleAddQuarterClick(data.startYear, "summer 10 Week")} variant="light" className="year-settings-btn">Summer 10 Week</Button>}
              </div>
            </Popover.Content>
          </Popover>
        </Overlay>
        <Overlay show={showEditYear} target={editYearTarget} placement="left">
          <Popover id={`edit-year-menu-${yearIndex}`}>
            <Popover.Content>
              <Form>
                <Form.Group>
                  <Form.Label className="edit-year-form-label">
                    Start Year
                  </Form.Label>
                  <Form.Control
                    type="number"
                    name="year"
                    value={placeholderYear}
                    onChange={(e) => {
                      setPlaceholderYear(parseInt(e.target.value));
                    }}
                    onKeyDown={(e: React.KeyboardEvent) => {
                      // prevent submitting form (reloads the page)
                      if (e.key === 'Enter') {
                        e.preventDefault();
                      }
                    }}
                    min={1000}
                    max={9999}
                    placeholder={placeholderYear.toString()}
                  ></Form.Control>
                </Form.Group>
                <Button
                  className="edit-year-popup-btn"
                  onClick={() => {
                    setShowEditYear(!showEditYear);
                    setShow(!show);
                    if (placeholderYear != data.startYear) {
                      dispatch(editYear({ startYear: placeholderYear, index: yearIndex }));
                    }
                  }}
                >
                  Confirm
                </Button>
              </Form>
            </Popover.Content>
          </Popover>
        </Overlay>
      </div>
      {showContent && (
        <div className="year-accordion-content">
          {
            data.quarters.map((quarter, quarterIndex) => {
              return <Quarter
                key={`year-quarter-${quarterIndex}`}
                year={data.startYear + (quarterIndex == 0 ? 0 : 1)}
                yearIndex={yearIndex}
                quarterIndex={quarterIndex}
                data={quarter}
              />
            })
          }

          {/* render blank, non-functional quarters to ensure there are 3 per row */}
          {data.quarters.length > 3 && data.quarters.length < 6 && (
            [undefined, undefined].slice(data.quarters.length - 4).map(() => {
              return <div className="empty-quarter"></div>
            })
          )
          }
        </div>
      )}
    </div>
  );
}
Example #5
Source File: index.tsx    From react-bootstrap-country-select with MIT License 4 votes vote down vote up
CountrySelect = ({
  value,
  onChange = () => {},
  onTextChange,
  countries = [ ...COUNTRIES ],
  exclusions,
  additions,
  valueAs = 'object',
  flags = true,
  flush = true,
  disabled = false,
  placeholder = 'Type or select country...',
  noMatchesText = 'No matches',
  size,
  sort, // e.g. (c1, c2) => c1.name < c2.name ? -1 : (c1.name > c2.name ? 1 : 0),
  matchNameFromStart = true,
  matchAbbreviations = false,
  countryLabelFormatter = ({ name }) => name,
  throwInvalidValueError = false, 
  listMaxHeight,
  closeOnSelect = true,
  formControlProps = {},
  overlayProps = {},
  classPrefix = DEFAULT_CLASS_PREFIX,
  className,
}: CountrySelectProps) => {

  const inputGroupRef = useRef(null);
  const formControlRef = useRef(null);
  const hasInitRef = useRef(false);
  const [ width, setWidth ] = useState(-1);

  const [ {
    focused,
    inputText,
    list,
    activeListItemIndex,
    combinedCountries,
  }, dispatch ] = useReducer(reducer, INITIAL_STATE);

  const handleFocus = focus(dispatch);
  const handleBlur = blur(dispatch);
  const handleTextChange = textChange(dispatch);
  const handleListActiveItemChange = activeListItemChange(dispatch);
  const handleCountrySelect = countrySelect(dispatch);
  const handleClear = clear(dispatch);

  const getCountryId = (value: ICountry | string): string => (typeof value === 'string' ? value : value.id);

  const selectedCountry = value ? (combinedCountries || []).find(country => country.id === getCountryId(value)) : null;

  if (throwInvalidValueError && value && !selectedCountry)
    throw new Error(`No matching country for value: ${JSON.stringify(value)}`);

  useEffect(() => {

    if (hasInitRef.current) return;

    const combinedCountries = applyExclusionsAndAdditions(countries, exclusions, additions);

    const sorted = getInitialList(combinedCountries, sort);

    init(dispatch)(sorted);

    hasInitRef.current = true;

  }, [ countries, exclusions, additions, sort ]);

  useEffect(() => {

    setWidth(inputGroupRef.current.offsetWidth);

  }, [ inputGroupRef ]);

  const select = listItemIndex => {

    const country = list[listItemIndex];

    handleCountrySelect();
    onChange(valueAs === 'id' ? country.id : country);

  };

  const escape = () => {

    handleClear();
    onChange(null);

  };

  const inputChange = (text, ev) => {

    if (selectedCountry && flags) {

      text = removeEmojiFlag(text);

    }

    const [ updatedList, updatedActiveListItemIndex ]
      = getUpdatedList(text, list, activeListItemIndex, combinedCountries, sort, matchNameFromStart, matchAbbreviations);

    handleTextChange(text, updatedList, updatedActiveListItemIndex);

    if (onTextChange) onTextChange(text, ev);
    if (value) onChange(null);

  };

  const handleKey = ev => {

    if (ev.key === 'ArrowUp') {

      ev.preventDefault();

      const newIndex = activeListItemIndex <= 0 ? list.length - 1 : activeListItemIndex - 1;
      handleListActiveItemChange(newIndex);

    } else if (ev.key === 'ArrowDown') {

      const newIndex = activeListItemIndex >= list.length - 1 ? 0 : activeListItemIndex + 1;
      handleListActiveItemChange(newIndex);

    } else if (ev.key === 'Enter') {

      if (activeListItemIndex >= 0) select(activeListItemIndex)

    } else if (ev.key === 'Escape') {

      escape();

    }

  };
  
  const classes = classNames([
    className,
    classPrefix,
    flush && `${classPrefix}--flush`,
  ]);

  return (
    <div className={classes}>

      <InputGroup
        ref={inputGroupRef}
        className={`${classPrefix}__input-group`}
        size={size}
      >

        { (!flush && flags) && 
          <InputGroup.Prepend>

            <InputGroup.Text
              className={`${classPrefix}__input-group__flag`}
            >

              {selectedCountry ? selectedCountry.flag : ''}
            
            </InputGroup.Text>
            
          </InputGroup.Prepend>
        }

        <FormControl
          ref={formControlRef}
          className={`${classPrefix}__form-control`}
          value={selectedCountry ? `${flush && flags ? selectedCountry.flag + '   ' : ''}${selectedCountry.name}` : inputText}
          onKeyDown={handleKey}
          onChange={ev => inputChange(ev.target.value, ev)}
          onFocus={handleFocus}
          onBlur={handleBlur}
          placeholder={placeholder}
          disabled={disabled}
          spellCheck={false}
          autoComplete='new-value'
          {...formControlProps}
        />

      </InputGroup>

      <Overlay
        target={inputGroupRef.current}
        rootClose
        placement='bottom-start'
        show={focused && (!selectedCountry || !closeOnSelect)} // experimental; not documented
        onHide={() => {}}
        transition
        {...overlayProps}
      >

        {({ placement, arrowProps, show: _show, popper, ...props }) => (

          <div
            {...props}
            style={{
              width: (width > 0) ? `${width}px` : 'calc(100% - 10px)',
              ...props.style,
            }}
          >

            <OverlayContent
              classPrefix={classPrefix}
              list={list}
              activeListItemIndex={activeListItemIndex}
              countryLabelFormatter={countryLabelFormatter}
              flags={flags}
              noMatchesText={noMatchesText}
              maxHeight={listMaxHeight}
              onListItemClick={select}
            />

          </div>

        )}

      </Overlay>
    
    </div>
  );

}