Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(s2): coachmarks [WIP] #7590

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

feat(s2): coachmarks [WIP] #7590

wants to merge 10 commits into from

Conversation

jluyau
Copy link
Member

@jluyau jluyau commented Jan 9, 2025

Closes

✅ 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:

@rspbot
Copy link

rspbot commented Jan 9, 2025

@rspbot
Copy link

rspbot commented Jan 9, 2025

@rspbot
Copy link

rspbot commented Jan 15, 2025

@rspbot
Copy link

rspbot commented Jan 15, 2025

## API Changes

@react-spectrum/s2

/@react-spectrum/s2:CoachMark

+CoachMark {
+  UNSTABLE_portalContainer?: Element = document.body
+  arrowBoundaryOffset?: number = 0
+  boundaryElement?: Element = document.body
+  children: ReactNode | ({
+    size: 'XS' | 'S' | 'M' | 'L' | 'XL'
+}) => ReactNode
+  className?: string | ((PopoverRenderProps & {
+    defaultClassName: string | undefined
+})) => string
+  containerPadding?: number = 12
+  crossOffset?: number = 0
+  defaultOpen?: boolean
+  isEntering?: boolean
+  isExiting?: boolean
+  isKeyboardDismissDisabled?: boolean = false
+  isNonModal?: boolean
+  isOpen?: boolean
+  maxHeight?: number
+  offset?: number = 8
+  onOpenChange?: (boolean) => void
+  placement?: Placement = 'bottom'
+  scrollRef?: RefObject<Element | null> = overlayRef
+  shouldCloseOnInteractOutside?: (Element) => boolean
+  shouldFlip?: boolean = true
+  shouldUpdatePosition?: boolean = true
+  size?: 'S' | 'M' | 'L' | 'XL'
+  slot?: string | null
+  style?: CSSProperties | ((PopoverRenderProps & {
+    defaultStyle: CSSProperties
+})) => CSSProperties | undefined
+  trigger?: string
+  triggerRef?: RefObject<Element | null>
+}

/@react-spectrum/s2:CoachMarkTrigger

+CoachMarkTrigger {
+  children: ReactNode
+  defaultOpen?: boolean
+  isOpen?: boolean
+  onOpenChange?: (boolean) => void
+}

/@react-spectrum/s2:CoachIndicator

+CoachIndicator {
+  children: ReactNode
+  isActive?: boolean
+}

/@react-spectrum/s2:useTour

+useTour {
+  undefined: any
+  returnVal: undefined
+}

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.

I think the Coachmark should be a Focus trap. Probably just need to include a Dialog inside the Popover.

Coachmarks and indicator look pretty :) have a couple initial big points

export default meta;

export const CoachMarkExample = (args) => (
<CoachMarkTrigger isOpen>
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is the API we want. Otherwise Coachmarks are always in the JSX and it becomes hard to disentangle them or coordinate over an entire application for a tour. For instance, a Coachmark may not be rendered until a lazy component has loaded or maybe a view is swapped out part way through the tour.

Instead, we should use the same strategy from v2 and attach to selectors with a retry pattern for finding the current step.

import TextBold from '../s2wf-icons/S2_Icon_TextBold_20_N.svg';
import TextIcon from '../s2wf-icons/S2_Icon_Text_20_N.svg';
import {Toolbar} from 'react-aria-components';

Copy link
Member

Choose a reason for hiding this comment

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

stories should all have a button to start the tour, I don't think the tour should auto start when you enter the docs otherwise there could be multiple tours at once

@jluyau
Copy link
Member Author

jluyau commented Jan 15, 2025

I think the Coachmark should be a Focus trap. Probably just need to include a Dialog inside the Popover.

yeah i initially went with a focus trap, but looking at the Spectrum design docs, there's a type of coach mark that will only advance if the element it's modifying is interacted with (e.g. a button is pressed), and i wasn't able to tap the element with the coach mark focusables.

@snowystinger
Copy link
Member

I think the Coachmark should be a Focus trap. Probably just need to include a Dialog inside the Popover.

yeah i initially went with a focus trap, but looking at the Spectrum design docs, there's a type of coach mark that will only advance if the element it's modifying is interacted with (e.g. a button is pressed), and i wasn't able to tap the element with the coach mark focusables.

oh... no....

That would be difficult to detect from a global coordination standpoint, so I see why you opted to try and place the coachmark using the target as the trigger element.

Would all the "clickable" things even be buttons? What if it's telling you how to paint on a canvas?

If we tried to do that, we'd need something better than a capturing click listener since we stop propagation and we also will be moving to firing onPress in the click event IF it even exists. Different forms of interaction may not even fire click, for instance keyboard.

I think the better thing to do would be to have the UI update state in response to the tour moving along, regardless of clicking on a button or canvas.

Maybe bring these different use cases to an Otters time, I suspect there will be opinions.

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.

3 participants