From c9c180070f08d9945d0f0d31536ec26071d7cd72 Mon Sep 17 00:00:00 2001 From: Robert Niznik Date: Thu, 29 Aug 2024 15:28:19 -0400 Subject: [PATCH] feat(components): add `Toolbar` and `Calendar` presets (#1326) * feat(components): add `Toolbar` and `Calendar` presets * chore: format * fix: biome * feat: add spacing variants * fix: version --- .changeset/beige-zebras-occur.md | 5 + package.json | 2 +- .../components/__tests__/Toolbar.spec.tsx | 24 +++++ packages/components/package.json | 2 +- packages/components/src/Calendar.tsx | 69 ++++++++++++- packages/components/src/Toolbar.tsx | 49 +++++++++ packages/components/src/index.ts | 6 ++ .../components/src/styles/Alert.module.css | 2 +- .../components/src/styles/Calendar.module.css | 13 +++ .../components/src/styles/Group.module.css | 4 +- .../components/src/styles/Menu.module.css | 6 +- .../components/src/styles/Modal.module.css | 10 +- .../components/src/styles/Popover.module.css | 10 +- .../src/styles/Separator.module.css | 13 ++- .../components/src/styles/Toast.module.css | 4 +- .../components/src/styles/Toolbar.module.css | 70 +++++++++++++ .../components/stories/Calendar.stories.tsx | 44 ++++++++- .../stories/RangeCalendar.stories.tsx | 71 ++++++++++++- .../components/stories/Toolbar.stories.tsx | 99 +++++++++++++++++++ packages/form/src/styles/Form.module.css | 4 +- .../progress-bubbles/src/ProgressBubbles.tsx | 1 - pnpm-lock.yaml | 82 +++++++-------- 22 files changed, 516 insertions(+), 74 deletions(-) create mode 100644 .changeset/beige-zebras-occur.md create mode 100644 packages/components/__tests__/Toolbar.spec.tsx create mode 100644 packages/components/src/Toolbar.tsx create mode 100644 packages/components/src/styles/Toolbar.module.css create mode 100644 packages/components/stories/Toolbar.stories.tsx diff --git a/.changeset/beige-zebras-occur.md b/.changeset/beige-zebras-occur.md new file mode 100644 index 000000000..9864fca2b --- /dev/null +++ b/.changeset/beige-zebras-occur.md @@ -0,0 +1,5 @@ +--- +"@launchpad-ui/components": patch +--- + +Add `Toolbar` and `Calendar` presets diff --git a/package.json b/package.json index 62315abc1..653759f06 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "homepage": "https://github.com/launchdarkly/launchpad-ui#readme", "devDependencies": { "@axe-core/playwright": "^4.10.0", - "@biomejs/biome": "1.8.1", + "@biomejs/biome": "1.8.3", "@changesets/changelog-github": "^0.5.0", "@changesets/cli": "^2.27.1", "@commitlint/cli": "^19.4.0", diff --git a/packages/components/__tests__/Toolbar.spec.tsx b/packages/components/__tests__/Toolbar.spec.tsx new file mode 100644 index 000000000..6b6c37e55 --- /dev/null +++ b/packages/components/__tests__/Toolbar.spec.tsx @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest'; + +import { render, screen } from '../../../test/utils'; +import { Button, Group, IconButton, Separator, Toolbar } from '../src'; + +describe('Toolbar', () => { + it('renders', () => { + render( + + + + + + + + + + + + , + ); + expect(screen.getByRole('toolbar')).toBeVisible(); + }); +}); diff --git a/packages/components/package.json b/packages/components/package.json index 4fb8798fb..55cc2578e 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -34,6 +34,7 @@ "test": "vitest run --coverage" }, "dependencies": { + "@internationalized/date": "3.5.5", "@launchpad-ui/icons": "workspace:~", "@launchpad-ui/tokens": "workspace:~", "@react-aria/toast": "3.0.0-beta.15", @@ -51,7 +52,6 @@ "react-dom": "18.3.1" }, "devDependencies": { - "@internationalized/date": "3.5.5", "react": "18.3.1", "react-dom": "18.3.1", "react-stately": "3.32.2" diff --git a/packages/components/src/Calendar.tsx b/packages/components/src/Calendar.tsx index 2e4c0f324..29af18a28 100644 --- a/packages/components/src/Calendar.tsx +++ b/packages/components/src/Calendar.tsx @@ -1,4 +1,6 @@ -import type { ForwardedRef } from 'react'; +import type { CalendarDate } from '@internationalized/date'; +import type { RangeValue } from '@react-types/shared'; +import type { ForwardedRef, HTMLAttributes } from 'react'; import type { CalendarCellProps, CalendarGridBodyProps, @@ -6,26 +8,39 @@ import type { CalendarGridProps, CalendarHeaderCellProps, CalendarProps, + DateRange, DateValue, RangeCalendarProps, } from 'react-aria-components'; +import type { ButtonProps } from './Button'; import { cva, cx } from 'class-variance-authority'; -import { forwardRef } from 'react'; +import { forwardRef, useState } from 'react'; import { Calendar as AriaCalendar, CalendarCell as AriaCalendarCell, RangeCalendar as AriaRangeCalendar, + ButtonContext, + CalendarContext, CalendarGrid, CalendarGridBody, CalendarGridHeader, CalendarHeaderCell, + Provider, + RangeCalendarContext, composeRenderProps, + useSlottedContext, } from 'react-aria-components'; -import { button } from './Button'; +import { Button, button } from './Button'; import styles from './styles/Calendar.module.css'; +interface CalendarPickerProps extends HTMLAttributes {} + +interface PresetProps extends Omit { + value: CalendarDate | RangeValue; +} + const calendar = cva(styles.calendar); const cell = cva(styles.cell); const range = cva(styles.range); @@ -93,6 +108,50 @@ const _RangeCalendar = ( */ const RangeCalendar = forwardRef(_RangeCalendar); +const _CalendarPicker = ( + { children, className, ...props }: CalendarPickerProps, + ref: ForwardedRef, +) => { + const [value, onChange] = useState(); + const [range, onChangeRange] = useState(); + const [focusedValue, onFocusChange] = useState(); + return ( + +
+ {children} +
+
+ ); +}; + +const CalendarPicker = forwardRef(_CalendarPicker); + +const _Preset = ({ value, ...props }: PresetProps, ref: ForwardedRef) => { + const context = useSlottedContext(CalendarContext); + const rangeContext = useSlottedContext(RangeCalendarContext); + const onPress = () => { + if ('start' in value) { + rangeContext?.onFocusChange?.(value.start); + rangeContext?.onChange?.(value); + } else { + context?.onFocusChange?.(value); + context?.onChange?.(value); + } + }; + return + + + + + + + + + + + ), + }, +}; + +export const Orientation: Story = { + args: { + children: ( + <> + + + + + + + + + ), + orientation: 'vertical', + spacing: 'compact', + }, +}; + +export const Compact: Story = { + args: { + children: ( + <> + + + + + + + + + ), + spacing: 'compact', + }, +}; + +export const Large: Story = { + args: { + children: ( + <> + + + + + + + + + ), + spacing: 'large', + }, +}; diff --git a/packages/form/src/styles/Form.module.css b/packages/form/src/styles/Form.module.css index f9cbaf741..e2ef5a5a4 100644 --- a/packages/form/src/styles/Form.module.css +++ b/packages/form/src/styles/Form.module.css @@ -440,7 +440,7 @@ input[type='checkbox']:disabled { background-color: var(--lp-color-bg-interactive-secondary-active); } - & span:has( svg) { + & span:has(svg) { width: 100%; color: var(--lp-color-text-ui-primary-base); } @@ -448,7 +448,7 @@ input[type='checkbox']:disabled { } &:hover, - &:has( input:focus) { + &:has(input:focus) { & .numberField-stepperContainer { opacity: 1; } diff --git a/packages/progress-bubbles/src/ProgressBubbles.tsx b/packages/progress-bubbles/src/ProgressBubbles.tsx index 845532185..3a6ae422f 100644 --- a/packages/progress-bubbles/src/ProgressBubbles.tsx +++ b/packages/progress-bubbles/src/ProgressBubbles.tsx @@ -57,7 +57,6 @@ const ProgressBubbles = ({ const hideLabel = showCurrentLabelOnly && idx !== currentBubble; const bubble = ( - // biome-ignore lint/correctness/useJsxKeyInIterable:
=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@1.8.1': - resolution: {integrity: sha512-XLiB7Uu6GALIOBWzQ2aMD0ru4Ly5/qSeQF7kk3AabzJ/kwsEWSe33iVySBP/SS2qv25cgqNiLksjGcw2bHT3mw==} + '@biomejs/cli-darwin-arm64@1.8.3': + resolution: {integrity: sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@1.8.1': - resolution: {integrity: sha512-uMTSxVLMfqkBVqyc25hSn83jBbp+wtWjzM/pHFlKXt3htJuw7FErVGW0nmQ9Sxa9vJ7GcqoltLMl28VQRIMYzg==} + '@biomejs/cli-darwin-x64@1.8.3': + resolution: {integrity: sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@1.8.1': - resolution: {integrity: sha512-UQ8Wc01J0wQL+5AYOc7qkJn20B4PZmQL1KrmDZh7ot0DvD6aX4+8mmfd/dG5b6Zjo/44QvCKcvkFGCMRYuhWZA==} + '@biomejs/cli-linux-arm64-musl@1.8.3': + resolution: {integrity: sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@1.8.1': - resolution: {integrity: sha512-3SzZRuC/9Oi2P2IBNPsEj0KXxSXUEYRR2kfRF/Ve8QAfGgrt4qnwuWd6QQKKN5R+oYH691qjm+cXBKEcrP1v/Q==} + '@biomejs/cli-linux-arm64@1.8.3': + resolution: {integrity: sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@1.8.1': - resolution: {integrity: sha512-fYbP/kNu/rtZ4kKzWVocIdqZOtBSUEg9qUhZaao3dy3CRzafR6u6KDtBeSCnt47O+iLnks1eOR1TUxzr5+QuqA==} + '@biomejs/cli-linux-x64-musl@1.8.3': + resolution: {integrity: sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@1.8.1': - resolution: {integrity: sha512-AeBycVdNrTzsyYKEOtR2R0Ph0hCD0sCshcp2aOnfGP0hCZbtFg09D0SdKLbyzKntisY41HxKVrydYiaApp+2uw==} + '@biomejs/cli-linux-x64@1.8.3': + resolution: {integrity: sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@1.8.1': - resolution: {integrity: sha512-6tEd1H/iFKpgpE3OIB7oNgW5XkjiVMzMRPL8zYoZ036YfuJ5nMYm9eB9H/y81+8Z76vL48fiYzMPotJwukGPqQ==} + '@biomejs/cli-win32-arm64@1.8.3': + resolution: {integrity: sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@1.8.1': - resolution: {integrity: sha512-g2H31jJzYmS4jkvl6TiyEjEX+Nv79a5km/xn+5DARTp5MBFzC9gwceusSSB2AkJKqZzY131AiACAWjKrVt5Ijw==} + '@biomejs/cli-win32-x64@1.8.3': + resolution: {integrity: sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -8752,39 +8752,39 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@biomejs/biome@1.8.1': + '@biomejs/biome@1.8.3': optionalDependencies: - '@biomejs/cli-darwin-arm64': 1.8.1 - '@biomejs/cli-darwin-x64': 1.8.1 - '@biomejs/cli-linux-arm64': 1.8.1 - '@biomejs/cli-linux-arm64-musl': 1.8.1 - '@biomejs/cli-linux-x64': 1.8.1 - '@biomejs/cli-linux-x64-musl': 1.8.1 - '@biomejs/cli-win32-arm64': 1.8.1 - '@biomejs/cli-win32-x64': 1.8.1 - - '@biomejs/cli-darwin-arm64@1.8.1': + '@biomejs/cli-darwin-arm64': 1.8.3 + '@biomejs/cli-darwin-x64': 1.8.3 + '@biomejs/cli-linux-arm64': 1.8.3 + '@biomejs/cli-linux-arm64-musl': 1.8.3 + '@biomejs/cli-linux-x64': 1.8.3 + '@biomejs/cli-linux-x64-musl': 1.8.3 + '@biomejs/cli-win32-arm64': 1.8.3 + '@biomejs/cli-win32-x64': 1.8.3 + + '@biomejs/cli-darwin-arm64@1.8.3': optional: true - '@biomejs/cli-darwin-x64@1.8.1': + '@biomejs/cli-darwin-x64@1.8.3': optional: true - '@biomejs/cli-linux-arm64-musl@1.8.1': + '@biomejs/cli-linux-arm64-musl@1.8.3': optional: true - '@biomejs/cli-linux-arm64@1.8.1': + '@biomejs/cli-linux-arm64@1.8.3': optional: true - '@biomejs/cli-linux-x64-musl@1.8.1': + '@biomejs/cli-linux-x64-musl@1.8.3': optional: true - '@biomejs/cli-linux-x64@1.8.1': + '@biomejs/cli-linux-x64@1.8.3': optional: true - '@biomejs/cli-win32-arm64@1.8.1': + '@biomejs/cli-win32-arm64@1.8.3': optional: true - '@biomejs/cli-win32-x64@1.8.1': + '@biomejs/cli-win32-x64@1.8.3': optional: true '@bundled-es-modules/deepmerge@4.3.1':