stripe / stripe-apps

Stripe Apps lets you embed custom user experiences directly in the Stripe Dashboard and orchestrate the Stripe API.
https://stripe.com/docs/stripe-apps
MIT License
148 stars 73 forks source link

onSelectionChange in the Tab component in version 9 returns an unexpected `$.index` value. #992

Closed bensontrent closed 2 weeks ago

bensontrent commented 2 weeks ago

The docs at https://docs.stripe.com/stripe-apps/components/tabs?app-sdk-version=9#controlled-tabs suggest that the result of onSelectionChange will return the tab or key ID. However, either the docs or the SDK need to be updated since the return result of setSelectionChange in a tab component is $.index, ie $.0, $.1 etc.

Here's a test component to confirm this:

import { Box, ContextView, Spinner, Tab, TabList, TabPanel, TabPanels, Tabs } from "@stripe/ui-extension-sdk/ui";
import React from "react";
import { useEffect, useState, useCallback } from "react";

const TabTest = () => {

    const [selectedKey, setSelectedKey] = useState<React.Key>(0);

    return (
        <ContextView title="Tab Test">
        <Tabs selectedKey={selectedKey} onSelectionChange={(newKey) => { console.log(newKey); console.log(typeof newKey); setSelectedKey(newKey) }}>
            <TabList>
                {["one", "two"].map((key) => (
                    <Tab key={key} id={key}>
                        Tab {key}
                    </Tab>
                ))}
            </TabList>
            <TabPanels>

                <TabPanel key='one' id='one'>
                    <Box css={{ backgroundColor: "container", padding: "large" }}>
                        Tab panel {selectedKey}
                    </Box>
                </TabPanel>

                <TabPanel key='two' id='two'>
                    <Box css={{ backgroundColor: "container", padding: "large" }}>
                        <LoadContentOnDemand selectedKey={selectedKey} />
                    </Box>
                </TabPanel>

            </TabPanels>
        </Tabs>
        </ContextView>
    );

}

export default TabTest;

type LoadContentOnDemandProps = {
    selectedKey: React.Key
}

const LoadContentOnDemand = ({ selectedKey }: LoadContentOnDemandProps) => {
    const [loading, setLoading] = useState(true);

    const mockApiCall = useCallback(async () => {
        await new Promise((resolve) => setTimeout(resolve, 1000));

        setLoading(false);
    }, []);

    useEffect(() => {
        console.log(selectedKey) // $.0
        console.assert(typeof selectedKey === 'string' && selectedKey.includes('$.'), 'Selected Key does not mirror the index key')
        if (loading && selectedKey === "$.1") {   // This value of $.index is unexpected
            mockApiCall().catch(error => console.error(error));
        }
    }, [selectedKey]);

    if (loading) {
        return <Box css={{ stack: "y", textAlign: "center" }}><Spinner />
            Loading tab panel {selectedKey}...
        </Box>
    }

    return <Box css={{padding: "large" }}>Tab panel {selectedKey} loaded</Box>;

}

Result:

tab-test

image

bensontrent commented 2 weeks ago

The tab issue appears to be fixed:

image

Thanks Stripe team!