@super-ic/web-patterns 0.0.0-oidc-bootstrap.0 → 0.1.9
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/README.md +309 -1
- package/contracts/contact-section.json +23 -0
- package/contracts/neighborhood-landing.json +162 -0
- package/contracts/public-content-refinement.json +38 -0
- package/css/case-study-card.css +29 -0
- package/css/contact-section.css +39 -0
- package/css/neighborhood-landing.css +143 -0
- package/css/powered-by-superic.css +33 -0
- package/css/public-content.css +187 -0
- package/css/tailwind.css +6 -0
- package/dist/case-study-card-types.d.ts +16 -0
- package/dist/case-study-card-types.js +1 -0
- package/dist/case-study-card.d.ts +66 -0
- package/dist/case-study-card.js +72 -0
- package/dist/contact-form.d.ts +56 -0
- package/dist/contact-form.js +75 -0
- package/dist/contact-section.d.ts +23 -0
- package/dist/contact-section.js +11 -0
- package/dist/editorial-image.d.ts +10 -0
- package/dist/editorial-image.js +18 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/neighborhood-landing.d.ts +129 -0
- package/dist/neighborhood-landing.js +26 -0
- package/dist/powered-by-superic.d.ts +10 -0
- package/dist/powered-by-superic.js +20 -0
- package/dist/public-content.d.ts +152 -0
- package/dist/public-content.js +48 -0
- package/dist/surface-radius.d.ts +20 -0
- package/dist/surface-radius.js +30 -0
- package/package.json +50 -8
package/README.md
CHANGED
|
@@ -1,3 +1,311 @@
|
|
|
1
1
|
# @super-ic/web-patterns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Marketing web patterns built on the SuperIC foundation token layer:
|
|
4
|
+
|
|
5
|
+
- `CaseStudyCard` (aliased as `CaseStudyCardShell`): the structural case-study
|
|
6
|
+
card: one whole-card control, a full-bleed 16:10 product-proof band, an
|
|
7
|
+
identity-first body, and an open/locked access contract.
|
|
8
|
+
- `SURFACE_RADIUS_TOKENS`, `SURFACE_RADIUS_CLASSES`, `nestedSurfaceRadius`: the
|
|
9
|
+
shared surface-radius scale used to keep nested surfaces concentric.
|
|
10
|
+
- `CaseStudyCardProvenance`, `CaseStudyCardProductAccess`: the **shape** of the
|
|
11
|
+
presentation metadata a consumer passes in.
|
|
12
|
+
|
|
13
|
+
The package ships no card records. There is no roster, no slug list and no
|
|
14
|
+
copy in this package: every card's destination, identity mark, product proof,
|
|
15
|
+
headline and result is consumer-owned and passed as props. That is deliberate,
|
|
16
|
+
and it is why the type is exported but the data is not.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install @super-ic/web-patterns @super-ic/foundation @super-ic/primitives react react-dom
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`@super-ic/foundation` (`^0.2.0`) and `react` (`>=19`) are **peer
|
|
25
|
+
dependencies**. Install them yourself; this package will not pull them in.
|
|
26
|
+
`@super-ic/icon-contracts` is a hard dependency and comes along automatically;
|
|
27
|
+
the card renders its forward chevron through it.
|
|
28
|
+
|
|
29
|
+
## Three mandatory setup steps
|
|
30
|
+
|
|
31
|
+
The existing case-study card ships JSX and Tailwind class strings. Its layout
|
|
32
|
+
requires the token and Tailwind steps below. NeighborhoodLanding additionally
|
|
33
|
+
ships its own exported recipe stylesheet, documented below. Skip the
|
|
34
|
+
nucleo bind and `Icon` throws `IconGlyphsNotBoundError` at render.
|
|
35
|
+
|
|
36
|
+
### 1. Import the token stylesheet once
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import "@super-ic/foundation/tokens.css";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Import it once at the application root, before anything renders. It defines the
|
|
43
|
+
`:root` layer the card's classes resolve against, including `--radius-card`,
|
|
44
|
+
`--radius-card-frame`, `--elev-card`, `--elev-pill`, `--motion-hover-duration`
|
|
45
|
+
and `--motion-ease-quiet`. Without it the card has square corners, no
|
|
46
|
+
elevation, and no hover transition.
|
|
47
|
+
|
|
48
|
+
### 2. Import the package Tailwind bridge
|
|
49
|
+
|
|
50
|
+
Tailwind v4 does not scan `node_modules`, so the utility classes this package
|
|
51
|
+
emits generate no CSS unless the package's built output is scanned. Import
|
|
52
|
+
Tailwind once, then import the public bridge. The bridge scans this package's
|
|
53
|
+
distributed JavaScript and includes the public primitives bridge:
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
@import "tailwindcss";
|
|
57
|
+
@import "@super-ic/web-patterns/tailwind.css";
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Omit the owning bridge and the card renders as unstyled markup with correct
|
|
61
|
+
semantics.
|
|
62
|
+
|
|
63
|
+
### 3. Bind Nucleo glyphs once at the application root
|
|
64
|
+
|
|
65
|
+
The card draws its control chevron through `@super-ic/icon-contracts` `Icon`.
|
|
66
|
+
That component throws `IconGlyphsNotBoundError` unless the consumer evaluates
|
|
67
|
+
the nucleo subpath before the first render:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import "@super-ic/icon-contracts/nucleo";
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Import it once in a module that runs on both the server and the client. A
|
|
74
|
+
server-only import leaves the client unbound after hydration. The package
|
|
75
|
+
contract test binds this subpath before it renders a card. Product tests should
|
|
76
|
+
do the same, or they will mask a production outage.
|
|
77
|
+
|
|
78
|
+
## Access contract: `locked` requires `onUnlock`
|
|
79
|
+
|
|
80
|
+
`access` defaults to `"open"`, which renders an anchor to `href`. Setting
|
|
81
|
+
`access="locked"` renders a single `role="button"` control with
|
|
82
|
+
`aria-haspopup="dialog"` and **no** `href`, so the consumer's own gate decides
|
|
83
|
+
what happens.
|
|
84
|
+
|
|
85
|
+
That control has to do something, so the component fails closed rather than
|
|
86
|
+
rendering a dead card:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
/* Throws: Locked case-study cards require an unlock handler */
|
|
90
|
+
<CaseStudyCard href="/case-studies/example" access="locked" {...rest} />
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
/* Correct */
|
|
95
|
+
<CaseStudyCard
|
|
96
|
+
href="/case-studies/example"
|
|
97
|
+
access="locked"
|
|
98
|
+
onUnlock={() => setGateOpen(true)}
|
|
99
|
+
lockedControlRef={gateReturnFocusRef}
|
|
100
|
+
{...rest}
|
|
101
|
+
/>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The throw happens during render, in development and production alike. Pass
|
|
105
|
+
`lockedControlRef` so focus can return to the card after your dialog closes.
|
|
106
|
+
|
|
107
|
+
## Framework-native navigation
|
|
108
|
+
|
|
109
|
+
An open card renders a plain `<a>` by default. To route through a framework
|
|
110
|
+
link, supply `renderOpenControl`. It receives the full set of control props
|
|
111
|
+
(`href`, `className`, the `data-*` slots, `aria-label`, `aria-describedby`) and
|
|
112
|
+
must spread all of them onto whatever it renders:
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<CaseStudyCard
|
|
116
|
+
href="/case-studies/example"
|
|
117
|
+
renderOpenControl={({ children, ...props }) => <Link {...props}>{children}</Link>}
|
|
118
|
+
{...rest}
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Known gap
|
|
123
|
+
|
|
124
|
+
One token family the card's class names is **not** in
|
|
125
|
+
`@super-ic/foundation/tokens.css` today:
|
|
126
|
+
|
|
127
|
+
- `--enterprise-bg` / `--enterprise-fg` (via `bg-enterprise-bg` and
|
|
128
|
+
`text-enterprise-fg`) are excluded from the generated layer on purpose. In
|
|
129
|
+
the source they are a site-local plate bound to the dark ramp, so emitting
|
|
130
|
+
them would ship a permanently dark card. See the `@super-ic/foundation` README.
|
|
131
|
+
The public Tailwind bridge supplies the foundation mappings for `border-border`,
|
|
132
|
+
`ring-ring` and `ring-offset-background`. Until the enterprise plate is closed in
|
|
133
|
+
a consumer's own stylesheet, its surface inherits the page background. Everything
|
|
134
|
+
else (geometry, hierarchy, radii, elevation, motion and the whole accessibility
|
|
135
|
+
contract) resolves from the token layer and public bridge.
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
## NeighborhoodLanding (candidate)
|
|
139
|
+
|
|
140
|
+
Sharing-tab foreground, background and borders change together without a color
|
|
141
|
+
transition. This preserves readable inactive and selected labels during theme
|
|
142
|
+
initialization as well as keyboard selection. Verify both themes at natural phone
|
|
143
|
+
size; a difference between background colors alone does not prove legibility.
|
|
144
|
+
|
|
145
|
+
`NeighborhoodLanding` is an object-led public community landing recipe. It pairs
|
|
146
|
+
a tangible illustrative example with two ways to participate, a residency and
|
|
147
|
+
joining section, practical disclosures, and legal/help destinations. Its CSS
|
|
148
|
+
belongs to the package; product consumers must not recreate this composition.
|
|
149
|
+
This is a review candidate, not an accepted product or release claim.
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
import { NeighborhoodLanding, type NeighborhoodLandingProps } from "@super-ic/web-patterns";
|
|
153
|
+
import "@super-ic/foundation/tokens.css";
|
|
154
|
+
import "@super-ic/web-patterns/neighborhood-landing.css";
|
|
155
|
+
// Bind the approved semantic glyph provider at server and client roots.
|
|
156
|
+
import "@super-ic/icon-contracts/nucleo";
|
|
157
|
+
|
|
158
|
+
const page: NeighborhoodLandingProps = /* product-owned content and routes */;
|
|
159
|
+
<NeighborhoodLanding {...page} />;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The consuming Tailwind v4 entry must compile the public primitive bridge:
|
|
163
|
+
|
|
164
|
+
```css
|
|
165
|
+
@import "tailwindcss";
|
|
166
|
+
@import "@super-ic/web-patterns/tailwind.css";
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The package bridge scans web-patterns and the primitives' built output and
|
|
170
|
+
provides foundation utility mappings and Accordion animations. Recipe layout comes from
|
|
171
|
+
`neighborhood-landing.css`; do not scan a private DS source path. The recipe uses
|
|
172
|
+
public `buttonVariants` on real anchors so navigation retains link semantics,
|
|
173
|
+
plus public Tabs, Accordion and semantic icons. It does not use a button role on
|
|
174
|
+
an anchor or implement replacement keyboard behavior. The recipe's module has a
|
|
175
|
+
client directive because its disclosures and tabs are interactive.
|
|
176
|
+
|
|
177
|
+
The product supplies brand, media, copy, eligibility, join availability, routes,
|
|
178
|
+
and each claim. `membership.join` is a required discriminated union:
|
|
179
|
+
|
|
180
|
+
- `available`: one destination with `label` and real `href`, plus a truthful note.
|
|
181
|
+
- `unavailable`: reason/title, explanation and a real help destination. No
|
|
182
|
+
disabled fake submit button or implicit waitlist is rendered.
|
|
183
|
+
|
|
184
|
+
`hero.availability` is also required. Keep it consistent with the product's
|
|
185
|
+
actual activation state. An unfinished DS build does not determine production
|
|
186
|
+
membership availability. This component never creates accounts, verifies
|
|
187
|
+
residency, collects email, sends support messages, or claims backend readiness.
|
|
188
|
+
|
|
189
|
+
`renderLink` may adapt external page destinations to a framework link. Forward
|
|
190
|
+
all received anchor properties, including href, className, children and focus
|
|
191
|
+
behavior. Internal skip, how-it-works and join anchors remain native document
|
|
192
|
+
navigation. The calling application supplies its route implementation and
|
|
193
|
+
back/forward behavior. Do not replace real destinations with `#` or silently
|
|
194
|
+
swallow links. The specimen's dialog destinations are explicitly labeled local
|
|
195
|
+
previews and are not part of this package.
|
|
196
|
+
|
|
197
|
+
### Contract and proof
|
|
198
|
+
|
|
199
|
+
- Two participation examples are required, each with a stable unique ID and
|
|
200
|
+
three real explanatory steps. These are examples, not fabricated posts.
|
|
201
|
+
Asking/offering copy belongs to the tenant. Keyboard Left/Right selects tabs;
|
|
202
|
+
Enter/Space operates disclosure triggers. The underlying public primitives
|
|
203
|
+
own these semantics.
|
|
204
|
+
- Every link has visible text or the brand's accessible name. The main, sharing
|
|
205
|
+
and membership sections have stable per-instance IDs and programmatic focus
|
|
206
|
+
targets for native anchor navigation. FAQ questions name their own buttons.
|
|
207
|
+
- Hero media requires src, nonempty alt, intrinsic dimensions and a visible
|
|
208
|
+
caption. Optional possibility and example media use the public
|
|
209
|
+
`NeighborhoodLandingMedia` shape. Possibility IDs must be unique. Test failures
|
|
210
|
+
both before hydration and after handlers attach; neither path may leave a broken
|
|
211
|
+
image or hide the associated copy and action. These images are
|
|
212
|
+
informative only, lazy-load outside the hero, use contain presentation, and disappear
|
|
213
|
+
independently on error; their surrounding copy and actions remain. A new `src` resets
|
|
214
|
+
that failure state. Media never establishes runtime availability, membership or authority. The consumer retains the rights/provenance record. No supplied media
|
|
215
|
+
or participation example may imply existing inventory or real demand without
|
|
216
|
+
evidence. The package contains no photos or tenant records.
|
|
217
|
+
- Layout uses the foundation's type, spacing, surface, action, border, radius
|
|
218
|
+
and focus roles. The optional tenant accent-quiet role falls back to surface-2
|
|
219
|
+
for a brand without that role. Width responds to the actual recipe container,
|
|
220
|
+
not only the viewport. Reduced motion preserves all content and actions.
|
|
221
|
+
- Allowed composition: a page-level landing, with a brand mark, short copy,
|
|
222
|
+
illustrative photo, two participation explanations and plain-text/linked FAQ
|
|
223
|
+
answers. Keep links and small paragraphs inside answers, not nested modals,
|
|
224
|
+
primary actions or another page recipe.
|
|
225
|
+
- Anti-patterns: fake member counts, listings, testimonials or trust scores;
|
|
226
|
+
blanket safety/insurance claims; public addresses or residency evidence;
|
|
227
|
+
inactive paid/service modes presented as available; repeated feature-card
|
|
228
|
+
walls; an application form that the consumer cannot actually submit.
|
|
229
|
+
- Limits: one landing/main landmark per page; exactly two examples and three
|
|
230
|
+
steps per example; unique IDs within each repeated collection; no invented
|
|
231
|
+
density modes or loading states. Text can grow without clipping, but long
|
|
232
|
+
hero copy weakens the first-viewport composition and needs editorial review.
|
|
233
|
+
- Ownership: shared recipe and its browser contract belong to SuperIC DS;
|
|
234
|
+
resident policy, routes, activation, claims and support belong to the
|
|
235
|
+
consuming product. The candidate has no automatic promotion path.
|
|
236
|
+
- Migration: replace page-local marketing shells with the public recipe and
|
|
237
|
+
exported CSS after review. Existing marketing exports remain unchanged; this
|
|
238
|
+
addition does not retroactively accept their legacy behavior.
|
|
239
|
+
|
|
240
|
+
Executable requirements in `contracts/neighborhood-landing.json` bind to the
|
|
241
|
+
candidate stories and the actual `neighborhood-landing.browser.test.ts` titles.
|
|
242
|
+
Those bindings are an input to the coordinator's canonical catalog integration,
|
|
243
|
+
not a fabricated accepted-registry record. A file being present is not proof of
|
|
244
|
+
execution. Record the executed report and exact source/package hashes when this
|
|
245
|
+
candidate is integrated; repeat installed-consumer checks on the final graph.
|
|
246
|
+
# Public help and documents
|
|
247
|
+
|
|
248
|
+
Import `PublicSiteFrame`, `PublicArticle`, `HelpDirectory` and `PublicAvailability`
|
|
249
|
+
from `@super-ic/web-patterns`, with `@super-ic/web-patterns/public-content.css`.
|
|
250
|
+
These are candidate recipes. Compile the public foundation/primitives Tailwind
|
|
251
|
+
bridge and load the tenant's public font sheets at the consumer root.
|
|
252
|
+
|
|
253
|
+
`PublicSiteFrame` owns the public header, one main landmark, skip link and footer.
|
|
254
|
+
Compose exactly one h1-owning article, help directory or availability boundary.
|
|
255
|
+
Pass real links and preserve normal browser modifier-key behavior in `onNavigate`.
|
|
256
|
+
Navigation IDs must be unique and at most one item is current. Marks use their
|
|
257
|
+
natural aspect ratio at a 100px width; the consumer supplies the actual tenant mark.
|
|
258
|
+
|
|
259
|
+
`PublicArticle` receives a title, introduction, optional factual date/version label,
|
|
260
|
+
optional notice, stable section slugs, trusted React prose and related routes. Use
|
|
261
|
+
paragraphs, lists, description lists, links and h3 subheadings in section bodies.
|
|
262
|
+
Do not inject raw HTML or another page/main/h1. Section IDs must be unique lowercase
|
|
263
|
+
slugs. The table of contents uses native fragment links and a native disclosure so
|
|
264
|
+
document navigation and all prose remain usable without JavaScript. This native
|
|
265
|
+
document disclosure is intentional; it does not replace application dialogs or
|
|
266
|
+
shadcn form controls. Supplied metadata is not a legal-readiness or acceptance claim.
|
|
267
|
+
Set `anchorId` to a stable lowercase slug when a document needs stable deep links.
|
|
268
|
+
The consumer must keep each supplied `anchorId` unique within the rendered document;
|
|
269
|
+
omitting it retains instance-safe fragment IDs. Article prose supports semantic tables
|
|
270
|
+
with a muted, left-aligned caption and token-bound reading rows.
|
|
271
|
+
|
|
272
|
+
`HelpDirectory` uses public Input and Button controls. The consumer supplies query,
|
|
273
|
+
search commands and mutually exclusive ready, empty, loading or failed results.
|
|
274
|
+
Ready groups need unique IDs and useful topic links. Keep the query on failure,
|
|
275
|
+
invalidate old results after a newer query/route and never interpret a successful
|
|
276
|
+
search as a support submission. The separate contact action is a real supplied route.
|
|
277
|
+
Set `search.action` for a native GET fallback before hydration, and optionally set
|
|
278
|
+
`search.queryName` when the query parameter is not `q`. Hydrated submission prevents
|
|
279
|
+
the native navigation and calls the controlled search callback.
|
|
280
|
+
|
|
281
|
+
`PublicAvailability` displays a public-safe closed, restricted, sign-in, unavailable
|
|
282
|
+
or loading projection. The product supplies the reason, permitted recovery links
|
|
283
|
+
and retained intent. Do not infer authorization from query parameters or render an
|
|
284
|
+
old private action during loading. No waitlist, membership or legal document exists
|
|
285
|
+
merely because the recipe renders.
|
|
286
|
+
|
|
287
|
+
The nine historical `marketing.tsx` values are removed from this candidate public
|
|
288
|
+
API. Their original examples remain privately under `stories/legacy-support/`.
|
|
289
|
+
NeighborhoodLanding replaces MarketingHero/ValueHypothesisBlock/HowItWorksSteps;
|
|
290
|
+
PublicArticle replaces DocumentPage/DocumentSection/DocumentVersionNotice and can
|
|
291
|
+
show a supplied notice; the controlled app-patterns SupportIntake replaces the
|
|
292
|
+
inert SupportIntakeForm/SupportReceivedState. The removal manifest is
|
|
293
|
+
`design-system/retired-web-exports.json` in the authoring repository. Retirement
|
|
294
|
+
does not close the complete product responsibilities or confer acceptance.
|
|
295
|
+
|
|
296
|
+
`PublicDocumentDialog` is the controlled document reader for policy, privacy and other
|
|
297
|
+
reference content opened from a form. Import `@super-ic/web-patterns/public-content.css`.
|
|
298
|
+
Supply `open`, `onOpenChange`, `title`, `description`, `contentLabel`, `returnLabel` and
|
|
299
|
+
trusted React prose as children. Put h3 headings inside its sections. The viewport
|
|
300
|
+
layout keeps the heading and return action visible while the prose scrolls. It uses
|
|
301
|
+
the public Sheet focus behavior and restores the opener; allow Base UI's scheduled
|
|
302
|
+
focus-guard handoff before asserting the resulting target. Place the consumer's public
|
|
303
|
+
PortalContainerProvider inside the active tenant/theme scope. Opening or closing the
|
|
304
|
+
reader must not accept any consent or submit/clear the form. Document validity,
|
|
305
|
+
publication status and authorization remain product responsibilities.
|
|
306
|
+
|
|
307
|
+
### Powered by SuperIC
|
|
308
|
+
|
|
309
|
+
Import `PoweredBySuperIC` from `@super-ic/web-patterns` or its `/powered-by-superic` subpath. The normal `@super-ic/web-patterns/tailwind.css` aggregate includes its styling automatically; the dedicated `@super-ic/web-patterns/powered-by-superic.css` subpath remains available with the shared foundation stylesheet. The exact approved outlined wordmark is provided by the peer package `@super-ic/brand-contracts/superic-logo`.
|
|
310
|
+
|
|
311
|
+
The neutral attribution preserves `href`, `variant` (`auto`, `light`, `dark`), `size` (`sm`, `md`), `label`, `source`, and `className`. Auto uses the nearest inherited semantic theme without client state or SVG swapping. Sizes preserve 14px/18px logos with 11px/12px labels. The small label is supplementary attribution, not an instruction or form label. Explicit variant secondary text uses the existing readable semantic role. HTTP(S) and root-relative destinations are accepted; referral parameters preserve existing query fields and hashes. External-link target behavior is `_blank` with `noopener noreferrer`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "superic.component-contract/v1",
|
|
3
|
+
"id": "contact-section",
|
|
4
|
+
"status": "candidate",
|
|
5
|
+
"package": "@super-ic/web-patterns",
|
|
6
|
+
"export": "ContactSection",
|
|
7
|
+
"publicImport": "@super-ic/web-patterns/contact-section",
|
|
8
|
+
"cssImport": "@super-ic/web-patterns/contact-section.css",
|
|
9
|
+
"origin": {
|
|
10
|
+
"implementation": "Original implementation of the root functional and layout brief.",
|
|
11
|
+
"referenceIntake": "design-system/intake/contact2.json",
|
|
12
|
+
"distributionReview": "pending",
|
|
13
|
+
"note": "An original implementation does not itself establish redistribution clearance for the referenced vendor material."
|
|
14
|
+
},
|
|
15
|
+
"purpose": "A controlled contact introduction and form presentation recipe.",
|
|
16
|
+
"imports": ["@super-ic/primitives/button", "@super-ic/primitives/input", "@super-ic/primitives/textarea", "@super-ic/primitives/label", "@super-ic/primitives/card"],
|
|
17
|
+
"consumerOwns": ["copy", "field values", "validation", "submission transport", "approved media"],
|
|
18
|
+
"recipeOwns": ["responsive composition", "field labels", "state presentation", "focus management"],
|
|
19
|
+
"states": ["idle", "invalid", "submitting", "success", "failure", "unavailable"],
|
|
20
|
+
"invalidState": "Consumers supply a new validationId for each completed validation attempt. The recipe focuses the first invalid field when that ID changes, without moving focus for value edits.",
|
|
21
|
+
"limits": ["No transport is performed.", "No tenant branding or media is supplied.", "The local package candidate exposes a reviewable import; registry publication and accepted consumer integration remain unproven."],
|
|
22
|
+
"accessibility": ["The section has an instance-safe accessible heading.", "Invalid state focuses the first invalid field for a new validationId.", "Success state receives focus.", "Unavailable state retains supplied contact details.", "Media captions remain meaningful when image loading fails."]
|
|
23
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"kind": "candidate-recipe-binding",
|
|
4
|
+
"id": "neighborhood-landing",
|
|
5
|
+
"maturity": "candidate",
|
|
6
|
+
"owner": "SuperIC DS",
|
|
7
|
+
"accepted": false,
|
|
8
|
+
"public": {
|
|
9
|
+
"imports": {
|
|
10
|
+
"@super-ic/web-patterns": [
|
|
11
|
+
"NeighborhoodLanding",
|
|
12
|
+
"NeighborhoodLandingProps",
|
|
13
|
+
"NeighborhoodLandingJoin",
|
|
14
|
+
"NeighborhoodLandingLink",
|
|
15
|
+
"NeighborhoodLandingExample",
|
|
16
|
+
"NeighborhoodLandingStep",
|
|
17
|
+
"NeighborhoodLandingMedia"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"css": [
|
|
21
|
+
"@super-ic/foundation/tokens.css",
|
|
22
|
+
"@super-ic/primitives/tailwind.css",
|
|
23
|
+
"@super-ic/web-patterns/neighborhood-landing.css"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": [
|
|
26
|
+
"@super-ic/primitives/button",
|
|
27
|
+
"@super-ic/primitives/tabs",
|
|
28
|
+
"@super-ic/primitives/accordion",
|
|
29
|
+
"@super-ic/icon-contracts"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"source": [
|
|
33
|
+
"src/neighborhood-landing.tsx",
|
|
34
|
+
"css/neighborhood-landing.css",
|
|
35
|
+
"src/public-content.tsx",
|
|
36
|
+
"css/public-content.css",
|
|
37
|
+
"src/editorial-image.tsx"
|
|
38
|
+
],
|
|
39
|
+
"tokens": [
|
|
40
|
+
"--background",
|
|
41
|
+
"--border",
|
|
42
|
+
"--brand-accent-quiet",
|
|
43
|
+
"--foreground",
|
|
44
|
+
"--muted-foreground",
|
|
45
|
+
"--primary-foreground",
|
|
46
|
+
"--radius-card",
|
|
47
|
+
"--radius-card-inset",
|
|
48
|
+
"--radius-xl",
|
|
49
|
+
"--radius-xs",
|
|
50
|
+
"--ring",
|
|
51
|
+
"--space-unit",
|
|
52
|
+
"--surface",
|
|
53
|
+
"--surface-2",
|
|
54
|
+
"--type-body-large-line-height",
|
|
55
|
+
"--type-body-large-size",
|
|
56
|
+
"--type-body-medium-family",
|
|
57
|
+
"--type-body-medium-line-height",
|
|
58
|
+
"--type-body-medium-size",
|
|
59
|
+
"--type-body-small-line-height",
|
|
60
|
+
"--type-body-small-size",
|
|
61
|
+
"--type-caption-size",
|
|
62
|
+
"--type-display-large-family",
|
|
63
|
+
"--type-display-large-size",
|
|
64
|
+
"--type-display-large-tracking",
|
|
65
|
+
"--type-display-large-weight",
|
|
66
|
+
"--type-display-small-family",
|
|
67
|
+
"--type-display-small-line-height",
|
|
68
|
+
"--type-display-small-size",
|
|
69
|
+
"--type-display-small-tracking",
|
|
70
|
+
"--type-display-small-weight",
|
|
71
|
+
"--type-h1-family",
|
|
72
|
+
"--type-h1-line-height",
|
|
73
|
+
"--type-h1-size",
|
|
74
|
+
"--type-h1-tracking",
|
|
75
|
+
"--type-h2-size",
|
|
76
|
+
"--type-h3-family",
|
|
77
|
+
"--type-h3-line-height",
|
|
78
|
+
"--type-h3-size",
|
|
79
|
+
"--type-h3-tracking",
|
|
80
|
+
"--type-h3-weight",
|
|
81
|
+
"--type-numeric-family",
|
|
82
|
+
"--type-overline-size",
|
|
83
|
+
"--type-overline-tracking",
|
|
84
|
+
"--type-overline-weight"
|
|
85
|
+
],
|
|
86
|
+
"states": {
|
|
87
|
+
"membership": [
|
|
88
|
+
"available",
|
|
89
|
+
"unavailable"
|
|
90
|
+
],
|
|
91
|
+
"examples": [
|
|
92
|
+
"first",
|
|
93
|
+
"second"
|
|
94
|
+
],
|
|
95
|
+
"disclosure": [
|
|
96
|
+
"open",
|
|
97
|
+
"closed"
|
|
98
|
+
],
|
|
99
|
+
"density": {
|
|
100
|
+
"applicable": false,
|
|
101
|
+
"reason": "One container-responsive editorial composition; no density variants."
|
|
102
|
+
},
|
|
103
|
+
"submission": {
|
|
104
|
+
"applicable": false,
|
|
105
|
+
"reason": "Consumer-owned route navigation; no form or command in this recipe."
|
|
106
|
+
},
|
|
107
|
+
"media": [
|
|
108
|
+
"omitted",
|
|
109
|
+
"loaded",
|
|
110
|
+
"failed",
|
|
111
|
+
"src-replaced"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"stories": [
|
|
115
|
+
"candidates-neighborhood-landing--sandbrock",
|
|
116
|
+
"candidates-neighborhood-landing--dark",
|
|
117
|
+
"candidates-neighborhood-landing--joining-available",
|
|
118
|
+
"candidates-neighborhood-landing--long-content",
|
|
119
|
+
"candidates-neighborhood-landing--narrow-container"
|
|
120
|
+
],
|
|
121
|
+
"testFile": "stories/candidates/neighborhood-landing.browser.test.ts",
|
|
122
|
+
"requirements": [
|
|
123
|
+
{
|
|
124
|
+
"id": "LANDING-01",
|
|
125
|
+
"behavior": "Recognizable object and join action within initial view; correct theme and readable unclipped layout; axe in 375/1280 and light/dark."
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "LANDING-02",
|
|
129
|
+
"behavior": "Keyboard tabs expose each complete example without simultaneous duplicate content."
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"id": "LANDING-03",
|
|
133
|
+
"behavior": "Skip and join links move focus to correct sections; closed state contains no application link."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "LANDING-04",
|
|
137
|
+
"behavior": "Available join uses actual consumer href; fixture previews destination and restores focus, without claiming account creation."
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "LANDING-05",
|
|
141
|
+
"behavior": "Disclosure keyboard behavior, correct fee text and distinct privacy/help routes, themed open-state axe."
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"id": "LANDING-06",
|
|
145
|
+
"behavior": "Long text and nested narrow container reflow; all visible navigation/tab targets reach 44px."
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "LANDING-07",
|
|
149
|
+
"behavior": "Reduced motion retains content and interaction."
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"id": "LANDING-08",
|
|
153
|
+
"behavior": "Optional informative hero, possibility, example and article media reserve supplied dimensions; failures both before and after hydration hide only that image and source replacement restores it. Media remains illustrative and creates no availability authority."
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"proof": {
|
|
157
|
+
"state": "not-accepted",
|
|
158
|
+
"execution": "External candidate report required; this file is a binding, not an execution receipt.",
|
|
159
|
+
"integration": "Coordinator must project into canonical catalog and bind final source/package hashes before acceptance."
|
|
160
|
+
},
|
|
161
|
+
"agentGuidance": "README.md#neighborhoodlanding-candidate"
|
|
162
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"status": "candidate-pending-product-proof",
|
|
5
|
+
"source": "packages/web-patterns/src/public-content.tsx",
|
|
6
|
+
"imports": [
|
|
7
|
+
"@super-ic/web-patterns",
|
|
8
|
+
"@super-ic/web-patterns/public-content.css"
|
|
9
|
+
],
|
|
10
|
+
"contracts": {
|
|
11
|
+
"PublicArticle": {
|
|
12
|
+
"anchorId": "Optional lowercase document slug unique within the page; prefix for stable section fragments. Omission uses unique instance IDs.",
|
|
13
|
+
"sections": "Unique lowercase slugs, trusted semantic prose, optional contextual informative media with alt and dimensions.",
|
|
14
|
+
"tables": "Native table, caption, scoped row/column headers. Token-bound strokes and responsive wrapping.",
|
|
15
|
+
"failure": "Failed media is omitted; adjacent copy and links remain available.",
|
|
16
|
+
"keyboard": "Native disclosure and focusable section targets work without JavaScript.",
|
|
17
|
+
"links": "Prose, back and related links are explicitly underlined so consumer resets cannot erase their affordance."
|
|
18
|
+
},
|
|
19
|
+
"HelpDirectory": {
|
|
20
|
+
"search": "Controlled draft and committed query belong to product. action provides native GET destination, queryName defaults to q.",
|
|
21
|
+
"states": [
|
|
22
|
+
"ready",
|
|
23
|
+
"empty",
|
|
24
|
+
"loading",
|
|
25
|
+
"failed"
|
|
26
|
+
],
|
|
27
|
+
"keyboard": "Visible search label and Enter submission; product preserves input focus and URL/Back/Forward state.",
|
|
28
|
+
"noJavaScript": "Native GET requires a real route that renders its query. The recipe alone does not implement that route.",
|
|
29
|
+
"limits": "No fabricated network states for a synchronous local catalog; a help result is not a persisted support case.",
|
|
30
|
+
"reset": "Optional reset.href renders a real link for empty-state recovery without JavaScript; omission retains controlled onAction button."
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"proof": [
|
|
34
|
+
"packages/web-patterns/src/public-content.test.tsx",
|
|
35
|
+
"SBR actual installed-package help/fees proof is tracked separately"
|
|
36
|
+
],
|
|
37
|
+
"acceptance": "Historical receipt hashes are not renewed by this candidate."
|
|
38
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* The public presentation marker is emitted by CaseStudyCard. These rules
|
|
2
|
+
deliberately affect only the recovered SuperIC presentation. */
|
|
3
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-surface"] {
|
|
4
|
+
font-family: var(--font-superic-case-study, "Inter Display"), "Inter Display", ui-sans-serif, system-ui, sans-serif;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-identity"],
|
|
8
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-headline"],
|
|
9
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-control-label"] {
|
|
10
|
+
color: var(--enterprise-fg);
|
|
11
|
+
font-family: var(--font-superic-case-study, "Inter Display"), "Inter Display", ui-sans-serif, system-ui, sans-serif;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-relationship"] {
|
|
15
|
+
color: var(--enterprise-muted);
|
|
16
|
+
font-family: var(--font-superic-case-study, "Inter Display"), "Inter Display", ui-sans-serif, system-ui, sans-serif;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-result"] {
|
|
20
|
+
color: var(--enterprise-subtle);
|
|
21
|
+
font-family: var(--font-superic-case-study, "Inter Display"), "Inter Display", ui-sans-serif, system-ui, sans-serif;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Consumer Tailwind `font-sans` and `font-mono` utilities otherwise reset
|
|
25
|
+
coded-art typography to the tenant defaults. */
|
|
26
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-art"] .font-sans,
|
|
27
|
+
[data-card-presentation="superic"] [data-slot="case-study-card-art"] .font-mono {
|
|
28
|
+
font-family: var(--font-superic-case-study, "Inter Display"), "Inter Display", ui-sans-serif, system-ui, sans-serif;
|
|
29
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.sic-contact-section { container: contact-section / inline-size; width: min(calc(100% - 2rem), 72rem); margin-inline: auto; color: var(--foreground); font-family: var(--type-body-medium-family); font-size: var(--type-body-medium-size); line-height: var(--type-body-medium-line-height); overflow-wrap: anywhere; }
|
|
2
|
+
.sic-contact-section *, .sic-contact-section *::before, .sic-contact-section *::after { box-sizing: border-box; }
|
|
3
|
+
.sic-contact-section :where(h1,h2,h3,p,dl,dd,figure) { margin: 0; }
|
|
4
|
+
.sic-contact-section :where(h1,h2,h3) { font-family: var(--type-h1-family); text-wrap: balance; }
|
|
5
|
+
.sic-contact-section h1 { font-size: var(--type-display-small-size); line-height: var(--type-display-small-line-height); font-weight: var(--type-display-small-weight); letter-spacing: var(--type-display-small-tracking); }
|
|
6
|
+
.sic-contact-section h2 { font-size: var(--type-h2-size); line-height: var(--type-h2-line-height); font-weight: var(--type-h2-weight); letter-spacing: var(--type-h2-tracking); }
|
|
7
|
+
.sic-contact-section h3 { font-size: var(--type-h3-size); line-height: var(--type-h3-line-height); font-weight: var(--type-h3-weight); }
|
|
8
|
+
.sic-contact-section a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: .22em; }
|
|
9
|
+
.sic-contact-section :where(a,button,input,textarea):focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
|
|
10
|
+
.sic-contact-section__layout { display: grid; gap: calc(var(--space-unit) * 8); max-inline-size: 72rem; }
|
|
11
|
+
.sic-contact-section__introduction { display: grid; align-content: start; gap: 1rem; min-inline-size: 0; }
|
|
12
|
+
.sic-contact-section__eyebrow { color: var(--brand-accent-strong, var(--foreground)); font-family: var(--type-overline-family); font-size: var(--type-overline-size); font-weight: var(--type-overline-weight); letter-spacing: var(--type-overline-tracking); line-height: var(--type-overline-line-height); text-transform: uppercase; }
|
|
13
|
+
.sic-contact-section__description { max-inline-size: 62ch; color: var(--muted-foreground); font-size: var(--type-body-large-size); line-height: var(--type-body-large-line-height); }
|
|
14
|
+
.sic-contact-section__media { max-inline-size: 20rem; margin-top: .5rem; }
|
|
15
|
+
.sic-contact-section__media img { display: block; inline-size: 100%; block-size: auto; aspect-ratio: 3 / 2; object-fit: contain; border: 1px solid var(--border); border-radius: var(--radius-card); background: var(--muted); }
|
|
16
|
+
.sic-contact-section__media figcaption { margin-top: .5rem; color: var(--muted-foreground); font-size: var(--type-caption-size); }
|
|
17
|
+
.sic-contact-section__details { display: grid; gap: .75rem; margin-top: 1rem; color: var(--muted-foreground); font-size: var(--type-body-small-size); }
|
|
18
|
+
.sic-contact-section__details > div { display: grid; gap: .25rem; }
|
|
19
|
+
.sic-contact-section__details dt { color: var(--foreground); font-weight: 600; }
|
|
20
|
+
.sic-contact-section__details dd { overflow-wrap: anywhere; }
|
|
21
|
+
.sic-contact-section__details a, .sic-contact-section__hint a { align-items: center; display: inline-flex; min-block-size: var(--control-target-min); min-inline-size: var(--control-target-min); }
|
|
22
|
+
.sic-contact-section__card { border-color: var(--border); background: var(--card); box-shadow: none; }
|
|
23
|
+
.sic-contact-section__form, .sic-contact-section__success { display: grid; gap: calc(var(--space-unit) * 6); }
|
|
24
|
+
.sic-contact-section__form fieldset { display: grid; gap: 1rem; min-inline-size: 0; margin: 0; padding: 0; border: 0; }
|
|
25
|
+
.sic-contact-section__field { display: grid; gap: .5rem; min-inline-size: 0; }
|
|
26
|
+
.sic-contact-section__field [data-slot=input], .sic-contact-section__field [data-slot=textarea] { min-block-size: 44px; }
|
|
27
|
+
.sic-contact-section__field [data-slot=textarea] { min-block-size: 8rem; resize: vertical; }
|
|
28
|
+
.sic-contact-section__hint { color: var(--muted-foreground); font-size: var(--type-caption-size); }
|
|
29
|
+
.sic-contact-section__error, .sic-contact-section__message { color: var(--destructive); font-size: var(--type-body-small-size); }
|
|
30
|
+
.sic-contact-section__form [role=status] { color: var(--muted-foreground); }
|
|
31
|
+
.sic-contact-section__form [data-slot=button], .sic-contact-section__success [data-slot=button] { min-block-size: 44px; white-space: normal; justify-content: center; }
|
|
32
|
+
.sic-contact-section__success:focus-visible { outline: 2px solid var(--ring); outline-offset: 4px; border-radius: var(--radius-card); }
|
|
33
|
+
@container contact-section (min-width: 48rem) { .sic-contact-section__layout { grid-template-columns: minmax(0, 1fr) minmax(20rem, .9fr); gap: calc(var(--space-unit) * 12); align-items: start; } }
|
|
34
|
+
@container contact-section (max-width: 47.99rem) { .sic-contact-section h1 { font-size: var(--type-h1-size); line-height: var(--type-h1-line-height); letter-spacing: var(--type-h1-tracking); } .sic-contact-section h2 { font-size: var(--type-h3-size); line-height: var(--type-h3-line-height); } .sic-contact-section__description { font-size: var(--type-body-medium-size); } .sic-contact-section__media { max-inline-size: 12rem; } }
|
|
35
|
+
|
|
36
|
+
.sic-contact-form { min-inline-size: 0; color: var(--foreground); font-family: var(--type-body-medium-family); font-size: var(--type-body-medium-size); line-height: var(--type-body-medium-line-height); overflow-wrap: anywhere; }
|
|
37
|
+
.sic-contact-form :where(a,button,input,textarea):focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
|
|
38
|
+
.sic-contact-form :where(h2,h3,p) { margin: 0; }
|
|
39
|
+
.sic-contact-form :where(h2,h3) { font-family: var(--type-h3-family); font-size: var(--type-h3-size); line-height: var(--type-h3-line-height); font-weight: var(--type-h3-weight); text-wrap: balance; }
|