diff --git a/packages/canon/docs/components/IconLibrary/index.ts b/packages/canon/docs/components/IconLibrary/index.ts
new file mode 100644
index 0000000000..071c80db85
--- /dev/null
+++ b/packages/canon/docs/components/IconLibrary/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+export { IconLibrary } from './IconLibrary';
diff --git a/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx b/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx
new file mode 100644
index 0000000000..56f389a389
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx
@@ -0,0 +1,64 @@
+/*
+ * 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 React from 'react';
+import { BoxSvg } from './svgs/box';
+import { StackSvg } from './svgs/stack';
+import { GridSvg } from './svgs/grid';
+import { InlineSvg } from './svgs/inline';
+import { ContainerSvg } from './svgs/container';
+
+export const LayoutComponents = () => {
+ return (
+
+
+
+
+
+
Box
+
The most basic layout component
+
+
+
+
+
+
Stack
+
Arrange your components vertically
+
+
+
+
+
+
Grid
+
Arrange your components in a grid
+
+
+
+
+
+
Inline
+
Arrange your components in a row
+
+
+
+
+
+
Container
+
A container for your components
+
+
+ );
+};
diff --git a/packages/canon/docs/components/LayoutComponents/index.ts b/packages/canon/docs/components/LayoutComponents/index.ts
new file mode 100644
index 0000000000..55cc9f25ef
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+export { LayoutComponents } from './LayoutComponents';
diff --git a/packages/canon/docs/components/LayoutComponents/index.tsx b/packages/canon/docs/components/LayoutComponents/index.tsx
deleted file mode 100644
index 9e0b039684..0000000000
--- a/packages/canon/docs/components/LayoutComponents/index.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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 React from 'react';
-import {
- container,
- box,
- content,
- title,
- description,
- whiteBox,
- whiteBoxStack,
- stack,
- verticalDivider,
- horizontalDivider,
- columns,
- inline,
- tiles,
- whiteBoxColumns,
- whiteBoxInline,
- whiteBoxTiles,
-} from './layout-components.css';
-
-export const LayoutComponents = () => {
- return (
-
-
-
-
-
-
Box
-
The most basic layout component.
-
-
-
-
-
-
-
-
Stack
-
Arrange your components vertically.
-
-
-
-
-
-
-
-
Columns
-
Arrange your components horizontally.
-
-
-
-
-
-
-
Tiles
-
Arrange your components in a grid.
-
-
- );
-};
diff --git a/packages/canon/docs/components/LayoutComponents/layout-components.css.ts b/packages/canon/docs/components/LayoutComponents/layout-components.css.ts
deleted file mode 100644
index a8440dd01f..0000000000
--- a/packages/canon/docs/components/LayoutComponents/layout-components.css.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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 { style } from '@vanilla-extract/css';
-
-export const container = style({
- display: 'flex',
- justifyContent: 'flex-start',
- gap: '1rem',
- flexWrap: 'wrap',
-});
-
-export const box = style({
- display: 'flex',
- flexDirection: 'column',
- width: 'calc(33.33% - 0.67rem)',
- marginBottom: '1rem',
- alignItems: 'flex-start',
-});
-
-export const content = style({
- flex: 'none',
- background: '#f2f2f2',
- borderRadius: '4px',
- width: '100%',
- height: '180px',
- border: '1px solid #e0e0e0',
- transition: 'border-color 0.2s ease-in-out',
- marginBottom: '0.75rem',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- selectors: {
- [`${box}:hover &`]: {
- borderColor: '#1f47ff',
- },
- },
-});
-
-export const title = style({
- fontSize: '16px',
- fontFamily: 'var(--canon-font-sans)',
- transition: 'color 0.2s ease-in-out',
- marginBottom: '0.25rem',
- selectors: {
- [`${box}:hover &`]: {
- color: '#1f47ff',
- },
- },
-});
-
-export const description = style({
- fontSize: '16px',
- fontFamily: 'var(--canon-font-sans)',
- color: '#9e9e9e',
-});
-
-export const whiteBox = style({
- background: '#fff',
- width: '40px',
- height: '40px',
- borderRadius: '4px',
- boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
-});
-
-export const whiteBoxStack = style([
- whiteBox,
- {
- width: '40%',
- height: '28px',
- },
-]);
-
-export const whiteBoxColumns = style([
- whiteBox,
- {
- width: '30%',
- height: '32px',
- },
-]);
-
-export const whiteBoxInline = style([
- whiteBox,
- {
- width: '32px',
- height: '32px',
- },
-]);
-
-export const whiteBoxTiles = style([
- whiteBox,
- {
- width: '100%',
- height: '32px',
- },
-]);
-
-export const stack = style({
- display: 'flex',
- flexDirection: 'column',
-});
-
-export const columns = style({
- display: 'flex',
- flexDirection: 'row',
-});
-
-export const inline = style({
- display: 'flex',
- flexWrap: 'wrap',
- flexDirection: 'row',
- justifyContent: 'flex-start',
- alignItems: 'flex-start',
- gap: '0.5rem',
- paddingLeft: '1rem',
-});
-
-export const tiles = style({
- display: 'grid',
- gridTemplateColumns: 'repeat(4, 1fr)',
- gap: '0.5rem',
- paddingLeft: '1rem',
- paddingRight: '1rem',
- width: '100%',
-});
-
-export const verticalDivider = style({
- display: 'flex',
- flexShrink: 0,
- flexDirection: 'column',
- position: 'relative',
- height: '20px',
- width: '2px',
- backgroundColor: '#1f47ff',
- selectors: {
- '&::before': {
- content: '""',
- position: 'absolute',
- top: 0,
- left: '-9px',
- width: '20px',
- height: '2px',
- backgroundColor: '#1f47ff',
- },
- '&::after': {
- content: '""',
- position: 'absolute',
- bottom: 0,
- left: '-9px',
- width: '20px',
- height: '2px',
- backgroundColor: '#1f47ff',
- },
- },
-});
-
-export const horizontalDivider = style({
- flexShrink: 0,
- display: 'flex',
- flexDirection: 'row',
- position: 'relative',
- height: '2px',
- width: '20px',
- backgroundColor: '#1f47ff',
- selectors: {
- '&::before': {
- content: '""',
- position: 'absolute',
- left: 0,
- top: '-9px',
- width: '2px',
- height: '20px',
- backgroundColor: '#1f47ff',
- },
- '&::after': {
- content: '""',
- position: 'absolute',
- right: 0,
- top: '-9px',
- width: '2px',
- height: '20px',
- backgroundColor: '#1f47ff',
- },
- },
-});
diff --git a/packages/canon/docs/components/LayoutComponents/styles.css b/packages/canon/docs/components/LayoutComponents/styles.css
new file mode 100644
index 0000000000..9319121224
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/styles.css
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+.layout-components {
+ display: flex;
+ justify-content: flex-start;
+ gap: 1rem;
+ flex-wrap: wrap;
+
+ & .box {
+ display: flex;
+ flex-direction: column;
+ width: calc(33.33% - 0.67rem);
+ margin-bottom: 1rem;
+ align-items: flex-start;
+ }
+
+ & .content {
+ flex: none;
+ background: linear-gradient(180deg, #f3f3f3 0%, #fff 100%);
+ border-radius: 4px;
+ width: 100%;
+ height: 180px;
+ transition: all 0.2s ease-in-out;
+ margin-bottom: 0.75rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ &:hover {
+ transform: translateY(-4px);
+ }
+ }
+
+ & .title {
+ font-size: 16px;
+ transition: color 0.2s ease-in-out;
+ margin-bottom: 0.25rem;
+ }
+
+ & .description {
+ font-size: 16px;
+ color: #9e9e9e;
+ }
+}
diff --git a/packages/canon/docs/components/LayoutComponents/svgs/box.tsx b/packages/canon/docs/components/LayoutComponents/svgs/box.tsx
new file mode 100644
index 0000000000..1749b38c6f
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/svgs/box.tsx
@@ -0,0 +1,54 @@
+/*
+ * 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 React from 'react';
+
+export const BoxSvg = () => {
+ return (
+
+ );
+};
diff --git a/packages/canon/docs/components/LayoutComponents/svgs/container.tsx b/packages/canon/docs/components/LayoutComponents/svgs/container.tsx
new file mode 100644
index 0000000000..62fe4ce266
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/svgs/container.tsx
@@ -0,0 +1,373 @@
+/*
+ * 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 React from 'react';
+
+export const ContainerSvg = () => {
+ return (
+
+ );
+};
diff --git a/packages/canon/docs/components/LayoutComponents/svgs/grid.tsx b/packages/canon/docs/components/LayoutComponents/svgs/grid.tsx
new file mode 100644
index 0000000000..5527d1f3e2
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/svgs/grid.tsx
@@ -0,0 +1,91 @@
+/*
+ * 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 React from 'react';
+
+export const GridSvg = () => {
+ return (
+
+ );
+};
diff --git a/packages/canon/docs/components/LayoutComponents/svgs/inline.tsx b/packages/canon/docs/components/LayoutComponents/svgs/inline.tsx
new file mode 100644
index 0000000000..fadb9bfc1b
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/svgs/inline.tsx
@@ -0,0 +1,92 @@
+/*
+ * 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 React from 'react';
+
+export const InlineSvg = () => {
+ return (
+
+ );
+};
diff --git a/packages/canon/docs/components/LayoutComponents/svgs/stack.tsx b/packages/canon/docs/components/LayoutComponents/svgs/stack.tsx
new file mode 100644
index 0000000000..aeda998d2e
--- /dev/null
+++ b/packages/canon/docs/components/LayoutComponents/svgs/stack.tsx
@@ -0,0 +1,82 @@
+/*
+ * 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 React from 'react';
+
+export const StackSvg = () => {
+ return (
+
+ );
+};
diff --git a/packages/canon/docs/components/PropsTable/PropsTable.tsx b/packages/canon/docs/components/PropsTable/PropsTable.tsx
new file mode 100644
index 0000000000..a3dc9e271c
--- /dev/null
+++ b/packages/canon/docs/components/PropsTable/PropsTable.tsx
@@ -0,0 +1,57 @@
+/*
+ * 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 React from 'react';
+import * as Table from '..';
+import { Chip } from '..';
+
+// Modify the PropsTable component to accept a generic type
+export const PropsTable =
>({
+ data,
+}: {
+ data: T;
+}) => {
+ return (
+
+
+
+ Prop
+ Type
+ Responsive
+
+
+
+ {Object.keys(data).map(n => (
+
+
+ {n}
+
+
+ {Array.isArray(data[n].type) ? (
+ data[n].type.map((t: any) => {t})
+ ) : (
+ {data[n].type}
+ )}
+
+
+ {data[n].responsive ? 'Yes' : 'No'}
+
+
+ ))}
+
+
+ );
+};
diff --git a/packages/canon/docs/components/PropsTable/getProps.ts b/packages/canon/docs/components/PropsTable/getProps.ts
new file mode 100644
index 0000000000..5773eaeb27
--- /dev/null
+++ b/packages/canon/docs/components/PropsTable/getProps.ts
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+export function getProps(styles: Record) {
+ return Object.keys(styles).reduce(
+ (acc: Record, n) => {
+ const style = styles[n];
+
+ let values: string[] = [];
+
+ if (style.values) {
+ // If values exist, use them
+ values = Object.keys(style.values);
+ } else if (style.mappings && style.mappings.length > 0) {
+ // If mappings exist, use the first mapping's values
+ const firstMapping = style.mappings[0];
+ values = Object.keys(styles[firstMapping].values);
+ } else {
+ // Default to an empty array if neither values nor mappings exist
+ values = [];
+ }
+
+ acc[n] = {
+ type: values,
+ responsive: true,
+ };
+ return acc;
+ },
+ {} as Record,
+ );
+}
diff --git a/packages/canon/docs/components/PropsTable/index.ts b/packages/canon/docs/components/PropsTable/index.ts
new file mode 100644
index 0000000000..181933f0f8
--- /dev/null
+++ b/packages/canon/docs/components/PropsTable/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+export { PropsTable } from './PropsTable';
+export { getProps } from './getProps';
diff --git a/packages/canon/docs/components/Roadmap/index.tsx b/packages/canon/docs/components/Roadmap/Roadmap.tsx
similarity index 100%
rename from packages/canon/docs/components/Roadmap/index.tsx
rename to packages/canon/docs/components/Roadmap/Roadmap.tsx
diff --git a/packages/canon/docs/components/Roadmap/index.ts b/packages/canon/docs/components/Roadmap/index.ts
new file mode 100644
index 0000000000..ac51dfa1ed
--- /dev/null
+++ b/packages/canon/docs/components/Roadmap/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+export { Roadmap } from './Roadmap';
diff --git a/packages/canon/docs/components/Roadmap/styles.css b/packages/canon/docs/components/Roadmap/styles.css
index e47aecf7fa..63f32312e7 100644
--- a/packages/canon/docs/components/Roadmap/styles.css
+++ b/packages/canon/docs/components/Roadmap/styles.css
@@ -4,7 +4,6 @@
}
.roadmap .roadmap-item {
- font-family: 'Geist', sans-serif;
display: flex;
align-items: center;
justify-content: space-between;
@@ -60,7 +59,6 @@
}
.roadmap .roadmap-item .title {
- font-weight: 300;
font-size: 16px;
}
diff --git a/packages/canon/docs/components/Table/index.tsx b/packages/canon/docs/components/Table/Table.tsx
similarity index 77%
rename from packages/canon/docs/components/Table/index.tsx
rename to packages/canon/docs/components/Table/Table.tsx
index ead30985aa..74a26a89af 100644
--- a/packages/canon/docs/components/Table/index.tsx
+++ b/packages/canon/docs/components/Table/Table.tsx
@@ -15,18 +15,11 @@
*/
import React from 'react';
-import {
- cellStyles,
- headerCellStyles,
- tableStyles,
- wrapperStyles,
- rowStyles,
-} from './table.css';
export const Root = ({ children }: { children: React.ReactNode }) => {
return (
-
-
+
);
};
@@ -44,13 +37,13 @@ export const HeaderRow = ({ children }: { children: React.ReactNode }) => {
};
export const HeaderCell = ({ children }: { children: React.ReactNode }) => {
- return
{children} | ;
+ return
{children} | ;
};
export const Row = ({ children }: { children: React.ReactNode }) => {
- return
{children}
;
+ return
{children}
;
};
export const Cell = ({ children }: { children: React.ReactNode }) => {
- return
{children} | ;
+ return
{children} | ;
};
diff --git a/packages/canon/docs/components/Table/index.ts b/packages/canon/docs/components/Table/index.ts
new file mode 100644
index 0000000000..7419aa83a8
--- /dev/null
+++ b/packages/canon/docs/components/Table/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+export { Root, Header, Body, Row, Cell, HeaderRow, HeaderCell } from './Table';
diff --git a/packages/canon/docs/components/Table/styles.css b/packages/canon/docs/components/Table/styles.css
new file mode 100644
index 0000000000..ed56774a85
--- /dev/null
+++ b/packages/canon/docs/components/Table/styles.css
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+.sb-table-wrapper {
+ border: 1px solid #e7e7e7;
+ border-radius: 4px;
+ overflow: hidden;
+
+ & .sb-table {
+ width: 100%;
+ margin: 0 !important;
+ padding: 0 !important;
+ border-spacing: 0px;
+ border-collapse: collapse;
+ }
+
+ & .sb-table-cell {
+ padding: 12px 16px !important;
+ border: none !important;
+ text-align: left;
+ background-color: white !important;
+ font-size: 16px;
+
+ & p {
+ margin: 0;
+ }
+ }
+
+ & .sb-table-header-cell {
+ background-color: #f5f5f5 !important;
+ border-bottom: 1px solid #e7e7e7 !important;
+ font-weight: 500;
+ font-size: 14px;
+ }
+
+ & .sb-table-row {
+ border: none;
+ border-bottom: 1px solid #e7e7e7;
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ & .sb-table-chip {
+ display: inline-block;
+ font-size: 14px !important;
+ border: 1px solid #e7e7e7;
+ border-radius: 6px;
+ padding: 0px 6px;
+ height: 24px;
+ }
+
+ & .sb-table-type {
+ display: flex;
+ flex-wrap: wrap;
+ flex-direction: row;
+ gap: 8px;
+ }
+}
diff --git a/packages/canon/docs/components/Table/table.css.ts b/packages/canon/docs/components/Table/table.css.ts
deleted file mode 100644
index b01373ee04..0000000000
--- a/packages/canon/docs/components/Table/table.css.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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 { style, globalStyle } from '@vanilla-extract/css';
-
-export const wrapperStyles = style({
- border: '1px solid #e7e7e7',
- borderRadius: '4px',
- overflow: 'hidden',
-});
-
-export const tableStyles = style({
- width: '100%',
- margin: '0 !important',
- padding: '0 !important',
- borderSpacing: '0px',
- borderCollapse: 'collapse',
-});
-
-export const cellStyles = style({
- padding: '12px 16px !important',
- border: 'none !important',
- textAlign: 'left',
- backgroundColor: 'white !important',
- fontFamily: '"Geist", sans-serif',
- fontSize: '16px',
- fontWeight: 300,
-});
-
-// Apply global styles to
elements inside cellStyles
-globalStyle(`${cellStyles} p`, {
- margin: '0',
-});
-
-export const headerRowStyles = style({
- borderBottom: '1px solid #e7e7e7',
-});
-
-export const headerCellStyles = style({
- backgroundColor: '#f5f5f5 !important',
- borderBottom: '1px solid #e7e7e7 !important',
- fontWeight: 500,
- fontSize: '14px',
-});
-
-export const rowStyles = style({
- border: 'none',
- borderBottom: '1px solid #e7e7e7',
- selectors: {
- '&:last-child': {
- borderBottom: 'none',
- },
- },
-});
-
-export const chipStyles = style({
- display: 'inline-block',
- fontSize: '14px !important',
- border: '1px solid #e7e7e7',
- borderRadius: '6px',
- padding: '0px 6px',
- height: '24px',
-});
-
-export const typeStyles = style({
- display: 'flex',
- flexWrap: 'wrap',
- flexDirection: 'row',
- gap: '8px',
-});
diff --git a/packages/canon/docs/components/Text/index.tsx b/packages/canon/docs/components/Text/Text.tsx
similarity index 90%
rename from packages/canon/docs/components/Text/index.tsx
rename to packages/canon/docs/components/Text/Text.tsx
index be882c0a81..90804b7da7 100644
--- a/packages/canon/docs/components/Text/index.tsx
+++ b/packages/canon/docs/components/Text/Text.tsx
@@ -15,7 +15,6 @@
*/
import React from 'react';
-import { textStyles } from './text.css';
export const Text = ({
children,
@@ -25,7 +24,7 @@ export const Text = ({
style?: React.CSSProperties;
}) => {
return (
-
+
{children}
);
diff --git a/packages/canon/docs/components/Text/index.ts b/packages/canon/docs/components/Text/index.ts
new file mode 100644
index 0000000000..873fca2c76
--- /dev/null
+++ b/packages/canon/docs/components/Text/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+export { Text } from './Text';
diff --git a/packages/canon/docs/components/Text/text.css.ts b/packages/canon/docs/components/Text/styles.css
similarity index 59%
rename from packages/canon/docs/components/Text/text.css.ts
rename to packages/canon/docs/components/Text/styles.css
index 01b4cb8fc8..b1bc40a1ac 100644
--- a/packages/canon/docs/components/Text/text.css.ts
+++ b/packages/canon/docs/components/Text/styles.css
@@ -14,21 +14,30 @@
* limitations under the License.
*/
-import { globalStyle, style } from '@vanilla-extract/css';
+.sb-text {
+ font-size: 16px;
+ line-height: 28px;
+ margin: 0;
+ margin-bottom: 16px;
+ color: #4f4f4f;
-export const textStyles = style({
- fontFamily: '"Geist", sans-serif',
- fontSize: '16px',
- lineHeight: '28px',
- margin: '0',
- fontWeight: 300,
- paddingBottom: '16px',
-});
+ & p {
+ font-size: 16px;
+ line-height: 28px;
+ margin: 0;
+ }
-globalStyle(`${textStyles} p`, {
- fontFamily: '"Geist", sans-serif',
- fontSize: '16px',
- lineHeight: '28px',
- margin: '0',
- fontWeight: 300,
-});
+ & code {
+ font-size: 13px;
+ color: #215cff;
+ background-color: #f1f3fc;
+ padding: 4px 4px;
+ border-radius: 4px;
+ }
+
+ & a {
+ color: #215cff;
+ text-decoration: none;
+ border-bottom: 1px solid #215cff;
+ }
+}
diff --git a/packages/canon/docs/components/Title/index.tsx b/packages/canon/docs/components/Title/Title.tsx
similarity index 92%
rename from packages/canon/docs/components/Title/index.tsx
rename to packages/canon/docs/components/Title/Title.tsx
index 13e5b964bb..59fefad8f9 100644
--- a/packages/canon/docs/components/Title/index.tsx
+++ b/packages/canon/docs/components/Title/Title.tsx
@@ -15,7 +15,6 @@
*/
import React from 'react';
-import { titleStyles } from './title.css';
export const Title = ({
children,
@@ -32,7 +31,7 @@ export const Title = ({
if (type === 'h3') Component = 'h3';
return React.createElement(Component, {
- className: titleStyles({ type }),
+ className: `sb-title ${type}`,
style,
children,
});
diff --git a/packages/canon/docs/components/Title/index.ts b/packages/canon/docs/components/Title/index.ts
new file mode 100644
index 0000000000..998dc81882
--- /dev/null
+++ b/packages/canon/docs/components/Title/index.ts
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
+export { Title } from './Title';
diff --git a/packages/canon/docs/components/Title/styles.css b/packages/canon/docs/components/Title/styles.css
new file mode 100644
index 0000000000..61e99e20b3
--- /dev/null
+++ b/packages/canon/docs/components/Title/styles.css
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+.sb-title {
+ margin: 0;
+ font-weight: 500;
+ border: none;
+
+ &.h1 {
+ font-size: 36px;
+ line-height: 44px;
+ margin-bottom: 24px;
+ margin-top: 0px;
+ }
+
+ &.h2 {
+ font-size: 24px;
+ line-height: 32px;
+ margin-bottom: 12px;
+ margin-top: 52px;
+ }
+
+ &.h3 {
+ font-size: 20px;
+ line-height: 28px;
+ margin-bottom: 12px;
+ margin-top: 40px;
+ }
+}
diff --git a/packages/canon/docs/components/Title/title.css.ts b/packages/canon/docs/components/Title/title.css.ts
deleted file mode 100644
index 5ca0394af6..0000000000
--- a/packages/canon/docs/components/Title/title.css.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 { recipe } from '@vanilla-extract/recipes';
-
-export const titleStyles = recipe({
- base: {
- fontFamily: '"Geist", sans-serif',
- margin: '0',
- fontWeight: 500,
- border: 'none',
- },
- variants: {
- type: {
- h1: {
- fontSize: '36px',
- lineHeight: '44px',
- marginBottom: '32px',
- marginTop: '0px',
- },
- h2: {
- fontSize: '24px',
- lineHeight: '32px',
- marginBottom: '12px',
- marginTop: '52px',
- },
- h3: {
- fontSize: '20px',
- lineHeight: '28px',
- marginBottom: '12px',
- marginTop: '52px',
- },
- },
- },
-});
diff --git a/packages/canon/docs/components/index.ts b/packages/canon/docs/components/index.ts
index 7ad07bec6a..0e5ff2e325 100644
--- a/packages/canon/docs/components/index.ts
+++ b/packages/canon/docs/components/index.ts
@@ -14,13 +14,14 @@
* limitations under the License.
*/
+export * from './Banner';
export * from './Chip';
-export * from './Table';
-export * from './Title';
-export * from './Text';
export * from './Columns';
export * from './ComponentStatus';
-export * from './LayoutComponents';
-export * from './Banner';
export * from './IconLibrary';
+export * from './LayoutComponents';
+export * from './PropsTable';
export * from './Roadmap';
+export * from './Table';
+export * from './Text';
+export * from './Title';
diff --git a/packages/canon/docs/components/styles.css b/packages/canon/docs/components/styles.css
index 698085ad19..706b1626b3 100644
--- a/packages/canon/docs/components/styles.css
+++ b/packages/canon/docs/components/styles.css
@@ -1,2 +1,15 @@
+.sbdocs-content {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
+ Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
+}
+
+@import './Banner/styles.css';
+@import './Chip/styles.css';
+@import './Columns/styles.css';
+@import './ComponentStatus/styles.css';
@import './IconLibrary/styles.css';
+@import './LayoutComponents/styles.css';
@import './Roadmap/styles.css';
+@import './Table/styles.css';
+@import './Text/styles.css';
+@import './Title/styles.css';
diff --git a/packages/canon/docs/spaceProps.ts b/packages/canon/docs/spaceProps.ts
new file mode 100644
index 0000000000..3eb6961bc1
--- /dev/null
+++ b/packages/canon/docs/spaceProps.ts
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+export const spacePropsList = [
+ 'margin',
+ 'marginBottom',
+ 'marginLeft',
+ 'marginRight',
+ 'marginTop',
+ 'marginX',
+ 'marginY',
+ 'padding',
+ 'paddingBottom',
+ 'paddingLeft',
+ 'paddingRight',
+ 'paddingTop',
+ 'paddingX',
+ 'paddingY',
+].reduce(
+ (acc: { [key: string]: { type: string[]; responsive: boolean } }, prop) => {
+ acc[prop] = {
+ type: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl'],
+ responsive: true,
+ };
+ return acc;
+ },
+ {},
+);
diff --git a/packages/canon/docs/utils/argTypes.ts b/packages/canon/docs/utils/argTypes.ts
deleted file mode 100644
index ff5a159677..0000000000
--- a/packages/canon/docs/utils/argTypes.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 { boxProperties } from '../../src/components/Box/sprinkles.css';
-import {
- colorProperties,
- spacingProperties,
-} from '../../src/layout/sprinkles.css';
-
-export const listResponsiveValues = (
- value: keyof typeof boxProperties.styles,
-) => {
- const values = boxProperties.styles[value];
-
- if ('values' in values) {
- return Object.keys(values.values);
- }
-
- return [];
-};
-
-export const listColorValues = (value: keyof typeof colorProperties.styles) => {
- const values = colorProperties.styles[value];
-
- if ('values' in values) {
- return Object.keys(values.values);
- }
-
- return [];
-};
-
-export const argTypesSpacing = Object.keys(spacingProperties.styles).reduce<
- Record
->((acc, n) => {
- acc[n] = {
- control: 'inline-radio',
- options: ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'],
- };
- return acc;
-}, {});
-
-export const argTypesColor = Object.keys(colorProperties.styles).reduce<
- Record
->((acc, n) => {
- acc[n as keyof typeof colorProperties.styles] = {
- control: 'select',
- options: Object.keys(
- colorProperties.styles[n as keyof typeof colorProperties.styles].values,
- ),
- };
- return acc;
-}, {});
diff --git a/packages/canon/package.json b/packages/canon/package.json
index 4ec11b31fb..23c40300f1 100644
--- a/packages/canon/package.json
+++ b/packages/canon/package.json
@@ -37,38 +37,31 @@
"test": "backstage-cli package test"
},
"dependencies": {
- "@base_ui/react": "^1.0.0-alpha.3",
- "@remixicon/react": "^4.5.0",
- "@vanilla-extract/css": "^1.16.0",
- "@vanilla-extract/dynamic": "^2.1.2",
- "@vanilla-extract/recipes": "^0.5.5",
- "@vanilla-extract/sprinkles": "^1.6.3"
+ "@base-ui-components/react": "^1.0.0-alpha.4",
+ "@remixicon/react": "^4.5.0"
},
"devDependencies": {
"@backstage/cli": "workspace:^",
"@chromatic-com/storybook": "^3.2.2",
- "@storybook/addon-essentials": "^8.4.5",
- "@storybook/addon-interactions": "^8.4.5",
+ "@storybook/addon-essentials": "^8.4.7",
+ "@storybook/addon-interactions": "^8.4.7",
"@storybook/addon-styling-webpack": "^1.0.1",
- "@storybook/addon-themes": "^8.4.5",
+ "@storybook/addon-themes": "^8.4.7",
"@storybook/addon-webpack5-compiler-swc": "^1.0.5",
- "@storybook/blocks": "^8.4.5",
- "@storybook/react": "^8.4.5",
- "@storybook/react-webpack5": "^8.4.5",
- "@storybook/test": "^8.4.5",
+ "@storybook/blocks": "^8.4.7",
+ "@storybook/react": "^8.4.7",
+ "@storybook/react-webpack5": "^8.4.7",
+ "@storybook/test": "^8.4.7",
"@testing-library/jest-dom": "^6.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
- "@vanilla-extract/rollup-plugin": "^1.3.10",
- "@vanilla-extract/webpack-plugin": "^2.3.14",
"eslint-plugin-storybook": "^0.11.1",
"globals": "^15.11.0",
"mini-css-extract-plugin": "^2.9.2",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-router-dom": "^6.3.0",
- "storybook": "^8.4.5",
- "webpack-merge": "^6.0.1"
+ "storybook": "^8.4.7"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md
index e98d57a13d..fc1f773b4b 100644
--- a/packages/canon/report.api.md
+++ b/packages/canon/report.api.md
@@ -5,20 +5,15 @@
```ts
///
-import { CSSProperties } from 'react';
-import { DOMElement } from 'react';
+import type { CSSProperties } from 'react';
+import { ForwardRefExoticComponent } from 'react';
import { default as React_2 } from 'react';
+import * as React_3 from 'react';
import { ReactNode } from 'react';
+import { RefAttributes } from 'react';
// @public (undocumented)
-export type AlignItemsProps =
- | 'stretch'
- | 'flex-start'
- | 'center'
- | 'flex-end'
- | Partial<
- Record
- >;
+export type AlignItems = 'stretch' | 'start' | 'center' | 'end';
// @public (undocumented)
export type AsProps =
@@ -40,95 +35,48 @@ export type AsProps =
| 'dt';
// @public (undocumented)
-export type Background =
- | 'background'
- | 'elevation1'
- | 'elevation2'
- | 'transparent'
- | Partial<
- Record
- >;
+export type Border = 'none' | 'base' | 'error' | 'warning' | 'selected';
// @public (undocumented)
-export type BorderRadiusProps =
+export type BorderRadius =
| 'none'
- | 'small'
- | 'medium'
- | 'full'
- | Partial>;
+ | '2xs'
+ | 'xs'
+ | 'sm'
+ | 'md'
+ | 'lg'
+ | 'xl'
+ | '2xl';
// @public (undocumented)
-export const Box: (props: BoxProps) => DOMElement<
- {
- className: string;
- style: CSSProperties | undefined;
- children: ReactNode;
- },
- Element
+export const Box: ForwardRefExoticComponent<
+ BoxProps & RefAttributes
>;
// @public (undocumented)
-export interface BoxProps extends SpaceProps, ColorProps {
- // (undocumented)
- alignItems?: AlignItemsProps;
+export interface BoxProps extends UtilityProps {
// (undocumented)
as?: keyof JSX.IntrinsicElements;
// (undocumented)
- borderRadius?: BorderRadiusProps;
- // (undocumented)
children?: React.ReactNode;
// (undocumented)
className?: string;
// (undocumented)
- display?: DisplayProps;
- // (undocumented)
- flexDirection?: FlexDirectionProps;
- // (undocumented)
- flexWrap?: FlexWrapProps;
- // (undocumented)
- justifyContent?: JustifyContentProps;
- // (undocumented)
style?: React.CSSProperties;
}
// @public (undocumented)
-export type Breakpoint = keyof typeof breakpoints;
+export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
// @public (undocumented)
-export const breakpoints: {
- xs: {};
- sm: {
- '@media': string;
- };
- md: {
- '@media': string;
- };
- lg: {
- '@media': string;
- };
- xl: {
- '@media': string;
- };
- '2xl': {
- '@media': string;
- };
-};
-
-// @public (undocumented)
-export const Button: ({
- size,
- variant,
- children,
- disabled,
- iconStart,
- iconEnd,
- ...props
-}: ButtonProps) => React_2.JSX.Element;
+export const Button: React_2.ForwardRefExoticComponent<
+ ButtonProps & React_2.RefAttributes
+>;
// @public
export interface ButtonProps {
// (undocumented)
- children: React_2.ReactNode;
+ children: React.ReactNode;
// (undocumented)
disabled?: boolean;
// (undocumented)
@@ -136,51 +84,178 @@ export interface ButtonProps {
// (undocumented)
iconStart?: IconNames;
// (undocumented)
- size?: 'small' | 'medium';
+ size?: 'small' | 'medium' | Partial>;
// (undocumented)
- variant?: 'primary' | 'secondary';
+ style?: React.CSSProperties;
+ // (undocumented)
+ variant?:
+ | 'primary'
+ | 'secondary'
+ | 'tertiary'
+ | Partial>;
}
// @public (undocumented)
-export type Color =
- | 'primary'
- | 'secondary'
- | 'error'
- | Partial>;
-
-// @public (undocumented)
-export interface ColorProps {
+export interface CanonContextProps {
// (undocumented)
- background?: Background;
+ breakpoint: Breakpoint;
// (undocumented)
- color?: Color;
+ getResponsiveValue: (
+ value: string | Partial>,
+ ) => string;
+ // (undocumented)
+ icons: IconMap;
}
// @public (undocumented)
-export type DisplayProps =
- | 'flex'
- | 'none'
- | 'inline'
- | 'block'
- | Partial>;
+export const CanonProvider: (props: CanonProviderProps) => React_2.JSX.Element;
// @public (undocumented)
-export type FlexDirectionProps =
- | 'row'
- | 'column'
- | Partial>;
+export interface CanonProviderProps {
+ // (undocumented)
+ children?: ReactNode;
+ // (undocumented)
+ overrides?: Partial>;
+}
// @public (undocumented)
-export type FlexWrapProps =
- | 'wrap'
- | 'nowrap'
- | Partial>;
+export const Checkbox: React_2.ForwardRefExoticComponent<
+ CheckboxProps & React_2.RefAttributes
+>;
// @public (undocumented)
-export type Gap = Space | Partial>;
+export interface CheckboxProps {
+ // (undocumented)
+ checked?: boolean;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ defaultChecked?: boolean;
+ // (undocumented)
+ disabled?: boolean;
+ // (undocumented)
+ label?: string;
+ // (undocumented)
+ name?: string;
+ // (undocumented)
+ onChange?: (checked: boolean) => void;
+ // (undocumented)
+ required?: boolean;
+ // (undocumented)
+ style?: React.CSSProperties;
+ // (undocumented)
+ value?: string;
+}
// @public (undocumented)
-export const Icon: ({ name }: { name: IconNames }) => React_2.JSX.Element;
+export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto';
+
+// @public (undocumented)
+export const Container: React_2.ForwardRefExoticComponent<
+ ContainerProps & React_2.RefAttributes
+>;
+
+// @public (undocumented)
+export interface ContainerProps {
+ // (undocumented)
+ children?: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ marginBottom?: SpaceProps['marginBottom'];
+ // (undocumented)
+ marginTop?: SpaceProps['marginTop'];
+ // (undocumented)
+ marginY?: SpaceProps['marginY'];
+ // (undocumented)
+ paddingBottom?: SpaceProps['paddingBottom'];
+ // (undocumented)
+ paddingTop?: SpaceProps['paddingTop'];
+ // (undocumented)
+ paddingY?: SpaceProps['paddingY'];
+ // (undocumented)
+ style?: React.CSSProperties;
+}
+
+// @public (undocumented)
+export type Display = 'none' | 'flex' | 'block' | 'inline';
+
+// @public (undocumented)
+export type FlexDirection = 'row' | 'column';
+
+// @public (undocumented)
+export type FlexWrap = 'wrap' | 'nowrap' | 'wrap-reverse';
+
+// @public (undocumented)
+export const Grid: ForwardRefExoticComponent<
+ GridProps & RefAttributes
+> & {
+ Item: ForwardRefExoticComponent<
+ GridItemProps & RefAttributes
+ >;
+};
+
+// @public (undocumented)
+export interface GridItemProps {
+ // (undocumented)
+ children: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ colEnd?: UtilityProps['colEnd'];
+ // (undocumented)
+ colSpan?: UtilityProps['colSpan'];
+ // (undocumented)
+ colStart?: UtilityProps['colStart'];
+ // (undocumented)
+ rowSpan?: UtilityProps['rowSpan'];
+ // (undocumented)
+ style?: React.CSSProperties;
+}
+
+// @public (undocumented)
+export interface GridProps extends SpaceProps {
+ // (undocumented)
+ children?: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ columns?: UtilityProps['columns'];
+ // (undocumented)
+ gap?: UtilityProps['gap'];
+ // (undocumented)
+ style?: React.CSSProperties;
+}
+
+// @public (undocumented)
+export const Heading: React_2.ForwardRefExoticComponent<
+ HeadingProps & React_2.RefAttributes
+>;
+
+// @public (undocumented)
+export interface HeadingProps {
+ // (undocumented)
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+ // (undocumented)
+ children: React.ReactNode;
+ // (undocumented)
+ variant?:
+ | 'display'
+ | 'title1'
+ | 'title2'
+ | 'title3'
+ | 'title4'
+ | 'title5'
+ | Partial<
+ Record<
+ Breakpoint,
+ 'display' | 'title1' | 'title2' | 'title3' | 'title4' | 'title5'
+ >
+ >;
+}
+
+// @public (undocumented)
+export const Icon: (props: IconProps) => React_2.JSX.Element;
// @public (undocumented)
export type IconMap = Partial>;
@@ -191,132 +266,227 @@ export type IconNames =
| 'arrowLeft'
| 'arrowRight'
| 'arrowUp'
+ | 'arrowDownCircle'
+ | 'arrowLeftCircle'
+ | 'arrowRightCircle'
+ | 'arrowUpCircle'
+ | 'check'
+ | 'chevronDown'
+ | 'chevronLeft'
+ | 'chevronRight'
+ | 'chevronUp'
| 'cloud'
+ | 'externalLink'
| 'heart'
+ | 'moon'
| 'plus'
+ | 'sun'
| 'trash';
// @public (undocumented)
-export type JustifyContentProps =
- | 'stretch'
- | 'flex-start'
- | 'center'
- | 'flex-end'
- | 'space-around'
- | 'space-between'
- | Partial<
- Record<
- Breakpoint,
- | 'stretch'
- | 'flex-start'
- | 'center'
- | 'flex-end'
- | 'space-around'
- | 'space-between'
- >
- >;
-
-// @public (undocumented)
-export type Margin = Space | Partial>;
-
-// @public (undocumented)
-export type MarginBottom = Space | Partial>;
-
-// @public (undocumented)
-export type MarginLeft = Space | Partial>;
-
-// @public (undocumented)
-export type MarginRight = Space | Partial>;
-
-// @public (undocumented)
-export type MarginTop = Space | Partial>;
-
-// @public (undocumented)
-export type MarginX = Space | Partial>;
-
-// @public (undocumented)
-export type MarginY = Space | Partial>;
-
-// @public (undocumented)
-export type Padding = Space | Partial>;
-
-// @public (undocumented)
-export type PaddingBottom = Space | Partial>;
-
-// @public (undocumented)
-export type PaddingLeft = Space | Partial>;
-
-// @public (undocumented)
-export type PaddingRight = Space | Partial>;
-
-// @public (undocumented)
-export type PaddingTop = Space | Partial>;
-
-// @public (undocumented)
-export type PaddingX = Space | Partial>;
-
-// @public (undocumented)
-export type PaddingY = Space | Partial>;
-
-// @public (undocumented)
-export type Space = keyof typeof space;
-
-// @public (undocumented)
-export const space: {
- none: number;
- xxs: string;
- xs: string;
- sm: string;
- md: string;
- lg: string;
- xl: string;
- xxl: string;
+export type IconProps = {
+ name: IconNames;
+ size?: number;
};
+// @public (undocumented)
+export const icons: IconMap;
+
+// @public (undocumented)
+export const Inline: ForwardRefExoticComponent<
+ InlineProps & RefAttributes
+>;
+
+// @public (undocumented)
+export interface InlineProps extends SpaceProps {
+ // (undocumented)
+ align?:
+ | 'left'
+ | 'center'
+ | 'right'
+ | Partial>;
+ // (undocumented)
+ alignY?:
+ | 'top'
+ | 'center'
+ | 'bottom'
+ | Partial>;
+ // (undocumented)
+ as?: AsProps;
+ // (undocumented)
+ children: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ gap?: UtilityProps['gap'];
+ // (undocumented)
+ style?: React.CSSProperties;
+}
+
+// @public (undocumented)
+export type JustifyContent =
+ | 'stretch'
+ | 'start'
+ | 'center'
+ | 'end'
+ | 'around'
+ | 'between';
+
+// @public (undocumented)
+export type Space = 'none' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
+
// @public (undocumented)
export interface SpaceProps {
// (undocumented)
- gap?: Gap;
+ margin?: Space | Partial>;
// (undocumented)
- margin?: Margin;
+ marginBottom?: Space | Partial>;
// (undocumented)
- marginBottom?: MarginBottom;
+ marginLeft?: Space | Partial>;
// (undocumented)
- marginLeft?: MarginLeft;
+ marginRight?: Space | Partial>;
// (undocumented)
- marginRight?: MarginRight;
+ marginTop?: Space | Partial>;
// (undocumented)
- marginTop?: MarginTop;
+ marginX?: Space | Partial>;
// (undocumented)
- marginX?: MarginX;
+ marginY?: Space | Partial>;
// (undocumented)
- marginY?: MarginY;
+ padding?: Space | Partial>;
// (undocumented)
- padding?: Padding;
+ paddingBottom?: Space | Partial>;
// (undocumented)
- paddingBottom?: PaddingBottom;
+ paddingLeft?: Space | Partial>;
// (undocumented)
- paddingLeft?: PaddingLeft;
+ paddingRight?: Space | Partial>;
// (undocumented)
- paddingRight?: PaddingRight;
+ paddingTop?: Space | Partial>;
// (undocumented)
- paddingTop?: PaddingTop;
+ paddingX?: Space | Partial>;
// (undocumented)
- paddingX?: PaddingX;
- // (undocumented)
- paddingY?: PaddingY;
+ paddingY?: Space | Partial>;
}
// @public (undocumented)
-export type Theme = keyof typeof themes;
+export const Stack: ForwardRefExoticComponent<
+ StackProps & RefAttributes
+>;
// @public (undocumented)
-export const themes: {
- light: {
- selector: string;
- };
- dark: {
- selector: string;
- };
-};
+export interface StackProps extends SpaceProps {
+ // (undocumented)
+ align?:
+ | 'left'
+ | 'center'
+ | 'right'
+ | Partial>;
+ // (undocumented)
+ as?: AsProps;
+ // (undocumented)
+ children: React.ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ gap?: UtilityProps['gap'];
+ // (undocumented)
+ style?: React.CSSProperties;
+}
+
+// @public (undocumented)
+export const Table: React_3.ForwardRefExoticComponent<
+ React_3.HTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+export const TableBody: React_3.ForwardRefExoticComponent<
+ React_3.HTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+export const TableCell: React_3.ForwardRefExoticComponent<
+ React_3.TdHTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+export const TableFooter: React_3.ForwardRefExoticComponent<
+ React_3.HTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+export const TableHead: React_3.ForwardRefExoticComponent<
+ React_3.ThHTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+export const TableHeader: React_3.ForwardRefExoticComponent<
+ React_3.HTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+export const TableRow: React_3.ForwardRefExoticComponent<
+ React_3.HTMLAttributes &
+ React_3.RefAttributes
+>;
+
+// @public (undocumented)
+const Text_2: React_2.ForwardRefExoticComponent<
+ TextProps & React_2.RefAttributes
+>;
+export { Text_2 as Text };
+
+// @public (undocumented)
+export interface TextProps {
+ // (undocumented)
+ children: ReactNode;
+ // (undocumented)
+ style?: CSSProperties;
+ // (undocumented)
+ variant?:
+ | 'subtitle'
+ | 'body'
+ | 'caption'
+ | 'label'
+ | Partial>;
+ // (undocumented)
+ weight?: 'regular' | 'bold' | Partial>;
+}
+
+// @public (undocumented)
+export const useCanon: () => CanonContextProps;
+
+// @public (undocumented)
+export interface UtilityProps extends SpaceProps {
+ // (undocumented)
+ alignItems?: AlignItems | Partial>;
+ // (undocumented)
+ border?: Border | Partial>;
+ // (undocumented)
+ borderRadius?: BorderRadius | Partial>;
+ // (undocumented)
+ colEnd?: Columns | 'auto' | Partial>;
+ // (undocumented)
+ colSpan?: Columns | 'full' | Partial>;
+ // (undocumented)
+ colStart?: Columns | 'auto' | Partial>;
+ // (undocumented)
+ columns?: Columns | Partial>;
+ // (undocumented)
+ display?: Display | Partial>;
+ // (undocumented)
+ flexDirection?: FlexDirection | Partial>;
+ // (undocumented)
+ flexWrap?: FlexWrap | Partial>;
+ // (undocumented)
+ gap?: Space | Partial>;
+ // (undocumented)
+ justifyContent?: JustifyContent | Partial>;
+ // (undocumented)
+ rowSpan?: Columns | 'full' | Partial>;
+}
```
diff --git a/packages/canon/src/components/Box/Box.stories.tsx b/packages/canon/src/components/Box/Box.stories.tsx
index 6f15d984e1..d11f9fbab7 100644
--- a/packages/canon/src/components/Box/Box.stories.tsx
+++ b/packages/canon/src/components/Box/Box.stories.tsx
@@ -17,22 +17,8 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Box } from './Box';
-import {
- listResponsiveValues,
- argTypesSpacing,
- argTypesColor,
-} from '../../../docs/utils/argTypes';
-import { boxProperties } from './sprinkles.css';
-
-const argTypesBox = Object.keys(boxProperties.styles).reduce<
- Record
->((acc, n) => {
- acc[n] = {
- control: 'select',
- options: listResponsiveValues(n as keyof typeof boxProperties.styles),
- };
- return acc;
-}, {});
+import { Stack } from '../Stack';
+import { Inline } from '../Inline';
const meta = {
title: 'Components/Box',
@@ -41,9 +27,6 @@ const meta = {
layout: 'centered',
},
argTypes: {
- ...argTypesSpacing,
- ...argTypesColor,
- ...argTypesBox,
as: {
control: { type: 'select' },
options: ['div', 'span', 'article', 'section'],
@@ -52,132 +35,381 @@ const meta = {
control: false,
},
},
- args: {
- as: 'div',
- background: 'elevation1',
- borderRadius: 'small',
- children: 'Basic Box',
- display: 'block',
- padding: 'sm',
- },
} satisfies Meta;
export default meta;
type Story = StoryObj;
-export const Basic: Story = {
- args: {},
+export const Default: Story = {
+ args: {
+ style: {
+ width: '64px',
+ height: '64px',
+ background: '#eaf2fd',
+ borderRadius: '4px',
+ border: '1px solid #2563eb',
+ color: '#2563eb',
+ backgroundImage:
+ 'url("data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E")',
+ },
+ },
};
-export const Responsive: Story = {
- render: () => (
-
- Responsive Box
-
+export const Display: Story = {
+ args: {
+ style: {
+ ...Default.args?.style,
+ width: 'auto',
+ height: 'auto',
+ padding: '8px',
+ },
+ },
+ render: args => (
+
+
+
+ Block
+
+
+ Flex
+
+
+ Inline
+
+
+ None
+
+
+
+ Responsive
+
+
),
};
-export const FlexContainer: Story = {
- render: () => (
-
-
- Item 1
+export const FlexDirection: Story = {
+ args: {
+ style: {
+ ...Default.args?.style,
+ width: 'auto',
+ height: 'auto',
+ padding: '8px',
+ },
+ display: 'flex',
+ gap: 'xs',
+ },
+ render: args => (
+
+
+ Row
+ Row
-
- Item 2
+
+ Column
+ Column
-
- Item 3
+
+ Responsive
+ Flex Direction
-
+
),
};
-export const Nested: Story = {
- render: () => (
-
-
- Header
+export const JustifyContent: Story = {
+ args: {
+ style: {
+ ...Default.args?.style,
+ width: '200px',
+ height: 'auto',
+ padding: '8px',
+ },
+ display: 'flex',
+ gap: 'xs',
+ },
+ render: args => (
+
+
+ Flex Start
+
+
+ Center
+
+
+ Flex End
+
+
+ Space
+ Around
+
+
+ Space
+ Between
-
- Sidebar
+ Responsive
+ Spacing
+
+
+ ),
+};
+
+export const AlignItems: Story = {
+ args: {
+ style: {
+ ...Default.args?.style,
+ width: '200px',
+ height: '100px',
+ padding: '8px',
+ },
+ display: 'flex',
+ gap: 'xs',
+ },
+ render: args => (
+
+
+ Flex Start
+
+
+ Center
+
+
+ Flex End
+
+
+ Responsive
+ Spacing
+
+
+ ),
+};
+
+const styleInsideBox = {
+ background: 'rgb(196, 202, 251)',
+ color: 'white',
+ borderRadius: '4px',
+};
+
+export const Padding: Story = {
+ args: {
+ style: {
+ background: '#1f47ff',
+ color: 'white',
+ borderRadius: '4px',
+ padding: '12px 12px',
+ },
+ },
+ render: args => (
+
+
+
+ Padding
-
- Main Content
+
+ Padding X
-
-
- Footer
-
-
+
+ Padding Y
+
+
+
+
+ Padding Top
+
+
+ Padding Right
+
+
+ Padding Bottom
+
+
+ Padding Left
+
+
+
),
};
-export const Alignment: Story = {
- render: () => (
-
-
- Centered Content
-
-
+export const Margin: Story = {
+ args: {
+ style: {
+ background: '#1f47ff',
+ color: 'white',
+ borderRadius: '4px',
+ padding: '12px 12px',
+ },
+ },
+ render: args => (
+
+
+
+
+ Margin
+
+
+
+
+ Margin X
+
+
+
+
+ Margin Y
+
+
+
+
+
+
+ Margin Top
+
+
+
+
+ Margin Right
+
+
+
+
+ Margin Bottom
+
+
+
+
+ Margin Left
+
+
+
+
),
};
-// Example showing different spacing combinations
-export const Spacing: Story = {
- render: () => (
-
-
- Small Padding
+export const FlexWrap: Story = {
+ args: {
+ style: {
+ ...Default.args?.style,
+ width: '200px',
+ height: 'auto',
+ padding: '8px',
+ },
+ display: 'flex',
+ gap: 'xs',
+ },
+ render: args => (
+
+
+ One
+ Two
+ Three
+ Four
+ Five
+ Six
-
- Medium Padding
+
+ One
+ Two
+ Three
+ Four
+ Five
+ Six
-
- Large Padding
+
+ One
+ Two
+ Three
+ Four
+ Five
+ Six
-
- Mixed Padding
-
-
+
),
};
-// Example showing different display values
-export const DisplayVariants: Story = {
- render: () => (
-
-
- Display Block
+export const BorderRadius: Story = {
+ args: {
+ style: {
+ width: '64px',
+ height: '64px',
+ background: '#eaf2fd',
+ border: '1px solid #2563eb',
+ color: '#2563eb',
+ backgroundImage:
+ 'url("data:image/svg+xml,%3Csvg%20width%3D%226%22%20height%3D%226%22%20viewBox%3D%220%200%206%206%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22%232563eb%22%20fill-opacity%3D%220.3%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M5%200h1L0%206V5zM6%205v1H5z%22/%3E%3C/g%3E%3C/svg%3E")',
+ padding: '4px 8px',
+ },
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ render: args => (
+
+
+ 2xs
-
- Display Flex
+
+ xs
-
- Display Inline
+
+ sm
-
+
+ md
+
+
+ xl
+
+
+ 2xl
+
+
+ ),
+};
+
+export const Border: Story = {
+ args: {
+ style: {
+ background: 'var(--canon-surface-1)',
+ color: 'var(--canon-text-primary)',
+ padding: '4px 8px',
+ width: '80px',
+ height: '32px',
+ },
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderRadius: 'xs',
+ },
+ render: args => (
+
+
+ Base
+
+
+ Error
+
+
+ Warning
+
+
+ Selected
+
+
+ None
+
+
),
};
diff --git a/packages/canon/src/components/Box/Box.tsx b/packages/canon/src/components/Box/Box.tsx
index d134abff35..020f2b6fbb 100644
--- a/packages/canon/src/components/Box/Box.tsx
+++ b/packages/canon/src/components/Box/Box.tsx
@@ -14,26 +14,26 @@
* limitations under the License.
*/
-import { createElement } from 'react';
-import { boxSprinkles } from './sprinkles.css';
-import { base } from './box.css';
+import { createElement, forwardRef } from 'react';
import { BoxProps } from './types';
+import { getClassNames } from '../../utils/getClassNames';
/** @public */
-export const Box = (props: BoxProps) => {
+export const Box = forwardRef((props, ref) => {
const { as = 'div', className, style, children, ...restProps } = props;
- // Generate the list of class names
- const sprinklesClassName = boxSprinkles(restProps);
+ // Generate utility class names
+ const utilityClassNames = getClassNames(restProps);
// Combine the base class name, the sprinkles class name, and any additional class names
- const classNames = [base, sprinklesClassName, className]
+ const classNames = ['canon-box', utilityClassNames, className]
.filter(Boolean)
.join(' ');
return createElement(as, {
+ ref,
className: classNames,
style,
children,
});
-};
+});
diff --git a/packages/canon/src/components/Box/Docs.mdx b/packages/canon/src/components/Box/Docs.mdx
index dac10952cf..ee30e17305 100644
--- a/packages/canon/src/components/Box/Docs.mdx
+++ b/packages/canon/src/components/Box/Docs.mdx
@@ -1,9 +1,8 @@
-import { Canvas, Meta, Unstyled } from '@storybook/blocks';
+import { Meta, Unstyled, Source, Canvas } from '@storybook/blocks';
import * as BoxStories from './Box.stories';
import { Title, Text } from '../../../docs/components';
-import { Padding } from './docs/padding';
-import { PropsTable } from './docs/props-table';
-import { SpacingTable } from './docs/spacing-table';
+import { PropsTable } from '../../../docs/components';
+import { spacePropsList } from '../../../docs/spaceProps';
@@ -12,21 +11,102 @@ import { SpacingTable } from './docs/spacing-table';
Box
Box is the lowest-level component in Canon. We use it internally to build all
- of our components. It is a wrapper around the HTML `` element and
- provides a consistent API for styling and layout. You'll find below a list of all the available properties.
+ of our components. It provides a consistent API for styling and layout.
-
+
Usage
+
Padding & Margin
+Hello World!
+`} language="tsx" dark />
+
+API reference
+
+Box
+ This is the Box component, our lowest-level component. Here are all the
+ available properties.
+
+
+
+
+
Padding and margin are used to create space around your component using our
predefined spacing tokens. We would recommend to use padding over margin to
avoid collapsing margins but both are available.
-
+
-
+
+
+Examples
+Here are some examples of how you can use the Box component.
+
+Simple example
+A simple example of how to use the Box component.
+Hello World`}
+ language="tsx"
+ dark
+/>
+
+Responsive
+
+ Most of the values can be defined per breakpoint, making it easy to create
+ responsive designs.
+
+Hello World`}
+ language="tsx"
+ dark
+/>
diff --git a/packages/canon/src/components/Box/docs/padding.tsx b/packages/canon/src/components/Box/docs/padding.tsx
deleted file mode 100644
index 86a7c801a2..0000000000
--- a/packages/canon/src/components/Box/docs/padding.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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 React from 'react';
-import { Inline } from '../../Inline';
-import { Box } from '../Box';
-
-const FakeBox = ({ children }: { children: string }) => (
-
- {children}
-
-);
-
-export const Padding = () => {
- return (
-
-
-
- padding
-
-
- paddingX
-
-
- paddingY
-
-
-
-
- paddingTop
-
-
- paddingBottom
-
-
- paddingLeft
-
-
- paddingRight
-
-
-
- );
-};
diff --git a/packages/canon/src/components/Box/docs/props-table.tsx b/packages/canon/src/components/Box/docs/props-table.tsx
deleted file mode 100644
index 9979701f2e..0000000000
--- a/packages/canon/src/components/Box/docs/props-table.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 React from 'react';
-import * as Table from '../../../../docs/components';
-import { Chip } from '../../../../docs/components';
-import { listResponsiveValues } from '../../../../docs/utils/argTypes';
-import { boxProperties } from '../sprinkles.css';
-
-export const PropsTable = () => {
- return (
-
-
-
- Prop
- Type
-
-
-
- {Object.keys(boxProperties.styles)
- .filter(
- n =>
- ![
- 'padding',
- 'paddingX',
- 'paddingY',
- 'paddingLeft',
- 'paddingRight',
- 'paddingTop',
- 'paddingBottom',
- 'margin',
- 'marginX',
- 'marginY',
- 'marginLeft',
- 'marginRight',
- 'marginTop',
- 'marginBottom',
- ].includes(n),
- )
- .map(n => (
-
-
- {n}
-
-
- {listResponsiveValues(
- n as keyof typeof boxProperties.styles,
- ).map(value => (
- {value}
- ))}
-
-
- ))}
-
-
- );
-};
diff --git a/packages/canon/src/components/Box/docs/spacing-table.tsx b/packages/canon/src/components/Box/docs/spacing-table.tsx
deleted file mode 100644
index 93c38457d4..0000000000
--- a/packages/canon/src/components/Box/docs/spacing-table.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 React from 'react';
-import * as Table from '../../../../docs/components';
-import { Chip } from '../../../../docs/components';
-import { spacingProperties } from '../../../layout/sprinkles.css';
-import { space } from '../../../layout/properties';
-
-export const SpacingTable = () => {
- return (
-
-
-
- Prop
- Type
-
-
-
- {Object.keys(spacingProperties.styles)
- .filter(n =>
- [
- 'padding',
- 'paddingX',
- 'paddingY',
- 'paddingLeft',
- 'paddingRight',
- 'paddingTop',
- 'paddingBottom',
- 'margin',
- 'marginX',
- 'marginY',
- 'marginLeft',
- 'marginRight',
- 'marginTop',
- 'marginBottom',
- ].includes(n),
- )
- .map(n => (
-
-
- {n}
-
-
- {Object.keys(space).map(value => (
- {value}
- ))}
-
-
- ))}
-
-
- );
-};
diff --git a/packages/canon/src/components/Box/index.tsx b/packages/canon/src/components/Box/index.tsx
index e4f1867edc..d47e653dfd 100644
--- a/packages/canon/src/components/Box/index.tsx
+++ b/packages/canon/src/components/Box/index.tsx
@@ -15,4 +15,3 @@
*/
export { Box } from './Box';
export type * from './types';
-export { breakpoints, space, themes } from '../../layout/properties';
diff --git a/packages/canon/src/components/Box/sprinkles.css.ts b/packages/canon/src/components/Box/sprinkles.css.ts
deleted file mode 100644
index df5664029b..0000000000
--- a/packages/canon/src/components/Box/sprinkles.css.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
-import { breakpoints } from '../../layout/properties';
-import { colorProperties, spacingProperties } from '../../layout/sprinkles.css';
-
-export const boxProperties = defineProperties({
- conditions: breakpoints,
- defaultCondition: 'xs',
- responsiveArray: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'],
- properties: {
- flexDirection: ['row', 'column'],
- justifyContent: [
- 'stretch',
- 'flex-start',
- 'center',
- 'flex-end',
- 'space-around',
- 'space-between',
- ],
- alignItems: ['stretch', 'flex-start', 'center', 'flex-end'],
- borderRadius: {
- none: 0,
- small: '4px',
- medium: '8px',
- full: '9999px',
- },
- boxShadow: {
- small: 'var(--canon-box-shadow-small)',
- medium: 'var(--canon-box-shadow-medium)',
- large: 'var(--canon-box-shadow-large)',
- },
- border: {
- none: 'none',
- thin: '1px solid var(--canon-outline)',
- error: '1px solid var(--canon-error)',
- },
- display: ['none', 'flex', 'block', 'inline'],
- flexWrap: ['wrap', 'nowrap'],
- },
-});
-
-export const boxSprinkles = createSprinkles(
- spacingProperties,
- boxProperties,
- colorProperties,
-);
diff --git a/packages/canon/src/components/Box/styles.css b/packages/canon/src/components/Box/styles.css
new file mode 100644
index 0000000000..a90ce578cd
--- /dev/null
+++ b/packages/canon/src/components/Box/styles.css
@@ -0,0 +1,4 @@
+.canon-box {
+ font-family: 'var(--canon-font-regular)';
+ color: 'var(--canon-text-primary)';
+}
diff --git a/packages/canon/src/components/Box/types.ts b/packages/canon/src/components/Box/types.ts
index 2ba5929fdd..a55c856caf 100644
--- a/packages/canon/src/components/Box/types.ts
+++ b/packages/canon/src/components/Box/types.ts
@@ -14,76 +14,12 @@
* limitations under the License.
*/
-import { Breakpoint, SpaceProps, ColorProps } from '../../layout/types';
+import type { UtilityProps } from '../../types';
/** @public */
-export type DisplayProps =
- | 'flex'
- | 'none'
- | 'inline'
- | 'block'
- | Partial>;
-
-/** @public */
-export type FlexDirectionProps =
- | 'row'
- | 'column'
- | Partial>;
-
-/** @public */
-export type FlexWrapProps =
- | 'wrap'
- | 'nowrap'
- | Partial>;
-
-/** @public */
-export type JustifyContentProps =
- | 'stretch'
- | 'flex-start'
- | 'center'
- | 'flex-end'
- | 'space-around'
- | 'space-between'
- | Partial<
- Record<
- Breakpoint,
- | 'stretch'
- | 'flex-start'
- | 'center'
- | 'flex-end'
- | 'space-around'
- | 'space-between'
- >
- >;
-
-/** @public */
-export type AlignItemsProps =
- | 'stretch'
- | 'flex-start'
- | 'center'
- | 'flex-end'
- | Partial<
- Record
- >;
-
-/** @public */
-export type BorderRadiusProps =
- | 'none'
- | 'small'
- | 'medium'
- | 'full'
- | Partial>;
-
-/** @public */
-export interface BoxProps extends SpaceProps, ColorProps {
+export interface BoxProps extends UtilityProps {
as?: keyof JSX.IntrinsicElements;
children?: React.ReactNode;
- display?: DisplayProps;
- flexDirection?: FlexDirectionProps;
- flexWrap?: FlexWrapProps;
- justifyContent?: JustifyContentProps;
- alignItems?: AlignItemsProps;
- borderRadius?: BorderRadiusProps;
className?: string;
style?: React.CSSProperties;
}
diff --git a/packages/canon/src/components/Button/Button.stories.tsx b/packages/canon/src/components/Button/Button.stories.tsx
index 7dddbd033b..728098970c 100644
--- a/packages/canon/src/components/Button/Button.stories.tsx
+++ b/packages/canon/src/components/Button/Button.stories.tsx
@@ -17,15 +17,14 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
-import { Box } from '../Box/Box';
+import { Inline } from '../Inline';
+import { Stack } from '../Stack';
+import { Text } from '../Text';
+import { ButtonProps } from './types';
const meta = {
title: 'Components/Button',
component: Button,
- parameters: {
- layout: 'centered',
- },
- tags: ['autodocs'],
argTypes: {
size: {
control: 'select',
@@ -40,28 +39,41 @@ const meta = {
export default meta;
type Story = StoryObj;
-export const Primary: Story = {
+export const Variants: Story = {
args: {
- children: 'Primary button',
+ children: 'Button',
},
-};
-
-export const Secondary: Story = {
- args: {
- children: 'Secondary button',
- variant: 'secondary',
+ parameters: {
+ argTypes: {
+ variant: {
+ control: false,
+ },
+ },
},
+ render: () => (
+
+
+
+
+
+ ),
};
export const Sizes: Story = {
args: {
children: 'Button',
},
- render: args => (
-
-
-
-
+ render: () => (
+
+
+
+
),
};
@@ -70,11 +82,11 @@ export const WithIcons: Story = {
children: 'Button',
},
render: args => (
-
+
-
-
-
+
+
+
),
};
@@ -83,11 +95,11 @@ export const FullWidth: Story = {
children: 'Button',
},
render: args => (
-
+
-
-
-
+
+
+
),
};
@@ -98,24 +110,61 @@ export const Disabled: Story = {
},
};
-export const CustomTheme: Story = {
+export const Responsive: Story = {
args: {
- children: 'Custom Button',
+ children: 'Button',
+ variant: {
+ xs: 'primary',
+ sm: 'secondary',
+ md: 'tertiary',
+ },
+ size: {
+ xs: 'small',
+ sm: 'medium',
+ },
},
- decorators: [
- Story => (
-
-
-
- ),
- ],
+};
+
+const variants: string[] = ['primary', 'secondary', 'tertiary'];
+
+export const Playground: Story = {
+ args: {
+ children: 'Button',
+ },
+ render: () => (
+
+ {variants.map(variant => (
+
+ {variant}
+ {['small', 'medium'].map(size => (
+
+
+
+
+
+ ))}
+
+ ))}
+
+ ),
};
diff --git a/packages/canon/src/components/Button/Button.tsx b/packages/canon/src/components/Button/Button.tsx
index 020d0adce4..081d09a1d5 100644
--- a/packages/canon/src/components/Button/Button.tsx
+++ b/packages/canon/src/components/Button/Button.tsx
@@ -14,46 +14,58 @@
* limitations under the License.
*/
-import React from 'react';
-import { button } from './button.css';
-import { Icon } from '../Icon/Icon';
-import type { IconNames } from '../Icon/types';
-
-/**
- * Properties for {@link Button}
- *
- * @public
- */
-export interface ButtonProps {
- size?: 'small' | 'medium';
- variant?: 'primary' | 'secondary';
- children: React.ReactNode;
- disabled?: boolean;
- iconStart?: IconNames;
- iconEnd?: IconNames;
-}
+import React, { forwardRef } from 'react';
+import { Icon } from '../Icon';
+import { ButtonProps } from './types';
+import { useCanon } from '../../contexts/canon';
/** @public */
-export const Button = ({
- size = 'medium',
- variant = 'primary',
- children,
- disabled,
- iconStart,
- iconEnd,
- ...props
-}: ButtonProps) => {
- return (
-
- );
-};
+export const Button = forwardRef(
+ (props: ButtonProps, ref) => {
+ const {
+ size = 'medium',
+ variant = 'primary',
+ disabled,
+ iconStart,
+ iconEnd,
+ children,
+ style,
+ ...rest
+ } = props;
+
+ const { getResponsiveValue } = useCanon();
+
+ // Get the responsive value for the variant
+ const responsiveSize = getResponsiveValue(size);
+ const responsiveVariant = getResponsiveValue(variant);
+
+ return (
+
+ );
+ },
+);
export default Button;
diff --git a/packages/canon/src/components/Button/Docs.mdx b/packages/canon/src/components/Button/Docs.mdx
new file mode 100644
index 0000000000..ae90b5fd80
--- /dev/null
+++ b/packages/canon/src/components/Button/Docs.mdx
@@ -0,0 +1,135 @@
+import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
+import * as ButtonStories from './Button.stories';
+import { Title, Text } from '../../../docs/components';
+import { PropsTable } from '../../../docs/components/PropsTable/PropsTable';
+
+
+
+
+
+Button
+A button component that can be used to trigger actions.
+
+
+
+Usage
+Click me
+`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+Examples
+
+Variants
+Here's a view when buttons have different variants.
+
+
+
+
+
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+Sizes
+Here's a view when buttons have different sizes.
+
+
+
+
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+With Icons
+Here's a view when buttons have icons.
+
+
+
+
+
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+Full width
+Here's a view when buttons are full width.
+
+
+
+
+
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+Disabled
+Here's a view when buttons are disabled.
+
+
+
+Button`} language="tsx" dark />
+
+Responsive
+Here's a view when buttons are responsive.
+
+
+
+
+ Button
+`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Button/button.css.ts b/packages/canon/src/components/Button/button.css.ts
deleted file mode 100644
index 9d6c8867c3..0000000000
--- a/packages/canon/src/components/Button/button.css.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 { recipe } from '@vanilla-extract/recipes';
-
-export const button = recipe({
- base: {
- all: 'unset',
- display: 'inline-flex',
- alignItems: 'center',
- userSelect: 'none',
- fontFamily: 'var(--canon-font-sans)',
- fontWeight: 600,
- fontSize: '0.875rem',
- lineHeight: '1.5',
- padding: 0,
- transition: 'all 150ms ease',
- cursor: 'pointer',
- },
- variants: {
- variant: {
- primary: {
- backgroundColor: 'var(--button-primary-background-color)',
- color: 'var(--button-primary-text-color)',
- borderRadius: 'var(--button-primary-border-radius)',
- border: `1px solid var(--button-primary-border-color)`,
- '&:hover': {
- backgroundColor: 'var(--button-primary-background-color-hover)',
- borderColor: 'var(--button-primary-border-color-hover)',
- },
- },
- secondary: {
- backgroundColor: 'transparent',
- color: 'var(--button-secondary-text-color)',
- borderRadius: 'var(--button-secondary-border-radius)',
- border: `1px solid var(--button-secondary-border-color)`,
- '&:hover': {
- backgroundColor: 'var(--button-secondary-background-color-hover)',
- borderColor: 'var(--button-secondary-border-color-hover)',
- },
- },
- },
- size: {
- small: {
- paddingLeft: '16px',
- paddingRight: '16px',
- height: 'var(--button-size-small)',
- },
- medium: {
- paddingLeft: '32px',
- paddingRight: '32px',
- height: 'var(--button-size-medium)',
- },
- },
- disabled: {
- true: {
- opacity: 0.3,
- cursor: 'not-allowed',
- },
- },
- },
-});
diff --git a/packages/canon/src/components/Button/index.tsx b/packages/canon/src/components/Button/index.tsx
index bc6714754d..c323ba0329 100644
--- a/packages/canon/src/components/Button/index.tsx
+++ b/packages/canon/src/components/Button/index.tsx
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { Button } from './Button';
-export type { ButtonProps } from './Button';
+export type { ButtonProps } from './types';
diff --git a/packages/canon/src/components/Button/styles.css b/packages/canon/src/components/Button/styles.css
index 766390a862..7af027ddcd 100644
--- a/packages/canon/src/components/Button/styles.css
+++ b/packages/canon/src/components/Button/styles.css
@@ -14,44 +14,70 @@
* limitations under the License.
*/
-:root {
- --button-primary-background-color: #1ed760;
- --button-primary-background-color-hover: #3be477;
- --button-primary-background-color-active: #1abc54;
- --button-primary-border-color: #1ed760;
- --button-primary-border-color-hover: #3be477;
- --button-primary-border-color-active: #1abc54;
- --button-primary-text-color: #000;
- --button-primary-border-radius: 9999px;
- --button-secondary-background-color: transparent;
- --button-secondary-background-color-hover: transparent;
- --button-secondary-background-color-active: rgba(0, 0, 0, 0.03);
- --button-secondary-border-color: #000;
- --button-secondary-border-color-hover: #000;
- --button-secondary-border-color-active: #000;
- --button-secondary-text-color: #000;
- --button-secondary-border-radius: 9999px;
- --button-size-small: 32px;
- --button-size-medium: 48px;
+.cn-button {
+ all: unset;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ user-select: none;
+ font-family: var(--canon-font-regular);
+ font-weight: var(--canon-font-weight-bold);
+ font-size: var(--canon-font-size-body);
+ padding: 0;
+ transition: all 150ms ease;
+ cursor: pointer;
+ border-radius: 8px;
}
-[data-theme='dark'] {
- --button-primary-background-color: #1ed760;
- --button-primary-background-color-hover: #3be477;
- --button-primary-background-color-active: #1abc54;
- --button-primary-border-color: #1ed760;
- --button-primary-border-color-hover: #3be477;
- --button-primary-border-color-active: #1abc54;
- --button-primary-text-color: #000;
- --button-primary-border-radius: 9999px;
- --button-secondary-background-color: transparent;
- --button-secondary-background-color-hover: transparent;
- --button-secondary-background-color-active: rgba(255, 255, 255, 0.1);
- --button-secondary-border-color: #fff;
- --button-secondary-border-color-hover: #fff;
- --button-secondary-border-color-active: #fff;
- --button-secondary-text-color: #fff;
- --button-secondary-border-radius: 9999px;
- --button-size-small: 32px;
- --button-size-medium: 48px;
+.cn-button-primary {
+ background-color: var(--canon-accent);
+ color: var(--canon-text-primary-on-accent);
+
+ &:hover {
+ background-color: transparent;
+ box-shadow: inset 0 0 0 1px var(--canon-border-focus);
+ color: var(--canon-text-primary);
+ }
+}
+
+.cn-button-secondary {
+ background-color: transparent;
+ box-shadow: inset 0 0 0 1px var(--canon-border-base);
+ color: var(--canon-text-primary);
+
+ &:hover {
+ box-shadow: inset 0 0 0 1px var(--canon-border-hover);
+ }
+}
+
+.cn-button-tertiary {
+ background-color: transparent;
+ color: var(--canon-text-primary);
+
+ &:hover {
+ color: var(--canon-text-secondary);
+ }
+}
+
+.cn-button-small {
+ padding-left: 6px;
+ padding-right: 6px;
+ height: 32px;
+}
+
+.cn-button-medium {
+ padding-left: 8px;
+ padding-right: 8px;
+ height: 40px;
+}
+
+.cn-button-content {
+ display: flex;
+ align-items: center;
+ gap: var(--canon-spacing-xs);
+ font-weight: var(--canon-font-weight-bold);
+}
+
+.cn-button-content-icon-both {
+ flex: 1;
}
diff --git a/packages/canon/src/components/Button/types.ts b/packages/canon/src/components/Button/types.ts
new file mode 100644
index 0000000000..96a11df84f
--- /dev/null
+++ b/packages/canon/src/components/Button/types.ts
@@ -0,0 +1,35 @@
+/*
+ * 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 { IconNames } from '../Icon';
+import type { Breakpoint } from '../../types';
+/**
+ * Properties for {@link Button}
+ *
+ * @public
+ */
+export interface ButtonProps {
+ size?: 'small' | 'medium' | Partial>;
+ variant?:
+ | 'primary'
+ | 'secondary'
+ | 'tertiary'
+ | Partial>;
+ children: React.ReactNode;
+ disabled?: boolean;
+ iconStart?: IconNames;
+ iconEnd?: IconNames;
+ style?: React.CSSProperties;
+}
diff --git a/packages/canon/src/components/Checkbox/Checkbox.stories.tsx b/packages/canon/src/components/Checkbox/Checkbox.stories.tsx
new file mode 100644
index 0000000000..574783578c
--- /dev/null
+++ b/packages/canon/src/components/Checkbox/Checkbox.stories.tsx
@@ -0,0 +1,64 @@
+/*
+ * 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 React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { Checkbox } from './Checkbox';
+import { Inline } from '../Inline';
+import { Stack } from '../Stack';
+import { Text } from '../Text';
+
+const meta = {
+ title: 'Components/Checkbox',
+ component: Checkbox,
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ label: 'Accept terms and conditions',
+ },
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+
+
+
+
+
+ ),
+};
+
+export const Playground: Story = {
+ render: () => (
+
+ All variants
+
+
+
+
+
+
+
+ ),
+};
diff --git a/packages/canon/src/components/Checkbox/Checkbox.tsx b/packages/canon/src/components/Checkbox/Checkbox.tsx
new file mode 100644
index 0000000000..a23ccc01ce
--- /dev/null
+++ b/packages/canon/src/components/Checkbox/Checkbox.tsx
@@ -0,0 +1,64 @@
+/*
+ * 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 React from 'react';
+
+import { Checkbox as CheckboxPrimitive } from '@base-ui-components/react/checkbox';
+import { Icon } from '@backstage/canon';
+import type { CheckboxProps } from './types';
+
+/** @public */
+export const Checkbox = React.forwardRef(
+ (props, ref) => {
+ const {
+ label,
+ checked,
+ onChange,
+ disabled,
+ required,
+ className,
+ name,
+ value,
+ style,
+ } = props;
+
+ const checkboxElement = (
+
+
+
+
+
+ );
+
+ return label ? (
+
+ ) : (
+ checkboxElement
+ );
+ },
+);
diff --git a/packages/canon/src/components/Checkbox/Docs.mdx b/packages/canon/src/components/Checkbox/Docs.mdx
new file mode 100644
index 0000000000..9826708888
--- /dev/null
+++ b/packages/canon/src/components/Checkbox/Docs.mdx
@@ -0,0 +1,70 @@
+import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
+import * as CheckboxStories from './Checkbox.stories';
+import { Title, Text } from '../../../docs/components';
+import { PropsTable } from '../../../docs/components/PropsTable';
+
+
+
+
+
+Checkbox
+A checkbox component that can be used to trigger actions.
+
+
+
+Usage
+
+`} language="tsx" dark />
+
+
+ API reference
+
+
+ void",
+ responsive: false,
+ },
+ disabled: {
+ type: 'boolean',
+ responsive: false,
+ },
+ required: {
+ type: 'boolean',
+ responsive: false,
+ },
+ name: {
+ type: 'string',
+ responsive: false,
+ },
+ value: {
+ type: 'string',
+ responsive: false,
+ },
+ className: {
+ type: 'string',
+ responsive: false,
+ },
+ style: {
+ type: 'CSSProperties',
+ responsive: false,
+ },
+ }}
+/>
+
+
diff --git a/packages/canon/src/components/Checkbox/index.ts b/packages/canon/src/components/Checkbox/index.ts
new file mode 100644
index 0000000000..f6dfbf6beb
--- /dev/null
+++ b/packages/canon/src/components/Checkbox/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+export { Checkbox } from './Checkbox';
+export type { CheckboxProps } from './types';
diff --git a/packages/canon/src/components/Checkbox/styles.css b/packages/canon/src/components/Checkbox/styles.css
new file mode 100644
index 0000000000..c1f285f7c7
--- /dev/null
+++ b/packages/canon/src/components/Checkbox/styles.css
@@ -0,0 +1,41 @@
+.checkbox-label {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap: var(--canon-spacing-xs);
+ font-size: var(--canon-font-size-xs);
+ font-family: var(--canon-font-regular);
+ color: var(--canon-text-primary);
+ user-select: none;
+
+ &:hover {
+ & .checkbox {
+ box-shadow: inset 0 0 0 1px var(--canon-border-hover);
+ }
+ }
+}
+
+.checkbox {
+ all: unset;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 1rem;
+ height: 1rem;
+ box-shadow: inset 0 0 0 1px var(--canon-border-base);
+ cursor: pointer;
+ border-radius: 2px;
+ transition: all 0.2s ease-in-out;
+
+ &[data-checked] {
+ background-color: var(--canon-accent);
+ }
+}
+
+.checkbox-indicator {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--canon-text-primary-on-accent);
+}
diff --git a/packages/canon/src/components/Checkbox/types.ts b/packages/canon/src/components/Checkbox/types.ts
new file mode 100644
index 0000000000..0240954afa
--- /dev/null
+++ b/packages/canon/src/components/Checkbox/types.ts
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/** @public */
+export interface CheckboxProps {
+ label?: string;
+ defaultChecked?: boolean;
+ checked?: boolean;
+ onChange?: (checked: boolean) => void;
+ disabled?: boolean;
+ required?: boolean;
+ className?: string;
+ name?: string;
+ value?: string;
+ style?: React.CSSProperties;
+}
diff --git a/packages/canon/src/components/Container/Container.stories.tsx b/packages/canon/src/components/Container/Container.stories.tsx
new file mode 100644
index 0000000000..c9f468048e
--- /dev/null
+++ b/packages/canon/src/components/Container/Container.stories.tsx
@@ -0,0 +1,69 @@
+/*
+ * 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 React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { Box } from '../Box/Box';
+import { Container } from './Container';
+
+const meta = {
+ title: 'Components/Container',
+ component: Container,
+ argTypes: {
+ children: {
+ control: false,
+ },
+ className: {
+ control: 'text',
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+const DecorativeBox = () => (
+
+);
+
+export const Default: Story = {
+ parameters: {
+ layout: 'fullscreen',
+ },
+ render: args => (
+
+
+
+ ),
+};
+
+export const Preview: Story = {
+ render: () => (
+
+
+
+ ),
+};
diff --git a/packages/canon/src/components/Container/Container.tsx b/packages/canon/src/components/Container/Container.tsx
new file mode 100644
index 0000000000..bea7b4caf1
--- /dev/null
+++ b/packages/canon/src/components/Container/Container.tsx
@@ -0,0 +1,39 @@
+/*
+ * 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 React, { forwardRef } from 'react';
+import { ContainerProps } from './types';
+import { getClassNames } from '../../utils/getClassNames';
+
+/** @public */
+export const Container = forwardRef(
+ (props, ref) => {
+ const { children, className, style, ...restProps } = props;
+
+ // Generate utility class names
+ const utilityClassNames = getClassNames(restProps);
+
+ // Combine the base class name, the sprinkles class name, and any additional class names
+ const classNames = ['canon-container', utilityClassNames, className]
+ .filter(Boolean)
+ .join(' ');
+
+ return (
+
+ {children}
+
+ );
+ },
+);
diff --git a/packages/canon/src/components/Container/Docs.mdx b/packages/canon/src/components/Container/Docs.mdx
new file mode 100644
index 0000000000..05a0600813
--- /dev/null
+++ b/packages/canon/src/components/Container/Docs.mdx
@@ -0,0 +1,99 @@
+import { Meta, Unstyled, Source } from '@storybook/blocks';
+import * as ContainerStories from './Container.stories';
+import { Title, Text, PropsTable, getProps } from '../../../docs/components';
+import { spacePropsList } from '../../../docs/spaceProps';
+
+
+
+
+
+Container
+
+
+ The container component let you use our default max-width and center the
+ content on the page.
+
+
+Usage
+Hello World!
+`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+Examples
+
+Simple
+A simple example of how to use the Container component.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+Responsive padding & margin
+
+ The Container component also supports responsive values, making it easy to
+ create responsive designs.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Container/index.tsx b/packages/canon/src/components/Container/index.tsx
new file mode 100644
index 0000000000..81614c352d
--- /dev/null
+++ b/packages/canon/src/components/Container/index.tsx
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+export { Container } from './Container';
+export type { ContainerProps } from './types';
diff --git a/packages/canon/src/components/Container/styles.css b/packages/canon/src/components/Container/styles.css
new file mode 100644
index 0000000000..f3ebd64f52
--- /dev/null
+++ b/packages/canon/src/components/Container/styles.css
@@ -0,0 +1,5 @@
+.canon-container {
+ max-width: var(--canon-container-max-width);
+ margin: 0 auto;
+ padding: 0 var(--canon-container-padding);
+}
diff --git a/packages/canon/src/components/Container/types.ts b/packages/canon/src/components/Container/types.ts
new file mode 100644
index 0000000000..f9a71ecfa1
--- /dev/null
+++ b/packages/canon/src/components/Container/types.ts
@@ -0,0 +1,29 @@
+/*
+ * 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 { SpaceProps } from '../../types';
+
+/** @public */
+export interface ContainerProps {
+ children?: React.ReactNode;
+ className?: string;
+ marginY?: SpaceProps['marginY'];
+ marginBottom?: SpaceProps['marginBottom'];
+ marginTop?: SpaceProps['marginTop'];
+ paddingY?: SpaceProps['paddingY'];
+ paddingBottom?: SpaceProps['paddingBottom'];
+ paddingTop?: SpaceProps['paddingTop'];
+ style?: React.CSSProperties;
+}
diff --git a/packages/canon/src/components/Grid/Docs.mdx b/packages/canon/src/components/Grid/Docs.mdx
new file mode 100644
index 0000000000..c1a0237279
--- /dev/null
+++ b/packages/canon/src/components/Grid/Docs.mdx
@@ -0,0 +1,199 @@
+import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
+import * as GridStories from './Grid.stories';
+import { Title, Text, PropsTable } from '../../../docs/components';
+import { spacePropsList } from '../../../docs/spaceProps';
+
+
+
+
+
+Grid
+
+ A layout component that helps to create simple column-based layouts as well as
+ more complex ones.
+
+
+Usage
+
+ Hello World
+
+`} language="tsx" dark />
+
+API reference
+
+Grid
+
+ This is the grid container component. It will help to define the number of
+ columns that will be used in the grid. You can also define the gap between the
+ columns. All values are responsive.
+
+
+
+
+
+ The grid component also accepts all the spacing props from the Box component.
+
+
+
+
+Grid Item
+
+ If you need more control over the columns, you can use the grid item
+ component. This will give you access to `rowSpan`, `colSpan`, `start` and
+ `end`. All values are responsive. This component is optional, you can use any
+ elements directly if you prefer.
+
+
+
+
+Examples
+
+Simple grid
+This is a simple grid with 3 columns and a gap of md.
+
+ Hello World
+ Hello World
+ Hello World
+
+`}
+ language="tsx"
+ dark
+/>
+
+Complex grid
+
+ You can also use the grid item to create more complex layouts. In this example
+ the first column will span 1 column and the second column will span 2 columns.
+
+
+
+
+ Hello World
+
+
+ Hello World
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+Mixing rows and columns
+
+ The grid item component also supports the `rowSpan` prop, which allows you to
+ span multiple rows within the grid layout. In this example, the first item
+ will span 2 rows to achieve a dynamic and flexible grid structure.
+
+
+
+
+ Hello World
+
+
+ Hello World
+
+
+ Hello World
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+Responsive
+
+ The grid component also supports responsive values. In this example the grid
+ will have 1 column on small screens and 3 on large screens, with a gap of xs
+ on small screens and md on large screens.
+
+
+
+ Hello World
+
+
+ Hello World
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+Start and End
+
+ The start and end props can be used to position the item in the grid.
+
+
+
+ Hello World
+
+
+`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Grid/Grid.stories.tsx b/packages/canon/src/components/Grid/Grid.stories.tsx
new file mode 100644
index 0000000000..9aeec52d00
--- /dev/null
+++ b/packages/canon/src/components/Grid/Grid.stories.tsx
@@ -0,0 +1,132 @@
+/*
+ * 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 React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { Grid } from './Grid';
+import type { GridItemProps } from './types';
+import { Box } from '../Box/Box';
+import { Stack } from '../Stack';
+
+const meta = {
+ title: 'Components/Grid',
+ component: Grid,
+ argTypes: {
+ children: {
+ control: false,
+ },
+ className: {
+ control: 'text',
+ },
+ },
+ args: {
+ gap: 'xs',
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+const FakeBox = () => (
+
+);
+
+export const Default: Story = {
+ args: {},
+ render: args => (
+
+
+
+
+
+ ),
+};
+
+export const LargeGap: Story = {
+ args: {
+ gap: 'lg',
+ },
+ render: args => (
+
+
+
+
+
+ ),
+};
+
+export const ColumnSizes: Story = {
+ args: {
+ columns: 12,
+ gap: 'md',
+ },
+ render: args => (
+
+ {Array.from({ length: 11 }, (_, i) => (
+
+
+
+
+
+
+
+
+ ))}
+
+ ),
+};
+
+export const RowAndColumns: Story = {
+ args: {
+ columns: 12,
+ gap: 'md',
+ },
+ render: args => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+};
diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/canon/src/components/Grid/Grid.tsx
new file mode 100644
index 0000000000..3799a70ae8
--- /dev/null
+++ b/packages/canon/src/components/Grid/Grid.tsx
@@ -0,0 +1,63 @@
+/*
+ * 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 { createElement, forwardRef } from 'react';
+import { GridItemProps, GridProps } from './types';
+import { getClassNames } from '../../utils/getClassNames';
+
+const GridBase = forwardRef((props, ref) => {
+ const {
+ children,
+ gap = 'xs',
+ columns = 'auto',
+ className,
+ style,
+ ...restProps
+ } = props;
+
+ const utilityClassNames = getClassNames({ gap, columns, ...restProps });
+
+ const classNames = ['canon-grid', utilityClassNames, className]
+ .filter(Boolean)
+ .join(' ');
+
+ return createElement('div', {
+ ref,
+ className: classNames,
+ style,
+ children,
+ });
+});
+
+const GridItem = forwardRef((props, ref) => {
+ const { children, className, style, ...restProps } = props;
+
+ const utilityClassNames = getClassNames(restProps);
+
+ const classNames = ['grid-item', utilityClassNames, className]
+ .filter(Boolean)
+ .join(' ');
+
+ return createElement('div', {
+ ref,
+ className: classNames,
+ style,
+ children,
+ });
+});
+
+/** @public */
+export const Grid = Object.assign(GridBase, { Item: GridItem });
diff --git a/packages/canon/src/components/Grid/index.ts b/packages/canon/src/components/Grid/index.ts
new file mode 100644
index 0000000000..b2534c6b77
--- /dev/null
+++ b/packages/canon/src/components/Grid/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+export { Grid } from './Grid';
+export type { GridProps, GridItemProps } from './types';
diff --git a/packages/canon/src/components/Grid/styles.css b/packages/canon/src/components/Grid/styles.css
new file mode 100644
index 0000000000..8314f896bc
--- /dev/null
+++ b/packages/canon/src/components/Grid/styles.css
@@ -0,0 +1,3 @@
+.canon-grid {
+ display: grid;
+}
diff --git a/packages/canon/src/components/Grid/types.ts b/packages/canon/src/components/Grid/types.ts
new file mode 100644
index 0000000000..4e154f03b7
--- /dev/null
+++ b/packages/canon/src/components/Grid/types.ts
@@ -0,0 +1,37 @@
+/*
+ * 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 { UtilityProps, SpaceProps } from '../../types';
+
+/** @public */
+export interface GridProps extends SpaceProps {
+ children?: React.ReactNode;
+ className?: string;
+ columns?: UtilityProps['columns'];
+ gap?: UtilityProps['gap'];
+ style?: React.CSSProperties;
+}
+
+/** @public */
+export interface GridItemProps {
+ children: React.ReactNode;
+ className?: string;
+ colSpan?: UtilityProps['colSpan'];
+ colEnd?: UtilityProps['colEnd'];
+ colStart?: UtilityProps['colStart'];
+ rowSpan?: UtilityProps['rowSpan'];
+ style?: React.CSSProperties;
+}
diff --git a/packages/canon/src/components/Heading/Docs.mdx b/packages/canon/src/components/Heading/Docs.mdx
new file mode 100644
index 0000000000..dd64bd59b2
--- /dev/null
+++ b/packages/canon/src/components/Heading/Docs.mdx
@@ -0,0 +1,83 @@
+import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
+import * as HeadingStories from './Heading.stories';
+import { Title, Text } from '../../../docs/components';
+import { PropsTable } from '../../../docs/components/PropsTable/PropsTable';
+
+
+
+
+
+Heading
+
+Headings are used to structure the content of your page.
+
+
+
+Usage
+Hello World!
+`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+Examples
+Here are some examples of how you can use the Heading component.
+
+All variants
+
+ The `Heading` component has a `variant` prop that can be used to change the
+ appearance of the heading.
+
+
+
+
+
+ Title 1 Lorem ipsum dolor sit amet consectetur...
+ Title 2 Lorem ipsum dolor sit amet consectetur...
+ Title 3 Lorem ipsum dolor sit amet consectetur...
+ Title 4 Lorem ipsum dolor sit amet consectetur...
+ Title 5 Lorem ipsum dolor sit amet consectetur...
+ Display Lorem ipsum dolor sit amet consectetur...
+`}
+ language="tsx"
+ dark
+/>
+
+Responsive
+
+ You can also use the `variant` prop to change the appearance of the text based
+ on the screen size.
+
+
+Responsive Lorem ipsum dolor sit amet consectetur...`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Heading/Heading.stories.tsx b/packages/canon/src/components/Heading/Heading.stories.tsx
new file mode 100644
index 0000000000..dc74ea0e16
--- /dev/null
+++ b/packages/canon/src/components/Heading/Heading.stories.tsx
@@ -0,0 +1,82 @@
+/*
+ * 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 React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { Heading } from './Heading';
+import { Stack } from '../Stack';
+import { Text } from '../Text';
+const meta = {
+ title: 'Components/Heading',
+ component: Heading,
+ args: {
+ children: 'Heading',
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {};
+
+export const Title1: Story = {
+ args: {
+ children: 'Look mum, no hands!',
+ variant: 'title1',
+ },
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+ Display
+ Title 1
+ Title 2
+ Title 3
+ Title 4
+
+ ),
+};
+
+export const Responsive: Story = {
+ args: {
+ variant: {
+ xs: 'title4',
+ md: 'display',
+ },
+ },
+};
+
+export const CustomTag: Story = {
+ args: {
+ variant: 'title5',
+ as: 'h2',
+ },
+};
+
+export const Playground: Story = {
+ render: () => (
+
+ All variants
+ Display
+ Title 1
+ Title 2
+ Title 3
+ Title 4
+ Title 5
+
+ ),
+};
diff --git a/packages/canon/src/components/Heading/Heading.tsx b/packages/canon/src/components/Heading/Heading.tsx
new file mode 100644
index 0000000000..612c871ebb
--- /dev/null
+++ b/packages/canon/src/components/Heading/Heading.tsx
@@ -0,0 +1,52 @@
+/*
+ * 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 React, { forwardRef } from 'react';
+import { HeadingProps } from './types';
+import { useCanon } from '../../contexts/canon';
+
+/** @public */
+export const Heading = forwardRef(
+ (props, ref) => {
+ const { children, variant = 'title1', as = 'h1', ...restProps } = props;
+ const { getResponsiveValue } = useCanon();
+
+ // Get the responsive value for the variant
+ const responsiveVariant = getResponsiveValue(variant);
+
+ // Determine the component to render based on the variant
+ let Component = as;
+ if (variant === 'title2') Component = 'h2';
+ if (variant === 'title3') Component = 'h3';
+ if (variant === 'title4') Component = 'h4';
+ if (variant === 'title5') Component = 'h5';
+ if (as) Component = as;
+
+ return (
+
+ {children}
+
+ );
+ },
+);
+
+Heading.displayName = 'Heading';
diff --git a/packages/canon/src/components/Heading/index.ts b/packages/canon/src/components/Heading/index.ts
new file mode 100644
index 0000000000..69b7c3c1a0
--- /dev/null
+++ b/packages/canon/src/components/Heading/index.ts
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+export { Heading } from './Heading';
+export type { HeadingProps } from './types';
diff --git a/packages/canon/src/components/Heading/styles.css b/packages/canon/src/components/Heading/styles.css
new file mode 100644
index 0000000000..446a5b7d2b
--- /dev/null
+++ b/packages/canon/src/components/Heading/styles.css
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+.text {
+ font-family: var(--canon-font-regular);
+ color: var(--canon-text-primary);
+ padding: 0;
+ margin: 0;
+
+ &.text-display {
+ font-size: var(--canon-font-size-display);
+ line-height: 100%;
+ font-weight: var(--canon-font-weight-bold);
+ }
+
+ &.text-title1 {
+ font-size: var(--canon-font-size-title1);
+ line-height: 100%;
+ font-weight: var(--canon-font-weight-bold);
+ }
+
+ &.text-title2 {
+ font-size: var(--canon-font-size-title2);
+ line-height: 100%;
+ font-weight: var(--canon-font-weight-bold);
+ }
+
+ &.text-title3 {
+ font-size: var(--canon-font-size-title3);
+ line-height: 100%;
+ font-weight: var(--canon-font-weight-bold);
+ }
+
+ &.text-title4 {
+ font-size: var(--canon-font-size-title4);
+ line-height: 100%;
+ font-weight: var(--canon-font-weight-bold);
+ }
+
+ &.text-title5 {
+ font-size: var(--canon-font-size-title5);
+ line-height: 100%;
+ font-weight: var(--canon-font-weight-bold);
+ }
+}
diff --git a/packages/canon/src/components/Heading/types.ts b/packages/canon/src/components/Heading/types.ts
new file mode 100644
index 0000000000..7a9a44560c
--- /dev/null
+++ b/packages/canon/src/components/Heading/types.ts
@@ -0,0 +1,36 @@
+/*
+ * 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 { Breakpoint } from '../../types';
+
+/** @public */
+export interface HeadingProps {
+ children: React.ReactNode;
+ variant?:
+ | 'display'
+ | 'title1'
+ | 'title2'
+ | 'title3'
+ | 'title4'
+ | 'title5'
+ | Partial<
+ Record<
+ Breakpoint,
+ 'display' | 'title1' | 'title2' | 'title3' | 'title4' | 'title5'
+ >
+ >;
+ as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+}
diff --git a/packages/canon/src/components/Icon/Docs.mdx b/packages/canon/src/components/Icon/Docs.mdx
new file mode 100644
index 0000000000..41c296424c
--- /dev/null
+++ b/packages/canon/src/components/Icon/Docs.mdx
@@ -0,0 +1,48 @@
+import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
+import * as IconStories from './Icon.stories';
+import { Title, Text } from '../../../docs/components';
+import { PropsTable } from '../../../docs/components/PropsTable/PropsTable';
+import { icons } from './icons';
+
+
+
+
+
+Icon
+
+Icons are used to represent an action or a state.
+
+
+
+Usage
+
+`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+
diff --git a/packages/canon/src/components/Icon/Icon.stories.tsx b/packages/canon/src/components/Icon/Icon.stories.tsx
index 61e837c5ed..cdf63fbb32 100644
--- a/packages/canon/src/components/Icon/Icon.stories.tsx
+++ b/packages/canon/src/components/Icon/Icon.stories.tsx
@@ -17,8 +17,8 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { Icon } from './Icon';
-import { ThemeProvider } from '../../theme/context';
-import { defaultIcons } from './icons';
+import { CanonProvider } from '../../contexts/canon';
+import { icons } from './icons';
const meta = {
title: 'Components/Icon',
@@ -29,7 +29,7 @@ const meta = {
argTypes: {
name: {
control: 'select',
- options: Object.keys(defaultIcons),
+ options: Object.keys(icons),
},
},
args: {
@@ -40,7 +40,7 @@ const meta = {
export default meta;
type Story = StoryObj;
-export const Primary: Story = {
+export const Default: Story = {
args: {
name: 'heart',
},
@@ -52,9 +52,9 @@ export const WithCustomIcon: Story = {
},
decorators: [
Story => (
- Custom Icon
}}>
+ Custom Icon
}}>
-
+
),
],
};
diff --git a/packages/canon/src/components/Icon/Icon.tsx b/packages/canon/src/components/Icon/Icon.tsx
index d7891c23cf..1df46c8a78 100644
--- a/packages/canon/src/components/Icon/Icon.tsx
+++ b/packages/canon/src/components/Icon/Icon.tsx
@@ -15,19 +15,20 @@
*/
import React from 'react';
-import { useTheme } from '../../theme/context';
-import type { IconNames } from './types';
+import { useCanon } from '../../contexts/canon';
+import type { IconProps } from './types';
/** @public */
-export const Icon = ({ name }: { name: IconNames }) => {
- const { icons } = useTheme();
+export const Icon = (props: IconProps) => {
+ const { name, size = 16 } = props;
+ const { icons } = useCanon();
- const RemixIcon = icons[name];
+ const RemixIcon = icons[name] as React.ComponentType<{ className?: string }>;
if (!RemixIcon) {
- console.error(`Icon "${name}" not found.`);
- return ; // Return default icon perhaps?
+ console.error(`Icon "${name}" not found or is not a valid component.`);
+ return ; // Return a default icon or handle the error appropriately
}
- return ;
+ return ;
};
diff --git a/packages/canon/src/components/Icon/icons.ts b/packages/canon/src/components/Icon/icons.ts
index 8c6a1248cb..40cbefb72d 100644
--- a/packages/canon/src/components/Icon/icons.ts
+++ b/packages/canon/src/components/Icon/icons.ts
@@ -26,16 +26,40 @@ import {
RiArrowUpFill,
RiDeleteBin6Line,
RiAddLine,
+ RiArrowDownSLine,
+ RiArrowUpSLine,
+ RiArrowLeftSLine,
+ RiArrowRightSLine,
+ RiArrowDownCircleLine,
+ RiArrowLeftCircleLine,
+ RiArrowRightCircleLine,
+ RiArrowUpCircleLine,
+ RiCheckLine,
+ RiMoonLine,
+ RiSunLine,
+ RiExternalLinkLine,
} from '@remixicon/react';
-// List of default icons
-export const defaultIcons: IconMap = {
+/** @public */
+export const icons: IconMap = {
arrowDown: RiArrowDownFill,
arrowLeft: RiArrowLeftFill,
arrowRight: RiArrowRightFill,
arrowUp: RiArrowUpFill,
+ arrowDownCircle: RiArrowDownCircleLine,
+ arrowLeftCircle: RiArrowLeftCircleLine,
+ arrowRightCircle: RiArrowRightCircleLine,
+ arrowUpCircle: RiArrowUpCircleLine,
+ check: RiCheckLine,
+ chevronDown: RiArrowDownSLine,
+ chevronUp: RiArrowUpSLine,
+ chevronLeft: RiArrowLeftSLine,
+ chevronRight: RiArrowRightSLine,
cloud: RiCloudFill,
+ externalLink: RiExternalLinkLine,
heart: RiHeartFill,
+ moon: RiMoonLine,
plus: RiAddLine,
+ sun: RiSunLine,
trash: RiDeleteBin6Line,
};
diff --git a/packages/canon/src/components/Icon/index.tsx b/packages/canon/src/components/Icon/index.tsx
index 3e7564c77e..0fa2eac35b 100644
--- a/packages/canon/src/components/Icon/index.tsx
+++ b/packages/canon/src/components/Icon/index.tsx
@@ -15,4 +15,5 @@
*/
export * from './Icon';
+export * from './icons';
export type * from './types';
diff --git a/packages/canon/src/components/Box/box.css.ts b/packages/canon/src/components/Icon/styles.css
similarity index 79%
rename from packages/canon/src/components/Box/box.css.ts
rename to packages/canon/src/components/Icon/styles.css
index 92af783eec..234105ed4e 100644
--- a/packages/canon/src/components/Box/box.css.ts
+++ b/packages/canon/src/components/Icon/styles.css
@@ -14,9 +14,17 @@
* limitations under the License.
*/
-import { style } from '@vanilla-extract/css';
+.icon-12 {
+ width: 12px;
+ height: 12px;
+}
-export const base = style({
- fontFamily: 'var(--canon-font-sans)',
- color: 'var(--canon-text-primary)',
-});
+.icon-16 {
+ width: 16px;
+ height: 16px;
+}
+
+.icon-24 {
+ width: 24px;
+ height: 24px;
+}
diff --git a/packages/canon/src/components/Icon/types.ts b/packages/canon/src/components/Icon/types.ts
index 6e16e627d4..57eddc74ba 100644
--- a/packages/canon/src/components/Icon/types.ts
+++ b/packages/canon/src/components/Icon/types.ts
@@ -20,10 +20,28 @@ export type IconNames =
| 'arrowLeft'
| 'arrowRight'
| 'arrowUp'
+ | 'arrowDownCircle'
+ | 'arrowLeftCircle'
+ | 'arrowRightCircle'
+ | 'arrowUpCircle'
+ | 'check'
+ | 'chevronDown'
+ | 'chevronLeft'
+ | 'chevronRight'
+ | 'chevronUp'
| 'cloud'
+ | 'externalLink'
| 'heart'
+ | 'moon'
| 'plus'
+ | 'sun'
| 'trash';
/** @public */
export type IconMap = Partial>;
+
+/** @public */
+export type IconProps = {
+ name: IconNames;
+ size?: number;
+};
diff --git a/packages/canon/src/components/Inline/Docs.mdx b/packages/canon/src/components/Inline/Docs.mdx
new file mode 100644
index 0000000000..7671122966
--- /dev/null
+++ b/packages/canon/src/components/Inline/Docs.mdx
@@ -0,0 +1,124 @@
+import { Meta, Unstyled, Source } from '@storybook/blocks';
+import * as InlineStories from './Inline.stories';
+import { Title, Text, PropsTable, getProps } from '../../../docs/components';
+import { spacePropsList } from '../../../docs/spaceProps';
+
+
+
+
+
+Inline
+
+
+ The Inline component is used to create a horizontal layout of elements. By
+ default it uses flex and flexWrap to make sure that your content always flows
+ responsively.
+
+
+Usage
+
+ Hello World
+ Hello World
+ Hello World
+
+`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+
+ The grid component also accepts all the spacing props from the Box component.
+
+
+
+
+Examples
+
+Simple
+A simple example of how to use the Inline component.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+Responsive
+
+ The Inline component also supports responsive values, making it easy to create
+ responsive designs.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+Align
+
+ The Inline component also supports responsive alignment, making it easy to
+ create responsive designs.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+Align vertically
+
+ The Inline component also supports responsive vertical alignment, making it
+ easy to create responsive designs.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Inline/Inline.stories.tsx b/packages/canon/src/components/Inline/Inline.stories.tsx
index 613fd68c68..6aa6079989 100644
--- a/packages/canon/src/components/Inline/Inline.stories.tsx
+++ b/packages/canon/src/components/Inline/Inline.stories.tsx
@@ -18,14 +18,11 @@ import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Inline } from './Inline';
import { Box } from '../Box/Box';
-import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes';
const meta = {
title: 'Components/Inline',
component: Inline,
argTypes: {
- ...argTypesSpacing,
- ...argTypesColor,
align: {
control: 'inline-radio',
options: ['left', 'center', 'right'],
@@ -44,11 +41,28 @@ const meta = {
control: 'text',
},
},
+ args: {
+ children: 'hello world',
+ },
} satisfies Meta;
export default meta;
type Story = StoryObj;
+const fakeBlockList = [
+ { width: 45, height: 60 },
+ { width: 150, height: 75 },
+ { width: 80, height: 50 },
+ { width: 120, height: 70 },
+ { width: 95, height: 65 },
+ { width: 80, height: 32 },
+ { width: 130, height: 60 },
+ { width: 100, height: 80 },
+ { width: 140, height: 45 },
+ { width: 85, height: 70 },
+ { width: 125, height: 50 },
+];
+
const FakeBox = ({
width = 120,
height = 80,
@@ -57,72 +71,67 @@ const FakeBox = ({
height?: number;
}) => (
);
export const Default: Story = {
- args: {
- children: (
- <>
- {Array.from({ length: 32 }).map((_, index) => (
-
- ))}
- >
- ),
- },
+ render: () => (
+
+ {fakeBlockList.map((block, index) => (
+
+ ))}
+
+ ),
};
export const AlignLeft: Story = {
args: {
- ...Default.args,
align: 'left',
},
};
export const AlignCenter: Story = {
args: {
- ...Default.args,
align: 'center',
},
};
export const AlignRight: Story = {
args: {
- ...Default.args,
align: 'right',
},
};
export const VerticalAlignTop: Story = {
args: {
- ...Default.args,
alignY: 'top',
},
};
export const VerticalAlignCenter: Story = {
args: {
- ...Default.args,
alignY: 'center',
},
};
export const VerticalAlignBottom: Story = {
args: {
- ...Default.args,
alignY: 'bottom',
},
};
export const LargeGap: Story = {
args: {
- ...Default.args,
gap: 'xl',
},
};
diff --git a/packages/canon/src/components/Inline/Inline.tsx b/packages/canon/src/components/Inline/Inline.tsx
index 2d1c649e29..b3aaeaf082 100644
--- a/packages/canon/src/components/Inline/Inline.tsx
+++ b/packages/canon/src/components/Inline/Inline.tsx
@@ -14,50 +14,76 @@
* limitations under the License.
*/
-import { createElement } from 'react';
-import { inlineSprinkles } from './sprinkles.css';
+import { createElement, forwardRef } from 'react';
import type { InlineProps } from './types';
+import { getClassNames } from '../../utils/getClassNames';
+import { JustifyContent, Breakpoint, AlignItems } from '../../types';
-const alignYToFlexAlign = (alignY: InlineProps['alignY']) => {
- if (alignY === 'top') return 'flex-start';
- if (alignY === 'center') return 'center';
- if (alignY === 'bottom') return 'flex-end';
- return undefined;
+// Function to map align values
+const mapAlignValue = (value?: InlineProps['align']) => {
+ if (typeof value === 'string') {
+ let returnedValue: JustifyContent = 'stretch';
+ if (value === 'left') returnedValue = 'start';
+ if (value === 'center') returnedValue = 'center';
+ if (value === 'right') returnedValue = 'end';
+ return returnedValue;
+ } else if (typeof value === 'object') {
+ const returnedValue: Partial> = {};
+ for (const [key, val] of Object.entries(value)) {
+ returnedValue[key as Breakpoint] = mapAlignValue(val) as JustifyContent;
+ }
+ return returnedValue;
+ }
+ return 'stretch';
};
-const alignToFlexAlignY = (align: InlineProps['align']) => {
- if (align === 'left') return 'flex-start';
- if (align === 'center') return 'center';
- if (align === 'right') return 'flex-end';
- return undefined;
+const mapAlignYValue = (value?: InlineProps['alignY']) => {
+ if (typeof value === 'string') {
+ let returnedValue: AlignItems = 'stretch';
+ if (value === 'top') returnedValue = 'start';
+ if (value === 'center') returnedValue = 'center';
+ if (value === 'bottom') returnedValue = 'end';
+ return returnedValue;
+ } else if (typeof value === 'object') {
+ const returnedValue: Partial> = {};
+ for (const [key, val] of Object.entries(value)) {
+ returnedValue[key as Breakpoint] = mapAlignYValue(val) as AlignItems;
+ }
+ return returnedValue;
+ }
+ return 'stretch';
};
-export const Inline = ({
- as = 'div',
- children,
- align = 'left',
- alignY = 'top',
- gap = 'xs',
- className,
- style,
- ...restProps
-}: InlineProps) => {
- // Generate the list of class names
- const sprinklesClassName = inlineSprinkles({
- ...restProps,
+/** @public */
+export const Inline = forwardRef((props, ref) => {
+ const {
+ as = 'div',
+ children,
+ align = 'left',
+ alignY = 'top',
+ gap = 'xs',
+ className,
+ style,
+ ...restProps
+ } = props;
+
+ // Generate utility class names
+ const utilityClassNames = getClassNames({
gap,
- alignItems: alignYToFlexAlign(alignY),
- justifyContent: alignToFlexAlignY(align),
+ alignItems: mapAlignYValue(alignY),
+ justifyContent: mapAlignValue(align),
+ ...restProps,
});
// Combine the base class name, the sprinkles class name, and any additional class names
- const classNames = ['inline', sprinklesClassName, className]
+ const classNames = ['canon-inline', utilityClassNames, className]
.filter(Boolean)
.join(' ');
return createElement(as, {
+ ref,
className: classNames,
style,
children,
});
-};
+});
diff --git a/packages/canon/src/components/Inline/index.ts b/packages/canon/src/components/Inline/index.ts
index 77a0e51629..2cc100c02a 100644
--- a/packages/canon/src/components/Inline/index.ts
+++ b/packages/canon/src/components/Inline/index.ts
@@ -14,3 +14,4 @@
* limitations under the License.
*/
export { Inline } from './Inline';
+export type { InlineProps } from './types';
diff --git a/packages/canon/src/components/Inline/sprinkles.css.ts b/packages/canon/src/components/Inline/sprinkles.css.ts
deleted file mode 100644
index 1d7e95da00..0000000000
--- a/packages/canon/src/components/Inline/sprinkles.css.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
-import { breakpoints } from '../../layout/properties';
-import { colorProperties, spacingProperties } from '../../layout/sprinkles.css';
-
-const inlineProperties = defineProperties({
- conditions: breakpoints,
- defaultCondition: 'xs',
- properties: {
- alignItems: ['flex-start', 'center', 'flex-end'],
- justifyContent: ['flex-start', 'center', 'flex-end'],
- },
-});
-
-export const inlineSprinkles = createSprinkles(
- spacingProperties,
- colorProperties,
- inlineProperties,
-);
diff --git a/packages/canon/src/components/Inline/styles.css b/packages/canon/src/components/Inline/styles.css
index fb9b1c3825..bafd29bf53 100644
--- a/packages/canon/src/components/Inline/styles.css
+++ b/packages/canon/src/components/Inline/styles.css
@@ -1,4 +1,4 @@
-.inline {
+.canon-inline {
display: flex;
flex-wrap: wrap;
}
diff --git a/packages/canon/src/components/Inline/types.ts b/packages/canon/src/components/Inline/types.ts
index 413f2fbbb0..c86f500018 100644
--- a/packages/canon/src/components/Inline/types.ts
+++ b/packages/canon/src/components/Inline/types.ts
@@ -14,12 +14,18 @@
* limitations under the License.
*/
-import { AsProps, Breakpoint, ColorProps } from '../../layout/types';
-import { SpaceProps } from '../../layout/types';
+import type {
+ SpaceProps,
+ UtilityProps,
+ AsProps,
+ Breakpoint,
+} from '../../types';
-export interface InlineProps extends SpaceProps, ColorProps {
+/** @public */
+export interface InlineProps extends SpaceProps {
children: React.ReactNode;
as?: AsProps;
+ gap?: UtilityProps['gap'];
align?:
| 'left'
| 'center'
diff --git a/packages/canon/src/components/Stack/Docs.mdx b/packages/canon/src/components/Stack/Docs.mdx
new file mode 100644
index 0000000000..921618f49f
--- /dev/null
+++ b/packages/canon/src/components/Stack/Docs.mdx
@@ -0,0 +1,126 @@
+import { Meta, Unstyled, Source } from '@storybook/blocks';
+import * as StackStories from './Stack.stories';
+import { Title, Text, PropsTable, getProps } from '../../../docs/components';
+import { spacePropsList } from '../../../docs/spaceProps';
+
+
+
+
+
+Stack
+
+
+ This is the stack container component. It will help to define the number of
+ columns that will be used in the grid. You can also define the gap between the
+ columns. All values are responsive.
+
+
+Usage
+
+ Hello World
+ Hello World
+ Hello World
+
+`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+
+ The grid component also accepts all the spacing props from the Box component.
+
+
+
+
+Common questions
+
+Can I stack horizontally?
+
+ The Stack component only allows for stacking elements vertically. If you want
+ to create a column layout, please use the Grid component.
+
+
+
+ Hello World
+ Hello World
+ Hello World
+
+`}
+ language="tsx"
+ dark
+/>
+
+Examples
+
+Simple
+
+ A simple example of how to use the Stack component with a medium gap.
+
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+Responsive
+
+ The Stack component also supports responsive values, making it easy to create
+ responsive designs.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+Align
+
+ The Stack component also supports responsive alignment, making it easy to
+ create responsive designs.
+
+
+ Hello World
+ Hello World
+ Hello World
+`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Stack/Stack.stories.tsx b/packages/canon/src/components/Stack/Stack.stories.tsx
index 601f6b847f..4c48cf80cc 100644
--- a/packages/canon/src/components/Stack/Stack.stories.tsx
+++ b/packages/canon/src/components/Stack/Stack.stories.tsx
@@ -17,15 +17,11 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Stack } from './Stack';
-import { Box } from '../Box/Box';
-import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes';
const meta = {
title: 'Components/Stack',
component: Stack,
argTypes: {
- ...argTypesSpacing,
- ...argTypesColor,
align: {
control: 'inline-radio',
options: ['left', 'center', 'right'],
@@ -43,81 +39,97 @@ const meta = {
args: {
align: 'left',
gap: 'xs',
+ children: 'hello world',
},
} satisfies Meta;
export default meta;
type Story = StoryObj;
-const FakeBox = () => (
-
- Fake Box
-
-);
+const DecorativeBox = () => {
+ return (
+
+ );
+};
export const Default: Story = {
- args: {
- children: (
- <>
-
-
-
- >
- ),
- },
+ render: () => (
+
+
+
+
+
+
+
+ ),
};
export const AlignLeft: Story = {
- args: {
- ...Default.args,
- align: 'left',
- },
+ render: () => (
+
+
+
+
+
+ ),
};
export const AlignCenter: Story = {
- args: {
- ...Default.args,
- align: 'center',
- },
+ render: () => (
+
+
+
+
+
+ ),
};
export const AlignRight: Story = {
- args: {
- ...Default.args,
- align: 'right',
- },
+ render: () => (
+
+
+
+
+
+ ),
};
export const ResponsiveAlign: Story = {
- args: {
- ...Default.args,
- align: {
- xs: 'left',
- md: 'center',
- lg: 'right',
- },
- },
+ render: () => (
+
+
+
+
+
+ ),
};
export const ResponsiveGap: Story = {
- args: {
- ...Default.args,
- gap: {
- xs: 'xs',
- md: 'md',
- lg: 'xxl',
- },
- },
+ render: () => (
+
+
+
+
+
+ ),
};
export const LargeGap: Story = {
- args: {
- ...Default.args,
- gap: 'xl',
- },
+ render: () => (
+
+
+
+
+
+ ),
};
diff --git a/packages/canon/src/components/Stack/Stack.tsx b/packages/canon/src/components/Stack/Stack.tsx
index f2316805b5..522782daac 100644
--- a/packages/canon/src/components/Stack/Stack.tsx
+++ b/packages/canon/src/components/Stack/Stack.tsx
@@ -14,44 +14,57 @@
* limitations under the License.
*/
-import { createElement } from 'react';
+import { createElement, forwardRef } from 'react';
import { StackProps } from './types';
-import { stackSprinkles } from './sprinkles.css';
+import { getClassNames } from '../../utils/getClassNames';
+import type { AlignItems, Breakpoint } from '../../types';
-const alignToFlexAlign = (align: StackProps['align']) => {
- if (align === 'left') return 'stretch';
- if (align === 'center') return 'center';
- if (align === 'right') return 'flex-end';
- return undefined;
+// Function to map align values
+const mapAlignValue = (value?: StackProps['align']) => {
+ if (typeof value === 'string') {
+ let returnedValue: AlignItems = 'stretch';
+ if (value === 'left') returnedValue = 'stretch';
+ if (value === 'center') returnedValue = 'center';
+ if (value === 'right') returnedValue = 'end';
+ return returnedValue;
+ } else if (typeof value === 'object') {
+ const returnedValue: Partial> = {};
+ for (const [key, val] of Object.entries(value)) {
+ returnedValue[key as Breakpoint] = mapAlignValue(val) as AlignItems;
+ }
+ return returnedValue;
+ }
+ return 'stretch';
};
-export const Stack = ({
- as = 'div',
- children,
- align = 'left',
- gap = 'xs',
- className,
- style,
- ...restProps
-}: StackProps) => {
- // Transform the align prop
- const flexAlign = alignToFlexAlign(align);
+/** @public */
+export const Stack = forwardRef((props, ref) => {
+ const {
+ as = 'div',
+ children,
+ align = 'left',
+ gap = 'xs',
+ className,
+ style,
+ ...restProps
+ } = props;
- // Generate the list of class names
- const sprinklesClassName = stackSprinkles({
- ...restProps,
+ // Generate utility class names
+ const utilityClassNames = getClassNames({
gap,
- alignItems: flexAlign,
+ alignItems: mapAlignValue(align),
+ ...restProps,
});
// Combine the base class name, the sprinkles class name, and any additional class names
- const classNames = ['stack', sprinklesClassName, className]
+ const classNames = ['canon-stack', utilityClassNames, className]
.filter(Boolean)
.join(' ');
return createElement(as, {
+ ref,
className: classNames,
style,
children,
});
-};
+});
diff --git a/packages/canon/src/components/Stack/index.ts b/packages/canon/src/components/Stack/index.ts
index 2aeaba3adf..7abbc3f439 100644
--- a/packages/canon/src/components/Stack/index.ts
+++ b/packages/canon/src/components/Stack/index.ts
@@ -14,3 +14,4 @@
* limitations under the License.
*/
export { Stack } from './Stack';
+export type { StackProps } from './types';
diff --git a/packages/canon/src/components/Stack/sprinkles.css.ts b/packages/canon/src/components/Stack/sprinkles.css.ts
deleted file mode 100644
index 85c8f83a71..0000000000
--- a/packages/canon/src/components/Stack/sprinkles.css.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
-import { breakpoints } from '../../layout/properties';
-import { colorProperties, spacingProperties } from '../../layout/sprinkles.css';
-
-const stackProperties = defineProperties({
- conditions: breakpoints,
- defaultCondition: 'xs',
- properties: {
- alignItems: ['stretch', 'flex-start', 'center', 'flex-end'],
- },
-});
-
-export const stackSprinkles = createSprinkles(
- spacingProperties,
- colorProperties,
- stackProperties,
-);
diff --git a/packages/canon/src/components/Stack/styles.css b/packages/canon/src/components/Stack/styles.css
index 784fd3b1ab..fa5c3f7e5d 100644
--- a/packages/canon/src/components/Stack/styles.css
+++ b/packages/canon/src/components/Stack/styles.css
@@ -1,4 +1,4 @@
-.stack {
+.canon-stack {
display: flex;
flex-direction: column;
}
diff --git a/packages/canon/src/components/Stack/types.ts b/packages/canon/src/components/Stack/types.ts
index 81abea9999..bccdc59a57 100644
--- a/packages/canon/src/components/Stack/types.ts
+++ b/packages/canon/src/components/Stack/types.ts
@@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { AsProps, Breakpoint, ColorProps } from '../../layout/types';
-import { SpaceProps } from '../../layout/types';
-export interface StackProps extends SpaceProps, ColorProps {
+import type {
+ SpaceProps,
+ UtilityProps,
+ AsProps,
+ Breakpoint,
+} from '../../types';
+
+/** @public */
+export interface StackProps extends SpaceProps {
children: React.ReactNode;
as?: AsProps;
+ gap?: UtilityProps['gap'];
align?:
| 'left'
| 'center'
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.stories.tsx b/packages/canon/src/components/Table/Table.stories.tsx
new file mode 100644
index 0000000000..c4c08be527
--- /dev/null
+++ b/packages/canon/src/components/Table/Table.stories.tsx
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+const invoices = [
+ {
+ invoice: 'INV001',
+ paymentStatus: 'Paid',
+ totalAmount: '$250.00',
+ paymentMethod: 'Credit Card',
+ },
+ {
+ invoice: 'INV002',
+ paymentStatus: 'Pending',
+ totalAmount: '$150.00',
+ paymentMethod: 'PayPal',
+ },
+ {
+ invoice: 'INV003',
+ paymentStatus: 'Unpaid',
+ totalAmount: '$350.00',
+ paymentMethod: 'Bank Transfer',
+ },
+ {
+ invoice: 'INV004',
+ paymentStatus: 'Paid',
+ totalAmount: '$450.00',
+ paymentMethod: 'Credit Card',
+ },
+ {
+ invoice: 'INV005',
+ paymentStatus: 'Paid',
+ totalAmount: '$550.00',
+ paymentMethod: 'PayPal',
+ },
+ {
+ invoice: 'INV006',
+ paymentStatus: 'Pending',
+ totalAmount: '$200.00',
+ paymentMethod: 'Bank Transfer',
+ },
+ {
+ invoice: 'INV007',
+ paymentStatus: 'Unpaid',
+ totalAmount: '$300.00',
+ paymentMethod: 'Credit Card',
+ },
+];
+
+import React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableFooter,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from '../Table';
+
+const meta = {
+ title: 'Components/Table',
+ component: Table,
+ subcomponents: {
+ TableBody: TableBody as React.ComponentType,
+ TableCell: TableCell as React.ComponentType,
+ TableFooter: TableFooter as React.ComponentType,
+ TableHead: TableHead as React.ComponentType,
+ TableHeader: TableHeader as React.ComponentType,
+ TableRow: TableRow as React.ComponentType,
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+
+
+ Invoice
+ Status
+ Method
+ Amount
+
+
+
+ {invoices.map(invoice => (
+
+ {invoice.invoice}
+ {invoice.paymentStatus}
+ {invoice.paymentMethod}
+ {invoice.totalAmount}
+
+ ))}
+
+
+
+ Total
+ $2,500.00
+
+
+
+ ),
+};
diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/canon/src/components/Table/Table.tsx
new file mode 100644
index 0000000000..efd5181036
--- /dev/null
+++ b/packages/canon/src/components/Table/Table.tsx
@@ -0,0 +1,115 @@
+/*
+ * 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';
+
+/** @public */
+const Table = React.forwardRef<
+ HTMLTableElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+Table.displayName = 'Table';
+
+/** @public */
+const TableHeader = React.forwardRef<
+ HTMLTableSectionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableHeader.displayName = 'TableHeader';
+
+/** @public */
+const TableBody = React.forwardRef<
+ HTMLTableSectionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableBody.displayName = 'TableBody';
+
+/** @public */
+const TableFooter = React.forwardRef<
+ HTMLTableSectionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+TableFooter.displayName = 'TableFooter';
+
+/** @public */
+const TableRow = React.forwardRef<
+ HTMLTableRowElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+ {props.children}
+
+));
+TableRow.displayName = 'TableRow';
+
+/** @public */
+const TableHead = React.forwardRef<
+ HTMLTableCellElement,
+ React.ThHTMLAttributes
+>(({ className, ...props }, ref) => (
+ |
+));
+TableHead.displayName = 'TableHead';
+
+/** @public */
+const TableCell = React.forwardRef<
+ HTMLTableCellElement,
+ React.TdHTMLAttributes
+>(({ className, ...props }, ref) => (
+ |
+));
+TableCell.displayName = 'TableCell';
+
+/** @public */
+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/index.ts b/packages/canon/src/components/Table/index.ts
new file mode 100644
index 0000000000..cf88de2b1a
--- /dev/null
+++ b/packages/canon/src/components/Table/index.ts
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+export {
+ Table,
+ TableHead,
+ TableRow,
+ TableHeader,
+ TableCell,
+ TableBody,
+ TableFooter,
+} from './Table';
diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css
new file mode 100644
index 0000000000..574fae67bf
--- /dev/null
+++ b/packages/canon/src/components/Table/styles.css
@@ -0,0 +1,65 @@
+.table {
+ position: relative;
+ overflow: auto;
+ width: 100%;
+ background-color: var(--canon-surface-1);
+ border-radius: var(--canon-border-radius-xs);
+ padding-bottom: var(--canon-spacing-5xs);
+ padding-top: var(--canon-spacing-5xs);
+ font-size: var(--canon-font-size-body);
+
+ table {
+ width: 100%;
+ caption-side: bottom;
+ font-size: var(--canon-font-size-sm);
+ border-collapse: collapse;
+ }
+}
+
+.table-header {
+ tr {
+ /* border-bottom: 1px solid var(--canon-border); */
+ }
+}
+
+.table-head {
+ text-align: left;
+ padding: var(--canon-spacing-xs);
+}
+
+.table-body {
+ tr:last-child {
+ border-bottom: none;
+ }
+}
+
+.table-row {
+ transition: color 0.2s ease-in-out;
+
+ &:hover td {
+ background-color: var(--canon-surface-3);
+ }
+
+ & .table-cell:first-child {
+ border-top-left-radius: var(--canon-border-radius-xs);
+ border-bottom-left-radius: var(--canon-border-radius-xs);
+ box-shadow: inset 4px 2px 0 0 var(--canon-surface-1),
+ inset 4px -2px 0 0 var(--canon-surface-1);
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ & .table-cell:last-child {
+ border-top-right-radius: var(--canon-border-radius-xs);
+ border-bottom-right-radius: var(--canon-border-radius-xs);
+ box-shadow: inset -4px 2px 0 0 var(--canon-surface-1),
+ inset -4px -2px 0 0 var(--canon-surface-1);
+ padding-right: var(--canon-spacing-xs);
+ }
+}
+
+.table-cell {
+ padding: var(--canon-spacing-xs);
+ background-color: var(--canon-surface-2);
+ box-shadow: inset 0px 2px 0 0 var(--canon-surface-1),
+ inset 0px -2px 0 0 var(--canon-surface-1);
+}
diff --git a/packages/canon/src/components/Text/Docs.mdx b/packages/canon/src/components/Text/Docs.mdx
new file mode 100644
index 0000000000..685a00a33f
--- /dev/null
+++ b/packages/canon/src/components/Text/Docs.mdx
@@ -0,0 +1,101 @@
+import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
+import * as TextStories from './Text.stories';
+import { Title, Text } from '../../../docs/components';
+import { PropsTable } from '../../../docs/components/PropsTable/PropsTable';
+
+
+
+
+
+Text
+
+The `Text` component is used to display content on your page.
+
+
+
+Usage
+Hello World!`} language="tsx" dark />
+
+
+ API reference
+
+
+
+
+Examples
+Here are some examples of how you can use the Text component.
+
+All variants
+
+ The `Text` component has a `variant` prop that can be used to change the
+ appearance of the text.
+
+
+
+
+
+ Subtitle Lorem ipsum dolor sit amet consectetur...
+ Body Lorem ipsum dolor sit amet consectetur...
+ Caption Lorem ipsum dolor sit amet consectetur...
+ Label Lorem ipsum dolor sit amet consectetur...
+`}
+ language="tsx"
+ dark
+/>
+
+All weights
+
+ The `Text` component has a `weight` prop that can be used to change the
+ appearance of the text.
+
+
+
+
+
+ Regular Lorem ipsum dolor sit amet consectetur...
+ Bold Lorem ipsum dolor sit amet consectetur...
+`}
+ language="tsx"
+ dark
+/>
+
+Responsive
+
+ You can also use the `variant` prop to change the appearance of the text based
+ on the screen size.
+
+
+Responsive Lorem ipsum dolor sit amet consectetur...`}
+ language="tsx"
+ dark
+/>
+
+
diff --git a/packages/canon/src/components/Text/Text.stories.tsx b/packages/canon/src/components/Text/Text.stories.tsx
new file mode 100644
index 0000000000..b0776beee9
--- /dev/null
+++ b/packages/canon/src/components/Text/Text.stories.tsx
@@ -0,0 +1,123 @@
+/*
+ * 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 React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { Text } from './Text';
+import { Stack } from '../Stack';
+
+const meta = {
+ title: 'Components/Text',
+ component: Text,
+ args: {
+ children: 'Text',
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ children:
+ "A man looks at a painting in a museum and says, “Brothers and sisters I have none, but that man's father is my father's son.” Who is in the painting?",
+ style: { maxWidth: '600px' },
+ },
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ ),
+};
+
+export const AllWeights: Story = {
+ render: () => (
+
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ ),
+};
+
+export const Responsive: Story = {
+ args: {
+ variant: {
+ xs: 'label',
+ md: 'body',
+ },
+ },
+};
+
+export const Playground: Story = {
+ render: () => (
+
+ Subtitle
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+ Body
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+ Caption
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+ Label
+
+ A man looks at a painting in a museum and says, “Brothers and sisters I
+ have none, but that man's father is my father's son.” Who is
+ in the painting?
+
+
+ ),
+};
diff --git a/packages/canon/src/components/Text/Text.tsx b/packages/canon/src/components/Text/Text.tsx
new file mode 100644
index 0000000000..1359a0e4c5
--- /dev/null
+++ b/packages/canon/src/components/Text/Text.tsx
@@ -0,0 +1,53 @@
+/*
+ * 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 React, { forwardRef } from 'react';
+import { TextProps } from './types';
+import { useCanon } from '../../contexts/canon';
+
+/** @public */
+export const Text = forwardRef(
+ (props, ref) => {
+ const {
+ children,
+ variant = 'body',
+ weight = 'regular',
+ style,
+ ...restProps
+ } = props;
+
+ const { getResponsiveValue } = useCanon();
+
+ // Get the responsive values for the variant and weight
+ const responsiveVariant = getResponsiveValue(variant);
+ const responsiveWeight = getResponsiveValue(weight);
+
+ return (
+
+ {children}
+
+ );
+ },
+);
+
+Text.displayName = 'Text';
diff --git a/packages/canon/src/components/Text/index.ts b/packages/canon/src/components/Text/index.ts
new file mode 100644
index 0000000000..ae1f532b2c
--- /dev/null
+++ b/packages/canon/src/components/Text/index.ts
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+export { Text } from './Text';
+export type { TextProps } from './types';
diff --git a/packages/canon/src/components/Text/styles.css b/packages/canon/src/components/Text/styles.css
new file mode 100644
index 0000000000..9bf22ccab5
--- /dev/null
+++ b/packages/canon/src/components/Text/styles.css
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+.text {
+ font-family: var(--canon-font-regular);
+ color: var(--canon-text-primary);
+ padding: 0;
+ margin: 0;
+
+ &.text-body {
+ font-size: var(--canon-font-size-body);
+ line-height: 140%;
+ }
+
+ &.text-subtitle {
+ font-size: var(--canon-font-size-subtitle);
+ line-height: 140%;
+ }
+
+ &.text-caption {
+ font-size: var(--canon-font-size-caption);
+ line-height: 140%;
+ }
+
+ &.text-label {
+ font-size: var(--canon-font-size-label);
+ line-height: 140%;
+ }
+
+ &.text-regular {
+ font-weight: var(--canon-font-weight-regular);
+ }
+
+ &.text-bold {
+ font-weight: var(--canon-font-weight-bold);
+ }
+}
diff --git a/packages/canon/src/components/Text/types.ts b/packages/canon/src/components/Text/types.ts
new file mode 100644
index 0000000000..7e11bed6e3
--- /dev/null
+++ b/packages/canon/src/components/Text/types.ts
@@ -0,0 +1,31 @@
+/*
+ * 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 { CSSProperties, ReactNode } from 'react';
+import type { Breakpoint } from '../../types';
+
+/** @public */
+export interface TextProps {
+ children: ReactNode;
+ variant?:
+ | 'subtitle'
+ | 'body'
+ | 'caption'
+ | 'label'
+ | Partial>;
+ weight?: 'regular' | 'bold' | Partial>;
+ style?: CSSProperties;
+}
diff --git a/packages/canon/src/contexts/canon.tsx b/packages/canon/src/contexts/canon.tsx
new file mode 100644
index 0000000000..5a0e6b4315
--- /dev/null
+++ b/packages/canon/src/contexts/canon.tsx
@@ -0,0 +1,101 @@
+/*
+ * 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 React, { createContext, useContext, ReactNode } from 'react';
+import { IconMap, IconNames } from '../components/Icon/types';
+import { icons } from '../components/Icon/icons';
+import { useMediaQuery } from '../hooks/useMediaQuery';
+import type { Breakpoint } from '../types';
+
+/** @public */
+export interface CanonContextProps {
+ icons: IconMap;
+ breakpoint: Breakpoint;
+ getResponsiveValue: (
+ value: string | Partial>,
+ ) => string;
+}
+
+const CanonContext = createContext({
+ icons,
+ breakpoint: 'md',
+ getResponsiveValue: () => '',
+});
+
+/** @public */
+export interface CanonProviderProps {
+ children?: ReactNode;
+ overrides?: Partial>;
+}
+
+/** @public */
+export const CanonProvider = (props: CanonProviderProps) => {
+ const { children, overrides } = props;
+
+ // Merge provided overrides with default icons
+ const combinedIcons = { ...icons, ...overrides };
+
+ const isBreakpointSm = useMediaQuery(`(min-width: 640px)`);
+ const isBreakpointMd = useMediaQuery(`(min-width: 768px)`);
+ const isBreakpointLg = useMediaQuery(`(min-width: 1024px)`);
+ const isBreakpointXl = useMediaQuery(`(min-width: 1280px)`);
+ const isBreakpoint2xl = useMediaQuery(`(min-width: 1536px)`);
+
+ // Determine the current breakpoint
+ const breakpoint = (() => {
+ if (isBreakpoint2xl) return '2xl';
+ if (isBreakpointXl) return 'xl';
+ if (isBreakpointLg) return 'lg';
+ if (isBreakpointMd) return 'md';
+ if (isBreakpointSm) return 'sm';
+ return 'xs';
+ })();
+
+ const getResponsiveValue = (
+ value: string | Partial>,
+ ) => {
+ if (typeof value === 'object') {
+ const breakpointsOrder: Breakpoint[] = [
+ 'xs',
+ 'sm',
+ 'md',
+ 'lg',
+ 'xl',
+ '2xl',
+ ];
+ const index = breakpointsOrder.indexOf(breakpoint);
+
+ for (let i = index; i >= 0; i--) {
+ if (value[breakpointsOrder[i]]) {
+ return value[breakpointsOrder[i]] as string;
+ }
+ }
+ return value['xs'] as string;
+ }
+ return value;
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+/** @public */
+export const useCanon = () => useContext(CanonContext);
diff --git a/packages/canon/docs/components/Columns/columns.css.ts b/packages/canon/src/css/base.css
similarity index 77%
rename from packages/canon/docs/components/Columns/columns.css.ts
rename to packages/canon/src/css/base.css
index 0b5ec18aef..b8bd0c4f81 100644
--- a/packages/canon/docs/components/Columns/columns.css.ts
+++ b/packages/canon/src/css/base.css
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-import { style } from '@vanilla-extract/css';
+@import './normalize.css';
-export const styles = style({
- display: 'grid',
- gridTemplateColumns: 'repeat(3, 1fr)',
- rowGap: '20px',
- columnGap: '80px',
-});
+@layer base {
+ *,
+ html,
+ body {
+ font-family: var(--canon-font-regular);
+ font-weight: var(--canon-font-weight-regular);
+ }
+}
diff --git a/packages/canon/src/theme/styles.css b/packages/canon/src/css/components.css
similarity index 71%
rename from packages/canon/src/theme/styles.css
rename to packages/canon/src/css/components.css
index 4a31340575..ed602b7ab7 100644
--- a/packages/canon/src/theme/styles.css
+++ b/packages/canon/src/css/components.css
@@ -14,14 +14,14 @@
* 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';
@import '../components/Inline/styles.css';
+@import '../components/Grid/styles.css';
+@import '../components/Container/styles.css';
+@import '../components/Icon/styles.css';
+@import '../components/Checkbox/styles.css';
+@import '../components/Table/styles.css';
+@import '../components/Text/styles.css';
+@import '../components/Heading/styles.css';
diff --git a/packages/canon/src/css/core.css b/packages/canon/src/css/core.css
new file mode 100644
index 0000000000..4f15d571c7
--- /dev/null
+++ b/packages/canon/src/css/core.css
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+/* Normalize */
+@import './base.css';
+@import './utilities.css';
+
+/* Light theme tokens */
+
+[data-theme='light'] {
+ /* Font families */
+ --canon-font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
+ 'Segoe UI Symbol', 'Noto Color Emoji';
+ --canon-font-monospace: ui-monospace, 'Menlo', 'Monaco', 'Consolas',
+ 'Liberation Mono', 'Courier New', monospace;
+
+ /* Font weights */
+ --canon-font-weight-regular: 400;
+ --canon-font-weight-bold: 600;
+
+ /* Font sizes */
+ --canon-font-size-label: 0.625rem; /* 10px */
+ --canon-font-size-caption: 0.75rem; /* 12px */
+ --canon-font-size-body: 0.875rem; /* 14px */
+ --canon-font-size-subtitle: 1rem; /* 16px */
+ --canon-font-size-title5: 1.25rem; /* 20px */
+ --canon-font-size-title4: 1.5rem; /* 24px */
+ --canon-font-size-title3: 2rem; /* 32px */
+ --canon-font-size-title2: 3rem; /* 48px */
+ --canon-font-size-title1: 4rem; /* 64px */
+ --canon-font-size-display: 5.75rem; /* 92px */
+
+ /* Spacing */
+ --canon-spacing-5xs: 0.125rem; /* 2px */
+ --canon-spacing-4xs: 0.25rem; /* 4px */
+ --canon-spacing-3xs: 0.375rem; /* 6px */
+ --canon-spacing-2xs: 0.5rem; /* 8px */
+ --canon-spacing-xs: 0.75rem; /* 12px */
+ --canon-spacing-sm: 1rem; /* 16px */
+ --canon-spacing-md: 1.5rem; /* 24px */
+ --canon-spacing-lg: 2rem; /* 32px */
+ --canon-spacing-xl: 2.5rem; /* 40px */
+ --canon-spacing-2xl: 3rem; /* 48px */
+ --canon-spacing-3xl: 3.5rem; /* 56px */
+
+ /* Border radius */
+ --canon-border-radius-2xs: 0.125rem; /* 2px */
+ --canon-border-radius-xs: 0.25rem; /* 4px */
+ --canon-border-radius-sm: 0.5rem; /* 8px */
+ --canon-border-radius-md: 0.75rem; /* 12px */
+ --canon-border-radius-lg: 1rem; /* 16px */
+ --canon-border-radius-xl: 1.25rem; /* 20px */
+ --canon-border-radius-2xl: 1.5rem; /* 24px */
+
+ /* Container */
+ --canon-container-max-width: 1200px;
+ --canon-container-padding: 1rem;
+
+ /* Colors */
+ --canon-accent: #000;
+ --canon-background: #f8f8f8;
+ --canon-surface-1: #fff;
+ --canon-surface-2: #f4f4f4;
+ --canon-surface-3: #f1f1f1;
+
+ /* Borders */
+ --canon-border-base: rgba(0, 0, 0, 0.1);
+ --canon-border-hover: rgba(0, 0, 0, 0.2);
+ --canon-border-warning: #e36d05;
+ --canon-border-error: #e22b2b;
+ --canon-border-selected: #1db954;
+
+ /* States - Add more states */
+ --canon-error: #f50000;
+
+ /* Text colors */
+ --canon-text-primary: #000;
+ --canon-text-primary-on-accent: #fff;
+ --canon-text-secondary: #646464;
+}
+
+/* Dark theme tokens */
+[data-theme='dark'] {
+ /* Font families */
+ --canon-font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
+ 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
+ 'Segoe UI Symbol', 'Noto Color Emoji';
+ --canon-font-monospace: ui-monospace, 'Menlo', 'Monaco', 'Consolas',
+ 'Liberation Mono', 'Courier New', monospace;
+
+ /* Font weights */
+ --canon-font-weight-regular: 400;
+ --canon-font-weight-bold: 600;
+
+ /* Font sizes */
+ --canon-font-size-label: 0.625rem; /* 10px */
+ --canon-font-size-caption: 0.75rem; /* 12px */
+ --canon-font-size-body: 0.875rem; /* 14px */
+ --canon-font-size-subtitle: 1rem; /* 16px */
+ --canon-font-size-title5: 1.25rem; /* 20px */
+ --canon-font-size-title4: 1.5rem; /* 24px */
+ --canon-font-size-title3: 2rem; /* 32px */
+ --canon-font-size-title2: 3rem; /* 48px */
+ --canon-font-size-title1: 4rem; /* 64px */
+ --canon-font-size-display: 5.75rem; /* 92px */
+
+ /* Spacing */
+ --canon-spacing-5xs: 0.125rem; /* 2px */
+ --canon-spacing-4xs: 0.25rem; /* 4px */
+ --canon-spacing-3xs: 0.375rem; /* 6px */
+ --canon-spacing-2xs: 0.5rem; /* 8px */
+ --canon-spacing-xs: 0.75rem; /* 12px */
+ --canon-spacing-sm: 1rem; /* 16px */
+ --canon-spacing-md: 1.5rem; /* 24px */
+ --canon-spacing-lg: 2rem; /* 32px */
+ --canon-spacing-xl: 2.5rem; /* 40px */
+ --canon-spacing-2xl: 3rem; /* 48px */
+ --canon-spacing-3xl: 3.5rem; /* 56px */
+
+ /* Border radius */
+ --canon-border-radius-2xs: 0.125rem; /* 2px */
+ --canon-border-radius-xs: 0.25rem; /* 4px */
+ --canon-border-radius-sm: 0.5rem; /* 8px */
+ --canon-border-radius-md: 0.75rem; /* 12px */
+ --canon-border-radius-lg: 1rem; /* 16px */
+ --canon-border-radius-xl: 1.25rem; /* 20px */
+ --canon-border-radius-2xl: 1.5rem; /* 24px */
+
+ /* Container */
+ --canon-container-max-width: 1200px;
+ --canon-container-padding: 1rem;
+
+ /* Colors */
+ --canon-accent: #fff;
+ --canon-background: #000;
+ --canon-surface-1: #121212;
+ --canon-surface-2: #1a1a1a;
+
+ /* Borders */
+ --canon-border-base: rgba(255, 255, 255, 0.2);
+ --canon-border-warning: #f50000;
+ --canon-border-error: #f87503;
+ --canon-border-selected: #25d262;
+
+ /* States - Add more states */
+ --canon-error: #f50000;
+
+ /* Text colors */
+ --canon-text-primary: #fff;
+ --canon-text-primary-on-accent: #000;
+ --canon-text-secondary: #b3b3b3;
+}
diff --git a/packages/canon/src/css/normalize.css b/packages/canon/src/css/normalize.css
new file mode 100644
index 0000000000..ca637e9d3f
--- /dev/null
+++ b/packages/canon/src/css/normalize.css
@@ -0,0 +1,203 @@
+/*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */
+
+/*
+Document
+========
+*/
+
+/**
+Use a better box model (opinionated).
+*/
+
+@layer base {
+ *,
+ ::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;
+ }
+}
diff --git a/packages/canon/src/css/utilities.css b/packages/canon/src/css/utilities.css
new file mode 100644
index 0000000000..ad4a8d03b4
--- /dev/null
+++ b/packages/canon/src/css/utilities.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/* Default utilities */
+@import './utilities/xs.css';
+
+/* Min 640px */
+@import './utilities/sm.css';
+
+/* Min 768px */
+@import './utilities/md.css';
+
+/* Min 1024px */
+@import './utilities/lg.css';
+
+/* Min 1280px */
+@import './utilities/xl.css';
+
+/* Min 1536px */
+@import './utilities/2xl.css';
diff --git a/packages/canon/src/css/utilities/2xl.css b/packages/canon/src/css/utilities/2xl.css
new file mode 100644
index 0000000000..4ea3d82db0
--- /dev/null
+++ b/packages/canon/src/css/utilities/2xl.css
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ */
+
+@layer utilities {
+ @media (min-width: 1536px) {
+ .cu-2xl-block {
+ display: block;
+ }
+
+ .cu-2xl-border-base {
+ border-color: var(--canon-border-base);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-2xl-border-error {
+ border-color: var(--canon-border-error);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-2xl-border-none {
+ border-color: transparent;
+ border-width: 0;
+ }
+
+ .cu-2xl-border-selected {
+ border-color: var(--canon-border-selected);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-2xl-border-warning {
+ border-color: var(--canon-border-warning);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-2xl-col-end-1 {
+ grid-column-end: 1;
+ }
+
+ .cu-2xl-col-end-10 {
+ grid-column-end: 10;
+ }
+
+ .cu-2xl-col-end-11 {
+ grid-column-end: 11;
+ }
+
+ .cu-2xl-col-end-12 {
+ grid-column-end: 12;
+ }
+
+ .cu-2xl-col-end-13 {
+ grid-column-end: 13;
+ }
+
+ .cu-2xl-col-end-2 {
+ grid-column-end: 2;
+ }
+
+ .cu-2xl-col-end-3 {
+ grid-column-end: 3;
+ }
+
+ .cu-2xl-col-end-4 {
+ grid-column-end: 4;
+ }
+
+ .cu-2xl-col-end-5 {
+ grid-column-end: 5;
+ }
+
+ .cu-2xl-col-end-6 {
+ grid-column-end: 6;
+ }
+
+ .cu-2xl-col-end-7 {
+ grid-column-end: 7;
+ }
+
+ .cu-2xl-col-end-8 {
+ grid-column-end: 8;
+ }
+
+ .cu-2xl-col-end-9 {
+ grid-column-end: 9;
+ }
+
+ .cu-2xl-col-end-auto {
+ grid-column-end: auto;
+ }
+
+ .cu-2xl-col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .cu-2xl-col-span-10 {
+ grid-column: span 10 / span 10;
+ }
+
+ .cu-2xl-col-span-11 {
+ grid-column: span 11 / span 11;
+ }
+
+ .cu-2xl-col-span-12 {
+ grid-column: span 12 / span 12;
+ }
+
+ .cu-2xl-col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ .cu-2xl-col-span-3 {
+ grid-column: span 3 / span 3;
+ }
+
+ .cu-2xl-col-span-4 {
+ grid-column: span 4 / span 4;
+ }
+
+ .cu-2xl-col-span-5 {
+ grid-column: span 5 / span 5;
+ }
+
+ .cu-2xl-col-span-6 {
+ grid-column: span 6 / span 6;
+ }
+
+ .cu-2xl-col-span-7 {
+ grid-column: span 7 / span 7;
+ }
+
+ .cu-2xl-col-span-8 {
+ grid-column: span 8 / span 8;
+ }
+
+ .cu-2xl-col-span-9 {
+ grid-column: span 9 / span 9;
+ }
+
+ .cu-2xl-col-span-auto {
+ grid-column: span auto / span auto;
+ }
+
+ .cu-2xl-col-start-1 {
+ grid-column-start: 1;
+ }
+
+ .cu-2xl-col-start-10 {
+ grid-column-start: 10;
+ }
+
+ .cu-2xl-col-start-11 {
+ grid-column-start: 11;
+ }
+
+ .cu-2xl-col-start-12 {
+ grid-column-start: 12;
+ }
+
+ .cu-2xl-col-start-13 {
+ grid-column-start: 13;
+ }
+
+ .cu-2xl-col-start-2 {
+ grid-column-start: 2;
+ }
+
+ .cu-2xl-col-start-3 {
+ grid-column-start: 3;
+ }
+
+ .cu-2xl-col-start-4 {
+ grid-column-start: 4;
+ }
+
+ .cu-2xl-col-start-5 {
+ grid-column-start: 5;
+ }
+
+ .cu-2xl-col-start-6 {
+ grid-column-start: 6;
+ }
+
+ .cu-2xl-col-start-7 {
+ grid-column-start: 7;
+ }
+
+ .cu-2xl-col-start-8 {
+ grid-column-start: 8;
+ }
+
+ .cu-2xl-col-start-9 {
+ grid-column-start: 9;
+ }
+
+ .cu-2xl-col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .cu-2xl-flex {
+ display: flex;
+ }
+
+ .cu-2xl-flex-col {
+ flex-direction: column;
+ }
+
+ .cu-2xl-flex-nowrap {
+ flex-wrap: nowrap;
+ }
+
+ .cu-2xl-flex-row {
+ flex-direction: row;
+ }
+
+ .cu-2xl-flex-wrap {
+ flex-wrap: wrap;
+ }
+
+ .cu-2xl-flex-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ .cu-2xl-gap-2xl {
+ gap: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-gap-lg {
+ gap: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-gap-md {
+ gap: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-gap-none {
+ gap: 0;
+ }
+
+ .cu-2xl-gap-sm {
+ gap: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-gap-xl {
+ gap: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-gap-xs {
+ gap: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-grid {
+ display: grid;
+ }
+
+ .cu-2xl-grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-10 {
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-11 {
+ grid-template-columns: repeat(11, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-12 {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-5 {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-6 {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-7 {
+ grid-template-columns: repeat(7, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-8 {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-9 {
+ grid-template-columns: repeat(9, minmax(0, 1fr));
+ }
+
+ .cu-2xl-grid-cols-auto {
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ }
+
+ .cu-2xl-hidden {
+ display: none;
+ }
+
+ .cu-2xl-inline {
+ display: inline;
+ }
+
+ .cu-2xl-inline-block {
+ display: inline-block;
+ }
+
+ .cu-2xl-items-center {
+ align-items: center;
+ }
+
+ .cu-2xl-items-end {
+ align-items: flex-end;
+ }
+
+ .cu-2xl-items-start {
+ align-items: flex-start;
+ }
+
+ .cu-2xl-items-stretch {
+ align-items: stretch;
+ }
+
+ .cu-2xl-justify-around {
+ justify-content: space-around;
+ }
+
+ .cu-2xl-justify-between {
+ justify-content: space-between;
+ }
+
+ .cu-2xl-justify-center {
+ justify-content: center;
+ }
+
+ .cu-2xl-justify-end {
+ justify-content: flex-end;
+ }
+
+ .cu-2xl-justify-start {
+ justify-content: flex-start;
+ }
+
+ .cu-2xl-justify-stretch {
+ justify-content: stretch;
+ }
+
+ .cu-2xl-m-2xl {
+ margin: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-m-2xs {
+ margin: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-m-lg {
+ margin: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-m-md {
+ margin: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-m-none {
+ margin: 0;
+ }
+
+ .cu-2xl-m-sm {
+ margin: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-m-xl {
+ margin: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-m-xs {
+ margin: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-mb-2xl {
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-mb-2xs {
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-mb-lg {
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-mb-md {
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-mb-none {
+ margin-bottom: 0;
+ }
+
+ .cu-2xl-mb-sm {
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-mb-xl {
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-mb-xs {
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-ml-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-ml-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-ml-lg {
+ margin-left: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-ml-md {
+ margin-left: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-ml-none {
+ margin-left: 0;
+ }
+
+ .cu-2xl-ml-sm {
+ margin-left: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-ml-xl {
+ margin-left: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-ml-xs {
+ margin-left: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-mr-2xl {
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-mr-2xs {
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-mr-lg {
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-mr-md {
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-mr-none {
+ margin-right: 0;
+ }
+
+ .cu-2xl-mr-sm {
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-mr-xl {
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-mr-xs {
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-mt-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-mt-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-mt-lg {
+ margin-top: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-mt-md {
+ margin-top: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-mt-none {
+ margin-top: 0;
+ }
+
+ .cu-2xl-mt-sm {
+ margin-top: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-mt-xl {
+ margin-top: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-mt-xs {
+ margin-top: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-mx-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-mx-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-mx-lg {
+ margin-left: var(--canon-spacing-lg);
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-mx-md {
+ margin-left: var(--canon-spacing-md);
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-mx-none {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cu-2xl-mx-sm {
+ margin-left: var(--canon-spacing-sm);
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-mx-xl {
+ margin-left: var(--canon-spacing-xl);
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-mx-xs {
+ margin-left: var(--canon-spacing-xs);
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-my-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-my-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-my-lg {
+ margin-top: var(--canon-spacing-lg);
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-my-md {
+ margin-top: var(--canon-spacing-md);
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-my-none {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .cu-2xl-my-sm {
+ margin-top: var(--canon-spacing-sm);
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-my-xl {
+ margin-top: var(--canon-spacing-xl);
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-my-xs {
+ margin-top: var(--canon-spacing-xs);
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-p-2xl {
+ padding: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-p-2xs {
+ padding: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-p-lg {
+ padding: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-p-md {
+ padding: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-p-none {
+ padding: 0;
+ }
+
+ .cu-2xl-p-sm {
+ padding: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-p-xl {
+ padding: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-p-xs {
+ padding: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-pb-2xl {
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-pb-2xs {
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-pb-lg {
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-pb-md {
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-pb-none {
+ padding-bottom: 0;
+ }
+
+ .cu-2xl-pb-sm {
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-pb-xl {
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-pb-xs {
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-pl-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-pl-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-pl-lg {
+ padding-left: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-pl-md {
+ padding-left: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-pl-none {
+ padding-left: 0;
+ }
+
+ .cu-2xl-pl-sm {
+ padding-left: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-pl-xl {
+ padding-left: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-pl-xs {
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-pr-2xl {
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-pr-2xs {
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-pr-lg {
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-pr-md {
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-pr-none {
+ padding-right: 0;
+ }
+
+ .cu-2xl-pr-sm {
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-pr-xl {
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-pr-xs {
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-pt-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-pt-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-pt-lg {
+ padding-top: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-pt-md {
+ padding-top: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-pt-none {
+ padding-top: 0;
+ }
+
+ .cu-2xl-pt-sm {
+ padding-top: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-pt-xl {
+ padding-top: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-pt-xs {
+ padding-top: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-px-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-px-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-px-lg {
+ padding-left: var(--canon-spacing-lg);
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-px-md {
+ padding-left: var(--canon-spacing-md);
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-px-none {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .cu-2xl-px-sm {
+ padding-left: var(--canon-spacing-sm);
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-px-xl {
+ padding-left: var(--canon-spacing-xl);
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-px-xs {
+ padding-left: var(--canon-spacing-xs);
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-py-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-2xl-py-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-2xl-py-lg {
+ padding-top: var(--canon-spacing-lg);
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-2xl-py-md {
+ padding-top: var(--canon-spacing-md);
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-2xl-py-none {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .cu-2xl-py-sm {
+ padding-top: var(--canon-spacing-sm);
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-2xl-py-xl {
+ padding-top: var(--canon-spacing-xl);
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-2xl-py-xs {
+ padding-top: var(--canon-spacing-xs);
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-2xl-rounded-2xl {
+ border-radius: var(--canon-border-radius-2xl);
+ }
+
+ .cu-2xl-rounded-2xs {
+ border-radius: var(--canon-border-radius-2xs);
+ }
+
+ .cu-2xl-rounded-lg {
+ border-radius: var(--canon-border-radius-lg);
+ }
+
+ .cu-2xl-rounded-md {
+ border-radius: var(--canon-border-radius-md);
+ }
+
+ .cu-2xl-rounded-none {
+ border-radius: 0;
+ }
+
+ .cu-2xl-rounded-sm {
+ border-radius: var(--canon-border-radius-sm);
+ }
+
+ .cu-2xl-rounded-xl {
+ border-radius: var(--canon-border-radius-xl);
+ }
+
+ .cu-2xl-rounded-xs {
+ border-radius: var(--canon-border-radius-xs);
+ }
+
+ .cu-2xl-row-span-1 {
+ grid-row: span 1 / span 1;
+ }
+
+ .cu-2xl-row-span-10 {
+ grid-row: span 10 / span 10;
+ }
+
+ .cu-2xl-row-span-11 {
+ grid-row: span 11 / span 11;
+ }
+
+ .cu-2xl-row-span-12 {
+ grid-row: span 12 / span 12;
+ }
+
+ .cu-2xl-row-span-2 {
+ grid-row: span 2 / span 2;
+ }
+
+ .cu-2xl-row-span-3 {
+ grid-row: span 3 / span 3;
+ }
+
+ .cu-2xl-row-span-4 {
+ grid-row: span 4 / span 4;
+ }
+
+ .cu-2xl-row-span-5 {
+ grid-row: span 5 / span 5;
+ }
+
+ .cu-2xl-row-span-6 {
+ grid-row: span 6 / span 6;
+ }
+
+ .cu-2xl-row-span-7 {
+ grid-row: span 7 / span 7;
+ }
+
+ .cu-2xl-row-span-8 {
+ grid-row: span 8 / span 8;
+ }
+
+ .cu-2xl-row-span-9 {
+ grid-row: span 9 / span 9;
+ }
+
+ .cu-2xl-row-span-auto {
+ grid-row: span auto / span auto;
+ }
+
+ .cu-2xl-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+ }
+}
diff --git a/packages/canon/src/css/utilities/lg.css b/packages/canon/src/css/utilities/lg.css
new file mode 100644
index 0000000000..caa2adb310
--- /dev/null
+++ b/packages/canon/src/css/utilities/lg.css
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ */
+
+@layer utilities {
+ @media (min-width: 1024px) {
+ .cu-lg-block {
+ display: block;
+ }
+
+ .cu-lg-border-base {
+ border-color: var(--canon-border-base);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-lg-border-error {
+ border-color: var(--canon-border-error);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-lg-border-none {
+ border-color: transparent;
+ border-width: 0;
+ }
+
+ .cu-lg-border-selected {
+ border-color: var(--canon-border-selected);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-lg-border-warning {
+ border-color: var(--canon-border-warning);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-lg-col-end-1 {
+ grid-column-end: 1;
+ }
+
+ .cu-lg-col-end-10 {
+ grid-column-end: 10;
+ }
+
+ .cu-lg-col-end-11 {
+ grid-column-end: 11;
+ }
+
+ .cu-lg-col-end-12 {
+ grid-column-end: 12;
+ }
+
+ .cu-lg-col-end-13 {
+ grid-column-end: 13;
+ }
+
+ .cu-lg-col-end-2 {
+ grid-column-end: 2;
+ }
+
+ .cu-lg-col-end-3 {
+ grid-column-end: 3;
+ }
+
+ .cu-lg-col-end-4 {
+ grid-column-end: 4;
+ }
+
+ .cu-lg-col-end-5 {
+ grid-column-end: 5;
+ }
+
+ .cu-lg-col-end-6 {
+ grid-column-end: 6;
+ }
+
+ .cu-lg-col-end-7 {
+ grid-column-end: 7;
+ }
+
+ .cu-lg-col-end-8 {
+ grid-column-end: 8;
+ }
+
+ .cu-lg-col-end-9 {
+ grid-column-end: 9;
+ }
+
+ .cu-lg-col-end-auto {
+ grid-column-end: auto;
+ }
+
+ .cu-lg-col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .cu-lg-col-span-10 {
+ grid-column: span 10 / span 10;
+ }
+
+ .cu-lg-col-span-11 {
+ grid-column: span 11 / span 11;
+ }
+
+ .cu-lg-col-span-12 {
+ grid-column: span 12 / span 12;
+ }
+
+ .cu-lg-col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ .cu-lg-col-span-3 {
+ grid-column: span 3 / span 3;
+ }
+
+ .cu-lg-col-span-4 {
+ grid-column: span 4 / span 4;
+ }
+
+ .cu-lg-col-span-5 {
+ grid-column: span 5 / span 5;
+ }
+
+ .cu-lg-col-span-6 {
+ grid-column: span 6 / span 6;
+ }
+
+ .cu-lg-col-span-7 {
+ grid-column: span 7 / span 7;
+ }
+
+ .cu-lg-col-span-8 {
+ grid-column: span 8 / span 8;
+ }
+
+ .cu-lg-col-span-9 {
+ grid-column: span 9 / span 9;
+ }
+
+ .cu-lg-col-span-auto {
+ grid-column: span auto / span auto;
+ }
+
+ .cu-lg-col-start-1 {
+ grid-column-start: 1;
+ }
+
+ .cu-lg-col-start-10 {
+ grid-column-start: 10;
+ }
+
+ .cu-lg-col-start-11 {
+ grid-column-start: 11;
+ }
+
+ .cu-lg-col-start-12 {
+ grid-column-start: 12;
+ }
+
+ .cu-lg-col-start-13 {
+ grid-column-start: 13;
+ }
+
+ .cu-lg-col-start-2 {
+ grid-column-start: 2;
+ }
+
+ .cu-lg-col-start-3 {
+ grid-column-start: 3;
+ }
+
+ .cu-lg-col-start-4 {
+ grid-column-start: 4;
+ }
+
+ .cu-lg-col-start-5 {
+ grid-column-start: 5;
+ }
+
+ .cu-lg-col-start-6 {
+ grid-column-start: 6;
+ }
+
+ .cu-lg-col-start-7 {
+ grid-column-start: 7;
+ }
+
+ .cu-lg-col-start-8 {
+ grid-column-start: 8;
+ }
+
+ .cu-lg-col-start-9 {
+ grid-column-start: 9;
+ }
+
+ .cu-lg-col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .cu-lg-flex {
+ display: flex;
+ }
+
+ .cu-lg-flex-col {
+ flex-direction: column;
+ }
+
+ .cu-lg-flex-nowrap {
+ flex-wrap: nowrap;
+ }
+
+ .cu-lg-flex-row {
+ flex-direction: row;
+ }
+
+ .cu-lg-flex-wrap {
+ flex-wrap: wrap;
+ }
+
+ .cu-lg-flex-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ .cu-lg-gap-2xl {
+ gap: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-gap-lg {
+ gap: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-gap-md {
+ gap: var(--canon-spacing-md);
+ }
+
+ .cu-lg-gap-none {
+ gap: 0;
+ }
+
+ .cu-lg-gap-sm {
+ gap: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-gap-xl {
+ gap: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-gap-xs {
+ gap: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-grid {
+ display: grid;
+ }
+
+ .cu-lg-grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-10 {
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-11 {
+ grid-template-columns: repeat(11, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-12 {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-5 {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-6 {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-7 {
+ grid-template-columns: repeat(7, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-8 {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-9 {
+ grid-template-columns: repeat(9, minmax(0, 1fr));
+ }
+
+ .cu-lg-grid-cols-auto {
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ }
+
+ .cu-lg-hidden {
+ display: none;
+ }
+
+ .cu-lg-inline {
+ display: inline;
+ }
+
+ .cu-lg-inline-block {
+ display: inline-block;
+ }
+
+ .cu-lg-items-center {
+ align-items: center;
+ }
+
+ .cu-lg-items-end {
+ align-items: flex-end;
+ }
+
+ .cu-lg-items-start {
+ align-items: flex-start;
+ }
+
+ .cu-lg-items-stretch {
+ align-items: stretch;
+ }
+
+ .cu-lg-justify-around {
+ justify-content: space-around;
+ }
+
+ .cu-lg-justify-between {
+ justify-content: space-between;
+ }
+
+ .cu-lg-justify-center {
+ justify-content: center;
+ }
+
+ .cu-lg-justify-end {
+ justify-content: flex-end;
+ }
+
+ .cu-lg-justify-start {
+ justify-content: flex-start;
+ }
+
+ .cu-lg-justify-stretch {
+ justify-content: stretch;
+ }
+
+ .cu-lg-m-2xl {
+ margin: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-m-2xs {
+ margin: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-m-lg {
+ margin: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-m-md {
+ margin: var(--canon-spacing-md);
+ }
+
+ .cu-lg-m-none {
+ margin: 0;
+ }
+
+ .cu-lg-m-sm {
+ margin: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-m-xl {
+ margin: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-m-xs {
+ margin: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-mb-2xl {
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-mb-2xs {
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-mb-lg {
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-mb-md {
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-lg-mb-none {
+ margin-bottom: 0;
+ }
+
+ .cu-lg-mb-sm {
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-mb-xl {
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-mb-xs {
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-ml-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-ml-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-ml-lg {
+ margin-left: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-ml-md {
+ margin-left: var(--canon-spacing-md);
+ }
+
+ .cu-lg-ml-none {
+ margin-left: 0;
+ }
+
+ .cu-lg-ml-sm {
+ margin-left: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-ml-xl {
+ margin-left: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-ml-xs {
+ margin-left: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-mr-2xl {
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-mr-2xs {
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-mr-lg {
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-mr-md {
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-lg-mr-none {
+ margin-right: 0;
+ }
+
+ .cu-lg-mr-sm {
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-mr-xl {
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-mr-xs {
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-mt-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-mt-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-mt-lg {
+ margin-top: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-mt-md {
+ margin-top: var(--canon-spacing-md);
+ }
+
+ .cu-lg-mt-none {
+ margin-top: 0;
+ }
+
+ .cu-lg-mt-sm {
+ margin-top: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-mt-xl {
+ margin-top: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-mt-xs {
+ margin-top: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-mx-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-mx-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-mx-lg {
+ margin-left: var(--canon-spacing-lg);
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-mx-md {
+ margin-left: var(--canon-spacing-md);
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-lg-mx-none {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cu-lg-mx-sm {
+ margin-left: var(--canon-spacing-sm);
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-mx-xl {
+ margin-left: var(--canon-spacing-xl);
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-mx-xs {
+ margin-left: var(--canon-spacing-xs);
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-my-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-my-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-my-lg {
+ margin-top: var(--canon-spacing-lg);
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-my-md {
+ margin-top: var(--canon-spacing-md);
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-lg-my-none {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .cu-lg-my-sm {
+ margin-top: var(--canon-spacing-sm);
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-my-xl {
+ margin-top: var(--canon-spacing-xl);
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-my-xs {
+ margin-top: var(--canon-spacing-xs);
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-p-2xl {
+ padding: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-p-2xs {
+ padding: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-p-lg {
+ padding: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-p-md {
+ padding: var(--canon-spacing-md);
+ }
+
+ .cu-lg-p-none {
+ padding: 0;
+ }
+
+ .cu-lg-p-sm {
+ padding: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-p-xl {
+ padding: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-p-xs {
+ padding: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-pb-2xl {
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-pb-2xs {
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-pb-lg {
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-pb-md {
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-lg-pb-none {
+ padding-bottom: 0;
+ }
+
+ .cu-lg-pb-sm {
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-pb-xl {
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-pb-xs {
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-pl-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-pl-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-pl-lg {
+ padding-left: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-pl-md {
+ padding-left: var(--canon-spacing-md);
+ }
+
+ .cu-lg-pl-none {
+ padding-left: 0;
+ }
+
+ .cu-lg-pl-sm {
+ padding-left: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-pl-xl {
+ padding-left: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-pl-xs {
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-pr-2xl {
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-pr-2xs {
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-pr-lg {
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-pr-md {
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-lg-pr-none {
+ padding-right: 0;
+ }
+
+ .cu-lg-pr-sm {
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-pr-xl {
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-pr-xs {
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-pt-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-pt-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-pt-lg {
+ padding-top: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-pt-md {
+ padding-top: var(--canon-spacing-md);
+ }
+
+ .cu-lg-pt-none {
+ padding-top: 0;
+ }
+
+ .cu-lg-pt-sm {
+ padding-top: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-pt-xl {
+ padding-top: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-pt-xs {
+ padding-top: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-px-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-px-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-px-lg {
+ padding-left: var(--canon-spacing-lg);
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-px-md {
+ padding-left: var(--canon-spacing-md);
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-lg-px-none {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .cu-lg-px-sm {
+ padding-left: var(--canon-spacing-sm);
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-px-xl {
+ padding-left: var(--canon-spacing-xl);
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-px-xs {
+ padding-left: var(--canon-spacing-xs);
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-py-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-lg-py-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-lg-py-lg {
+ padding-top: var(--canon-spacing-lg);
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-lg-py-md {
+ padding-top: var(--canon-spacing-md);
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-lg-py-none {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .cu-lg-py-sm {
+ padding-top: var(--canon-spacing-sm);
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-lg-py-xl {
+ padding-top: var(--canon-spacing-xl);
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-lg-py-xs {
+ padding-top: var(--canon-spacing-xs);
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-lg-rounded-2xl {
+ border-radius: var(--canon-border-radius-2xl);
+ }
+
+ .cu-lg-rounded-2xs {
+ border-radius: var(--canon-border-radius-2xs);
+ }
+
+ .cu-lg-rounded-lg {
+ border-radius: var(--canon-border-radius-lg);
+ }
+
+ .cu-lg-rounded-md {
+ border-radius: var(--canon-border-radius-md);
+ }
+
+ .cu-lg-rounded-none {
+ border-radius: 0;
+ }
+
+ .cu-lg-rounded-sm {
+ border-radius: var(--canon-border-radius-sm);
+ }
+
+ .cu-lg-rounded-xl {
+ border-radius: var(--canon-border-radius-xl);
+ }
+
+ .cu-lg-rounded-xs {
+ border-radius: var(--canon-border-radius-xs);
+ }
+
+ .cu-lg-row-span-1 {
+ grid-row: span 1 / span 1;
+ }
+
+ .cu-lg-row-span-10 {
+ grid-row: span 10 / span 10;
+ }
+
+ .cu-lg-row-span-11 {
+ grid-row: span 11 / span 11;
+ }
+
+ .cu-lg-row-span-12 {
+ grid-row: span 12 / span 12;
+ }
+
+ .cu-lg-row-span-2 {
+ grid-row: span 2 / span 2;
+ }
+
+ .cu-lg-row-span-3 {
+ grid-row: span 3 / span 3;
+ }
+
+ .cu-lg-row-span-4 {
+ grid-row: span 4 / span 4;
+ }
+
+ .cu-lg-row-span-5 {
+ grid-row: span 5 / span 5;
+ }
+
+ .cu-lg-row-span-6 {
+ grid-row: span 6 / span 6;
+ }
+
+ .cu-lg-row-span-7 {
+ grid-row: span 7 / span 7;
+ }
+
+ .cu-lg-row-span-8 {
+ grid-row: span 8 / span 8;
+ }
+
+ .cu-lg-row-span-9 {
+ grid-row: span 9 / span 9;
+ }
+
+ .cu-lg-row-span-auto {
+ grid-row: span auto / span auto;
+ }
+
+ .cu-lg-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+ }
+}
diff --git a/packages/canon/src/css/utilities/md.css b/packages/canon/src/css/utilities/md.css
new file mode 100644
index 0000000000..fe6d56ad7c
--- /dev/null
+++ b/packages/canon/src/css/utilities/md.css
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ */
+
+@layer utilities {
+ @media (min-width: 768px) {
+ .cu-md-block {
+ display: block;
+ }
+
+ .cu-md-border-base {
+ border-color: var(--canon-border-base);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-md-border-error {
+ border-color: var(--canon-border-error);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-md-border-none {
+ border-color: transparent;
+ border-width: 0;
+ }
+
+ .cu-md-border-selected {
+ border-color: var(--canon-border-selected);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-md-border-warning {
+ border-color: var(--canon-border-warning);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-md-col-end-1 {
+ grid-column-end: 1;
+ }
+
+ .cu-md-col-end-10 {
+ grid-column-end: 10;
+ }
+
+ .cu-md-col-end-11 {
+ grid-column-end: 11;
+ }
+
+ .cu-md-col-end-12 {
+ grid-column-end: 12;
+ }
+
+ .cu-md-col-end-13 {
+ grid-column-end: 13;
+ }
+
+ .cu-md-col-end-2 {
+ grid-column-end: 2;
+ }
+
+ .cu-md-col-end-3 {
+ grid-column-end: 3;
+ }
+
+ .cu-md-col-end-4 {
+ grid-column-end: 4;
+ }
+
+ .cu-md-col-end-5 {
+ grid-column-end: 5;
+ }
+
+ .cu-md-col-end-6 {
+ grid-column-end: 6;
+ }
+
+ .cu-md-col-end-7 {
+ grid-column-end: 7;
+ }
+
+ .cu-md-col-end-8 {
+ grid-column-end: 8;
+ }
+
+ .cu-md-col-end-9 {
+ grid-column-end: 9;
+ }
+
+ .cu-md-col-end-auto {
+ grid-column-end: auto;
+ }
+
+ .cu-md-col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .cu-md-col-span-10 {
+ grid-column: span 10 / span 10;
+ }
+
+ .cu-md-col-span-11 {
+ grid-column: span 11 / span 11;
+ }
+
+ .cu-md-col-span-12 {
+ grid-column: span 12 / span 12;
+ }
+
+ .cu-md-col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ .cu-md-col-span-3 {
+ grid-column: span 3 / span 3;
+ }
+
+ .cu-md-col-span-4 {
+ grid-column: span 4 / span 4;
+ }
+
+ .cu-md-col-span-5 {
+ grid-column: span 5 / span 5;
+ }
+
+ .cu-md-col-span-6 {
+ grid-column: span 6 / span 6;
+ }
+
+ .cu-md-col-span-7 {
+ grid-column: span 7 / span 7;
+ }
+
+ .cu-md-col-span-8 {
+ grid-column: span 8 / span 8;
+ }
+
+ .cu-md-col-span-9 {
+ grid-column: span 9 / span 9;
+ }
+
+ .cu-md-col-span-auto {
+ grid-column: span auto / span auto;
+ }
+
+ .cu-md-col-start-1 {
+ grid-column-start: 1;
+ }
+
+ .cu-md-col-start-10 {
+ grid-column-start: 10;
+ }
+
+ .cu-md-col-start-11 {
+ grid-column-start: 11;
+ }
+
+ .cu-md-col-start-12 {
+ grid-column-start: 12;
+ }
+
+ .cu-md-col-start-13 {
+ grid-column-start: 13;
+ }
+
+ .cu-md-col-start-2 {
+ grid-column-start: 2;
+ }
+
+ .cu-md-col-start-3 {
+ grid-column-start: 3;
+ }
+
+ .cu-md-col-start-4 {
+ grid-column-start: 4;
+ }
+
+ .cu-md-col-start-5 {
+ grid-column-start: 5;
+ }
+
+ .cu-md-col-start-6 {
+ grid-column-start: 6;
+ }
+
+ .cu-md-col-start-7 {
+ grid-column-start: 7;
+ }
+
+ .cu-md-col-start-8 {
+ grid-column-start: 8;
+ }
+
+ .cu-md-col-start-9 {
+ grid-column-start: 9;
+ }
+
+ .cu-md-col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .cu-md-flex {
+ display: flex;
+ }
+
+ .cu-md-flex-col {
+ flex-direction: column;
+ }
+
+ .cu-md-flex-nowrap {
+ flex-wrap: nowrap;
+ }
+
+ .cu-md-flex-row {
+ flex-direction: row;
+ }
+
+ .cu-md-flex-wrap {
+ flex-wrap: wrap;
+ }
+
+ .cu-md-flex-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ .cu-md-gap-2xl {
+ gap: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-gap-lg {
+ gap: var(--canon-spacing-lg);
+ }
+
+ .cu-md-gap-md {
+ gap: var(--canon-spacing-md);
+ }
+
+ .cu-md-gap-none {
+ gap: 0;
+ }
+
+ .cu-md-gap-sm {
+ gap: var(--canon-spacing-sm);
+ }
+
+ .cu-md-gap-xl {
+ gap: var(--canon-spacing-xl);
+ }
+
+ .cu-md-gap-xs {
+ gap: var(--canon-spacing-xs);
+ }
+
+ .cu-md-grid {
+ display: grid;
+ }
+
+ .cu-md-grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-10 {
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-11 {
+ grid-template-columns: repeat(11, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-12 {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-5 {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-6 {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-7 {
+ grid-template-columns: repeat(7, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-8 {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-9 {
+ grid-template-columns: repeat(9, minmax(0, 1fr));
+ }
+
+ .cu-md-grid-cols-auto {
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ }
+
+ .cu-md-hidden {
+ display: none;
+ }
+
+ .cu-md-inline {
+ display: inline;
+ }
+
+ .cu-md-inline-block {
+ display: inline-block;
+ }
+
+ .cu-md-items-center {
+ align-items: center;
+ }
+
+ .cu-md-items-end {
+ align-items: flex-end;
+ }
+
+ .cu-md-items-start {
+ align-items: flex-start;
+ }
+
+ .cu-md-items-stretch {
+ align-items: stretch;
+ }
+
+ .cu-md-justify-around {
+ justify-content: space-around;
+ }
+
+ .cu-md-justify-between {
+ justify-content: space-between;
+ }
+
+ .cu-md-justify-center {
+ justify-content: center;
+ }
+
+ .cu-md-justify-end {
+ justify-content: flex-end;
+ }
+
+ .cu-md-justify-start {
+ justify-content: flex-start;
+ }
+
+ .cu-md-justify-stretch {
+ justify-content: stretch;
+ }
+
+ .cu-md-m-2xl {
+ margin: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-m-2xs {
+ margin: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-m-lg {
+ margin: var(--canon-spacing-lg);
+ }
+
+ .cu-md-m-md {
+ margin: var(--canon-spacing-md);
+ }
+
+ .cu-md-m-none {
+ margin: 0;
+ }
+
+ .cu-md-m-sm {
+ margin: var(--canon-spacing-sm);
+ }
+
+ .cu-md-m-xl {
+ margin: var(--canon-spacing-xl);
+ }
+
+ .cu-md-m-xs {
+ margin: var(--canon-spacing-xs);
+ }
+
+ .cu-md-mb-2xl {
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-mb-2xs {
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-mb-lg {
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-md-mb-md {
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-md-mb-none {
+ margin-bottom: 0;
+ }
+
+ .cu-md-mb-sm {
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-md-mb-xl {
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-md-mb-xs {
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-md-ml-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-ml-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-ml-lg {
+ margin-left: var(--canon-spacing-lg);
+ }
+
+ .cu-md-ml-md {
+ margin-left: var(--canon-spacing-md);
+ }
+
+ .cu-md-ml-none {
+ margin-left: 0;
+ }
+
+ .cu-md-ml-sm {
+ margin-left: var(--canon-spacing-sm);
+ }
+
+ .cu-md-ml-xl {
+ margin-left: var(--canon-spacing-xl);
+ }
+
+ .cu-md-ml-xs {
+ margin-left: var(--canon-spacing-xs);
+ }
+
+ .cu-md-mr-2xl {
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-mr-2xs {
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-mr-lg {
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-md-mr-md {
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-md-mr-none {
+ margin-right: 0;
+ }
+
+ .cu-md-mr-sm {
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-md-mr-xl {
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-md-mr-xs {
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-md-mt-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-mt-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-mt-lg {
+ margin-top: var(--canon-spacing-lg);
+ }
+
+ .cu-md-mt-md {
+ margin-top: var(--canon-spacing-md);
+ }
+
+ .cu-md-mt-none {
+ margin-top: 0;
+ }
+
+ .cu-md-mt-sm {
+ margin-top: var(--canon-spacing-sm);
+ }
+
+ .cu-md-mt-xl {
+ margin-top: var(--canon-spacing-xl);
+ }
+
+ .cu-md-mt-xs {
+ margin-top: var(--canon-spacing-xs);
+ }
+
+ .cu-md-mx-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-mx-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-mx-lg {
+ margin-left: var(--canon-spacing-lg);
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-md-mx-md {
+ margin-left: var(--canon-spacing-md);
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-md-mx-none {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cu-md-mx-sm {
+ margin-left: var(--canon-spacing-sm);
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-md-mx-xl {
+ margin-left: var(--canon-spacing-xl);
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-md-mx-xs {
+ margin-left: var(--canon-spacing-xs);
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-md-my-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-my-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-my-lg {
+ margin-top: var(--canon-spacing-lg);
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-md-my-md {
+ margin-top: var(--canon-spacing-md);
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-md-my-none {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .cu-md-my-sm {
+ margin-top: var(--canon-spacing-sm);
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-md-my-xl {
+ margin-top: var(--canon-spacing-xl);
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-md-my-xs {
+ margin-top: var(--canon-spacing-xs);
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-md-p-2xl {
+ padding: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-p-2xs {
+ padding: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-p-lg {
+ padding: var(--canon-spacing-lg);
+ }
+
+ .cu-md-p-md {
+ padding: var(--canon-spacing-md);
+ }
+
+ .cu-md-p-none {
+ padding: 0;
+ }
+
+ .cu-md-p-sm {
+ padding: var(--canon-spacing-sm);
+ }
+
+ .cu-md-p-xl {
+ padding: var(--canon-spacing-xl);
+ }
+
+ .cu-md-p-xs {
+ padding: var(--canon-spacing-xs);
+ }
+
+ .cu-md-pb-2xl {
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-pb-2xs {
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-pb-lg {
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-md-pb-md {
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-md-pb-none {
+ padding-bottom: 0;
+ }
+
+ .cu-md-pb-sm {
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-md-pb-xl {
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-md-pb-xs {
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-md-pl-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-pl-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-pl-lg {
+ padding-left: var(--canon-spacing-lg);
+ }
+
+ .cu-md-pl-md {
+ padding-left: var(--canon-spacing-md);
+ }
+
+ .cu-md-pl-none {
+ padding-left: 0;
+ }
+
+ .cu-md-pl-sm {
+ padding-left: var(--canon-spacing-sm);
+ }
+
+ .cu-md-pl-xl {
+ padding-left: var(--canon-spacing-xl);
+ }
+
+ .cu-md-pl-xs {
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ .cu-md-pr-2xl {
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-pr-2xs {
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-pr-lg {
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-md-pr-md {
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-md-pr-none {
+ padding-right: 0;
+ }
+
+ .cu-md-pr-sm {
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-md-pr-xl {
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-md-pr-xs {
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-md-pt-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-pt-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-pt-lg {
+ padding-top: var(--canon-spacing-lg);
+ }
+
+ .cu-md-pt-md {
+ padding-top: var(--canon-spacing-md);
+ }
+
+ .cu-md-pt-none {
+ padding-top: 0;
+ }
+
+ .cu-md-pt-sm {
+ padding-top: var(--canon-spacing-sm);
+ }
+
+ .cu-md-pt-xl {
+ padding-top: var(--canon-spacing-xl);
+ }
+
+ .cu-md-pt-xs {
+ padding-top: var(--canon-spacing-xs);
+ }
+
+ .cu-md-px-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-px-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-px-lg {
+ padding-left: var(--canon-spacing-lg);
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-md-px-md {
+ padding-left: var(--canon-spacing-md);
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-md-px-none {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .cu-md-px-sm {
+ padding-left: var(--canon-spacing-sm);
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-md-px-xl {
+ padding-left: var(--canon-spacing-xl);
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-md-px-xs {
+ padding-left: var(--canon-spacing-xs);
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-md-py-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-md-py-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-md-py-lg {
+ padding-top: var(--canon-spacing-lg);
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-md-py-md {
+ padding-top: var(--canon-spacing-md);
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-md-py-none {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .cu-md-py-sm {
+ padding-top: var(--canon-spacing-sm);
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-md-py-xl {
+ padding-top: var(--canon-spacing-xl);
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-md-py-xs {
+ padding-top: var(--canon-spacing-xs);
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-md-rounded-2xl {
+ border-radius: var(--canon-border-radius-2xl);
+ }
+
+ .cu-md-rounded-2xs {
+ border-radius: var(--canon-border-radius-2xs);
+ }
+
+ .cu-md-rounded-lg {
+ border-radius: var(--canon-border-radius-lg);
+ }
+
+ .cu-md-rounded-md {
+ border-radius: var(--canon-border-radius-md);
+ }
+
+ .cu-md-rounded-none {
+ border-radius: 0;
+ }
+
+ .cu-md-rounded-sm {
+ border-radius: var(--canon-border-radius-sm);
+ }
+
+ .cu-md-rounded-xl {
+ border-radius: var(--canon-border-radius-xl);
+ }
+
+ .cu-md-rounded-xs {
+ border-radius: var(--canon-border-radius-xs);
+ }
+
+ .cu-md-row-span-1 {
+ grid-row: span 1 / span 1;
+ }
+
+ .cu-md-row-span-10 {
+ grid-row: span 10 / span 10;
+ }
+
+ .cu-md-row-span-11 {
+ grid-row: span 11 / span 11;
+ }
+
+ .cu-md-row-span-12 {
+ grid-row: span 12 / span 12;
+ }
+
+ .cu-md-row-span-2 {
+ grid-row: span 2 / span 2;
+ }
+
+ .cu-md-row-span-3 {
+ grid-row: span 3 / span 3;
+ }
+
+ .cu-md-row-span-4 {
+ grid-row: span 4 / span 4;
+ }
+
+ .cu-md-row-span-5 {
+ grid-row: span 5 / span 5;
+ }
+
+ .cu-md-row-span-6 {
+ grid-row: span 6 / span 6;
+ }
+
+ .cu-md-row-span-7 {
+ grid-row: span 7 / span 7;
+ }
+
+ .cu-md-row-span-8 {
+ grid-row: span 8 / span 8;
+ }
+
+ .cu-md-row-span-9 {
+ grid-row: span 9 / span 9;
+ }
+
+ .cu-md-row-span-auto {
+ grid-row: span auto / span auto;
+ }
+
+ .cu-md-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+ }
+}
diff --git a/packages/canon/src/css/utilities/sm.css b/packages/canon/src/css/utilities/sm.css
new file mode 100644
index 0000000000..87657c2222
--- /dev/null
+++ b/packages/canon/src/css/utilities/sm.css
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ */
+
+@layer utilities {
+ @media (min-width: 640px) {
+ .cu-sm-block {
+ display: block;
+ }
+
+ .cu-sm-border-base {
+ border-color: var(--canon-border-base);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-sm-border-error {
+ border-color: var(--canon-border-error);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-sm-border-none {
+ border-color: transparent;
+ border-width: 0;
+ }
+
+ .cu-sm-border-selected {
+ border-color: var(--canon-border-selected);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-sm-border-warning {
+ border-color: var(--canon-border-warning);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-sm-col-end-1 {
+ grid-column-end: 1;
+ }
+
+ .cu-sm-col-end-10 {
+ grid-column-end: 10;
+ }
+
+ .cu-sm-col-end-11 {
+ grid-column-end: 11;
+ }
+
+ .cu-sm-col-end-12 {
+ grid-column-end: 12;
+ }
+
+ .cu-sm-col-end-13 {
+ grid-column-end: 13;
+ }
+
+ .cu-sm-col-end-2 {
+ grid-column-end: 2;
+ }
+
+ .cu-sm-col-end-3 {
+ grid-column-end: 3;
+ }
+
+ .cu-sm-col-end-4 {
+ grid-column-end: 4;
+ }
+
+ .cu-sm-col-end-5 {
+ grid-column-end: 5;
+ }
+
+ .cu-sm-col-end-6 {
+ grid-column-end: 6;
+ }
+
+ .cu-sm-col-end-7 {
+ grid-column-end: 7;
+ }
+
+ .cu-sm-col-end-8 {
+ grid-column-end: 8;
+ }
+
+ .cu-sm-col-end-9 {
+ grid-column-end: 9;
+ }
+
+ .cu-sm-col-end-auto {
+ grid-column-end: auto;
+ }
+
+ .cu-sm-col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .cu-sm-col-span-10 {
+ grid-column: span 10 / span 10;
+ }
+
+ .cu-sm-col-span-11 {
+ grid-column: span 11 / span 11;
+ }
+
+ .cu-sm-col-span-12 {
+ grid-column: span 12 / span 12;
+ }
+
+ .cu-sm-col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ .cu-sm-col-span-3 {
+ grid-column: span 3 / span 3;
+ }
+
+ .cu-sm-col-span-4 {
+ grid-column: span 4 / span 4;
+ }
+
+ .cu-sm-col-span-5 {
+ grid-column: span 5 / span 5;
+ }
+
+ .cu-sm-col-span-6 {
+ grid-column: span 6 / span 6;
+ }
+
+ .cu-sm-col-span-7 {
+ grid-column: span 7 / span 7;
+ }
+
+ .cu-sm-col-span-8 {
+ grid-column: span 8 / span 8;
+ }
+
+ .cu-sm-col-span-9 {
+ grid-column: span 9 / span 9;
+ }
+
+ .cu-sm-col-span-auto {
+ grid-column: span auto / span auto;
+ }
+
+ .cu-sm-col-start-1 {
+ grid-column-start: 1;
+ }
+
+ .cu-sm-col-start-10 {
+ grid-column-start: 10;
+ }
+
+ .cu-sm-col-start-11 {
+ grid-column-start: 11;
+ }
+
+ .cu-sm-col-start-12 {
+ grid-column-start: 12;
+ }
+
+ .cu-sm-col-start-13 {
+ grid-column-start: 13;
+ }
+
+ .cu-sm-col-start-2 {
+ grid-column-start: 2;
+ }
+
+ .cu-sm-col-start-3 {
+ grid-column-start: 3;
+ }
+
+ .cu-sm-col-start-4 {
+ grid-column-start: 4;
+ }
+
+ .cu-sm-col-start-5 {
+ grid-column-start: 5;
+ }
+
+ .cu-sm-col-start-6 {
+ grid-column-start: 6;
+ }
+
+ .cu-sm-col-start-7 {
+ grid-column-start: 7;
+ }
+
+ .cu-sm-col-start-8 {
+ grid-column-start: 8;
+ }
+
+ .cu-sm-col-start-9 {
+ grid-column-start: 9;
+ }
+
+ .cu-sm-col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .cu-sm-flex {
+ display: flex;
+ }
+
+ .cu-sm-flex-col {
+ flex-direction: column;
+ }
+
+ .cu-sm-flex-nowrap {
+ flex-wrap: nowrap;
+ }
+
+ .cu-sm-flex-row {
+ flex-direction: row;
+ }
+
+ .cu-sm-flex-wrap {
+ flex-wrap: wrap;
+ }
+
+ .cu-sm-flex-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ .cu-sm-gap-2xl {
+ gap: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-gap-lg {
+ gap: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-gap-md {
+ gap: var(--canon-spacing-md);
+ }
+
+ .cu-sm-gap-none {
+ gap: 0;
+ }
+
+ .cu-sm-gap-sm {
+ gap: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-gap-xl {
+ gap: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-gap-xs {
+ gap: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-grid {
+ display: grid;
+ }
+
+ .cu-sm-grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-10 {
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-11 {
+ grid-template-columns: repeat(11, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-12 {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-5 {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-6 {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-7 {
+ grid-template-columns: repeat(7, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-8 {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-9 {
+ grid-template-columns: repeat(9, minmax(0, 1fr));
+ }
+
+ .cu-sm-grid-cols-auto {
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ }
+
+ .cu-sm-hidden {
+ display: none;
+ }
+
+ .cu-sm-inline {
+ display: inline;
+ }
+
+ .cu-sm-inline-block {
+ display: inline-block;
+ }
+
+ .cu-sm-items-center {
+ align-items: center;
+ }
+
+ .cu-sm-items-end {
+ align-items: flex-end;
+ }
+
+ .cu-sm-items-start {
+ align-items: flex-start;
+ }
+
+ .cu-sm-items-stretch {
+ align-items: stretch;
+ }
+
+ .cu-sm-justify-around {
+ justify-content: space-around;
+ }
+
+ .cu-sm-justify-between {
+ justify-content: space-between;
+ }
+
+ .cu-sm-justify-center {
+ justify-content: center;
+ }
+
+ .cu-sm-justify-end {
+ justify-content: flex-end;
+ }
+
+ .cu-sm-justify-start {
+ justify-content: flex-start;
+ }
+
+ .cu-sm-justify-stretch {
+ justify-content: stretch;
+ }
+
+ .cu-sm-m-2xl {
+ margin: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-m-2xs {
+ margin: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-m-lg {
+ margin: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-m-md {
+ margin: var(--canon-spacing-md);
+ }
+
+ .cu-sm-m-none {
+ margin: 0;
+ }
+
+ .cu-sm-m-sm {
+ margin: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-m-xl {
+ margin: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-m-xs {
+ margin: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-mb-2xl {
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-mb-2xs {
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-mb-lg {
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-mb-md {
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-sm-mb-none {
+ margin-bottom: 0;
+ }
+
+ .cu-sm-mb-sm {
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-mb-xl {
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-mb-xs {
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-ml-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-ml-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-ml-lg {
+ margin-left: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-ml-md {
+ margin-left: var(--canon-spacing-md);
+ }
+
+ .cu-sm-ml-none {
+ margin-left: 0;
+ }
+
+ .cu-sm-ml-sm {
+ margin-left: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-ml-xl {
+ margin-left: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-ml-xs {
+ margin-left: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-mr-2xl {
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-mr-2xs {
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-mr-lg {
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-mr-md {
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-sm-mr-none {
+ margin-right: 0;
+ }
+
+ .cu-sm-mr-sm {
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-mr-xl {
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-mr-xs {
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-mt-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-mt-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-mt-lg {
+ margin-top: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-mt-md {
+ margin-top: var(--canon-spacing-md);
+ }
+
+ .cu-sm-mt-none {
+ margin-top: 0;
+ }
+
+ .cu-sm-mt-sm {
+ margin-top: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-mt-xl {
+ margin-top: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-mt-xs {
+ margin-top: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-mx-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-mx-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-mx-lg {
+ margin-left: var(--canon-spacing-lg);
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-mx-md {
+ margin-left: var(--canon-spacing-md);
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-sm-mx-none {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cu-sm-mx-sm {
+ margin-left: var(--canon-spacing-sm);
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-mx-xl {
+ margin-left: var(--canon-spacing-xl);
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-mx-xs {
+ margin-left: var(--canon-spacing-xs);
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-my-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-my-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-my-lg {
+ margin-top: var(--canon-spacing-lg);
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-my-md {
+ margin-top: var(--canon-spacing-md);
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-sm-my-none {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .cu-sm-my-sm {
+ margin-top: var(--canon-spacing-sm);
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-my-xl {
+ margin-top: var(--canon-spacing-xl);
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-my-xs {
+ margin-top: var(--canon-spacing-xs);
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-p-2xl {
+ padding: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-p-2xs {
+ padding: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-p-lg {
+ padding: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-p-md {
+ padding: var(--canon-spacing-md);
+ }
+
+ .cu-sm-p-none {
+ padding: 0;
+ }
+
+ .cu-sm-p-sm {
+ padding: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-p-xl {
+ padding: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-p-xs {
+ padding: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-pb-2xl {
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-pb-2xs {
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-pb-lg {
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-pb-md {
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-sm-pb-none {
+ padding-bottom: 0;
+ }
+
+ .cu-sm-pb-sm {
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-pb-xl {
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-pb-xs {
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-pl-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-pl-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-pl-lg {
+ padding-left: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-pl-md {
+ padding-left: var(--canon-spacing-md);
+ }
+
+ .cu-sm-pl-none {
+ padding-left: 0;
+ }
+
+ .cu-sm-pl-sm {
+ padding-left: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-pl-xl {
+ padding-left: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-pl-xs {
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-pr-2xl {
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-pr-2xs {
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-pr-lg {
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-pr-md {
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-sm-pr-none {
+ padding-right: 0;
+ }
+
+ .cu-sm-pr-sm {
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-pr-xl {
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-pr-xs {
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-pt-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-pt-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-pt-lg {
+ padding-top: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-pt-md {
+ padding-top: var(--canon-spacing-md);
+ }
+
+ .cu-sm-pt-none {
+ padding-top: 0;
+ }
+
+ .cu-sm-pt-sm {
+ padding-top: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-pt-xl {
+ padding-top: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-pt-xs {
+ padding-top: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-px-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-px-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-px-lg {
+ padding-left: var(--canon-spacing-lg);
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-px-md {
+ padding-left: var(--canon-spacing-md);
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-sm-px-none {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .cu-sm-px-sm {
+ padding-left: var(--canon-spacing-sm);
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-px-xl {
+ padding-left: var(--canon-spacing-xl);
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-px-xs {
+ padding-left: var(--canon-spacing-xs);
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-py-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-sm-py-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-sm-py-lg {
+ padding-top: var(--canon-spacing-lg);
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-sm-py-md {
+ padding-top: var(--canon-spacing-md);
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-sm-py-none {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .cu-sm-py-sm {
+ padding-top: var(--canon-spacing-sm);
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-sm-py-xl {
+ padding-top: var(--canon-spacing-xl);
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-sm-py-xs {
+ padding-top: var(--canon-spacing-xs);
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-sm-rounded-2xl {
+ border-radius: var(--canon-border-radius-2xl);
+ }
+
+ .cu-sm-rounded-2xs {
+ border-radius: var(--canon-border-radius-2xs);
+ }
+
+ .cu-sm-rounded-lg {
+ border-radius: var(--canon-border-radius-lg);
+ }
+
+ .cu-sm-rounded-md {
+ border-radius: var(--canon-border-radius-md);
+ }
+
+ .cu-sm-rounded-none {
+ border-radius: 0;
+ }
+
+ .cu-sm-rounded-sm {
+ border-radius: var(--canon-border-radius-sm);
+ }
+
+ .cu-sm-rounded-xl {
+ border-radius: var(--canon-border-radius-xl);
+ }
+
+ .cu-sm-rounded-xs {
+ border-radius: var(--canon-border-radius-xs);
+ }
+
+ .cu-sm-row-span-1 {
+ grid-row: span 1 / span 1;
+ }
+
+ .cu-sm-row-span-10 {
+ grid-row: span 10 / span 10;
+ }
+
+ .cu-sm-row-span-11 {
+ grid-row: span 11 / span 11;
+ }
+
+ .cu-sm-row-span-12 {
+ grid-row: span 12 / span 12;
+ }
+
+ .cu-sm-row-span-2 {
+ grid-row: span 2 / span 2;
+ }
+
+ .cu-sm-row-span-3 {
+ grid-row: span 3 / span 3;
+ }
+
+ .cu-sm-row-span-4 {
+ grid-row: span 4 / span 4;
+ }
+
+ .cu-sm-row-span-5 {
+ grid-row: span 5 / span 5;
+ }
+
+ .cu-sm-row-span-6 {
+ grid-row: span 6 / span 6;
+ }
+
+ .cu-sm-row-span-7 {
+ grid-row: span 7 / span 7;
+ }
+
+ .cu-sm-row-span-8 {
+ grid-row: span 8 / span 8;
+ }
+
+ .cu-sm-row-span-9 {
+ grid-row: span 9 / span 9;
+ }
+
+ .cu-sm-row-span-auto {
+ grid-row: span auto / span auto;
+ }
+
+ .cu-sm-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+ }
+}
diff --git a/packages/canon/src/css/utilities/xl.css b/packages/canon/src/css/utilities/xl.css
new file mode 100644
index 0000000000..7d9e3b8add
--- /dev/null
+++ b/packages/canon/src/css/utilities/xl.css
@@ -0,0 +1,944 @@
+/*
+ * 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.
+ */
+
+@layer utilities {
+ @media (min-width: 1280px) {
+ .cu-xl-block {
+ display: block;
+ }
+
+ .cu-xl-border-base {
+ border-color: var(--canon-border-base);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-xl-border-error {
+ border-color: var(--canon-border-error);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-xl-border-none {
+ border-color: transparent;
+ border-width: 0;
+ }
+
+ .cu-xl-border-selected {
+ border-color: var(--canon-border-selected);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-xl-border-warning {
+ border-color: var(--canon-border-warning);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-xl-col-end-1 {
+ grid-column-end: 1;
+ }
+
+ .cu-xl-col-end-10 {
+ grid-column-end: 10;
+ }
+
+ .cu-xl-col-end-11 {
+ grid-column-end: 11;
+ }
+
+ .cu-xl-col-end-12 {
+ grid-column-end: 12;
+ }
+
+ .cu-xl-col-end-13 {
+ grid-column-end: 13;
+ }
+
+ .cu-xl-col-end-2 {
+ grid-column-end: 2;
+ }
+
+ .cu-xl-col-end-3 {
+ grid-column-end: 3;
+ }
+
+ .cu-xl-col-end-4 {
+ grid-column-end: 4;
+ }
+
+ .cu-xl-col-end-5 {
+ grid-column-end: 5;
+ }
+
+ .cu-xl-col-end-6 {
+ grid-column-end: 6;
+ }
+
+ .cu-xl-col-end-7 {
+ grid-column-end: 7;
+ }
+
+ .cu-xl-col-end-8 {
+ grid-column-end: 8;
+ }
+
+ .cu-xl-col-end-9 {
+ grid-column-end: 9;
+ }
+
+ .cu-xl-col-end-auto {
+ grid-column-end: auto;
+ }
+
+ .cu-xl-col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .cu-xl-col-span-10 {
+ grid-column: span 10 / span 10;
+ }
+
+ .cu-xl-col-span-11 {
+ grid-column: span 11 / span 11;
+ }
+
+ .cu-xl-col-span-12 {
+ grid-column: span 12 / span 12;
+ }
+
+ .cu-xl-col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ .cu-xl-col-span-3 {
+ grid-column: span 3 / span 3;
+ }
+
+ .cu-xl-col-span-4 {
+ grid-column: span 4 / span 4;
+ }
+
+ .cu-xl-col-span-5 {
+ grid-column: span 5 / span 5;
+ }
+
+ .cu-xl-col-span-6 {
+ grid-column: span 6 / span 6;
+ }
+
+ .cu-xl-col-span-7 {
+ grid-column: span 7 / span 7;
+ }
+
+ .cu-xl-col-span-8 {
+ grid-column: span 8 / span 8;
+ }
+
+ .cu-xl-col-span-9 {
+ grid-column: span 9 / span 9;
+ }
+
+ .cu-xl-col-span-auto {
+ grid-column: span auto / span auto;
+ }
+
+ .cu-xl-col-start-1 {
+ grid-column-start: 1;
+ }
+
+ .cu-xl-col-start-10 {
+ grid-column-start: 10;
+ }
+
+ .cu-xl-col-start-11 {
+ grid-column-start: 11;
+ }
+
+ .cu-xl-col-start-12 {
+ grid-column-start: 12;
+ }
+
+ .cu-xl-col-start-13 {
+ grid-column-start: 13;
+ }
+
+ .cu-xl-col-start-2 {
+ grid-column-start: 2;
+ }
+
+ .cu-xl-col-start-3 {
+ grid-column-start: 3;
+ }
+
+ .cu-xl-col-start-4 {
+ grid-column-start: 4;
+ }
+
+ .cu-xl-col-start-5 {
+ grid-column-start: 5;
+ }
+
+ .cu-xl-col-start-6 {
+ grid-column-start: 6;
+ }
+
+ .cu-xl-col-start-7 {
+ grid-column-start: 7;
+ }
+
+ .cu-xl-col-start-8 {
+ grid-column-start: 8;
+ }
+
+ .cu-xl-col-start-9 {
+ grid-column-start: 9;
+ }
+
+ .cu-xl-col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .cu-xl-flex {
+ display: flex;
+ }
+
+ .cu-xl-flex-col {
+ flex-direction: column;
+ }
+
+ .cu-xl-flex-nowrap {
+ flex-wrap: nowrap;
+ }
+
+ .cu-xl-flex-row {
+ flex-direction: row;
+ }
+
+ .cu-xl-flex-wrap {
+ flex-wrap: wrap;
+ }
+
+ .cu-xl-flex-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ .cu-xl-gap-2xl {
+ gap: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-gap-lg {
+ gap: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-gap-md {
+ gap: var(--canon-spacing-md);
+ }
+
+ .cu-xl-gap-none {
+ gap: 0;
+ }
+
+ .cu-xl-gap-sm {
+ gap: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-gap-xl {
+ gap: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-gap-xs {
+ gap: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-grid {
+ display: grid;
+ }
+
+ .cu-xl-grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-10 {
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-11 {
+ grid-template-columns: repeat(11, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-12 {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-5 {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-6 {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-7 {
+ grid-template-columns: repeat(7, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-8 {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-9 {
+ grid-template-columns: repeat(9, minmax(0, 1fr));
+ }
+
+ .cu-xl-grid-cols-auto {
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ }
+
+ .cu-xl-hidden {
+ display: none;
+ }
+
+ .cu-xl-inline {
+ display: inline;
+ }
+
+ .cu-xl-inline-block {
+ display: inline-block;
+ }
+
+ .cu-xl-items-center {
+ align-items: center;
+ }
+
+ .cu-xl-items-end {
+ align-items: flex-end;
+ }
+
+ .cu-xl-items-start {
+ align-items: flex-start;
+ }
+
+ .cu-xl-items-stretch {
+ align-items: stretch;
+ }
+
+ .cu-xl-justify-around {
+ justify-content: space-around;
+ }
+
+ .cu-xl-justify-between {
+ justify-content: space-between;
+ }
+
+ .cu-xl-justify-center {
+ justify-content: center;
+ }
+
+ .cu-xl-justify-end {
+ justify-content: flex-end;
+ }
+
+ .cu-xl-justify-start {
+ justify-content: flex-start;
+ }
+
+ .cu-xl-justify-stretch {
+ justify-content: stretch;
+ }
+
+ .cu-xl-m-2xl {
+ margin: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-m-2xs {
+ margin: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-m-lg {
+ margin: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-m-md {
+ margin: var(--canon-spacing-md);
+ }
+
+ .cu-xl-m-none {
+ margin: 0;
+ }
+
+ .cu-xl-m-sm {
+ margin: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-m-xl {
+ margin: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-m-xs {
+ margin: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-mb-2xl {
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-mb-2xs {
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-mb-lg {
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-mb-md {
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-xl-mb-none {
+ margin-bottom: 0;
+ }
+
+ .cu-xl-mb-sm {
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-mb-xl {
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-mb-xs {
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-ml-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-ml-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-ml-lg {
+ margin-left: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-ml-md {
+ margin-left: var(--canon-spacing-md);
+ }
+
+ .cu-xl-ml-none {
+ margin-left: 0;
+ }
+
+ .cu-xl-ml-sm {
+ margin-left: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-ml-xl {
+ margin-left: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-ml-xs {
+ margin-left: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-mr-2xl {
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-mr-2xs {
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-mr-lg {
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-mr-md {
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-xl-mr-none {
+ margin-right: 0;
+ }
+
+ .cu-xl-mr-sm {
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-mr-xl {
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-mr-xs {
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-mt-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-mt-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-mt-lg {
+ margin-top: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-mt-md {
+ margin-top: var(--canon-spacing-md);
+ }
+
+ .cu-xl-mt-none {
+ margin-top: 0;
+ }
+
+ .cu-xl-mt-sm {
+ margin-top: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-mt-xl {
+ margin-top: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-mt-xs {
+ margin-top: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-mx-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-mx-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-mx-lg {
+ margin-left: var(--canon-spacing-lg);
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-mx-md {
+ margin-left: var(--canon-spacing-md);
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-xl-mx-none {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cu-xl-mx-sm {
+ margin-left: var(--canon-spacing-sm);
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-mx-xl {
+ margin-left: var(--canon-spacing-xl);
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-mx-xs {
+ margin-left: var(--canon-spacing-xs);
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-my-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-my-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-my-lg {
+ margin-top: var(--canon-spacing-lg);
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-my-md {
+ margin-top: var(--canon-spacing-md);
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-xl-my-none {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .cu-xl-my-sm {
+ margin-top: var(--canon-spacing-sm);
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-my-xl {
+ margin-top: var(--canon-spacing-xl);
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-my-xs {
+ margin-top: var(--canon-spacing-xs);
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-p-2xl {
+ padding: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-p-2xs {
+ padding: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-p-lg {
+ padding: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-p-md {
+ padding: var(--canon-spacing-md);
+ }
+
+ .cu-xl-p-none {
+ padding: 0;
+ }
+
+ .cu-xl-p-sm {
+ padding: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-p-xl {
+ padding: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-p-xs {
+ padding: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-pb-2xl {
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-pb-2xs {
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-pb-lg {
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-pb-md {
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-xl-pb-none {
+ padding-bottom: 0;
+ }
+
+ .cu-xl-pb-sm {
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-pb-xl {
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-pb-xs {
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-pl-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-pl-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-pl-lg {
+ padding-left: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-pl-md {
+ padding-left: var(--canon-spacing-md);
+ }
+
+ .cu-xl-pl-none {
+ padding-left: 0;
+ }
+
+ .cu-xl-pl-sm {
+ padding-left: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-pl-xl {
+ padding-left: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-pl-xs {
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-pr-2xl {
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-pr-2xs {
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-pr-lg {
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-pr-md {
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-xl-pr-none {
+ padding-right: 0;
+ }
+
+ .cu-xl-pr-sm {
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-pr-xl {
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-pr-xs {
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-pt-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-pt-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-pt-lg {
+ padding-top: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-pt-md {
+ padding-top: var(--canon-spacing-md);
+ }
+
+ .cu-xl-pt-none {
+ padding-top: 0;
+ }
+
+ .cu-xl-pt-sm {
+ padding-top: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-pt-xl {
+ padding-top: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-pt-xs {
+ padding-top: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-px-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-px-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-px-lg {
+ padding-left: var(--canon-spacing-lg);
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-px-md {
+ padding-left: var(--canon-spacing-md);
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-xl-px-none {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .cu-xl-px-sm {
+ padding-left: var(--canon-spacing-sm);
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-px-xl {
+ padding-left: var(--canon-spacing-xl);
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-px-xs {
+ padding-left: var(--canon-spacing-xs);
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-py-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-xl-py-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-xl-py-lg {
+ padding-top: var(--canon-spacing-lg);
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-xl-py-md {
+ padding-top: var(--canon-spacing-md);
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-xl-py-none {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .cu-xl-py-sm {
+ padding-top: var(--canon-spacing-sm);
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-xl-py-xl {
+ padding-top: var(--canon-spacing-xl);
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-xl-py-xs {
+ padding-top: var(--canon-spacing-xs);
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-xl-rounded-2xl {
+ border-radius: var(--canon-border-radius-2xl);
+ }
+
+ .cu-xl-rounded-2xs {
+ border-radius: var(--canon-border-radius-2xs);
+ }
+
+ .cu-xl-rounded-lg {
+ border-radius: var(--canon-border-radius-lg);
+ }
+
+ .cu-xl-rounded-md {
+ border-radius: var(--canon-border-radius-md);
+ }
+
+ .cu-xl-rounded-none {
+ border-radius: 0;
+ }
+
+ .cu-xl-rounded-sm {
+ border-radius: var(--canon-border-radius-sm);
+ }
+
+ .cu-xl-rounded-xl {
+ border-radius: var(--canon-border-radius-xl);
+ }
+
+ .cu-xl-rounded-xs {
+ border-radius: var(--canon-border-radius-xs);
+ }
+
+ .cu-xl-row-span-1 {
+ grid-row: span 1 / span 1;
+ }
+
+ .cu-xl-row-span-10 {
+ grid-row: span 10 / span 10;
+ }
+
+ .cu-xl-row-span-11 {
+ grid-row: span 11 / span 11;
+ }
+
+ .cu-xl-row-span-12 {
+ grid-row: span 12 / span 12;
+ }
+
+ .cu-xl-row-span-2 {
+ grid-row: span 2 / span 2;
+ }
+
+ .cu-xl-row-span-3 {
+ grid-row: span 3 / span 3;
+ }
+
+ .cu-xl-row-span-4 {
+ grid-row: span 4 / span 4;
+ }
+
+ .cu-xl-row-span-5 {
+ grid-row: span 5 / span 5;
+ }
+
+ .cu-xl-row-span-6 {
+ grid-row: span 6 / span 6;
+ }
+
+ .cu-xl-row-span-7 {
+ grid-row: span 7 / span 7;
+ }
+
+ .cu-xl-row-span-8 {
+ grid-row: span 8 / span 8;
+ }
+
+ .cu-xl-row-span-9 {
+ grid-row: span 9 / span 9;
+ }
+
+ .cu-xl-row-span-auto {
+ grid-row: span auto / span auto;
+ }
+
+ .cu-xl-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+ }
+}
diff --git a/packages/canon/src/css/utilities/xs.css b/packages/canon/src/css/utilities/xs.css
new file mode 100644
index 0000000000..926a2cc627
--- /dev/null
+++ b/packages/canon/src/css/utilities/xs.css
@@ -0,0 +1,942 @@
+/*
+ * 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.
+ */
+
+@layer utilities {
+ .cu-block {
+ display: block;
+ }
+
+ .cu-border-base {
+ border-color: var(--canon-border-base);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-border-error {
+ border-color: var(--canon-border-error);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-border-none {
+ border-color: transparent;
+ border-width: 0;
+ }
+
+ .cu-border-selected {
+ border-color: var(--canon-border-selected);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-border-warning {
+ border-color: var(--canon-border-warning);
+ border-width: 1px;
+ border-style: solid;
+ }
+
+ .cu-col-end-1 {
+ grid-column-end: 1;
+ }
+
+ .cu-col-end-10 {
+ grid-column-end: 10;
+ }
+
+ .cu-col-end-11 {
+ grid-column-end: 11;
+ }
+
+ .cu-col-end-12 {
+ grid-column-end: 12;
+ }
+
+ .cu-col-end-13 {
+ grid-column-end: 13;
+ }
+
+ .cu-col-end-2 {
+ grid-column-end: 2;
+ }
+
+ .cu-col-end-3 {
+ grid-column-end: 3;
+ }
+
+ .cu-col-end-4 {
+ grid-column-end: 4;
+ }
+
+ .cu-col-end-5 {
+ grid-column-end: 5;
+ }
+
+ .cu-col-end-6 {
+ grid-column-end: 6;
+ }
+
+ .cu-col-end-7 {
+ grid-column-end: 7;
+ }
+
+ .cu-col-end-8 {
+ grid-column-end: 8;
+ }
+
+ .cu-col-end-9 {
+ grid-column-end: 9;
+ }
+
+ .cu-col-end-auto {
+ grid-column-end: auto;
+ }
+
+ .cu-col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .cu-col-span-10 {
+ grid-column: span 10 / span 10;
+ }
+
+ .cu-col-span-11 {
+ grid-column: span 11 / span 11;
+ }
+
+ .cu-col-span-12 {
+ grid-column: span 12 / span 12;
+ }
+
+ .cu-col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
+ .cu-col-span-3 {
+ grid-column: span 3 / span 3;
+ }
+
+ .cu-col-span-4 {
+ grid-column: span 4 / span 4;
+ }
+
+ .cu-col-span-5 {
+ grid-column: span 5 / span 5;
+ }
+
+ .cu-col-span-6 {
+ grid-column: span 6 / span 6;
+ }
+
+ .cu-col-span-7 {
+ grid-column: span 7 / span 7;
+ }
+
+ .cu-col-span-8 {
+ grid-column: span 8 / span 8;
+ }
+
+ .cu-col-span-9 {
+ grid-column: span 9 / span 9;
+ }
+
+ .cu-col-span-auto {
+ grid-column: span auto / span auto;
+ }
+
+ .cu-col-start-1 {
+ grid-column-start: 1;
+ }
+
+ .cu-col-start-10 {
+ grid-column-start: 10;
+ }
+
+ .cu-col-start-11 {
+ grid-column-start: 11;
+ }
+
+ .cu-col-start-12 {
+ grid-column-start: 12;
+ }
+
+ .cu-col-start-13 {
+ grid-column-start: 13;
+ }
+
+ .cu-col-start-2 {
+ grid-column-start: 2;
+ }
+
+ .cu-col-start-3 {
+ grid-column-start: 3;
+ }
+
+ .cu-col-start-4 {
+ grid-column-start: 4;
+ }
+
+ .cu-col-start-5 {
+ grid-column-start: 5;
+ }
+
+ .cu-col-start-6 {
+ grid-column-start: 6;
+ }
+
+ .cu-col-start-7 {
+ grid-column-start: 7;
+ }
+
+ .cu-col-start-8 {
+ grid-column-start: 8;
+ }
+
+ .cu-col-start-9 {
+ grid-column-start: 9;
+ }
+
+ .cu-col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .cu-flex {
+ display: flex;
+ }
+
+ .cu-flex-col {
+ flex-direction: column;
+ }
+
+ .cu-flex-nowrap {
+ flex-wrap: nowrap;
+ }
+
+ .cu-flex-row {
+ flex-direction: row;
+ }
+
+ .cu-flex-wrap {
+ flex-wrap: wrap;
+ }
+
+ .cu-flex-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+
+ .cu-gap-2xl {
+ gap: var(--canon-spacing-2xl);
+ }
+
+ .cu-gap-lg {
+ gap: var(--canon-spacing-lg);
+ }
+
+ .cu-gap-md {
+ gap: var(--canon-spacing-md);
+ }
+
+ .cu-gap-none {
+ gap: 0;
+ }
+
+ .cu-gap-sm {
+ gap: var(--canon-spacing-sm);
+ }
+
+ .cu-gap-xl {
+ gap: var(--canon-spacing-xl);
+ }
+
+ .cu-gap-xs {
+ gap: var(--canon-spacing-xs);
+ }
+
+ .cu-grid {
+ display: grid;
+ }
+
+ .cu-grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-10 {
+ grid-template-columns: repeat(10, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-11 {
+ grid-template-columns: repeat(11, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-12 {
+ grid-template-columns: repeat(12, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-5 {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-6 {
+ grid-template-columns: repeat(6, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-7 {
+ grid-template-columns: repeat(7, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-8 {
+ grid-template-columns: repeat(8, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-9 {
+ grid-template-columns: repeat(9, minmax(0, 1fr));
+ }
+
+ .cu-grid-cols-auto {
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
+ }
+
+ .cu-hidden {
+ display: none;
+ }
+
+ .cu-inline {
+ display: inline;
+ }
+
+ .cu-inline-block {
+ display: inline-block;
+ }
+
+ .cu-items-center {
+ align-items: center;
+ }
+
+ .cu-items-end {
+ align-items: flex-end;
+ }
+
+ .cu-items-start {
+ align-items: flex-start;
+ }
+
+ .cu-items-stretch {
+ align-items: stretch;
+ }
+
+ .cu-justify-around {
+ justify-content: space-around;
+ }
+
+ .cu-justify-between {
+ justify-content: space-between;
+ }
+
+ .cu-justify-center {
+ justify-content: center;
+ }
+
+ .cu-justify-end {
+ justify-content: flex-end;
+ }
+
+ .cu-justify-start {
+ justify-content: flex-start;
+ }
+
+ .cu-justify-stretch {
+ justify-content: stretch;
+ }
+
+ .cu-m-2xl {
+ margin: var(--canon-spacing-2xl);
+ }
+
+ .cu-m-2xs {
+ margin: var(--canon-spacing-2xs);
+ }
+
+ .cu-m-lg {
+ margin: var(--canon-spacing-lg);
+ }
+
+ .cu-m-md {
+ margin: var(--canon-spacing-md);
+ }
+
+ .cu-m-none {
+ margin: 0;
+ }
+
+ .cu-m-sm {
+ margin: var(--canon-spacing-sm);
+ }
+
+ .cu-m-xl {
+ margin: var(--canon-spacing-xl);
+ }
+
+ .cu-m-xs {
+ margin: var(--canon-spacing-xs);
+ }
+
+ .cu-mb-2xl {
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-mb-2xs {
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-mb-lg {
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-mb-md {
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-mb-none {
+ margin-bottom: 0;
+ }
+
+ .cu-mb-sm {
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-mb-xl {
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-mb-xs {
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-ml-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-ml-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-ml-lg {
+ margin-left: var(--canon-spacing-lg);
+ }
+
+ .cu-ml-md {
+ margin-left: var(--canon-spacing-md);
+ }
+
+ .cu-ml-none {
+ margin-left: 0;
+ }
+
+ .cu-ml-sm {
+ margin-left: var(--canon-spacing-sm);
+ }
+
+ .cu-ml-xl {
+ margin-left: var(--canon-spacing-xl);
+ }
+
+ .cu-ml-xs {
+ margin-left: var(--canon-spacing-xs);
+ }
+
+ .cu-mr-2xl {
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-mr-2xs {
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-mr-lg {
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-mr-md {
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-mr-none {
+ margin-right: 0;
+ }
+
+ .cu-mr-sm {
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-mr-xl {
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-mr-xs {
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-mt-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-mt-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-mt-lg {
+ margin-top: var(--canon-spacing-lg);
+ }
+
+ .cu-mt-md {
+ margin-top: var(--canon-spacing-md);
+ }
+
+ .cu-mt-none {
+ margin-top: 0;
+ }
+
+ .cu-mt-sm {
+ margin-top: var(--canon-spacing-sm);
+ }
+
+ .cu-mt-xl {
+ margin-top: var(--canon-spacing-xl);
+ }
+
+ .cu-mt-xs {
+ margin-top: var(--canon-spacing-xs);
+ }
+
+ .cu-mx-2xl {
+ margin-left: var(--canon-spacing-2xl);
+ margin-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-mx-2xs {
+ margin-left: var(--canon-spacing-2xs);
+ margin-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-mx-lg {
+ margin-left: var(--canon-spacing-lg);
+ margin-right: var(--canon-spacing-lg);
+ }
+
+ .cu-mx-md {
+ margin-left: var(--canon-spacing-md);
+ margin-right: var(--canon-spacing-md);
+ }
+
+ .cu-mx-none {
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ .cu-mx-sm {
+ margin-left: var(--canon-spacing-sm);
+ margin-right: var(--canon-spacing-sm);
+ }
+
+ .cu-mx-xl {
+ margin-left: var(--canon-spacing-xl);
+ margin-right: var(--canon-spacing-xl);
+ }
+
+ .cu-mx-xs {
+ margin-left: var(--canon-spacing-xs);
+ margin-right: var(--canon-spacing-xs);
+ }
+
+ .cu-my-2xl {
+ margin-top: var(--canon-spacing-2xl);
+ margin-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-my-2xs {
+ margin-top: var(--canon-spacing-2xs);
+ margin-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-my-lg {
+ margin-top: var(--canon-spacing-lg);
+ margin-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-my-md {
+ margin-top: var(--canon-spacing-md);
+ margin-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-my-none {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+
+ .cu-my-sm {
+ margin-top: var(--canon-spacing-sm);
+ margin-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-my-xl {
+ margin-top: var(--canon-spacing-xl);
+ margin-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-my-xs {
+ margin-top: var(--canon-spacing-xs);
+ margin-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-p-2xl {
+ padding: var(--canon-spacing-2xl);
+ }
+
+ .cu-p-2xs {
+ padding: var(--canon-spacing-2xs);
+ }
+
+ .cu-p-lg {
+ padding: var(--canon-spacing-lg);
+ }
+
+ .cu-p-md {
+ padding: var(--canon-spacing-md);
+ }
+
+ .cu-p-none {
+ padding: 0;
+ }
+
+ .cu-p-sm {
+ padding: var(--canon-spacing-sm);
+ }
+
+ .cu-p-xl {
+ padding: var(--canon-spacing-xl);
+ }
+
+ .cu-p-xs {
+ padding: var(--canon-spacing-xs);
+ }
+
+ .cu-pb-2xl {
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-pb-2xs {
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-pb-lg {
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-pb-md {
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-pb-none {
+ padding-bottom: 0;
+ }
+
+ .cu-pb-sm {
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-pb-xl {
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-pb-xs {
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-pl-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ }
+
+ .cu-pl-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ }
+
+ .cu-pl-lg {
+ padding-left: var(--canon-spacing-lg);
+ }
+
+ .cu-pl-md {
+ padding-left: var(--canon-spacing-md);
+ }
+
+ .cu-pl-none {
+ padding-left: 0;
+ }
+
+ .cu-pl-sm {
+ padding-left: var(--canon-spacing-sm);
+ }
+
+ .cu-pl-xl {
+ padding-left: var(--canon-spacing-xl);
+ }
+
+ .cu-pl-xs {
+ padding-left: var(--canon-spacing-xs);
+ }
+
+ .cu-pr-2xl {
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-pr-2xs {
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-pr-lg {
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-pr-md {
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-pr-none {
+ padding-right: 0;
+ }
+
+ .cu-pr-sm {
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-pr-xl {
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-pr-xs {
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-pt-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ }
+
+ .cu-pt-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ }
+
+ .cu-pt-lg {
+ padding-top: var(--canon-spacing-lg);
+ }
+
+ .cu-pt-md {
+ padding-top: var(--canon-spacing-md);
+ }
+
+ .cu-pt-none {
+ padding-top: 0;
+ }
+
+ .cu-pt-sm {
+ padding-top: var(--canon-spacing-sm);
+ }
+
+ .cu-pt-xl {
+ padding-top: var(--canon-spacing-xl);
+ }
+
+ .cu-pt-xs {
+ padding-top: var(--canon-spacing-xs);
+ }
+
+ .cu-px-2xl {
+ padding-left: var(--canon-spacing-2xl);
+ padding-right: var(--canon-spacing-2xl);
+ }
+
+ .cu-px-2xs {
+ padding-left: var(--canon-spacing-2xs);
+ padding-right: var(--canon-spacing-2xs);
+ }
+
+ .cu-px-lg {
+ padding-left: var(--canon-spacing-lg);
+ padding-right: var(--canon-spacing-lg);
+ }
+
+ .cu-px-md {
+ padding-left: var(--canon-spacing-md);
+ padding-right: var(--canon-spacing-md);
+ }
+
+ .cu-px-none {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .cu-px-sm {
+ padding-left: var(--canon-spacing-sm);
+ padding-right: var(--canon-spacing-sm);
+ }
+
+ .cu-px-xl {
+ padding-left: var(--canon-spacing-xl);
+ padding-right: var(--canon-spacing-xl);
+ }
+
+ .cu-px-xs {
+ padding-left: var(--canon-spacing-xs);
+ padding-right: var(--canon-spacing-xs);
+ }
+
+ .cu-py-2xl {
+ padding-top: var(--canon-spacing-2xl);
+ padding-bottom: var(--canon-spacing-2xl);
+ }
+
+ .cu-py-2xs {
+ padding-top: var(--canon-spacing-2xs);
+ padding-bottom: var(--canon-spacing-2xs);
+ }
+
+ .cu-py-lg {
+ padding-top: var(--canon-spacing-lg);
+ padding-bottom: var(--canon-spacing-lg);
+ }
+
+ .cu-py-md {
+ padding-top: var(--canon-spacing-md);
+ padding-bottom: var(--canon-spacing-md);
+ }
+
+ .cu-py-none {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+
+ .cu-py-sm {
+ padding-top: var(--canon-spacing-sm);
+ padding-bottom: var(--canon-spacing-sm);
+ }
+
+ .cu-py-xl {
+ padding-top: var(--canon-spacing-xl);
+ padding-bottom: var(--canon-spacing-xl);
+ }
+
+ .cu-py-xs {
+ padding-top: var(--canon-spacing-xs);
+ padding-bottom: var(--canon-spacing-xs);
+ }
+
+ .cu-rounded-2xl {
+ border-radius: var(--canon-border-radius-2xl);
+ }
+
+ .cu-rounded-2xs {
+ border-radius: var(--canon-border-radius-2xs);
+ }
+
+ .cu-rounded-lg {
+ border-radius: var(--canon-border-radius-lg);
+ }
+
+ .cu-rounded-md {
+ border-radius: var(--canon-border-radius-md);
+ }
+
+ .cu-rounded-none {
+ border-radius: 0;
+ }
+
+ .cu-rounded-sm {
+ border-radius: var(--canon-border-radius-sm);
+ }
+
+ .cu-rounded-xl {
+ border-radius: var(--canon-border-radius-xl);
+ }
+
+ .cu-rounded-xs {
+ border-radius: var(--canon-border-radius-xs);
+ }
+
+ .cu-row-span-1 {
+ grid-row: span 1 / span 1;
+ }
+
+ .cu-row-span-10 {
+ grid-row: span 10 / span 10;
+ }
+
+ .cu-row-span-11 {
+ grid-row: span 11 / span 11;
+ }
+
+ .cu-row-span-12 {
+ grid-row: span 12 / span 12;
+ }
+
+ .cu-row-span-2 {
+ grid-row: span 2 / span 2;
+ }
+
+ .cu-row-span-3 {
+ grid-row: span 3 / span 3;
+ }
+
+ .cu-row-span-4 {
+ grid-row: span 4 / span 4;
+ }
+
+ .cu-row-span-5 {
+ grid-row: span 5 / span 5;
+ }
+
+ .cu-row-span-6 {
+ grid-row: span 6 / span 6;
+ }
+
+ .cu-row-span-7 {
+ grid-row: span 7 / span 7;
+ }
+
+ .cu-row-span-8 {
+ grid-row: span 8 / span 8;
+ }
+
+ .cu-row-span-9 {
+ grid-row: span 9 / span 9;
+ }
+
+ .cu-row-span-auto {
+ grid-row: span auto / span auto;
+ }
+
+ .cu-wrap-reverse {
+ flex-wrap: wrap-reverse;
+ }
+}
diff --git a/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts b/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts
new file mode 100644
index 0000000000..25ea45124e
--- /dev/null
+++ b/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts
@@ -0,0 +1,19 @@
+/*
+ * 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 { useEffect, useLayoutEffect } from 'react';
+
+export const useIsomorphicLayoutEffect =
+ typeof window !== 'undefined' ? useLayoutEffect : useEffect;
diff --git a/packages/canon/src/hooks/useMediaQuery.ts b/packages/canon/src/hooks/useMediaQuery.ts
new file mode 100644
index 0000000000..9e2cc9ef0b
--- /dev/null
+++ b/packages/canon/src/hooks/useMediaQuery.ts
@@ -0,0 +1,76 @@
+/*
+ * 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 { useState } from 'react';
+
+import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';
+
+type UseMediaQueryOptions = {
+ defaultValue?: boolean;
+ initializeWithValue?: boolean;
+};
+
+const IS_SERVER = typeof window === 'undefined';
+
+export function useMediaQuery(
+ query: string,
+ {
+ defaultValue = false,
+ initializeWithValue = true,
+ }: UseMediaQueryOptions = {},
+): boolean {
+ const getMatches = (query: string): boolean => {
+ if (IS_SERVER) {
+ return defaultValue;
+ }
+ return window.matchMedia(query).matches;
+ };
+
+ const [matches, setMatches] = useState(() => {
+ if (initializeWithValue) {
+ return getMatches(query);
+ }
+ return defaultValue;
+ });
+
+ // Handles the change event of the media query.
+ function handleChange() {
+ setMatches(getMatches(query));
+ }
+
+ useIsomorphicLayoutEffect(() => {
+ const matchMedia = window.matchMedia(query);
+
+ // Triggered at the first client-side load and if query changes
+ handleChange();
+
+ // Use deprecated `addListener` and `removeListener` to support Safari < 14 (#135)
+ if (matchMedia.addListener) {
+ matchMedia.addListener(handleChange);
+ } else {
+ matchMedia.addEventListener('change', handleChange);
+ }
+
+ return () => {
+ if (matchMedia.removeListener) {
+ matchMedia.removeListener(handleChange);
+ } else {
+ matchMedia.removeEventListener('change', handleChange);
+ }
+ };
+ }, [query]);
+
+ return matches;
+}
diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts
index 198a626f06..f6cca4bed6 100644
--- a/packages/canon/src/index.ts
+++ b/packages/canon/src/index.ts
@@ -20,7 +20,23 @@
* @packageDocumentation
*/
-export * from './components/Button';
+// Providers
+export * from './contexts/canon';
+
+// Layout components
export * from './components/Box';
+export * from './components/Grid';
+export * from './components/Stack';
+export * from './components/Inline';
+export * from './components/Container';
+export * from './components/Text';
+export * from './components/Heading';
+
+// UI components
+export * from './components/Button';
export * from './components/Icon';
-export * from './layout/types';
+export * from './components/Checkbox';
+export * from './components/Table';
+
+// Types
+export * from './types';
diff --git a/packages/canon/src/layout/properties.ts b/packages/canon/src/layout/properties.ts
deleted file mode 100644
index 37cb53666c..0000000000
--- a/packages/canon/src/layout/properties.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-/** @public */
-export const breakpoints = {
- xs: {},
- sm: { '@media': 'screen and (min-width: 640px)' },
- md: { '@media': 'screen and (min-width: 768px)' },
- lg: { '@media': 'screen and (min-width: 1024px)' },
- xl: { '@media': 'screen and (min-width: 1280px)' },
- '2xl': { '@media': 'screen and (min-width: 1536px)' },
-};
-
-/** @public */
-export const themes = {
- light: { selector: '[data-theme="light"] &' },
- dark: { selector: '[data-theme="dark"] &' },
-};
-
-/** @public */
-export const space = {
- none: 0,
- xxs: 'var(--canon-space-xxs)',
- xs: 'var(--canon-space-xs)',
- sm: 'var(--canon-space-sm)',
- md: 'var(--canon-space-md)',
- lg: 'var(--canon-space-lg)',
- xl: 'var(--canon-space-xl)',
- xxl: 'var(--canon-space-xxl)',
-};
diff --git a/packages/canon/src/layout/sprinkles.css.ts b/packages/canon/src/layout/sprinkles.css.ts
deleted file mode 100644
index 7e85487fe3..0000000000
--- a/packages/canon/src/layout/sprinkles.css.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 { defineProperties } from '@vanilla-extract/sprinkles';
-import { breakpoints, space } from './properties';
-
-export const spacingProperties = defineProperties({
- conditions: breakpoints,
- defaultCondition: 'xs',
- responsiveArray: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'],
- properties: {
- paddingTop: space,
- paddingBottom: space,
- paddingLeft: space,
- paddingRight: space,
- marginTop: space,
- marginBottom: space,
- marginLeft: space,
- marginRight: space,
- gap: space,
- },
- shorthands: {
- padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'],
- paddingX: ['paddingLeft', 'paddingRight'],
- paddingY: ['paddingTop', 'paddingBottom'],
- margin: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'],
- marginX: ['marginLeft', 'marginRight'],
- marginY: ['marginTop', 'marginBottom'],
- },
-});
-
-export const colorProperties = defineProperties({
- conditions: {
- light: { selector: '[data-theme="light"] &' },
- dark: { selector: '[data-theme="dark"] &' },
- },
- defaultCondition: ['light', 'dark'],
- properties: {
- color: {
- primary: 'var(--canon-text-primary)',
- secondary: 'var(--canon-text-secondary)',
- error: 'var(--canon-error)',
- },
- background: {
- background: 'var(--canon-background)',
- elevation1: 'var(--canon-surface-1)',
- elevation2: 'var(--canon-surface-2)',
- transparent: 'transparent',
- },
- },
-});
diff --git a/packages/canon/src/layout/types.ts b/packages/canon/src/layout/types.ts
deleted file mode 100644
index c051dacb44..0000000000
--- a/packages/canon/src/layout/types.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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 { breakpoints, space, themes } from './properties';
-
-/** @public */
-export type Breakpoint = keyof typeof breakpoints;
-
-/** @public */
-export type Space = keyof typeof space;
-
-/** @public */
-export type Theme = keyof typeof themes;
-
-/** @public */
-export type Gap = Space | Partial>;
-
-/** @public */
-export type PaddingLeft = Space | Partial>;
-
-/** @public */
-export type PaddingRight = Space | Partial>;
-
-/** @public */
-export type PaddingTop = Space | Partial>;
-
-/** @public */
-export type PaddingBottom = Space | Partial