Skip to content
Merged
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
14 changes: 14 additions & 0 deletions packages/examples/accessibility-test/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Badge,
Breadcrumb, BreadcrumbItem, BreadcrumbLink,
Button,
ButtonGroup, ButtonGroupItem,
Card,
Checkbox, CheckboxControl, CheckboxLabel,
Clipboard, ClipboardControl, ClipboardTrigger,
Expand Down Expand Up @@ -249,6 +250,19 @@ function App(): ReactElement {
<Button color={ BUTTON_COLOR.warning } size="sm" variant={ BUTTON_VARIANT.outline }>Warning</Button>
</section>

<section>
<h1>Button Group</h1>

<ButtonGroup>
<ButtonGroupItem value="hourly">Hourly</ButtonGroupItem>
<ButtonGroupItem value="daily">Daily</ButtonGroupItem>
<ButtonGroupItem value="monthly">Monthly</ButtonGroupItem>
<ButtonGroupItem value="custom">
<Icon name={ ICON_NAME.calendar } /> Custom
</ButtonGroupItem>
</ButtonGroup>
</section>

<section>
<h1>Card</h1>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
core: {
disableTelemetry: true,
disableWhatsNewNotifications: true,
},
docs: {
autodocs: false,
},
framework: '@storybook/react-vite',
previewHead: (head) => `
${head}
<style>
html, body {
font-family: "Source Sans Pro", "Trebuchet MS", "Arial", "Segoe UI", sans-serif;
}
</style>
`,
stories: [
'../src/dev.stories.tsx',
'../tests/**/*.stories.tsx',
],
};

export default config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { addons } from '@storybook/manager-api';

addons.register('custom-panel', (api) => {
api.togglePanel(false);
});

addons.setConfig({
enableShortcuts: false,
showToolbar: true,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { type Preview } from '@storybook/react';
import '@ovhcloud/ods-themes/default/css';
import '@ovhcloud/ods-themes/default/fonts';

const preview: Preview = {
parameters: {},
};

export default preview;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const isCI = !!process.env.CI;

export default {
launch: {
headless: isCI,
slowMo: isCI ? 0 : 300,
product: 'chrome',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
"--disable-dev-shm-usage",
"--disable-accelerated-2d-canvas",
"--disable-gpu",
'--font-render-hinting=none',
],
},
};
26 changes: 26 additions & 0 deletions packages/ods-react/src/components/button-group/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const baseOption = {
collectCoverage: false,
testPathIgnorePatterns: [
'node_modules/',
'dist/',
],
testRegex: 'tests\\/.*\\.spec\\.(ts|tsx)$',
transform: {
'\\.(ts|tsx)$': 'ts-jest',
},
verbose: true,
};

export default !!process.env.E2E ?
{
...baseOption,
preset: 'jest-puppeteer',
testRegex: 'tests\\/.*\\.e2e\\.ts$',
testTimeout: 60000,
} : {
...baseOption,
transform: {
...baseOption.transform,
'\\.scss$': 'jest-transform-stub',
}
};
2 changes: 2 additions & 0 deletions packages/ods-react/src/components/button-group/modules.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare module '*.css';
declare module '*.scss';
23 changes: 23 additions & 0 deletions packages/ods-react/src/components/button-group/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@ovhcloud/ods-react-button-group",
"version": "19.3.0",
"private": true,
"description": "ODS React ButtonGroup component",
"type": "module",
"main": "dist/index.js",
"scripts": {
"clean": "rimraf documentation node_modules",
"doc": "npm run clean && npm run doc:ts && npm run doc:css",
"doc:css": "sass src/components:documentation --no-source-map --pkg-importer=node && node ../../../scripts/generate-component-token-list.js",
"doc:ts": "typedoc",
"lint:a11y": "eslint --config ../../../../../.eslintrc-a11y 'src/**/*.{js,ts,tsx}' --ignore-pattern '*.stories.tsx'",
"lint:scss": "stylelint --aei 'src/components/**/*.scss'",
"lint:ts": "eslint '{src,tests}/**/*.{js,ts,tsx}' --ignore-pattern '*.stories.tsx'",
"start": "npm run start:storybook",
"start:storybook": "storybook dev -p 3000 --no-open",
"test:e2e": "E2E=true start-server-and-test 'npm run start:storybook' 3000 'jest -i --detectOpenHandles'",
"test:e2e:ci": "CI=true npm run test:e2e",
"test:spec": "jest --passWithNoTests",
"test:spec:ci": "npm run test:spec"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ToggleGroup, useToggleGroupContext } from '@ark-ui/react/toggle-group';
import classNames from 'classnames';
import { type ComponentPropsWithRef, type FC, type JSX, forwardRef } from 'react';
import { BUTTON_COLOR, BUTTON_VARIANT, Button } from '../../../../button/src';
import { useButtonGroup } from '../../contexts/useButtonGroup';
import style from './buttonGroupItem.module.scss';

interface ButtonGroupItemProp extends ComponentPropsWithRef<'button'> {
/**
* Whether the component is disabled.
*/
disabled?: boolean;
/**
* The value of the item.
*/
value: string,
}

const ButtonGroupItem: FC<ButtonGroupItemProp> = forwardRef(({
children,
className,
disabled,
value,
...props
}, ref): JSX.Element => {
const { value: selection } = useToggleGroupContext();
const { size } = useButtonGroup();

return (
<ToggleGroup.Item
asChild
className={ classNames(style['button-group-item'], className) }
data-ods="button-group-item"
disabled={ disabled }
ref={ ref }
value={ value }
{ ...props }>
<Button
color={ BUTTON_COLOR.primary }
size={ size }
variant={ selection.indexOf(value) > -1 ? BUTTON_VARIANT.default : BUTTON_VARIANT.outline }>
{ children }
</Button>
</ToggleGroup.Item>
);
});

ButtonGroupItem.displayName = 'ButtonGroupItem';

export {
ButtonGroupItem,
type ButtonGroupItemProp,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
$ods-button-group-item-z-index: 1;

@layer ods-molecules {
.button-group-item {
--ods-button-group-item-background-color-checked-disabled: var(--ods-color-neutral-500);

z-index: $ods-button-group-item-z-index;

&:first-child {
margin-inline-start: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

&:not(:first-child) {
margin-inline-start: -1px;

&:not(:last-child) {
border-radius: 0;
}
}

&:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

&:hover,
&[data-focus],
&[data-state="on"] {
z-index: $ods-button-group-item-z-index + 1;
}

&[data-state="on"] {
&:not([data-disabled]) {
border-color: var(--ods-theme-background-color-selected);
background-color: var(--ods-theme-background-color-selected);
}

&[data-disabled] {
border-color: var(--ods-button-group-item-background-color-checked-disabled);
background-color: var(--ods-button-group-item-background-color-checked-disabled);
color: var(--ods-button-text-color-primary);
}
}

&[data-disabled] {
z-index: $ods-button-group-item-z-index - 1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ToggleGroup } from '@ark-ui/react/toggle-group';
import classNames from 'classnames';
import { type FC, type JSX, forwardRef } from 'react';
import { ButtonGroupProvider, type ButtonGroupRootProp } from '../../contexts/useButtonGroup';
import style from './buttonGroup.module.scss';

interface ButtonGroupProp extends ButtonGroupRootProp {}

const ButtonGroup: FC<ButtonGroupProp> = forwardRef(({
children,
className,
defaultValue,
disabled,
multiple,
onValueChange,
size,
value,
...props
}, ref): JSX.Element => {
return (
<ButtonGroupProvider size={ size }>
<ToggleGroup.Root
className={ classNames(style['button-group'], className) }
data-ods="button-group"
defaultValue={ defaultValue }
disabled={ disabled }
multiple={ multiple }
onValueChange={ onValueChange }
ref={ ref }
value={ value }
{ ...props }>
{ children }
</ToggleGroup.Root>
</ButtonGroupProvider>
);
});

ButtonGroup.displayName = 'ButtonGroup';

export {
ButtonGroup,
type ButtonGroupProp,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@layer ods-molecules {
.button-group {
display: flex;
flex-direction: row;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { BUTTON_SIZE, BUTTON_SIZES, type ButtonSize } from '../../../button/src';

export {
BUTTON_SIZE as BUTTON_GROUP_SIZE,
BUTTON_SIZES as BUTTON_GROUP_SIZES,
type ButtonSize as ButtonGroupSize,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { type ComponentPropsWithRef, type JSX, type ReactNode, createContext, useContext } from 'react';
import { type ButtonGroupSize } from '../constants/button-group-size';

interface ButtonGroupValueChangeDetail {
value: string[],
}

type ButtonGroupRootProp = ComponentPropsWithRef<'div'> & {
/**
* The initial value of the selected items. Use when you don't need to control the value of the component.
*/
defaultValue?: string[];
/**
* Whether the component is disabled.
*/
disabled?: boolean;
/**
* Whether multiple items can be selected at the same time.
*/
multiple?: boolean;
/**
* Callback fired when the selection changes.
*/
onValueChange?: (detail: ButtonGroupValueChangeDetail) => void;
/**
* The size preset to use.
*/
size?: ButtonGroupSize,
/**
* The controlled value of the selected items.
*/
value?: string[];
};

interface ButtonGroupProviderProp extends ButtonGroupRootProp {
children: ReactNode;
}

type ButtonGroupContextType = Omit<ButtonGroupProviderProp, 'children'>;

const ButtonGroupContext = createContext<ButtonGroupContextType | undefined>(undefined);

const ButtonGroupProvider = ({
children,
size,
}: ButtonGroupProviderProp): JSX.Element => {
return (
<ButtonGroupContext.Provider value={{
size,
}}>
{ children }
</ButtonGroupContext.Provider>
);
};

function useButtonGroup(): ButtonGroupContextType {
const context = useContext(ButtonGroupContext);

if (!context) {
throw new Error('useButtonGroup must be used within a ButtonGroupProvider');
}

return context;
}

export {
ButtonGroupProvider,
type ButtonGroupRootProp,
type ButtonGroupValueChangeDetail,
useButtonGroup,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.custom-button-group {

}
Loading