ItsJonQ / g2

✨ An experimental reimagining of WordPress components
http://g2-components.com/
MIT License
105 stars 12 forks source link

FlatList: Add component #17

Open ItsJonQ opened 3 years ago

ItsJonQ commented 3 years ago

I feel that it's important that G2 provides some sort of "FlatList" component (even if it's a basic one).

(Drawing inspiration from the world of native development...)

What's a FlatList?

FlatLists are a feature-rich and high-performant way to render collections of things.

Features

Below are some of the very helpful features that a FlatList component should offer out-of-the-box (speaking purely from a web-based context)

What's it look like?

From a visual UI perspective, FlatLists can resemble many forms. The most familiar example, would be something like this:

1_tpL2xhs1TGEQ09AwKqkYYQ

The above example is typical of a "Contact List" in contact/messaging-based applications.

Stepping away from mobile....

In Gutenberg, the Block Inserter sidebar can be imagined as a FlatList:

Screen Shot 2020-08-06 at 9 21 22 AM

From the G2 storybook, the following would use a FlatList as well:

Screen Shot 2020-08-06 at 9 33 03 AM

https://g2-components.xyz/?path=/story/examples-blocks--layout-grid

It's usefulness extends beyond just the Editor UI. 3rd party block authors, plugin authors, and others can use this component as a way to add "native" (editor) support to their data collections.

What's the code going to look like?

I don't think it is necessary to replicate the exact API interfaces from React Native's FlatList. To start, I think it should have some basic props, like...

<FlatList
    data={[...]}
    renderItem={}
    listHeader={}
    numColumns={}
/>

Also a way to enable programatic sortTo... methods.

We can try to recreate the BlockInserter as a starting test case!

ItsJonQ commented 3 years ago

Ohhh boy! Some fun updates. I just prototyped out the initial feature set + component API for <FlatList />. It's inspired very heavily on React Native's implementation as well as List from Swift UI.

Demo:

Live Demo: https://g2-components.xyz/?path=/story/components-flatlist--default

More importantly... check out the code!!!!

const Example = () => {
  const [users, setUsers] = useFlatListState(userSchema.make(10));

  const addUser = () => setUsers.prepend(userSchema.makeOne());
  const deleteUser = (id) => setUsers.delete({ id });
  const moveUser = (from, to) => setUsers.move(from, to);

  return (
    <HStack>
      <FlatList
        css={{ maxWidth: 400 }}
        onMove={(from, to) => moveUser(from, to)}
      >
        <HStack alignment="edge">
          <Button onClick={addUser} variant="primary">
            Add User
          </Button>
          <EditButton />
        </HStack>
        <FlatListItems>
          {users.map((user, index) => {
            return (
              <FlatListItem
                css={{ padding: 12 }}
                key={user.id || index}
                onDelete={() => deleteUser(user.id)}
              >
                <HStack alignment="left" spacing={3}>
                  <Avatar src={user.avatar} />
                  <Spacer>
                    <VStack spacing={1}>
                      <Text size={14} weight="bold">
                        {user.name}
                      </Text>
                      <Text
                        numberOfLines={2}
                        size={12}
                        truncate
                        variant="muted"
                      >
                        {user.description}
                      </Text>
                    </VStack>
                  </Spacer>
                </HStack>
              </FlatListItem>
            );
          })}
        </FlatListItems>
      </FlatList>
    </HStack>
  );
};

Key features

jasmussen commented 3 years ago

Nicely gelatinous animation, love it!

We use a mover control (up/down arrow) in many places, not just blocks but in the block navigator as well. This is based on the idea that drag and drop is additive to explicit button actions. Do you have any thoughts on how to best handle that?

ItsJonQ commented 3 years ago

@jasmussen Haii!! I'm not sure yet! We could offer arrows along side the drag handle.

(Feel free to share design ideas if you have any!)

Or maybe.. we could offer a "mode" where the user can prefer drag handles, mover arrows, or both?

This could be a preference like dark mode, etc...

jasmussen commented 3 years ago

We could offer arrows along side the drag handle.

It does become a lot, but it also seems necessary. I'd probably just use the two-line drag handle that the block editor uses.

Or maybe.. we could offer a "mode" where the user can prefer drag handles, mover arrows, or both?

If we were to offer a mode, I'd think it was a toggle of the mover control, not drag & drop vs. arrows. For example exactly as shown in this gif, you enter and exit a rearranging "mode".

User options remain a plan B, but even then we'd want to choose a default option, and it would have to be the one that balances the accessibility aspect best.

ItsJonQ commented 3 years ago

More ideas on list types + interactions: https://material.io/components/lists#types