Skip to content

Commit

Permalink
Add initial CarouselPagination
Browse files Browse the repository at this point in the history
  • Loading branch information
connor-baer committed Sep 6, 2024
1 parent 04a7016 commit d919d77
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Meta, Status, Props, Story } from '../../../../.storybook/components';
import * as Stories from './CarouselPagination.stories';

<Meta of={Stories} />

# CarouselPagination

<Status variant="stable" />

<Story of={Stories.Base} />
<Props />

- colors
- size ([minimum tap target size](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html): 24px)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.base {
display: flex;
list-style-type: none;
}

.cue {
display: block;
padding: var(--cui-spacings-byte);
background: none;
border: none;
border-radius: var(--cui-border-radius-pill);
}

a.cue,
button.cue {
cursor: pointer;
}

.shape {
display: block;
width: var(--cui-spacings-kilo);
height: var(--cui-spacings-kilo);
background-color: var(--cui-bg-highlight);
border-radius: var(--cui-border-radius-pill);
transition:
background-color var(--cui-transitions-default),
width var(--cui-transitions-default);
}

a.cue:hover .shape,
button.cue:hover .shape {
background-color: var(--cui-bg-highlight-hovered);
}

a.cue:active .shape,
button.cue:active .shape {
background-color: var(--cui-bg-highlight-pressed);
}

.cue[aria-current] .shape {
width: var(--cui-spacings-peta);
background-color: var(--cui-bg-strong);
}

a.cue[aria-current]:hover .shape,
button.cue[aria-current]:hover .shape {
background-color: var(--cui-bg-strong-hovered);
}

a.cue[aria-current]:active .shape,
button.cue[aria-current]:active .shape {
background-color: var(--cui-bg-strong-pressed);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright 2024, SumUp Ltd.
* 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 { describe, it } from 'vitest';

describe('CarouselPagination', () => {
it.todo('should render as button');
it.todo('should render as links');
it.todo('should mark the current active item');
it.todo('should mark the current active item with the type');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Copyright 2024, SumUp Ltd.
* 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 { useState } from 'react';

import {
CarouselPagination,
type CarouselPaginationProps,
} from './CarouselPagination.js';

export default {
title: 'Components/Carousel/CarouselPagination',
component: CarouselPagination,
};

const baseArgs = {
items: [
{ id: 'foo', label: 'Foo' },
{ id: 'bar', label: 'Bar' },
{ id: 'baz', label: 'Baz' },
],
currentId: 'foo',
};

export const Base = (args: CarouselPaginationProps) => {
const [currentId, setCurrentId] = useState(args.currentId);

const items = args.items.map((item) => ({
...item,
onClick: () => {
setCurrentId(item.id);
},
}));

return <CarouselPagination {...args} items={items} currentId={currentId} />;
};

Base.args = baseArgs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Copyright 2024, SumUp Ltd.
* 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.
*/

'use client';

import {
forwardRef,
type AnchorHTMLAttributes,
type ButtonHTMLAttributes,
type HTMLAttributes,
} from 'react';

import { useComponents } from '../ComponentsContext/useComponents.js';
import type { AsPropType } from '../../types/prop-types.js';
import { utilClasses } from '../../styles/utility.js';
import { clsx } from '../../styles/clsx.js';

import classes from './CarouselPagination.module.css';

type LinkElProps = AnchorHTMLAttributes<HTMLAnchorElement>;
type ButtonElProps = ButtonHTMLAttributes<HTMLButtonElement>;

export type Items = LinkElProps &
ButtonElProps & {
/**
* TODO:
*/
id: string | number;
/**
* TODO:
*/
label: string;
};

export interface CarouselPaginationProps
extends HTMLAttributes<HTMLUListElement> {
/**
* TODO:
*/
items: Items[];
/**
* TODO: same as item id
*/
currentId: string | number;
/**
* TODO:
*/
type?: 'page' | 'step';
}

export const CarouselPagination = forwardRef<
HTMLUListElement,
CarouselPaginationProps
>(({ items, currentId, type }, ref) => {
const components = useComponents();
const Link = components.Link as AsPropType;

return (
// eslint-disable-next-line jsx-a11y/no-redundant-roles
<ul ref={ref} className={classes.base} role="list">
{items.map(({ id, label, ...item }) => {
let Element: AsPropType;
if (item.href) {
Element = Link;
} else if (item.onClick) {
Element = 'button';
} else {
Element = 'span';
}
return (
<li key={id}>
<Element
{...item}
aria-current={currentId === id ? type || true : undefined}
className={clsx(classes.cue, utilClasses.focusVisibleInset)}
>
<span className={classes.shape} />
<span className={utilClasses.hideVisually}>{label}</span>
</Element>
</li>
);
})}
</ul>
);
});
18 changes: 18 additions & 0 deletions packages/circuit-ui/components/CarouselPagination/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright 2024, SumUp Ltd.
* 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.
*/

export { CarouselPagination } from './CarouselPagination.js';

export type { CarouselPaginationProps } from './CarouselPagination.js';
2 changes: 2 additions & 0 deletions packages/circuit-ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ export {
CarouselComposer,
} from './components/Carousel/index.js';
export type { CarouselProps } from './components/Carousel/index.js';
export { CarouselPagination } from './components/CarouselPagination/index.js';
export type { CarouselPaginationProps } from './components/CarouselPagination/index.js';
export { Avatar } from './components/Avatar/index.js';
export type { AvatarProps } from './components/Avatar/index.js';

Expand Down

0 comments on commit d919d77

Please sign in to comment.