From 1ccd1d920662a08056ba765af2d13dd1187fc211 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 10 Dec 2024 16:31:52 +0000 Subject: [PATCH] Improve styling + add Table components Signed-off-by: Charles de Dreuille --- packages/canon/.storybook/preview.tsx | 9 +- .../canon/src/components/Button/styles.css | 2 +- .../canon/src/components/Checkbox/styles.css | 2 +- packages/canon/src/components/Table/Docs.mdx | 5 + packages/canon/src/components/Table/Table.tsx | 93 ++++++++ .../Table/stories/Table.stories.tsx | 32 +++ .../Table/stories/TableBody.stories.tsx | 30 +++ .../Table/stories/TableCaption.stories.tsx | 30 +++ .../Table/stories/TableCell.stories.tsx | 30 +++ .../Table/stories/TableFooter.stories.tsx | 30 +++ .../Table/stories/TableHead.stories.tsx | 30 +++ .../Table/stories/TableHeader.stories.tsx | 30 +++ .../Table/stories/TableRow.stories.tsx | 30 +++ .../canon/src/components/Table/styles.css | 11 + .../{theme/theme.css => css/backstage.css} | 45 ++-- .../{theme/styles.css => css/components.css} | 8 +- packages/canon/src/css/normalize.css | 201 ++++++++++++++++++ 17 files changed, 592 insertions(+), 26 deletions(-) create mode 100644 packages/canon/src/components/Table/Docs.mdx create mode 100644 packages/canon/src/components/Table/Table.tsx create mode 100644 packages/canon/src/components/Table/stories/Table.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableBody.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableCaption.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableCell.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableFooter.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableHead.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableHeader.stories.tsx create mode 100644 packages/canon/src/components/Table/stories/TableRow.stories.tsx create mode 100644 packages/canon/src/components/Table/styles.css rename packages/canon/src/{theme/theme.css => css/backstage.css} (73%) rename packages/canon/src/{theme/styles.css => css/components.css} (77%) create mode 100644 packages/canon/src/css/normalize.css diff --git a/packages/canon/.storybook/preview.tsx b/packages/canon/.storybook/preview.tsx index 8beeb82720..906434e4f7 100644 --- a/packages/canon/.storybook/preview.tsx +++ b/packages/canon/.storybook/preview.tsx @@ -6,7 +6,9 @@ import { withThemeByDataAttribute } from '@storybook/addon-themes'; import '../docs/components/styles.css'; // Canon specific styles -import '../src/theme/styles.css'; + +import '../src/css/backstage.css'; +import '../src/css/components.css'; // Custom themes import './themes/backstage.css'; @@ -22,6 +24,11 @@ const preview: Preview = { backgrounds: { disable: true, }, + options: { + storySort: { + method: 'alphabetical', + }, + }, }, decorators: [ withThemeByDataAttribute({ diff --git a/packages/canon/src/components/Button/styles.css b/packages/canon/src/components/Button/styles.css index aaf1cae8bf..355a759c80 100644 --- a/packages/canon/src/components/Button/styles.css +++ b/packages/canon/src/components/Button/styles.css @@ -22,7 +22,7 @@ user-select: none; font-family: var(--canon-font-regular); font-weight: var(--canon-font-bold); - font-size: var(--canon-font-sizes-md); + font-size: var(--canon-font-size-md); padding: 0; transition: all 150ms ease; cursor: pointer; diff --git a/packages/canon/src/components/Checkbox/styles.css b/packages/canon/src/components/Checkbox/styles.css index fb7e0d0ab7..4c382863c2 100644 --- a/packages/canon/src/components/Checkbox/styles.css +++ b/packages/canon/src/components/Checkbox/styles.css @@ -4,7 +4,7 @@ align-items: center; justify-content: center; gap: var(--canon-spacing-xs); - font-size: var(--canon-font-sizes-xs); + font-size: var(--canon-font-size-xs); font-family: var(--canon-font-regular); color: var(--canon-text-primary); diff --git a/packages/canon/src/components/Table/Docs.mdx b/packages/canon/src/components/Table/Docs.mdx new file mode 100644 index 0000000000..6a6e9c8a59 --- /dev/null +++ b/packages/canon/src/components/Table/Docs.mdx @@ -0,0 +1,5 @@ +import { Meta, Controls } from '@storybook/blocks'; + + + +# Table diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/canon/src/components/Table/Table.tsx new file mode 100644 index 0000000000..887b2a6216 --- /dev/null +++ b/packages/canon/src/components/Table/Table.tsx @@ -0,0 +1,93 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 * as React from 'react'; + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)); +Table.displayName = 'Table'; + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableHeader.displayName = 'TableHeader'; + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableBody.displayName = 'TableBody'; + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableFooter.displayName = 'TableFooter'; + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableRow.displayName = 'TableRow'; + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableHead.displayName = 'TableHead'; + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableCell.displayName = 'TableCell'; + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableCaption.displayName = 'TableCaption'; + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +}; diff --git a/packages/canon/src/components/Table/stories/Table.stories.tsx b/packages/canon/src/components/Table/stories/Table.stories.tsx new file mode 100644 index 0000000000..0772d3aa91 --- /dev/null +++ b/packages/canon/src/components/Table/stories/Table.stories.tsx @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { Table } from '../Table'; + +const meta = { + title: 'Components/Table/Table', + component: Table, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Hello World! I'm a basic table", + }, +}; diff --git a/packages/canon/src/components/Table/stories/TableBody.stories.tsx b/packages/canon/src/components/Table/stories/TableBody.stories.tsx new file mode 100644 index 0000000000..ef08f47913 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableBody.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableBody } from '../Table'; + +const meta = { + title: 'Components/Table/TableBody', + component: TableBody, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableCaption.stories.tsx b/packages/canon/src/components/Table/stories/TableCaption.stories.tsx new file mode 100644 index 0000000000..8b86e33d8f --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableCaption.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableCaption } from '../Table'; + +const meta = { + title: 'Components/Table/TableCaption', + component: TableCaption, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableCell.stories.tsx b/packages/canon/src/components/Table/stories/TableCell.stories.tsx new file mode 100644 index 0000000000..6ef4c9b539 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableCell.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableCell } from '../Table'; + +const meta = { + title: 'Components/Table/TableCell', + component: TableCell, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableFooter.stories.tsx b/packages/canon/src/components/Table/stories/TableFooter.stories.tsx new file mode 100644 index 0000000000..5d220194c9 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableFooter.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableFooter } from '../Table'; + +const meta = { + title: 'Components/Table/TableFooter', + component: TableFooter, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableHead.stories.tsx b/packages/canon/src/components/Table/stories/TableHead.stories.tsx new file mode 100644 index 0000000000..af20d5b9fc --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableHead.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableHead } from '../Table'; + +const meta = { + title: 'Components/Table/TableHead', + component: TableHead, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableHeader.stories.tsx b/packages/canon/src/components/Table/stories/TableHeader.stories.tsx new file mode 100644 index 0000000000..faaab22ac9 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableHeader.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableHeader } from '../Table'; + +const meta = { + title: 'Components/Table/TableHeader', + component: TableHeader, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableRow.stories.tsx b/packages/canon/src/components/Table/stories/TableRow.stories.tsx new file mode 100644 index 0000000000..f048df6b53 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableRow.stories.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 type { Meta, StoryObj } from '@storybook/react'; +import { TableRow } from '../Table'; + +const meta = { + title: 'Components/Table/TableRow', + component: TableRow, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css new file mode 100644 index 0000000000..f57280f642 --- /dev/null +++ b/packages/canon/src/components/Table/styles.css @@ -0,0 +1,11 @@ +.table { + position: relative; + overflow: auto; + width: 100%; + + table { + width: 100%; + caption-side: bottom; + font-size: var(--canon-font-size-sm); + } +} diff --git a/packages/canon/src/theme/theme.css b/packages/canon/src/css/backstage.css similarity index 73% rename from packages/canon/src/theme/theme.css rename to packages/canon/src/css/backstage.css index ef78b2221a..40f143baac 100644 --- a/packages/canon/src/theme/theme.css +++ b/packages/canon/src/css/backstage.css @@ -14,7 +14,20 @@ * limitations under the License. */ -/* Light theme */ +/* Normalize */ +@import './normalize.css'; + +/* Geist font */ +@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap'); + +*, +html, +body { + font-family: var(--canon-font-regular); +} + +/* Light theme tokens */ :root { /* Colors */ --canon-accent: #000; @@ -51,20 +64,20 @@ --canon-font-bold: 600; /* Font sizes */ - --canon-font-sizes-2xs: 0.625rem; - --canon-font-sizes-xs: 0.75rem; - --canon-font-sizes-sm: 0.875rem; - --canon-font-sizes-md: 1rem; - --canon-font-sizes-lg: 1.125rem; - --canon-font-sizes-xl: 1.25rem; - --canon-font-sizes-2xl: 1.5rem; - --canon-font-sizes-3xl: 1.875rem; - --canon-font-sizes-4xl: 2.25rem; - --canon-font-sizes-5xl: 3rem; - --canon-font-sizes-6xl: 3.75rem; - --canon-font-sizes-7xl: 4.5rem; - --canon-font-sizes-8xl: 6rem; - --canon-font-sizes-9xl: 8rem; + --canon-font-size-2xs: 0.625rem; + --canon-font-size-xs: 0.75rem; + --canon-font-size-sm: 0.875rem; + --canon-font-size-md: 1rem; + --canon-font-size-lg: 1.125rem; + --canon-font-size-xl: 1.25rem; + --canon-font-size-2xl: 1.5rem; + --canon-font-size-3xl: 1.875rem; + --canon-font-size-4xl: 2.25rem; + --canon-font-size-5xl: 3rem; + --canon-font-size-6xl: 3.75rem; + --canon-font-size-7xl: 4.5rem; + --canon-font-size-8xl: 6rem; + --canon-font-size-9xl: 8rem; /* Spacing */ --canon-spacing-2xs: 0.25rem; @@ -80,7 +93,7 @@ --canon-container-padding: 1rem; } -/* Dark theme */ +/* Dark theme tokens */ [data-theme='dark'] { /* Colors */ --canon-accent: #fff; diff --git a/packages/canon/src/theme/styles.css b/packages/canon/src/css/components.css similarity index 77% rename from packages/canon/src/theme/styles.css rename to packages/canon/src/css/components.css index 8cb74374c6..50978a6710 100644 --- a/packages/canon/src/theme/styles.css +++ b/packages/canon/src/css/components.css @@ -14,13 +14,6 @@ * limitations under the License. */ -/* Geist font */ -@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap'); - -/* Theme */ -@import './theme.css'; - /* Components */ @import '../components/Button/styles.css'; @import '../components/Stack/styles.css'; @@ -29,3 +22,4 @@ @import '../components/Container/styles.css'; @import '../components/Icon/styles.css'; @import '../components/Checkbox/styles.css'; +@import '../components/Table/styles.css'; diff --git a/packages/canon/src/css/normalize.css b/packages/canon/src/css/normalize.css new file mode 100644 index 0000000000..80e1ca4119 --- /dev/null +++ b/packages/canon/src/css/normalize.css @@ -0,0 +1,201 @@ +/*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ + +/* +Document +======== +*/ + +/** +Use a better box model (opinionated). +*/ + +*, +::before, +::after { + box-sizing: border-box; +} + +html { + /* Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */ + font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji'; + line-height: 1.15; /* 1. Correct the line height in all browsers. */ + -webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */ + tab-size: 4; /* 3. Use a more readable tab size (opinionated). */ +} + +/* +Sections +======== +*/ + +body { + margin: 0; /* Remove the margin in all browsers. */ +} + +/* +Text-level semantics +==================== +*/ + +/** +Add the correct font weight in Chrome and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/** +1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) +2. Correct the odd 'em' font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, + monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/** +Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +Tabular data +============ +*/ + +/** +Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016) +*/ + +table { + border-color: currentcolor; +} + +/* +Forms +===== +*/ + +/** +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** +Correct the inability to style clickable types in iOS and Safari. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; +} + +/** +Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. +*/ + +legend { + padding: 0; +} + +/** +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/** +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/** +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to 'inherit' in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Interactive +=========== +*/ + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +}