Merge branch 'master' into canon-field

This commit is contained in:
Charles de Dreuille
2024-12-19 16:46:52 +00:00
109 changed files with 7104 additions and 2470 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-backend-module-catalog': patch
---
Internal refactor to use cursor based pagination
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-notifications-backend': patch
---
Remove `@backstage/backend-common` dependency
+2 -2
View File
@@ -33,7 +33,7 @@ jobs:
registry-url: https://registry.npmjs.org/
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: linux-v20
@@ -46,7 +46,7 @@ jobs:
cat ${{ github.event_path }} > event.json
- name: Upload Artifacts
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
with:
name: preview-spec
path: |
@@ -34,7 +34,7 @@ jobs:
ref: 'refs/pull/${{ github.event.pull_request.number }}/merge'
- name: fetch base
run: git fetch --depth 1 origin ${{ github.base_ref }}
- uses: backstage/actions/changeset-feedback@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
- uses: backstage/actions/changeset-feedback@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
name: Generate feedback
with:
diff-ref: 'origin/master'
+5 -5
View File
@@ -41,7 +41,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -77,7 +77,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -225,7 +225,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -235,7 +235,7 @@ jobs:
# Use the lower-level cache actions for the success cache, so that we can store the cache even on failed builds
- name: restore backstage-cli cache
uses: actions/cache/restore@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4
with:
path: .cache/backstage-cli
key: ${{ runner.os }}-v${{ matrix.node-version }}-backstage-cli-${{ github.run_id }}
@@ -256,7 +256,7 @@ jobs:
# Always save success cache even if there were failures, that way it can be used in re-triggered builds
- name: save backstage-cli cache
uses: actions/cache/save@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4
if: always()
with:
path: .cache/backstage-cli
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
with:
egress-policy: audit
- uses: backstage/actions/cron@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
- uses: backstage/actions/cron@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
+2 -2
View File
@@ -37,7 +37,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -62,7 +62,7 @@ jobs:
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
- name: Build and push
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
with:
context: './example-app'
file: ./example-app/packages/backend/Dockerfile
+5 -5
View File
@@ -65,7 +65,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
@@ -73,7 +73,7 @@ jobs:
run: yarn build:api-docs
- name: upload API reference
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
with:
name: stable-reference
path: docs/reference/
@@ -105,7 +105,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
@@ -113,7 +113,7 @@ jobs:
run: yarn build:api-docs
- name: upload API reference
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
with:
name: next-reference
path: docs/reference/
@@ -130,7 +130,7 @@ jobs:
working-directory: storybook
- name: storybook upload
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
with:
name: storybook
path: storybook/dist/
+2 -2
View File
@@ -76,7 +76,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
@@ -94,7 +94,7 @@ jobs:
run: yarn backstage-cli config:check --lax
- name: backstage-cli cache
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4
with:
path: .cache/backstage-cli
key: ${{ runner.os }}-v${{ matrix.node-version }}-backstage-cli-${{ github.run_id }}
+1 -1
View File
@@ -40,7 +40,7 @@ jobs:
const prNumber = artifact.name.slice('pr_number-'.length)
core.setOutput('pr-number', prNumber);
- uses: backstage/actions/re-review@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
- uses: backstage/actions/re-review@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }}
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
egress-policy: audit
- name: PR sync
uses: backstage/actions/pr-sync@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/pr-sync@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }}
app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }}
+1 -1
View File
@@ -67,6 +67,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7
uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
with:
sarif_file: results.sarif
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
@@ -24,7 +24,7 @@ jobs:
node-version: 20.x
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
+1 -1
View File
@@ -58,6 +58,6 @@ jobs:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
NODE_OPTIONS: --max-old-space-size=7168
- name: Upload Snyk report
uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7
uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
with:
sarif_file: snyk.sarif
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
with:
node-version: 20.x
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v20.x
- name: run Lighthouse CI
+3 -3
View File
@@ -55,7 +55,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7
uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -66,7 +66,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7
uses: github/codeql-action/autobuild@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -80,4 +80,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7
uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
+1 -1
View File
@@ -60,7 +60,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+1 -1
View File
@@ -80,7 +80,7 @@ jobs:
uses: browser-actions/setup-chrome@803ef6dfb4fdf22089c9563225d95e4a515820a0 # latest
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
+2 -2
View File
@@ -42,7 +42,7 @@ jobs:
node-version: ${{ matrix.node-version }}
registry-url: https://registry.npmjs.org/ # Needed for auth
- name: yarn install
uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16
uses: backstage/actions/yarn-install@b3c1841fd69e1658ac631afafd0fb140a2309024 # v0.6.17
with:
cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }}
- name: storybook yarn install
@@ -54,7 +54,7 @@ jobs:
- run: yarn --cwd packages/canon build-storybook
- uses: chromaui/action@0efa3230f403b7848d5d65c6ce140b617fb68380 # v11
- uses: chromaui/action@64a9c0ca3bfb724389b0d536e544f56b7b5ff5b3 # v11
with:
token: ${{ secrets.GITHUB_TOKEN }}
# projectToken intentionally shared to allow collaborators to run Chromatic on forks
+5 -1
View File
@@ -301,12 +301,16 @@ indexBuilder.addCollator({
});
```
Note: if you are using the in-memory Lunr search engine, you probably want to
:::note Note
if you are using the in-memory Lunr search engine, you probably want to
implement a non-distributed `SchedulerServiceTaskRunner` like the following to ensure consistency
if you're running multiple search backend nodes (alternatively, you can configure
the search plugin to use a non-distributed database such as
[SQLite](../../tutorials/configuring-plugin-databases.md#postgresql-and-sqlite-3)):
:::
```typescript
import {
SchedulerServiceTaskRunner,
@@ -0,0 +1,177 @@
---
# prettier-ignore
title: "Backstage Wrapped 2024: The year's Top 5 milestones and highlights"
author: Patrik Oldsberg, Spotify & Ben Lambert, Spotify
---
![Bowie the Backstage Beaver in an astronaut outfit riding a firecracker surrounded by fireworks exploding with stats: 210+ open source plugins, 1.6k contributors, 60k total contributions](assets/2024-12-18/wrapped2024-top5.png)
It was another banner year for everyone's favorite platform for improving developer experience — and we're closing 2024 out with a bang🧨🎆. To give you a snapshot of how the Backstage community is doing, we're counting down our Top 5 milestones for the year (plus a few other highlights sprinkled in). To start things off, let's see what you and your 1,616 fellow contributors were up to last year…
{/* truncate */}
---
## 5️⃣: 60k+ Contributions from a Global Community of Very Busy Beavers🦫
<iframe
src="https://www.youtube.com/embed/U0m3TJ-2cFw"
width="100%"
height="440"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
_Behold! Every commit to the Backstage open source project this year — can you
see your name in there?_
As we shared last month when we kicked off [BackstageCon North America](https://youtu.be/OfavM6j4Z5o?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X&t=112), the Backstage community hit a new milestone this year — reaching 60,000 total contributions (discussions, issues, and pull requests) to the project since Spotify donated it to the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/projects/backstage/) in 2020. Busy Backstage beavers, indeed.
And the community was as active as ever in 2024 — if you hit play on the visualization above, you can see all 12.3k commits from the year being made. (Though, instead of busy beavers, it's more like a giant cluster of space spiders shooting galactic laser webs. Pew pew!)
### The most commits of any CNCF project, by a lot
![Taylor Dolezal presenting a chart showing the Top 10 CNCF Projects by Number of End User Commits on the Keynote stage at KubeCon Europe 2024](assets/2024-03-27/cncf-keynote-kubecon-2024.jpg)
Speaking of commits, rewinding back to [KubeCon + CloudNativeCon Europe](https://backstage.io/blog/2024/03/27/backstagecon-kubecon-24/) in March gives us another way to visualize the mightiness of the Backstage community.
From the keynote stage in Paris, Taylor Dolezal, the head of ecosystem at The Linux Foundation, [presented a chart](https://www.youtube.com/watch?v=MICHGBAe8gc&list=PLj6h78yzYM2N8nw1YcqqKveySH6_0VnI0&index=161) showing the "Top CNCF Projects by Number of End User Commits", using data from the previous four months.
At the top of the chart, a conspicuous blue bar — more than twice the length as the next longest one — had Taylor noting that, among CNCF projects, Backstage was "rocketing into the forefront when it comes to end user contributions".🚀🚀🚀
### Our first Contribfest!
![A room full of developers working together at the first Backstage Contribfest](assets/2024-12-18/wrapped2024-contribfest.jpg)
What's better than ogling a nifty visualization or nerding out on a good bar graph? Feeling the buzz of those contributions in person.
Just last month at KubeCon + CloudNativeCon North America, maintainers from Spotify and Red Hat cohosted the first-ever [Backstage Contribfest](https://backstage.io/blog/2024/12/09/kubecon-slc-24/#contribfest-its-all-about-community). We packed the room with engineers obsessed with developer experience and let them loose on a curated list of issues. The session was good, old-fashioned coding fun — devs sharing ideas and solving problems together — and we look forward to doing it again with all of you.
If you missed it and want to get in on the action, just follow along with the [Contribfest slide deck](https://static.sched.com/hosted_files/kccncna2024/53/KubeCon-ContribFest-Backstage-NA-2024.pdf). Or meet us in 💂‍♂️London in April for [BackstageCon](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/co-located-events/backstagecon/) and [KubeCon + CloudNativeCon Europe 2025](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/)!
---
## 4️⃣: 210+ Open Source Plugins (and Counting)🧩
![Bowie the Backstage Beaver surrounded by icons for plugins: Argo CD, Datadog, GitHub Actions, Grafana, Jira, and Kubernetes](assets/2024-12-18/wrapped2024-4-plugins.gif)
_Just a few of the plugins built by the Backstage community_
### Plugins, plugins, plugins
Everybody's building them, everywhere you look. We see official plugins from popular third-party service providers ([DX](https://backstage.spotify.com/marketplace/dx/plugin/dx/), [PagerDuty](https://pagerduty.github.io/backstage-plugin-docs/index.html), [Rootly](https://backstage.spotify.com/marketplace/rootly/plugin/rootly/)), in-house plugins going open source (like these from [DAZN](https://github.com/backstage/community-plugins/blob/main/workspaces/github-pull-requests-board/plugins/github-pull-requests-board/README.md), [Keyloop](https://github.com/backstage/community-plugins/blob/main/workspaces/azure-devops/plugins/azure-devops/README.md), and [SeatGeek](https://github.com/seatgeek/backstage-plugins)), essential plugins built and maintained by ecosystem champions and supporters ([AWS](https://github.com/awslabs/backstage-plugins-for-aws), [GCP](https://github.com/googlecloudplatform/google-cloud-backstage-plugins), [Roadie](https://roadie.io), [Spotify](https://backstage.spotify.com)), as well as creative and [useful](https://github.com/procore-oss/backstage-plugin-announcements) plugins from contributors and enthusiasts from all corners of the Backstage community.
### A yearlong plugin party
In 2024, the plugin ecosystem continued to expand — with about a hundred new plugins being introduced over the year and many others getting big updates.
SeatGeek started the plugin party in February❄️ at a Backstage Community Session where they [demoed](https://www.youtube.com/watch?v=CRw0m3J11Bc&t=526s) five of the seven plugins they've open sourced, including their [Awards Plugin](https://github.com/seatgeek/backstage-plugins/tree/main/plugins/awards) and [Entity Scaffolder Plugin](https://github.com/seatgeek/backstage-plugins/tree/main/plugins/entity-scaffolder-content).
By spring🌷, new plugins for [Linkerd](https://github.com/backstage/community-plugins/tree/main/workspaces/linkerd) and [Black Duck](https://github.com/backstage/community-plugins/tree/main/workspaces/blackduck/plugins/blackduck) had sprung onto the scene.
During the summer☀️, the official [PagerDuty](https://pagerduty.github.io/backstage-plugin-docs/index.html) plugin received updates that made it a breeze to configure existing PagerDuty services and also added support for multiple PagerDuty accounts in the same Backstage instance.
By fall🍁, some of the most-used plugins — including plugins for [Argo CD](https://www.npmjs.com/package/@roadiehq/backstage-plugin-argo-cd), [Datadog](https://www.npmjs.com/package/@roadiehq/backstage-plugin-datadog), [GitHub Actions](https://github.com/backstage/community-plugins/tree/main/workspaces/github-actions/plugins/github-actions), [Grafana](https://github.com/backstage/community-plugins/blob/main/workspaces/grafana/plugins/grafana/docs/index.md), [Jira](https://github.com/AxisCommunications/backstage-plugins/tree/main/plugins/jira-dashboard), [Kubernetes](https://backstage.io/docs/features/kubernetes/), and [Tech Radar](https://github.com/backstage/community-plugins/tree/main/workspaces/tech-radar/plugins/tech-radar) — had already been updated to support the very latest versions of the Backstage framework's [New Frontend System](https://backstage.io/docs/releases/v1.30.0) and [New Backend System](https://github.com/backstage/backstage/issues/24493). (Thanks to the teams at Roadie and Spotify for helping to kickstart a new era of easy-to-install-and-configure plugins!)
And last but not least, AWS just released the [AWS Config catalog plugin for Backstage](https://github.com/awslabs/backstage-plugins-for-aws/blob/main/plugins/core/catalog-config/README.md) — a great new plugin that makes it easy for their customers to ingest AWS resources into the Backstage Software Catalog.
Have a plugin you'd like to show off and share with the community? Sign up to demo it at one of our monthly [Backstage Community Sessions](https://github.com/backstage/community/tree/main/backstage-community-sessions#readme)!
### A shiny new plugins repo
Alongside all this plugin-building action, there was also plenty of plugin-migrating action. In April, community plugins moved to a repo they could call their own — the [Backstage Community Plugins Repository](https://backstage.io/blog/2024/04/19/community-plugins/).
With release tooling, workspace tooling, and migration guide all included, [the new repo](https://github.com/backstage/community-plugins) gives plugin owners a leg up on building and shipping plugins. Now you can release independently of the main monorepo, at your own release cadence.
Special thanks go to Red Hat as maintainers of the [community plugins project area](https://github.com/backstage/backstage/blob/master/OWNERS.md#community-plugins) and to everyone who provided feedback on the migration plan. With the new community plugins repo now established, it will be fascinating to see what new, innovative plugins we'll be talking about this time next year. [Go start building](https://backstage.io/docs/plugins/)!
---
## 3️⃣: 278 Companies Listed in ADOPTERS.md💚
![Bowie the Backstage Beaver wearing a I heart Backstage T-shirt and hugging the ADOPTERS.md file](assets/2024-12-18/wrapped2024-3-adopters.gif)
_We 💚 all our Backstage adopters_
### One thing in common
At the top level of the `backstage/backstage` GitHub repo is a little file called [ADOPTERS.md](https://github.com/backstage/backstage/blob/master/ADOPTERS.md) that contains the names of hundreds of companies who have adopted Backstage and added themselves to the list.
There are companies from all over the world on that list, of all shapes and sizes, including cloud natives and cloud newbies, brand new startups and fast-growing scale-ups, airlines, banks, and healthcare companies, along with online retailers, gaming studios, digital entertainment platforms, and hundred-year-old government consulting firms.
But no matter how different their industries, their business models, their engineering cultures, or their tech stacks, when they join that list of public Backstage adopters, they all share one thing in common: their commitment to improving developer experience as the surest path to innovation. So while the file is just a simple table, it's also an invitation for other companies to join in that commitment.
This year, the following companies added themselves to ADOPTERS.md, bringing the total to 278 public Backstage adopters — let's give a big welcome to: [Anuclei](https://anuclei.com), [Fortnox](https://www.fortnox.se), [Wefox](https://www.wefox.com), [Aurora Innovation](https://aurorainnovation.com), [ENSEK](https://ensek.com/), [OP Financial Group](https://www.op.fi/op-financial-group), [Scania](https://www.scania.com), [Senora.dev](https://senora.dev), [Covestro](https://www.covestro.com), [Grupo OLX](https://www.olx.com.br/), [DPG Media](https://www.dpgmediagroup.com), [Baloise](https://www.baloise.ch), [Cigna](https://www.cigna.com/), [Evernorth](https://www.evernorth.com/), [Infobip](https://www.infobip.com/), [CloudScript](https://www.cloudscript.com.br/), [Alauda](https://www.alauda.io/), [New10](https://www.new10.com/), [Tele2 Kazakhstan](https://tele2.kz/), [Altel Digital](https://digital.altel.kz/), and [Axelerant](https://www.axelerant.com/).
### Plus, thousands more in the wild
The companies on that list represent just a fraction of the active Backstage adopters out there — we know there are thousands more of you. How do we know?
We've seen your [amazing talks](https://backstage.io/blog/2024/12/09/kubecon-slc-24/#toyota-and-akamai-in-the-house). We've read your [insightful blog posts](https://backstage.io/blog/2024/09/24/dynatrace-adopter-spotlight/). We've heard your [engaging adoption journeys](https://www.youtube.com/watch?v=nZuEMojNi9A&t=565s). We've enjoyed your [automation workshops](https://philips-labs.github.io/automation-workshop/). And we've celebrated your [well-deserved awards](https://backstage.io/blog/2024/12/09/kubecon-slc-24/#and-the-award-goes-to).
There are so many different kinds of adopters out there, and so many different ways to share with the community — and we love to see it all.
### Support the community! Add yourself to ADOPTERS.md
If you work somewhere that's using Backstage, don't be shy. Jump into 2025 by [adding your company](https://github.com/backstage/backstage/blob/master/ADOPTERS.md) to the public adopters list. We love to see you there, and it's a simple but meaningful way to contribute back to the community.🙏
---
## 2️⃣: 2 Legit 2 Quit: The Official Backstage Certification Launches🎓
![Bowie the Backstage Beaver wearing glasses and holding a book pointing at the badge for Certified Backstage Associate](assets/2024-12-18/wrapped2024-2-cba.gif)
_Time to make it official_
With the Backstage community growing across so many companies, the need for Backstage experts grows, as well. Now there's an easy way to spot 'em.
### Become a Certified Backstage Associate (CBA)
Last month, the CNCF and Linux Foundation Education [announced](https://training.linuxfoundation.org/blog/just-launched-certified-backstage-associate-cba/) the launch of a new certification: [Certified Backstage Associate (CBA)](https://training.linuxfoundation.org/certification/certified-backstage-associate-cba/). So now you can make your expertise for "building on top of the most popular open source IDP" official:
> Designed for IT engineers, developers, platform engineers, and other IT professionals, the CBA proves you have the mindset and skills to work in and build Backstage tools that improve performance and drive innovation benefiting your career, your team and your organization.
It's a huge help for Backstage experts and practitioners, as well as all those Backstage adopters (and future adopters) who prioritize developer experience and productivity amid the increasing complexity of modern software development.
As Pia Nilsson, head of platform developer experience at Spotify, says in the announcement, "With the CNCF's Certified Backstage Associate program, companies now have a way to identify and tap into that expertise, while helping to contribute back to the growing Backstage community."
### Enroll today!
The program to become a Certified Backstage Associate is live, so you can [enroll today](https://training.linuxfoundation.org/certification/certified-backstage-associate-cba/)!
And if you want to see what domains the 90-minute, multiple-choice CBA exam covers — and hear more about how "earning a Backstage certification can be a career game-changer for developers and IT engineer's careers" — makes sure to read the full announcement on the [The Linux Foundation Education blog](https://training.linuxfoundation.org/blog/just-launched-certified-backstage-associate-cba/).
---
## 1️⃣: Version 1.0 of the Future of Backstage🎉
![The top half of Bowie the Backstage Beaver sticking out of the top of a portal, the beaver's bottom half sticking out of the bottom of another portal, with Backend System 1.0! written in between the floating halves](assets/2024-12-18/wrapped2024-1-backend.gif)
_And the number one milestone of 2024 is…Backend System 1.0!_
As we saw in the video visualizing a year's worth of commits, there were a lot of changes to Backstage in 2024 — including improved documentation, the introduction of the Framework SIG ([join a Backstage special interest group](https://github.com/backstage/community/tree/main/sigs#sig)!), Yarn 4 as the default, our second security audit, a built-in event bus, major new features to the Scaffolder UI (form decorators and retries — shout-out to [Bogdan Nechyporenko](https://github.com/backstage/backstage/blob/master/OWNERS.md#scaffolder) from Bol.com!), big strides in the plugin-building experience in the [New Frontend System](https://youtu.be/BzPCJMQH8tg?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X) — and much, much more. And that was just in the last six months.
But the 1.0 release of the New Backend System was the biggie of the year.
### The "New Backend System" becomes _the_ backend system
After months of testing, feedback, and improvements with the community, the New Backend System landed as a [stable v.1.0 release](https://backstage.io/docs/releases/v1.31.0/) in September — marking the beginning of a new era for building for Backstage.
The New Backend System (which shall henceforth be known as "_the_ backend system") brings a host of improvements to the way that backends and their features are constructed. Instead of the old convention-based structure that could lead to migration pains, features now fit together with dependency injection, like a jigsaw puzzle, while leveraging powerful core services and extending each other dynamically with additional behaviors.
And this is just scratching the surface of it. To see what else is new in the backend system — check out [the docs](https://backstage.io/docs/backend-system/)!
We are very excited about this important milestone after a long period of development and refinement together with our passionate community, and hope that you will find it as refreshing and simple yet powerful as it was envisioned to be. This also lays the foundation for us being able to continue iterating at a high pace without incurring undue end user breakages during upgrades.
### How to migrate your backends and plugins
We have documentation for both [migrating backends](https://backstage.io/docs/backend-system/building-backends/migrating) and [migrating plugins](https://backstage.io/docs/backend-system/building-plugins-and-modules/migrating). If you haven't migrated already, we encourage you to do so as soon as possible, so that all adopters and end users can begin to unlock the benefits of the new system!
And keep the feedback coming, either on the community [Discord](https://discord.gg/backstage-687207715902193673) or through [issues](https://github.com/backstage/backstage/issues/new/choose) on GitHub. If you're looking for a way to help, take a look at these open issues in the [backstage](https://github.com/backstage/backstage/issues/26353) and [community plugins](https://github.com/backstage/community-plugins/issues/1176) repos about deprecating old backend capabilities of already migrated plugins. To the future we go!
---
## We won! Hooray to the community! 🏆
![Bowie the Backstage Beaver standing bashfully on a podium with 2024 flashing behind in big letters](assets/2024-12-18/wrapped2024-infoworld.gif)
To cap off the year, last week Backstage won the "[InfoWorld 2024 Technology of the Year Award for Software Development: Platforms](https://www.linkedin.com/posts/backstage-from-spotify_infoworlds-2024-technology-of-the-year-award-activity-7273338824561246208-KY-w/)"!
Congrats to [all the project maintainers](https://github.com/backstage/backstage/blob/master/OWNERS.md), the CNCF, and everyone in the Backstage community — including all our contributors, adopters, partners, and end users. It's great to see developer experience recognized for the critical role it plays in innovation.
Let's do it again next year!
Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

+6 -6
View File
@@ -8804,11 +8804,11 @@ __metadata:
linkType: hard
"nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
version: 3.3.8
resolution: "nanoid@npm:3.3.8"
bin:
nanoid: bin/nanoid.cjs
checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2
checksum: dfe0adbc0c77e9655b550c333075f51bb28cfc7568afbf3237249904f9c86c9aaaed1f113f0fddddba75673ee31c758c30c43d4414f014a52a7a626efc5958c9
languageName: node
linkType: hard
@@ -9836,14 +9836,14 @@ __metadata:
linkType: hard
"prism-react-renderer@npm:^2.1.0, prism-react-renderer@npm:^2.3.0":
version: 2.4.0
resolution: "prism-react-renderer@npm:2.4.0"
version: 2.4.1
resolution: "prism-react-renderer@npm:2.4.1"
dependencies:
"@types/prismjs": ^1.26.0
clsx: ^2.0.0
peerDependencies:
react: ">=16.0.0"
checksum: d15d944a8cbf05f7b04deecd2cf4ffb08229a6027918641b6f046cd8ab24b65ca4ebe4ac8e95a53a7d7cefb1bba8df3ce394fe4f1d75418e34fa92553dc63ef7
checksum: ddd5490a1335629addde9535db7872f0aee8dbce048818dd6e4c3972c779780af13d669c12d3f2fbb54c5b22d1578e50945099ef1a24dd445f33774e87d85e6e
languageName: node
linkType: hard
+1 -9
View File
@@ -1,7 +1,4 @@
import type { StorybookConfig } from '@storybook/react-webpack5';
import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin';
import { merge } from 'webpack-merge';
import { join, dirname } from 'path';
/**
@@ -28,13 +25,8 @@ const config: StorybookConfig = {
framework: {
name: getAbsolutePath('@storybook/react-webpack5'),
options: {
plugins: [new VanillaExtractPlugin()],
plugins: [],
},
},
webpackFinal: config => {
return merge(config, {
plugins: [new VanillaExtractPlugin()],
});
},
};
export default config;
@@ -14,20 +14,28 @@
* 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 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;
},
});
export const stackSprinkles = createSprinkles(
spacingProperties,
colorProperties,
stackProperties,
{},
);
-69
View File
@@ -1,69 +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) {
console.warn(`Value "${value}" not found in boxProperties.styles`);
return [];
}
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<string, any>
>((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<string, any>
>((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;
}, {});
+1 -5
View File
@@ -56,17 +56,13 @@
"@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/sprinkles": "^1.6.3",
"@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.7",
"webpack-merge": "^6.0.1"
"storybook": "^8.4.7"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
+91 -244
View File
@@ -5,22 +5,13 @@
```ts
/// <reference types="react" />
import { Field as Field_2 } from '@base-ui-components/react/field';
import { ForwardRefExoticComponent } from 'react';
import { Input as Input_2 } from '@base-ui-components/react/input';
import { default as React_2 } from 'react';
import * as React_3 from 'react';
import { RefAttributes } from 'react';
// @public (undocumented)
export type AlignItemsProps =
| 'stretch'
| 'flex-start'
| 'center'
| 'flex-end'
| Partial<
Record<Breakpoint, 'stretch' | 'flex-start' | 'center' | 'flex-end'>
>;
export type AlignItems = 'stretch' | 'start' | 'center' | 'end';
// @public (undocumented)
export type AsProps =
@@ -42,22 +33,18 @@ export type AsProps =
| 'dt';
// @public (undocumented)
export type Background =
| 'background'
| 'elevation1'
| 'elevation2'
| 'transparent'
| Partial<
Record<Theme, 'background' | 'elevation1' | 'elevation2' | 'transparent'>
>;
export type Border = 'none' | 'base' | 'error' | 'warning' | 'selected';
// @public (undocumented)
export type BorderRadiusProps =
export type BorderRadius =
| 'none'
| 'small'
| 'medium'
| 'full'
| Partial<Record<Breakpoint, 'none' | 'small' | 'medium' | 'full'>>;
| '2xs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| '2xl';
// @public (undocumented)
export const Box: ForwardRefExoticComponent<
@@ -65,51 +52,19 @@ export const Box: ForwardRefExoticComponent<
>;
// @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;
// @public (undocumented)
export const breakpoints: {
xs: {};
sm: {
'@media': string;
};
md: {
'@media': string;
};
lg: {
'@media': string;
};
xl: {
'@media': string;
};
'2xl': {
'@media': string;
};
};
export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
// @public (undocumented)
export const Button: React_2.ForwardRefExoticComponent<
@@ -166,22 +121,7 @@ export interface CheckboxProps {
}
// @public (undocumented)
export type Color =
| 'primary'
| 'secondary'
| 'error'
| Partial<Record<Theme, 'primary' | 'secondary' | 'error'>>;
// @public (undocumented)
export interface ColorProps {
// (undocumented)
background?: Background;
// (undocumented)
color?: Color;
}
// @public (undocumented)
export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto';
// @public (undocumented)
export const Container: React_2.ForwardRefExoticComponent<
@@ -189,78 +129,35 @@ export const Container: React_2.ForwardRefExoticComponent<
>;
// @public (undocumented)
export interface ContainerProps
extends Omit<
SpaceProps,
| 'padding'
| 'paddingLeft'
| 'paddingRight'
| 'paddingX'
| 'margin'
| 'marginLeft'
| 'marginRight'
| 'marginX'
| 'gap'
> {
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 DisplayProps =
| 'flex'
| 'none'
| 'inline'
| 'block'
| Partial<Record<Breakpoint, 'flex' | 'none' | 'inline' | 'block'>>;
export type Display = 'none' | 'flex' | 'block' | 'inline';
// @public (undocumented)
export const Field: {
Root: React_2.ForwardRefExoticComponent<
Omit<Field_2.Root.Props & React_2.RefAttributes<HTMLDivElement>, 'ref'> &
React_2.RefAttributes<HTMLDivElement>
>;
Label: React_2.ForwardRefExoticComponent<
Omit<Field_2.Label.Props & React_2.RefAttributes<any>, 'ref'> &
React_2.RefAttributes<any>
>;
Description: React_2.ForwardRefExoticComponent<
Omit<
Field_2.Description.Props & React_2.RefAttributes<HTMLParagraphElement>,
'ref'
> &
React_2.RefAttributes<HTMLParagraphElement>
>;
Error: React_2.ForwardRefExoticComponent<
Omit<Field_2.Error.Props & React_2.RefAttributes<HTMLDivElement>, 'ref'> &
React_2.RefAttributes<HTMLDivElement>
>;
Validity: ({
children,
...props
}: React_2.ComponentPropsWithoutRef<
typeof Field_2.Validity
>) => React_2.JSX.Element;
};
export type FlexDirection = 'row' | 'column';
// @public (undocumented)
export type FlexDirectionProps =
| 'row'
| 'column'
| Partial<Record<Breakpoint, 'row' | 'column'>>;
// @public (undocumented)
export type FlexWrapProps =
| 'wrap'
| 'nowrap'
| Partial<Record<Breakpoint, 'wrap' | 'nowrap'>>;
// @public (undocumented)
export type Gap = Space | Partial<Record<Breakpoint, Space>>;
export type FlexWrap = 'wrap' | 'nowrap' | 'wrap-reverse';
// @public (undocumented)
export const Grid: ForwardRefExoticComponent<
@@ -278,25 +175,27 @@ export interface GridItemProps {
// (undocumented)
className?: string;
// (undocumented)
colSpan?: Columns | 'full';
colEnd?: UtilityProps['colEnd'];
// (undocumented)
end?: Columns | 'auto';
colSpan?: UtilityProps['colSpan'];
// (undocumented)
rowSpan?: Columns | 'full';
colStart?: UtilityProps['colStart'];
// (undocumented)
start?: Columns | 'auto';
rowSpan?: UtilityProps['rowSpan'];
// (undocumented)
style?: React.CSSProperties;
}
// @public (undocumented)
export interface GridProps extends SpaceProps, ColorProps {
export interface GridProps extends SpaceProps {
// (undocumented)
children?: React.ReactNode;
// (undocumented)
className?: string;
// (undocumented)
columns?: Columns | Partial<Record<Breakpoint, Columns>>;
columns?: UtilityProps['columns'];
// (undocumented)
gap?: UtilityProps['gap'];
// (undocumented)
style?: React.CSSProperties;
}
@@ -339,7 +238,7 @@ export const Inline: ForwardRefExoticComponent<
>;
// @public (undocumented)
export interface InlineProps extends SpaceProps, ColorProps {
export interface InlineProps extends SpaceProps {
// (undocumented)
align?:
| 'left'
@@ -359,124 +258,53 @@ export interface InlineProps extends SpaceProps, ColorProps {
// (undocumented)
className?: string;
// (undocumented)
gap?: UtilityProps['gap'];
// (undocumented)
style?: React.CSSProperties;
}
// @public (undocumented)
export const Input: React_2.ForwardRefExoticComponent<
Omit<Input_2.Props & React_2.RefAttributes<HTMLInputElement>, 'ref'> &
React_2.RefAttributes<HTMLInputElement>
>;
// @public (undocumented)
export type JustifyContentProps =
export type JustifyContent =
| 'stretch'
| 'flex-start'
| 'start'
| 'center'
| 'flex-end'
| 'space-around'
| 'space-between'
| Partial<
Record<
Breakpoint,
| 'stretch'
| 'flex-start'
| 'center'
| 'flex-end'
| 'space-around'
| 'space-between'
>
>;
| 'end'
| 'around'
| 'between';
// @public (undocumented)
export type Margin = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type MarginBottom = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type MarginLeft = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type MarginRight = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type MarginTop = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type MarginX = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type MarginY = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type Padding = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type PaddingBottom = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type PaddingLeft = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type PaddingRight = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type PaddingTop = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type PaddingX = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type PaddingY = Space | Partial<Record<Breakpoint, Space>>;
// @public (undocumented)
export type Space = keyof typeof space;
// @public (undocumented)
export const space: {
none: number;
'2xs': string;
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
};
export type Space = 'none' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
// @public (undocumented)
export interface SpaceProps {
// (undocumented)
gap?: Gap;
margin?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
margin?: Margin;
marginBottom?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
marginBottom?: MarginBottom;
marginLeft?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
marginLeft?: MarginLeft;
marginRight?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
marginRight?: MarginRight;
marginTop?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
marginTop?: MarginTop;
marginX?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
marginX?: MarginX;
marginY?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
marginY?: MarginY;
padding?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
padding?: Padding;
paddingBottom?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
paddingBottom?: PaddingBottom;
paddingLeft?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
paddingLeft?: PaddingLeft;
paddingRight?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
paddingRight?: PaddingRight;
paddingTop?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
paddingTop?: PaddingTop;
paddingX?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
paddingX?: PaddingX;
// (undocumented)
paddingY?: PaddingY;
paddingY?: Space | Partial<Record<Breakpoint, Space>>;
}
// @public (undocumented)
@@ -485,7 +313,7 @@ export const Stack: ForwardRefExoticComponent<
>;
// @public (undocumented)
export interface StackProps extends SpaceProps, ColorProps {
export interface StackProps extends SpaceProps {
// (undocumented)
align?:
| 'left'
@@ -499,6 +327,8 @@ export interface StackProps extends SpaceProps, ColorProps {
// (undocumented)
className?: string;
// (undocumented)
gap?: UtilityProps['gap'];
// (undocumented)
style?: React.CSSProperties;
}
@@ -545,15 +375,32 @@ export const TableRow: React_3.ForwardRefExoticComponent<
>;
// @public (undocumented)
export type Theme = keyof typeof themes;
// @public (undocumented)
export const themes: {
light: {
selector: string;
};
dark: {
selector: string;
};
};
export interface UtilityProps extends SpaceProps {
// (undocumented)
alignItems?: AlignItems | Partial<Record<Breakpoint, AlignItems>>;
// (undocumented)
border?: Border | Partial<Record<Breakpoint, Border>>;
// (undocumented)
borderRadius?: BorderRadius | Partial<Record<Breakpoint, BorderRadius>>;
// (undocumented)
colEnd?: Columns | 'auto' | Partial<Record<Breakpoint, Columns | 'auto'>>;
// (undocumented)
colSpan?: Columns | 'full' | Partial<Record<Breakpoint, Columns | 'full'>>;
// (undocumented)
colStart?: Columns | 'auto' | Partial<Record<Breakpoint, Columns | 'auto'>>;
// (undocumented)
columns?: Columns | Partial<Record<Breakpoint, Columns>>;
// (undocumented)
display?: Display | Partial<Record<Breakpoint, Display>>;
// (undocumented)
flexDirection?: FlexDirection | Partial<Record<Breakpoint, FlexDirection>>;
// (undocumented)
flexWrap?: FlexWrap | Partial<Record<Breakpoint, FlexWrap>>;
// (undocumented)
gap?: Space | Partial<Record<Breakpoint, Space>>;
// (undocumented)
justifyContent?: JustifyContent | Partial<Record<Breakpoint, JustifyContent>>;
// (undocumented)
rowSpan?: Columns | 'full' | Partial<Record<Breakpoint, Columns | 'full'>>;
}
```
+324 -109
View File
@@ -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<string, any>
>((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,364 @@ const meta = {
control: false,
},
},
args: {
as: 'div',
background: 'elevation1',
borderRadius: 'small',
children: 'Basic Box',
display: 'block',
padding: 'sm',
},
} satisfies Meta<typeof Box>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Basic: Story = {
args: {},
args: {
style: {
background: '#1f47ff',
color: 'white',
padding: '4px 8px',
borderRadius: '4px',
},
children: 'Basic Box',
},
};
export const Responsive: Story = {
render: () => (
<Box
display={{ xs: 'block', sm: 'flex' }}
padding={{ xs: 'xs', sm: 'md', lg: 'lg' }}
background="background"
>
Responsive Box
</Box>
export const Display: Story = {
args: {
style: {
...Basic.args?.style,
},
},
render: args => (
<Stack align="center">
<Inline>
<Box display="block" {...args}>
Block
</Box>
<Box display="flex" {...args}>
Flex
</Box>
<Box display="inline" {...args}>
Inline
</Box>
<Box display="none" {...args}>
None
</Box>
</Inline>
<Box display={{ xs: 'block', sm: 'flex', md: 'inline' }} {...args}>
Responsive
</Box>
</Stack>
),
};
export const FlexContainer: Story = {
render: () => (
<Box
display="flex"
flexDirection="column"
padding="lg"
background="background"
>
<Box padding="md" background="background" color="primary">
Item 1
export const FlexDirection: Story = {
args: {
style: {
...Basic.args?.style,
},
display: 'flex',
gap: 'xs',
},
render: args => (
<Stack align="center">
<Box flexDirection="row" {...args}>
<span>Row</span>
<span>Row</span>
</Box>
<Box padding="md" background="background" color="primary">
Item 2
<Box flexDirection="column" {...args}>
<span>Column</span>
<span>Column</span>
</Box>
<Box padding="md" background="background" color="primary">
Item 3
<Box flexDirection={{ xs: 'column', sm: 'row' }} {...args}>
<span>Responsive</span>
<span>Flex Direction</span>
</Box>
</Box>
</Stack>
),
};
export const Nested: Story = {
render: () => (
<Box padding="lg" background="background">
<Box padding="md" background="background">
Header
export const JustifyContent: Story = {
args: {
style: {
...Basic.args?.style,
width: '200px',
},
display: 'flex',
gap: 'xs',
},
render: args => (
<Stack>
<Box justifyContent="start" {...args}>
<span>Flex Start</span>
</Box>
<Box justifyContent="center" {...args}>
<span>Center</span>
</Box>
<Box justifyContent="end" {...args}>
<span>Flex End</span>
</Box>
<Box justifyContent="around" {...args}>
<span>Space</span>
<span>Around</span>
</Box>
<Box justifyContent="between" {...args}>
<span>Space</span>
<span>Between</span>
</Box>
<Box
display="flex"
padding="md"
background="background"
justifyContent="space-between"
justifyContent={{
xs: 'between',
sm: 'around',
md: 'start',
}}
{...args}
>
<Box padding="xs" background="background">
Sidebar
<span>Responsive</span>
<span>Spacing</span>
</Box>
</Stack>
),
};
export const AlignItems: Story = {
args: {
style: {
...Basic.args?.style,
width: '200px',
height: '100px',
},
display: 'flex',
gap: 'xs',
},
render: args => (
<Stack>
<Box alignItems="start" {...args}>
<span>Flex Start</span>
</Box>
<Box alignItems="center" {...args}>
<span>Center</span>
</Box>
<Box alignItems="end" {...args}>
<span>Flex End</span>
</Box>
<Box
alignItems={{
xs: 'start',
sm: 'center',
md: 'end',
}}
{...args}
>
<span>Responsive</span>
<span>Spacing</span>
</Box>
</Stack>
),
};
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 => (
<Stack align="center" gap="md">
<Inline alignY="center" gap="md">
<Box padding="md" style={styleInsideBox}>
<Box {...args}>Padding</Box>
</Box>
<Box padding="xs" background="background">
Main Content
<Box paddingX="md" style={styleInsideBox}>
<Box {...args}>Padding X</Box>
</Box>
</Box>
<Box padding="md" background="background">
Footer
</Box>
</Box>
<Box paddingY="md" style={styleInsideBox}>
<Box {...args}>Padding Y</Box>
</Box>
</Inline>
<Inline alignY="center" gap="md">
<Box paddingTop="md" style={styleInsideBox}>
<Box {...args}>Padding Top</Box>
</Box>
<Box paddingRight="md" style={styleInsideBox}>
<Box {...args}>Padding Right</Box>
</Box>
<Box paddingBottom="md" style={styleInsideBox}>
<Box {...args}>Padding Bottom</Box>
</Box>
<Box paddingLeft="md" style={styleInsideBox}>
<Box {...args}>Padding Left</Box>
</Box>
</Inline>
</Stack>
),
};
export const Alignment: Story = {
render: () => (
<Box
display="flex"
padding="lg"
background="background"
justifyContent="center"
alignItems="center"
style={{ height: '200px' }}
>
<Box padding="md" background="background">
Centered Content
</Box>
</Box>
export const Margin: Story = {
args: {
style: {
background: '#1f47ff',
color: 'white',
borderRadius: '4px',
padding: '12px 12px',
},
},
render: args => (
<Stack align="center" gap="md">
<Inline alignY="center" gap="md">
<Box style={styleInsideBox}>
<Box margin="md" {...args}>
Margin
</Box>
</Box>
<Box style={styleInsideBox}>
<Box marginX="md" {...args}>
Margin X
</Box>
</Box>
<Box style={styleInsideBox}>
<Box marginY="md" {...args}>
Margin Y
</Box>
</Box>
</Inline>
<Inline alignY="center" gap="md">
<Box style={styleInsideBox}>
<Box marginTop="md" {...args}>
Margin Top
</Box>
</Box>
<Box style={styleInsideBox}>
<Box marginRight="md" {...args}>
Margin Right
</Box>
</Box>
<Box style={styleInsideBox}>
<Box marginBottom="md" {...args}>
Margin Bottom
</Box>
</Box>
<Box style={styleInsideBox}>
<Box marginLeft="md" {...args}>
Margin Left
</Box>
</Box>
</Inline>
</Stack>
),
};
// Example showing different spacing combinations
export const Spacing: Story = {
render: () => (
<Box display="flex" flexDirection="column" gap="md">
<Box padding="xs" background="background">
Small Padding
export const FlexWrap: Story = {
args: {
style: {
...Basic.args?.style,
width: '200px',
},
display: 'flex',
gap: 'xs',
},
render: args => (
<Stack align="center">
<Box flexWrap="wrap" {...args}>
<span>One</span>
<span>Two</span>
<span>Three</span>
<span>Four</span>
<span>Five</span>
<span>Six</span>
</Box>
<Box padding="md" background="background">
Medium Padding
<Box flexWrap="nowrap" {...args}>
<span>One</span>
<span>Two</span>
<span>Three</span>
<span>Four</span>
<span>Five</span>
<span>Six</span>
</Box>
<Box padding="lg" background="background">
Large Padding
<Box flexWrap="wrap-reverse" {...args}>
<span>One</span>
<span>Two</span>
<span>Three</span>
<span>Four</span>
<span>Five</span>
<span>Six</span>
</Box>
<Box paddingX="lg" paddingY="xs" background="background">
Mixed Padding
</Box>
</Box>
</Stack>
),
};
// Example showing different display values
export const DisplayVariants: Story = {
render: () => (
<Box display="flex" flexDirection="column" gap="md">
<Box padding="md" background="background" display="block">
Display Block
export const BorderRadius: Story = {
args: {
style: {
background: '#1f47ff',
color: 'white',
padding: '4px 8px',
width: '64px',
height: '64px',
},
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
render: args => (
<Inline align="center">
<Box borderRadius="2xs" {...args}>
<span>2xs</span>
</Box>
<Box padding="md" background="background" display="flex">
Display Flex
<Box borderRadius="xs" {...args}>
<span>xs</span>
</Box>
<Box padding="md" background="background" display="inline">
Display Inline
<Box borderRadius="sm" {...args}>
<span>sm</span>
</Box>
</Box>
<Box borderRadius="md" {...args}>
<span>md</span>
</Box>
<Box borderRadius="xl" {...args}>
<span>xl</span>
</Box>
<Box borderRadius="2xl" {...args}>
<span>2xl</span>
</Box>
</Inline>
),
};
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 => (
<Inline align="center">
<Box border="base" {...args}>
Base
</Box>
<Box border="error" {...args}>
Error
</Box>
<Box border="warning" {...args}>
Warning
</Box>
<Box border="selected" {...args}>
Selected
</Box>
<Box border="none" {...args}>
None
</Box>
</Inline>
),
};
+4 -4
View File
@@ -15,18 +15,18 @@
*/
import { createElement, forwardRef } from 'react';
import { boxSprinkles } from './sprinkles.css';
import { BoxProps } from './types';
import { getClassNames } from '../../utils/getClassNames';
/** @public */
export const Box = forwardRef<HTMLDivElement, BoxProps>((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 = ['box', sprinklesClassName, className]
const classNames = ['canon-box', utilityClassNames, className]
.filter(Boolean)
.join(' ');
+40 -11
View File
@@ -1,10 +1,8 @@
import { Meta, Unstyled, Source } 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, getProps } from '../../../docs/components';
import { boxProperties } from './sprinkles.css';
import { spacingProperties } from '../../layout/sprinkles.css';
import { PropsTable } from '../../../docs/components';
import { spacePropsList } from '../../../docs/spaceProps';
<Meta of={BoxStories} />
@@ -32,18 +30,49 @@ import { spacingProperties } from '../../layout/sprinkles.css';
<PropsTable
data={{
...getProps(boxProperties.styles),
alignItems: {
type: ['stretch', 'start', 'center', 'end'],
responsive: true,
},
border: {
type: ['none', 'base', 'error', 'warning', 'selected'],
responsive: true,
},
borderRadius: {
type: ['none', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'],
responsive: true,
},
children: {
type: 'ReactNode',
required: false,
responsive: false,
},
className: {
type: 'string',
required: false,
responsive: false,
},
display: {
type: ['none', 'flex', 'block', 'inline'],
responsive: true,
},
flexDirection: {
type: ['row', 'column'],
responsive: true,
},
flexWrap: {
type: ['wrap', 'nowrap', 'wrap-reverse'],
responsive: true,
},
gap: {
type: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl'],
responsive: true,
},
justifyContent: {
type: ['stretch', 'start', 'center', 'end', 'around', 'between'],
responsive: true,
},
style: {
type: 'CSSProperties',
required: false,
responsive: false,
},
}}
/>
@@ -54,9 +83,9 @@ import { spacingProperties } from '../../layout/sprinkles.css';
avoid collapsing margins but both are available.
</Text>
<Padding />
<Canvas of={BoxStories.Padding} />
<PropsTable data={getProps(spacingProperties.styles)} />
<PropsTable data={spacePropsList} />
<Title type="h2">Examples</Title>
<Text>Here are some examples of how you can use the Box component.</Text>
@@ -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 }) => (
<Box
paddingX="md"
paddingY="sm"
borderRadius="small"
style={{ background: '#1f47ff', color: 'white' }}
>
{children}
</Box>
);
export const Padding = () => {
return (
<Box
display="flex"
justifyContent="center"
flexDirection="column"
alignItems="center"
borderRadius="small"
marginBottom="md"
gap="xl"
paddingY="xl"
style={{ border: '1px solid #e7e7e7' }}
>
<Inline align="center" alignY="center" gap="xl">
<Box
alignItems="center"
borderRadius="small"
padding="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>padding</FakeBox>
</Box>
<Box
alignItems="center"
borderRadius="small"
paddingX="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>paddingX</FakeBox>
</Box>
<Box
alignItems="center"
borderRadius="small"
paddingY="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>paddingY</FakeBox>
</Box>
</Inline>
<Inline align="center" alignY="center" gap="xl">
<Box
alignItems="center"
borderRadius="small"
paddingTop="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>paddingTop</FakeBox>
</Box>
<Box
alignItems="center"
borderRadius="small"
paddingBottom="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>paddingBottom</FakeBox>
</Box>
<Box
alignItems="center"
borderRadius="small"
paddingLeft="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>paddingLeft</FakeBox>
</Box>
<Box
alignItems="center"
borderRadius="small"
paddingRight="md"
style={{ background: '#c4cafb', color: 'white' }}
>
<FakeBox>paddingRight</FakeBox>
</Box>
</Inline>
</Box>
);
};
@@ -15,4 +15,3 @@
*/
export { Box } from './Box';
export type * from './types';
export { breakpoints, space, themes } from '../../layout/properties';
@@ -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,
);
+1 -1
View File
@@ -1,4 +1,4 @@
.box {
.canon-box {
font-family: 'var(--canon-font-regular)';
color: 'var(--canon-text-primary)';
}
+2 -66
View File
@@ -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<Record<Breakpoint, 'flex' | 'none' | 'inline' | 'block'>>;
/** @public */
export type FlexDirectionProps =
| 'row'
| 'column'
| Partial<Record<Breakpoint, 'row' | 'column'>>;
/** @public */
export type FlexWrapProps =
| 'wrap'
| 'nowrap'
| Partial<Record<Breakpoint, 'wrap' | 'nowrap'>>;
/** @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<Breakpoint, 'stretch' | 'flex-start' | 'center' | 'flex-end'>
>;
/** @public */
export type BorderRadiusProps =
| 'none'
| 'small'
| 'medium'
| 'full'
| Partial<Record<Breakpoint, 'none' | 'small' | 'medium' | 'full'>>;
/** @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;
}
@@ -14,8 +14,7 @@
* limitations under the License.
*/
import { IconNames } from '../Icon';
import { Breakpoint } from '../../layout/types';
import type { Breakpoint } from '../../types';
/**
* Properties for {@link Button}
*
@@ -17,25 +17,12 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Box } from '../Box/Box';
import { argTypesSpacing } from '../../../docs/utils/argTypes';
import { Container } from './Container';
const argTypesSpacingWithoutLeftAndRight = { ...argTypesSpacing };
delete argTypesSpacingWithoutLeftAndRight.padding;
delete argTypesSpacingWithoutLeftAndRight.paddingLeft;
delete argTypesSpacingWithoutLeftAndRight.paddingRight;
delete argTypesSpacingWithoutLeftAndRight.paddingX;
delete argTypesSpacingWithoutLeftAndRight.margin;
delete argTypesSpacingWithoutLeftAndRight.marginLeft;
delete argTypesSpacingWithoutLeftAndRight.marginRight;
delete argTypesSpacingWithoutLeftAndRight.marginX;
delete argTypesSpacingWithoutLeftAndRight.gap;
const meta = {
title: 'Components/Container',
component: Container,
argTypes: {
...argTypesSpacingWithoutLeftAndRight,
children: {
control: false,
},
@@ -53,7 +40,7 @@ type Story = StoryObj<typeof meta>;
const FakeBox = () => (
<Box
borderRadius="small"
borderRadius="xs"
style={{ background: '#1f47ff', color: 'white', height: '400px' }}
/>
);
@@ -14,22 +14,24 @@
* limitations under the License.
*/
import React, { forwardRef } from 'react';
import { containerSprinkles } from './sprinkles.css';
import { ContainerProps } from './types';
import { getClassNames } from '../../utils/getClassNames';
/** @public */
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
(props, ref) => {
const { children, className, style, ...restProps } = props;
const containerClassName = containerSprinkles(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 = ['canon-container', utilityClassNames, className]
.filter(Boolean)
.join(' ');
return (
<div
ref={ref}
className={['container', containerClassName].filter(Boolean).join(' ')}
style={style}
>
<div ref={ref} className={classNames} style={style}>
{children}
</div>
);
@@ -1,8 +1,7 @@
import { Meta, Unstyled, Source } from '@storybook/blocks';
import * as ContainerStories from './Container.stories';
import { Title, Text, PropsTable, getProps } from '../../../docs/components';
import { spacingProperties } from '../../layout/sprinkles.css';
import { containerProperties } from './sprinkles.css';
import { spacePropsList } from '../../../docs/spaceProps';
<Meta of={ContainerStories} />
@@ -28,18 +27,41 @@ import { containerProperties } from './sprinkles.css';
<PropsTable
data={{
...getProps(containerProperties.styles),
children: {
type: 'ReactNode',
required: false,
responsive: false,
},
className: {
type: 'string',
required: false,
responsive: false,
},
marginY: {
type: spacePropsList.marginY.type,
responsive: spacePropsList.marginY.responsive,
},
marginBottom: {
type: spacePropsList.marginBottom.type,
responsive: spacePropsList.marginBottom.responsive,
},
marginTop: {
type: spacePropsList.marginTop.type,
responsive: spacePropsList.marginTop.responsive,
},
paddingY: {
type: spacePropsList.paddingY.type,
responsive: spacePropsList.paddingY.responsive,
},
paddingBottom: {
type: spacePropsList.paddingBottom.type,
responsive: spacePropsList.paddingBottom.responsive,
},
paddingTop: {
type: spacePropsList.paddingTop.type,
responsive: spacePropsList.paddingTop.responsive,
},
style: {
type: 'CSSProperties',
required: false,
responsive: false,
},
}}
/>
@@ -1,40 +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, space } from '../../layout/properties';
import { colorProperties, spacingProperties } from '../../layout/sprinkles.css';
export const containerProperties = defineProperties({
conditions: breakpoints,
defaultCondition: 'xs',
properties: {
paddingTop: space,
paddingBottom: space,
marginTop: space,
marginBottom: space,
},
shorthands: {
paddingY: ['paddingTop', 'paddingBottom'],
marginY: ['marginTop', 'marginBottom'],
},
});
export const containerSprinkles = createSprinkles(
spacingProperties,
colorProperties,
containerProperties,
);
@@ -1,4 +1,4 @@
.container {
.canon-container {
max-width: var(--canon-container-max-width);
margin: 0 auto;
padding: 0 var(--canon-container-padding);
@@ -13,23 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { SpaceProps } from '../../layout/types';
import { SpaceProps } from '../../types';
/** @public */
export interface ContainerProps
extends Omit<
SpaceProps,
| 'padding'
| 'paddingLeft'
| 'paddingRight'
| 'paddingX'
| 'margin'
| 'marginLeft'
| 'marginRight'
| 'marginX'
| 'gap'
> {
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;
}
+3 -3
View File
@@ -1,7 +1,7 @@
import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks';
import * as GridStories from './Grid.stories';
import { Title, Text, PropsTable, getProps } from '../../../docs/components';
import { spacingProperties } from '../../layout/sprinkles.css';
import { Title, Text, PropsTable } from '../../../docs/components';
import { spacePropsList } from '../../../docs/spaceProps';
<Meta of={GridStories} />
@@ -59,7 +59,7 @@ import { spacingProperties } from '../../layout/sprinkles.css';
The grid component also accepts all the spacing props from the Box component.
</Text>
<PropsTable data={getProps(spacingProperties.styles)} />
<PropsTable data={spacePropsList} />
<Title type="h3">Grid Item</Title>
<Text>
@@ -19,15 +19,12 @@ import type { Meta, StoryObj } from '@storybook/react';
import { Grid } from './Grid';
import type { GridItemProps } from './types';
import { Box } from '../Box/Box';
import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes';
import { Stack } from '../Stack';
const meta = {
title: 'Components/Grid',
component: Grid,
argTypes: {
...argTypesSpacing,
...argTypesColor,
children: {
control: false,
},
@@ -45,7 +42,7 @@ type Story = StoryObj<typeof meta>;
const FakeBox = () => (
<Box
borderRadius="small"
borderRadius="xs"
style={{ background: '#1f47ff', color: 'white', height: '64px' }}
/>
);
@@ -105,7 +102,7 @@ export const RowAndColumns: Story = {
<Grid {...args} columns={3}>
<Grid.Item colSpan={1} rowSpan={2}>
<Box
borderRadius="small"
borderRadius="xs"
style={{ background: '#1f47ff', color: 'white', height: '100%' }}
/>
</Grid.Item>
+17 -32
View File
@@ -16,62 +16,47 @@
import { createElement, forwardRef } from 'react';
import { GridItemProps, GridProps } from './types';
import { gridItemSprinkles, gridSprinkles } from './sprinkles.css';
import { getClassNames } from '../../utils/getClassNames';
const GridBase = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
const {
children,
columns,
gap = 'xs',
columns = 'auto',
className,
style,
...restProps
} = props;
const sprinklesClassName = gridSprinkles({
...restProps,
gap,
gridTemplateColumns: columns ? columns : 'auto',
});
const utilityClassNames = getClassNames({ gap, columns, ...restProps });
const classNames = ['grid', sprinklesClassName, className]
const classNames = ['canon-grid', utilityClassNames, className]
.filter(Boolean)
.join(' ');
return createElement(
'div',
{
ref,
className: classNames,
style,
},
return createElement('div', {
ref,
className: classNames,
style,
children,
);
});
});
const GridItem = forwardRef<HTMLDivElement, GridItemProps>((props, ref) => {
const { children, rowSpan, colSpan, start, end, className, style } = props;
const { children, className, style, ...restProps } = props;
const sprinklesClassName = gridItemSprinkles({
rowSpan,
colSpan,
start,
end,
});
const utilityClassNames = getClassNames(restProps);
const classNames = ['grid-item', sprinklesClassName, className]
const classNames = ['grid-item', utilityClassNames, className]
.filter(Boolean)
.join(' ');
return createElement(
'div',
{
ref,
className: classNames,
style,
},
return createElement('div', {
ref,
className: classNames,
style,
children,
);
});
});
/** @public */
+1 -1
View File
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export { Grid } from './Grid';
export type { GridProps, GridItemProps, Columns } from './types';
export type { GridProps, GridItemProps } from './types';
@@ -1,130 +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 gridProperties = defineProperties({
conditions: breakpoints,
defaultCondition: 'xs',
properties: {
gridTemplateColumns: {
1: 'repeat(1, minmax(0, 1fr))',
2: 'repeat(2, minmax(0, 1fr))',
3: 'repeat(3, minmax(0, 1fr))',
4: 'repeat(4, minmax(0, 1fr))',
5: 'repeat(5, minmax(0, 1fr))',
6: 'repeat(6, minmax(0, 1fr))',
7: 'repeat(7, minmax(0, 1fr))',
8: 'repeat(8, minmax(0, 1fr))',
9: 'repeat(9, minmax(0, 1fr))',
10: 'repeat(10, minmax(0, 1fr))',
11: 'repeat(11, minmax(0, 1fr))',
12: 'repeat(12, minmax(0, 1fr))',
auto: 'repeat(auto-fit, minmax(0, 1fr))',
},
},
shorthands: {
columns: ['gridTemplateColumns'],
},
});
export const gridSprinkles = createSprinkles(
spacingProperties,
colorProperties,
gridProperties,
);
const gridItemProperties = defineProperties({
conditions: breakpoints,
defaultCondition: 'xs',
properties: {
gridColumn: {
1: 'span 1 / span 1',
2: 'span 2 / span 2',
3: 'span 3 / span 3',
4: 'span 4 / span 4',
5: 'span 5 / span 5',
6: 'span 6 / span 6',
7: 'span 7 / span 7',
8: 'span 8 / span 8',
9: 'span 9 / span 9',
10: 'span 10 / span 10',
11: 'span 11 / span 11',
12: 'span 12 / span 12',
full: '1 / -1',
},
gridRow: {
1: 'span 1 / span 1',
2: 'span 2 / span 2',
3: 'span 3 / span 3',
4: 'span 4 / span 4',
5: 'span 5 / span 5',
6: 'span 6 / span 6',
7: 'span 7 / span 7',
8: 'span 8 / span 8',
9: 'span 9 / span 9',
10: 'span 10 / span 10',
11: 'span 11 / span 11',
12: 'span 12 / span 12',
full: '1 / -1',
},
gridColumnStart: {
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
13: '13',
auto: 'auto',
},
gridColumnEnd: {
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
13: '13',
auto: 'auto',
},
},
shorthands: {
colSpan: ['gridColumn'],
rowSpan: ['gridRow'],
start: ['gridColumnStart'],
end: ['gridColumnEnd'],
},
});
export const gridItemSprinkles = createSprinkles(
colorProperties,
gridItemProperties,
);
@@ -1,3 +1,3 @@
.grid {
.canon-grid {
display: grid;
}
+9 -11
View File
@@ -13,27 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Breakpoint, ColorProps } from '../../layout/types';
import { SpaceProps } from '../../layout/types';
import type { UtilityProps, SpaceProps } from '../../types';
/** @public */
export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
/** @public */
export interface GridProps extends SpaceProps, ColorProps {
export interface GridProps extends SpaceProps {
children?: React.ReactNode;
columns?: Columns | Partial<Record<Breakpoint, Columns>>;
className?: string;
columns?: UtilityProps['columns'];
gap?: UtilityProps['gap'];
style?: React.CSSProperties;
}
/** @public */
export interface GridItemProps {
children: React.ReactNode;
rowSpan?: Columns | 'full';
colSpan?: Columns | 'full';
start?: Columns | 'auto';
end?: Columns | 'auto';
className?: string;
colSpan?: UtilityProps['colSpan'];
colEnd?: UtilityProps['colEnd'];
colStart?: UtilityProps['colStart'];
rowSpan?: UtilityProps['rowSpan'];
style?: React.CSSProperties;
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { Breakpoint } from '../../layout/types';
import { Breakpoint } from '../../types';
/** @public */
export interface HeadingProps {
@@ -1,8 +1,7 @@
import { Meta, Unstyled, Source } from '@storybook/blocks';
import * as InlineStories from './Inline.stories';
import { Title, Text, PropsTable, getProps } from '../../../docs/components';
import { spacingProperties } from '../../layout/sprinkles.css';
import { inlineProperties } from './sprinkles.css';
import { spacePropsList } from '../../../docs/spaceProps';
<Meta of={InlineStories} />
@@ -34,11 +33,11 @@ import { inlineProperties } from './sprinkles.css';
<PropsTable
data={{
align: {
type: 'left | center | right',
type: 'start | center | end',
responsive: true,
},
alignY: {
type: 'top | center | bottom',
type: 'start | center | end',
responsive: true,
},
children: {
@@ -60,7 +59,7 @@ import { inlineProperties } from './sprinkles.css';
The grid component also accepts all the spacing props from the Box component.
</Text>
<PropsTable data={getProps(spacingProperties.styles)} />
<PropsTable data={spacePropsList} />
<Title type="h2">Examples</Title>
@@ -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'],
@@ -49,6 +46,41 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
const fakeBlockList = [
{ width: 45, height: 60 },
{ width: 150, height: 75 },
{ width: 80, height: 50 },
{ width: 120, height: 70 },
{ width: 95, height: 65 },
{ width: 110, height: 55 },
{ width: 130, height: 60 },
{ width: 100, height: 80 },
{ width: 140, height: 45 },
{ width: 85, height: 70 },
{ width: 125, height: 50 },
{ width: 105, height: 75 },
{ width: 115, height: 65 },
{ width: 135, height: 55 },
{ width: 90, height: 60 },
{ width: 145, height: 80 },
{ width: 75, height: 45 },
{ width: 155, height: 70 },
{ width: 60, height: 50 },
{ width: 160, height: 75 },
{ width: 70, height: 65 },
{ width: 150, height: 55 },
{ width: 95, height: 60 },
{ width: 120, height: 80 },
{ width: 85, height: 45 },
{ width: 130, height: 70 },
{ width: 100, height: 50 },
{ width: 140, height: 75 },
{ width: 110, height: 65 },
{ width: 125, height: 55 },
{ width: 105, height: 60 },
{ width: 145, height: 80 },
];
const FakeBox = ({
width = 120,
height = 80,
@@ -57,7 +89,7 @@ const FakeBox = ({
height?: number;
}) => (
<Box
borderRadius="small"
borderRadius="xs"
style={{ background: '#1f47ff', color: 'white', width, height }}
/>
);
@@ -66,12 +98,8 @@ export const Default: Story = {
args: {
children: (
<>
{Array.from({ length: 32 }).map((_, index) => (
<FakeBox
key={index}
width={Math.floor(Math.random() * (160 - 40 + 1)) + 40}
height={Math.floor(Math.random() * (80 - 40 + 1)) + 40}
/>
{fakeBlockList.map((block, index) => (
<FakeBox key={index} width={block.width} height={block.height} />
))}
</>
),
+39 -17
View File
@@ -15,21 +15,43 @@
*/
import { createElement, forwardRef } from 'react';
import { inlineSprinkles } from './sprinkles.css';
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<Record<Breakpoint, JustifyContent>> = {};
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<Record<Breakpoint, AlignItems>> = {};
for (const [key, val] of Object.entries(value)) {
returnedValue[key as Breakpoint] = mapAlignYValue(val) as AlignItems;
}
return returnedValue;
}
return 'stretch';
};
/** @public */
@@ -45,16 +67,16 @@ export const Inline = forwardRef<HTMLElement, InlineProps>((props, ref) => {
...restProps
} = props;
// Generate the list of class names
const sprinklesClassName = inlineSprinkles({
...restProps,
// 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(' ');
@@ -1,4 +1,4 @@
.inline {
.canon-inline {
display: flex;
flex-wrap: wrap;
}
@@ -14,13 +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';
/** @public */
export interface InlineProps extends SpaceProps, ColorProps {
export interface InlineProps extends SpaceProps {
children: React.ReactNode;
as?: AsProps;
gap?: UtilityProps['gap'];
align?:
| 'left'
| 'center'
+3 -3
View File
@@ -1,7 +1,7 @@
import { Meta, Unstyled, Source } from '@storybook/blocks';
import * as StackStories from './Stack.stories';
import { Title, Text, PropsTable, getProps } from '../../../docs/components';
import { spacingProperties } from '../../layout/sprinkles.css';
import { spacePropsList } from '../../../docs/spaceProps';
<Meta of={StackStories} />
@@ -33,7 +33,7 @@ import { spacingProperties } from '../../layout/sprinkles.css';
<PropsTable
data={{
align: {
type: ['left', 'center', 'right'],
type: ['start', 'center', 'end'],
responsive: true,
},
children: {
@@ -55,7 +55,7 @@ import { spacingProperties } from '../../layout/sprinkles.css';
The grid component also accepts all the spacing props from the Box component.
</Text>
<PropsTable data={getProps(spacingProperties.styles)} />
<PropsTable data={spacePropsList} />
<Title type="h2">Common questions</Title>
@@ -18,14 +18,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'],
@@ -53,7 +50,7 @@ const FakeBox = () => (
<Box
paddingX="xl"
paddingY="md"
borderRadius="small"
borderRadius="xs"
style={{ background: '#1f47ff', color: 'white' }}
>
Fake Box
+23 -14
View File
@@ -16,13 +16,25 @@
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<Record<Breakpoint, AlignItems>> = {};
for (const [key, val] of Object.entries(value)) {
returnedValue[key as Breakpoint] = mapAlignValue(val) as AlignItems;
}
return returnedValue;
}
return 'stretch';
};
/** @public */
@@ -37,18 +49,15 @@ export const Stack = forwardRef<HTMLDivElement, StackProps>((props, ref) => {
...restProps
} = props;
// Transform the align prop
const flexAlign = alignToFlexAlign(align);
// 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(' ');
@@ -1,4 +1,4 @@
.stack {
.canon-stack {
display: flex;
flex-direction: column;
}
+9 -3
View File
@@ -13,13 +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';
import type {
SpaceProps,
UtilityProps,
AsProps,
Breakpoint,
} from '../../types';
/** @public */
export interface StackProps extends SpaceProps, ColorProps {
export interface StackProps extends SpaceProps {
children: React.ReactNode;
as?: AsProps;
gap?: UtilityProps['gap'];
align?:
| 'left'
| 'center'
+1 -1
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { Breakpoint } from '../../layout/types';
import type { Breakpoint } from '../../types';
/** @public */
export interface TextProps {
+15 -21
View File
@@ -18,21 +18,14 @@ import React, { createContext, useContext, ReactNode } from 'react';
import { IconMap, IconNames } from '../components/Icon/types';
import { defaultIcons } from '../components/Icon/icons';
import { useMediaQuery } from '../hooks/useMediaQuery';
import { Breakpoints } from '../types';
const defaultBreakpoints: Breakpoints = {
xs: '0px',
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1536px',
};
import type { Breakpoint } from '../types';
interface CanonContextProps {
icons: IconMap;
breakpoint: keyof Breakpoints;
getResponsiveValue: (value: string | Partial<Breakpoints>) => string;
breakpoint: Breakpoint;
getResponsiveValue: (
value: string | Partial<Record<Breakpoint, string>>,
) => string;
}
const CanonContext = createContext<CanonContextProps>({
@@ -44,21 +37,20 @@ const CanonContext = createContext<CanonContextProps>({
interface CanonProviderProps {
children?: ReactNode;
overrides?: Partial<Record<IconNames, React.ComponentType>>;
breakpoints?: Partial<Breakpoints>;
}
/** @public */
export const CanonProvider = (props: CanonProviderProps) => {
const { children, overrides, breakpoints = defaultBreakpoints } = props;
const { children, overrides } = props;
// Merge provided overrides with default icons
const combinedIcons = { ...defaultIcons, ...overrides };
const isBreakpointSm = useMediaQuery(`(min-width: ${breakpoints.sm})`);
const isBreakpointMd = useMediaQuery(`(min-width: ${breakpoints.md})`);
const isBreakpointLg = useMediaQuery(`(min-width: ${breakpoints.lg})`);
const isBreakpointXl = useMediaQuery(`(min-width: ${breakpoints.xl})`);
const isBreakpoint2xl = useMediaQuery(`(min-width: ${breakpoints['2xl']})`);
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 = (() => {
@@ -70,9 +62,11 @@ export const CanonProvider = (props: CanonProviderProps) => {
return 'xs';
})();
const getResponsiveValue = (value: string | Partial<Breakpoints>) => {
const getResponsiveValue = (
value: string | Partial<Record<Breakpoint, string>>,
) => {
if (typeof value === 'object') {
const breakpointsOrder: (keyof Breakpoints)[] = [
const breakpointsOrder: Breakpoint[] = [
'xs',
'sm',
'md',
+26
View File
@@ -0,0 +1,26 @@
/*
* 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 base {
@import './normalize.css';
*,
html,
body {
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
}
}
+15 -19
View File
@@ -15,14 +15,8 @@
*/
/* Normalize */
@import './normalize.css';
*,
html,
body {
font-family: var(--canon-font-regular);
font-weight: var(--canon-font-weight-regular);
}
@import './base.css';
@import './utilities.css';
/* Light theme tokens */
:root {
@@ -33,10 +27,11 @@ body {
--canon-surface-2: #f4f4f4;
--canon-surface-3: #f1f1f1;
/* Outlines */
--canon-outline: rgba(0, 0, 0, 0.1);
--canon-outline-hover: rgba(0, 0, 0, 0.2);
--canon-outline-focus: #000;
/* Borders */
--canon-border-base: rgba(0, 0, 0, 0.1);
--canon-border-warning: #e36d05;
--canon-border-error: #e22b2b;
--canon-border-selected: #1db954;
/* States - Add more states */
--canon-error: #f50000;
@@ -47,9 +42,9 @@ body {
--canon-text-secondary: #646464;
/* Box shadows */
--canon-box-shadow-small: 0 0 0 1px rgba(0, 0, 0, 0.05);
--canon-box-shadow-medium: 0 0 0 1px rgba(0, 0, 0, 0.1);
--canon-box-shadow-large: 0 0 0 1px rgba(0, 0, 0, 0.2);
/* --canon-box-shadow-small: 0 0 0 1px rgba(0, 0, 0, 0.05); */
/* --canon-box-shadow-medium: 0 0 0 1px rgba(0, 0, 0, 0.1); */
/* --canon-box-shadow-large: 0 0 0 1px rgba(0, 0, 0, 0.2); */
/* Font families */
--canon-font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
@@ -108,10 +103,11 @@ body {
--canon-surface-1: #121212;
--canon-surface-2: #1a1a1a;
/* Outlines */
--canon-outline: rgba(255, 255, 255, 0.2);
--canon-outline-hover: rgba(255, 255, 255, 0.4);
--canon-outline-focus: #fff;
/* 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;
@@ -14,21 +14,20 @@
* limitations under the License.
*/
import { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
import { breakpoints } from '../../layout/properties';
import { colorProperties, spacingProperties } from '../../layout/sprinkles.css';
/* Default utilities */
@import './utilities/xs.css';
export const inlineProperties = defineProperties({
conditions: breakpoints,
defaultCondition: 'xs',
properties: {
alignItems: ['flex-start', 'center', 'flex-end'],
justifyContent: ['flex-start', 'center', 'flex-end'],
},
});
/* Min 640px */
@import './utilities/sm.css';
export const inlineSprinkles = createSprinkles(
spacingProperties,
colorProperties,
inlineProperties,
);
/* Min 768px */
@import './utilities/md.css';
/* Min 1024px */
@import './utilities/lg.css';
/* Min 1280px */
@import './utilities/xl.css';
/* Min 1536px */
@import './utilities/2xl.css';
+884
View File
@@ -0,0 +1,884 @@
/*
* 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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;
}
}
}
+884
View File
@@ -0,0 +1,884 @@
/*
* 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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;
}
}
}
+884
View File
@@ -0,0 +1,884 @@
/*
* 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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;
}
}
}
+884
View File
@@ -0,0 +1,884 @@
/*
* 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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;
}
}
}
+884
View File
@@ -0,0 +1,884 @@
/*
* 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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;
}
}
}
+882
View File
@@ -0,0 +1,882 @@
/*
* 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-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-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-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-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-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-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-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-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-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-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-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-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-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-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;
}
}
+3 -5
View File
@@ -20,9 +20,6 @@
* @packageDocumentation
*/
// Layout types
export * from './layout/types';
// Layout components
export * from './components/Box';
export * from './components/Grid';
@@ -35,5 +32,6 @@ export * from './components/Button';
export * from './components/Icon';
export * from './components/Checkbox';
export * from './components/Table';
export * from './components/Field';
export * from './components/Input';
// Types
export * from './types';
-43
View File
@@ -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,
'2xs': 'var(--canon-spacing-2xs)',
xs: 'var(--canon-spacing-xs)',
sm: 'var(--canon-spacing-sm)',
md: 'var(--canon-spacing-md)',
lg: 'var(--canon-spacing-lg)',
xl: 'var(--canon-spacing-xl)',
'2xl': 'var(--canon-spacing-2xl)',
};
@@ -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',
},
},
});
-131
View File
@@ -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<Record<Breakpoint, Space>>;
/** @public */
export type PaddingLeft = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingRight = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingTop = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingBottom = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type Padding = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingX = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingY = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginLeft = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginRight = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginTop = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginBottom = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type Margin = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginX = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginY = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export interface SpaceProps {
gap?: Gap;
padding?: Padding;
paddingLeft?: PaddingLeft;
paddingRight?: PaddingRight;
paddingTop?: PaddingTop;
paddingBottom?: PaddingBottom;
paddingX?: PaddingX;
paddingY?: PaddingY;
margin?: Margin;
marginLeft?: MarginLeft;
marginRight?: MarginRight;
marginTop?: MarginTop;
marginBottom?: MarginBottom;
marginX?: MarginX;
marginY?: MarginY;
}
/** @public */
export type Background =
| 'background'
| 'elevation1'
| 'elevation2'
| 'transparent'
| Partial<
Record<Theme, 'background' | 'elevation1' | 'elevation2' | 'transparent'>
>;
/** @public */
export type Color =
| 'primary'
| 'secondary'
| 'error'
| Partial<Record<Theme, 'primary' | 'secondary' | 'error'>>;
/** @public */
export type AsProps =
| 'div'
| 'span'
| 'p'
| 'article'
| 'section'
| 'main'
| 'nav'
| 'aside'
| 'ul'
| 'ol'
| 'li'
| 'details'
| 'summary'
| 'dd'
| 'dl'
| 'dt';
/** @public */
export interface ColorProps {
color?: Color;
background?: Background;
}
+97 -7
View File
@@ -13,11 +13,101 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export interface Breakpoints {
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
/** @public */
export type AsProps =
| 'div'
| 'span'
| 'p'
| 'article'
| 'section'
| 'main'
| 'nav'
| 'aside'
| 'ul'
| 'ol'
| 'li'
| 'details'
| 'summary'
| 'dd'
| 'dl'
| 'dt';
/** @public */
export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
/** @public */
export type Space = 'none' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
/** @public */
export type Display = 'none' | 'flex' | 'block' | 'inline';
/** @public */
export type FlexDirection = 'row' | 'column';
/** @public */
export type FlexWrap = 'wrap' | 'nowrap' | 'wrap-reverse';
/** @public */
export type JustifyContent =
| 'stretch'
| 'start'
| 'center'
| 'end'
| 'around'
| 'between';
/** @public */
export type AlignItems = 'stretch' | 'start' | 'center' | 'end';
/** @public */
export type BorderRadius =
| 'none'
| '2xs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| '2xl';
/** @public */
export type Border = 'none' | 'base' | 'error' | 'warning' | 'selected';
/** @public */
export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 'auto';
/** @public */
export interface SpaceProps {
margin?: Space | Partial<Record<Breakpoint, Space>>;
marginBottom?: Space | Partial<Record<Breakpoint, Space>>;
marginLeft?: Space | Partial<Record<Breakpoint, Space>>;
marginRight?: Space | Partial<Record<Breakpoint, Space>>;
marginTop?: Space | Partial<Record<Breakpoint, Space>>;
marginX?: Space | Partial<Record<Breakpoint, Space>>;
marginY?: Space | Partial<Record<Breakpoint, Space>>;
padding?: Space | Partial<Record<Breakpoint, Space>>;
paddingBottom?: Space | Partial<Record<Breakpoint, Space>>;
paddingLeft?: Space | Partial<Record<Breakpoint, Space>>;
paddingRight?: Space | Partial<Record<Breakpoint, Space>>;
paddingTop?: Space | Partial<Record<Breakpoint, Space>>;
paddingX?: Space | Partial<Record<Breakpoint, Space>>;
paddingY?: Space | Partial<Record<Breakpoint, Space>>;
}
/** @public */
export interface UtilityProps extends SpaceProps {
alignItems?: AlignItems | Partial<Record<Breakpoint, AlignItems>>;
border?: Border | Partial<Record<Breakpoint, Border>>;
borderRadius?: BorderRadius | Partial<Record<Breakpoint, BorderRadius>>;
colEnd?: Columns | 'auto' | Partial<Record<Breakpoint, Columns | 'auto'>>;
colSpan?: Columns | 'full' | Partial<Record<Breakpoint, Columns | 'full'>>;
colStart?: Columns | 'auto' | Partial<Record<Breakpoint, Columns | 'auto'>>;
columns?: Columns | Partial<Record<Breakpoint, Columns>>;
display?: Display | Partial<Record<Breakpoint, Display>>;
flexDirection?: FlexDirection | Partial<Record<Breakpoint, FlexDirection>>;
flexWrap?: FlexWrap | Partial<Record<Breakpoint, FlexWrap>>;
gap?: Space | Partial<Record<Breakpoint, Space>>;
justifyContent?: JustifyContent | Partial<Record<Breakpoint, JustifyContent>>;
rowSpan?: Columns | 'full' | Partial<Record<Breakpoint, Columns | 'full'>>;
}
+206
View File
@@ -0,0 +1,206 @@
/*
* 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 { Breakpoint, UtilityProps } from '../types';
const spaceMap = (type: string) => ({
none: `${type}-none`,
'2xs': `${type}-2xs`,
xs: `${type}-xs`,
sm: `${type}-sm`,
md: `${type}-md`,
lg: `${type}-lg`,
xl: `${type}-xl`,
'2xl': `${type}-2xl`,
});
const valueMap: Record<string, Record<string, string>> = {
alignItems: {
stretch: 'items-stretch',
start: 'items-start',
center: 'items-center',
end: 'items-end',
},
border: {
none: 'border-none',
base: 'border-base',
error: 'border-error',
warning: 'border-warning',
selected: 'border-selected',
},
borderRadius: {
none: 'rounded-none',
'2xs': 'rounded-2xs',
xs: 'rounded-xs',
sm: 'rounded-sm',
md: 'rounded-md',
lg: 'rounded-lg',
xl: 'rounded-xl',
'2xl': 'rounded-2xl',
},
colEnd: {
1: 'col-end-1',
2: 'col-end-2',
3: 'col-end-3',
4: 'col-end-4',
5: 'col-end-5',
6: 'col-end-6',
7: 'col-end-7',
8: 'col-end-8',
9: 'col-end-9',
10: 'col-end-10',
11: 'col-end-11',
12: 'col-end-12',
auto: 'col-end-auto',
},
colSpan: {
1: 'col-span-1',
2: 'col-span-2',
3: 'col-span-3',
4: 'col-span-4',
5: 'col-span-5',
6: 'col-span-6',
7: 'col-span-7',
8: 'col-span-8',
9: 'col-span-9',
10: 'col-span-10',
11: 'col-span-11',
12: 'col-span-12',
auto: 'col-span-auto',
},
colStart: {
1: 'col-start-1',
2: 'col-start-2',
3: 'col-start-3',
4: 'col-start-4',
5: 'col-start-5',
6: 'col-start-6',
7: 'col-start-7',
8: 'col-start-8',
9: 'col-start-9',
10: 'col-start-10',
11: 'col-start-11',
12: 'col-start-12',
auto: 'col-start-auto',
},
columns: {
1: 'grid-cols-1',
2: 'grid-cols-2',
3: 'grid-cols-3',
4: 'grid-cols-4',
5: 'grid-cols-5',
6: 'grid-cols-6',
7: 'grid-cols-7',
8: 'grid-cols-8',
9: 'grid-cols-9',
10: 'grid-cols-10',
11: 'grid-cols-11',
12: 'grid-cols-12',
auto: 'grid-cols-auto',
},
display: {
none: 'hidden',
flex: 'flex',
block: 'block',
inline: 'inline',
},
flexDirection: {
row: 'flex-row',
column: 'flex-col',
},
flexWrap: {
wrap: 'flex-wrap',
nowrap: 'flex-nowrap',
'wrap-reverse': 'flex-wrap-reverse',
},
gap: spaceMap('gap'),
justifyContent: {
stretch: 'justify-stretch',
start: 'justify-start',
center: 'justify-center',
end: 'justify-end',
around: 'justify-around',
between: 'justify-between',
},
margin: spaceMap('m'),
marginBottom: spaceMap('mb'),
marginLeft: spaceMap('ml'),
marginRight: spaceMap('mr'),
marginTop: spaceMap('mt'),
marginX: spaceMap('mx'),
marginY: spaceMap('my'),
padding: spaceMap('p'),
paddingBottom: spaceMap('pb'),
paddingLeft: spaceMap('pl'),
paddingRight: spaceMap('pr'),
paddingTop: spaceMap('pt'),
paddingX: spaceMap('px'),
paddingY: spaceMap('py'),
rowSpan: {
1: 'row-span-1',
2: 'row-span-2',
3: 'row-span-3',
4: 'row-span-4',
5: 'row-span-5',
6: 'row-span-6',
7: 'row-span-7',
8: 'row-span-8',
9: 'row-span-9',
10: 'row-span-10',
11: 'row-span-11',
12: 'row-span-12',
full: 'row-span-full',
},
};
const generateClassNames = (propName: string, propValue: any) => {
const classNames: string[] = [];
// If the property name is not in the valueMap, return an empty array
if (!valueMap.hasOwnProperty(propName)) {
return classNames;
}
if (typeof propValue === 'string' || typeof propValue === 'number') {
// If the property value is a string, map it to the valueMap
const value = valueMap[propName]?.[propValue] || propValue;
classNames.push(`cu-${value}`);
} else if (typeof propValue === 'object') {
// If the property value is an object, map each key-value pair
Object.entries(propValue as Record<Breakpoint, string>).forEach(
([breakpoint, value]) => {
const mappedValue = valueMap[propName]?.[value] || value;
if (breakpoint === 'xs') {
classNames.push(`cu-${mappedValue}`);
} else {
classNames.push(`cu-${breakpoint}-${mappedValue}`);
}
},
);
}
return classNames;
};
export const getClassNames = (props: UtilityProps) => {
const classNames: string[] = [];
Object.entries(props).forEach(([propName, propValue]) => {
classNames.push(...generateClassNames(propName, propValue));
});
return classNames.filter(Boolean).join(' ');
};
@@ -28,16 +28,12 @@ import {
textPlaceholderResolver,
yamlPlaceholderResolver,
} from './PlaceholderProcessor';
import { UrlReaderService } from '@backstage/backend-plugin-api';
import { mockServices } from '@backstage/backend-test-utils';
const integrations = ScmIntegrations.fromConfig(new ConfigReader({}));
describe('PlaceholderProcessor', () => {
const reader: jest.Mocked<UrlReaderService> = {
readTree: jest.fn(),
search: jest.fn(),
readUrl: jest.fn(),
};
const reader = mockServices.urlReader.mock();
beforeEach(() => {
jest.resetAllMocks();
@@ -31,7 +31,6 @@ import {
import { defaultEntityDataParser } from '../util/parse';
import { UrlReaderProcessor } from './UrlReaderProcessor';
import { UrlReaders } from '@backstage/backend-defaults/urlReader';
import { UrlReaderService } from '@backstage/backend-plugin-api';
describe('UrlReaderProcessor', () => {
const mockApiOrigin = 'http://localhost';
@@ -193,11 +192,9 @@ describe('UrlReaderProcessor', () => {
it('uses search when there are globs', async () => {
const logger = mockServices.logger.mock();
const reader: jest.Mocked<UrlReaderService> = {
readUrl: jest.fn(),
readTree: jest.fn(),
search: jest.fn().mockImplementation(async () => []),
};
const reader = mockServices.urlReader.mock({
search: jest.fn().mockResolvedValue([]),
});
const processor = new UrlReaderProcessor({ reader, logger });
@@ -42,7 +42,6 @@ import { wrapServer } from '@backstage/backend-openapi-utils';
import { Server } from 'http';
import { mockCredentials, mockServices } from '@backstage/backend-test-utils';
import { LocationAnalyzer } from '@backstage/plugin-catalog-node';
import { PermissionsService } from '@backstage/backend-plugin-api';
describe('createRouter readonly disabled', () => {
let entitiesCatalog: jest.Mocked<EntitiesCatalog>;
@@ -51,7 +50,7 @@ describe('createRouter readonly disabled', () => {
let app: express.Express | Server;
let refreshService: RefreshService;
let locationAnalyzer: jest.Mocked<LocationAnalyzer>;
let permissionsService: jest.Mocked<PermissionsService>;
const permissionsService = mockServices.permissions.mock();
beforeEach(async () => {
entitiesCatalog = {
@@ -69,15 +68,9 @@ describe('createRouter readonly disabled', () => {
deleteLocation: jest.fn(),
getLocationByEntity: jest.fn(),
};
locationAnalyzer = {
analyzeLocation: jest.fn(),
};
permissionsService = {
authorize: jest.fn(),
authorizeConditional: jest.fn(),
};
refreshService = { refresh: jest.fn() };
orchestrator = { process: jest.fn() };
const router = await createRouter({
@@ -91,13 +84,13 @@ describe('createRouter readonly disabled', () => {
auth: mockServices.auth(),
httpAuth: mockServices.httpAuth(),
locationAnalyzer,
permissionsService: permissionsService,
permissionsService,
});
app = await wrapServer(express().use(router));
});
beforeEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
describe('POST /refresh', () => {
@@ -158,7 +151,7 @@ describe('createRouter readonly disabled', () => {
auth: mockServices.auth(),
httpAuth: mockServices.httpAuth(),
locationAnalyzer,
permissionsService: permissionsService,
permissionsService,
disableRelationsCompatibility: true, // added
});
app = await wrapServer(express().use(router));
@@ -218,7 +211,7 @@ describe('createRouter readonly disabled', () => {
auth: mockServices.auth(),
httpAuth: mockServices.httpAuth(),
locationAnalyzer,
permissionsService: permissionsService,
permissionsService,
disableRelationsCompatibility: true, // added
});
app = await wrapServer(express().use(router));
@@ -939,7 +932,7 @@ describe('createRouter readonly and raw json enabled', () => {
let entitiesCatalog: jest.Mocked<EntitiesCatalog>;
let app: express.Express;
let locationService: jest.Mocked<LocationService>;
let permissionsService: jest.Mocked<PermissionsService>;
const permissionsService = mockServices.permissions.mock();
beforeAll(async () => {
entitiesCatalog = {
@@ -970,13 +963,13 @@ describe('createRouter readonly and raw json enabled', () => {
permissionIntegrationRouter: express.Router(),
auth: mockServices.auth(),
httpAuth: mockServices.httpAuth(),
permissionsService: permissionsService,
permissionsService,
});
app = express().use(router);
});
beforeEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
describe('GET /entities', () => {
@@ -1141,7 +1134,7 @@ describe('NextRouter permissioning', () => {
let locationService: jest.Mocked<LocationService>;
let app: express.Express;
let refreshService: RefreshService;
let permissionsService: jest.Mocked<PermissionsService>;
const permissionsService = mockServices.permissions.mock();
const fakeRule = createPermissionRule({
name: 'FAKE_RULE',
@@ -1188,13 +1181,13 @@ describe('NextRouter permissioning', () => {
}),
auth: mockServices.auth(),
httpAuth: mockServices.httpAuth(),
permissionsService: permissionsService,
permissionsService,
});
app = express().use(router);
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
it('accepts and evaluates conditions at the apply-conditions endpoint', async () => {
@@ -23,10 +23,7 @@ import {
registerMswTestHooks,
} from '@backstage/backend-test-utils';
import { NotFoundError } from '@backstage/errors';
import {
AuthorizeResult,
PermissionEvaluator,
} from '@backstage/plugin-permission-common';
import { AuthorizeResult } from '@backstage/plugin-permission-common';
import {
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
KubernetesRequestAuth,
@@ -55,10 +52,7 @@ import {
} from './KubernetesProxy';
import type { Request } from 'express';
import {
BackstageCredentials,
DiscoveryService,
} from '@backstage/backend-plugin-api';
import { BackstageCredentials } from '@backstage/backend-plugin-api';
const mockCertDir = createMockDirectory({
content: {
@@ -79,15 +73,8 @@ describe('KubernetesProxy', () => {
>(),
};
const permissionApi: jest.Mocked<PermissionEvaluator> = {
authorize: jest.fn(),
authorizeConditional: jest.fn(),
};
const mockDisocveryApi: jest.Mocked<DiscoveryService> = {
getBaseUrl: jest.fn(),
getExternalBaseUrl: jest.fn(),
};
const permissionApi = mockServices.permissions.mock();
const mockDisocveryApi = mockServices.discovery.mock();
registerMswTestHooks(worker);
+7 -3
View File
@@ -20,13 +20,13 @@ import {
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { notificationService } from '@backstage/plugin-notifications-node';
import { errorHandler } from '@backstage/backend-common';
import {
notificationSeverities,
NotificationSeverity,
} from '@backstage/plugin-notifications-common';
import express, { Response } from 'express';
import Router from 'express-promise-router';
import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';
const randomSeverity = (): NotificationSeverity => {
return notificationSeverities[
@@ -77,8 +77,12 @@ const notificationsDebug = createBackendPlugin({
deps: {
notifications: notificationService,
httpRouter: coreServices.httpRouter,
config: coreServices.rootConfig,
logger: coreServices.logger,
},
async init({ notifications, httpRouter }) {
async init({ notifications, httpRouter, config, logger }) {
const middleware = MiddlewareFactory.create({ config, logger });
const router = Router();
router.use(express.json());
router.post('/', async (_, res: Response<unknown>) => {
@@ -96,7 +100,7 @@ const notificationsDebug = createBackendPlugin({
});
res.status(200).send({ status: 'ok' });
});
router.use(errorHandler());
router.use(middleware.error());
httpRouter.use(router);
httpRouter.addAuthPolicy({
@@ -38,7 +38,6 @@
"test": "backstage-cli package test"
},
"dependencies": {
"@backstage/backend-common": "^0.25.0",
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/catalog-client": "workspace:^",
"@backstage/catalog-model": "workspace:^",
@@ -14,16 +14,12 @@
* limitations under the License.
*/
import {
DatabaseManager,
PluginDatabaseManager,
} from '@backstage/backend-common';
import express from 'express';
import request from 'supertest';
import { createRouter } from './router';
import { ConfigReader } from '@backstage/config';
import { SignalsService } from '@backstage/plugin-signals-node';
import {
TestDatabases,
mockCredentials,
mockErrorHandler,
mockServices,
@@ -31,20 +27,9 @@ import {
import { NotificationSendOptions } from '@backstage/plugin-notifications-node';
import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils';
function createDatabase(): PluginDatabaseManager {
return DatabaseManager.fromConfig(
new ConfigReader({
backend: {
database: {
client: 'better-sqlite3',
connection: ':memory:',
},
},
}),
).forPlugin('notifications');
}
describe('createRouter', () => {
const databases = TestDatabases.create();
let app: express.Express;
const signalService: jest.Mocked<SignalsService> = {
@@ -62,9 +47,10 @@ describe('createRouter', () => {
const catalog = catalogServiceMock();
beforeAll(async () => {
const knex = await databases.init('SQLITE_3');
const router = await createRouter({
logger: mockServices.logger.mock(),
database: createDatabase(),
database: { getClient: async () => knex },
signals: signalService,
userInfo,
config,
@@ -14,17 +14,13 @@
* limitations under the License.
*/
import { registerMswTestHooks } from '@backstage/backend-test-utils';
import { mockServices } from '@backstage/backend-test-utils';
import { Entity } from '@backstage/catalog-model';
import { ConfigReader } from '@backstage/config';
import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils';
import { TestPipeline } from '@backstage/plugin-search-backend-node';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { Readable } from 'stream';
import { DefaultCatalogCollatorFactory } from './DefaultCatalogCollatorFactory';
import { DiscoveryService } from '@backstage/backend-plugin-api';
const server = setupServer();
const expectedEntities: Entity[] = [
{
@@ -57,44 +53,21 @@ const expectedEntities: Entity[] = [
];
describe('DefaultCatalogCollatorFactory', () => {
const config = new ConfigReader({});
const mockDiscoveryApi: jest.Mocked<DiscoveryService> = {
getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007'),
getExternalBaseUrl: jest.fn(),
};
const options = {
discovery: mockDiscoveryApi,
};
registerMswTestHooks(server);
beforeEach(() => {
server.use(
rest.get('http://localhost:7007/entities', (req, res, ctx) => {
if (req.url.searchParams.has('filter')) {
const filter = req.url.searchParams.get('filter');
if (filter === 'kind=Foo,kind=Bar') {
// When filtering on the 'Foo,Bar' kinds we simply return no items, to simulate a filter
return res(ctx.json([]));
}
throw new Error('Unexpected filter parameter');
}
// Imitate offset/limit pagination.
const offset = parseInt(req.url.searchParams.get('offset') || '0', 10);
const limit = parseInt(req.url.searchParams.get('limit') || '500', 10);
return res(ctx.json(expectedEntities.slice(offset, limit + offset)));
}),
);
const config = mockServices.rootConfig();
const discovery = mockServices.discovery.mock({
getBaseUrl: async () => 'http://localhost:7007',
});
const catalog = catalogServiceMock({ entities: expectedEntities });
describe('getCollator', () => {
let factory: DefaultCatalogCollatorFactory;
let collator: Readable;
beforeEach(async () => {
factory = DefaultCatalogCollatorFactory.fromConfig(config, options);
factory = DefaultCatalogCollatorFactory.fromConfig(config, {
discovery,
catalogClient: catalog,
});
collator = await factory.getCollator();
});
@@ -105,7 +78,6 @@ describe('DefaultCatalogCollatorFactory', () => {
it('fetches from the configured catalog service', async () => {
const pipeline = TestPipeline.fromCollator(collator);
const { documents } = await pipeline.execute();
expect(mockDiscoveryApi.getBaseUrl).toHaveBeenCalledWith('catalog');
expect(documents).toHaveLength(expectedEntities.length);
});
@@ -145,7 +117,8 @@ describe('DefaultCatalogCollatorFactory', () => {
it('maps a returned entity to an expected CatalogEntityDocument with custom transformer', async () => {
const customFactory = DefaultCatalogCollatorFactory.fromConfig(config, {
...options,
discovery,
catalogClient: catalog,
entityTransformer: entity => ({
title: `custom-title-${
entity.metadata.title ?? entity.metadata.name
@@ -201,7 +174,8 @@ describe('DefaultCatalogCollatorFactory', () => {
it('maps a returned entity with a custom locationTemplate', async () => {
// Provide an alternate location template.
factory = DefaultCatalogCollatorFactory.fromConfig(new ConfigReader({}), {
discovery: mockDiscoveryApi,
discovery: discovery,
catalogClient: catalog,
locationTemplate: '/software/:name',
});
collator = await factory.getCollator();
@@ -216,7 +190,8 @@ describe('DefaultCatalogCollatorFactory', () => {
it('allows filtering of the retrieved catalog entities', async () => {
// Provide a custom filter.
factory = DefaultCatalogCollatorFactory.fromConfig(new ConfigReader({}), {
discovery: mockDiscoveryApi,
discovery: discovery,
catalogClient: catalog,
filter: {
kind: ['Foo', 'Bar'],
},
@@ -232,7 +207,8 @@ describe('DefaultCatalogCollatorFactory', () => {
it('paginates through catalog entities using batchSize', async () => {
factory = DefaultCatalogCollatorFactory.fromConfig(config, {
...options,
discovery,
catalogClient: catalog,
batchSize: 1,
});
collator = await factory.getCollator();
@@ -18,6 +18,7 @@ import {
TokenManager,
createLegacyAuthAdapters,
} from '@backstage/backend-common';
import { AuthService, DiscoveryService } from '@backstage/backend-plugin-api';
import {
CatalogApi,
CatalogClient,
@@ -33,7 +34,6 @@ import { Readable } from 'stream';
import { CatalogCollatorEntityTransformer } from './CatalogCollatorEntityTransformer';
import { readCollatorConfigOptions } from './config';
import { defaultCatalogCollatorEntityTransformer } from './defaultCatalogCollatorEntityTransformer';
import { AuthService, DiscoveryService } from '@backstage/backend-plugin-api';
/**
* @public
@@ -55,6 +55,7 @@ export type DefaultCatalogCollatorFactoryOptions = {
* @deprecated Use the config key `search.collators.catalog.batchSize` instead.
*/
batchSize?: number;
// TODO(freben): Change to required CatalogService instead when fully migrated to the new backend system.
catalogClient?: CatalogApi;
/**
* Allows you to customize how entities are shaped into documents.
@@ -137,32 +138,25 @@ export class DefaultCatalogCollatorFactory implements DocumentCollatorFactory {
private async *execute(): AsyncGenerator<CatalogEntityDocument> {
let entitiesRetrieved = 0;
let moreEntitiesToGet = true;
let cursor: string | undefined = undefined;
// Offset/limit pagination is used on the Catalog Client in order to
// limit (and allow some control over) memory used by the search backend
// at index-time.
while (moreEntitiesToGet) {
do {
const { token } = await this.auth.getPluginRequestToken({
onBehalfOf: await this.auth.getOwnServiceCredentials(),
targetPluginId: 'catalog',
});
const entities = (
await this.catalogClient.getEntities(
{
filter: this.filter,
limit: this.batchSize,
offset: entitiesRetrieved,
},
{ token },
)
).items;
const response = await this.catalogClient.queryEntities(
{
filter: this.filter,
limit: this.batchSize,
...(cursor ? { cursor } : {}),
},
{ token },
);
cursor = response.pageInfo.nextCursor;
entitiesRetrieved += response.items.length;
// Control looping through entity batches.
moreEntitiesToGet = entities.length === this.batchSize;
entitiesRetrieved += entities.length;
for (const entity of entities) {
for (const entity of response.items) {
yield {
...this.entityTransformer(entity),
authorization: {
@@ -175,7 +169,7 @@ export class DefaultCatalogCollatorFactory implements DocumentCollatorFactory {
}),
};
}
}
} while (cursor);
}
private applyArgsToFormat(
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ConfigReader } from '@backstage/config';
import { TestPipeline } from '@backstage/plugin-search-backend-node';
import {
mockServices,
@@ -23,7 +23,6 @@ import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { Readable } from 'stream';
import { ToolDocumentCollatorFactory } from './ToolDocumentCollatorFactory';
import { DiscoveryService } from '@backstage/backend-plugin-api';
const logger = mockServices.logger.mock();
@@ -54,11 +53,10 @@ const mockTools = {
};
describe('ToolDocumentCollatorFactory', () => {
const config = new ConfigReader({});
const mockDiscoveryApi: jest.Mocked<DiscoveryService> = {
getBaseUrl: jest.fn().mockResolvedValue('http://test-backend/api/explore'),
getExternalBaseUrl: jest.fn(),
};
const config = mockServices.rootConfig();
const mockDiscoveryApi = mockServices.discovery.mock({
getBaseUrl: async () => 'http://test-backend/api/explore',
});
const options = {
discovery: mockDiscoveryApi,
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
import { ConfigReader } from '@backstage/config';
import { TestPipeline } from '@backstage/plugin-search-backend-node';
@@ -25,7 +26,6 @@ import { setupServer } from 'msw/node';
import { Readable } from 'stream';
import { DefaultTechDocsCollatorFactory } from './DefaultTechDocsCollatorFactory';
import { TechDocsCollatorEntityTransformer } from './TechDocsCollatorEntityTransformer';
import { DiscoveryService } from '@backstage/backend-plugin-api';
import {
MkSearchIndexDoc,
TechDocsCollatorDocumentTransformer,
@@ -81,11 +81,10 @@ const expectedEntities: Entity[] = [
];
describe('DefaultTechDocsCollatorFactory', () => {
const config = new ConfigReader({});
const mockDiscoveryApi: jest.Mocked<DiscoveryService> = {
getBaseUrl: jest.fn().mockResolvedValue('http://test-backend'),
getExternalBaseUrl: jest.fn(),
};
const config = mockServices.rootConfig.mock();
const mockDiscoveryApi = mockServices.discovery.mock({
getBaseUrl: async () => 'http://test-backend',
});
const options = {
logger,
discovery: mockDiscoveryApi,
@@ -18,27 +18,14 @@ import express from 'express';
import request from 'supertest';
import { createRouter } from './router';
import { EventsService } from '@backstage/plugin-events-node';
import {
DiscoveryService,
UserInfoService,
} from '@backstage/backend-plugin-api';
import { ConfigReader } from '@backstage/config';
import { mockErrorHandler, mockServices } from '@backstage/backend-test-utils';
const eventsServiceMock: jest.Mocked<EventsService> = {
subscribe: jest.fn(),
publish: jest.fn(),
};
const discovery: jest.Mocked<DiscoveryService> = {
getBaseUrl: jest.fn().mockResolvedValue('/api/signals'),
getExternalBaseUrl: jest.fn(),
};
const userInfo: jest.Mocked<UserInfoService> = {
getUserInfo: jest.fn(),
};
const eventsServiceMock = mockServices.events.mock();
const discovery = mockServices.discovery.mock({
getBaseUrl: async () => '/api/signals',
});
const userInfo = mockServices.userInfo.mock();
describe('createRouter', () => {
let app: express.Express;

Some files were not shown because too many files have changed in this diff Show More