From eb4886fdecc37914dcc43a685f39435359b393c8 Mon Sep 17 00:00:00 2001 From: Gregory Douglas <2968519+ggdouglas@users.noreply.github.com> Date: Fri, 13 Sep 2024 22:09:20 -0400 Subject: [PATCH 1/3] Add box component --- packages/core/src/common/classes.ts | 2 + packages/core/src/components/_index.scss | 1 + .../src/components/box/_box-variables.scss | 104 ++++ packages/core/src/components/box/_box.scss | 446 ++++++++++++++++++ packages/core/src/components/box/box.tsx | 19 + packages/core/src/components/box/boxProps.ts | 240 ++++++++++ .../core/src/components/box/buildStyles.ts | 261 ++++++++++ packages/core/src/components/index.ts | 2 + packages/demo-app/src/examples/BoxExample.tsx | 19 + packages/demo-app/src/examples/Examples.tsx | 2 + 10 files changed, 1096 insertions(+) create mode 100644 packages/core/src/components/box/_box-variables.scss create mode 100644 packages/core/src/components/box/_box.scss create mode 100644 packages/core/src/components/box/box.tsx create mode 100644 packages/core/src/components/box/boxProps.ts create mode 100644 packages/core/src/components/box/buildStyles.ts create mode 100644 packages/demo-app/src/examples/BoxExample.tsx diff --git a/packages/core/src/common/classes.ts b/packages/core/src/common/classes.ts index 4998736d6ca..ce8863c8db1 100644 --- a/packages/core/src/common/classes.ts +++ b/packages/core/src/common/classes.ts @@ -98,6 +98,8 @@ export const ALERT_BODY = `${ALERT}-body`; export const ALERT_CONTENTS = `${ALERT}-contents`; export const ALERT_FOOTER = `${ALERT}-footer`; +export const BOX = `${NS}-box`; + export const BREADCRUMB = `${NS}-breadcrumb`; export const BREADCRUMB_CURRENT = `${BREADCRUMB}-current`; export const BREADCRUMBS = `${BREADCRUMB}s`; diff --git a/packages/core/src/components/_index.scss b/packages/core/src/components/_index.scss index 368d842ef9f..f714e1a0457 100644 --- a/packages/core/src/components/_index.scss +++ b/packages/core/src/components/_index.scss @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. @import "alert/alert"; +@import "box/box"; @import "breadcrumbs/breadcrumbs"; @import "button/button"; @import "button/button-group"; diff --git a/packages/core/src/components/box/_box-variables.scss b/packages/core/src/components/box/_box-variables.scss new file mode 100644 index 00000000000..06a08f82585 --- /dev/null +++ b/packages/core/src/components/box/_box-variables.scss @@ -0,0 +1,104 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ +@import "../../common/variables"; + +$space-unit: calc($pt-grid-size / 2); + +$relative-sizes: ( + "25": 25%, + "50": 50%, + "75": 75%, + "100": 100%, + "auto": auto, +); + +$colors: ( + "black": $black, + "dark-gray-1": $dark-gray1, + "dark-gray-2": $dark-gray2, + "dark-gray-3": $dark-gray3, + "dark-gray-4": $dark-gray4, + "dark-gray-5": $dark-gray5, + "gray-1": $gray1, + "gray-2": $gray2, + "gray-3": $gray3, + "gray-4": $gray4, + "gray-5": $gray5, + "light-gray-1": $light-gray1, + "light-gray-2": $light-gray2, + "light-gray-3": $light-gray3, + "light-gray-4": $light-gray4, + "light-gray-5": $light-gray5, + "white": $white, + "blue-1": $blue1, + "blue-2": $blue2, + "blue-3": $blue3, + "blue-4": $blue4, + "blue-5": $blue5, + "green-1": $green1, + "green-2": $green2, + "green-3": $green3, + "green-4": $green4, + "green-5": $green5, + "orange-1": $orange1, + "orange-2": $orange2, + "orange-3": $orange3, + "orange-4": $orange4, + "orange-5": $orange5, + "red-1": $red1, + "red-2": $red2, + "red-3": $red3, + "red-4": $red4, + "red-5": $red5, + "cerulean-1": $cerulean1, + "cerulean-2": $cerulean2, + "cerulean-3": $cerulean3, + "cerulean-4": $cerulean4, + "cerulean-5": $cerulean5, + "forest-1": $forest1, + "forest-2": $forest2, + "forest-3": $forest3, + "forest-4": $forest4, + "forest-5": $forest5, + "gold-1": $gold1, + "gold-2": $gold2, + "gold-3": $gold3, + "gold-4": $gold4, + "gold-5": $gold5, + "indigo-1": $indigo1, + "indigo-2": $indigo2, + "indigo-3": $indigo3, + "indigo-4": $indigo4, + "indigo-5": $indigo5, + "lime-1": $lime1, + "lime-2": $lime2, + "lime-3": $lime3, + "lime-4": $lime4, + "lime-5": $lime5, + "rose-1": $rose1, + "rose-2": $rose2, + "rose-3": $rose3, + "rose-4": $rose4, + "rose-5": $rose5, + "sepia-1": $sepia1, + "sepia-2": $sepia2, + "sepia-3": $sepia3, + "sepia-4": $sepia4, + "sepia-5": $sepia5, + "turquoise-1": $turquoise1, + "turquoise-2": $turquoise2, + "turquoise-3": $turquoise3, + "turquoise-4": $turquoise4, + "turquoise-5": $turquoise5, + "vermilion-1": $vermilion1, + "vermilion-2": $vermilion2, + "vermilion-3": $vermilion3, + "vermilion-4": $vermilion4, + "vermilion-5": $vermilion5, + "violet-1": $violet1, + "violet-2": $violet2, + "violet-3": $violet3, + "violet-4": $violet4, + "violet-5": $violet5, +); diff --git a/packages/core/src/components/box/_box.scss b/packages/core/src/components/box/_box.scss new file mode 100644 index 00000000000..04b9f6fe454 --- /dev/null +++ b/packages/core/src/components/box/_box.scss @@ -0,0 +1,446 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ + +@import "./box-variables"; + +.#{$ns}-box { + @for $i from 0 through 10 { + $value: $space-unit * $i; + + &.gap-#{$i} { + gap: $value; + } + + &.margin-#{$i} { + margin: $value; + } + + &.margin-x-#{$i} { + margin-left: $value; + margin-right: $value; + } + + &.margin-y-#{$i} { + margin-bottom: $value; + margin-top: $value; + } + + &.margin-top-#{$i} { + margin-top: $value; + } + + &.margin-right-#{$i} { + margin-right: $value; + } + + &.margin-bottom-#{$i} { + margin-bottom: $value; + } + + &.margin-left-#{$i} { + margin-left: $value; + } + + &.padding-#{$i} { + padding: $value; + } + + &.padding-x-#{$i} { + padding-left: $value; + padding-right: $value; + } + + &.padding-y-#{$i} { + padding-bottom: $value; + padding-top: $value; + } + + &.padding-top-#{$i} { + padding-top: $value; + } + + &.padding-right-#{$i} { + padding-right: $value; + } + + &.padding-bottom-#{$i} { + padding-bottom: $value; + } + + &.padding-left-#{$i} { + padding-left: $value; + } + + &.top-#{$i} { + top: $value; + } + + &.right-#{$i} { + right: $value; + } + + &.bottom-#{$i} { + bottom: $value; + } + + &.left-#{$i} { + left: $value; + } + } + + &.margin-auto { + margin: auto; + } + + &.margin-x-auto { + margin-left: auto; + margin-right: auto; + } + + &.margin-y-auto { + margin-bottom: auto; + margin-top: auto; + } + + &.margin-top-auto { + margin-top: auto; + } + + &.margin-right-auto { + margin-right: auto; + } + + &.margin-bottom-auto { + margin-bottom: auto; + } + + &.margin-left-auto { + margin-left: auto; + } + + // colors + @each $name, $value in $colors { + &.#{$name} { + color: $value; + } + + &.bg-#{$name} { + background-color: $value; + } + } + + // width & height + @each $name, $size in $relative-sizes { + &.width-#{$name} { + width: $size; + } + + &.height-#{$name} { + height: $size; + } + } + + // align-content + &.content-start { + align-content: flex-start; + } + + &.content-end { + align-content: flex-end; + } + + &.content-center { + align-content: center; + } + + &.content-between { + align-content: space-between; + } + + &.content-around { + align-content: space-around; + } + + &.content-evenly { + align-content: space-evenly; + } + + &.content-normal { + align-content: normal; + } + + &.content-baseline { + align-content: baseline; + } + + &.content-stretch { + align-content: stretch; + } + + // align-items + &.items-start { + align-items: flex-start; + } + + &.items-end { + align-items: flex-end; + } + + &.items-center { + align-items: center; + } + + &.items-baseline { + align-items: baseline; + } + + &.items-stretch { + align-items: stretch; + } + + // align-self + &.self-auto { + align-self: auto; + } + + &.self-start { + align-self: flex-start; + } + + &.self-end { + align-self: flex-end; + } + + &.self-center { + align-self: center; + } + + &.self-baseline { + align-self: stretch; + } + + &.self-stretch { + align-self: baseline; + } + + // display + &.block { + display: block; + } + + &.inline-block { + display: inline-block; + } + + &.inline { + display: inline; + } + + &.flex { + display: flex; + } + + &.inline-flex { + display: inline-flex; + } + + &.grid { + display: grid; + } + + &.inline-grid { + display: inline-grid; + } + + &.table { + display: table; + } + + &.inline-table { + display: inline-table; + } + + &.table-row-group { + display: table-row-group; + } + + &.table-header-group { + display: table-header-group; + } + + &.table-footer-group { + display: table-footer-group; + } + + &.table-row { + display: table-row; + } + + &.table-cell { + display: table-cell; + } + + &.table-column { + display: table-column; + } + + &.table-column-group { + display: table-column-group; + } + + &.table-caption { + display: table-caption; + } + + &.list-item { + display: list-item; + } + + &.contents { + display: contents; + } + + &.none { + display: none; + } + + // flex + &.flex-1 { + flex: 1 1 0%; + } + + &.flex-auto { + flex: 1 1 auto; + } + + &.flex-initial { + flex: 0 1 auto; + } + + &.flex-none { + flex: none; + } + + // flex-direction + &.flex-row { + flex-direction: row; + } + + &.flex-row-reverse { + flex-direction: row-reverse; + } + + &.flex-column { + flex-direction: column; + } + + &.flex-column-reverse { + flex-direction: column-reverse; + } + + // flex-wrap + &.flex-nowrap { + flex-wrap: nowrap; + } + + &.flex-wrap { + flex-wrap: wrap; + } + + &.flex-wrap-reverse { + flex-wrap: wrap-reverse; + } + + // justify-content + &.justify-start { + justify-content: flex-start; + } + + &.justify-end { + justify-content: flex-end; + } + + &.justify-center { + justify-content: center; + } + + &.justify-between { + justify-content: space-between; + } + + &.justify-around { + justify-content: space-around; + } + + &.justify-evenly { + justify-content: space-evenly; + } + + &.justify-normal { + justify-content: normal; + } + + &.justify-stretch { + justify-content: stretch; + } + + // justify-items + &.justify-items-start { + justify-items: start; + } + + &.justify-items-end { + justify-items: end; + } + + &.justify-items-center { + justify-items: center; + } + + &.justify-items-stretch { + justify-items: stretch; + } + + // justify-self + &.justify-self-auto { + justify-self: auto; + } + + &.justify-self-start { + justify-self: start; + } + + &.justify-self-end { + justify-self: end; + } + + &.justify-self-center { + justify-self: center; + } + + &.justify-self-stretch { + justify-self: stretch; + } + + // position + &.static { + position: static; + } + + &.fixed { + position: fixed; + } + + &.absolute { + position: absolute; + } + + &.relative { + position: relative; + } + + &.sticky { + position: sticky; + } +} diff --git a/packages/core/src/components/box/box.tsx b/packages/core/src/components/box/box.tsx new file mode 100644 index 00000000000..7f32aee526a --- /dev/null +++ b/packages/core/src/components/box/box.tsx @@ -0,0 +1,19 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ + +import classNames from "classnames"; +import React from "react"; + +import { Classes, DISPLAYNAME_PREFIX } from "../../common"; + +import type { BoxProps } from "./boxProps"; +import { buildStyles } from "./buildStyles"; + +export const Box = ({ as, className, ...props }: BoxProps) => { + const Component = as ?? "div"; + const { generatedClassNames, passThroughProps } = React.useMemo(() => buildStyles(props), [props]); + return ; +}; + +Box.displayName = `${DISPLAYNAME_PREFIX}.Box`; diff --git a/packages/core/src/components/box/boxProps.ts b/packages/core/src/components/box/boxProps.ts new file mode 100644 index 00000000000..f44beabdc59 --- /dev/null +++ b/packages/core/src/components/box/boxProps.ts @@ -0,0 +1,240 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ + +import type * as React from "react"; + +type SpacingRange = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; +type SizeRange = 25 | 50 | 75 | 100; + +export const ColorMap = { + // gray scale + BLACK: "black", + + DARK_GRAY1: "dark-gray-1", + DARK_GRAY2: "dark-gray-2", + DARK_GRAY3: "dark-gray-3", + DARK_GRAY4: "dark-gray-4", + DARK_GRAY5: "dark-gray-5", + + GRAY1: "gray-1", + GRAY2: "gray-2", + GRAY3: "gray-3", + GRAY4: "gray-4", + GRAY5: "gray-5", + + LIGHT_GRAY1: "light-gray-1", + LIGHT_GRAY2: "light-gray-2", + LIGHT_GRAY3: "light-gray-3", + LIGHT_GRAY4: "light-gray-4", + LIGHT_GRAY5: "light-gray-5", + + WHITE: "white", + + // core colors + BLUE1: "blue-1", + BLUE2: "blue-2", + BLUE3: "blue-3", + BLUE4: "blue-4", + BLUE5: "blue-5", + + GREEN1: "green-1", + GREEN2: "green-2", + GREEN3: "green-3", + GREEN4: "green-4", + GREEN5: "green-5", + + ORANGE1: "orange-1", + ORANGE2: "orange-2", + ORANGE3: "orange-3", + ORANGE4: "orange-4", + ORANGE5: "orange-5", + + RED1: "red-1", + RED2: "red-2", + RED3: "red-3", + RED4: "red-4", + RED5: "red-5", + + CERULEAN1: "cerulean-1", + CERULEAN2: "cerulean-2", + CERULEAN3: "cerulean-3", + CERULEAN4: "cerulean-4", + CERULEAN5: "cerulean-5", + + FOREST1: "forest-1", + FOREST2: "forest-2", + FOREST3: "forest-3", + FOREST4: "forest-4", + FOREST5: "forest-5", + + GOLD1: "gold-1", + GOLD2: "gold-2", + GOLD3: "gold-3", + GOLD4: "gold-4", + GOLD5: "gold-5", + + INDIGO1: "indigo-1", + INDIGO2: "indigo-2", + INDIGO3: "indigo-3", + INDIGO4: "indigo-4", + INDIGO5: "indigo-5", + + LIME1: "lime-1", + LIME2: "lime-2", + LIME3: "lime-3", + LIME4: "lime-4", + LIME5: "lime-5", + + ROSE1: "rose-1", + ROSE2: "rose-2", + ROSE3: "rose-3", + ROSE4: "rose-4", + ROSE5: "rose-5", + + SEPIA1: "sepia-1", + SEPIA2: "sepia-2", + SEPIA3: "sepia-3", + SEPIA4: "sepia-4", + SEPIA5: "sepia-5", + + TURQUOISE1: "turquoise-1", + TURQUOISE2: "turquoise-2", + TURQUOISE3: "turquoise-3", + TURQUOISE4: "turquoise-4", + TURQUOISE5: "turquoise-5", + + VERMILION1: "vermilion-1", + VERMILION2: "vermilion-2", + VERMILION3: "vermilion-3", + VERMILION4: "vermilion-4", + VERMILION5: "vermilion-5", + + VIOLET1: "violet-1", + VIOLET2: "violet-2", + VIOLET3: "violet-3", + VIOLET4: "violet-4", + VIOLET5: "violet-5", +} as const; + +export type Color = (typeof ColorMap)[keyof typeof ColorMap]; + +export type Gap = SpacingRange | `${SpacingRange}`; + +export type Margin = SpacingRange | `${SpacingRange}` | "auto"; + +export type Padding = SpacingRange | `${SpacingRange}`; + +export type Width = SizeRange | `${SizeRange}` | "auto"; + +export type Height = SizeRange | `${SizeRange}` | "auto"; + +export type Top = SpacingRange | `${SpacingRange}`; + +export type Right = SpacingRange | `${SpacingRange}`; + +export type Bottom = SpacingRange | `${SpacingRange}`; + +export type Left = SpacingRange | `${SpacingRange}`; + +export type AlignContent = + | "start" + | "end" + | "center" + | "between" + | "around" + | "evenly" + | "normal" + | "baseline" + | "stretch"; + +export type AlignItems = "start" | "end" | "center" | "baseline" | "stretch"; + +export type AlignSelf = "auto" | "start" | "end" | "center" | "baseline" | "stretch"; + +export type Display = + | "block" + | "inline-block" + | "inline" + | "flex" + | "inline-flex" + | "grid" + | "inline-grid" + | "table" + | "inline-table" + | "table-row-group" + | "table-header-group" + | "table-footer-group" + | "table-row" + | "table-cell" + | "table-column" + | "table-column-group" + | "table-caption" + | "list-item" + | "contents" + | "none"; + +export type Flex = 1 | "1" | "auto" | "initial" | "none"; + +export type FlexDirection = "row" | "row-reverse" | "column" | "column-reverse"; + +export type FlexWrap = "nowrap" | "wrap" | "wrap-reverse"; + +export type JustifyContent = "start" | "end" | "center" | "between" | "around" | "evenly" | "normal" | "stretch"; + +export type JustifyItems = "start" | "end" | "center" | "stretch"; + +export type JustifySelf = "auto" | "start" | "end" | "center" | "stretch"; + +export type Position = "static" | "absolute" | "relative" | "fixed" | "sticky"; + +export interface BoxOwnProps { + color?: Color; + bg?: Color; + + gap?: Gap; + + m?: Margin; + mt?: Margin; + mr?: Margin; + mb?: Margin; + ml?: Margin; + mx?: Margin; + my?: Margin; + + p?: Padding; + pt?: Padding; + pr?: Padding; + pb?: Padding; + pl?: Padding; + px?: Padding; + py?: Padding; + + w?: Width; + h?: Height; + + top?: Top; + right?: Right; + bottom?: Bottom; + left?: Left; + + alignContent?: AlignContent; + alignItems?: AlignItems; + alignSelf?: AlignSelf; + display?: Display; + flex?: Flex; + flexDirection?: FlexDirection; + flexWrap?: FlexWrap; + justifyContent?: JustifyContent; + justifyItems?: JustifyItems; + justifySelf?: JustifySelf; + position?: Position; +} + +export type AsProp = { + as?: T; +}; + +export type BoxProps = BoxOwnProps & + AsProp & + Omit, keyof BoxOwnProps>; diff --git a/packages/core/src/components/box/buildStyles.ts b/packages/core/src/components/box/buildStyles.ts new file mode 100644 index 00000000000..3576b54c5a5 --- /dev/null +++ b/packages/core/src/components/box/buildStyles.ts @@ -0,0 +1,261 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ + +/* tslint:disable:object-literal-sort-keys */ + +import { + type AlignContent, + type AlignItems, + type AlignSelf, + type Bottom, + type Color, + ColorMap, + type Display, + type Flex, + type FlexDirection, + type FlexWrap, + type Gap, + type Height, + type JustifyContent, + type JustifyItems, + type JustifySelf, + type Left, + type Margin, + type Padding, + type Position, + type Right, + type Top, + type Width, +} from "./boxProps"; + +function appendValue(prefix: string) { + return (value: T) => `${prefix}-${value}`; +} + +function mapping(styleMap: Record) { + return (value: T) => styleMap[value]; +} + +function identity(value: T) { + return value; +} + +const bgColorMap: Record = Object.fromEntries( + Object.values(ColorMap).map(color => [color, `bg-${color}`]), +); +const bg = mapping(bgColorMap); + +const gap = appendValue("gap"); + +const margin = appendValue("margin"); +const marginX = appendValue("margin-x"); +const marginY = appendValue("margin-y"); +const marginStart = appendValue("margin-start"); +const marginEnd = appendValue("margin-end"); +const marginTop = appendValue("margin-top"); +const marginRight = appendValue("margin-right"); +const marginBottom = appendValue("margin-bottom"); +const marginLeft = appendValue("margin-left"); + +const padding = appendValue("padding"); +const paddingX = appendValue("padding-x"); +const paddingY = appendValue("padding-y"); +const paddingStart = appendValue("padding-start"); +const paddingEnd = appendValue("padding-end"); +const paddingTop = appendValue("padding-top"); +const paddingRight = appendValue("padding-right"); +const paddingBottom = appendValue("padding-bottom"); +const paddingLeft = appendValue("padding-left"); + +const width = mapping({ + 25: "width-25", + 50: "width-50", + 75: "width-75", + 100: "width-100", + auto: "width-auto", +}); + +const height = mapping({ + 25: "height-25", + 50: "height-50", + 75: "height-75", + 100: "height-100", + auto: "height-auto", +}); + +const top = appendValue("top"); +const right = appendValue("right"); +const bottom = appendValue("bottom"); +const left = appendValue("left"); + +const alignContent = mapping({ + start: "content-start", + end: "content-end", + center: "content-center", + between: "content-between", + around: "content-around", + evenly: "content-evenly", + normal: "content-normal", + baseline: "content-baseline", + stretch: "content-stretch", +}); + +const alignItems = mapping({ + start: "items-start", + end: "items-end", + center: "items-center", + baseline: "items-baseline", + stretch: "items-stretch", +}); + +const alignSelf = mapping({ + auto: "self-auto", + start: "self-start", + end: "self-end", + center: "self-center", + baseline: "self-baseline", + stretch: "self-stretch", +}); + +const display = mapping({ + block: "block", + "inline-block": "inline-block", + inline: "inline", + flex: "flex", + "inline-flex": "inline-flex", + grid: "grid", + "inline-grid": "inline-grid", + table: "table", + "inline-table": "inline-table", + "table-row-group": "table-row-group", + "table-header-group": "table-header-group", + "table-footer-group": "table-footer-group", + "table-row": "table-row", + "table-cell": "table-cell", + "table-column": "table-column", + "table-column-group": "table-column-group", + "table-caption": "table-caption", + "list-item": "list-item", + contents: "contents", + none: "none", +}); + +const flex = mapping({ + "1": "flex-1", + auto: "flex-auto", + initial: "flex-initial", + none: "flex-none", +}); + +const flexDirection = mapping({ + row: "flex-row", + "row-reverse": "flex-row-reverse", + column: "flex-column", + "column-reverse": "flex-column-reverse", +}); + +const flexWrap = mapping({ + nowrap: "flex-nowrap", + wrap: "flex-wrap", + "wrap-reverse": "flex-wrap-reverse", +}); + +const justifyContent = mapping({ + start: "justify-start", + end: "justify-end", + center: "justify-center", + between: "justify-between", + around: "justify-around", + evenly: "justify-evenly", + normal: "justify-normal", + stretch: "justify-stretch", +}); + +const justifyItems = mapping({ + start: "justify-items-start", + end: "justify-items-end", + center: "justify-items-center", + stretch: "justify-items-stretch", +}); + +const justifySelf = mapping({ + auto: "justify-self-auto", + start: "justify-self-start", + end: "justify-self-end", + center: "justify-self-center", + stretch: "justify-self-stretch", +}); + +const position = mapping({ + static: "static", + relative: "relative", + absolute: "absolute", + fixed: "fixed", + sticky: "sticky", +}); + +const styles: Record string> = { + color: identity, + bg, + + gap, + + m: margin, + mx: marginX, + my: marginY, + ms: marginStart, + me: marginEnd, + mt: marginTop, + mr: marginRight, + mb: marginBottom, + ml: marginLeft, + + p: padding, + px: paddingX, + py: paddingY, + ps: paddingStart, + pe: paddingEnd, + pt: paddingTop, + pr: paddingRight, + pb: paddingBottom, + pl: paddingLeft, + + w: width, + h: height, + + top, + right, + bottom, + left, + + alignContent, + alignItems, + alignSelf, + display, + flex, + flexDirection, + flexWrap, + justifyContent, + justifyItems, + justifySelf, + position, +}; + +export function buildStyles>(props: T) { + const classNames = new Set(); + const passThroughProps: Record = {}; + + for (const [key, value] of Object.entries(props)) { + if (Object.prototype.hasOwnProperty.call(styles, key)) { + const className = styles[key]?.(value); + if (className != null) { + classNames.add(className); + } + } else { + passThroughProps[key] = value; + } + } + + return { generatedClassNames: Array.from(classNames), passThroughProps }; +} diff --git a/packages/core/src/components/index.ts b/packages/core/src/components/index.ts index 57e197446c0..f41a14b35e4 100644 --- a/packages/core/src/components/index.ts +++ b/packages/core/src/components/index.ts @@ -17,6 +17,8 @@ export { Alert, type AlertProps } from "./alert/alert"; export { Breadcrumb, type BreadcrumbProps } from "./breadcrumbs/breadcrumb"; export { Breadcrumbs, type BreadcrumbsProps } from "./breadcrumbs/breadcrumbs"; +export { Box } from "./box/box"; +export type { BoxProps } from "./box/boxProps"; export { AnchorButton, Button } from "./button/buttons"; export type { AnchorButtonProps, diff --git a/packages/demo-app/src/examples/BoxExample.tsx b/packages/demo-app/src/examples/BoxExample.tsx new file mode 100644 index 00000000000..55ef8ceeb5a --- /dev/null +++ b/packages/demo-app/src/examples/BoxExample.tsx @@ -0,0 +1,19 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ + +import * as React from "react"; + +import { Box } from "@blueprintjs/core"; + +import { ExampleCard } from "./ExampleCard"; + +export function BoxExample() { + return ( + + + BOX + + + ); +} diff --git a/packages/demo-app/src/examples/Examples.tsx b/packages/demo-app/src/examples/Examples.tsx index 2da61638c75..cac7bd7f585 100644 --- a/packages/demo-app/src/examples/Examples.tsx +++ b/packages/demo-app/src/examples/Examples.tsx @@ -19,6 +19,7 @@ import * as React from "react"; import { Classes } from "@blueprintjs/core"; +import { BoxExample } from "./BoxExample"; import { BreadcrumbExample } from "./BreadcrumbExample"; import { ButtonExample } from "./ButtonExample"; import { ButtonGroupExample } from "./ButtonGroupExample"; @@ -51,6 +52,7 @@ export class Examples extends React.PureComponent { private renderExamples(className?: string) { return (
+ From a8e88cf2873cf8100638876f7e88460389e89e0d Mon Sep 17 00:00:00 2001 From: Gregory Douglas <2968519+ggdouglas@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:41:11 -0400 Subject: [PATCH 2/3] Update ExampleCard to use Box --- .../demo-app/src/examples/ExampleCard.tsx | 23 ++++++++++--------- packages/demo-app/src/styles/_examples.scss | 17 -------------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/packages/demo-app/src/examples/ExampleCard.tsx b/packages/demo-app/src/examples/ExampleCard.tsx index 201fc271fea..b7a779057d7 100644 --- a/packages/demo-app/src/examples/ExampleCard.tsx +++ b/packages/demo-app/src/examples/ExampleCard.tsx @@ -14,10 +14,9 @@ * limitations under the License. */ -import classNames from "classnames"; import * as React from "react"; -import { Card, H5 } from "@blueprintjs/core"; +import { Box, Card, H5 } from "@blueprintjs/core"; export interface ExampleCardProps { children: React.ReactNode; @@ -31,17 +30,19 @@ const DEFAULT_WIDTH = 500; export class ExampleCard extends React.PureComponent { public render() { - const { width = DEFAULT_WIDTH } = this.props; + const { children, horizontal, label, subLabel, width = DEFAULT_WIDTH } = this.props; return (
-
{this.props.label}
- {this.props.subLabel ??
{this.props.subLabel}
} - - {this.props.children} +
{label}
+ {subLabel && ( + + {subLabel} + + )} + + + {children} +
); diff --git a/packages/demo-app/src/styles/_examples.scss b/packages/demo-app/src/styles/_examples.scss index 1378442d3b6..e282be88424 100644 --- a/packages/demo-app/src/styles/_examples.scss +++ b/packages/demo-app/src/styles/_examples.scss @@ -52,23 +52,6 @@ $dark-intent-danger-text: $red5; .example-card { background-color: $content-background-color; - display: flex; - flex-direction: column; - margin-bottom: 10px; - - > :not(:last-child) { - margin-bottom: 10px; - } - - &.horizontal { - flex-direction: row; - justify-content: center; - - > :not(:last-child) { - margin-bottom: 0; - margin-right: 10px; - } - } } .tag-container { From 1a40c7ec5aa6ebdc735cb73a23280da9ee100155 Mon Sep 17 00:00:00 2001 From: Gregory Douglas <2968519+ggdouglas@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:03:15 -0400 Subject: [PATCH 3/3] Add tests for Box --- packages/core/test/box/boxTests.tsx | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/core/test/box/boxTests.tsx diff --git a/packages/core/test/box/boxTests.tsx b/packages/core/test/box/boxTests.tsx new file mode 100644 index 00000000000..659381b6250 --- /dev/null +++ b/packages/core/test/box/boxTests.tsx @@ -0,0 +1,46 @@ +/* ! + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + */ + +import { render, screen } from "@testing-library/react"; +import { expect } from "chai"; +import * as React from "react"; + +import { Box } from "../../src"; + +describe("", () => { + it("renders content", () => { + render(Test); + expect(screen.getByText("Test")).to.exist; + }); + + it("renders as another element", () => { + render(Test); + expect(screen.getByText("Test").tagName).to.equal("SPAN"); + }); + + it("passes through props", () => { + render(Test); + expect(screen.getByTestId("foo")).to.exist; + }); + + it("supports className", () => { + render(Test); + expect(screen.getByText("Test").className).to.include("foo"); + }); + + it("supports style", () => { + render(Test); + expect(screen.getByText("Test").style.color).to.equal("red"); + }); + + it("supports display", () => { + render(Test); + expect(screen.getByText("Test").className).to.include("flex"); + }); + + it("supports margin", () => { + render(Test); + expect(screen.getByText("Test").className).to.include("margin-2"); + }); +});