sheleg-design-skill 1.48.0 → 1.49.0
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/CHANGELOG.md +154 -0
- package/README.md +5 -4
- package/bin/cli.js +5 -2
- package/cursor/rules/sheleg-design.mdc +6 -1
- package/kits/nameplate/src/Mark.md +24 -0
- package/kits/nameplate/src/Mark.tsx +26 -0
- package/kits/nameplate/src/index.ts +2 -0
- package/kits/nameplate/src/styles.css +74 -4
- package/kits/rimlight/.design-sync/config.json +14 -0
- package/kits/rimlight/.design-sync/conventions.md +62 -0
- package/kits/rimlight/README.md +39 -0
- package/kits/rimlight/package.json +29 -0
- package/kits/rimlight/src/Act.md +19 -0
- package/kits/rimlight/src/Act.tsx +21 -0
- package/kits/rimlight/src/Button.md +17 -0
- package/kits/rimlight/src/Button.tsx +33 -0
- package/kits/rimlight/src/Card.md +14 -0
- package/kits/rimlight/src/Card.tsx +24 -0
- package/kits/rimlight/src/Chip.md +12 -0
- package/kits/rimlight/src/Chip.tsx +25 -0
- package/kits/rimlight/src/Heading.md +14 -0
- package/kits/rimlight/src/Heading.tsx +19 -0
- package/kits/rimlight/src/Label.md +16 -0
- package/kits/rimlight/src/Label.tsx +18 -0
- package/kits/rimlight/src/LitButton.md +22 -0
- package/kits/rimlight/src/LitButton.tsx +26 -0
- package/kits/rimlight/src/Rule.md +13 -0
- package/kits/rimlight/src/Rule.tsx +18 -0
- package/kits/rimlight/src/Stat.md +13 -0
- package/kits/rimlight/src/Stat.tsx +17 -0
- package/kits/rimlight/src/Tile.md +16 -0
- package/kits/rimlight/src/Tile.tsx +22 -0
- package/kits/rimlight/src/index.ts +23 -0
- package/kits/rimlight/src/styles.css +546 -0
- package/kits/rimlight/tsconfig.json +15 -0
- package/package.json +2 -2
- package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
- package/plugins/sheleg-design/commands/sheleg-design.md +2 -2
- package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/FIGMA_BRIDGE.md +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/MOBILE_SURFACES.md +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +4 -3
- package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +3 -3
- package/plugins/sheleg-design/skills/sheleg-design/styles/STYLE_PACK_TEMPLATE.md +50 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/nameplate.md +36 -2
- package/plugins/sheleg-design/skills/sheleg-design/styles/pigeonhole.md +1 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/rimlight.md +342 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/showroom.md +1 -0
- package/plugins/sheleg-design/skills/sheleg-design/styles/tenor.md +1 -1
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/nameplate.css +51 -4
- package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/rimlight.css +306 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,160 @@ follow [SemVer](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.49.0] - 2026-08-24
|
|
10
|
+
|
|
11
|
+
### Rimlight, the thirty-fourth pack — elevation made of light
|
|
12
|
+
|
|
13
|
+
Extracted from `peppermint.global/services/web-design`, a design studio's service page.
|
|
14
|
+
The site is Webflow: one shared stylesheet of 230,354 bytes declaring 82 custom
|
|
15
|
+
properties, and an interaction engine that ships on the page and drives exactly **one**
|
|
16
|
+
element. Every value was read off **computed styles on the live page** through CDP at
|
|
17
|
+
1440×900 — 487 visible of 562 elements on a 12,410px page — and at a device-emulated
|
|
18
|
+
390×844.
|
|
19
|
+
|
|
20
|
+
**The signature is a light, not a shadow.** The primary control wears a **sixteen-layer**
|
|
21
|
+
`box-shadow`: six layers lit — a white rim, a teal spill, a cyan throw, two insets that
|
|
22
|
+
keep it from reading as a sticker, and a mint bloom at 44px of blur offset −14.78px in x
|
|
23
|
+
— and **ten pre-declared at alpha 0**, every offset already in place so a direction can
|
|
24
|
+
be lit by moving alpha alone with no relayout. The light sits below and to the left. On a
|
|
25
|
+
page otherwise made of ink, one blue and two greys, that bloom is the only chromatic
|
|
26
|
+
event, so the most saturated thing on the screen is also the thing you are meant to click.
|
|
27
|
+
No pack in the library had elevation made of coloured light.
|
|
28
|
+
|
|
29
|
+
**Reading the render mattered twice, in opposite directions**, which is exactly what the
|
|
30
|
+
template's new rule 7 was written for a release earlier. The uppercase micro-labels *look*
|
|
31
|
+
generously tracked and are not — `letter-spacing` computes to `normal` on every one, and
|
|
32
|
+
the openness is Source Code Pro's own advance width, so a pack matched from a screenshot
|
|
33
|
+
ships a tracking value that does not exist. And the button's elevation *looks* like one
|
|
34
|
+
soft shadow; sixteen layers only resolve under `getComputedStyle`.
|
|
35
|
+
|
|
36
|
+
**The palette is split by field, and that is the pack's central law.** Every one of the
|
|
37
|
+
reference's five secondary hues measures 6.5–10.5:1 on the dark act and **1.65–2.65:1 on
|
|
38
|
+
the white page**. They did not fail — they were designed for the dark, and the light field
|
|
39
|
+
is where they must be held back. So the hues live in `[data-surface="dark"]`, which is a
|
|
40
|
+
**surface variant and not a theme twin**: one section is dark, the document never inverts,
|
|
41
|
+
and the four statuses are remapped rather than inherited because the light set measures
|
|
42
|
+
1.1–1.5:1 there.
|
|
43
|
+
|
|
44
|
+
**The blue is two tokens because it does two jobs.** `--accent` is 3.03:1 on `--bg` —
|
|
45
|
+
below the 4.5:1 body floor and above the 3:1 large-text one — so it is declared
|
|
46
|
+
`@role non-text` with its exemption stated: legal on a word only at ≥ 24px, which is where
|
|
47
|
+
the reference spends it, at 86px in the headline's first phrase. Anything smaller takes
|
|
48
|
+
`--accent-ink` at 5.16:1.
|
|
49
|
+
|
|
50
|
+
**Four corrections travel with the pack.** Secondary copy is `#9d9fa3` at 2.65:1 on the
|
|
51
|
+
page. The tertiary grey `#767676` passes the page at 4.54:1 and fails the act separator at
|
|
52
|
+
4.05:1. The reference's secondary set is a palette and not a scheme — eight of its
|
|
53
|
+
twenty-one pairs are too close to separate under dichromacy — so the four status roles were
|
|
54
|
+
derived from its own hues rather than adopted from its names. And 26 of 37 visible
|
|
55
|
+
interactive elements at 390 are under 44px.
|
|
56
|
+
|
|
57
|
+
**Two doctrine corrections the gates caught, both worth recording.** The pack prescribed
|
|
58
|
+
its press at the reference's own 200ms, which sits outside the doctrine's 100–160ms band,
|
|
59
|
+
so `--dur-press` takes the band's ceiling instead of the nearest measured value — the one
|
|
60
|
+
motion value here that is not measured, and it says so. And the pack bans bold while the
|
|
61
|
+
token layer shipped no base rule for it: the UA supplies `strong { font-weight: 700 }`
|
|
62
|
+
whether a pack does or not, so a ban with no rule is invisible. The layer now sets
|
|
63
|
+
`strong, b { font-weight: var(--weight-label) }` — 500, the heaviest weight this pack has.
|
|
64
|
+
|
|
65
|
+
**Rendering the kit caught a defect the gates could not**, for the third release running.
|
|
66
|
+
The light control variant rendered *dark* inside the dark act: it was built on
|
|
67
|
+
`--surface`, which `[data-surface="dark"]` remaps to `#242424`, so a control that is white
|
|
68
|
+
by definition followed the field and the rig lit nothing. `--lit-light-fill` does not
|
|
69
|
+
follow the field. A gate reads structure, not layout.
|
|
70
|
+
|
|
71
|
+
`MOTION_INTENSITY` is pinned at **2** — the lowest ceiling in the library beside
|
|
72
|
+
`bulletin`. 432 of 487 elements compute `transition-duration: 0s`, `animation-timeline`
|
|
73
|
+
appears zero times, and the rig is a **static** light: animating it is the pack's first
|
|
74
|
+
ban and the fastest way to turn it into a toy.
|
|
75
|
+
|
|
76
|
+
The fork against `showroom` is written from both ends: both are white and both spend a big
|
|
77
|
+
layered elevation on one object, and the distinction is that `showroom` lights the
|
|
78
|
+
application in a neutral shadow dropped from above while this lights a control in coloured
|
|
79
|
+
light thrown from the side — and this hero carries no product at all. `ADR-0001` gains a
|
|
80
|
+
further application, with `halation`, `limelight` and `luminaire` weighed and rejected.
|
|
81
|
+
|
|
82
|
+
Gates: 4626 → **4754**, 2681 → **2784**, 692 → **706**. Both palette ceilings held for the
|
|
83
|
+
second consecutive release; `computed_at_least` rises 572 → 600.
|
|
84
|
+
|
|
85
|
+
## [1.48.1] - 2026-08-24
|
|
86
|
+
|
|
87
|
+
### The assembly rule is written down, and the render step earned its place within the hour
|
|
88
|
+
|
|
89
|
+
The procedure for adding a pack lived in three homes — `CONTRIBUTING.md`'s authoring
|
|
90
|
+
steps, `docs/DOCMAP.md`'s propagation row, and the release section — and three things
|
|
91
|
+
the `nameplate` run actually did were in none of them. They are now in the home that
|
|
92
|
+
already owns each, rather than in a fourth document, which `DOCMAP`'s single-homes
|
|
93
|
+
discipline forbids.
|
|
94
|
+
|
|
95
|
+
**`STYLE_PACK_TEMPLATE.md` gains rules 7 and 8**, and both ship inside the bundle so an
|
|
96
|
+
author holding only the installed skill sees them. Rule 7 is *read the render, not the
|
|
97
|
+
stylesheet*: a dead token reads as the brand, a gradient hides from a
|
|
98
|
+
`background-color` census because its element's is transparent, and vendor CSS
|
|
99
|
+
outnumbers authored CSS — three traps met in one run, each with the shipped pack that
|
|
100
|
+
met it. Rule 8 is *write a ratio so the gate can compute it*, with all four shapes that
|
|
101
|
+
fail: a line break between the number and its partner, a token whose name contains
|
|
102
|
+
another's (`--on-action` resolves as `--action`, a gradient that pairs with nothing), a
|
|
103
|
+
table row stating a bare ratio, and a line whose **only** token is the partner, so it
|
|
104
|
+
fills both slots and pairs with itself.
|
|
105
|
+
|
|
106
|
+
**`CONTRIBUTING.md` gains step 8: render the kit and check its computed values against
|
|
107
|
+
what the pack claims.** Not a screenshot for the eye — mount it on real content at
|
|
108
|
+
1440, 768 and an emulated 390, then read `getComputedStyle` back. The step existed
|
|
109
|
+
only as a sentence in `bulletin`'s CHANGELOG entry, so whether it happened depended on
|
|
110
|
+
the next author reading that paragraph. **It caught a defect within the hour of being
|
|
111
|
+
written:** the `Mark` tile added in this same release rendered 60×60 against a declared
|
|
112
|
+
50, because `.np-mark` was not in the kit's `border-box` list — the same defect as the
|
|
113
|
+
plate one release earlier, in the component added to close a different gap.
|
|
114
|
+
|
|
115
|
+
### The mark set, and what measuring it changed
|
|
116
|
+
|
|
117
|
+
`nameplate`'s reference repeats one object per feature on the report surface it embeds:
|
|
118
|
+
a 50×50 tile at 16px radius wearing a **5px solid ring**, a wash at 9–12% alpha and a
|
|
119
|
+
glyph in the matching solid. Six hue pairs drive it and the pack carried none of them,
|
|
120
|
+
so an agent building the reference's own feature row would have invented six colours.
|
|
121
|
+
|
|
122
|
+
**Measuring them changed the answer from "carry six hues" to "carry a mechanism and a
|
|
123
|
+
ban".** The set does not separate from itself: seven of its fifteen pairs are tight,
|
|
124
|
+
and the reference's own indigo `#5b4bd4` and violet `#6c5ce7` are 5.58 OKLab units
|
|
125
|
+
apart at full colour — one colour wearing two names. So the hue is variety, never
|
|
126
|
+
meaning; it does not encode which feature this is; and the tokens are **numbered**
|
|
127
|
+
rather than named so nothing can misread them as semantic. That is the measured
|
|
128
|
+
difference from `pigeonhole`, whose hues *are* a taxonomy and whose label word is
|
|
129
|
+
therefore mandatory, and the fork is now written from both ends.
|
|
130
|
+
|
|
131
|
+
The sixth hue was dropped for a second measured reason: the reference's red `#d94558`
|
|
132
|
+
sits **2.92** units from `--action-to` and 1.12 under the worst dichromacy — the same
|
|
133
|
+
colour to every reader, not only to a colourblind one. A mark in the action's colour
|
|
134
|
+
reads as a control, so the coral stays with `--action` and the sixth slot takes
|
|
135
|
+
`--mark-neutral`. All six clear the 3:1 non-text floor on their own composited tile,
|
|
136
|
+
and none may carry a word: `--mark-4` is 3.89:1 on the slab, `--mark-2` is 4.27:1, and
|
|
137
|
+
the dropped red was 3.96:1.
|
|
138
|
+
|
|
139
|
+
Ships `Mark` as the kit's twelfth component, with `tone` as a number precisely because
|
|
140
|
+
it means nothing.
|
|
141
|
+
|
|
142
|
+
### A claim that was wider than its evidence
|
|
143
|
+
|
|
144
|
+
The pack said *the reference has no dark band anywhere*, and what had been checked was
|
|
145
|
+
the home page at 1440. The authored stylesheets declare **eight** dark fills, and both
|
|
146
|
+
kinds were then checked: `.bg-header-blue` (`#231b66`) is dead CSS no served page uses,
|
|
147
|
+
and the one that renders (`#1f2937`) sits inside a **mock of another product's
|
|
148
|
+
interface** in the hero image. The claim holds in substance and now states the width it
|
|
149
|
+
was measured at, in the Bans and in the token layer's own comment. A claim wider than
|
|
150
|
+
its evidence is this repository's own defect class, and it does not get an exemption
|
|
151
|
+
for being ours.
|
|
152
|
+
|
|
153
|
+
### Still open, and named rather than quietly dropped
|
|
154
|
+
|
|
155
|
+
`T31` is unrun — it needs fresh contexts reading blind. And 29% of the reference's
|
|
156
|
+
authored CSS is still unmeasured into the pack: the checkout (`order-form-cro.css`,
|
|
157
|
+
66,546 B) and the report surface (71,302 B) of 500,051 B total. The pack describes a
|
|
158
|
+
front door and says nothing about the payment step. That is an extension to a second
|
|
159
|
+
surface, not a loose end.
|
|
160
|
+
|
|
161
|
+
Gates: 4617 → **4626**, 2659 → **2681**, 692 unchanged. Both palette ceilings held.
|
|
162
|
+
|
|
9
163
|
## [1.48.0] - 2026-08-24
|
|
10
164
|
|
|
11
165
|
### Nameplate, the thirty-third pack — the proof is a borrowed name
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ problem — invented colors, six accent hues, dark mode retrofitted later.
|
|
|
11
11
|
|
|
12
12
|
This skill is the taste layer. It gives a coding agent **one motion
|
|
13
13
|
methodology** for cinematic, scroll-driven pages, **a motion doctrine** that
|
|
14
|
-
decides whether to animate before it decides how, and **thirty-
|
|
14
|
+
decides whether to animate before it decides how, and **thirty-four locked style
|
|
15
15
|
packs** with ready-made design tokens, so what it builds reads as one system
|
|
16
16
|
instead of a pile of effects.
|
|
17
17
|
|
|
@@ -53,6 +53,7 @@ into the cinematic layer, and says so in its own *Motion flavor* section.
|
|
|
53
53
|
| `babylove` | white with one orange in six steps and nothing else declared — seven tokens over Tailwind's defaults, two card levels nested at 16 and 8px, no shadow and no dark theme | SEO and AI-visibility SaaS with a long time-to-value — the minimal-system answer to the same brief `outrank` answers maximally |
|
|
54
54
|
| `patchbay` | near-black under a faint 40px grid, one mint-cyan doing every functional job, elevation made of 8% hairlines with no shadow anywhere, and a live architecture diagram whose cords carry SMIL particles | engines, message buses, pipelines, schedulers and open-source front doors — anything whose argument is an architecture rather than a promise |
|
|
55
55
|
| `nameplate` | a cool near-white slab under a page that is **square on 87% of its elements** — 1,091 of 1,251 measured — where the one round shape is reserved for a white 1px-bordered pill carrying somebody else's publication name **as type rather than as a logo**, one family with the body at **weight 500**, and two uppercase registers tracked 0.06em and 0.175em | **pages whose argument is that named third parties will vouch for you** — press and media placement, PR distribution, trust marks and badges, certification, review aggregation and "as featured in" surfaces (standalone) |
|
|
56
|
+
| `rimlight` | a white field with a cool grey act separator and one near-black act, a grotesque for every sentence and a **monospace for every piece of chrome**, square on 84% of its elements, tracked negative at every size and with **no bold anywhere** — and an elevation made of **coloured light**: a sixteen-layer rig, six layers lit and ten held at alpha 0, thrown from below-left onto one control per viewport | **a studio's own front door and the pages that sell what it makes** — design and engineering agencies, product studios, service and case-study pages (standalone) |
|
|
56
57
|
| `outrank` | white field with one violet that carries text in both directions, a 5px light ring standing in for a button shadow, and two type families split by how long a thing is read | SEO and growth SaaS, agent-run back-office — the pack for a product that ships a landing and a dashboard at once |
|
|
57
58
|
| `orchard` | warm oat field of rounded slabs, sage brand + one candy-orange action, rounded geometric display, soft-3D pills built from inset light | friendly consumer biotech, DTC wellness, testing kits & supplements |
|
|
58
59
|
| `field-notes` | warm green-cast paper ruled by hairlines, one rust accent, a hero that dissolves into the page instead of ending, numbered mono eyebrows, crop marks, colour that encodes how a claim is known | open-source & developer tools sold on auditability — code intelligence, provenance, evals, agent memory |
|
|
@@ -153,7 +154,7 @@ skills.
|
|
|
153
154
|
| `DESIGN_SYNC_BRIDGE.md` | The Claude Design contract: what a pack sends to claude.ai/design and in what shape, the rule for each of the four reference types, and the border motion does not cross |
|
|
154
155
|
| `FIGMA_BRIDGE.md` | The design↔code contract: how a pack's tokens map onto Figma variable collections and modes, how to implement a design without importing raw values, and what cannot cross the border |
|
|
155
156
|
| `AI_PRODUCT_PATTERNS.md` | The surfaces a model drives: the five states of a call, streaming instead of spinners, latency, provenance and uncertainty, agent confirmations, and the bans that keep it honest |
|
|
156
|
-
| `styles/*.md` | The thirty-
|
|
157
|
+
| `styles/*.md` | The thirty-four style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
|
|
157
158
|
| `styles/tokens/*.css` | The ready-made token layer per pack, copied verbatim instead of transcribed (`workbench` and `field-notes` each ship a light `:root` plus a `data-theme="dark"` twin) |
|
|
158
159
|
| `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
|
|
159
160
|
|
|
@@ -224,7 +225,7 @@ cd ./ds-workbench && npm install && npm run build
|
|
|
224
225
|
then `/design-sync` in that directory, from Claude Code. Three layers cross: the
|
|
225
226
|
pack's **bans** as the design system's own README, `styles.css` built from
|
|
226
227
|
`tokens/<pack>.css` verbatim, and the components — a six-name spine that is
|
|
227
|
-
identical in all thirty-
|
|
228
|
+
identical in all thirty-four kits, so switching packs swaps identity rather than API,
|
|
228
229
|
plus each pack's signature parts. **Motion does not cross**, exactly as it does
|
|
229
230
|
not cross into Figma: a kit is the static half of a pack, and saying so is what
|
|
230
231
|
stops an agent inventing motion to fill the silence.
|
|
@@ -270,7 +271,7 @@ a pack's four widened sections used to make two gates *quieter* and still green.
|
|
|
270
271
|
One honest limit: the npx installer is checked by asserting its runtime bundle
|
|
271
272
|
walker exists, not by reading a file list — it has none by design. What proves
|
|
272
273
|
it ships the right files is CI, which installs the bundle through **both**
|
|
273
|
-
installers and `diff -r`s the result against the source, then builds all thirty-
|
|
274
|
+
installers and `diff -r`s the result against the source, then builds all thirty-four
|
|
274
275
|
kits.
|
|
275
276
|
|
|
276
277
|
`test/scenarios.md` (T1–T30) is the behavioral harness: fresh subagents given a
|
package/bin/cli.js
CHANGED
|
@@ -234,14 +234,17 @@ ${c("bold", "What it installs")}
|
|
|
234
234
|
DESIGN_SYNC_BRIDGE.md the Claude Design contract (what a pack sends, and
|
|
235
235
|
what does not cross)
|
|
236
236
|
AI_PRODUCT_PATTERNS.md chat / agent / streaming surfaces (honest state)
|
|
237
|
-
styles/ thirty-
|
|
237
|
+
styles/ thirty-four style packs — instrument-console (dark console),
|
|
238
238
|
editorial-luxury (warm editorial), workbench (light/dark
|
|
239
239
|
product UI), briefing-room (dark 16:9 presentation deck),
|
|
240
240
|
atrium (warm cream consumer health), patchbay (dark live
|
|
241
241
|
schematic), nameplate (a cool near-white slab under a
|
|
242
242
|
square page, the one round shape reserved for a white
|
|
243
243
|
bordered pill carrying somebody else's publication name
|
|
244
|
-
as type),
|
|
244
|
+
as type), rimlight (a white field and one near-black
|
|
245
|
+
act, a monospace carrying every label and button, and
|
|
246
|
+
an elevation made of coloured light rather than a
|
|
247
|
+
shadow), babylove (white +
|
|
245
248
|
one orange, seven tokens over Tailwind defaults),
|
|
246
249
|
outrank (white +
|
|
247
250
|
one violet, a landing and a dashboard in one brand),
|
|
@@ -107,7 +107,12 @@ the one round shape reserved for a white 1px-bordered pill carrying somebody
|
|
|
107
107
|
else's publication name as type, one family with the body at weight 500, and two
|
|
108
108
|
uppercase registers tracked 0.06em and 0.175em, for pages whose argument is that
|
|
109
109
|
named third parties will vouch for you: press placement, trust marks,
|
|
110
|
-
certification and review aggregation
|
|
110
|
+
certification and review aggregation;
|
|
111
|
+
rimlight — a white field with a cool grey act separator and one near-black act, a
|
|
112
|
+
grotesque for every sentence and a monospace for every piece of chrome, square on 84%
|
|
113
|
+
of its elements, tracked negative at every size and with no bold anywhere, whose only
|
|
114
|
+
elevation is a sixteen-layer coloured light rig thrown from below-left onto one
|
|
115
|
+
control per viewport, for a studio's front door and its service and case-study pages);
|
|
111
116
|
otherwise follow the contract below (self-contained on purpose).
|
|
112
117
|
|
|
113
118
|
## Whether to animate at all — before how
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: Signature
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The report surface's one repeated object: a `--mark-tile` (50px) square at
|
|
6
|
+
`--mark-tile-r`, wearing a **5px solid ring** in `--mark-tile-ring` — not a hairline —
|
|
7
|
+
with a 1px `--mark-tile-edge` outside it, a wash background at 9–12% alpha and a glyph
|
|
8
|
+
in the matching solid.
|
|
9
|
+
|
|
10
|
+
**`tone` is variety, not meaning, and that is why it is a number.** The five hues do
|
|
11
|
+
not separate from each other — seven of their fifteen pairs are tight, and the
|
|
12
|
+
reference's own indigo and violet are 5.58 OKLab units apart at full colour — so no
|
|
13
|
+
reader can reliably tell two marks apart and nothing may require it. The icon and the
|
|
14
|
+
label carry which feature this is. `tone="neutral"` exists because the reference's
|
|
15
|
+
sixth hue was its red, 2.92 units from `--action-to`: a mark in the action's colour
|
|
16
|
+
reads as a control, so the coral stays with the action.
|
|
17
|
+
|
|
18
|
+
The glyph clears the 3:1 non-text floor on its own tile and nothing more. It is never
|
|
19
|
+
a word, and the tile is never a button.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<Mark tone={1} label="Distribution">{/* icon */}</Mark>
|
|
23
|
+
<Mark tone="neutral" label="Reporting">{/* icon */}</Mark>
|
|
24
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface MarkProps {
|
|
4
|
+
/** The glyph. An icon, never a word — the hue clears only the non-text floor. */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
/** Decorative variety across a grid, 1–5, or the neutral. It carries no meaning:
|
|
7
|
+
* the set does not separate from itself, so nothing may depend on telling two
|
|
8
|
+
* marks apart. The icon and the label say which feature this is. */
|
|
9
|
+
tone?: 1 | 2 | 3 | 4 | 5 | 'neutral';
|
|
10
|
+
/** Accessible name for the tile, since the glyph inside is decorative. */
|
|
11
|
+
label?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Mark({ children, tone = 1, label, className }: MarkProps) {
|
|
16
|
+
return (
|
|
17
|
+
<span
|
|
18
|
+
className={['np-mark', `np-mark--${tone}`, className].filter(Boolean).join(' ')}
|
|
19
|
+
role={label ? 'img' : undefined}
|
|
20
|
+
aria-label={label}
|
|
21
|
+
aria-hidden={label ? undefined : true}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</span>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -257,6 +257,50 @@
|
|
|
257
257
|
--lift-sm: 1px;
|
|
258
258
|
--reveal-y: 10px;
|
|
259
259
|
|
|
260
|
+
/* ---- Marks: decorative variety across a grid, NOT a taxonomy -------- */
|
|
261
|
+
/* MEASURED off the report showcase the home page embeds: a 50x50 icon tile at
|
|
262
|
+
16px radius, a 5px solid ring in --mark-tile-ring, a 1px outer ring at 8%
|
|
263
|
+
ink, its background one tint at 9-12% alpha and its glyph the matching
|
|
264
|
+
solid. The reference ships six of these pairs and this pack ships five plus
|
|
265
|
+
a neutral, for two measured reasons.
|
|
266
|
+
|
|
267
|
+
FIRST, the sixth is the action. The reference's red mark #d94558 sits 2.92
|
|
268
|
+
OKLab units from --action-to and 1.12 under the worst dichromacy: the same
|
|
269
|
+
colour to everyone, not only to a colourblind reader. A mark in the action's
|
|
270
|
+
colour reads as a control, so the coral belongs to --action alone and the
|
|
271
|
+
sixth slot takes --mark-neutral.
|
|
272
|
+
|
|
273
|
+
SECOND, and this is why the tokens are numbered rather than named: the set
|
|
274
|
+
does NOT separate from itself. Seven of the fifteen pairs are tight, and the
|
|
275
|
+
reference's own indigo #5b4bd4 and violet #6c5ce7 are 5.58 apart at full
|
|
276
|
+
colour, which is one colour wearing two names. So the hue here is variety,
|
|
277
|
+
never meaning -- it does not encode WHICH feature this is, and nothing may
|
|
278
|
+
depend on telling two marks apart. The icon and the label carry that, and a
|
|
279
|
+
numbered token cannot be mistaken for a semantic one. */
|
|
280
|
+
--mark-tile-r: 16px; /* MEASURED */
|
|
281
|
+
--mark-tile: 50px; /* MEASURED */
|
|
282
|
+
--mark-tile-ring: #f7f8fc; /* MEASURED — a 5px solid ring, not a hairline */
|
|
283
|
+
--mark-tile-ring-w: 5px; /* MEASURED */
|
|
284
|
+
--mark-tile-edge: rgba(34, 36, 76, 0.08); /* MEASURED — 0 0 0 1px, outside the ring */
|
|
285
|
+
|
|
286
|
+
/* Each solid clears the 3:1 non-text floor on its own composited tile, which is
|
|
287
|
+
the only floor it owes: it is a glyph. None of them may carry a word — see
|
|
288
|
+
the pack's Bans, where three of the five miss AA on --field as text. */
|
|
289
|
+
--mark-1: #187c59; /* 4.53:1 on #ecf1f2, its own tile */
|
|
290
|
+
--mark-1-wash: rgba(31, 157, 107, 0.1); /* MEASURED */
|
|
291
|
+
--mark-2: #247cb0; /* 4.01:1 on #ecf0f7, its own tile */
|
|
292
|
+
--mark-2-wash: rgba(49, 144, 199, 0.1); /* MEASURED */
|
|
293
|
+
--mark-3: #5b4bd4; /* 5.36:1 on #eeeefa, its own tile */
|
|
294
|
+
--mark-3-wash: rgba(108, 92, 231, 0.1); /* MEASURED */
|
|
295
|
+
--mark-4: #b36b18; /* 3.69:1 on #f5f0ef, its own tile */
|
|
296
|
+
--mark-4-wash: rgba(227, 165, 60, 0.12); /* MEASURED — the one tint at 12% */
|
|
297
|
+
--mark-5: #6c5ce7; /* 4.26:1 on #efeffa, its own tile */
|
|
298
|
+
--mark-5-wash: rgba(108, 92, 231, 0.09); /* MEASURED — 9%, the lightest */
|
|
299
|
+
/* DERIVED, and it replaces the reference's red for the reason above. It is
|
|
300
|
+
--ink-mid, so a grid whose sixth block has no hue left still has a mark. */
|
|
301
|
+
--mark-neutral: #374151; /* 8.84:1 on #ecedf2, its own tile */
|
|
302
|
+
--mark-neutral-wash: rgba(55, 65, 81, 0.1);
|
|
303
|
+
|
|
260
304
|
/* ---- Status: the action is red, so danger goes dark ----------------- */
|
|
261
305
|
/* SELECTED, all four — a marketing site paints no error state — and each is a
|
|
262
306
|
step of a hue the reference itself carries: its #187c59 green, its #b36b18
|
|
@@ -281,10 +325,13 @@
|
|
|
281
325
|
font-weight: var(--weight-body);
|
|
282
326
|
}
|
|
283
327
|
|
|
284
|
-
/* No dark theme block, and that is a measurement rather than an omission
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
328
|
+
/* No dark theme block, and that is a measurement rather than an omission. No dark
|
|
329
|
+
band PAINTS on any served page: every full-bleed block was walked at 1440 and the
|
|
330
|
+
footer computes white. The authored stylesheets do declare eight dark fills, and
|
|
331
|
+
both kinds were checked -- .bg-header-blue (#231b66) is dead CSS no served page
|
|
332
|
+
uses, and the one that renders (#1f2937) sits inside a mock of another product's
|
|
333
|
+
interface in the hero image. The #181b31 navy and the on-dark link colours beside
|
|
334
|
+
it paint nothing. A pack that shipped a dark variant here would be inventing one. */
|
|
288
335
|
|
|
289
336
|
/* The reference ships a real reduced-motion contract — 23 blocks across 7 of
|
|
290
337
|
its 11 authored stylesheets — and, unusually, gets the important part right:
|
|
@@ -325,6 +372,7 @@
|
|
|
325
372
|
.np-chip,
|
|
326
373
|
.np-frame,
|
|
327
374
|
.np-band,
|
|
375
|
+
.np-mark,
|
|
328
376
|
.np-shell {
|
|
329
377
|
box-sizing: border-box;
|
|
330
378
|
}
|
|
@@ -760,3 +808,25 @@ a.np-plate:active {
|
|
|
760
808
|
font-size: var(--t-sm);
|
|
761
809
|
letter-spacing: var(--track-caps-control);
|
|
762
810
|
}
|
|
811
|
+
|
|
812
|
+
/* ---- The mark tile: variety across a grid, never a control ------------- */
|
|
813
|
+
|
|
814
|
+
.np-mark {
|
|
815
|
+
display: grid;
|
|
816
|
+
place-items: center;
|
|
817
|
+
inline-size: var(--mark-tile);
|
|
818
|
+
block-size: var(--mark-tile);
|
|
819
|
+
border: var(--mark-tile-ring-w) solid var(--mark-tile-ring);
|
|
820
|
+
border-radius: var(--mark-tile-r);
|
|
821
|
+
box-shadow: 0 0 0 var(--line-w) var(--mark-tile-edge);
|
|
822
|
+
transition:
|
|
823
|
+
color var(--dur-base) var(--ease-out),
|
|
824
|
+
background-color var(--dur-base) var(--ease-out);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.np-mark--1 { background: var(--mark-1-wash); color: var(--mark-1); }
|
|
828
|
+
.np-mark--2 { background: var(--mark-2-wash); color: var(--mark-2); }
|
|
829
|
+
.np-mark--3 { background: var(--mark-3-wash); color: var(--mark-3); }
|
|
830
|
+
.np-mark--4 { background: var(--mark-4-wash); color: var(--mark-4); }
|
|
831
|
+
.np-mark--5 { background: var(--mark-5-wash); color: var(--mark-5); }
|
|
832
|
+
.np-mark--neutral { background: var(--mark-neutral-wash); color: var(--mark-neutral); }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pkg": "@sheleg-design/rimlight",
|
|
3
|
+
"globalName": "ShelegRimlight",
|
|
4
|
+
"shape": "package",
|
|
5
|
+
"buildCmd": "npm run build",
|
|
6
|
+
"srcDir": "src",
|
|
7
|
+
"tsconfig": "tsconfig.json",
|
|
8
|
+
"cssEntry": "src/styles.css",
|
|
9
|
+
"docsDir": "src",
|
|
10
|
+
"readmeHeader": ".design-sync/conventions.md",
|
|
11
|
+
"guidelinesGlob": [
|
|
12
|
+
"guidelines/*.md"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Rimlight — the contract this design system ships under
|
|
2
|
+
|
|
3
|
+
**Register.** Choose Rimlight for **a studio's own front door and the pages that sell
|
|
4
|
+
what it makes**: design and engineering agencies, product studios, service and
|
|
5
|
+
case-study pages, B2B surfaces whose argument is craft rather than a feature list. A
|
|
6
|
+
white field, a cool grey act separator, one near-black act, and coloured light where
|
|
7
|
+
other systems put a shadow. Build every screen against `var(--…)` and never a literal.
|
|
8
|
+
|
|
9
|
+
**Elevation is a light, and it belongs to one control.** `--glow-rig` is sixteen
|
|
10
|
+
layers — six lit and ten held at alpha 0, thrown from below and to the left. Exactly
|
|
11
|
+
one control per viewport wears it. Two lit controls and the light stops meaning *this
|
|
12
|
+
one*.
|
|
13
|
+
|
|
14
|
+
**The rig is static.** It does not change on hover, press or focus: the fill moves one
|
|
15
|
+
step and the light stays. Pulsing, rotating or hover-growing it is the first ban here,
|
|
16
|
+
and it is the single change that turns this pack into a novelty.
|
|
17
|
+
|
|
18
|
+
**The only other shadows are the tile's.** `--shadow-tile` on the 80px icon tile and
|
|
19
|
+
`--shadow-tile-inner` on its 68px image. Nothing else carries one — 483 of the
|
|
20
|
+
reference's 487 visible elements compute `box-shadow: none`. A card has no shadow and
|
|
21
|
+
no border; it is separated by the field it sits on.
|
|
22
|
+
|
|
23
|
+
**The monospace is the chrome.** Every nav item, button and label is Source Code Pro;
|
|
24
|
+
every sentence is Archivo. That split is how a reader tells a control from a statement
|
|
25
|
+
without reading either, and it is not decorative.
|
|
26
|
+
|
|
27
|
+
**Do not track the monospace.** `letter-spacing` computes to `normal` on every label
|
|
28
|
+
in the reference — the openness is the face's own advance width. Adding tracking is
|
|
29
|
+
the trap this pack sets for anyone matching it from a screenshot.
|
|
30
|
+
|
|
31
|
+
**No bold anywhere.** 500 is the heaviest weight and it belongs to the mono label; the
|
|
32
|
+
display runs at 400 and the lede at 300. The display is loud because it is 86px.
|
|
33
|
+
|
|
34
|
+
**Tracking is negative at every size and tightens as the display shrinks** —
|
|
35
|
+
`--track-display` (−0.02em) at 86px, `--track-display-narrow` (−0.04em) at the 40px
|
|
36
|
+
narrow headline.
|
|
37
|
+
|
|
38
|
+
**The blue is two tokens because it does two jobs.** `--accent` is 3.03:1 on `--bg`:
|
|
39
|
+
legal on a word only at WCAG large text, which at weight 400 means ≥ 24px. Anything
|
|
40
|
+
smaller takes `--accent-ink`. A 16px link in `--accent` is a word below the floor and
|
|
41
|
+
is the commonest way to break this pack while believing you matched it.
|
|
42
|
+
|
|
43
|
+
**The colours live in the dark act.** Every one of the reference's five secondary hues
|
|
44
|
+
is 6.5–10.5:1 on `#1b1b1b` and 1.65–2.65:1 on white. They were designed for the dark;
|
|
45
|
+
on a light field they are not text.
|
|
46
|
+
|
|
47
|
+
**`[data-surface="dark"]` is a section, never the document.** There is no toggle and
|
|
48
|
+
no second palette for the page — one band is dark and the rest stays light. Putting it
|
|
49
|
+
on `:root` inverts a page that was never designed to invert, and the light field's four
|
|
50
|
+
statuses measure 1.1–1.5:1 if they arrive unremapped.
|
|
51
|
+
|
|
52
|
+
**Status is never by colour alone** — every state takes a glyph or a label beside its
|
|
53
|
+
colour. The four roles are derived rather than adopted: the reference's own secondary
|
|
54
|
+
set is a palette, not a scheme, with eight of its twenty-one pairs too close to
|
|
55
|
+
separate under dichromacy.
|
|
56
|
+
|
|
57
|
+
**Every control clears `--tap-min` (44px).** A correction: 26 of the reference's 37
|
|
58
|
+
visible interactive elements at 390px are shorter than that.
|
|
59
|
+
|
|
60
|
+
**Nothing travels in space.** No parallax, no scrub, no `animation-timeline`, no press
|
|
61
|
+
translation. `MOTION_INTENSITY` above 2 has nothing legal to buy, and reduced motion
|
|
62
|
+
collapses every duration to zero.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @sheleg-design/rimlight
|
|
2
|
+
|
|
3
|
+
The React reference kit for the SHELEG **Rimlight** style pack — a white field, one
|
|
4
|
+
near-black act, a monospace carrying every piece of chrome, and an elevation made of
|
|
5
|
+
coloured light rather than shadow.
|
|
6
|
+
|
|
7
|
+
It is generated from the pack, not authored beside it: `src/styles.css` opens with
|
|
8
|
+
`styles/tokens/rimlight.css` byte for byte, and the rules the design agent must obey
|
|
9
|
+
are in [`.design-sync/conventions.md`](./.design-sync/conventions.md).
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install && npm run build
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## The spine
|
|
16
|
+
|
|
17
|
+
`Button`, `Card`, `Chip`, `Stat`, `Heading`, `Rule` — identical names, props and types
|
|
18
|
+
in every SHELEG kit, so switching packs swaps identity rather than API.
|
|
19
|
+
|
|
20
|
+
## This pack's own
|
|
21
|
+
|
|
22
|
+
`LitButton` (the sixteen-layer rig, one per viewport), `Tile` (the 80px icon square
|
|
23
|
+
that opens a section, and one of only two objects allowed an ordinary shadow), `Label`
|
|
24
|
+
(the monospace chrome — untracked, always) and `Act` (a full-bleed section, including
|
|
25
|
+
the dark one, which is a surface variant and never a document theme).
|
|
26
|
+
|
|
27
|
+
## The three rules that carry the kit
|
|
28
|
+
|
|
29
|
+
1. **One lit control per viewport.** The rig is the only chromatic event on a page
|
|
30
|
+
otherwise made of ink, one blue and two greys — so the most saturated thing on the
|
|
31
|
+
screen is also the thing you are meant to click. Two of them and that stops working.
|
|
32
|
+
2. **The light does not move.** It is deliberately absent from `.rl-lit`'s transition
|
|
33
|
+
list. A static light reads as craft; an animated one reads as a toy.
|
|
34
|
+
3. **The monospace is chrome and the grotesque is prose.** Never mix the two roles, and
|
|
35
|
+
never track the monospace.
|
|
36
|
+
|
|
37
|
+
**Motion does not cross into a design tool.** A kit is the static half of a pack: this
|
|
38
|
+
one is unusually literal about that, because the pack's whole motion budget is a 0.3s
|
|
39
|
+
colour transition.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sheleg-design/rimlight",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.6.0",
|
|
27
|
+
"@types/react": "^18.3.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: Surfaces
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
A full-bleed section on one of the pack's three fields. `field="dark"` sets
|
|
6
|
+
`data-surface="dark"`, which remaps the palette **for that band only**.
|
|
7
|
+
|
|
8
|
+
**It is not a dark mode.** The reference has no toggle and no second palette for the
|
|
9
|
+
document: one section carries the dark treatment and the rest of the page stays light.
|
|
10
|
+
Putting `data-surface="dark"` on `:root` inverts a page that was never designed to
|
|
11
|
+
invert.
|
|
12
|
+
|
|
13
|
+
The dark act is where the reference's colours finally work — every one of its
|
|
14
|
+
secondary hues is 6.5–10.5:1 there against 1.65–2.65:1 on white.
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
<Act>…</Act>
|
|
18
|
+
<Act field="dark">…</Act>
|
|
19
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ActProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** `page` is white, `field` the cool grey separator, `dark` the near-black act. */
|
|
6
|
+
field?: 'page' | 'field' | 'dark';
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** A full-bleed section. `dark` sets data-surface, which remaps the palette for the
|
|
11
|
+
* band only — it is a surface variant, never a document theme. */
|
|
12
|
+
export function Act({ children, field = 'page', className }: ActProps) {
|
|
13
|
+
return (
|
|
14
|
+
<section
|
|
15
|
+
className={['rl-act', `rl-act--${field}`, className].filter(Boolean).join(' ')}
|
|
16
|
+
data-surface={field === 'dark' ? 'dark' : undefined}
|
|
17
|
+
>
|
|
18
|
+
{children}
|
|
19
|
+
</section>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: Actions
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
The ordinary control: transparent with a `1px solid --ink-faint` border at `--r-pill`
|
|
6
|
+
(160px), its label the monospace at 16–18px/500 uppercase, height `--control-h` (48px)
|
|
7
|
+
or `--control-h-lg` (60px).
|
|
8
|
+
|
|
9
|
+
`primary` fills with `--ink` and takes `--on-ink`. **It does not wear the rig** — that
|
|
10
|
+
belongs to `LitButton`, one per viewport. Hover moves the border to `--ink` and never
|
|
11
|
+
adds a fill; nothing on this page travels in space.
|
|
12
|
+
|
|
13
|
+
Every size honours `--tap-min` (44px) as a floor.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<Button variant="secondary">View project</Button>
|
|
17
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps {
|
|
4
|
+
/** `primary` is the accent fill — at most one per view. */
|
|
5
|
+
variant?: 'primary' | 'secondary' | 'ghost';
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
onClick?: () => void;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function Button({
|
|
14
|
+
variant = 'primary',
|
|
15
|
+
size = 'md',
|
|
16
|
+
disabled = false,
|
|
17
|
+
onClick,
|
|
18
|
+
children,
|
|
19
|
+
className,
|
|
20
|
+
}: ButtonProps) {
|
|
21
|
+
return (
|
|
22
|
+
<button
|
|
23
|
+
type="button"
|
|
24
|
+
className={['rl-btn', `rl-btn--${variant}`, `rl-btn--${size}`, className]
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join(' ')}
|
|
27
|
+
disabled={disabled}
|
|
28
|
+
onClick={onClick}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
}
|