addons/components/Panels.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {ReactNode} from 'react';
b69ab319import type {ColumnAlignmentProps} from './Flex';
b69ab3110
b69ab3111import * as stylex from '@stylexjs/stylex';
b69ab3112import {Column, Row} from './Flex';
b69ab3113import {spacing} from './theme/tokens.stylex';
b69ab3114
b69ab3115const styles = stylex.create({
b69ab3116 tabList: {
b69ab3117 padding: '4px',
b69ab3118 paddingBottom: spacing.pad,
b69ab3119 gap: '32px',
b69ab3120 },
b69ab3121 tab: {
b69ab3122 color: {
b69ab3123 default: 'var(--panel-tab-foreground)',
b69ab3124 ':hover': 'var(--panel-tab-active-foreground)',
b69ab3125 },
b69ab3126 padding: '4px 0',
b69ab3127 backgroundColor: 'transparent',
b69ab3128 border: 'none',
b69ab3129 cursor: 'pointer',
b69ab3130 borderBottom: '1px solid transparent',
b69ab3131 },
b69ab3132 activeTab: {
b69ab3133 borderBottom: '1px solid var(--panel-tab-active-foreground)',
b69ab3134 color: 'var(--panel-tab-active-foreground)',
b69ab3135 },
b69ab3136 tabpanel: {
b69ab3137 padding: '0 6px 10px 6px',
b69ab3138 },
b69ab3139 spaceBetween: {
b69ab3140 justifyContent: 'space-between',
b69ab3141 },
b69ab3142});
b69ab3143
b69ab3144export type PanelInfo = {render: () => ReactNode; label: ReactNode};
b69ab3145export function Panels<T extends string>({
b69ab3146 panels,
b69ab3147 xstyle,
b69ab3148 tabXstyle,
b69ab3149 tabListXstyle,
b69ab3150 alignmentProps,
b69ab3151 active,
b69ab3152 onSelect,
b69ab3153 tabListOptionalComponent,
b69ab3154}: {
b69ab3155 panels: Record<T, PanelInfo>;
b69ab3156 xstyle?: stylex.StyleXStyles;
b69ab3157 tabXstyle?: stylex.StyleXStyles;
b69ab3158 tabListXstyle?: stylex.StyleXStyles;
b69ab3159 alignmentProps?: ColumnAlignmentProps;
b69ab3160 active: T;
b69ab3161 onSelect: (item: T) => void;
b69ab3162 tabListOptionalComponent?: ReactNode;
b69ab3163}) {
b69ab3164 return (
b69ab3165 <Column xstyle={xstyle} {...(alignmentProps ?? {alignStart: true})}>
b69ab3166 <Row xstyle={[styles.tabList, styles.spaceBetween, tabListXstyle]} role="tablist">
b69ab3167 <Row>
b69ab3168 {(Object.entries(panels) as Array<[T, PanelInfo]>).map(([name, value]) => {
b69ab3169 return (
b69ab3170 <button
b69ab3171 role="tab"
b69ab3172 aria-selected={active === name}
b69ab3173 key={name}
b69ab3174 onClick={() => onSelect(name)}
b69ab3175 {...stylex.props(styles.tab, active === name && styles.activeTab, tabXstyle)}>
b69ab3176 {value.label}
b69ab3177 </button>
b69ab3178 );
b69ab3179 })}
b69ab3180 </Row>
b69ab3181 {tabListOptionalComponent}
b69ab3182 </Row>
b69ab3183 <div role="tabpanel" {...stylex.props(styles.tabpanel)}>
b69ab3184 {panels[active]?.render()}
b69ab3185 </div>
b69ab3186 </Column>
b69ab3187 );
b69ab3188}