Skip to content

Commit

Permalink
Carousel: Initial skeleton and spec (microsoft#31184)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mitch-At-Work authored and miroslavstastny committed Jun 14, 2024
1 parent f2bb42c commit 4e43bb8
Show file tree
Hide file tree
Showing 100 changed files with 1,903 additions and 1 deletion.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ packages/react-components/react-teaching-popover @microsoft/xc-uxe @Mitch-At-Wor
packages/react-components/react-timepicker-compat @microsoft/teams-prg
packages/react-components/react-icons-compat @microsoft/cxe-red @tomi-msft
packages/react-components/react-tag-picker-preview @microsoft/teams-prg
packages/react-components/react-carousel-preview @microsoft/xc-uxe @Mitch-At-Work
# <%= NX-CODEOWNER-PLACEHOLDER %>

## Components
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../../.babelrc-v9.json",
"plugins": ["annotate-pure-calls", "@babel/transform-react-pure-annotations"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["plugin:@fluentui/eslint-plugin/react"],
"root": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const rootMain = require('../../../../.storybook/main');

module.exports = /** @type {Omit<import('../../../../.storybook/main'), 'typescript'|'babel'>} */ ({
...rootMain,
stories: [...rootMain.stories, '../stories/**/*.stories.mdx', '../stories/**/index.stories.@(ts|tsx)'],
addons: [...rootMain.addons],
webpackFinal: (config, options) => {
const localConfig = { ...rootMain.webpackFinal(config, options) };

// add your own webpack tweaks if needed

return localConfig;
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as rootPreview from '../../../../.storybook/preview';

/** @type {typeof rootPreview.decorators} */
export const decorators = [...rootPreview.decorators];

/** @type {typeof rootPreview.parameters} */
export const parameters = { ...rootPreview.parameters };
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "",
"allowJs": true,
"checkJs": true,
"types": ["static-assets", "environment", "storybook__addons"]
},
"include": ["../stories/**/*.stories.ts", "../stories/**/*.stories.tsx", "*.js"]
}
30 changes: 30 additions & 0 deletions packages/react-components/react-carousel-preview/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"exclude": [
"/testing",
"/**/*.cy.ts",
"/**/*.cy.tsx",
"/**/*.spec.ts",
"/**/*.spec.tsx",
"/**/*.test.ts",
"/**/*.test.tsx"
],
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": false,
"dynamicImport": false
},
"externalHelpers": true,
"transform": {
"react": {
"runtime": "classic",
"useSpread": true
}
},
"target": "es2019"
},
"minify": false,
"sourceMaps": true
}
15 changes: 15 additions & 0 deletions packages/react-components/react-carousel-preview/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@fluentui/react-carousel-preview

Copyright (c) Microsoft Corporation

All rights reserved.

MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license
5 changes: 5 additions & 0 deletions packages/react-components/react-carousel-preview/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# @fluentui/react-carousel-preview

**React Carousel components for [Fluent UI React](https://react.fluentui.dev/)**

These are not production-ready components and **should never be used in product**. This space is useful for testing new components whose APIs might change before final release.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"extends": "@fluentui/scripts-api-extractor/api-extractor.common.v-next.json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/** Jest test setup file. */
102 changes: 102 additions & 0 deletions packages/react-components/react-carousel-preview/docs/Spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# @fluentui/react-carousel-preview Spec

## Background

Carousel enables users to wrap content in 'cards' that can then be paginated via previous/next or page index navigation buttons.

## Prior Art

_Include background research done for this component_

- [OpenUI Research - Carousel](https://open-ui.org/components/carousel.research/)
- [Fluent V9 - Task: Carousel](https://github.com/microsoft/fluentui/issues/26647)

## Sample Code

```jsx
<Carousel defaultValue="test-0">
<CarouselCard value="test-0">
<div>This is card: 1</div>
</CarouselCard>

<CarouselCard value="test-1">
<div>This is card: 2</div>
</CarouselCard>

<CarouselCard value="test-3">
<div>This is card: 3</div>
</CarouselCard>

<CarouselFooter showAutoplay>
<CarouselNav>{() => <CarouselNavButton />}</CarouselNav>
</CarouselFooter>
</Carousel>
```

## Variants

### Card Peeking

When peeking is enabled, the previous and next card will be partially displayed on either side of the current active card.

### Condensed Navigation

The CarouselFooter can be condensed, this will center all controls with minimal padding.

### Inline vs Composed Navigation

The CarouselFooter contains all navigation components in an inline horizontal container, however we have multiple valid layouts of the CarouselNavigation. If disconnected variants are required (such as prev/next buttons being overlaid in a different place than footer), then the individual navigation components can be placed within the Carousel wrapper in a variety of layouts.

## API

The core driver of the API will be context provided via the Carousel component, CarouselCards will register themselves via this context, and the Navigation components will subscribe to any updates that occur. The Carousel itself will only re-render on active index change.

Since the navigation has multiple valid layout formats, navigation components will be available individually to move around, or combined into slots via CarouselFooter within a single horizontal container.

Carousel provides callbacks on navigation changes, as well as the ability to drive pagination externally via a controlled index.

Users **must** provide a value on each carouselCard, and a defaultValue that the carousel will initiate on.

Motion can be enabled for next/previous button shift.

A gap prop will be provided to place spacing between cards.

## Behaviors

### Carousel

Carousel is the context wrapper and container for all carousel content/controls, it has no direct style or slot opinions. Carousel also provides API interfaces for callbacks that will occur on navigation events.

### CarouselAutoplayButton

If the carousel is on auto-play, the user may opt into pausing the auto-play feature via the CarouselAutoplayButton which must be present for auto-play to be enabled (if CarouselAutoplayButton present, auto-play will default to true on mount).

### CarouselButton

A default navigation button that will set value to the next/previous page, driven by it's type 'next' or 'previous'.

### CarouselCard

The defining wrapper of a carousel's indexed content, they will take up the full viewport of Carousel wrapper (with consideration for gap and peeking variants), users may place multiple items within this Card if desired, with consideration of viewport width.

Clickable actions within the content area are available via mouse and tab as expected, non-active index content will be set to inert until moved to active card.

### CarouselFooter

A unified navigation footer with all Carousel navigation components as slots, with the CarouselNav intended to be placed within the root children. The footer will have variant layouts that are condensed or extended, as well as options to null out slots if not required or placed externally.

### CarouselNav

Used to jump to a card based on index, using arrow navigation via Tabster. The children of this component will be wrapped in a context to provide the appropriate value based on their index position.

### CarouselNavButton

The child element of CarouselNav, a singular button that will set the carousels active index on click.

### CarouselNavImageButton

A variant child element of CarouselNav, a singular image button that displays a preview of card content and will set the carousels active index on click.

### Other

Interactive content is expected to be available in logical tab order within DOM, including when a user may place navigation components via absolute positioning (i.e. when overlaid on Carousel content).
Loading

0 comments on commit 4e43bb8

Please sign in to comment.