From aebcd07daf19c4070ffac829152ff9387125b013 Mon Sep 17 00:00:00 2001 From: El P Date: Fri, 15 Jul 2022 17:37:05 -0700 Subject: [PATCH] feat: Expander component (vertical tabs). Closes #33 --- docs/layout.md | 50 ++++++++++++++++++++++++++++++++++++++++ py/pkg/docs/layout.py | 41 +++++++++++++++++++++++++++++++++ web/src/expander.tsx | 53 +++++++++++++++++++++++++++++++++++++++++++ web/src/zone.tsx | 33 ++++++++++++++++++--------- 4 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 web/src/expander.tsx diff --git a/docs/layout.md b/docs/layout.md index 992061a8..6c67a18f 100644 --- a/docs/layout.md +++ b/docs/layout.md @@ -159,8 +159,58 @@ view( ![Screenshot](assets/screenshots/layout_tabs.png) +## Lay out in tabs vertically + +Set `layout='column'` to lay out tabs one below the other. + + +```py +view( + box( + mode='tabs', + layout='column', + items=[ + box( + 'Profile', + icon='Contact', + items=[ + box('First name', value='Boaty'), + box('Last name', value='McBoatface'), + box('Age', value=42) + ], + ), + box( + 'Billing Address', + icon='PaymentCard', + items=[ + box('Billing address line 1', value=''), + box('Billing address line 2', value=''), + row(box('City', value=''), box('State', value=''), box('Zip', value='')), + ], + ), + box( + 'Shipping Address', + icon='DeliveryTruck', + items=[ + box('Shipping address line 1', value=''), + box('Shipping address line 2', value=''), + row(box('City', value=''), box('State', value=''), box('Zip', value='')), + ], + ), + ] + ) +) +``` + + +![Screenshot](assets/screenshots/layout_tabs_vertical.png) + + ## Show icons on tabs +Set `icon=` on each tab to show an icon on the tab. + + ```py view( box( diff --git a/py/pkg/docs/layout.py b/py/pkg/docs/layout.py index 3c817826..472583ae 100644 --- a/py/pkg/docs/layout.py +++ b/py/pkg/docs/layout.py @@ -138,7 +138,48 @@ def layout_tabs(view: View): # height 5 ) +# ## Lay out in tabs vertically +# Set `layout='column'` to lay out tabs one below the other. +def layout_tabs_vertical(view: View): # height 5 + view( + box( + mode='tabs', + layout='column', + items=[ + box( + 'Profile', + icon='Contact', + items=[ + box('First name', value='Boaty'), + box('Last name', value='McBoatface'), + box('Age', value=42) + ], + ), + box( + 'Billing Address', + icon='PaymentCard', + items=[ + box('Billing address line 1', value=''), + box('Billing address line 2', value=''), + row(box('City', value=''), box('State', value=''), box('Zip', value='')), + ], + ), + box( + 'Shipping Address', + icon='DeliveryTruck', + items=[ + box('Shipping address line 1', value=''), + box('Shipping address line 2', value=''), + row(box('City', value=''), box('State', value=''), box('Zip', value='')), + ], + ), + ] + ) + ) + + # ## Show icons on tabs +# Set `icon=` on each tab to show an icon on the tab. def layout_tabs_icons(view: View): # height 5 view( box( diff --git a/web/src/expander.tsx b/web/src/expander.tsx new file mode 100644 index 00000000..5ca8b8ae --- /dev/null +++ b/web/src/expander.tsx @@ -0,0 +1,53 @@ +// Copyright 2022 H2O.ai, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ActionButton, IButtonStyles, IIconProps } from '@fluentui/react'; +import React from 'react'; +import styled from 'styled-components'; +import { S, signal } from './core'; +import { make } from './ui'; + +const + iconOpen: IIconProps = { iconName: 'ChevronDownMed' }, + iconClose: IIconProps = { iconName: 'ChevronRightMed' }, + bodyOpenStyle: React.CSSProperties = { display: 'block' }, + bodyCloseStyle: React.CSSProperties = { display: 'none' }, + buttonStyles: IButtonStyles = { root: { padding: 0 } } + +const + Body = styled.div` + padding: 0 0 10px 30px; + ` + +export const Expander = make(({ headerText, children }: { headerText: S, children: JSX.Element }) => { + const + expandedB = signal(false), + toggle = () => expandedB(!expandedB()), + render = () => { + const expanded = expandedB() + return ( +
+
+ {headerText} +
+ {children} +
+ ) + } + return { render, expandedB } +}) \ No newline at end of file diff --git a/web/src/zone.tsx b/web/src/zone.tsx index 0d856e2d..840e24c3 100644 --- a/web/src/zone.tsx +++ b/web/src/zone.tsx @@ -18,6 +18,7 @@ import styled from 'styled-components'; import { XBox } from './box'; import { ClientContext } from './client'; import { B, Dict, isS, S } from './core'; +import { Expander } from './expander'; import { Help } from './help'; import { ImageBlock } from './image'; import { Box } from './protocol'; @@ -202,7 +203,7 @@ const Container = styled.div` ` export const Zone = ({ context, box, inRow }: { context: ClientContext, box: Box, inRow: B }) => { const - { mode, items } = box, + { mode, items, layout } = box, isRow = mode === 'row', style = computeStyle(box, inRow) @@ -210,17 +211,27 @@ export const Zone = ({ context, box, inRow }: { context: ClientContext, box: Box switch (mode) { case 'tabs': { - const tabs = items.map((box, i) => ( - - - - )) - return ( - - {tabs} - - ) + if (layout === 'column') { + const tabs = items.map((box, i) => ( + + + + )) + return {tabs} + } else { + const tabs = items.map((box, i) => ( + + + + )) + return ( + + {tabs} + + ) + } } + break default: { const children = items.map(box => (