Coder Social home page Coder Social logo

lrud's People

Contributors

jamesplease avatar promwad-odc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

lrud's Issues

More dynamic node props

such as defaultFocusRow. atm the node isn't updated when these update. tbqh they should prob all be dynamic

Animations: screen transitions

The biggest issue with this lib is handling animations. Specifically, an animation where there something on the previous page is in focus and something on the new page is entering in a focused state. isExiting was added to solve this use case, but there are clearly some bugs with that approach.

A few thoughts:

  • Maybe isExiting can be fixed. It needs to support animating in as well as out (right now it can error on some in transitions)
  • A radical idea I had was the ability to have multiple things in focus at the same time. Sounds crazy, right? It might be. But here me out: only one of those focused items can receive input events at a time. The way it would work is something like this: all focused items on the page would be grouped together in "screens." Within each screen, there can be up to one focused item. One screen can be made active at a time.

So, imagine:

  • you're on a homepage. That screen is active and has a focused item.
  • you start a transition. A new screen mounts and starts animating in as the old screen exits.
  • both the home page screen and new screen have a focused item. And that focused item is visible. However, maybe during the transition we have it so both screens are disabled, so the user cannot take any action.
  • after the transition ends we set the new screen to be active, so the focus can be moved/selected.

Architecturally it is simple. What would the API look like?


This idea of screens seems like a natural evolution of the already-implemented trap, btw. And it would actually tie in super nicely with #62

onActive/onInactive props

This will need a new Event type; ActiveEvent

interface ActiveEvent {
  prevActiveId: Id | null;
  nextActiveId: Id;
  prevActiveNode: Id | null;
  nextActiveNode: Node;
}

Docs

  • API Reference
  • Interfaces
    • FocusNode
    • FocusStore
    • MoveEvent
    • GridMoveEvent
    • FocusEvent
  • Guides
    • Orientation
    • Focus (Mar 2022 update: I forget what I planned to include in this guide)
    • Active
    • Disabled
    • isExiting
    • focus trap
    • Pointer events (include using pointer-events: none for traps; complexity involved)
  • Examples (#7 )

New hook: usePreviousFocusedChildIndex

usePreviousFocusedChildIndex

Useful for when you care to know the last child index that was focused, even if the node becomes unfocused. For example, when navigating off of the nav. The focus indicator still displays on the last-focused nav item, even though no nav items are focused nor active at that time.

FocusEvent update: add Source

Source could be:

  • an arrow
  • an imperative call from setFocus
  • other sources (child mounting and taking focus from parent, or parent leaving)

Really it's a lot of work to document all of the sources. But this is useful for responding to events based on the direction of the arrow that led to the focus.

Tests

Integration-style tests rather than the traditional per-file unit tests.

  • Test focus trap that is also a grid. Does it behave as expected in regards to preferredChildren?
  • - Mounting
    • onMountAssignFocusTo
    • Grids + default columns/rows
    • All children are disabled
  • Tree Updates
    • onMountAssignFocusTo
    • Grids
    • Disabled (leaf)
    • Disabled (enabled parent, single disabled child)
    • Focus trap
  • Grid behavior
  • Focus trap behavior
  • All hooks
  • FocusNode props
  • Active state
  • Disable parent, propagate that down
  • Warnings (all)

Idea: Portal-like behavior for Traps

When a trap is focused, so is its immediate parent. In many situations this is unlikely to be the desired behavior.

One way around this would be to render traps in their own separate subtrees...outside of the root, even.

In the store, it could be managed like this:

trees: {
  root: { /* default tree */ },
  focusTrapOne: { ... },
  focusTrapTwo: { ... }
}

It's easy enough to work around this right now, but it would still be pretty cool if traps behaved like this.

Child nodes that are disabled behavior

The following is a peculiar arrangement of nodes:

<FocusNode focusId="A">
  <FocusNode disabled focusId="B" />
</FocusNode>

Situation 1

Consider a tree that is just the root. After some time, the above tree mounts. What would you expect to happen? Right now, the focus moves to A.

Situation 2

However, consider if this a sibling of another node. Trying to arrow into this won't work, as the parent has no eligible children to be focused.


These two situations treat this tree differently. In Situation 1, disabled nodes are effectively nonexistent, so the parent is considered a "leaf." In Situation 2, disabled nodes are treated as children, and can therefore make their parents ineligible for focus.

I currently think Situation 2 is the appropriate behavior, so I should probably update Situation 1 to match it. This will ensure that non-leaf nodes are never focused, no matter the situation.

Note: this must also apply to traps and isExiting nodes!

HTML only

Looking through the code I think I can guess the answer to this, but will ask anyway.

Is this library HTML (react-dom) only, or can you see this being usable on other renderers, such as React Native?

[possible bug] updating state onGridMove

Here's the possible situation. Needs to be investigated further:

  • Create a grid
  • Store the focused row/column in a useState
  • Keep that state in sync via onGridMove
  • Use that state to set defaultRowIndex and defaultColumnIndex

This is a bug because the updated default indices gets wiped. The reason is as follows:

  1. The user presses an arrow key.
  2. The arrow handler begins, using the old state (State 1), and creating a new state, State2.
  3. As a part of this state update, onGridMove is called
  4. onGridMove sets the external grid state, which then re-renders the <FocusNode/>, causing the node's update function to be executed
  5. Update function is executed, referencing State1 and outputting a brand new State3. Remember: onGridMove doesn't know about State2 as it hasn't been committed yet
  6. The arrow handler concludes, saving State2 and overriding State3

I need to verify this...although this explanation seems plausible for what I was seeing, I'm surprised because step 4/5 occur in a useEffect and should therefore be async from the arrow key handler.

v1.0.0

Here's the list of to-do's before I'd feel comfortable cutting a v1:

  • More examples (#7 )
  • Ensure types are accurate (#17 )
  • Tests (#6 )
  • More guides (#1)
  • Active/inactive event props (#18)
  • #78
  • #71
  • #87
  • #98

Include production build in package

This will allow me to see where the file size is coming from. And for the record the lib seems to be a hefty 32kb atm. I feel pretty confident I can shrink that down a bit!

Propagate node updates down

A parent becoming disabled should disable the children.

Question: should exiting a parent also exit the children? Perhaps?
Yes


To implement this:

  • I'll need a new prop on each node, representing whether an ancestor has that value set
  • When computing the value, I'll need to use this.disabled || this.ancestorDisabled

Examples

Examples to Create

Basic

  • Basic layout
  • Wrapping
  • A grid
  • Active. A grid, clicking a tile makes it active and styled visually different from the others
  • Disabled nodes
  • Focus trap

Advanced

  • Transitions using active states
  • Transitions using isExiting
  • Transitions with setting mount on focus to a particular node
  • Modal using traps
  • Basic TV app
  • Pointer events
  • Grid that maintains its position

Fix traps

Navigating in a trap is not currently functioning

Dynamic node callbacks

The node callbacks are not currently dynamic. This is OK if you always use refs, but if you rely on the recreate-every-render behavior, then you might encounter stale values (todo: verify this claim).

One way to handle this is to treat callbacks the same as #38 , but this could cause infinite renders.

Node callback changes in React component =>
node is updated in the store =>
store updates subscribers =>
subscribers re-render the React components =>
repeat

A better solution is to ref the callbacks internally within the FocusNode component. Then a static wrapper fn would be called on the node itself, which then calls the ref. The downside is that this is an unfortunate amount of boilerplate code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.