Merge pull request #29137 from backstage/canon-styles

Add Canon styles
This commit is contained in:
Fredrik Adelöw
2025-03-18 13:14:04 +01:00
committed by GitHub
37 changed files with 20689 additions and 22 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Canon is now ready to be used in Alpha. We are adding a custom CSS file at the root of the app to make all styles available for Canon components.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
Introducing Canon to Backstage. Canon styling system is based on pure CSS. We are adding our styles.css at the top of your Backstage instance.
+1
View File
@@ -4,6 +4,7 @@ microsite
canon-docs/.next
canon-docs/public
canon-docs/out
packages/canon/css
coverage
*.hbs
templates
+1
View File
@@ -35,6 +35,7 @@
},
"dependencies": {
"@backstage/app-defaults": "workspace:^",
"@backstage/canon": "workspace:^",
"@backstage/catalog-model": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/config": "workspace:^",
@@ -16,6 +16,7 @@
import ReactDOM from 'react-dom/client';
import { createPublicSignInApp } from '@backstage/frontend-defaults';
import '@backstage/canon/css/styles.css';
const app = createPublicSignInApp();
+1
View File
@@ -17,5 +17,6 @@
import '@backstage/cli/asset-types';
import ReactDOM from 'react-dom/client';
import app from './App';
import '@backstage/canon/css/styles.css';
ReactDOM.createRoot(document.getElementById('root')!).render(app);
+1
View File
@@ -36,6 +36,7 @@
},
"dependencies": {
"@backstage/app-defaults": "workspace:^",
"@backstage/canon": "workspace:^",
"@backstage/catalog-model": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/config": "workspace:^",
@@ -31,6 +31,7 @@ import {
discoveryApiRef,
} from '@backstage/core-plugin-api';
import { AuthProxyDiscoveryApi } from '../src/AuthProxyDiscoveryApi';
import '@backstage/canon/css/styles.css';
const app = createApp({
apis: [
+1
View File
@@ -18,5 +18,6 @@ import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@backstage/canon/css/styles.css';
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
-3
View File
@@ -1,5 +1,2 @@
# Build output
storybook-static
# CSS output
/css
+5
View File
@@ -0,0 +1,5 @@
.canon-Box {
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
}
+89
View File
@@ -0,0 +1,89 @@
.canon-Button {
user-select: none;
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-bold);
cursor: pointer;
border-radius: var(--canon-radius-2);
justify-content: center;
align-items: center;
gap: var(--canon-space-1_5);
border: none;
padding: 0;
display: inline-flex;
&:disabled {
cursor: not-allowed;
}
}
.canon-Button--variant-primary {
background-color: var(--canon-bg-solid);
color: var(--canon-fg-solid);
transition: background-color .15s, box-shadow .15s;
&:hover {
background-color: var(--canon-bg-solid-hover);
}
&:active {
background-color: var(--canon-bg-solid-pressed);
}
&:focus-visible {
outline: 2px solid var(--canon-ring);
outline-offset: 2px;
}
&:disabled {
background-color: var(--canon-bg-solid-disabled);
color: var(--canon-fg-solid-disabled);
}
}
.canon-Button--variant-secondary {
background-color: var(--canon-bg-surface-1);
box-shadow: inset 0 0 0 1px var(--canon-border);
color: var(--canon-fg-primary);
transition: box-shadow .15s;
&:hover {
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
}
&:active {
box-shadow: inset 0 0 0 1px var(--canon-border-pressed);
}
&:focus-visible {
box-shadow: inset 0 0 0 2px var(--canon-ring);
outline: none;
transition: none;
}
&:disabled {
box-shadow: inset 0 0 0 1px var(--canon-border-disabled);
color: var(--canon-fg-disabled);
}
}
.canon-Button--size-medium {
font-size: var(--canon-font-size-4);
padding: 0 var(--canon-space-3);
height: 40px;
}
.canon-Button--size-small {
font-size: var(--canon-font-size-3);
padding: 0 var(--canon-space-2);
height: 32px;
}
.canon-Button--size-small .canon-Button--icon {
width: 1rem;
height: 1rem;
}
.canon-Button--size-medium .canon-Button--icon {
width: 1.5rem;
height: 1.5rem;
}
+48
View File
@@ -0,0 +1,48 @@
.canon-CheckboxRoot {
width: 1rem;
height: 1rem;
box-shadow: inset 0 0 0 1px var(--canon-border);
cursor: pointer;
border: none;
border-radius: 2px;
justify-content: center;
align-items: center;
transition: all .2s ease-in-out;
display: flex;
&:focus-visible {
outline: 2px solid var(--canon-ring);
outline-offset: 2px;
transition: none;
}
&[data-checked] {
background-color: var(--canon-bg-solid);
color: var(--canon-fg-solid);
}
}
.canon-CheckboxLabel {
align-items: center;
gap: var(--canon-space-2);
font-size: var(--canon-font-size-3);
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
user-select: none;
flex-direction: row;
display: flex;
&:hover {
& .canon-CheckboxRoot {
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
}
}
}
.canon-CheckboxIndicator {
color: var(--canon-fg-accent);
justify-content: center;
align-items: center;
display: flex;
}
+744
View File
@@ -0,0 +1,744 @@
.canon-Box {
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
}
.canon-Button {
user-select: none;
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-bold);
cursor: pointer;
border-radius: var(--canon-radius-2);
justify-content: center;
align-items: center;
gap: var(--canon-space-1_5);
border: none;
padding: 0;
display: inline-flex;
&:disabled {
cursor: not-allowed;
}
}
.canon-Button--variant-primary {
background-color: var(--canon-bg-solid);
color: var(--canon-fg-solid);
transition: background-color .15s, box-shadow .15s;
&:hover {
background-color: var(--canon-bg-solid-hover);
}
&:active {
background-color: var(--canon-bg-solid-pressed);
}
&:focus-visible {
outline: 2px solid var(--canon-ring);
outline-offset: 2px;
}
&:disabled {
background-color: var(--canon-bg-solid-disabled);
color: var(--canon-fg-solid-disabled);
}
}
.canon-Button--variant-secondary {
background-color: var(--canon-bg-surface-1);
box-shadow: inset 0 0 0 1px var(--canon-border);
color: var(--canon-fg-primary);
transition: box-shadow .15s;
&:hover {
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
}
&:active {
box-shadow: inset 0 0 0 1px var(--canon-border-pressed);
}
&:focus-visible {
box-shadow: inset 0 0 0 2px var(--canon-ring);
outline: none;
transition: none;
}
&:disabled {
box-shadow: inset 0 0 0 1px var(--canon-border-disabled);
color: var(--canon-fg-disabled);
}
}
.canon-Button--size-medium {
font-size: var(--canon-font-size-4);
padding: 0 var(--canon-space-3);
height: 40px;
}
.canon-Button--size-small {
font-size: var(--canon-font-size-3);
padding: 0 var(--canon-space-2);
height: 32px;
}
.canon-Button--size-small .canon-Button--icon {
width: 1rem;
height: 1rem;
}
.canon-Button--size-medium .canon-Button--icon {
width: 1.5rem;
height: 1.5rem;
}
.canon-Flex {
display: flex;
}
.canon-Grid {
display: grid;
}
.canon-Container {
max-width: 75rem;
margin: 0 auto;
padding: 0 1rem;
}
.canon-Icon {
width: 1rem;
height: 1rem;
}
.canon-CheckboxRoot {
width: 1rem;
height: 1rem;
box-shadow: inset 0 0 0 1px var(--canon-border);
cursor: pointer;
border: none;
border-radius: 2px;
justify-content: center;
align-items: center;
transition: all .2s ease-in-out;
display: flex;
&:focus-visible {
outline: 2px solid var(--canon-ring);
outline-offset: 2px;
transition: none;
}
&[data-checked] {
background-color: var(--canon-bg-solid);
color: var(--canon-fg-solid);
}
}
.canon-CheckboxLabel {
align-items: center;
gap: var(--canon-space-2);
font-size: var(--canon-font-size-3);
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
user-select: none;
flex-direction: row;
display: flex;
&:hover {
& .canon-CheckboxRoot {
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
}
}
}
.canon-CheckboxIndicator {
color: var(--canon-fg-accent);
justify-content: center;
align-items: center;
display: flex;
}
.table {
background-color: var(--canon-bg-surface-1);
border-radius: var(--canon-radius-2);
width: 100%;
padding-bottom: var(--canon-space-0_5);
padding-top: var(--canon-space-0_5);
font-size: var(--canon-font-size-3);
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
position: relative;
overflow: auto;
& table {
caption-side: bottom;
width: 100%;
font-size: var(--canon-font-size-sm);
border-collapse: collapse;
}
}
.table-head {
text-align: left;
padding: var(--canon-space-3);
}
.table-body {
& tr:last-child {
border-bottom: none;
}
}
.table-row {
transition: color .2s ease-in-out;
&:hover td {
background-color: var(--canon-bg-tint);
}
& .table-cell:first-child {
border-top-left-radius: var(--canon-radius-2);
border-bottom-left-radius: var(--canon-radius-2);
box-shadow: inset 4px 2px 0 0 var(--canon-bg-surface-1), inset 4px -2px 0 0 var(--canon-bg-surface-1);
padding-left: var(--canon-space-3);
}
& .table-cell:last-child {
border-top-right-radius: var(--canon-radius-2);
border-bottom-right-radius: var(--canon-radius-2);
box-shadow: inset -4px 2px 0 0 var(--canon-bg-surface-1), inset -4px -2px 0 0 var(--canon-bg-surface-1);
padding-right: var(--canon-space-3);
}
}
.table-cell {
padding: var(--canon-space-3);
background-color: var(--canon-bg);
box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), inset 0px -2px 0 0 var(--canon-bg-surface-1);
}
.canon-Text {
font-family: var(--canon-font-regular);
color: var(--canon-fg-primary);
margin: 0;
padding: 0;
}
.canon-Text--variant-body {
font-size: var(--canon-font-size-3);
line-height: 140%;
}
.canon-Text--variant-subtitle {
font-size: var(--canon-font-size-4);
line-height: 140%;
}
.canon-Text--variant-caption {
font-size: var(--canon-font-size-2);
line-height: 140%;
}
.canon-Text--variant-label {
font-size: var(--canon-font-size-1);
line-height: 140%;
}
.canon-Text--weight-regular {
font-weight: var(--canon-font-weight-regular);
}
.canon-Text--weight-bold {
font-weight: var(--canon-font-weight-bold);
}
.canon-Text--color-primary {
color: var(--canon-fg-primary);
}
.canon-Text--color-secondary {
color: var(--canon-fg-secondary);
}
.canon-Text--color-danger {
color: var(--canon-fg-danger);
}
.canon-Text--color-warning {
color: var(--canon-fg-warning);
}
.canon-Text--color-success {
color: var(--canon-fg-success);
}
.canon-Heading {
font-family: var(--canon-font-regular);
color: var(--canon-fg-primary);
margin: 0;
padding: 0;
line-height: 100%;
}
.canon-Heading--variant-display {
font-size: var(--canon-font-size-10);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title1 {
font-size: var(--canon-font-size-9);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title2 {
font-size: var(--canon-font-size-8);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title3 {
font-size: var(--canon-font-size-7);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title4 {
font-size: var(--canon-font-size-title4);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title5 {
font-size: var(--canon-font-size-5);
font-weight: var(--canon-font-weight-bold);
}
.canon-IconButton {
user-select: none;
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-bold);
cursor: pointer;
border-radius: var(--canon-radius-2);
justify-content: center;
align-items: center;
gap: var(--canon-space-1_5);
border: none;
padding: 0;
display: inline-flex;
&:disabled {
cursor: not-allowed;
}
}
.canon-IconButton--variant-primary {
background-color: var(--canon-bg-solid);
color: var(--canon-fg-solid);
transition: background-color .15s, box-shadow .15s;
&:hover {
background-color: var(--canon-bg-solid-hover);
}
&:active {
background-color: var(--canon-bg-solid-pressed);
}
&:focus-visible {
outline: 2px solid var(--canon-ring);
outline-offset: 2px;
}
&:disabled {
background-color: var(--canon-bg-solid-disabled);
color: var(--canon-fg-solid-disabled);
}
}
.canon-IconButton--variant-secondary {
background-color: var(--canon-bg-surface-1);
box-shadow: inset 0 0 0 1px var(--canon-border);
color: var(--canon-fg-primary);
transition: box-shadow .15s;
&:hover {
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
}
&:active {
box-shadow: inset 0 0 0 1px var(--canon-border-pressed);
}
&:focus-visible {
box-shadow: inset 0 0 0 2px var(--canon-ring);
outline: none;
transition: none;
}
&:disabled {
box-shadow: inset 0 0 0 1px var(--canon-border-disabled);
color: var(--canon-fg-disabled);
}
}
.canon-IconButton--size-medium {
font-size: var(--canon-font-size-4);
width: 40px;
height: 40px;
}
.canon-IconButton--size-small {
font-size: var(--canon-font-size-3);
width: 32px;
height: 32px;
}
.canon-IconButton--size-small .canon-IconButton--icon {
width: 1rem;
height: 1rem;
}
.canon-IconButton--size-medium .canon-IconButton--icon {
width: 1.5rem;
height: 1.5rem;
}
.canon-Input {
border-radius: var(--canon-radius-3);
border: 1px solid var(--canon-border);
padding: 0 var(--canon-space-4);
background-color: var(--canon-bg-surface-1);
font-size: var(--canon-font-size-3);
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
width: 100%;
transition: border-color .2s ease-in-out, outline-color .2s ease-in-out;
}
.canon-Input::placeholder {
color: var(--canon-fg-secondary);
}
.canon-Input:hover {
border-color: var(--canon-border-hover);
}
.canon-Input:focus-visible {
outline-color: var(--canon-border-pressed);
border-color: var(--canon-border-pressed);
outline-width: 0;
}
.canon-Input[data-invalid] {
border-color: var(--canon-fg-danger);
}
.canon-Input--size-sm {
height: 2rem;
}
.canon-Input--size-md {
height: 2.5rem;
}
.canon-FieldRoot {
font-family: var(--canon-font-regular);
flex-direction: column;
width: 100%;
display: flex;
}
.canon-FieldLabel {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
margin-bottom: var(--canon-space-1_5);
}
.canon-FieldDescription {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-secondary);
padding-top: var(--canon-space-1_5);
margin: 0;
}
.canon-FieldError {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-danger);
padding-top: var(--canon-space-1_5);
margin: 0;
}
.canon-FieldValidity {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-secondary);
padding-top: var(--canon-space-1_5);
margin: 0;
}
.canon-MenuTrigger {
box-sizing: border-box;
border: 1px solid var(--color-gray-200);
background-color: var(--color-gray-50);
height: 2.5rem;
color: var(--color-gray-900);
user-select: none;
border-radius: .375rem;
outline: 0;
justify-content: center;
align-items: center;
gap: .375rem;
margin: 0;
padding: 0 .875rem;
font-family: inherit;
font-size: 1rem;
font-weight: 500;
line-height: 1.5rem;
display: flex;
@media (hover: hover) {
&:hover {
background-color: var(--color-gray-100);
}
}
&:active, &[data-popup-open] {
background-color: var(--color-gray-100);
}
&:focus-visible {
outline: 2px solid var(--color-blue);
outline-offset: -1px;
}
}
.canon-MenuPositioner {
outline: 0;
}
.canon-MenuPopup {
box-sizing: border-box;
background-color: var(--canon-bg-elevated);
color: var(--color-fg-primary);
transform-origin: var(--transform-origin);
border-radius: .375rem;
padding-block: .25rem;
transition: transform .15s, opacity .15s;
&[data-starting-style], &[data-ending-style] {
opacity: 0;
transform: scale(.9);
}
@media (prefers-color-scheme: light) {
& {
outline: 1px solid var(--color-gray-200);
box-shadow: 0px 10px 15px -3px var(--color-gray-200), 0px 4px 6px -4px var(--color-gray-200);
}
}
@media (prefers-color-scheme: dark) {
& {
outline: 1px solid var(--color-gray-300);
outline-offset: -1px;
}
}
}
.canon-MenuItem {
cursor: default;
user-select: none;
padding-block: .5rem;
outline: 0;
padding-left: 1rem;
padding-right: 2rem;
font-size: .875rem;
line-height: 1rem;
display: flex;
&[data-highlighted] {
z-index: 0;
color: var(--color-gray-50);
position: relative;
}
&[data-highlighted]:before {
content: "";
z-index: -1;
background-color: var(--color-gray-900);
border-radius: .25rem;
position: absolute;
inset-block: 0;
inset-inline: .25rem;
}
}
.canon-MenuSeparator {
background-color: var(--color-gray-200);
height: 1px;
margin: .375rem 1rem;
}
.canon-Link {
font-family: var(--canon-font-regular);
color: var(--canon-fg-link);
cursor: pointer;
margin: 0;
padding: 0;
text-decoration-line: none;
&:hover {
color: var(--canon-fg-link-hover);
text-underline-offset: calc(.025em + 2px);
text-decoration-line: underline;
text-decoration-style: solid;
text-decoration-thickness: min(2px, max(1px, .05em));
text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent);
}
}
.canon-Link--variant-body {
font-size: var(--canon-font-size-3);
line-height: 140%;
}
.canon-Link--variant-subtitle {
font-size: var(--canon-font-size-4);
line-height: 140%;
}
.canon-Link--variant-caption {
font-size: var(--canon-font-size-2);
line-height: 140%;
}
.canon-Link--variant-label {
font-size: var(--canon-font-size-1);
line-height: 140%;
}
.canon-Link--weight-regular {
font-weight: var(--canon-font-weight-regular);
}
.canon-Link--weight-bold {
font-weight: var(--canon-font-weight-bold);
}
.canon-TooltipPopup {
box-sizing: border-box;
transform-origin: var(--transform-origin);
background-color: canvas;
background-color: var(--canon-bg-surface-1);
color: var(--canon-fg-primary);
outline: 1px solid var(--canon-border);
box-shadow: 0 10px 15px -3px var(--canon-border), 0 4px 6px -4px var(--canon-border);
border-radius: .375rem;
flex-direction: column;
padding: .25rem .5rem;
font-size: .875rem;
line-height: 1.25rem;
transition: transform .15s, opacity .15s;
display: flex;
&[data-starting-style], &[data-ending-style] {
opacity: 0;
transform: scale(.9);
}
&[data-instant] {
transition-duration: 0s;
}
}
.canon-TooltipArrow {
display: flex;
&[data-side="top"] {
bottom: -8px;
rotate: 180deg;
}
&[data-side="bottom"] {
top: -8px;
rotate: none;
}
&[data-side="left"] {
right: -13px;
rotate: 90deg;
}
&[data-side="right"] {
left: -13px;
rotate: -90deg;
}
}
.canon-TooltipArrow-fill {
fill: var(--canon-bg-surface-1);
}
.canon-TooltipArrow-outer-stroke {
@media (prefers-color-scheme: light) {
& {
fill: var(--canon-border);
}
}
}
.canon-ScrollAreaRoot {
box-sizing: border-box;
width: 24rem;
max-width: calc(100vw - 8rem);
height: 8.5rem;
}
.canon-ScrollAreaViewport {
overscroll-behavior: contain;
height: 100%;
}
.canon-ScrollAreaContent {
padding-block: .75rem;
flex-direction: column;
gap: 1rem;
padding-left: 1rem;
padding-right: 1.5rem;
display: flex;
}
.canon-ScrollAreaScrollbar {
background-color: var(--canon-scrollbar);
opacity: 0;
border-radius: .375rem;
justify-content: center;
width: .25rem;
margin: .5rem;
transition: opacity .15s .3s;
display: flex;
&[data-hovering], &[data-scrolling] {
opacity: 1;
transition-duration: 75ms;
transition-delay: 0s;
}
&:before {
content: "";
width: 1.25rem;
height: 100%;
position: absolute;
}
}
.canon-ScrollAreaThumb {
border-radius: inherit;
background-color: var(--canon-scrollbar-thumb);
width: 100%;
}
+5
View File
@@ -0,0 +1,5 @@
.canon-Container {
max-width: 75rem;
margin: 0 auto;
padding: 0 1rem;
}
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
.canon-FieldRoot {
font-family: var(--canon-font-regular);
flex-direction: column;
width: 100%;
display: flex;
}
.canon-FieldLabel {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
margin-bottom: var(--canon-space-1_5);
}
.canon-FieldDescription {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-secondary);
padding-top: var(--canon-space-1_5);
margin: 0;
}
.canon-FieldError {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-danger);
padding-top: var(--canon-space-1_5);
margin: 0;
}
.canon-FieldValidity {
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-secondary);
padding-top: var(--canon-space-1_5);
margin: 0;
}
+3
View File
@@ -0,0 +1,3 @@
.canon-Flex {
display: flex;
}
+3
View File
@@ -0,0 +1,3 @@
.canon-Grid {
display: grid;
}
+37
View File
@@ -0,0 +1,37 @@
.canon-Heading {
font-family: var(--canon-font-regular);
color: var(--canon-fg-primary);
margin: 0;
padding: 0;
line-height: 100%;
}
.canon-Heading--variant-display {
font-size: var(--canon-font-size-10);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title1 {
font-size: var(--canon-font-size-9);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title2 {
font-size: var(--canon-font-size-8);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title3 {
font-size: var(--canon-font-size-7);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title4 {
font-size: var(--canon-font-size-title4);
font-weight: var(--canon-font-weight-bold);
}
.canon-Heading--variant-title5 {
font-size: var(--canon-font-size-5);
font-weight: var(--canon-font-weight-bold);
}
+4
View File
@@ -0,0 +1,4 @@
.canon-Icon {
width: 1rem;
height: 1rem;
}
+89
View File
@@ -0,0 +1,89 @@
.canon-IconButton {
user-select: none;
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-bold);
cursor: pointer;
border-radius: var(--canon-radius-2);
justify-content: center;
align-items: center;
gap: var(--canon-space-1_5);
border: none;
padding: 0;
display: inline-flex;
&:disabled {
cursor: not-allowed;
}
}
.canon-IconButton--variant-primary {
background-color: var(--canon-bg-solid);
color: var(--canon-fg-solid);
transition: background-color .15s, box-shadow .15s;
&:hover {
background-color: var(--canon-bg-solid-hover);
}
&:active {
background-color: var(--canon-bg-solid-pressed);
}
&:focus-visible {
outline: 2px solid var(--canon-ring);
outline-offset: 2px;
}
&:disabled {
background-color: var(--canon-bg-solid-disabled);
color: var(--canon-fg-solid-disabled);
}
}
.canon-IconButton--variant-secondary {
background-color: var(--canon-bg-surface-1);
box-shadow: inset 0 0 0 1px var(--canon-border);
color: var(--canon-fg-primary);
transition: box-shadow .15s;
&:hover {
box-shadow: inset 0 0 0 1px var(--canon-border-hover);
}
&:active {
box-shadow: inset 0 0 0 1px var(--canon-border-pressed);
}
&:focus-visible {
box-shadow: inset 0 0 0 2px var(--canon-ring);
outline: none;
transition: none;
}
&:disabled {
box-shadow: inset 0 0 0 1px var(--canon-border-disabled);
color: var(--canon-fg-disabled);
}
}
.canon-IconButton--size-medium {
font-size: var(--canon-font-size-4);
width: 40px;
height: 40px;
}
.canon-IconButton--size-small {
font-size: var(--canon-font-size-3);
width: 32px;
height: 32px;
}
.canon-IconButton--size-small .canon-IconButton--icon {
width: 1rem;
height: 1rem;
}
.canon-IconButton--size-medium .canon-IconButton--icon {
width: 1.5rem;
height: 1.5rem;
}
+38
View File
@@ -0,0 +1,38 @@
.canon-Input {
border-radius: var(--canon-radius-3);
border: 1px solid var(--canon-border);
padding: 0 var(--canon-space-4);
background-color: var(--canon-bg-surface-1);
font-size: var(--canon-font-size-3);
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
color: var(--canon-fg-primary);
width: 100%;
transition: border-color .2s ease-in-out, outline-color .2s ease-in-out;
}
.canon-Input::placeholder {
color: var(--canon-fg-secondary);
}
.canon-Input:hover {
border-color: var(--canon-border-hover);
}
.canon-Input:focus-visible {
outline-color: var(--canon-border-pressed);
border-color: var(--canon-border-pressed);
outline-width: 0;
}
.canon-Input[data-invalid] {
border-color: var(--canon-fg-danger);
}
.canon-Input--size-sm {
height: 2rem;
}
.canon-Input--size-md {
height: 2.5rem;
}
+45
View File
@@ -0,0 +1,45 @@
.canon-Link {
font-family: var(--canon-font-regular);
color: var(--canon-fg-link);
cursor: pointer;
margin: 0;
padding: 0;
text-decoration-line: none;
&:hover {
color: var(--canon-fg-link-hover);
text-underline-offset: calc(.025em + 2px);
text-decoration-line: underline;
text-decoration-style: solid;
text-decoration-thickness: min(2px, max(1px, .05em));
text-decoration-color: color-mix(in srgb, var(--canon-fg-link-hover) 30%, transparent);
}
}
.canon-Link--variant-body {
font-size: var(--canon-font-size-3);
line-height: 140%;
}
.canon-Link--variant-subtitle {
font-size: var(--canon-font-size-4);
line-height: 140%;
}
.canon-Link--variant-caption {
font-size: var(--canon-font-size-2);
line-height: 140%;
}
.canon-Link--variant-label {
font-size: var(--canon-font-size-1);
line-height: 140%;
}
.canon-Link--weight-regular {
font-weight: var(--canon-font-weight-regular);
}
.canon-Link--weight-bold {
font-weight: var(--canon-font-weight-bold);
}
+102
View File
@@ -0,0 +1,102 @@
.canon-MenuTrigger {
box-sizing: border-box;
border: 1px solid var(--color-gray-200);
background-color: var(--color-gray-50);
height: 2.5rem;
color: var(--color-gray-900);
user-select: none;
border-radius: .375rem;
outline: 0;
justify-content: center;
align-items: center;
gap: .375rem;
margin: 0;
padding: 0 .875rem;
font-family: inherit;
font-size: 1rem;
font-weight: 500;
line-height: 1.5rem;
display: flex;
@media (hover: hover) {
&:hover {
background-color: var(--color-gray-100);
}
}
&:active, &[data-popup-open] {
background-color: var(--color-gray-100);
}
&:focus-visible {
outline: 2px solid var(--color-blue);
outline-offset: -1px;
}
}
.canon-MenuPositioner {
outline: 0;
}
.canon-MenuPopup {
box-sizing: border-box;
background-color: var(--canon-bg-elevated);
color: var(--color-fg-primary);
transform-origin: var(--transform-origin);
border-radius: .375rem;
padding-block: .25rem;
transition: transform .15s, opacity .15s;
&[data-starting-style], &[data-ending-style] {
opacity: 0;
transform: scale(.9);
}
@media (prefers-color-scheme: light) {
& {
outline: 1px solid var(--color-gray-200);
box-shadow: 0px 10px 15px -3px var(--color-gray-200), 0px 4px 6px -4px var(--color-gray-200);
}
}
@media (prefers-color-scheme: dark) {
& {
outline: 1px solid var(--color-gray-300);
outline-offset: -1px;
}
}
}
.canon-MenuItem {
cursor: default;
user-select: none;
padding-block: .5rem;
outline: 0;
padding-left: 1rem;
padding-right: 2rem;
font-size: .875rem;
line-height: 1rem;
display: flex;
&[data-highlighted] {
z-index: 0;
color: var(--color-gray-50);
position: relative;
}
&[data-highlighted]:before {
content: "";
z-index: -1;
background-color: var(--color-gray-900);
border-radius: .25rem;
position: absolute;
inset-block: 0;
inset-inline: .25rem;
}
}
.canon-MenuSeparator {
background-color: var(--color-gray-200);
height: 1px;
margin: .375rem 1rem;
}
+50
View File
@@ -0,0 +1,50 @@
.canon-ScrollAreaRoot {
box-sizing: border-box;
width: 24rem;
max-width: calc(100vw - 8rem);
height: 8.5rem;
}
.canon-ScrollAreaViewport {
overscroll-behavior: contain;
height: 100%;
}
.canon-ScrollAreaContent {
padding-block: .75rem;
flex-direction: column;
gap: 1rem;
padding-left: 1rem;
padding-right: 1.5rem;
display: flex;
}
.canon-ScrollAreaScrollbar {
background-color: var(--canon-scrollbar);
opacity: 0;
border-radius: .375rem;
justify-content: center;
width: .25rem;
margin: .5rem;
transition: opacity .15s .3s;
display: flex;
&[data-hovering], &[data-scrolling] {
opacity: 1;
transition-duration: 75ms;
transition-delay: 0s;
}
&:before {
content: "";
width: 1.25rem;
height: 100%;
position: absolute;
}
}
.canon-ScrollAreaThumb {
border-radius: inherit;
background-color: var(--canon-scrollbar-thumb);
width: 100%;
}
File diff suppressed because it is too large Load Diff
+58
View File
@@ -0,0 +1,58 @@
.table {
background-color: var(--canon-bg-surface-1);
border-radius: var(--canon-radius-2);
width: 100%;
padding-bottom: var(--canon-space-0_5);
padding-top: var(--canon-space-0_5);
font-size: var(--canon-font-size-3);
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
position: relative;
overflow: auto;
& table {
caption-side: bottom;
width: 100%;
font-size: var(--canon-font-size-sm);
border-collapse: collapse;
}
}
.table-head {
text-align: left;
padding: var(--canon-space-3);
}
.table-body {
& tr:last-child {
border-bottom: none;
}
}
.table-row {
transition: color .2s ease-in-out;
&:hover td {
background-color: var(--canon-bg-tint);
}
& .table-cell:first-child {
border-top-left-radius: var(--canon-radius-2);
border-bottom-left-radius: var(--canon-radius-2);
box-shadow: inset 4px 2px 0 0 var(--canon-bg-surface-1), inset 4px -2px 0 0 var(--canon-bg-surface-1);
padding-left: var(--canon-space-3);
}
& .table-cell:last-child {
border-top-right-radius: var(--canon-radius-2);
border-bottom-right-radius: var(--canon-radius-2);
box-shadow: inset -4px 2px 0 0 var(--canon-bg-surface-1), inset -4px -2px 0 0 var(--canon-bg-surface-1);
padding-right: var(--canon-space-3);
}
}
.table-cell {
padding: var(--canon-space-3);
background-color: var(--canon-bg);
box-shadow: inset 0px 2px 0 0 var(--canon-bg-surface-1), inset 0px -2px 0 0 var(--canon-bg-surface-1);
}
+54
View File
@@ -0,0 +1,54 @@
.canon-Text {
font-family: var(--canon-font-regular);
color: var(--canon-fg-primary);
margin: 0;
padding: 0;
}
.canon-Text--variant-body {
font-size: var(--canon-font-size-3);
line-height: 140%;
}
.canon-Text--variant-subtitle {
font-size: var(--canon-font-size-4);
line-height: 140%;
}
.canon-Text--variant-caption {
font-size: var(--canon-font-size-2);
line-height: 140%;
}
.canon-Text--variant-label {
font-size: var(--canon-font-size-1);
line-height: 140%;
}
.canon-Text--weight-regular {
font-weight: var(--canon-font-weight-regular);
}
.canon-Text--weight-bold {
font-weight: var(--canon-font-weight-bold);
}
.canon-Text--color-primary {
color: var(--canon-fg-primary);
}
.canon-Text--color-secondary {
color: var(--canon-fg-secondary);
}
.canon-Text--color-danger {
color: var(--canon-fg-danger);
}
.canon-Text--color-warning {
color: var(--canon-fg-warning);
}
.canon-Text--color-success {
color: var(--canon-fg-success);
}
+61
View File
@@ -0,0 +1,61 @@
.canon-TooltipPopup {
box-sizing: border-box;
transform-origin: var(--transform-origin);
background-color: canvas;
background-color: var(--canon-bg-surface-1);
color: var(--canon-fg-primary);
outline: 1px solid var(--canon-border);
box-shadow: 0 10px 15px -3px var(--canon-border), 0 4px 6px -4px var(--canon-border);
border-radius: .375rem;
flex-direction: column;
padding: .25rem .5rem;
font-size: .875rem;
line-height: 1.25rem;
transition: transform .15s, opacity .15s;
display: flex;
&[data-starting-style], &[data-ending-style] {
opacity: 0;
transform: scale(.9);
}
&[data-instant] {
transition-duration: 0s;
}
}
.canon-TooltipArrow {
display: flex;
&[data-side="top"] {
bottom: -8px;
rotate: 180deg;
}
&[data-side="bottom"] {
top: -8px;
rotate: none;
}
&[data-side="left"] {
right: -13px;
rotate: 90deg;
}
&[data-side="right"] {
left: -13px;
rotate: -90deg;
}
}
.canon-TooltipArrow-fill {
fill: var(--canon-bg-surface-1);
}
.canon-TooltipArrow-outer-stroke {
@media (prefers-color-scheme: light) {
& {
fill: var(--canon-border);
}
}
}
+4 -2
View File
@@ -28,14 +28,16 @@
],
"scripts": {
"build": "yarn build:app && yarn build:css",
"build-storybook": "storybook build",
"build:app": "backstage-cli package build",
"build:css": "node scripts/build-css.mjs",
"build-storybook": "storybook build",
"build:css:watch": "node scripts/build-css.mjs --watch",
"clean": "backstage-cli package clean",
"lint": "backstage-cli package lint",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack",
"start": "storybook dev -p 6006",
"start": "yarn build:css:watch && yarn storybook",
"storybook": "storybook dev -p 6006",
"test": "backstage-cli package test"
},
"dependencies": {
+43 -16
View File
@@ -58,23 +58,50 @@ if (!fs.existsSync(distDir)) {
fs.mkdirSync(distDir, { recursive: true });
}
// Bundle and transform files
cssFiles.forEach(file => {
let { code: bundleCode } = bundle({
filename: file.path,
// Add watch mode support
const args = process.argv.slice(2);
const watchMode = args.includes('--watch');
async function buildCSS(logs = true) {
// Bundle and transform files
cssFiles.forEach(file => {
let { code: bundleCode } = bundle({
filename: file.path,
});
let { code } = transform({
filename: `${distDir}/${file.newName}`,
code: bundleCode,
});
fs.writeFileSync(`${distDir}/${file.newName}`, code);
if (logs) {
console.log(chalk.blue('CSS bundled: ') + file.newName);
}
});
let { code, map } = transform({
filename: `${distDir}/${file.newName}`,
code: bundleCode,
minify: true,
sourceMap: true,
if (logs) {
console.log(chalk.green('CSS files bundled successfully!'));
}
}
if (watchMode) {
// Watch both directories for changes
[cssDir, componentsDir].forEach(dir => {
fs.watch(dir, { recursive: true }, (eventType, filename) => {
if (filename?.endsWith('.css')) {
console.log(
chalk.yellow(`Changes detected in ${filename}, rebuilding...`),
);
buildCSS(false).catch(console.error);
}
});
});
fs.writeFileSync(`${distDir}/${file.newName}`, code);
fs.writeFileSync(`${distDir}/${file.newName}.map`, map);
console.log(chalk.blue('CSS bundled: ') + file.newName);
});
console.log(chalk.green('CSS files bundled successfully!'));
// Initial build
buildCSS().catch(console.error);
console.log(chalk.yellow('Watching for CSS changes...'));
} else {
buildCSS().catch(console.error);
}
@@ -52,6 +52,7 @@ jest.mock('./versions', () => ({
'@backstage/cli': '1.0.0',
'@backstage/backend-defaults': '1.0.0',
'@backstage/backend-tasks': '1.0.0',
'@backstage/canon': '1.0.0',
'@backstage/catalog-model': '1.0.0',
'@backstage/catalog-client': '1.0.0',
'@backstage/config': '1.0.0',
+2
View File
@@ -33,6 +33,7 @@ import { version as root } from '../../../../package.json';
import { version as appDefaults } from '../../../app-defaults/package.json';
import { version as backendDefaults } from '../../../backend-defaults/package.json';
import { version as canon } from '../../../canon/package.json';
import { version as catalogClient } from '../../../catalog-client/package.json';
import { version as catalogModel } from '../../../catalog-model/package.json';
import { version as cli } from '../../../cli/package.json';
@@ -93,6 +94,7 @@ export const packageVersions = {
'@backstage/catalog-client': catalogClient,
'@backstage/catalog-model': catalogModel,
'@backstage/cli': cli,
'@backstage/canon': canon,
'@backstage/config': config,
'@backstage/core-app-api': coreAppApi,
'@backstage/core-components': coreComponents,
@@ -15,6 +15,7 @@
},
"dependencies": {
"@backstage/app-defaults": "^{{version '@backstage/app-defaults'}}",
"@backstage/canon": "^{{version '@backstage/canon'}}",
"@backstage/catalog-model": "^{{version '@backstage/catalog-model'}}",
"@backstage/cli": "^{{version '@backstage/cli'}}",
"@backstage/core-app-api": "^{{version '@backstage/core-app-api'}}",
@@ -2,5 +2,6 @@ import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@backstage/canon/css/styles.css';
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
+3 -1
View File
@@ -3793,7 +3793,7 @@ __metadata:
languageName: unknown
linkType: soft
"@backstage/canon@workspace:packages/canon":
"@backstage/canon@workspace:^, @backstage/canon@workspace:packages/canon":
version: 0.0.0-use.local
resolution: "@backstage/canon@workspace:packages/canon"
dependencies:
@@ -28915,6 +28915,7 @@ __metadata:
resolution: "example-app-next@workspace:packages/app-next"
dependencies:
"@backstage/app-defaults": "workspace:^"
"@backstage/canon": "workspace:^"
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"
@@ -28988,6 +28989,7 @@ __metadata:
resolution: "example-app@workspace:packages/app"
dependencies:
"@backstage/app-defaults": "workspace:^"
"@backstage/canon": "workspace:^"
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"