preact/hooks#useState JavaScript Examples

The following examples show how to use preact/hooks#useState. 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: invalid.js    From eslint-config-preact with MIT License 7 votes vote down vote up
export function Foo () {
	const [value, setValue] = useState(0);
	const increment = useCallback(() => setValue(value + 1));

	useEffect(() => {
		console.log(value);
	}, []);

	return <button onClick={increment}>{value}</button>;
}
Example #2
Source File: app.js    From shorts-ui with MIT License 6 votes vote down vote up
App = () => {
	let [ashProperties, setAshProperties] = useState(null);
	// eslint-disable-next-line no-undef
	useEffect(() => setAshProperties(globalAshProperties), []);
	if (ashProperties?.inAftercore === "true") {
		const localBellPockets = [...bellPockets,
			['Frost-rimed desk bell', 'Cold wads, nuggets, powder', 587, '/images/adventureimages/ccs_herald.gif'],
		];
		return (
			<div id="preact_root">
				<PropertiesContext.Provider value={ashProperties}>
					<ButtonRow title="Bells" buttons={localBellPockets} />
					<ButtonRow title="Chess Pieces" buttons={chessPockets} />
					<ButtonRow title="Yeg's Stuff" buttons={yegPockets} />
					<ButtonRow title="Other Items" buttons={aftercoreItemPockets} />
				</PropertiesContext.Provider>
			</div>
		);
	} 
	const localItemPockets = ashProperties?.lastUsername?.toLowerCase() !== 'accodorian' ? itemPockets : [...itemPockets,
		['Jumbo olive', 'Oil of slipperiness', 570, '/images/itemimages/olive.gif'],
	];
	const ascensions = ashProperties?.knownAscensions ?? 0;
	const localFightPockets = [...fightPockets, ascensions % 2 == 0 ? skinflute : camelsToe];
	return (
		<div id="preact_root">
			<PropertiesContext.Provider value={ashProperties}>
				<ButtonRow title="Stats" buttons={statPockets} />
				<ButtonRow title="Fights" buttons={localFightPockets} />
				<ButtonRow title="Bell Fights" buttons={bellPockets} />
				<ButtonRow title="Buffs" buttons={buffPockets} />
				<ButtonRow title="Items" buttons={localItemPockets} />
				<ButtonRow title="Chess Pieces" buttons={chessPockets} />
			</PropertiesContext.Provider>
		</div>
	);
}
Example #3
Source File: pwaPrompt.js    From domicilioBoilerplate with GNU Affero General Public License v3.0 6 votes vote down vote up
PWAPrompt = (props) => {
	const [isVisible, setIsVisible] = useState(false);
	
	function handleClosePopup() {
		setIsVisible(false);
		if (typeof window !== 'undefined') {
		   window.localStorage.setItem('pwaPrompt', 'true')
		}
	}

	useEffect(() => {
		setIsVisible(visibilityCheks())
	}, [])

	return visibilityCheks() && (	
		<Prompt
			visible={isVisible}
			closePopup={handleClosePopup}
			{...props}
		/>
	);
}
Example #4
Source File: verify.js    From rctf with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
Verify = () => {
  const [authToken, setAuthToken] = useState(null)
  const [emailSet, setEmailSet] = useState(false)
  const [error, setError] = useState(null)

  useEffect(() => {
    document.title = `Verify | ${config.ctfName}`

    ;(async () => {
      const qs = new URLSearchParams(location.search)
      if (qs.has('token')) {
        const verifyRes = await verify({ verifyToken: qs.get('token') })
        if (verifyRes.authToken) {
          setAuthToken(verifyRes.authToken)
        } else if (verifyRes.emailSet) {
          setEmailSet(true)
        } else {
          setError(verifyRes.verifyToken)
        }
      }
    })()
  }, [])

  if (error) {
    return <Error error='401' message={error} />
  }
  if (emailSet) {
    return (
      <div class='row u-center'>
        <h3>The email change has been verified. You can now close this tab.</h3>
      </div>
    )
  }
  return <PendingToken authToken={authToken} />
}
Example #5
Source File: toast.js    From rctf with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export function ToastProvider ({ children }) {
  const [toasts, setToasts] = useState([])

  const remove = useCallback((id) => {
    setToasts(toasts => toasts.filter(t => id !== t.id))
  }, [])
  const add = useCallback((data) => {
    const id = genToastId()
    const toast = {
      ...data,
      id
    }
    setToasts(toasts => [...toasts, toast])
    return () => remove(id)
  }, [remove])

  return (
    <ToastCtx.Provider value={add}>
      {children}
      { toasts.length > 0 &&
        <ToastContainer>
          { toasts.map(({ id, type, body }) =>
            <Toast type={type} key={id} id={id} remove={remove}>
              {body}
            </Toast>
          )}
        </ToastContainer>
      }
    </ToastCtx.Provider>
  )
}
Example #6
Source File: pending-token.js    From rctf with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
PendingToken = ({ authToken }) => {
  const [user, setUser] = useState(null)
  useEffect(() => {
    (async () => {
      if (!authToken) {
        return
      }
      const user = await pendingPrivateProfile({ authToken })
      setUser(user)
    })()
  }, [authToken])
  const handleLoginClick = useCallback(() => {
    setAuthToken({ authToken })
  }, [authToken])
  if (!user) {
    return null
  }
  return (
    <Fragment>
      <div class='row u-center'>
        <h3>Login as {user.name}?</h3>
      </div>
      <div class='row u-center'>
        <button class='btn-info' onClick={handleLoginClick}>Login</button>
      </div>
    </Fragment>
  )
}
Example #7
Source File: modal.js    From rctf with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
function Modal ({
  classes, open, onClose, children
}) {
  const [isLinger, setIsLinger] = useState(open)

  useEffect(() => {
    if (open) {
      setIsLinger(true)
    } else {
      const timer = setTimeout(() => {
        setIsLinger(false)
      }, ANIMATION_DURATION)
      return () => clearTimeout(timer)
    }
  }, [open])

  useEffect(() => {
    function listener (e) {
      if (e.key === 'Escape') {
        onClose()
      }
    }
    if (open) {
      document.addEventListener('keyup', listener)
      return () => document.removeEventListener('keyup', listener)
    }
  }, [open, onClose])

  return (open || isLinger) && createPortal((
    <div class={`modal shown ${classes.animated}${open ? '' : ' leaving'}`} hidden={!(open || isLinger)}>
      <div class='modal-overlay' onClick={onClose} aria-label='Close' />
      <div class={`modal-content ${classes.modal}`} role='document'>
        {children}
      </div>
    </div>
  ), document.body)
}
Example #8
Source File: logout-button.js    From rctf with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
function LogoutButton ({ ...props }) {
  const [isDialogVisible, setIsDialogVisible] = useState(false)
  const onClick = useCallback(e => {
    e.preventDefault()
    setIsDialogVisible(true)
  }, [])
  const onClose = useCallback(() => setIsDialogVisible(false), [])

  return (
    <Fragment>
      <a {...props} href='#' native onClick={onClick}>
        Logout
      </a>
      <LogoutDialog open={isDialogVisible} onClose={onClose} />
    </Fragment>
  )
}
Example #9
Source File: valid.js    From eslint-config-preact with MIT License 6 votes vote down vote up
export function Foo () {
	const [value, setValue] = useState(0);
	const increment = useCallback(() => setValue(v => v + 1), [setValue]);

	useEffect(() => {
		console.log(value);
	}, [value]);

	return <button onClick={increment}>{value}</button>;
}
Example #10
Source File: A2H.jsx    From todo-pwa with MIT License 6 votes vote down vote up
A2H = () => {
  const [prompt, setPrompt] = useState(false);

  useEffect(() => {
    // this will catch the beforeinstallprompt and prevents the native prompt from appearing
    window.addEventListener('beforeinstallprompt', e => {
      e.preventDefault();
      setPrompt(e);
    });
  }, []);

  if (!prompt) {
    return '';
  }

  return (
    <button
      className="text-white bg-indigo-800 hover:bg-indigo-700 rounded-full shadow a2h"
      onClick={() => prompt.prompt() /* fire the prompt on button click */}
    >
      <svg viewBox="0 0 24 24">
        <path
          fill="currentColor"
          d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z"
        />
      </svg>
    </button>
  );
}
Example #11
Source File: App.js    From vegemite with MIT License 6 votes vote down vote up
// ---

export default function () {
	const [state, setState] = useState(todomvc.state);
	useEffect(() => todomvc.listen(setState));

	const actives = state.todos.filter(FILTER.active).length;
	const visibles = state.todos.filter(FILTER[state.filter]);

	return (
		<div class="todoapp">
			<header class="header">
				<h1>todos</h1>
				<input
					class="new-todo"
					placeholder="What needs to be done?"
					onKeyDown={onkeydown} autoFocus={true}
				/>
			</header>

			{
				state.todos.length ? [
					<section class="main">
						<input
							type="checkbox"
							class="toggle-all"
							onchange={ontoggleall}
							checked={!actives}
						/>
						<ul class="todo-list">
							{ visibles.map(x => <Item key={x.id} {...x} />) }
						</ul>
					</section>,
					<Footer {...state} count={actives} />
				] : null
			}
		</div>
	);
}
Example #12
Source File: index.js    From ReactCookbook-source with MIT License 6 votes vote down vote up
Profile = ({ user }) => {
	const [time, setTime] = useState(Date.now());
	const [count, setCount] = useState(10);

	useEffect(() => {
		let timer = setInterval(() => setTime(Date.now()), 1000);
		return () => clearInterval(timer);
	}, []);

	return (
		<div class={style.profile}>
			<h1>Profile: {user}</h1>
			<p>This is the user profile for a user named { user }.</p>

			<div>Current time: {new Date(time).toLocaleString()}</div>

			<p>
				<button onClick={() => setCount((count) => count + 1)}>Click Me</button>
				{' '}
				Clicked {count} times.
			</p>
		</div>
	);
}
Example #13
Source File: Count.jsx    From uvu with MIT License 6 votes vote down vote up
export default function Counter(props) {
	const { count=5 } = props;
	const [value, setValue] = useState(count);

	return (
		<>
			<button id="decr" onClick={() => setValue(value - 1)}>--</button>
			<span>{value}</span>
			<button id="incr" onClick={() => setValue(value + 1)}>++</button>
		</>
	);
}
Example #14
Source File: useHashLocation.js    From v8-deopt-viewer with MIT License 6 votes vote down vote up
/**
 * @returns {[string, (to: string) => string]}
 */
export function useHashLocation() {
	const [loc, setLoc] = useState(currentLocation());

	useEffect(() => {
		// this function is called whenever the hash changes
		const handler = () => setLoc(currentLocation());

		// subscribe to hash changes
		window.addEventListener("hashchange", handler);
		return () => window.removeEventListener("hashchange", handler);
	}, []);

	// remember to wrap your function with `useCallback` hook
	// a tiny but important optimization
	const navigate = useCallback((to) => (window.location.hash = to), []);

	return [loc, navigate];
}
Example #15
Source File: FilterInput.js    From duolingo-solution-viewer with MIT License 6 votes vote down vote up
SuggestionsDropdown = ({ context, classNames, children }) => {
  const [ isClosed, setIsClosed ] = useState(false);

  // Reopens the dropdown after a scroll / resize event when the suggestions have changed.
  useEffect(() => setIsClosed(false), [ children, setIsClosed ]);

  if (isClosed) {
    return null;
  }

  return (
    <div className={classNames.suggestions}>
      <Dropdown
        context={context}
        options={children}
        renderOption={identity}
        onClose={() => setIsClosed(true)}
      />
    </div>
  );
}
Example #16
Source File: MapExplorer.js    From v8-deopt-viewer with MIT License 5 votes vote down vote up
/**
 * @typedef MapTimelineItemProps
 * @property {any} key To make TS happy, sigh
 * @property {MapData} mapData
 * @property {MapEntry} map
 * @property {boolean} [selected]
 * @property {import("../appState").FilePosition} selectedPosition
 * @property {string} currentFile
 * @param {MapTimelineItemProps} props
 */
function MapTimelineItem({
	mapData,
	map,
	selected = false,
	selectedPosition,
	currentFile,
}) {
	const detailsId = `${map.id}-details`;
	const selectedClass = selected ? selected_class : "";
	const map_timeline_item = "";
	const map_icon = "";

	const [open, setOpen] = useState(selected);
	const { setSelectedPosition } = useAppDispatch();

	const parentEdge = map.edge ? mapData.edges[map.edge] : null;

	const isInCurrentFile = map.filePosition?.file === currentFile;
	const isSelectedPosition = isSameLocation(map.filePosition, selectedPosition);

	return (
		<div class={`${timeline_item} ${map_timeline_item} ${selectedClass}`}>
			<div class={timeline_left}>
				<button
					class={`${timeline_icon} ${selected ? icon_lg : ""} ${map_icon}`}
					aria-controls={detailsId}
					style={{
						padding: 0,
						border: 0,
						cursor: "pointer",
						background: selected ? "#5755d9" : "inherit",
					}}
					onClick={() => setOpen((opened) => !opened)}
				>
					{selected ? <i class={`${icon} ${getEdgeIcon(parentEdge)}`}></i> : ""}
				</button>
			</div>
			<div class={timeline_content}>
				<details id={detailsId} class={map_details} open={open}>
					<summary
						class={`${selectedClass} ${map_title}`}
						onClick={(ev) => {
							ev.preventDefault();
							setOpen((opened) => !opened);
						}}
					>
						{parentEdge ? edgeToString(parentEdge) : map.address}
					</summary>
					<div>
						<button
							class={`${btn} ${btn_link} ${goto_loc_btn}`}
							disabled={!isInCurrentFile || isSelectedPosition}
							title={
								!isInCurrentFile
									? "Location is not in current file"
									: isSelectedPosition
									? "Location is currently highlighted"
									: null
							}
							onClick={() => setSelectedPosition(map.filePosition)}
						>
							Show creation location
						</button>
						{formatDescription(map)}
					</div>
				</details>
			</div>
		</div>
	);
}
Example #17
Source File: recover.js    From rctf with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
Recover = ({ classes }) => {
  const [disabled, setDisabled] = useState(false)
  const [errors, setErrors] = useState({})
  const [verifySent, setVerifySent] = useState(false)
  const [email, setEmail] = useState('')
  const requestRecaptchaCode = useRecaptcha('recover')

  const handleSubmit = useCallback(async (evt) => {
    evt.preventDefault()
    const recaptchaCode = await requestRecaptchaCode?.()
    setDisabled(true)
    const { errors, verifySent } = await recover({
      email,
      recaptchaCode
    })
    setErrors(errors)
    setVerifySent(verifySent)
    setDisabled(false)
  }, [setDisabled, email, setErrors, setVerifySent, requestRecaptchaCode])

  const handleEmailChange = useCallback(evt => setEmail(evt.target.value), [setEmail])

  if (verifySent) {
    return (
      <div class='row u-center'>
        <h3>Recovery email sent</h3>
      </div>
    )
  }

  return (
    <div class={`row u-center ${classes.root}`}>
      <h4 class={classes.title}>Recover your {config.ctfName} account</h4>
      <Form class={`${classes.form} col-6`} onSubmit={handleSubmit} disabled={disabled} errors={errors} buttonText='Recover'>
        <input
          class={classes.input}
          autofocus
          required
          autocomplete='email'
          autocorrect='off'
          icon={<EnvelopeOpen />}
          name='email'
          placeholder='Email'
          type='email'
          value={email}
          onChange={handleEmailChange}
        />
      </Form>
      {requestRecaptchaCode && (
        <div class={classes.recaptchaLegalNotice}>
          <RecaptchaLegalNotice />
        </div>
      )}
    </div>
  )
}
Example #18
Source File: profile.js    From rctf with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
TeamCodeCard = withStyles({
  btn: {
    marginRight: '10px'
  }
}, ({ teamToken, classes }) => {
  const { toast } = useToast()

  const tokenUrl = `${location.origin}/login?token=${encodeURIComponent(teamToken)}`

  const [reveal, setReveal] = useState(false)
  const toggleReveal = useCallback(
    () => setReveal(!reveal),
    [reveal]
  )

  const onCopyClick = useCallback(() => {
    if (navigator.clipboard) {
      try {
        navigator.clipboard.writeText(tokenUrl).then(() => {
          toast({ body: 'Copied team invite URL to clipboard' })
        })
      } catch {}
    }
  }, [toast, tokenUrl])

  return (
    <div class='card'>
      <div class='content'>
        <p>Team Invite</p>
        <p class='font-thin'>Send this team invite URL to your teammates so they can login.</p>

        <button onClick={onCopyClick} class={`${classes.btn} btn-info u-center`} name='btn' value='submit' type='submit'>Copy</button>

        <button onClick={toggleReveal} class='btn-info u-center' name='btn' value='submit' type='submit'>{reveal ? 'Hide' : 'Reveal'}</button>

        {
          reveal &&
            <TokenPreview token={tokenUrl} />
        }
      </div>
    </div>
  )
})
Example #19
Source File: challs.js    From rctf with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
Challenges = ({ classes }) => {
  const [problems, setProblems] = useState([])

  // newId is the id of the new problem. this allows us to reuse code for problem creation
  // eslint-disable-next-line react-hooks/exhaustive-deps
  const newId = useMemo(() => uuid(), [problems])

  const completeProblems = problems.concat({
    ...SAMPLE_PROBLEM,
    id: newId
  })

  useEffect(() => {
    document.title = `Admin Challenges | ${config.ctfName}`
  }, [])

  useEffect(() => {
    const action = async () => {
      setProblems(await getChallenges())
    }
    action()
  }, [])

  const updateProblem = useCallback(({ problem }) => {
    let nextProblems = completeProblems

    // If we aren't creating new problem, remove sample problem first
    if (problem.id !== newId) {
      nextProblems = nextProblems.filter(p => p.id !== newId)
    }
    setProblems(nextProblems.map(p => {
      // Perform partial update by merging properties
      if (p.id === problem.id) {
        return {
          ...p,
          ...problem
        }
      }
      return p
    }))
  }, [newId, completeProblems])

  return (
    <div class={`row ${classes.row}`}>
      <div class='col-9'>
        {
          completeProblems.map(problem => {
            return (
              <Problem update={updateProblem} key={problem.id} problem={problem} />
            )
          })
        }
      </div>
    </div>
  )
}
Example #20
Source File: index.js    From rctf with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
function useTriggerRerender () {
  const setToggle = useState(false)[1]
  return useCallback(() => setToggle(t => !t), [setToggle])
}
Example #21
Source File: timer.js    From rctf with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
Timer = withStyles({
  card: {
    background: '#222',
    margin: 'auto'
  },
  section: {
    display: 'inline'
  },
  content: {
    display: 'grid',
    gridTemplateColumns: 'repeat(4, 1fr)',
    columnGap: '20px',
    margin: '20px 40px',
    textAlign: 'center'
  },
  time: {
    fontSize: '40px'
  },
  absolute: {
    gridColumn: 'span 4',
    fontSize: '15px',
    color: '#bbb'
  },
  sub: {
    gridColumn: 'span 4',
    marginTop: '10px',
    fontSize: '20px'
  },
  over: {
    margin: '20px 40px',
    fontSize: '20px',
    textAlign: 'center'
  }
}, ({ classes }) => {
  const [time, setTime] = useState(Date.now())
  useEffect(() => {
    const intervalId = setInterval(() => setTime(Date.now()), 1000)
    return () => clearInterval(intervalId)
  }, [])
  if (time > config.endTime) {
    return (
      <div class='row'>
        <div class={`card ${classes.card}`}>
          <div class={classes.over}>
            The CTF is over.
          </div>
        </div>
      </div>
    )
  }
  const targetEnd = time > config.startTime
  const targetTime = targetEnd ? config.endTime : config.startTime
  const timeLeft = targetTime - time
  const daysLeft = Math.floor(timeLeft / (1000 * 60 * 60 * 24))
  const hoursLeft = Math.floor(timeLeft / (1000 * 60 * 60)) % 24
  const minutesLeft = Math.floor(timeLeft / (1000 * 60)) % 60
  const secondsLeft = Math.floor(timeLeft / 1000) % 60
  return (
    <div class='row'>
      <div class={`card ${classes.card}`}>
        <div class={classes.content}>
          <span class={classes.time}>{daysLeft}</span>
          <span class={classes.time}>{hoursLeft}</span>
          <span class={classes.time}>{minutesLeft}</span>
          <span class={classes.time}>{secondsLeft}</span>
          <span>Days</span>
          <span>Hours</span>
          <span>Minutes</span>
          <span>Seconds</span>
          <span class={classes.sub}>until {config.ctfName} {targetEnd ? 'ends' : 'starts'}</span>
          <span class={classes.absolute}>{formatAbsoluteTimeWithTz(targetTime)}</span>
        </div>
      </div>
    </div>
  )
})
Example #22
Source File: members-card.js    From rctf with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
MembersCard = withStyles({
  form: {
    '& button': {
      display: 'block',
      marginLeft: 'auto',
      marginRight: '0',
      marginTop: '10px'
    }
  }
}, ({ classes }) => {
  const { toast } = useToast()

  const [email, setEmail] = useState('')
  const handleEmailChange = useCallback(e => setEmail(e.target.value), [])

  const [buttonDisabled, setButtonDisabled] = useState(false)

  const [members, setMembers] = useState([])

  const handleSubmit = useCallback(e => {
    e.preventDefault()
    setButtonDisabled(true)

    addMember({ email })
      .then(({ error, data }) => {
        setButtonDisabled(false)

        if (error) {
          toast({ body: error, type: 'error' })
        } else {
          toast({ body: 'Team member successfully added' })
          setMembers(members => [...members, data])
          setEmail('')
        }
      })
  }, [email, toast])

  useEffect(() => {
    getMembers()
      .then(data => setMembers(data))
  }, [])

  return (
    <div class='card'>
      <div class='content'>
        <p>Team Information</p>
        <p class='font-thin u-no-margin'>Please enter a separate email for each team member. This data is collected for informational purposes only. Ensure that this section is up to date in order to remain prize eligible.</p>
        <div class='row u-center'>
          <Form class={`col-12 ${classes.form}`} onSubmit={handleSubmit} disabled={buttonDisabled} buttonText='Add Member'>
            <input
              required
              autocomplete='email'
              autocorrect='off'
              icon={<EnvelopeOpen />}
              name='email'
              placeholder='Email'
              type='email'
              value={email}
              onChange={handleEmailChange}
            />
          </Form>
          {
            members.length !== 0 &&
              <div class='row'>
                {
                  members.map(data => <MemberRow setMembers={setMembers} { ...data } />)
                }
              </div>
          }
        </div>
      </div>
    </div>
  )
})
Example #23
Source File: CorrectedAnswer.js    From duolingo-solution-viewer with MIT License 5 votes vote down vote up
CorrectedAnswer = ({ diffTokens = [], result = RESULT_CORRECT }) => {
  const getElementClassNames = useStyles(CLASS_NAMES, STYLE_SHEETS, [ result ]);

  // Renders a diff token.
  const renderToken = useCallback((token, displayMode) => {
    let elementKey = null;

    if (token.added) {
      if (DISPLAY_MODE_CORRECTED === displayMode) {
        return null;
      } else if (!token.ignorable) {
        elementKey = ADDED_TOKEN;
      }
    } else if (token.removed) {
      if (DISPLAY_MODE_ORIGINAL === displayMode) {
        return null;
      } else if (!token.ignorable) {
        elementKey = REMOVED_TOKEN;
      }
    }

    return (
      <span className={getElementClassNames(elementKey)}>
        {token.value}
      </span>
    );
  }, [ getElementClassNames ]);

  const [ originalAnswer, setOriginalAnswer ] = useState([]);
  const [ correctedAnswer, setCorrectedAnswer ] = useState([]);

  // Refreshes both versions of the answer when the diff tokens change.
  useEffect(() => {
    setOriginalAnswer(diffTokens.map(renderToken(_, DISPLAY_MODE_ORIGINAL)));
    setCorrectedAnswer(diffTokens.map(renderToken(_, DISPLAY_MODE_CORRECTED)));
  }, [ diffTokens, renderToken ]);

  if (0 === diffTokens.length) {
    return null;
  }

  return (
    <IntlProvider scope="corrected_answer">
      <h2 className={getElementClassNames(WRAPPER)}>
        <Text id="title">Corrected answer:</Text>
        <div className={getElementClassNames(VALUE)}>
          {originalAnswer}
        </div>
        <div className={getElementClassNames(VALUE)}>
          {correctedAnswer}
        </div>
      </h2>
    </IntlProvider>
  );
}
Example #24
Source File: FilterInput.js    From duolingo-solution-viewer with MIT License 5 votes vote down vote up
FilterSetting = ({ context, setting: { key, values }, currentFilter, onUpdate }) => {
  const menu = useRef();
  const wrapper = useRef();
  const [ isMenuDisplayed, setIsMenuDisplayed ] = useState(false);

  const currentValue = values.find(it.value === currentFilter[key]);

  const onCloseMenu = () => setIsMenuDisplayed(false);

  const onSelect = value => {
    onCloseMenu();
    onUpdate({ ...currentFilter, [key]: value });
  };

  const onToggleMenu = event => {
    discardEvent(event);
    setIsMenuDisplayed(!isMenuDisplayed);
  };

  useClickAway([ wrapper, menu ], onCloseMenu);

  const getElementClassNames = useStyles(CLASS_NAMES, STYLE_SHEETS, [ context ]);

  return (
    <Localizer>
      <div
        ref={wrapper}
        onClick={onToggleMenu}
        title={<Text id={currentValue.labelId}>{currentValue.defaultLabel}</Text>}
        className={getElementClassNames(FILTER_SETTING)}
      >
        <FontAwesomeIcon
          icon={currentValue.icon}
          size="xs"
          fixedWidth
          className={getElementClassNames(FILTER_SETTING_ICON)}
        />
        {isMenuDisplayed && (
          <div>
            <Dropdown
              ref={menu}
              context={context}
              options={values}
              getOptionKey={({ value }) => value}
              onSelect={onSelect}
              onClose={onCloseMenu}
            />
          </div>
        )}
      </div>
    </Localizer>
  );
}
Example #25
Source File: hooks.js    From paypal-installments with Apache License 2.0 5 votes vote down vote up
export function useXProps<T>() : T {
    const [ xprops, setXProps ] = useState(window.xprops);
    useEffect(() => xprops.onProps(newProps => {
        setXProps({ ...newProps });
    }), []);
    return { ...xprops };
}
Example #26
Source File: Item.js    From vegemite with MIT License 5 votes vote down vote up
// ---

export default function (props) {
	const { id, title, completed } = props;

	const editor = useRef(null);
	const [editing, setEditing] = useState(false);

	useEffect(() => {
		if (editing) {
			editor.current.value = title;
			editor.current.focus();
		}
	}, [editing]);

	const classname = [
		editing && 'editing',
		completed && 'completed',
	].filter(Boolean).join(' ');

	function onToggle() {
		todomvc.dispatch('todo:toggle', id);
	}

	function onDestroy() {
		todomvc.dispatch('todo:del', id);
	}

	function onDblClick() {
		setEditing(true);
	}

	function onblur(ev) {
		let value = ev.target.value.trim();
		if (value.length > 0) {
			todomvc.dispatch('todo:put', { id, value });
		}
		ev.target.value = null;
		setEditing(false);
	}

	function onkeydown(ev) {
		if (ev.which === 27) {
			ev.target.value = null;
			setEditing(false);
		} else if (ev.which === 13) {
			onblur(ev);
		}
	}

	return (
		<li class={classname}>
			<div class="view">
				<input type="checkbox" class="toggle" checked={completed} onchange={onToggle} />
				<label onDblClick={onDblClick}>{title}</label>
				<button class="destroy" onclick={onDestroy} />
			</div>
			{ editing && <input ref={editor} class="edit" onblur={onblur} onkeydown={onkeydown} /> }
		</li>
	);
}
Example #27
Source File: App.jsx    From todo-pwa with MIT License 5 votes vote down vote up
App = () => {
  const [items, setItems] = useState([]);
  const [mounted, setMounted] = useState(false);

  const itemsAdd = title =>
    setItems([
      {
        title,
        id: uuid(),
        done: false,
      },
      ...items,
    ]);
  const itemsRemove = id => setItems(items.filter(item => id !== item.id));
  const itemsSet = (id, done) =>
    setItems(items.map(item => (item.id === id ? { ...item, done } : item)));

  // Whenever the items Array changes, the new Values should be stored in idb
  useEffect(() => mounted && idb.set('items', items), [items]);

  // on mount, the items from the idb should be set
  useEffect(() => {
    setMounted(true);
    idb.get('items').then(items => setItems(items || []));
  }, []);

  return (
    <div className="flex flex-col justify-start">
      <div className="bg-indigo-800 text-white w-full shadow-lg sticky top-0">
        <Header className="w-11/12 max-w-lg mx-auto" />
      </div>
      <Form className="w-11/12 max-w-lg mx-auto mt-10" itemsAdd={itemsAdd} />
      <List
        className="w-11/12 max-w-lg mx-auto my-16"
        items={items}
        itemsRemove={itemsRemove}
        itemsSet={itemsSet}
      />
      <Footer className="m-auto w-11/12 max-w-2xl" />
      <A2H />
    </div>
  );
}
Example #28
Source File: Form.jsx    From todo-pwa with MIT License 5 votes vote down vote up
Form = ({ className = '', itemsAdd }) => {
  const input = useRef(null);
  const [value, setValue] = useState(
    new URL(window.location).searchParams.get('title') || ''
  );

  useEffect(() => {
    // The shareTargetAPI creates a get Request that looks like this:
    // /preact/?title={title}&text={text}&url={url}
    const params = new URL(window.location).searchParams;
    const v = [
      ...(params.get('title') ? [params.get('title')] : []),
      ...(params.get('text') ? [params.get('text')] : []),
      ...(params.get('url') ? [params.get('url')] : []),
    ];

    setValue(v.join(' - '));
  }, []);

  return (
    <div className={className}>
      <form
        className="flex items-stretch"
        autocomplete="off"
        onSubmit={e => {
          e.preventDefault();
          if (value !== '') {
            itemsAdd(value);
            setValue('');
            input.current.focus();
          }
        }}
      >
        <input
          type="text"
          name="title"
          id="title"
          className="appearance-none border rounded rounded-r-none w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
          ref={input}
          value={value}
          onKeyUp={e => setValue(e.target.value)}
          autocomplete="off"
        />
        <button
          type="submit"
          className="font-bold rounded rounded-l-none text-white px-4 hover:bg-indigo-700 bg-indigo-800 text-center no-underline block focus:shadow-outline focus:outline-none"
        >
          Add
        </button>
      </form>
      <ContactPicker value={value} setValue={setValue} className="w-full" />
    </div>
  );
}
Example #29
Source File: page.jsx    From paypal-installments with Apache License 2.0 5 votes vote down vote up
function Page({ cspNonce, content } : PageProps) : mixed {
    const { data, close } = useXProps();
    const [ visible, setVisible ] = useState(false);

    useEffect(() => {
        const hasOptions = Boolean(data && data.options && data.options.length);
        setVisible(hasOptions);
    }, [ data ]);

    return (
        <Fragment>
            <style nonce={ cspNonce }>
                {`
                    * {
                        box-sizing: border-box;
                    }

                    html, body {
                        margin: 0;
                        padding: 0;
                        font-family: Helvetica, sans-serif;
                        font-size: 14px;
                    }

                    body {
                        width: 100%;
                        overflow:auto;
                    }
                `}
            </style>

            {
                (visible)
                    ? <Installments
                        data={ data }
                        cspNonce={ cspNonce }
                        close={ close }
                        content={ content } />
                    : null
            }
        </Fragment>
    );
}