feat(Gallery): add inline view and controlled active item index#397
Conversation
6ceafa5 to
cfe3760
Compare
cfe3760 to
0e794b9
Compare
0e794b9 to
5e50e2c
Compare
| | open | `Boolean` | | | | `modal` only. The modal opened state | | ||
| | onOpenChange | `(open: boolean) => void` | | | | `modal` only. The modal toggle handler | | ||
| | container | `HTMLElement` | | | | `modal` only. The modal container | | ||
| | onClose | `() => void` | | | | `inline` only. Called on the header close/back button; the button is hidden when omitted | |
There was a problem hiding this comment.
onOpenChange and onClose: when using the component, it will seem that these props do the same thing
I think that for inline mode, onClose and rendering an additional header with a close button are unnecessary
There was a problem hiding this comment.
Agree, removed.
|
|
||
| ```tsx | ||
| { | ||
| open && ( |
There was a problem hiding this comment.
Please remove this flag from the example, the goal here is to show that the gallery can be rendered inline, not to show how its conditional rendering can be implemented
There was a problem hiding this comment.
Good catch, I forgot to remove it after the previous version.
| } | ||
|
|
||
| &_view_inline { | ||
| position: absolute; |
There was a problem hiding this comment.
I don't think it's a good idea to set such position rules; they should be set by the user for a specific use case.
There was a problem hiding this comment.
Agreed, styling the inline gallery's container is the consumer's responsibility. Updated.
|
|
||
| export type GalleryProps = GalleryModalProps | GalleryInlineProps; | ||
|
|
||
| function resolveViewProps(props: GalleryProps) { |
There was a problem hiding this comment.
Let's move this to Gallery/utils/resolveViewProps, so this file will contain only the component
But in general, this function seems to be unnecessary, because the props type already excludes the passing of unnecessary properties, and instead of isInline, it is better to use view === inline directly, as this constant does not make readability better, it is equivalent to
There was a problem hiding this comment.
You're right, removed the unnecessary helpers.
| * - `modal` — open the gallery in a viewport-sized modal overlay (default). | ||
| * - `inline` — render the gallery in place, filling its parent container. | ||
| */ | ||
| export type GalleryView = 'modal' | 'inline'; |
There was a problem hiding this comment.
Let's move this to Gallery/types.ts
| }, [onOpenChange]); | ||
|
|
||
| const handleClose = React.useCallback(() => { | ||
| if (isInline) { |
There was a problem hiding this comment.
This is superfluous when we remove onClose.
|
Preview is ready. |
ca3c517 to
9423eab
Compare
| @@ -0,0 +1,31 @@ | |||
| import * as React from 'react'; | |||
|
|
|||
| // Copied from `@gravity-ui/uikit`'s private `useStateWithCallback` hook: | |||
There was a problem hiding this comment.
I think we don't need this information
There was a problem hiding this comment.
I see, replaced with hook description.
|
|
||
| import {useStateWithCallback} from '../useStateWithCallback'; | ||
|
|
||
| // Copied from `@gravity-ui/uikit`'s private `useConditionallyControlledState` hook: |
There was a problem hiding this comment.
I think we don't need this information
There was a problem hiding this comment.
I see, replaced with hook description.
| open, | ||
| onOpenChange, | ||
| container, | ||
| } = props; |
There was a problem hiding this comment.
Let's return immediate props destructuring
export const Gallery = ({ ... }: GalleryProps) => {| container, | ||
| } = props; | ||
|
|
||
| const inlineRef = React.useRef<HTMLDivElement>(null); |
There was a problem hiding this comment.
Let's rename this to something like inlineGalleryContainerRef
| - **Swipe Gestures**: Mobile swipe navigation (automatically disabled during zoom interaction) | ||
| - **Fullscreen Mode**: Toggle fullscreen view | ||
| - **Custom Actions**: Add custom action buttons for each gallery item | ||
| - **Contained Mode**: Render the gallery inside its `container` bounds instead of over the whole viewport |
There was a problem hiding this comment.
Maybe Inline view will be clearer
| container?: undefined; | ||
| }; | ||
|
|
||
| export type GalleryProps = GalleryModalProps | GalleryInlineProps; |
There was a problem hiding this comment.
Seems like this will be a braking change since only modal view properties could be used (as in the GalleryProvider) , there will be an error through the new union type
There was a problem hiding this comment.
It's not a breaking change - existing modal usage keeps compiling:
- GalleryModalProps keeps
view?: 'modal'optional, so old call sites with no view (<Gallery open onOpenChange container>) still resolve to the modal branch. - GalleryInlineProps declares
open?/onOpenChange?/container?as undefined rather than dropping them, so those keys still exist on both members - reads andkeyof GalleryPropsare unchanged, so property access / Pick / Omit all behave as before. - GalleryProvider is unaffected since it references
Pick<GalleryModalProps, ...>directly, not the union.
The only thing the union newly forbids is combining view="inline" with open/onOpenChange/container - a new invalid combo that didn't exist before, so it can't break existing code.
Verified with npm run typecheck.
9423eab to
408497d
Compare
| } | ||
|
|
||
| &_view_inline { | ||
| width: 100%; |
There was a problem hiding this comment.
Maybe this also should be controlled by the user
- add `view` prop ('modal' default | 'inline') to render the gallery in place instead of a modal
- add controlled `activeItemIndex` / `onActiveItemIndexChange`,
backed by a local `useConditionallyControlledState`
- add `GalleryItem.id` to keep item previews reconciled by identity
408497d to
1753e0b
Compare
viewprop ('modal' default | 'inline') to render the gallery in place instead of a modalactiveItemIndex/onActiveItemIndexChange,backed by a local
useConditionallyControlledStateGalleryItem.idto keep item previews reconciled by identityI hereby agree to the terms of the CLA available at: link.