Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,21 @@ describe('<ToggleButton />', () => {
expect(onClick).toHaveBeenCalledTimes(1)
})
})

describe('margin prop', () => {
it('forwards margin to the button, resolving spacing tokens', () => {
render(
<ToggleButton
screenReaderLabel="label"
renderIcon={icon}
renderTooltipContent="tip"
status="unpressed"
margin="general.spaceMd"
/>
)
const button = screen.getByRole('button')

expect(getComputedStyle(button).marginTop).toEqual('0.75rem')
})
})
})
2 changes: 2 additions & 0 deletions packages/ui-buttons/src/ToggleButton/v2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class ToggleButton extends Component<ToggleButtonProps, ToggleButtonState> {
status,
placement,
onClick,
margin,
...props
} = this.props

Expand Down Expand Up @@ -124,6 +125,7 @@ class ToggleButton extends Component<ToggleButtonProps, ToggleButtonState> {
aria-pressed={status === 'pressed'}
data-cid="ToggleButton"
renderIcon={renderIcon}
margin={margin}
/>
</Tooltip>
)
Expand Down
9 changes: 9 additions & 0 deletions packages/ui-buttons/src/ToggleButton/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import type {
} from '@instructure/ui-position'
import type { ViewProps } from '@instructure/ui-view/latest'
import { Renderable } from '@instructure/shared-types'
import type { Spacing } from '@instructure/emotion'

type ToggleButtonOwnProps = {
/**
Expand Down Expand Up @@ -110,6 +111,13 @@ type ToggleButtonOwnProps = {
* or a function returning an element.
*/
constrain?: PositionConstraint

/**
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
}

type PropKeys = keyof ToggleButtonOwnProps
Expand All @@ -129,6 +137,7 @@ const allowedProps: AllowedPropKeys = [
'elementRef',
'interaction',
'isShowingTooltip',
'margin',
'mountNode',
'onClick',
'placement',
Expand Down
24 changes: 24 additions & 0 deletions packages/ui-checkbox/src/Checkbox/__tests__/Checkbox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,28 @@ describe('<Checkbox />', () => {
expect(input).not.toHaveAttribute('aria-labelledby')
})
})

describe('margin prop', () => {
it('resolves spacing tokens, custom CSS values, and shorthand', () => {
const { container } = render(
<div>
<Checkbox label="A" value="a" margin="general.spaceMd" />
<Checkbox label="B" value="b" margin="30px" />
<Checkbox label="C" value="c" margin="general.spaceLg auto" />
</div>
)
const boxes = container.querySelectorAll("[class$='-checkbox']")

const token = getComputedStyle(boxes[0]!)
expect(token.marginTop).toEqual('0.75rem') // general.spaceMd
expect(token.marginLeft).toEqual('0.75rem')

const custom = getComputedStyle(boxes[1]!)
expect(custom.marginTop).toEqual('30px')

const shorthand = getComputedStyle(boxes[2]!)
expect(shorthand.marginTop).toEqual('1rem') // general.spaceLg
expect(shorthand.marginRight).toEqual('auto')
})
})
})
13 changes: 12 additions & 1 deletion packages/ui-checkbox/src/Checkbox/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@

import type { FormMessage } from '@instructure/ui-form-field/latest'
import type { OtherHTMLAttributes } from '@instructure/shared-types'
import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
import type {
WithStyleProps,
ComponentStyle,
Spacing
} from '@instructure/emotion'
import type { NewComponentTypes } from '@instructure/ui-themes'
import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'

Expand Down Expand Up @@ -71,6 +75,12 @@ type CheckboxOwnProps = {
inline?: boolean
labelPlacement?: 'top' | 'start' | 'end'
isRequired?: boolean
/**
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
/**
* A function that provides a reference to the actual underlying input element
*/
Expand Down Expand Up @@ -116,6 +126,7 @@ const allowedProps: AllowedPropKeys = [
'inline',
'labelPlacement',
'isRequired',
'margin',
'inputRef'
]

Expand Down
13 changes: 10 additions & 3 deletions packages/ui-checkbox/src/Checkbox/v2/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
*/

import type { CheckboxProps, CheckboxStyle } from './props'
import type { NewComponentTypes } from '@instructure/ui-themes'
import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes'
import { calcSpacingFromShorthand } from '@instructure/emotion'

/**
* ---
Expand All @@ -38,9 +39,10 @@ import type { NewComponentTypes } from '@instructure/ui-themes'
*/
const generateStyle = (
componentTheme: ReturnType<NewComponentTypes['Checkbox']>,
props: CheckboxProps
props: CheckboxProps,
sharedTokens: SharedTokens
): CheckboxStyle => {
const { inline, size, variant } = props
const { inline, size, variant, margin } = props

// toggleFullWidth calculation based on Toggle facade width (1.625rem * 1.5) and the marginInlineEnd (0.75rem)
const toggleFullWidth = `calc(1.625rem * 1.5 + 0.75rem)`
Expand Down Expand Up @@ -82,6 +84,11 @@ const generateStyle = (
label: 'checkbox',
position: 'relative',
width: '100%',
// Resolves spacing tokens (or custom CSS values) into a margin shorthand.
margin: calcSpacingFromShorthand(margin, {
...sharedTokens.spacing,
...sharedTokens.legacy.spacing
}),
...(inline && {
display: 'inline-block',
verticalAlign: 'middle',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,13 @@ describe('<CheckboxGroup />', () => {
expect(group).not.toHaveAttribute('aria-invalid')
})
})

describe('margin prop', () => {
it('forwards margin to the field layout, resolving spacing tokens', () => {
const { container } = renderCheckboxGroup({ margin: 'general.spaceMd' })
const layout = container.querySelector("[class$='-formFieldLayout']")

expect(getComputedStyle(layout!).marginTop).toEqual('0.75rem')
})
})
})
1 change: 1 addition & 0 deletions packages/ui-checkbox/src/CheckboxGroup/v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type: example
---
<FormFieldGroup description={<ScreenReaderContent>CheckboxGroup examples</ScreenReaderContent>}>
<CheckboxGroup name="sports"
margin="general.spaceMd 0"
onChange={function (value) { console.log(value) }}
defaultValue={['football', 'volleyball']}
description="Select your favorite sports"
Expand Down
10 changes: 9 additions & 1 deletion packages/ui-checkbox/src/CheckboxGroup/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { type InputHTMLAttributes } from 'react'
import type { FormMessage } from '@instructure/ui-form-field/latest'
import type { OtherHTMLAttributes } from '@instructure/shared-types'
import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'
import type { Spacing } from '@instructure/emotion'

import { Checkbox } from '../../Checkbox/v2/index.js'
import type { CheckboxProps } from '../../Checkbox/v2/props'
Expand All @@ -44,6 +45,12 @@ type CheckboxGroupOwnProps = {
messages?: FormMessage[]
size?: 'small' | 'medium' | 'large'
layout?: 'stacked' | 'columns' | 'inline'
/**
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
}

type PropKeys = keyof CheckboxGroupOwnProps
Expand All @@ -67,7 +74,8 @@ const allowedProps: AllowedPropKeys = [
'messages',
'children',
'size',
'layout'
'layout',
'margin'
]

type CheckboxGroupState = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,19 @@ describe('<FormFieldGroup />', () => {

expect(axeCheck).toBe(true)
})

describe('margin prop', () => {
it('forwards margin to the field layout, resolving spacing tokens', () => {
const { container } = render(
<FormFieldGroup description="Name" margin="general.spaceMd">
<label>
First: <input />
</label>
</FormFieldGroup>
)
const layout = container.querySelector("[class$='-formFieldLayout']")

expect(getComputedStyle(layout!).marginTop).toEqual('0.75rem')
})
})
})
1 change: 1 addition & 0 deletions packages/ui-form-field/src/FormFieldGroup/v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type: example
rowSpacing="small"
layout="inline"
vAlign="middle"
margin="general.spaceMd 0"
>
<TextInput renderLabel="Favorite Breakfast Eatery"
messages={[
Expand Down
13 changes: 12 additions & 1 deletion packages/ui-form-field/src/FormFieldGroup/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import type {
AsElementType,
OtherHTMLAttributes
} from '@instructure/shared-types'
import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
import type {
WithStyleProps,
ComponentStyle,
Spacing
} from '@instructure/emotion'
import type { FormFieldLayoutOwnProps } from '../../FormFieldLayout/v2/props'
import type { FormMessage } from '../../utils/v1/FormPropTypes'

Expand Down Expand Up @@ -62,6 +66,12 @@ type FormFieldGroupOwnProps = {
colSpacing?: 'none' | 'small' | 'medium' | 'large'
vAlign?: 'top' | 'middle' | 'bottom'
startAt?: 'small' | 'medium' | 'large' | 'x-large' | null
/**
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
/**
* provides a reference to the underlying html root element
*/
Expand Down Expand Up @@ -96,6 +106,7 @@ const allowedProps: AllowedPropKeys = [
'colSpacing',
'vAlign',
'startAt',
'margin',
'elementRef'
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,4 +305,33 @@ describe('<RadioInput />', () => {
expect(axeCheck).toBe(true)
})
})

describe('margin prop', () => {
it('resolves spacing tokens, custom CSS values, and shorthand', () => {
const { container } = render(
<div>
<RadioInput label="A" value="a" name="n" margin="general.spaceMd" />
<RadioInput label="B" value="b" name="n" margin="30px" />
<RadioInput
label="C"
value="c"
name="n"
margin="general.spaceLg auto"
/>
</div>
)
const inputs = container.querySelectorAll("[class$='-radioInput']")

const token = getComputedStyle(inputs[0]!)
expect(token.marginTop).toEqual('0.75rem') // general.spaceMd
expect(token.marginLeft).toEqual('0.75rem')

const custom = getComputedStyle(inputs[1]!)
expect(custom.marginTop).toEqual('30px')

const shorthand = getComputedStyle(inputs[2]!)
expect(shorthand.marginTop).toEqual('1rem') // general.spaceLg
expect(shorthand.marginRight).toEqual('auto')
})
})
})
4 changes: 3 additions & 1 deletion packages/ui-radio-input/src/RadioInput/v2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const RadioInput = forwardRef<RadioInputHandle, RadioInputProps>(
inline = false,
context = 'success',
readOnly = false,
margin,
id: idProp,
label,
value,
Expand Down Expand Up @@ -100,7 +101,8 @@ const RadioInput = forwardRef<RadioInputHandle, RadioInputProps>(
hovered,
readOnly,
size,
variant
variant,
margin
},
componentId: 'RadioInput',
displayName: 'RadioInput'
Expand Down
13 changes: 12 additions & 1 deletion packages/ui-radio-input/src/RadioInput/v2/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@
import React from 'react'
import type { InputHTMLAttributes } from 'react'
import type { OtherHTMLAttributes } from '@instructure/shared-types'
import type { ComponentStyle, NewThemeOverrideProp } from '@instructure/emotion'
import type {
ComponentStyle,
NewThemeOverrideProp,
Spacing
} from '@instructure/emotion'
import type { WithDeterministicIdProps } from '@instructure/ui-react-utils'
import type { NewComponentTypes } from '@instructure/ui-themes'

Expand Down Expand Up @@ -77,6 +81,12 @@ type RadioInputOwnProps = {
* Sets the `display:inline-flex` in CSS
*/
inline?: boolean
/**
* Valid values are `0`, `none`, `auto`, and Spacing token values,
* see https://instructure.design/layout-spacing. Apply these values via
* familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`.
*/
margin?: Spacing
onClick?: (event: React.MouseEvent<HTMLInputElement>) => void
/**
* Callback fired when the input fires a change event.
Expand Down Expand Up @@ -118,6 +128,7 @@ const allowedProps: AllowedPropKeys = [
'size',
'context',
'inline',
'margin',
'onClick',
'onChange',
'inputRef'
Expand Down
Loading
Loading