sheleg-design-skill 1.34.0 → 1.35.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +6 -4
  3. package/bin/cli.js +9 -2
  4. package/cursor/rules/sheleg-design.mdc +9 -1
  5. package/kits/awning/.design-sync/config.json +14 -0
  6. package/kits/awning/.design-sync/conventions.md +34 -0
  7. package/kits/awning/README.md +15 -0
  8. package/kits/awning/package.json +29 -0
  9. package/kits/awning/src/Button.md +23 -0
  10. package/kits/awning/src/Button.tsx +33 -0
  11. package/kits/awning/src/Card.md +18 -0
  12. package/kits/awning/src/Card.tsx +23 -0
  13. package/kits/awning/src/Chip.md +22 -0
  14. package/kits/awning/src/Chip.tsx +21 -0
  15. package/kits/awning/src/FeatureRow.md +15 -0
  16. package/kits/awning/src/FeatureRow.tsx +21 -0
  17. package/kits/awning/src/Heading.md +15 -0
  18. package/kits/awning/src/Heading.tsx +17 -0
  19. package/kits/awning/src/PlanCard.md +19 -0
  20. package/kits/awning/src/PlanCard.tsx +40 -0
  21. package/kits/awning/src/ProductFrame.md +18 -0
  22. package/kits/awning/src/ProductFrame.tsx +20 -0
  23. package/kits/awning/src/Rule.md +13 -0
  24. package/kits/awning/src/Rule.tsx +15 -0
  25. package/kits/awning/src/Stat.md +12 -0
  26. package/kits/awning/src/Stat.tsx +17 -0
  27. package/kits/awning/src/index.ts +21 -0
  28. package/kits/awning/src/styles.css +363 -0
  29. package/kits/awning/tsconfig.json +20 -0
  30. package/kits/ledger/.design-sync/config.json +12 -0
  31. package/kits/ledger/.design-sync/conventions.md +58 -0
  32. package/kits/ledger/README.md +20 -0
  33. package/kits/ledger/package.json +29 -0
  34. package/kits/ledger/src/Button.md +20 -0
  35. package/kits/ledger/src/Button.tsx +33 -0
  36. package/kits/ledger/src/Card.md +21 -0
  37. package/kits/ledger/src/Card.tsx +24 -0
  38. package/kits/ledger/src/Chip.md +18 -0
  39. package/kits/ledger/src/Chip.tsx +25 -0
  40. package/kits/ledger/src/DataTable.md +25 -0
  41. package/kits/ledger/src/DataTable.tsx +70 -0
  42. package/kits/ledger/src/EmptyState.md +19 -0
  43. package/kits/ledger/src/EmptyState.tsx +47 -0
  44. package/kits/ledger/src/Heading.md +18 -0
  45. package/kits/ledger/src/Heading.tsx +19 -0
  46. package/kits/ledger/src/Kicker.md +16 -0
  47. package/kits/ledger/src/Kicker.tsx +16 -0
  48. package/kits/ledger/src/Rule.md +12 -0
  49. package/kits/ledger/src/Rule.tsx +18 -0
  50. package/kits/ledger/src/Seal.md +30 -0
  51. package/kits/ledger/src/Seal.tsx +34 -0
  52. package/kits/ledger/src/SegmentedControl.md +21 -0
  53. package/kits/ledger/src/SegmentedControl.tsx +41 -0
  54. package/kits/ledger/src/Stat.md +17 -0
  55. package/kits/ledger/src/Stat.tsx +17 -0
  56. package/kits/ledger/src/StatusDot.md +17 -0
  57. package/kits/ledger/src/StatusDot.tsx +32 -0
  58. package/kits/ledger/src/index.ts +27 -0
  59. package/kits/ledger/src/styles.css +702 -0
  60. package/kits/ledger/tsconfig.json +20 -0
  61. package/package.json +2 -2
  62. package/plugins/sheleg-design/.claude-plugin/plugin.json +2 -2
  63. package/plugins/sheleg-design/commands/sheleg-design.md +1 -1
  64. package/plugins/sheleg-design/skills/sheleg-design/DESIGN_SYNC_BRIDGE.md +1 -1
  65. package/plugins/sheleg-design/skills/sheleg-design/MOBILE_SURFACES.md +1 -1
  66. package/plugins/sheleg-design/skills/sheleg-design/SKILL.md +11 -7
  67. package/plugins/sheleg-design/skills/sheleg-design/SURFACE_COMPOSITION.md +3 -3
  68. package/plugins/sheleg-design/skills/sheleg-design/styles/awning.md +278 -0
  69. package/plugins/sheleg-design/skills/sheleg-design/styles/ledger.md +387 -0
  70. package/plugins/sheleg-design/skills/sheleg-design/styles/paperclip.md +9 -0
  71. package/plugins/sheleg-design/skills/sheleg-design/styles/scoreboard.md +8 -0
  72. package/plugins/sheleg-design/skills/sheleg-design/styles/showroom.md +16 -0
  73. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/awning.css +196 -0
  74. package/plugins/sheleg-design/skills/sheleg-design/styles/tokens/ledger.css +233 -0
  75. package/plugins/sheleg-design/skills/sheleg-design/styles/workbench.md +11 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,122 @@ All notable changes to this project are documented in this file. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
5
5
  follow [SemVer](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.35.0] - 2026-08-15
8
+
9
+ **The twenty-first pack, and two counts that had been wrong for eight releases.**
10
+ `ledger` was extracted from `basedash.com` — a warm cream console for a product
11
+ that answers questions about data. Adding it walked the library past twenty for
12
+ the first time, which is where two gates turned out to have been counting with a
13
+ table that stopped at twenty and a regex that read one modifier word.
14
+
15
+ ### Added
16
+
17
+ - **`ledger` — style pack 21 (widened contract, standalone product UI).** Warm
18
+ cream field `#fcf9f5` under `#14100c` ink, elevation as a **1px hairline at 12%
19
+ ink and no shadow on any card**, the reference's ×1.25 radius ramp nested
20
+ concentrically (a 15px track with 4px of padding holds a 10px thumb), an **ink**
21
+ primary button, and a terracotta `#c2410c` that **never fills a control** — of
22
+ eleven accent-coloured elements on the reference, five are a 10px monospace
23
+ uppercase kicker and none is a button. 32px data rows in the system monospace;
24
+ the large figure on a stat tile is the UI face at 34px, not the mono, which is
25
+ what the reference actually does. Light `:root` plus a `[data-theme="dark"]`
26
+ twin whose alpha ramp is a different set of steps rather than the light one
27
+ inverted.
28
+ - **Signature element: the seal in a card's title row** — `Verified` /
29
+ `Inferred` / `Unverified`, linking to the proof. It is
30
+ `AI_PRODUCT_PATTERNS.md` §4's provenance tag applied to a card instead of a
31
+ span, and it maps onto three tokens the pack already ships, so implementing
32
+ it adds no hue.
33
+ - **`--warn` is derived and says so at the declaration**, per the template's
34
+ rule 3: the reference declares an amber in its theme layer and never paints a
35
+ warning. The step differs per theme because at amber-500 the *dark* accent and
36
+ the warning are 7.1 apart at full colour — one colour with two meanings, below
37
+ the hard floor. amber-300 is 16.2 apart and clears every dichromacy.
38
+ - **`--chart-1` … `--chart-5` are named for shadcn/ui**, so a Recharts series
39
+ reads the pack's chart ramp through `ChartConfig` with no adapter.
40
+ - **`kits/ledger`** — twelve components: the six-name spine plus `Seal`,
41
+ `Kicker`, `DataTable`, `SegmentedControl`, `StatusDot` and an `EmptyState` that
42
+ carries the capability and two runnable example questions.
43
+
44
+ ### Fixed
45
+
46
+ - **The counted-claims gate could not count past twenty.** `NUMBER_WORDS` stopped
47
+ there, so every correct "twenty-one packs" was read as **"one packs"** and
48
+ failed, in nine files at once. The table now runs to thirty, the alternation is
49
+ longest-first, and a lookbehind refuses a match that starts mid-compound. Two
50
+ planted-defect fixtures had the same hyphen blindness and one of them had
51
+ stopped mutating anything — a plant that changes nothing reports BROKEN, which
52
+ is how it was found.
53
+ - **A count with two modifier words was never read as a count at all.** The regex
54
+ allowed one of `visual `/`style `, and both manifests say "pluggable **visual
55
+ style** packs". Widening it to `*` immediately surfaced two stale numbers: the
56
+ plugin description said **twenty** on the day twenty-one shipped, and
57
+ `marketplace.json`'s own top-level description had said **thirteen** since the
58
+ thirteenth pack — eight releases, in the two files an agent host reads first.
59
+ - **The core-contract paragraph's two regexes matched `\w+`**, so a hyphenated
60
+ total failed to parse and the check reported the paragraph missing rather than
61
+ wrong.
62
+
63
+ ### Known limitation
64
+
65
+ - `validate_pack_enumerations` tests membership by **substring**, so `ledger`
66
+ passed in four files that merely described `scoreboard` as carrying "a dark
67
+ ledger". The four were filled in by hand and are now genuinely exhaustive; the
68
+ check that would have caught it — a name in a context that routes to it — is
69
+ not written.
70
+
71
+ ## [1.35.0] - 2026-08-15
72
+
73
+ **A twenty-second pack, and the reference it was asked for did not survive measurement.**
74
+ The request was "a pack in the style of taskip.net". Taskip turned out to be WordPress and
75
+ Elementor over a bought theme (Xilancer), carrying **three token systems that disagree** —
76
+ the theme's declared primary `#6074f6` appears nowhere on the rendered page, the visible
77
+ emerald lives in a second sheet, and a third set of values is Tailwind slate. Twelve radius
78
+ values, six shadows, seven weights, four font families, and `.3s` / `0.3s` / `300ms` written
79
+ as three different things. That is a page-builder output, not a vocabulary, and this library
80
+ exists on the premise that a pack is the reference's own vocabulary rather than a
81
+ reconstruction of one. It was declined as a source and the register was re-sourced instead.
82
+
83
+ ### Added — `awning`, the twenty-second pack
84
+
85
+ Origin: <https://www.shopify.com>, read 2026-08-15 from the served HTML plus its six linked
86
+ stylesheets. Chosen after measuring five candidates on the same axes; it was the only one
87
+ that paired the register with a real system.
88
+
89
+ - **The accent is black, and it is a resolved chain rather than a stylistic absence.**
90
+ `--color-component-button-primary-bg` → `--color-theme-bg-cta` → `#000`, with hover, active
91
+ and disabled declared beside it. No hue reaches the chrome at all, which is what leaves
92
+ every colour on the page belonging to the product screenshot inside it.
93
+ - **A three-tier token layer** — primitives, semantic roles, per-component states — so the
94
+ pack ships the indirection rather than the resolved values. `--radius-component-button:
95
+ var(--radius-theme-full)` is the only place the system says *why* a button is a pill.
96
+ - **420 and 550, and no 700 anywhere.** A variable grotesque used as one. Setting a heading
97
+ in 700 here is not a small deviation; it is the one number the system was built to avoid.
98
+ - **Tracking crosses zero inside one family** — negative on the display ramp, positive on the
99
+ body ramp, crossover around 1.375rem — where most packs in this library split tracking
100
+ across two faces.
101
+ - **Leading ships paired with size in `rem`**, not as a ratio, and the ratio *changes* down
102
+ the ramp: 1.08 at display, 1.12 at t2, 1.30 at t7.
103
+ - **One shadow, three layers** — ambient, contact, and a `0 0 2px` hairline edge that is what
104
+ stops a card dissolving on pure white. That third layer is the one people drop when they
105
+ copy a shadow by eye.
106
+ - Six Gotchas, three of them defects in the reference: `--ink-faint` at **4.40:1 on the
107
+ system's own second field**; three eases named as tokens against **ten unnamed inline
108
+ durations**; and `ease-in` shipped as a token while the doctrine bans it in UI.
109
+ - Routed through all seven surfaces the validator checks, mirrored to `.cursor`, added to
110
+ `install.sh`, and shipped with `kits/awning` — the six-name spine on the canonical API plus
111
+ `ProductFrame`, `PlanCard` and `FeatureRow`.
112
+
113
+ ### Fixed
114
+
115
+ - `paperclip` and `showroom` now link **back** to `awning`. The validator caught the one-way
116
+ fork: a neighbour reference that only points one direction is a dead end for anyone who
117
+ reaches the other pack first.
118
+ - Nine stated counts moved from twenty-one to twenty-two across `SKILL.md`, `README.md`,
119
+ `package.json`, both manifests, `bin/cli.js`, `MOBILE_SURFACES.md`, `SURFACE_COMPOSITION.md`
120
+ and `DESIGN_SYNC_BRIDGE.md`, plus core-contract packs from six to seven. Every one was
121
+ caught by the gate rather than remembered.
122
+
7
123
  ## [1.34.0] - 2026-08-15
8
124
 
9
125
  **The pack was applied correctly and the result still read as somebody else's typography.**
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 **twenty locked style
14
+ decides whether to animate before it decides how, and **twenty-two 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
 
@@ -65,6 +65,8 @@ into the cinematic layer, and says so in its own *Motion flavor* section.
65
65
  | `ora` | a warm coal field with cream ink and **no third hue** — the accent is the inverted field, so the one solid object on a page is the one meant to be pressed — a serif doing the sans job over a monospace that carries every machine fact, a terminal surface cut *below* the page plane, a six-step verdict ramp, and dark as the default theme rather than the option | products whose output is **a machine's verdict about the reader** — agent-readiness and crawlability scores, SEO and answer-engine audits, agent-run traces, MCP and protocol surfaces, bot observability |
66
66
  | `tenor` | warm paper with **zero radius and zero shadow anywhere**, a single hairline weight assembling every lattice, and one orange that exists only on hover and on focus — so the page screenshots with no colour in it at all — a sans held at weight 400 and tracked negative against a mono tracked positive, display at a line-height below one in an eight-to-twelve-character measure, and proof delivered as silent looping video in a 1px rectangle | products arguing a **management thesis** — that a new kind of thing has to be run like an existing organisation: AI-workforce and agent-operations platforms, autonomous back-office, revenue and sales operations, sold to the director who will have to manage it |
67
67
  | `paperclip` | neutral coal with **no functional colour at all** — every control monochrome, elevation made of hairlines, and the whole chromatic budget spent on a curtain of 96 gradient capsules and twelve gradient section badges that cannot be clicked — a tight grotesque over a plain one over a monospace, and the capsule as the shape of everything from a button to a 10 × 20 schedule tick | products that ask a person to **run something that runs itself** — agent teams and orchestrators, autonomous back-office, schedulers, job runners, budget-governed compute |
68
+ | `awning` | white forecourt where **the accent is black** and no hue reaches the chrome at all; a pill whose radius is a declared component token, one variable grotesque at **420 / 550 with no 700**, two rule weights and a single three-layer shadow | commerce and platform front doors — the surface that sells a system other businesses will run their storefront, payroll, billing or logistics on |
69
+ | `ledger` | warm cream paper where elevation is a **1px hairline at 12% ink** and no card casts a shadow, radii of 7.5/10/15/20 nested concentrically, an **ink** primary button, and a terracotta accent forbidden from filling any control — it labels, as a 10px monospace uppercase kicker — over 32px data rows, with a seal on every card stating how its number is known | the console of a product that answers questions **about data** — AI analysts, BI surfaces, query workspaces, agents that read a warehouse and write back a figure |
68
70
 
69
71
  Each pack locks palette, type, texture, motion tokens, signature motifs and
70
72
  bans — and ships a `tokens/<pack>.css` to copy verbatim, so the agent never
@@ -139,7 +141,7 @@ skills.
139
141
  | `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 |
140
142
  | `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 |
141
143
  | `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 |
142
- | `styles/*.md` | The twenty style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
144
+ | `styles/*.md` | The twenty-two style packs — palette, type, texture, motion tokens, motifs, bans, and the traps each one carries |
143
145
  | `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) |
144
146
  | `styles/STYLE_PACK_TEMPLATE.md` | The pack contract as a skeleton, so a new style is authored against the same headings rather than improvised |
145
147
 
@@ -210,7 +212,7 @@ cd ./ds-workbench && npm install && npm run build
210
212
  then `/design-sync` in that directory, from Claude Code. Three layers cross: the
211
213
  pack's **bans** as the design system's own README, `styles.css` built from
212
214
  `tokens/<pack>.css` verbatim, and the components — a six-name spine that is
213
- identical in all twenty kits, so switching packs swaps identity rather than API,
215
+ identical in all twenty-two kits, so switching packs swaps identity rather than API,
214
216
  plus each pack's signature parts. **Motion does not cross**, exactly as it does
215
217
  not cross into Figma: a kit is the static half of a pack, and saying so is what
216
218
  stops an agent inventing motion to fill the silence.
@@ -256,7 +258,7 @@ a pack's four widened sections used to make two gates *quieter* and still green.
256
258
  One honest limit: the npx installer is checked by asserting its runtime bundle
257
259
  walker exists, not by reading a file list — it has none by design. What proves
258
260
  it ships the right files is CI, which installs the bundle through **both**
259
- installers and `diff -r`s the result against the source, then builds all twenty
261
+ installers and `diff -r`s the result against the source, then builds all twenty-two
260
262
  kits.
261
263
 
262
264
  `test/scenarios.md` (T1–T19) is the behavioral harness: fresh subagents given a
package/bin/cli.js CHANGED
@@ -234,7 +234,7 @@ ${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/ twenty style packs — instrument-console (dark console),
237
+ styles/ twenty-two 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), orchard (friendly
@@ -258,7 +258,14 @@ ${c("bold", "What it installs")}
258
258
  on hover, and proof delivered as silent looping video),
259
259
  paperclip (neutral coal with no functional colour at all
260
260
  and one curtain of gradient capsules that cannot be
261
- clicked, for products that run themselves)
261
+ clicked, for products that run themselves),
262
+ ledger (warm cream paper ruled by a hairline at 12% ink,
263
+ an ink primary button, a terracotta that only labels, and
264
+ a seal on every card saying how its number is known),
265
+ awning (a white forecourt where the accent is black and
266
+ no hue reaches the chrome, a pill whose radius is a
267
+ declared component token, and one variable grotesque at
268
+ 420/550 with no 700) —
262
269
  plus a ready-made token CSS per pack and
263
270
  STYLE_PACK_TEMPLATE.md for authoring more
264
271
  `);
@@ -56,7 +56,15 @@ existing organisation; paperclip — neutral coal with no functional colour
56
56
  anywhere, every control monochrome and elevation made of hairlines, the whole
57
57
  chromatic budget spent on a curtain of gradient capsules and a row of gradient
58
58
  section badges that cannot be clicked, for products that ask a person to run
59
- something that runs itself);
59
+ something that runs itself); ledger — warm cream paper where elevation is a
60
+ hairline at 12% ink and no card casts a shadow, an ink primary button and a
61
+ terracotta that never fills a control but labels in 10px monospace uppercase,
62
+ over 32px data rows, with a seal on every card saying how its number is known,
63
+ for the console of a product that answers questions about data);
64
+ awning — a white forecourt where the accent is black and no hue reaches the
65
+ chrome at all, a pill whose radius is a declared component token, one variable
66
+ grotesque at 420/550 with no 700, two rule weights and a single three-layer
67
+ shadow, for commerce and platform front doors);
60
68
  otherwise follow the contract below (self-contained on purpose).
61
69
 
62
70
  ## Whether to animate at all — before how
@@ -0,0 +1,14 @@
1
+ {
2
+ "pkg": "@sheleg-design/awning",
3
+ "globalName": "ShelegAwning",
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,34 @@
1
+ # Awning — the rules this design system is built on
2
+
3
+ A pure white forecourt for a product other businesses will run their own
4
+ business on. **The accent is black.** No hue reaches the chrome at all, which is
5
+ what leaves every colour on the page belonging to the thing being sold.
6
+ Extracted from a production reference (shopify.com, 2026-08-15) whose delivered
7
+ CSS carries a real three-tier token system; the full pack, with every
8
+ measurement and every trap, is `styles/awning.md` in the sheleg-design skill.
9
+
10
+ **This is the static half of a pack.** Motion does not cross this boundary:
11
+ build screens from these components, never a scroll narrative around them.
12
+
13
+ ## Bans — what this system never does
14
+
15
+ - **No accent hue.** Not on a button, a link, a tab, a badge or a focus ring.
16
+ The primary action is black; the moment chrome takes a colour, the screenshot
17
+ inside it stops being the only colourful thing on the page.
18
+ - **No weight of 700.** Body is **420** and bold is **550**, both off the
19
+ standard axis and both reachable only because the face is variable. Setting a
20
+ heading in 700 is the one number this system was built to avoid.
21
+ - **No second shadow.** One three-layer token — ambient, contact, and a hairline
22
+ edge that keeps a card legible on pure white. Dropping the third layer is why
23
+ a copied card floats without sitting.
24
+ - **No `clamp()` in the type layer.** Size and leading ship as a paired `rem`
25
+ value so they cannot drift; a fluid step breaks the pair.
26
+ - **Status is never by colour alone.** The derived red and green collapse toward
27
+ each other under deuteranopia at a measured 5.2 against a floor of 8.0, so
28
+ every state carries its word.
29
+
30
+ ## The two shapes
31
+
32
+ Surfaces take the radius scale — `0.375 / 0.5 / 0.75 / 1rem`. **Buttons take
33
+ `--radius-full`,** and they take it through `--radius-button`, which is the only
34
+ place the system says why a button is a pill. Keep the indirection.
@@ -0,0 +1,15 @@
1
+ # @sheleg-design/awning
2
+
3
+ The static half of the SHELEG **Awning** style pack — a white forecourt where the
4
+ accent is black and no hue reaches the chrome.
5
+
6
+ Extracted from a production reference (shopify.com, read 2026-08-15). The full
7
+ pack, with every measurement and every trap, is
8
+ `styles/awning.md` in the sheleg-design skill.
9
+
10
+ ```bash
11
+ npm install && npm run build
12
+ ```
13
+
14
+ `src/styles.css` opens with `styles/tokens/awning.css` copied byte for byte;
15
+ everything under `/* ── components ── */` consumes `var(--…)` only.
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@sheleg-design/awning",
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,23 @@
1
+ ---
2
+ category: Actions
3
+ ---
4
+
5
+ The primary button is a **black pill**. Its radius comes from `--radius-button`,
6
+ which points at `--radius-full` — the indirection is the only place the system
7
+ says why a button is that shape, so keep it rather than writing `9999px`.
8
+
9
+ Hover changes **two** properties: the fill lightens to `--accent-hover` and the
10
+ label moves to `--accent-ink-hover`. Moving only the fill reads as a lightening;
11
+ moving both reads as a press. `secondary` is transparent at every state — fill,
12
+ hover, active and disabled alike — so its whole identity is the border and the
13
+ label, which is why this pack ships two rule weights.
14
+
15
+ Disabled is a **value**, not an opacity: `--accent-disabled` fill with
16
+ `--accent-ink-disabled` content. Nothing in this system fades, so a disabled
17
+ control keeps its edges and stays measurable.
18
+
19
+ ```tsx
20
+ <Button onClick={start}>Start free trial</Button>
21
+ <Button variant="secondary" onClick={demo}>Watch the demo</Button>
22
+ <Button variant="ghost" size="sm" onClick={more}>Compare plans</Button>
23
+ ```
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ButtonProps {
4
+ /** `primary` is the BLACK pill — the accent, and there is no hue in the control set. */
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={['aw-btn', `aw-btn--${variant}`, `aw-btn--${size}`, className]
25
+ .filter(Boolean)
26
+ .join(' ')}
27
+ disabled={disabled}
28
+ onClick={onClick}
29
+ >
30
+ {children}
31
+ </button>
32
+ );
33
+ }
@@ -0,0 +1,18 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ `raised` carries the system's **one** shadow — three layers: a wide ambient, a
6
+ close contact, and a `0 0 2px` hairline edge. That third layer is what people
7
+ drop when they copy a shadow by eye, and dropping it is why a copied card floats
8
+ on white without sitting on it. There is no second shadow and no elevation
9
+ scale, so a card that needs to feel heavier needs a different layout, not a
10
+ bigger blur.
11
+
12
+ `flat` sits on `--bg-deep` with no shadow — use it when cards are tiled and the
13
+ shadows would otherwise stack into noise.
14
+
15
+ ```tsx
16
+ <Card><Heading level={3}>Point of sale</Heading><p>Sell anywhere.</p></Card>
17
+ <Card elevation="flat" radius="2xl">…</Card>
18
+ ```
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface CardProps {
4
+ title?: string;
5
+ /** Right-aligned metadata on the title row: a count, an id, a timestamp. */
6
+ meta?: string;
7
+ children: ReactNode;
8
+ className?: string;
9
+ }
10
+
11
+ export function Card({ title, meta, children, className }: CardProps) {
12
+ return (
13
+ <div className={['aw-card', className].filter(Boolean).join(' ')}>
14
+ {title ? (
15
+ <div className="aw-card__head">
16
+ <span className="aw-card__title">{title}</span>
17
+ {meta ? <span className="aw-card__meta">{meta}</span> : null}
18
+ </div>
19
+ ) : null}
20
+ {children}
21
+ </div>
22
+ );
23
+ }
@@ -0,0 +1,22 @@
1
+ ---
2
+ category: Data
3
+ ---
4
+
5
+ A chip is a **pill**, like the button — this system has two shapes and a chip
6
+ takes the round one.
7
+
8
+ `accent` is the **ink** fill, not a hue: this pack has no colour to tint a chip
9
+ with, so a selected or emphasised chip inverts exactly as the primary button
10
+ does. That constraint is the register rather than a limitation — it is what
11
+ keeps every colour on the page belonging to the product screenshot.
12
+
13
+ Where a chip must carry a *state*, put the word in it and take the colour from
14
+ `--good` / `--warn` / `--danger` in your own rule. Those three are derived, and
15
+ the red and the green collapse toward each other under deuteranopia at a
16
+ measured 5.2 against a floor of 8.0 — so the word is the primary encoding and
17
+ the colour is the second. A status chip with no word is a bug here.
18
+
19
+ ```tsx
20
+ <Chip>Draft</Chip>
21
+ <Chip tone="accent" selected>Monthly</Chip>
22
+ ```
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ChipProps {
4
+ children: ReactNode;
5
+ selected?: boolean;
6
+ /** `accent` is the INK fill — this pack has no hue to tint a chip with. */
7
+ tone?: 'neutral' | 'accent';
8
+ className?: string;
9
+ }
10
+
11
+ export function Chip({ children, selected = false, tone = 'neutral', className }: ChipProps) {
12
+ return (
13
+ <span
14
+ className={['aw-chip', `aw-chip--${tone}`, selected ? 'aw-chip--selected' : undefined, className]
15
+ .filter(Boolean)
16
+ .join(' ')}
17
+ >
18
+ {children}
19
+ </span>
20
+ );
21
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ category: Signature
3
+ ---
4
+
5
+ The catalogue unit. This register's page is long and sectioned, and a buyer
6
+ scrolls it to **compare** — so a capability is a row with a title and one
7
+ paragraph, not a card with an illustration. Rows are separated by `Rule`, never
8
+ by a gap alone, and the paragraph sits in `--ink-soft` because `--ink-faint`
9
+ does not clear AA on the second field.
10
+
11
+ ```tsx
12
+ <FeatureRow index="01" title="Checkout">
13
+ The fastest checkout on the internet, and it converts.
14
+ </FeatureRow>
15
+ ```
@@ -0,0 +1,21 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface FeatureRowProps {
4
+ title: string;
5
+ children: ReactNode;
6
+ /** A short mono index — `01`, `02` — when the row belongs to an ordered set. */
7
+ index?: string;
8
+ className?: string;
9
+ }
10
+
11
+ export function FeatureRow({ title, children, index, className }: FeatureRowProps) {
12
+ return (
13
+ <div className={['aw-feature', className].filter(Boolean).join(' ')}>
14
+ {index ? <span className="aw-feature__index">{index}</span> : null}
15
+ <div className="aw-feature__body">
16
+ <span className="aw-feature__title">{title}</span>
17
+ <p className="aw-feature__text">{children}</p>
18
+ </div>
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ category: Foundations
3
+ ---
4
+
5
+ Three steps off the reference's nine-step title ramp. Each carries its **paired**
6
+ size and leading — `3.5rem / 3.78rem`, `2.75rem / 2.97rem` — because the system
7
+ ships them as one token so they cannot drift apart. Do not substitute a ratio.
8
+
9
+ Weight is **550**, never 700. Tracking runs negative here and **positive** on
10
+ body text, both within the same family; the crossover sits around `1.375rem`.
11
+
12
+ ```tsx
13
+ <Heading level={1}>Everything you need to sell</Heading>
14
+ <Heading level={3}>Payments</Heading>
15
+ ```
@@ -0,0 +1,17 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface HeadingProps {
4
+ /** 1 = page title (`dsp`), 2 = section (`t1`), 3 = card title (`t3`). */
5
+ level?: 1 | 2 | 3;
6
+ children: ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ export function Heading({ level = 2, children, className }: HeadingProps) {
11
+ const Tag = `h${level}` as 'h1' | 'h2' | 'h3';
12
+ return (
13
+ <Tag className={['aw-h', `aw-h--${level}`, className].filter(Boolean).join(' ')}>
14
+ {children}
15
+ </Tag>
16
+ );
17
+ }
@@ -0,0 +1,19 @@
1
+ ---
2
+ category: Signature
3
+ ---
4
+
5
+ The commerce front door's load-bearing section. **A featured plan is featured by
6
+ fill, not by hue** — it inverts to `--ink` with `--bg` content, exactly as the
7
+ primary button does, because there is no accent colour to tint it with. At most
8
+ one per row; two featured plans is a row with no recommendation in it.
9
+
10
+ The price takes the `t1` step and the cadence the `b4`, so the number carries
11
+ and the interval does not compete with it.
12
+
13
+ ```tsx
14
+ <PlanCard
15
+ name="Basic" price="$29" cadence="per month"
16
+ features={['2 staff accounts', '10 locations']}
17
+ action={<Button size="sm">Start free trial</Button>}
18
+ />
19
+ ```
@@ -0,0 +1,40 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface PlanCardProps {
4
+ name: string;
5
+ price: ReactNode;
6
+ cadence?: string;
7
+ features: string[];
8
+ /** At most ONE plan per row is featured, and it is featured by fill, not by hue. */
9
+ featured?: boolean;
10
+ action: ReactNode;
11
+ className?: string;
12
+ }
13
+
14
+ export function PlanCard({
15
+ name,
16
+ price,
17
+ cadence,
18
+ features,
19
+ featured = false,
20
+ action,
21
+ className,
22
+ }: PlanCardProps) {
23
+ return (
24
+ <div
25
+ className={['aw-plan', featured ? 'aw-plan--featured' : '', className]
26
+ .filter(Boolean)
27
+ .join(' ')}
28
+ >
29
+ <span className="aw-plan__name">{name}</span>
30
+ <span className="aw-plan__price">{price}</span>
31
+ {cadence ? <span className="aw-plan__cadence">{cadence}</span> : null}
32
+ <ul className="aw-plan__features">
33
+ {features.map((f) => (
34
+ <li key={f}>{f}</li>
35
+ ))}
36
+ </ul>
37
+ <div className="aw-plan__action">{action}</div>
38
+ </div>
39
+ );
40
+ }
@@ -0,0 +1,18 @@
1
+ ---
2
+ category: Signature
3
+ ---
4
+
5
+ **The colourless chrome.** A full-colour screenshot of the product sits in a
6
+ frame that contains no hue at all — the card's radius, the one shadow, and
7
+ nothing else. This is the pack's second motif and the reason the accent is
8
+ black: every colour a reader sees on the page belongs to the thing being sold.
9
+
10
+ The frame carries a real `aria-label` describing what the shot shows. A frame
11
+ whose label repeats the section heading is a frame that told a screen-reader
12
+ user nothing.
13
+
14
+ ```tsx
15
+ <ProductFrame label="The orders list, filtered to unfulfilled">
16
+ <img src={shot} alt="" />
17
+ </ProductFrame>
18
+ ```
@@ -0,0 +1,20 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export interface ProductFrameProps {
4
+ /** Describe what the shot shows — this is the accessible name, not decoration. */
5
+ label: string;
6
+ children: ReactNode;
7
+ className?: string;
8
+ }
9
+
10
+ export function ProductFrame({ label, children, className }: ProductFrameProps) {
11
+ return (
12
+ <figure
13
+ className={['aw-frame', className].filter(Boolean).join(' ')}
14
+ role="img"
15
+ aria-label={label}
16
+ >
17
+ {children}
18
+ </figure>
19
+ );
20
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ category: Surfaces
3
+ ---
4
+
5
+ This pack ships **two** border weights, which is unusual in this library.
6
+ `--line` goes between rows; `--line-strong` goes around a control. The
7
+ difference is load-bearing: it is what makes an outlined secondary button read
8
+ as a control at all, given its fill is transparent in every state.
9
+
10
+ ```tsx
11
+ <Rule />
12
+ <Rule tone="strong" />
13
+ ```