Skip to content

Conversation

LFDanLu
Copy link
Member

@LFDanLu LFDanLu commented Oct 5, 2020

Closes #1117

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

🧢 Your Project:

@adobe-bot
Copy link

Build successful! 🎉

@adobe-bot
Copy link

Build successful! 🎉

@adobe-bot
Copy link

Build successful! 🎉

@adobe-bot
Copy link

Build successful! 🎉

@LFDanLu LFDanLu changed the title (WIP) Add Tabs collapse Adding collapsible Tabs Oct 7, 2020
'aria-label': ariaLabel
};

// TODO: Figure out if tabListProps should go onto the div here, v2 doesn't do it
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume stuff like "role: tablist" shouldn't go here so I excluded adding tablistProps from useTabs to the picker

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

() => render({keyboardActivation: 'manual'})
)
.add(
'overflowMode: dropdown',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got rid of overflow mode stories for now since the prop isn't a thing yet

@adobe-bot
Copy link

Build successful! 🎉

…umbs

adds useValueEffect as a util. Also removes extraneous propagation of styleprops from other tab elements
@adobe-bot
Copy link

Build successful! 🎉

@adobe-bot
Copy link

Build successful! 🎉

snowystinger
snowystinger previously approved these changes Oct 24, 2020
Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for fixing that css!

@adobe-bot
Copy link

Build successful! 🎉

snowystinger
snowystinger previously approved these changes Nov 5, 2020
checkShouldCollapse();
}, [props.children, checkShouldCollapse]);

useResizeObserver({ref: wrapperRef.current && wrapperRef, onResize: checkShouldCollapse});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, i didn't have any issue with this one just passing wrapperRef and not checking if current wasn't null
I take it you did?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a hold over from before I tweaked useResizeObserver, removed it and didn't see any issues

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but if I remember correctly the reproduction was doing the orientation switch from vertical to horizontal

@adobe-bot
Copy link

Build successful! 🎉

ktabors
ktabors previously approved these changes Nov 5, 2020
if (state.selectionManager.isEmpty || !state.collection.getItem(state.selectedKey)) {
state.selectionManager.replaceSelection(state.collection.getFirstKey());
}
}, [state]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to listen to the entire state or just the selectedKey or selectionManager?


useEffect(() => {
if (ref.current) {
let tabs: HTMLElement[] = Array.from(ref.current.querySelectorAll('.' + styles['spectrum-Tabs-item']));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What am I missing that we check the HTML for the tabs instead of using the children?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason behind this is that we want to obtain the Tab HTML element so we can get things like offsetTop, offsetParent, etc for TabLine positioning

snowystinger
snowystinger previously approved these changes Nov 5, 2020
@LFDanLu LFDanLu dismissed stale reviews from snowystinger and ktabors via 7278408 November 6, 2020 19:49
@adobe-bot
Copy link

Build successful! 🎉

Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a bug, in the story "resizable" if i select tab 5, then collapse it to the dropdown, then select tab 3, then expand it again. Tab 3 won't get the indicator line

Simpler repro steps, go to that story, select tab 3, collapse, then expand.

used to work when state was in the dep array since state.selectionManager updated constantly on resize, replaced that with collapse
@adobe-bot
Copy link

Build successful! 🎉

Copy link
Member

@devongovett devongovett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. A few suggestions. Please address in a followup!

disallowEmptySelection: true
});

// Ensure a tab is always selected
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I think we need to at least have a default. I think it's weird that you'd need to implement this yourself when it will be most common for the first tab to be selected on mount. If you wish to control it some other way, you can use the controlled props. IMO this logic should be in stately.

tabListclassName?: string
}

const CollapsibleTabList = React.forwardRef(function <T> (props: CollapsibleTabListProps<T>, ref: MutableRefObject<HTMLDivElement>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why this is a separate component from Tabs? You already render a tab list there, so could theoretically also just render a tab picker as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally it was in Tabs as well, but was split out like this for readability as per previous reviews.

Since the CollapsibleTabList has a wrapping div (aka collapseWrapper) that shouldn't be present on a vertical tablist it looked something like this:

  let tablist = (
    <TabList
      {...tabListProps}
      ref={ref}
      orientation={orientation}
      density={density}
      isQuiet={isQuiet}
      isDisabled={isDisabled}
      state={state}
      selectedTab={selectedTab} />
  );

  if (collapse && orientation !== 'vertical') {
    tablist = (
      <TabPicker
        {...props}
        state={state} />
    );
  }

  if (orientation !== 'vertical') {
    tablist = (
      <div
        ref={wrapperRef}
        className={classNames(
          styles,
          'spectrum-Tabs--collapsible'
        )}>
        {tablist}
      </div>
    );
  }

<Text>{item.name}</Text>
</>
}>
<Content margin="size-160">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the Content required here or why is it needed? Should this margin be built into the tab itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Content w/ margin is to provided margins around the tab panel content.
Without:
image

With:
image

I assume the original contributer added these since it looks better, XD files don't have any examples on what the tab panel content should look like. IMO we should keep as is since it allows users to customize what the tab panel content should look like in terms of positioning relative to the tab list

key={item.name}
textValue={item.name}
title={
<>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should maybe consider whether we want this to be the way of adding icons to tabs or whether we want to do a semantic element/slots style API with children like we have for other components... Does seem a bit harder in this case though due to to needing to place the two parts in different elements completely.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, a bit tricky since we need to differentiate from the Tab and the Tab's contents (tab panel stuff)

@adobe-bot
Copy link

Build successful! 🎉

@adobe-bot
Copy link

Build successful! 🎉

@dannify dannify merged commit 63d7fd9 into main Nov 13, 2020
@dannify dannify deleted the tabs_collapse branch November 13, 2020 01:43
@dannify
Copy link
Member

dannify commented Nov 13, 2020

Please address comments from Devon in a follow PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement Tabs collapsing behavior
6 participants