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

fix rtl direction for components #1381

Merged
merged 12 commits into from
Dec 19, 2024
Merged

fix rtl direction for components #1381

merged 12 commits into from
Dec 19, 2024

Conversation

Sebastian-ubs
Copy link
Contributor

@Sebastian-ubs Sebastian-ubs commented Dec 11, 2024

This change is Reviewable

This is about fixing correct alignment of ui elements in a right to left layout, not direction of the text, which will be determined by the script of the text itself.

Components fixed

  • Book chapter control: arrow buttons navigation, alignment of the history icon, direction of the popover content, align popover position start vs end
  • Book selector: direction, spacing: tw-ml -> tw-ms
  • Inventory: direction of filter comboboxes
  • MultiSelectCombobox: direction, spacing
  • Result viewer: direction
  • scroll group selector: direction
  • tab nav search: direction
  • chapter range selector: direction of combobx, spacing
  • checklist: spacing
  • combobox: spacing
  • search: alignment of icons + no resizing + fix ring color by removing unneeded duplication of classNames (8b6a9e3)
  • spinner: animation direction -- is it valid to spin anti clockwise in a rtl language? https://github.com/paranext/ux/issues/168#issuecomment-2523558709
  • dialog: mentioned the current bug
  • dropdown: mentioned the current bug
  • switch: alignment of the circle
  • toggle group: direction
  • sidebar: direction + flip icon + (together with Jolie) mark our code comments

Example: BCV

Before
image

After
image

@Sebastian-ubs Sebastian-ubs changed the title fix rtl fix rtl direction for components Dec 11, 2024
@Sebastian-ubs Sebastian-ubs marked this pull request as ready for review December 11, 2024 17:12
@merchako
Copy link
Contributor

merchako commented Dec 11, 2024

I feel like there should be a way of getting direction keyboard events like "RightArrow" and "LeftBracket" but as text-direction-aware abstractions like "EndArrow" and "StartBracket". CSS already does this (e.g. padding-start). Anybody know of a way to do it with the Javascript API?


I saw @Sebastian-ubs's PR to add text direction awareness to a bunch of components and thought, golly, a JS core feature like like this could save us a lot of code. https://github.com/paranext/paranext-core/pull/1381/files

ChatGPT seems to think any component should be able to get text direction from an element using

const computedStyle = window.getComputedStyle(targetElement);
    const direction = computedStyle.direction; // 'ltr' or 'rtl'

Might we use this approach for components to get text direction without needing to pass it as a parameter?

  • Or perhaps this wouldn't work if the component doesn't already contain a targetElement to grab the direction info from.
  • Or perhaps we need to manually pass down direction since some elements with direction A may contain other elements with direction B.

Convo in Discord

Copy link
Member

@lyonsil lyonsil 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 picking up the work to make these controls work left-to-right and right-to-left. This is very helpful!

Unfortunately, I don't think we want to explicitly have a direction prop to determine ltr or rtl. HTML already defines a mechanism for specifying this, and creating a separate prop to indicate the same idea can cause conflicts/confusion. For React controls, it would be helpful to create a hook that uses getComputedStyle as Alex indicates above. We need to make sure not to call getComputedStyle on every render as it isn't "free", but allowing the controls to call a hook to get the direction will standardize where/how we get it safely.

Reviewable status: 0 of 44 files reviewed, 1 unresolved discussion (waiting on @Sebastian-ubs)


lib/platform-bible-react/dist/index.d.ts line 211 at r1 (raw file):

	handleSubmit: (scrRef: ScriptureReference) => void;
	/** Text and layout direction */
	direction?: "rtl" | "ltr";

We should not be adding direction props to all of our controls. I'm just marking the first one as a block, but the same thought applies to all the later ones. More thoughts in the overall comments for this PR.

// TODO: issue: both exported functions fire x^2 times with x = the number of elements on screen that use this, however not all do fire on re-rendering.
// It works well for expected cases like a popover (combobox), but not so where unexpectedly a dir prop is needed (select, radio group, toggle group)
// or where we want to re-position elements with absolute position based on the current direction (bcv, search bar)
// This a problem in the preview app, but may not be a problem in the product, as we do not expect switching layout direction at runtime - maybe?
Copy link
Contributor

Choose a reason for hiding this comment

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

Currently, Platform requires a restart for UI language to change, and any direction change would reasonably be due to a UI language change or spawning a new webview (i.e., for scripture editor). So it may be fine…for now.

I believe that consultants/advisors will need to change their UI language frequently, though. So I'm going to advocate for being able to change UI language without a restart.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

solved with localStorage for now.

Copy link
Member

@lyonsil lyonsil left a comment

Choose a reason for hiding this comment

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

Reviewed 3 of 44 files at r1, all commit messages.
Reviewable status: 3 of 46 files reviewed, 3 unresolved discussions (waiting on @Sebastian-ubs)


lib/platform-bible-react/src/utils/dir-helper.ts line 5 at r2 (raw file):

export type Direction = 'ltr' | 'rtl';

// TODO: issue: both exported functions fire x^2 times with x = the number of elements on screen that use this, however not all do fire on re-rendering.

Thanks for looking into this approach, @Sebastian-ubs . Any exponential impact to performance is definitely concerning.

I mentioned it in Discord, but to reiterate here, if you want to drop this approach and just use a const temporarily in each control to indicate direction, changing it from 'ltr' to 'rtl' locally on your machine to work through rtl layout problems, that could unblock your work to update the layouts on each control. They won't show up rtl in the preview app that way, but hopefully you could get through the bulk of the harder changes this way.

I think a good solution on where to store the direction could be an application-wide Context provider, but I would like to get some more opinions from people who are out the rest of the year. Sorry this is not going quickly. This set of changes was a surprise when the PR first came up, and it has taken some thought about what we should do about direction. Anytime we have to touch every control, service, module, etc. to make something work, it makes me pause.

Copy link
Member

@lyonsil lyonsil left a comment

Choose a reason for hiding this comment

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

Reviewable status: 3 of 46 files reviewed, 3 unresolved discussions (waiting on @Sebastian-ubs)


lib/platform-bible-react/dist/index.d.ts line 211 at r1 (raw file):

Previously, lyonsil (Matt Lyons) wrote…

We should not be adding direction props to all of our controls. I'm just marking the first one as a block, but the same thought applies to all the later ones. More thoughts in the overall comments for this PR.

Per our discussion in Discord, using localStorage temporarily as the location to decide between ltr and rtl is fine. We'll want to change this to something else (e.g., a Context provider), but exactly what the "something else" should be doesn't need to hold up this PR.

Copy link
Member

@lyonsil lyonsil 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 the updates. I understand that we need to pass an explicit direction to 3rd party components or wrap those 3rd party components in a div with an explicit direction, but when we have our own components I'm assuming those should lookup the direction themselves.

Reviewed 5 of 44 files at r1, 1 of 24 files at r3, 54 of 54 files at r4, all commit messages.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @Sebastian-ubs)


lib/platform-bible-react/dist/index.d.ts line 211 at r1 (raw file):

Previously, lyonsil (Matt Lyons) wrote…

Per our discussion in Discord, using localStorage temporarily as the location to decide between ltr and rtl is fine. We'll want to change this to something else (e.g., a Context provider), but exactly what the "something else" should be doesn't need to hold up this PR.

I think you need to rebuild the react library and include the updated dist files in your PR. This shouldn't be here anymore.


lib/platform-bible-react/src/components/advanced/inventory/inventory-columns.tsx line 179 at r4 (raw file):

      const dir: Direction = readDirection();
      return (
        <ToggleGroup value={status} variant="outline" type="single" dir={dir}>

Why are we passing the direction here instead using readDirection? Shouldn't we update our component to read the direction itself?


lib/platform-bible-react/src/components/advanced/book-chapter-control/book-menu-item.component.tsx line 67 at r4 (raw file):

        onFocus={handleHighlightBook}
        onMouseMove={handleHighlightBook}
        dir={dir}

Why are we passing the direction here instead using readDirection? Shouldn't we update our component to read the direction itself?


lib/platform-bible-react/src/components/advanced/inventory/inventory.component.tsx line 401 at r4 (raw file):

          onValueChange={(value) => handleStatusFilterChange(value)}
          defaultValue={statusFilter}
          dir={dir}

Why are we passing the direction here instead using readDirection? Shouldn't we update our component to read the direction itself?

Copy link
Contributor Author

@Sebastian-ubs Sebastian-ubs left a comment

Choose a reason for hiding this comment

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

Dismissed @merchako from a discussion.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on @lyonsil)


lib/platform-bible-react/dist/index.d.ts line 211 at r1 (raw file):

Previously, lyonsil (Matt Lyons) wrote…

I think you need to rebuild the react library and include the updated dist files in your PR. This shouldn't be here anymore.

Done.


lib/platform-bible-react/src/components/advanced/book-chapter-control/book-menu-item.component.tsx line 67 at r4 (raw file):

Previously, lyonsil (Matt Lyons) wrote…

Why are we passing the direction here instead using readDirection? Shouldn't we update our component to read the direction itself?

Done.


lib/platform-bible-react/src/components/advanced/inventory/inventory-columns.tsx line 179 at r4 (raw file):

Previously, lyonsil (Matt Lyons) wrote…

Why are we passing the direction here instead using readDirection? Shouldn't we update our component to read the direction itself?

Done.


lib/platform-bible-react/src/components/advanced/inventory/inventory.component.tsx line 401 at r4 (raw file):

Previously, lyonsil (Matt Lyons) wrote…

Why are we passing the direction here instead using readDirection? Shouldn't we update our component to read the direction itself?

Done.

// TODO: issue: both exported functions fire x^2 times with x = the number of elements on screen that use this, however not all do fire on re-rendering.
// It works well for expected cases like a popover (combobox), but not so where unexpectedly a dir prop is needed (select, radio group, toggle group)
// or where we want to re-position elements with absolute position based on the current direction (bcv, search bar)
// This a problem in the preview app, but may not be a problem in the product, as we do not expect switching layout direction at runtime - maybe?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

solved with localStorage for now.

@Sebastian-ubs Sebastian-ubs enabled auto-merge (squash) December 19, 2024 20:35
Copy link
Member

@lyonsil lyonsil left a comment

Choose a reason for hiding this comment

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

Reviewed 20 of 20 files at r5, all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved


lib/platform-bible-react/src/preview/pages/components/basics/tab.examples.component.tsx line 15 at r5 (raw file):

  return (
    <>
      <Tabs defaultValue="2-youShouldNotSeeThis" dir={dir}>

I don't think that dir={dir} should be needed anymore. It looks like the Tabs component handles this internally now. I'm making this a non-blocking comment since it's just in the example.

Copy link
Member

@lyonsil lyonsil left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewable status: :shipit: complete! all files reviewed, all discussions resolved

@Sebastian-ubs Sebastian-ubs merged commit eea56ee into main Dec 19, 2024
7 checks passed
@Sebastian-ubs Sebastian-ubs deleted the fix-rtl-issues-in-pbr branch December 19, 2024 21:10
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