@stealthscale/component-surfaces 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/cyclonedx/bom.json +1 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.js +124 -0
- package/dist/recipe-BSMN8WoK.js +511 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/theme.d.ts +11 -0
- package/dist/theme.js +16 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stealth Scale B.V.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @stealthscale/component-surfaces
|
|
2
|
+
|
|
3
|
+
Renders the surfaces a page is built from.
|
|
4
|
+
|
|
5
|
+
Every value a theme can change is an axis of a component's recipe, so set it as a prop and write no
|
|
6
|
+
style. Change the element a component renders with `as`. A component with parts is published as a
|
|
7
|
+
namespace, `Card.Root`.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @stealthscale/component-surfaces
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The package peers on `react` and `@stealthscale/theme`. List the preset under `./theme` among the
|
|
16
|
+
presets your compiler installs.
|
|
17
|
+
|
|
18
|
+
## Card
|
|
19
|
+
|
|
20
|
+
A card stacks a picture, a header, content or sections, and a footer of controls on one panel.
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { Button, IconButton } from "@stealthscale/component-actions";
|
|
24
|
+
import { Card } from "@stealthscale/component-surfaces";
|
|
25
|
+
import { EllipsisIcon, ReceiptTextIcon } from "lucide-react";
|
|
26
|
+
|
|
27
|
+
<Card.Root aria-labelledby="invoice-4821">
|
|
28
|
+
<Card.Header>
|
|
29
|
+
<Card.Indicator>
|
|
30
|
+
<ReceiptTextIcon aria-hidden />
|
|
31
|
+
</Card.Indicator>
|
|
32
|
+
<Card.Title id="invoice-4821">Invoice 4821</Card.Title>
|
|
33
|
+
<Card.Description>Issued on 2 September</Card.Description>
|
|
34
|
+
<Card.Aside>
|
|
35
|
+
<IconButton aria-label="More actions for invoice 4821" size="sm" variant="ghost">
|
|
36
|
+
<EllipsisIcon aria-hidden />
|
|
37
|
+
</IconButton>
|
|
38
|
+
</Card.Aside>
|
|
39
|
+
</Card.Header>
|
|
40
|
+
<Card.Content>Three lines, one unbilled.</Card.Content>
|
|
41
|
+
<Card.Footer>
|
|
42
|
+
<Button size="sm">Send</Button>
|
|
43
|
+
</Card.Footer>
|
|
44
|
+
</Card.Root>;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
| Part | Element | What it renders |
|
|
48
|
+
| ------------- | --------- | ------------------------------------------------------------------------- |
|
|
49
|
+
| `Root` | `article` | The panel. It resolves every variant |
|
|
50
|
+
| `Media` | `div` | A picture that extends to the card's edges |
|
|
51
|
+
| `Overlay` | `div` | A layer over the picture, inside `Media`, for a badge or a caption |
|
|
52
|
+
| `Header` | `div` | A three-column grid: indicator, title over description, aside |
|
|
53
|
+
| `Indicator` | `div` | An icon or an avatar image at the start of the header |
|
|
54
|
+
| `Title` | `h3` | The card's heading |
|
|
55
|
+
| `Description` | `p` | The line under the title |
|
|
56
|
+
| `Aside` | `div` | A control or a badge at the end of the header |
|
|
57
|
+
| `Content` | `div` | The body, which takes the height the other bands leave |
|
|
58
|
+
| `Section` | `div` | A band that extends to the side edges, with a rule to each band beside it |
|
|
59
|
+
| `Footer` | `div` | The controls |
|
|
60
|
+
|
|
61
|
+
| Axis | Values | Default |
|
|
62
|
+
| ------------- | ---------------------------------------------------------------------------------- | ---------- |
|
|
63
|
+
| `variant` | `elevated`, `outline`, `subtle`, `glass`, `plain` | `elevated` |
|
|
64
|
+
| `palette` | `primary`, `secondary`, `accent`, `neutral`, `info`, `success`, `warning`, `error` | none |
|
|
65
|
+
| `size` | `sm`, `md`, `lg`, `xl` | `md` |
|
|
66
|
+
| `radius` | the theme's corner radii | `l2` |
|
|
67
|
+
| `orientation` | `vertical`, `horizontal` | `vertical` |
|
|
68
|
+
| `scrim` | `true` | off |
|
|
69
|
+
| `divided` | `true` | off |
|
|
70
|
+
| `justify` | `start`, `center`, `end`, `between`, `around`, `evenly` | `end` |
|
|
71
|
+
| `interactive` | `true` | off |
|
|
72
|
+
| `disabled` | `true` | off |
|
|
73
|
+
| `effect` | `glow` | none |
|
|
74
|
+
| `motion` | `fade`, `rise`, `reveal` | none |
|
|
75
|
+
|
|
76
|
+
### Name the card
|
|
77
|
+
|
|
78
|
+
Point `aria-labelledby` at the title's `id`, or pass `aria-label`. Pass `as="div"` for a card that
|
|
79
|
+
is part of its surroundings and does not need a name.
|
|
80
|
+
|
|
81
|
+
### Header
|
|
82
|
+
|
|
83
|
+
Put the indicator, the title, the description and the aside directly in `Card.Header`. The indicator
|
|
84
|
+
and the aside are centred on the title and description rows. An `img` in the indicator renders as a
|
|
85
|
+
round avatar of 32 to 56px by size, and an `svg` placed directly in it takes the icon size of the
|
|
86
|
+
card's size.
|
|
87
|
+
|
|
88
|
+
### Pictures
|
|
89
|
+
|
|
90
|
+
Put the picture in `Card.Media` with its alternative text, or `alt=""` when it is decorative. In a
|
|
91
|
+
vertical card the picture extends to both side edges, to the top edge as the first band, and to the
|
|
92
|
+
bottom edge as the last. In a horizontal card it covers the leading third at the card's full height.
|
|
93
|
+
|
|
94
|
+
Put a badge or a caption over the picture in `Card.Overlay`, after the image. Set `scrim` on the
|
|
95
|
+
root when the overlay contains text. It darkens the lower half of the picture and renders the
|
|
96
|
+
overlay in the dark color scheme.
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
<Card.Root scrim>
|
|
100
|
+
<Card.Media>
|
|
101
|
+
<img alt="" src={cover} />
|
|
102
|
+
<Card.Overlay>
|
|
103
|
+
<Badge variant="solid">Engineering</Badge>
|
|
104
|
+
<Text size="sm">6 min read</Text>
|
|
105
|
+
</Card.Overlay>
|
|
106
|
+
</Card.Media>
|
|
107
|
+
<Card.Header>
|
|
108
|
+
<Card.Title>How we settle payouts in two days</Card.Title>
|
|
109
|
+
</Card.Header>
|
|
110
|
+
</Card.Root>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Sections
|
|
114
|
+
|
|
115
|
+
Use `Card.Section` for rows of settings, a list of features or a summary. A section extends to the
|
|
116
|
+
card's side edges and keeps its content at the card's inset, so its text is aligned with the header.
|
|
117
|
+
It renders a hairline between itself and each band beside it, and two adjacent sections share one
|
|
118
|
+
rule. Each rule spans the card's full width with the inset above and below it. `divided` renders the
|
|
119
|
+
rules under the header and above the footer the same way.
|
|
120
|
+
|
|
121
|
+
### Interactive cards
|
|
122
|
+
|
|
123
|
+
Set `interactive` and put a link in the title. The link's hit area covers the whole card, and the
|
|
124
|
+
link keeps the focus and the accessible name. Other links and buttons in the card take their own
|
|
125
|
+
clicks. Do not put a click handler or a `tabindex` on the root, and do not put a second link in the
|
|
126
|
+
title.
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<Card.Root interactive>
|
|
130
|
+
<Card.Header>
|
|
131
|
+
<Card.Title>
|
|
132
|
+
<Link href="/invoices/4821">Invoice 4821</Link>
|
|
133
|
+
</Card.Title>
|
|
134
|
+
</Card.Header>
|
|
135
|
+
</Card.Root>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Set `disabled` to render the card at the disabled opacity with no pointer events. The root sets
|
|
139
|
+
`aria-disabled`. The styles do not remove the title's link from the tab order, so render the title
|
|
140
|
+
without the link, or give the link `aria-disabled` and no `href`.
|
|
141
|
+
|
|
142
|
+
### Palettes
|
|
143
|
+
|
|
144
|
+
`palette` sets the palette of the focus ring and the glow. An `outline` card also sets its border to
|
|
145
|
+
the palette, and a `subtle` card fills with the palette's subtle color. The stylesheet contains
|
|
146
|
+
every palette whether a page uses it, so a value set at runtime has a class.
|
|
147
|
+
|
|
148
|
+
## Licence
|
|
149
|
+
|
|
150
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"http://cyclonedx.org/schema/bom-1.7.schema.json","bomFormat":"CycloneDX","specVersion":"1.7","version":1,"metadata":{"lifecycles":[{"phase":"build"}],"tools":{"components":[{"type":"application","name":"rolldown","version":"1.2.11"},{"type":"application","name":"vite","version":"8.3.1"},{"type":"library","name":"core","group":"@arethetypeswrong","version":"0.18.5","bom-ref":"pkg:npm/%40arethetypeswrong/core@0.18.5","author":"Andrew Branch","description":"The API behind arethetypeswrong.github.io","hashes":[{"alg":"SHA-512","content":"f72b63cc6c318e6f54cfb23d6af7dbb79be542deae93db914444b3263aabce797a58abc8e9dc184e8faf277534d96aeafe64778aa97f3f386f1e129d2480230d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40arethetypeswrong/core@0.18.5","externalReferences":[{"url":"https://github.com/arethetypeswrong/arethetypeswrong.github.io.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20"}]},{"type":"library","name":"component-actions","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/component-actions@0.1.0","description":"Renders what a person presses: a button, a toggle group, a swap, a color mode toggle, a clipboard and a download trigger.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/component-actions@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#components/actions","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/components/actions#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"component-navigation","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/component-navigation@0.1.0","description":"Draws the ways a person moves between places: links, tabs, breadcrumbs and rails.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/component-navigation@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#components/navigation","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/components/navigation#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"theme","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/theme@0.3.0","description":"Publishes the foundation every recipe is written against, the runtime every component binds its recipe with, and the vocabulary a theme is written in.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/theme@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#foundations/theme","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/foundations/theme#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-i18n","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-i18n@0.1.0","description":"Configures a package or an application with words: the catalogue plugin, and the words in scope for its specifications.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-i18n@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-i18n","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-i18n#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-react","group":"@stealthscale","version":"0.8.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-react@0.8.0","description":"Adds the JSX transform, the React lint rules, a test document and an MDX compiler to a package that renders.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-react@0.8.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-react#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-specimen","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-specimen@0.1.0","description":"Configures an application that shows a catalogue, and the workspace root the specimens sit under.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-specimen@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-specimen","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-specimen#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-theme","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-theme@0.1.0","description":"Adds the runtime generator to a design-system package and the stylesheet compiler to an application.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-theme@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-theme","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-theme#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-typescript","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","description":"Sets the TypeScript options every stealthscale package compiles with.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config-typescript","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config-typescript#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config","group":"@stealthscale","version":"0.6.0","bom-ref":"pkg:npm/%40stealthscale/vite-config@0.6.0","description":"Configures a package from five Vite+ tiers and a named layer for every block.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config@0.6.0","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#packages/vite-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/packages/vite-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"react","group":"@testing-library","version":"16.3.3","bom-ref":"pkg:npm/%40testing-library/react@16.3.3","author":"Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)","description":"Simple and complete React DOM testing utilities that encourage good testing practices.","hashes":[{"alg":"SHA-512","content":"528d7ddcd8106cf333ea5aeb86d45040570c0ba45efc42cb15b6ee54bdf4583959c65a597fdfe53074c05713d12f0d6ad62bbd389991d5cd812e210d46cb5d06"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40testing-library/react@16.3.3","externalReferences":[{"url":"https://github.com/testing-library/react-testing-library/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/testing-library/react-testing-library","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://github.com/testing-library/react-testing-library#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=18"}]},{"type":"library","name":"react-dom","group":"@types","version":"19.3.0","bom-ref":"pkg:npm/%40types/react-dom@19.3.0","description":"TypeScript definitions for react-dom","hashes":[{"alg":"SHA-512","content":"648edb538da66575ca1e7fea34b130d88adb888354ed7e7ebdf81d8b10479023696165e32a07d0fcffaec866f90a338b07d51c9d37a0debca542d5768729b8e1"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/react-dom@19.3.0","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/react-dom","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"react","group":"@types","version":"19.3.0","bom-ref":"pkg:npm/%40types/react@19.3.0","description":"TypeScript definitions for react","hashes":[{"alg":"SHA-512","content":"374ac50ae1fd628c46f7f9bad65f4c7e924a7e62ce554d1e9bb8a9233e9346049292f45e2c1f6f2fce4607ecabf01b3995eaa9be0f7a252c05e194b5b38be242"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/react@19.3.0","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"happy-dom","version":"20.14.5","bom-ref":"pkg:npm/happy-dom@20.14.5","author":"David Ortner","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.","hashes":[{"alg":"SHA-512","content":"c7f47392958ee346d38c8a13df4890b6deb814b2e61ff89171408dd97fff6cbc7b1f789f91d7cf5f2aacae8fce62dab32008622cc300ee69a2391f42dcd38a8d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/happy-dom@20.14.5","externalReferences":[{"url":"https://github.com/capricorn86/happy-dom","type":"vcs","comment":"as detected from PackageJson property \"repository\""},{"url":"https://github.com/capricorn86/happy-dom","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20.0.0"}]},{"type":"library","name":"lucide-react","version":"1.48.0","bom-ref":"pkg:npm/lucide-react@1.48.0","author":"Eric Fennis","description":"A Lucide icon library package for React applications.","hashes":[{"alg":"SHA-512","content":"474088298fdf5e20bacbdc510400e0b0af955b6a7fa5c4c938c84b65fd53fae1bebc952fc94474da718e8262080bb30f92234ae0ec7c4039dba85f2b25858f65"}],"licenses":[{"license":{"id":"ISC"}}],"purl":"pkg:npm/lucide-react@1.48.0","externalReferences":[{"url":"https://github.com/lucide-icons/lucide/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"https://github.com/lucide-icons/lucide.git#packages/lucide-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://lucide.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"oxc-transform-react","version":"0.151.0","bom-ref":"pkg:npm/oxc-transform-react@0.151.0","author":"Boshen and oxc contributors","description":"Oxc React Compiler Node API","hashes":[{"alg":"SHA-512","content":"60ed7f62cdc5202fee060ca37b1bc6b084d05085c318d9b1272eafa906ddf1663b263ccc0f5faf095879f65cdaf7f3f4dbf4d135a517c94eceaf6c70c7f29b77"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/oxc-transform-react@0.151.0","externalReferences":[{"url":"https://github.com/oxc-project/oxc/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/oxc-project/oxc.git#napi/transform-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://oxc.rs","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^20.19.0 || >=22.12.0"}]},{"type":"library","name":"react-dom","version":"19.3.0","bom-ref":"pkg:npm/react-dom@19.3.0","description":"React package for working with the DOM.","hashes":[{"alg":"SHA-512","content":"24393c76089fe753a31680c4ef4f8e4fd202c98afeebd1e59a284dc29d7e36c7db9dadede6c22209af59264b43990e3fd5bfeb9f6ea1200476b985c332be6bd1"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/react-dom@19.3.0","externalReferences":[{"url":"https://github.com/react/react/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/react/react.git#packages/react-dom","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://react.dev/","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"react","version":"19.3.0","bom-ref":"pkg:npm/react@19.3.0","description":"React is a JavaScript library for building user interfaces.","hashes":[{"alg":"SHA-512","content":"13c2d471bb415addb46db9766281dfc7864305dc554df38ab42667f5c0d227897afe7ba8029729201723e3bb76c19a155fc836647b8c1db892860091d53e52a2"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/react@19.3.0","externalReferences":[{"url":"https://github.com/react/react/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"https://github.com/react/react.git#packages/react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://react.dev/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=0.10.0"}]},{"type":"library","name":"typescript","version":"7.0.2","bom-ref":"pkg:npm/typescript@7.0.2","author":"Microsoft Corp.","description":"TypeScript is a language for application scale JavaScript development","hashes":[{"alg":"SHA-512","content":"f0561abbdea8dcd28e85b8ca8bfa8dbc6fd6e63873c646dd9b9b23f406d9ff94f9b16aa7de12602df1b1dbbb11299593bf2cc23fc74b4414dfe6d05349155434"}],"licenses":[{"license":{"id":"Apache-2.0"}}],"purl":"pkg:npm/typescript@7.0.2","externalReferences":[{"url":"https://github.com/microsoft/TypeScript/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/microsoft/TypeScript.git","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://www.typescriptlang.org/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=16.20.0"}]},{"type":"library","name":"vitest","version":"5.0.1","bom-ref":"pkg:npm/vitest@5.0.1","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"Next generation testing framework powered by Vite","hashes":[{"alg":"SHA-512","content":"880f799506ca124bebb5391d0209d66d77db8a95a28967bf8439763f9b4c8ba585c03efa1b43715c01a9fccf4439c62ea5e18946beb0a6931cec2a00e354d08e"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/vitest@5.0.1","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/vitest","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^22.12.0 || ^24.0.0 || >=26.0.0"}]}]},"component":{"type":"library","name":"component-surfaces","group":"@stealthscale","version":"0.0.1","bom-ref":"pkg:npm/%40stealthscale/component-surfaces@0.0.1","description":"Draws the surface under a thing, and the rule between two of them.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/component-surfaces@0.0.1","externalReferences":[{"url":"https://github.com/stealth-scale/scale/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/scale.git#components/surfaces","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/scale/tree/main/components/surfaces#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}],"evidence":{"licenses":[{"license":{"name":"file: LICENSE","text":{"content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNiBTdGVhbHRoIFNjYWxlIEIuVi4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==","contentType":"text/plain","encoding":"base64"}}}]}},"supplier":{"name":"Stealth Scale B.V.","url":["https://stealthscale.io"]}},"components":[],"dependencies":[{"ref":"pkg:npm/%40stealthscale/component-surfaces@0.0.1"}]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import "@stealthscale/theme/authoring";
|
|
2
|
+
import { ComponentProps, ReactElement } from "react";
|
|
3
|
+
//#region src/card/aside.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Renders the aside slot at the end of the header.
|
|
6
|
+
*/
|
|
7
|
+
declare const Aside: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
8
|
+
/**
|
|
9
|
+
* Describes the props of `Aside`: the props of a `div`.
|
|
10
|
+
*/
|
|
11
|
+
type AsideProps = ComponentProps<typeof Aside>;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/card/content.d.ts
|
|
14
|
+
/**
|
|
15
|
+
* Renders the content slot.
|
|
16
|
+
*/
|
|
17
|
+
declare const Content: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
18
|
+
/**
|
|
19
|
+
* Describes the props of `Content`: the props of a `div`.
|
|
20
|
+
*/
|
|
21
|
+
type ContentProps = ComponentProps<typeof Content>;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/card/description.d.ts
|
|
24
|
+
/**
|
|
25
|
+
* Renders the description slot under the title.
|
|
26
|
+
*/
|
|
27
|
+
declare const Description: import("@stealthscale/theme").StyledComponent<"p", {}>;
|
|
28
|
+
/**
|
|
29
|
+
* Describes the props of `Description`: the props of a `p`.
|
|
30
|
+
*/
|
|
31
|
+
type DescriptionProps = ComponentProps<typeof Description>;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/card/footer.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* Renders the footer slot.
|
|
36
|
+
*/
|
|
37
|
+
declare const Footer: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
38
|
+
/**
|
|
39
|
+
* Describes the props of `Footer`: the props of a `div`.
|
|
40
|
+
*/
|
|
41
|
+
type FooterProps = ComponentProps<typeof Footer>;
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/card/header.d.ts
|
|
44
|
+
/**
|
|
45
|
+
* Renders the header slot.
|
|
46
|
+
*/
|
|
47
|
+
declare const Header: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
48
|
+
/**
|
|
49
|
+
* Describes the props of `Header`: the props of a `div`.
|
|
50
|
+
*/
|
|
51
|
+
type HeaderProps = ComponentProps<typeof Header>;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/card/indicator.d.ts
|
|
54
|
+
/**
|
|
55
|
+
* Renders the indicator slot at the start of the header.
|
|
56
|
+
*/
|
|
57
|
+
declare const Indicator: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
58
|
+
/**
|
|
59
|
+
* Describes the props of `Indicator`: the props of a `div`.
|
|
60
|
+
*/
|
|
61
|
+
type IndicatorProps = ComponentProps<typeof Indicator>;
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/card/media.d.ts
|
|
64
|
+
/**
|
|
65
|
+
* Renders the media slot.
|
|
66
|
+
*/
|
|
67
|
+
declare const Media: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
68
|
+
/**
|
|
69
|
+
* Describes the props of `Media`: the props of a `div`.
|
|
70
|
+
*/
|
|
71
|
+
type MediaProps = ComponentProps<typeof Media>;
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/card/overlay.d.ts
|
|
74
|
+
/**
|
|
75
|
+
* Renders the overlay slot.
|
|
76
|
+
*/
|
|
77
|
+
declare const Overlay: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
78
|
+
/**
|
|
79
|
+
* Describes the props of `Overlay`: the props of a `div`.
|
|
80
|
+
*/
|
|
81
|
+
type OverlayProps = ComponentProps<typeof Overlay>;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/card/metrics.d.ts
|
|
84
|
+
/**
|
|
85
|
+
* Selects one of the four sizes a card offers.
|
|
86
|
+
*/
|
|
87
|
+
type Step = "lg" | "md" | "sm" | "xl";
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/card/root.d.ts
|
|
90
|
+
/**
|
|
91
|
+
* Renders the root slot and provides the recipe's variants to the other parts.
|
|
92
|
+
*/
|
|
93
|
+
declare const Styled: import("@stealthscale/theme").StyledComponent<"article", {
|
|
94
|
+
readonly disabled?: boolean;
|
|
95
|
+
readonly divided?: boolean;
|
|
96
|
+
readonly effect?: "glow";
|
|
97
|
+
readonly interactive?: boolean;
|
|
98
|
+
readonly justify?: import("@stealthscale/theme/authoring").Justify;
|
|
99
|
+
readonly motion?: "fade" | "reveal" | "rise";
|
|
100
|
+
readonly orientation?: "horizontal" | "vertical";
|
|
101
|
+
readonly palette?: "accent" | "error" | "info" | "neutral" | "primary" | "secondary" | "success" | "warning";
|
|
102
|
+
readonly radius?: import("@stealthscale/theme/authoring").Corner;
|
|
103
|
+
readonly scrim?: boolean;
|
|
104
|
+
readonly size?: Step;
|
|
105
|
+
readonly variant?: "elevated" | "glass" | "outline" | "plain" | "subtle";
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Describes the props of `Root`: the recipe's variants and the props of an `article`.
|
|
109
|
+
*/
|
|
110
|
+
type RootProps = ComponentProps<typeof Styled>;
|
|
111
|
+
/**
|
|
112
|
+
* Renders the root, with `aria-disabled` on a disabled card.
|
|
113
|
+
*
|
|
114
|
+
* @remarks
|
|
115
|
+
* `aria-disabled` announces the card's content as unavailable and marks it inactive for contrast
|
|
116
|
+
* checks. An `aria-disabled` the caller passes takes precedence.
|
|
117
|
+
* @param props - The recipe's variants and the props of an `article`.
|
|
118
|
+
* @returns The root element.
|
|
119
|
+
*/
|
|
120
|
+
declare function Root(props: RootProps): ReactElement;
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/card/section.d.ts
|
|
123
|
+
/**
|
|
124
|
+
* Renders the section slot.
|
|
125
|
+
*/
|
|
126
|
+
declare const Section: import("@stealthscale/theme").StyledComponent<"div", {}>;
|
|
127
|
+
/**
|
|
128
|
+
* Describes the props of `Section`: the props of a `div`.
|
|
129
|
+
*/
|
|
130
|
+
type SectionProps = ComponentProps<typeof Section>;
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/card/title.d.ts
|
|
133
|
+
/**
|
|
134
|
+
* Renders the title slot in the header grid's second column.
|
|
135
|
+
*/
|
|
136
|
+
declare const Title: import("@stealthscale/theme").StyledComponent<"h3", {}>;
|
|
137
|
+
/**
|
|
138
|
+
* Describes the props of `Title`: the props of an `h3`.
|
|
139
|
+
*/
|
|
140
|
+
type TitleProps = ComponentProps<typeof Title>;
|
|
141
|
+
declare namespace index_d_exports {
|
|
142
|
+
export { Aside, AsideProps, Content, ContentProps, Description, DescriptionProps, Footer, FooterProps, Header, HeaderProps, Indicator, IndicatorProps, Media, MediaProps, Overlay, OverlayProps, Root, RootProps, Section, SectionProps, Title, TitleProps };
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { index_d_exports as Card };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { t as recipe } from "./recipe-BSMN8WoK.js";
|
|
3
|
+
import { createSlotRecipeContext } from "@stealthscale/theme";
|
|
4
|
+
import { createElement } from "react";
|
|
5
|
+
//#region src/card/context.ts
|
|
6
|
+
/**
|
|
7
|
+
* Binds the card slot recipe to the React context its parts share.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* The binding is a separate module from `recipe.ts`, because an application's style compiler
|
|
11
|
+
* imports the recipe at build time without the React runtime.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Factories that bind the root, which resolves the variants, and every other part, which reads
|
|
15
|
+
* them.
|
|
16
|
+
*/
|
|
17
|
+
const { withContext, withProvider } = createSlotRecipeContext(recipe);
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/card/aside.ts
|
|
20
|
+
/**
|
|
21
|
+
* Renders the aside slot at the end of the header.
|
|
22
|
+
*/
|
|
23
|
+
const Aside = withContext("div", "aside");
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/card/content.ts
|
|
26
|
+
/**
|
|
27
|
+
* Renders the content slot.
|
|
28
|
+
*/
|
|
29
|
+
const Content = withContext("div", "content");
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/card/description.ts
|
|
32
|
+
/**
|
|
33
|
+
* Renders the description slot under the title.
|
|
34
|
+
*/
|
|
35
|
+
const Description = withContext("p", "description");
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/card/footer.ts
|
|
38
|
+
/**
|
|
39
|
+
* Renders the footer slot.
|
|
40
|
+
*/
|
|
41
|
+
const Footer = withContext("div", "footer");
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/card/header.ts
|
|
44
|
+
/**
|
|
45
|
+
* Renders the header slot.
|
|
46
|
+
*/
|
|
47
|
+
const Header = withContext("div", "header");
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/card/indicator.ts
|
|
50
|
+
/**
|
|
51
|
+
* Renders the indicator slot at the start of the header.
|
|
52
|
+
*/
|
|
53
|
+
const Indicator = withContext("div", "indicator");
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/card/media.ts
|
|
56
|
+
/**
|
|
57
|
+
* Renders the media slot.
|
|
58
|
+
*/
|
|
59
|
+
const Media = withContext("div", "media");
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/card/overlay.ts
|
|
62
|
+
/**
|
|
63
|
+
* Renders the overlay slot.
|
|
64
|
+
*/
|
|
65
|
+
const Overlay = withContext("div", "overlay");
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/card/root.ts
|
|
68
|
+
/**
|
|
69
|
+
* Renders the panel that contains every band of a card.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* The element is an `article`, which a screen reader lists and moves between. Name it: point
|
|
73
|
+
* `aria-labelledby` at the title's `id`, or pass `aria-label`. Pass `as="div"` for a card that is
|
|
74
|
+
* part of its surroundings. The root resolves every variant, and the other parts read them from
|
|
75
|
+
* context.
|
|
76
|
+
*/
|
|
77
|
+
/**
|
|
78
|
+
* Renders the root slot and provides the recipe's variants to the other parts.
|
|
79
|
+
*/
|
|
80
|
+
const Styled = withProvider("article", "root");
|
|
81
|
+
/**
|
|
82
|
+
* Renders the root, with `aria-disabled` on a disabled card.
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* `aria-disabled` announces the card's content as unavailable and marks it inactive for contrast
|
|
86
|
+
* checks. An `aria-disabled` the caller passes takes precedence.
|
|
87
|
+
* @param props - The recipe's variants and the props of an `article`.
|
|
88
|
+
* @returns The root element.
|
|
89
|
+
*/
|
|
90
|
+
function Root(props) {
|
|
91
|
+
return createElement(Styled, props.disabled === true ? {
|
|
92
|
+
"aria-disabled": true,
|
|
93
|
+
...props
|
|
94
|
+
} : props);
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/card/section.ts
|
|
98
|
+
/**
|
|
99
|
+
* Renders the section slot.
|
|
100
|
+
*/
|
|
101
|
+
const Section = withContext("div", "section");
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/card/title.ts
|
|
104
|
+
/**
|
|
105
|
+
* Renders the title slot in the header grid's second column.
|
|
106
|
+
*/
|
|
107
|
+
const Title = withContext("h3", "title");
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/card/index.ts
|
|
110
|
+
var card_exports = /* @__PURE__ */ __exportAll({
|
|
111
|
+
Aside: () => Aside,
|
|
112
|
+
Content: () => Content,
|
|
113
|
+
Description: () => Description,
|
|
114
|
+
Footer: () => Footer,
|
|
115
|
+
Header: () => Header,
|
|
116
|
+
Indicator: () => Indicator,
|
|
117
|
+
Media: () => Media,
|
|
118
|
+
Overlay: () => Overlay,
|
|
119
|
+
Root: () => Root,
|
|
120
|
+
Section: () => Section,
|
|
121
|
+
Title: () => Title
|
|
122
|
+
});
|
|
123
|
+
//#endregion
|
|
124
|
+
export { card_exports as Card };
|
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import { PALETTES, below, cornerVariants, defineSlotRecipe, dense, justifyVariants, motionVariants, onSlot, onSlots, paletteVariants, sizeVariants, surface } from "@stealthscale/theme/authoring";
|
|
2
|
+
//#region src/card/metrics.ts
|
|
3
|
+
/**
|
|
4
|
+
* Computes the geometry the card's size axis and bleeding bands are written from.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* The root publishes its inset and its gap as custom properties at every size. `Media` and
|
|
8
|
+
* `Section` read them back, so a band bleeds to the card's edge and spaces its rules at any size
|
|
9
|
+
* and density without one compound per size. The module is separate from the recipe so the recipe
|
|
10
|
+
* is under the 300-line limit.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Lists the sizes the card is styled at, smallest first.
|
|
14
|
+
*/
|
|
15
|
+
const STEPS = [
|
|
16
|
+
"sm",
|
|
17
|
+
"md",
|
|
18
|
+
"lg",
|
|
19
|
+
"xl"
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Class name of the recipe, which selectors across parts are built from.
|
|
23
|
+
*/
|
|
24
|
+
const CLASS = "card";
|
|
25
|
+
/**
|
|
26
|
+
* Custom property on the root that contains the root's inset.
|
|
27
|
+
*/
|
|
28
|
+
const INSET = "--card-inset";
|
|
29
|
+
/**
|
|
30
|
+
* Custom property on the root that contains the gap between two bands.
|
|
31
|
+
*/
|
|
32
|
+
const GAP = "--card-gap";
|
|
33
|
+
/**
|
|
34
|
+
* Negative margin that cancels the root's inset.
|
|
35
|
+
*/
|
|
36
|
+
const BLEED = `calc(-1 * var(${INSET}))`;
|
|
37
|
+
/**
|
|
38
|
+
* Border colour and style of a rule between two bands.
|
|
39
|
+
*/
|
|
40
|
+
const RULE = {
|
|
41
|
+
borderColor: "border",
|
|
42
|
+
borderStyle: "solid"
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Maps each size to the size token of an image in the indicator: 32, 40, 48 and 56px.
|
|
46
|
+
*/
|
|
47
|
+
const AVATAR = {
|
|
48
|
+
lg: "12",
|
|
49
|
+
md: "10",
|
|
50
|
+
sm: "8",
|
|
51
|
+
xl: "14"
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Maps each size to the gap token between the header's text and the indicator or the aside: 8,
|
|
55
|
+
* 12, 16 and 16px.
|
|
56
|
+
*/
|
|
57
|
+
const FLANK = {
|
|
58
|
+
lg: "xl",
|
|
59
|
+
md: "lg",
|
|
60
|
+
sm: "md",
|
|
61
|
+
xl: "xl"
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Returns the root's inset and gap at a size, published as custom properties and applied as the
|
|
65
|
+
* root's padding and gap.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* The properties contain the density-scaled lengths, so a band that bleeds by the inset ends at
|
|
69
|
+
* the edge under any density.
|
|
70
|
+
* @param size - The card's size.
|
|
71
|
+
* @returns The root's size styles.
|
|
72
|
+
*/
|
|
73
|
+
function spaced(size) {
|
|
74
|
+
return {
|
|
75
|
+
[GAP]: dense(`{spacing.gap.${size}}`),
|
|
76
|
+
gap: `var(${GAP})`,
|
|
77
|
+
[INSET]: dense(`{spacing.inset.${size}}`),
|
|
78
|
+
padding: `var(${INSET})`
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Returns the title's text style: the heading one size smaller than the card, or `label.lg` at
|
|
83
|
+
* `sm`.
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* One size smaller than `heading.sm` is body text, so the smallest card takes the largest label
|
|
87
|
+
* instead.
|
|
88
|
+
* @param size - The card's size.
|
|
89
|
+
* @returns The title's styles.
|
|
90
|
+
*/
|
|
91
|
+
function titled(size) {
|
|
92
|
+
return { textStyle: size === "sm" ? "label.lg" : `heading.${below(size)}` };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns the indicator's styles at a size: the gap to the title, and the size of an image or an
|
|
96
|
+
* icon inside it.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* An image anywhere in the indicator is a round avatar of 32 to 56px, so a skeleton around it
|
|
100
|
+
* keeps its size. An icon placed directly in the indicator takes the icon size of the card's
|
|
101
|
+
* size. The gap is a margin on the indicator rather than a column gap on the header, so a header
|
|
102
|
+
* without an indicator starts its title at the inset.
|
|
103
|
+
* @param size - The card's size.
|
|
104
|
+
* @returns The indicator's styles.
|
|
105
|
+
*/
|
|
106
|
+
function marked(size) {
|
|
107
|
+
return {
|
|
108
|
+
"& > svg": { boxSize: dense(`{sizes.icon.${size}}`) },
|
|
109
|
+
"& img": {
|
|
110
|
+
borderRadius: "full",
|
|
111
|
+
boxSize: dense(`{sizes.${AVATAR[size]}}`),
|
|
112
|
+
objectFit: "cover"
|
|
113
|
+
},
|
|
114
|
+
marginInlineEnd: dense(`{spacing.gap.${FLANK[size]}}`)
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns the aside's start margin at a size, the gap between the header's text and the aside.
|
|
119
|
+
*
|
|
120
|
+
* @param size - The card's size.
|
|
121
|
+
* @returns The aside's styles.
|
|
122
|
+
*/
|
|
123
|
+
function asided(size) {
|
|
124
|
+
return { marginInlineStart: dense(`{spacing.gap.${FLANK[size]}}`) };
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Returns the styles that bleed a band of a vertical card to the card's edges.
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* The band always extends to both inline edges. It extends to the top edge only as the root's
|
|
131
|
+
* first child and to the bottom edge only as its last child, so a band between two others keeps
|
|
132
|
+
* the gap above and below it.
|
|
133
|
+
* @returns The band's styles.
|
|
134
|
+
*/
|
|
135
|
+
function bled() {
|
|
136
|
+
return {
|
|
137
|
+
"&:first-child": { marginBlockStart: BLEED },
|
|
138
|
+
"&:last-child": { marginBlockEnd: BLEED },
|
|
139
|
+
marginInline: BLEED
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Returns the styles of a band that renders the rule above it: a hairline across the card's full
|
|
144
|
+
* width with the inset on both sides.
|
|
145
|
+
*
|
|
146
|
+
* @remarks
|
|
147
|
+
* The band extends to both side edges and pads its content back to the inset. The space above
|
|
148
|
+
* the rule is the root's gap plus a margin of the inset less the gap, and the space below it is
|
|
149
|
+
* the inset as padding. Every rule in a card is rendered by the lower band of its boundary, so no
|
|
150
|
+
* boundary has two rules.
|
|
151
|
+
* @returns The band's styles.
|
|
152
|
+
*/
|
|
153
|
+
function ruled() {
|
|
154
|
+
const inset = `var(${INSET})`;
|
|
155
|
+
return {
|
|
156
|
+
...RULE,
|
|
157
|
+
borderBlockStartWidth: "hairline",
|
|
158
|
+
marginBlockStart: `calc(${inset} - var(${GAP}))`,
|
|
159
|
+
marginInline: BLEED,
|
|
160
|
+
paddingBlockStart: inset,
|
|
161
|
+
paddingInline: inset
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Returns the styles of a section, a band that bleeds to the card's side edges with its content at
|
|
166
|
+
* the inset.
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* A section renders the rule above it unless it is the first band or follows the picture. As the
|
|
170
|
+
* first band it extends to the top edge, and as the last band to the bottom edge, with the inset
|
|
171
|
+
* as padding. The band after a section renders the rule below it, through {@link ruled}.
|
|
172
|
+
* @returns The section's styles.
|
|
173
|
+
*/
|
|
174
|
+
function sectioned() {
|
|
175
|
+
const inset = `var(${INSET})`;
|
|
176
|
+
return {
|
|
177
|
+
"&:first-child": {
|
|
178
|
+
marginBlockStart: BLEED,
|
|
179
|
+
paddingBlockStart: inset
|
|
180
|
+
},
|
|
181
|
+
"&:last-child": {
|
|
182
|
+
marginBlockEnd: BLEED,
|
|
183
|
+
paddingBlockEnd: inset
|
|
184
|
+
},
|
|
185
|
+
[`&:not(:first-child, .${CLASS}__media + *)`]: ruled(),
|
|
186
|
+
marginInline: BLEED,
|
|
187
|
+
paddingInline: inset
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/card/recipe.ts
|
|
192
|
+
/**
|
|
193
|
+
* Declares the card slot recipe: a panel of bands, with a picture, a header, content, sections and
|
|
194
|
+
* a footer.
|
|
195
|
+
*
|
|
196
|
+
* @remarks
|
|
197
|
+
* The root is a flex column in both orientations. In the horizontal orientation the picture is
|
|
198
|
+
* positioned along the leading third and the root pads its start past it, so every other band
|
|
199
|
+
* still stacks in one column. The header is a three-column grid: the indicator and the aside each
|
|
200
|
+
* span the title and the description rows and are centred on them. The root clips its content, so
|
|
201
|
+
* a bled picture takes the root's corners.
|
|
202
|
+
*/
|
|
203
|
+
/**
|
|
204
|
+
* Width of the picture along the leading side of a horizontal card.
|
|
205
|
+
*/
|
|
206
|
+
const SIDE = "33%";
|
|
207
|
+
/**
|
|
208
|
+
* Selects the link in the title that an interactive card stretches over its whole face.
|
|
209
|
+
*/
|
|
210
|
+
const TITLE_LINK = `.${CLASS}__title > a`;
|
|
211
|
+
/**
|
|
212
|
+
* Styles a card as an elevated panel at the md size, in the palette of its surroundings.
|
|
213
|
+
*/
|
|
214
|
+
const recipe = defineSlotRecipe({
|
|
215
|
+
base: {
|
|
216
|
+
aside: {
|
|
217
|
+
alignItems: "center",
|
|
218
|
+
display: "flex",
|
|
219
|
+
flex: "0 0 auto",
|
|
220
|
+
gridColumn: "3",
|
|
221
|
+
gridRow: "1 / span 2"
|
|
222
|
+
},
|
|
223
|
+
content: {
|
|
224
|
+
display: "flex",
|
|
225
|
+
flex: "1",
|
|
226
|
+
flexDirection: "column",
|
|
227
|
+
gap: dense("{spacing.gap.sm}")
|
|
228
|
+
},
|
|
229
|
+
description: {
|
|
230
|
+
color: "fg.muted",
|
|
231
|
+
gridColumn: "2",
|
|
232
|
+
textStyle: "body.sm"
|
|
233
|
+
},
|
|
234
|
+
footer: {
|
|
235
|
+
alignItems: "center",
|
|
236
|
+
display: "flex",
|
|
237
|
+
flexWrap: "wrap",
|
|
238
|
+
gap: dense("{spacing.gap.sm}")
|
|
239
|
+
},
|
|
240
|
+
header: {
|
|
241
|
+
alignItems: "center",
|
|
242
|
+
display: "grid",
|
|
243
|
+
gridTemplateColumns: "auto 1fr auto"
|
|
244
|
+
},
|
|
245
|
+
indicator: {
|
|
246
|
+
alignItems: "center",
|
|
247
|
+
display: "flex",
|
|
248
|
+
flex: "0 0 auto",
|
|
249
|
+
gridColumn: "1",
|
|
250
|
+
gridRow: "span 2"
|
|
251
|
+
},
|
|
252
|
+
media: {
|
|
253
|
+
"& > img": {
|
|
254
|
+
display: "block",
|
|
255
|
+
inlineSize: "full"
|
|
256
|
+
},
|
|
257
|
+
overflow: "hidden",
|
|
258
|
+
position: "relative"
|
|
259
|
+
},
|
|
260
|
+
/**
|
|
261
|
+
* The overlay covers the picture and places its content at the bottom-start corner.
|
|
262
|
+
*
|
|
263
|
+
* @remarks
|
|
264
|
+
* The overlay passes the pointer through, and its children take it back. The `scrim` axis
|
|
265
|
+
* darkens the picture behind text.
|
|
266
|
+
*/
|
|
267
|
+
overlay: {
|
|
268
|
+
"& > *": { pointerEvents: "auto" },
|
|
269
|
+
alignItems: "flex-start",
|
|
270
|
+
display: "flex",
|
|
271
|
+
flexDirection: "column",
|
|
272
|
+
gap: dense("{spacing.gap.sm}"),
|
|
273
|
+
inset: "0",
|
|
274
|
+
justifyContent: "flex-end",
|
|
275
|
+
padding: `var(${INSET})`,
|
|
276
|
+
pointerEvents: "none",
|
|
277
|
+
position: "absolute"
|
|
278
|
+
},
|
|
279
|
+
root: {
|
|
280
|
+
...surface(),
|
|
281
|
+
[`& > .${CLASS}__section + :is(.${CLASS}__content, .${CLASS}__footer)`]: ruled(),
|
|
282
|
+
display: "flex",
|
|
283
|
+
flexDirection: "column",
|
|
284
|
+
overflow: "hidden",
|
|
285
|
+
position: "relative"
|
|
286
|
+
},
|
|
287
|
+
section: sectioned(),
|
|
288
|
+
title: {
|
|
289
|
+
fontWeight: "semibold",
|
|
290
|
+
gridColumn: "2"
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
className: CLASS,
|
|
294
|
+
compoundVariants: [
|
|
295
|
+
(
|
|
296
|
+
/**
|
|
297
|
+
* Sets the border of an outline card in a palette to the palette's muted role, the edge every
|
|
298
|
+
* outlined look draws.
|
|
299
|
+
*/
|
|
300
|
+
{
|
|
301
|
+
css: { root: { borderColor: "colorPalette.muted" } },
|
|
302
|
+
name: "toned",
|
|
303
|
+
palette: [...PALETTES],
|
|
304
|
+
variant: "outline"
|
|
305
|
+
}),
|
|
306
|
+
(
|
|
307
|
+
/**
|
|
308
|
+
* Fills a subtle card in a palette with the palette's subtle role and sets its border to the
|
|
309
|
+
* palette's muted role.
|
|
310
|
+
*/
|
|
311
|
+
{
|
|
312
|
+
css: { root: {
|
|
313
|
+
background: "colorPalette.subtle",
|
|
314
|
+
borderColor: "colorPalette.muted"
|
|
315
|
+
} },
|
|
316
|
+
name: "tinted",
|
|
317
|
+
palette: [...PALETTES],
|
|
318
|
+
variant: "subtle"
|
|
319
|
+
}),
|
|
320
|
+
(
|
|
321
|
+
/**
|
|
322
|
+
* An interactive elevated card raises its shadow one step under the pointer.
|
|
323
|
+
*/
|
|
324
|
+
{
|
|
325
|
+
css: { root: { _hover: { boxShadow: "lg" } } },
|
|
326
|
+
interactive: true,
|
|
327
|
+
name: "lifted",
|
|
328
|
+
variant: "elevated"
|
|
329
|
+
})
|
|
330
|
+
],
|
|
331
|
+
defaultVariants: {
|
|
332
|
+
justify: "end",
|
|
333
|
+
orientation: "vertical",
|
|
334
|
+
radius: "l2",
|
|
335
|
+
size: "md",
|
|
336
|
+
variant: "elevated"
|
|
337
|
+
},
|
|
338
|
+
jsx: [/^Card(\.\w+)?$/u],
|
|
339
|
+
slots: [
|
|
340
|
+
"root",
|
|
341
|
+
"media",
|
|
342
|
+
"overlay",
|
|
343
|
+
"header",
|
|
344
|
+
"indicator",
|
|
345
|
+
"title",
|
|
346
|
+
"description",
|
|
347
|
+
"aside",
|
|
348
|
+
"content",
|
|
349
|
+
"section",
|
|
350
|
+
"footer"
|
|
351
|
+
],
|
|
352
|
+
staticCss: [{ palette: [...PALETTES] }],
|
|
353
|
+
variants: {
|
|
354
|
+
/**
|
|
355
|
+
* Unavailable look: the card at the disabled opacity, with no pointer events on any band.
|
|
356
|
+
*
|
|
357
|
+
* @remarks
|
|
358
|
+
* The styles do not remove the title's link from the tab order. Render the title without a
|
|
359
|
+
* link, or give the link `aria-disabled` and no `href`.
|
|
360
|
+
*/
|
|
361
|
+
disabled: { true: { root: {
|
|
362
|
+
opacity: "disabled",
|
|
363
|
+
pointerEvents: "none"
|
|
364
|
+
} } },
|
|
365
|
+
/**
|
|
366
|
+
* Rules under the header and above the footer.
|
|
367
|
+
*
|
|
368
|
+
* @remarks
|
|
369
|
+
* The band after the header and the footer each render the rule above them through `ruled`,
|
|
370
|
+
* so both rules span the card's full width with the inset on both sides, like a section's.
|
|
371
|
+
*/
|
|
372
|
+
divided: { true: {
|
|
373
|
+
footer: ruled(),
|
|
374
|
+
root: { [`& > .${CLASS}__header + :is(.${CLASS}__content, .${CLASS}__section, .${CLASS}__footer)`]: ruled() }
|
|
375
|
+
} },
|
|
376
|
+
/**
|
|
377
|
+
* Halo around the card in the palette's solid at half opacity.
|
|
378
|
+
*
|
|
379
|
+
* @remarks
|
|
380
|
+
* The axis offers `glow` and no `pulse`. A pulse animates `box-shadow` on the root, whose
|
|
381
|
+
* `animation` the `motion` axis already sets, and the root clips a pseudo-element's shadow.
|
|
382
|
+
*/
|
|
383
|
+
effect: onSlot("root", { glow: { layerStyle: "glow.lg" } }),
|
|
384
|
+
/**
|
|
385
|
+
* Whole-card press through the link in the title.
|
|
386
|
+
*
|
|
387
|
+
* @remarks
|
|
388
|
+
* The title's link stretches a pseudo-element over the root, so a click anywhere follows the
|
|
389
|
+
* link and the link keeps the focus and the accessible name. Every other link and button in
|
|
390
|
+
* the card is positioned, so it paints over the pseudo-element and takes its own clicks. The
|
|
391
|
+
* root renders the focus ring while the title's link is focused, in the palette's
|
|
392
|
+
* `focusRing`.
|
|
393
|
+
*/
|
|
394
|
+
interactive: { true: {
|
|
395
|
+
root: {
|
|
396
|
+
_hover: { borderColor: "border.emphasized" },
|
|
397
|
+
[`&:has(${TITLE_LINK}:focus-visible)`]: {
|
|
398
|
+
outlineColor: "colorPalette.focusRing",
|
|
399
|
+
outlineOffset: "ring",
|
|
400
|
+
outlineStyle: "solid",
|
|
401
|
+
outlineWidth: "ring"
|
|
402
|
+
},
|
|
403
|
+
[`& :is(a[href], button):not(${TITLE_LINK})`]: { position: "relative" },
|
|
404
|
+
cursor: "button",
|
|
405
|
+
transitionDuration: "press",
|
|
406
|
+
transitionProperty: "common",
|
|
407
|
+
transitionTimingFunction: "press"
|
|
408
|
+
},
|
|
409
|
+
title: { "& > a::after": {
|
|
410
|
+
content: "\"\"",
|
|
411
|
+
inset: "0",
|
|
412
|
+
position: "absolute"
|
|
413
|
+
} }
|
|
414
|
+
} },
|
|
415
|
+
/**
|
|
416
|
+
* Alignment of the footer's controls along the row.
|
|
417
|
+
*/
|
|
418
|
+
justify: onSlot("footer", justifyVariants()),
|
|
419
|
+
motion: onSlot("root", motionVariants([
|
|
420
|
+
"fade",
|
|
421
|
+
"rise",
|
|
422
|
+
"reveal"
|
|
423
|
+
])),
|
|
424
|
+
/**
|
|
425
|
+
* Placement of the picture: bled across the top of a vertical card, or along the leading third
|
|
426
|
+
* of a horizontal one.
|
|
427
|
+
*
|
|
428
|
+
* @remarks
|
|
429
|
+
* A horizontal card pads its start by the picture's width plus the inset only when it
|
|
430
|
+
* contains a picture, and the picture fills its full height with `object-fit: cover`.
|
|
431
|
+
*/
|
|
432
|
+
orientation: {
|
|
433
|
+
horizontal: {
|
|
434
|
+
media: {
|
|
435
|
+
"& > img": {
|
|
436
|
+
blockSize: "full",
|
|
437
|
+
objectFit: "cover"
|
|
438
|
+
},
|
|
439
|
+
inlineSize: SIDE,
|
|
440
|
+
insetBlock: "0",
|
|
441
|
+
insetInlineStart: "0",
|
|
442
|
+
position: "absolute"
|
|
443
|
+
},
|
|
444
|
+
root: { [`&:has(> .${CLASS}__media)`]: { paddingInlineStart: `calc(${SIDE} + var(${INSET}))` } }
|
|
445
|
+
},
|
|
446
|
+
vertical: { media: bled() }
|
|
447
|
+
},
|
|
448
|
+
/**
|
|
449
|
+
* Palette of the card's tint, border, focus ring and glow.
|
|
450
|
+
*
|
|
451
|
+
* @remarks
|
|
452
|
+
* The outline look sets its border to the palette's border role, and the subtle look also
|
|
453
|
+
* fills with the palette's subtle role. Without a palette the card inherits the palette of
|
|
454
|
+
* its surroundings.
|
|
455
|
+
*/
|
|
456
|
+
palette: onSlot("root", paletteVariants()),
|
|
457
|
+
radius: onSlot("root", cornerVariants()),
|
|
458
|
+
/**
|
|
459
|
+
* Scrim behind the overlay: 64% black across the lower half of the picture, fading to
|
|
460
|
+
* transparent at the top.
|
|
461
|
+
*
|
|
462
|
+
* @remarks
|
|
463
|
+
* The scrim declares the dark color scheme on the overlay, so `fg` and every semantic color
|
|
464
|
+
* in it take their dark-mode values in both modes. Set it for text over a picture. A badge
|
|
465
|
+
* has its own fill and does not need it.
|
|
466
|
+
*/
|
|
467
|
+
scrim: { true: { overlay: {
|
|
468
|
+
backgroundImage: "linear-gradient(to top, {colors.blackAlpha.700}, {colors.blackAlpha.700} 50%, transparent)",
|
|
469
|
+
color: "fg",
|
|
470
|
+
colorScheme: "dark"
|
|
471
|
+
} } },
|
|
472
|
+
/**
|
|
473
|
+
* Inset, gap, title style, header gaps and indicator media at each size.
|
|
474
|
+
*/
|
|
475
|
+
size: onSlots({
|
|
476
|
+
aside: sizeVariants(asided, STEPS),
|
|
477
|
+
indicator: sizeVariants(marked, STEPS),
|
|
478
|
+
root: sizeVariants(spaced, STEPS),
|
|
479
|
+
title: sizeVariants(titled, STEPS)
|
|
480
|
+
}),
|
|
481
|
+
/**
|
|
482
|
+
* Treatment of the panel.
|
|
483
|
+
*
|
|
484
|
+
* @remarks
|
|
485
|
+
* `plain` removes the fill, the border and the shadow, and keeps the bands and the inset.
|
|
486
|
+
*/
|
|
487
|
+
variant: {
|
|
488
|
+
elevated: { root: {
|
|
489
|
+
borderColor: "transparent",
|
|
490
|
+
boxShadow: "md"
|
|
491
|
+
} },
|
|
492
|
+
glass: { root: {
|
|
493
|
+
boxShadow: "none",
|
|
494
|
+
layerStyle: "glass"
|
|
495
|
+
} },
|
|
496
|
+
outline: { root: { boxShadow: "none" } },
|
|
497
|
+
plain: { root: {
|
|
498
|
+
background: "transparent",
|
|
499
|
+
borderColor: "transparent",
|
|
500
|
+
boxShadow: "none"
|
|
501
|
+
} },
|
|
502
|
+
subtle: { root: {
|
|
503
|
+
background: "bg.subtle",
|
|
504
|
+
borderColor: "transparent",
|
|
505
|
+
boxShadow: "none"
|
|
506
|
+
} }
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
//#endregion
|
|
511
|
+
export { recipe as t };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/theme.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Publishes the preset an application's style compiler installs to pick up this package's recipes.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* The list of recipes is maintained by hand. The package's own specification fails when a recipe
|
|
7
|
+
* file is missing from it, which is why nothing generates the list.
|
|
8
|
+
*/
|
|
9
|
+
declare const _default: import("@stealthscale/theme/authoring").Preset;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { _default as default };
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { t as recipe } from "./recipe-BSMN8WoK.js";
|
|
2
|
+
import { definePreset } from "@stealthscale/theme/authoring";
|
|
3
|
+
//#region src/theme.ts
|
|
4
|
+
/**
|
|
5
|
+
* Publishes the preset an application's style compiler installs to pick up this package's recipes.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* The list of recipes is maintained by hand. The package's own specification fails when a recipe
|
|
9
|
+
* file is missing from it, which is why nothing generates the list.
|
|
10
|
+
*/
|
|
11
|
+
var theme_default = definePreset({
|
|
12
|
+
name: "@stealthscale/component-surfaces",
|
|
13
|
+
theme: { extend: { slotRecipes: { card: recipe } } }
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { theme_default as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stealthscale/component-surfaces",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Draws the surface under a thing, and the rule between two of them.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"card",
|
|
7
|
+
"components",
|
|
8
|
+
"react",
|
|
9
|
+
"surfaces"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/stealth-scale/scale/tree/main/components/surfaces#readme",
|
|
12
|
+
"bugs": "https://github.com/stealth-scale/scale/issues",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/stealth-scale/scale.git",
|
|
17
|
+
"directory": "components/surfaces"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"imports": {
|
|
27
|
+
"#*": "./src/*"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./dist/index.js",
|
|
31
|
+
"./theme": "./dist/theme.js",
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@arethetypeswrong/core": "^0.18",
|
|
39
|
+
"@stealthscale/component-actions": "^0.1.0",
|
|
40
|
+
"@stealthscale/component-navigation": "^0.1.0",
|
|
41
|
+
"@stealthscale/theme": "^0.3.0",
|
|
42
|
+
"@stealthscale/vite-config": "^0.6.0",
|
|
43
|
+
"@stealthscale/vite-config-i18n": "^0.1.0",
|
|
44
|
+
"@stealthscale/vite-config-react": "^0.8.0",
|
|
45
|
+
"@stealthscale/vite-config-specimen": "^0.1.0",
|
|
46
|
+
"@stealthscale/vite-config-theme": "^0.1.0",
|
|
47
|
+
"@stealthscale/vite-config-typescript": "^0.3.0",
|
|
48
|
+
"@testing-library/react": "^16.3",
|
|
49
|
+
"@types/react": "^19.3",
|
|
50
|
+
"@types/react-dom": "^19.3",
|
|
51
|
+
"happy-dom": "^20.14",
|
|
52
|
+
"lucide-react": "^1.48",
|
|
53
|
+
"oxc-transform-react": "^0.151",
|
|
54
|
+
"publint": "^0.3",
|
|
55
|
+
"react": "^19.3",
|
|
56
|
+
"react-dom": "^19.3",
|
|
57
|
+
"typescript": "^7.0",
|
|
58
|
+
"vitest": "5.0.1"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@stealthscale/theme": "^0.3.0",
|
|
62
|
+
"react": "^19.3"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=26.0.0"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "vp pack",
|
|
69
|
+
"check": "vp check",
|
|
70
|
+
"test": "vp test"
|
|
71
|
+
}
|
|
72
|
+
}
|