@spark-line/web-framework 0.1.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 (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/dist/astro/index.js +13 -0
  4. package/dist/react/Carousel.d.ts +13 -0
  5. package/dist/react/Carousel.d.ts.map +1 -0
  6. package/dist/react/Carousel.js +14 -0
  7. package/dist/react/Carousel.js.map +1 -0
  8. package/dist/react/Dialog.d.ts +8 -0
  9. package/dist/react/Dialog.d.ts.map +1 -0
  10. package/dist/react/Dialog.js +23 -0
  11. package/dist/react/Dialog.js.map +1 -0
  12. package/dist/react/Menu.d.ts +11 -0
  13. package/dist/react/Menu.d.ts.map +1 -0
  14. package/dist/react/Menu.js +46 -0
  15. package/dist/react/Menu.js.map +1 -0
  16. package/dist/react/Tabs.d.ts +12 -0
  17. package/dist/react/Tabs.d.ts.map +1 -0
  18. package/dist/react/Tabs.js +43 -0
  19. package/dist/react/Tabs.js.map +1 -0
  20. package/dist/react/index.d.ts +9 -0
  21. package/dist/react/index.d.ts.map +1 -0
  22. package/dist/react/index.js +5 -0
  23. package/dist/react/index.js.map +1 -0
  24. package/dist/registry/index.d.ts +197 -0
  25. package/dist/registry/index.d.ts.map +1 -0
  26. package/dist/registry/index.js +170 -0
  27. package/dist/registry/index.js.map +1 -0
  28. package/dist/sanity/index.d.ts +57 -0
  29. package/dist/sanity/index.d.ts.map +1 -0
  30. package/dist/sanity/index.js +117 -0
  31. package/dist/sanity/index.js.map +1 -0
  32. package/package.json +96 -0
  33. package/skills/spark-line-web-framework/SKILL.md +84 -0
  34. package/skills/spark-line-web-framework/agents/openai.yaml +4 -0
  35. package/skills/spark-line-web-framework/references/contracts.md +75 -0
  36. package/skills/spark-line-web-framework/references/qa-checklist.md +56 -0
  37. package/skills/spark-line-web-framework/references/stack-boundaries.md +53 -0
  38. package/skills/spark-line-web-framework/scripts/audit_layout.mjs +66 -0
  39. package/src/astro/Action.astro +34 -0
  40. package/src/astro/CardShell.astro +19 -0
  41. package/src/astro/Cluster.astro +30 -0
  42. package/src/astro/Container.astro +15 -0
  43. package/src/astro/Disclosure.astro +16 -0
  44. package/src/astro/Grid.astro +38 -0
  45. package/src/astro/Heading.astro +17 -0
  46. package/src/astro/PageFlow.astro +13 -0
  47. package/src/astro/Section.astro +44 -0
  48. package/src/astro/SectionGroup.astro +14 -0
  49. package/src/astro/Stack.astro +16 -0
  50. package/src/astro/Text.astro +21 -0
  51. package/src/astro/VisualFrame.astro +32 -0
  52. package/src/astro/index.d.ts +17 -0
  53. package/starter/astro/astro.config.mjs +5 -0
  54. package/starter/astro/package.json +13 -0
  55. package/starter/astro/src/pages/index.astro +48 -0
  56. package/starter/astro/src/pages/style-guide.astro +76 -0
  57. package/starter/astro/src/styles/project.css +27 -0
  58. package/styles/foundation.css +267 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Spark Line
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # `@spark-line/web-framework`
2
+
3
+ Structural UI contracts for Astro pages, optional React islands, and optional
4
+ Sanity section data.
5
+
6
+ This package adapts the durable parts of the Lumos method—tokens before
7
+ components, explicit containment, fluid layout, registered variants, and
8
+ reserved visual space—to the Spark Line web stack. It does not include a
9
+ universal visual identity, generated site CSS, or a Webflow/global browser
10
+ runtime. React JavaScript ships only when a consumer imports and hydrates an
11
+ island.
12
+
13
+ ## Install
14
+
15
+ Pin an exact version while the API is young:
16
+
17
+ ```sh
18
+ npm install @spark-line/web-framework@0.1.0
19
+ ```
20
+
21
+ Astro is required. React, React DOM, and Sanity are optional peer dependencies
22
+ and are only needed when their respective exports are used.
23
+
24
+ ```astro
25
+ ---
26
+ import "@spark-line/web-framework/styles/foundation.css";
27
+ import {
28
+ Action,
29
+ Heading,
30
+ PageFlow,
31
+ Section,
32
+ Stack,
33
+ Text,
34
+ VisualFrame
35
+ } from "@spark-line/web-framework/astro";
36
+ ---
37
+
38
+ <PageFlow>
39
+ <Section theme="default" spaceTop="lg" spaceBottom="lg">
40
+ <Stack gap="md">
41
+ <Heading level={1} size="display">Project-owned design</Heading>
42
+ <Text size="lead">Framework-owned structure.</Text>
43
+ <Action href="/projects">View projects</Action>
44
+ <VisualFrame aspectRatio="16 / 9">
45
+ <slot name="visual" />
46
+ </VisualFrame>
47
+ </Stack>
48
+ </Section>
49
+ </PageFlow>
50
+ ```
51
+
52
+ Define project tokens after the foundation stylesheet. The package deliberately
53
+ uses semantic slots rather than a palette:
54
+
55
+ ```css
56
+ :root {
57
+ --project-surface-default: Canvas;
58
+ --project-text-default: CanvasText;
59
+ --project-action-background: CanvasText;
60
+ --project-action-foreground: Canvas;
61
+ --project-type-display: clamp(3rem, 8vw, 7rem);
62
+ }
63
+ ```
64
+
65
+ ## Section contract
66
+
67
+ - `PageFlow` introduces no implicit gap.
68
+ - Every `Section` owns its background, theme, and both internal vertical edges.
69
+ - `Container` owns maximum width and inline gutters.
70
+ - Child layouts own only their internal grid or flex behavior.
71
+ - Section roots do not use external margins or selectors that style siblings.
72
+ - A changed section may move the following section in normal flow, but may not
73
+ change that section's spacing, theme, width, or layout.
74
+ - Joined seams and deliberate overlaps use `SectionGroup`.
75
+ - Floating or absolutely positioned artwork uses `VisualFrame` with a reserved
76
+ aspect ratio or block size.
77
+
78
+ ## Component sourcing order
79
+
80
+ 1. Inspect the real implementation and the component registry.
81
+ 2. Reuse an exact registered component.
82
+ 3. Add a typed variant when semantics and behavior are unchanged.
83
+ 4. Compose existing primitives.
84
+ 5. Create and register a component only for new structure or behavior.
85
+ 6. Add every meaningful state to the component gallery.
86
+
87
+ The registry is available from `@spark-line/web-framework/registry`.
88
+
89
+ ## React islands
90
+
91
+ The React export contains reference `Tabs`, `Carousel`, `Dialog`, and `Menu`
92
+ islands. Props are serializable data. Astro still owns the outer section,
93
+ surface, container, and spacing.
94
+
95
+ ```astro
96
+ ---
97
+ import { Tabs } from "@spark-line/web-framework/react";
98
+ ---
99
+
100
+ <Tabs
101
+ client:visible
102
+ label="Project sections"
103
+ items={[
104
+ { id: "context", label: "Context", content: "Approved source material." },
105
+ { id: "proof", label: "Proof", content: "Verified outcomes." }
106
+ ]}
107
+ />
108
+ ```
109
+
110
+ Use `client:visible` or `client:idle` by default. Use `client:load` only when the
111
+ interaction must be available immediately.
112
+
113
+ ## Sanity adapter
114
+
115
+ The Sanity export has no runtime import from `sanity`. It provides typed
116
+ registry, normalization, and schema-shape helpers while keeping the peer
117
+ optional.
118
+
119
+ ```ts
120
+ import {
121
+ defineSectionRegistry,
122
+ normalizePageSections
123
+ } from "@spark-line/web-framework/sanity";
124
+
125
+ const registry = defineSectionRegistry([
126
+ {
127
+ type: "heroSection",
128
+ componentId: "hero",
129
+ themes: ["default", "inverse"],
130
+ spaces: ["none", "sm", "md", "lg", "xl"],
131
+ layouts: ["split", "centered"]
132
+ }
133
+ ]);
134
+
135
+ const sections = normalizePageSections(document.sections, registry);
136
+ ```
137
+
138
+ `_type`, `_key`, Portable Text, references, asset data, and preview metadata
139
+ remain on `props` and the original record remains available as `source`.
140
+ Unknown section policy is explicitly `omit`, `preserve`, or `throw`.
141
+
142
+ ## Component gallery
143
+
144
+ Copy `starter/astro/src/pages/style-guide.astro` into a project. The route is
145
+ unlinked and includes `noindex, nofollow`. Register every new component and
146
+ show every meaningful state before considering it reusable.
147
+
148
+ ## v14.23 guidance
149
+
150
+ Executable code comes from npm. Reviewed workflow and project canon come from
151
+ the existing v14.23 MCP endpoint through the `web_framework` module. UI work
152
+ requests both `design_authoring` and `web_framework`; structural-only work may
153
+ request `web_framework`. Version drift is advisory and must never edit
154
+ dependencies automatically.
155
+
156
+ ## Development and release
157
+
158
+ ```sh
159
+ npm ci
160
+ npm run check
161
+ npm test
162
+ npm run pack:artifact
163
+ npm run test:fixtures
164
+ npm run test:browser
165
+ npm run pack:inspect
166
+ ```
167
+
168
+ `pack:artifact` creates the single release tarball. Fixture tests, inspection,
169
+ and publication all use that same file rather than silently repacking it.
170
+ Releases are immutable. Tag the exact verified commit as `v0.1.0`; the included
171
+ workflow publishes the verified tarball with npm provenance.
@@ -0,0 +1,13 @@
1
+ export { default as PageFlow } from "../../src/astro/PageFlow.astro";
2
+ export { default as Section } from "../../src/astro/Section.astro";
3
+ export { default as SectionGroup } from "../../src/astro/SectionGroup.astro";
4
+ export { default as Container } from "../../src/astro/Container.astro";
5
+ export { default as Stack } from "../../src/astro/Stack.astro";
6
+ export { default as Cluster } from "../../src/astro/Cluster.astro";
7
+ export { default as Grid } from "../../src/astro/Grid.astro";
8
+ export { default as VisualFrame } from "../../src/astro/VisualFrame.astro";
9
+ export { default as Heading } from "../../src/astro/Heading.astro";
10
+ export { default as Text } from "../../src/astro/Text.astro";
11
+ export { default as Action } from "../../src/astro/Action.astro";
12
+ export { default as CardShell } from "../../src/astro/CardShell.astro";
13
+ export { default as Disclosure } from "../../src/astro/Disclosure.astro";
@@ -0,0 +1,13 @@
1
+ export interface CarouselItem {
2
+ id: string;
3
+ label: string;
4
+ description?: string;
5
+ }
6
+ export interface CarouselProps {
7
+ label: string;
8
+ items: readonly CarouselItem[];
9
+ previousLabel?: string;
10
+ nextLabel?: string;
11
+ }
12
+ export declare function Carousel({ label, items, previousLabel, nextLabel }: CarouselProps): import("react").JSX.Element | null;
13
+ //# sourceMappingURL=Carousel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Carousel.d.ts","sourceRoot":"","sources":["../../src/react/Carousel.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,aAA0B,EAC1B,SAAkB,EACnB,EAAE,aAAa,sCAqCf"}
@@ -0,0 +1,14 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useId, useState } from "react";
3
+ export function Carousel({ label, items, previousLabel = "Previous", nextLabel = "Next" }) {
4
+ const id = useId();
5
+ const [index, setIndex] = useState(0);
6
+ const active = items[index];
7
+ if (!active)
8
+ return null;
9
+ const move = (offset) => {
10
+ setIndex((current) => (current + offset + items.length) % items.length);
11
+ };
12
+ return (_jsxs("section", { "data-slf-island": "carousel", role: "region", "aria-roledescription": "carousel", "aria-label": label, children: [_jsxs("div", { id: `${id}-slide`, "aria-live": "polite", "aria-atomic": "true", children: [_jsxs("p", { children: [_jsxs("span", { className: "slf-visually-hidden", children: ["Item ", index + 1, " of ", items.length, ":", " "] }), active.label] }), active.description ? _jsx("p", { children: active.description }) : null] }), _jsxs("div", { children: [_jsx("button", { type: "button", onClick: () => move(-1), "aria-controls": `${id}-slide`, children: previousLabel }), _jsx("button", { type: "button", onClick: () => move(1), "aria-controls": `${id}-slide`, children: nextLabel })] })] }));
13
+ }
14
+ //# sourceMappingURL=Carousel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Carousel.js","sourceRoot":"","sources":["../../src/react/Carousel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAexC,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,aAAa,GAAG,UAAU,EAC1B,SAAS,GAAG,MAAM,EACJ;IACd,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE5B,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,EAAE;QAC9B,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1E,CAAC,CAAC;IAEF,OAAO,CACL,sCACkB,UAAU,EAC1B,IAAI,EAAC,QAAQ,0BACQ,UAAU,gBACnB,KAAK,aAEjB,eAAK,EAAE,EAAE,GAAG,EAAE,QAAQ,eAAY,QAAQ,iBAAa,MAAM,aAC3D,wBACE,gBAAM,SAAS,EAAC,qBAAqB,sBAC7B,KAAK,GAAG,CAAC,UAAM,KAAK,CAAC,MAAM,OAAG,GAAG,IAClC,EACN,MAAM,CAAC,KAAK,IACX,EACH,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,sBAAI,MAAM,CAAC,WAAW,GAAK,CAAC,CAAC,CAAC,IAAI,IACpD,EACN,0BACE,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,mBAAiB,GAAG,EAAE,QAAQ,YACxE,aAAa,GACP,EACT,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAiB,GAAG,EAAE,QAAQ,YACvE,SAAS,GACH,IACL,IACE,CACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface DialogProps {
2
+ triggerLabel: string;
3
+ title: string;
4
+ description: string;
5
+ closeLabel?: string;
6
+ }
7
+ export declare function Dialog({ triggerLabel, title, description, closeLabel }: DialogProps): import("react").JSX.Element;
8
+ //# sourceMappingURL=Dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../src/react/Dialog.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,MAAM,CAAC,EACrB,YAAY,EACZ,KAAK,EACL,WAAW,EACX,UAAoB,EACrB,EAAE,WAAW,+BAsCb"}
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from "react";
3
+ export function Dialog({ triggerLabel, title, description, closeLabel = "Close" }) {
4
+ const [open, setOpen] = useState(false);
5
+ const dialog = useRef(null);
6
+ const trigger = useRef(null);
7
+ const titleId = useId();
8
+ const descriptionId = useId();
9
+ useEffect(() => {
10
+ const element = dialog.current;
11
+ if (!element)
12
+ return;
13
+ if (open && !element.open)
14
+ element.showModal();
15
+ if (!open && element.open)
16
+ element.close();
17
+ }, [open]);
18
+ return (_jsxs("div", { "data-slf-island": "dialog", children: [_jsx("button", { ref: trigger, type: "button", onClick: () => setOpen(true), children: triggerLabel }), _jsxs("dialog", { ref: dialog, "aria-labelledby": titleId, "aria-describedby": descriptionId, onClose: () => {
19
+ setOpen(false);
20
+ trigger.current?.focus();
21
+ }, onCancel: () => setOpen(false), children: [_jsx("h2", { id: titleId, children: title }), _jsx("p", { id: descriptionId, children: description }), _jsx("button", { type: "button", onClick: () => setOpen(false), children: closeLabel })] })] }));
22
+ }
23
+ //# sourceMappingURL=Dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../src/react/Dialog.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAS3D,MAAM,UAAU,MAAM,CAAC,EACrB,YAAY,EACZ,KAAK,EACL,WAAW,EACX,UAAU,GAAG,OAAO,EACR;IACZ,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IACxB,MAAM,aAAa,GAAG,KAAK,EAAE,CAAC;IAE9B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI;YAAE,OAAO,CAAC,SAAS,EAAE,CAAC;QAC/C,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;YAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IAC7C,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACL,kCAAqB,QAAQ,aAC3B,iBAAQ,GAAG,EAAE,OAAO,EAAE,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,YAC7D,YAAY,GACN,EACT,kBACE,GAAG,EAAE,MAAM,qBACM,OAAO,sBACN,aAAa,EAC/B,OAAO,EAAE,GAAG,EAAE;oBACZ,OAAO,CAAC,KAAK,CAAC,CAAC;oBACf,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;gBAC3B,CAAC,EACD,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,aAE9B,aAAI,EAAE,EAAE,OAAO,YAAG,KAAK,GAAM,EAC7B,YAAG,EAAE,EAAE,aAAa,YAAG,WAAW,GAAK,EACvC,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAChD,UAAU,GACJ,IACF,IACL,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface MenuItem {
2
+ id: string;
3
+ label: string;
4
+ href: string;
5
+ }
6
+ export interface MenuProps {
7
+ label: string;
8
+ items: readonly MenuItem[];
9
+ }
10
+ export declare function Menu({ label, items }: MenuProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=Menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../../src/react/Menu.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;CAC5B;AAED,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,SAAS,+BA2E/C"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from "react";
3
+ export function Menu({ label, items }) {
4
+ const id = useId();
5
+ const [open, setOpen] = useState(false);
6
+ const trigger = useRef(null);
7
+ const links = useRef([]);
8
+ useEffect(() => {
9
+ if (open)
10
+ links.current[0]?.focus();
11
+ }, [open]);
12
+ function onTriggerKeyDown(event) {
13
+ if (event.key === "ArrowDown") {
14
+ event.preventDefault();
15
+ setOpen(true);
16
+ }
17
+ }
18
+ function onMenuKeyDown(event) {
19
+ const current = links.current.indexOf(document.activeElement);
20
+ if (event.key === "Escape") {
21
+ event.preventDefault();
22
+ setOpen(false);
23
+ trigger.current?.focus();
24
+ }
25
+ else if (event.key === "ArrowDown") {
26
+ event.preventDefault();
27
+ links.current[(current + 1 + items.length) % items.length]?.focus();
28
+ }
29
+ else if (event.key === "ArrowUp") {
30
+ event.preventDefault();
31
+ links.current[(current - 1 + items.length) % items.length]?.focus();
32
+ }
33
+ else if (event.key === "Home") {
34
+ event.preventDefault();
35
+ links.current[0]?.focus();
36
+ }
37
+ else if (event.key === "End") {
38
+ event.preventDefault();
39
+ links.current[items.length - 1]?.focus();
40
+ }
41
+ }
42
+ return (_jsxs("div", { "data-slf-island": "menu", children: [_jsx("button", { ref: trigger, type: "button", "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": `${id}-menu`, onClick: () => setOpen((value) => !value), onKeyDown: onTriggerKeyDown, children: label }), _jsx("ul", { id: `${id}-menu`, role: "menu", hidden: !open, onKeyDown: onMenuKeyDown, children: items.map((item, index) => (_jsx("li", { role: "none", children: _jsx("a", { ref: (node) => {
43
+ links.current[index] = node;
44
+ }, role: "menuitem", href: item.href, tabIndex: open ? 0 : -1, onClick: () => setOpen(false), children: item.label }) }, item.id))) })] }));
45
+ }
46
+ //# sourceMappingURL=Menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menu.js","sourceRoot":"","sources":["../../src/react/Menu.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface TabItem {
2
+ id: string;
3
+ label: string;
4
+ content: string;
5
+ }
6
+ export interface TabsProps {
7
+ label: string;
8
+ items: readonly TabItem[];
9
+ initialId?: string;
10
+ }
11
+ export declare function Tabs({ label, items, initialId }: TabsProps): import("react").JSX.Element | null;
12
+ //# sourceMappingURL=Tabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../src/react/Tabs.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,sCA2E1D"}
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId, useRef, useState } from "react";
3
+ export function Tabs({ label, items, initialId }) {
4
+ const generatedId = useId();
5
+ const initialIndex = Math.max(0, initialId ? items.findIndex((item) => item.id === initialId) : 0);
6
+ const [activeIndex, setActiveIndex] = useState(initialIndex);
7
+ const buttons = useRef([]);
8
+ const active = items[activeIndex];
9
+ if (!active)
10
+ return null;
11
+ function select(index) {
12
+ const next = (index + items.length) % items.length;
13
+ setActiveIndex(next);
14
+ buttons.current[next]?.focus();
15
+ }
16
+ function onKeyDown(event, index) {
17
+ if (event.key === "ArrowRight") {
18
+ event.preventDefault();
19
+ select(index + 1);
20
+ }
21
+ else if (event.key === "ArrowLeft") {
22
+ event.preventDefault();
23
+ select(index - 1);
24
+ }
25
+ else if (event.key === "Home") {
26
+ event.preventDefault();
27
+ select(0);
28
+ }
29
+ else if (event.key === "End") {
30
+ event.preventDefault();
31
+ select(items.length - 1);
32
+ }
33
+ }
34
+ return (_jsxs("div", { "data-slf-island": "tabs", children: [_jsx("div", { role: "tablist", "aria-label": label, children: items.map((item, index) => {
35
+ const tabId = `${generatedId}-tab-${item.id}`;
36
+ const panelId = `${generatedId}-panel-${item.id}`;
37
+ const selected = activeIndex === index;
38
+ return (_jsx("button", { ref: (node) => {
39
+ buttons.current[index] = node;
40
+ }, id: tabId, type: "button", role: "tab", "aria-selected": selected, "aria-controls": panelId, tabIndex: selected ? 0 : -1, onClick: () => setActiveIndex(index), onKeyDown: (event) => onKeyDown(event, index), children: item.label }, item.id));
41
+ }) }), items.map((item, index) => (_jsx("div", { id: `${generatedId}-panel-${item.id}`, role: "tabpanel", "aria-labelledby": `${generatedId}-tab-${item.id}`, hidden: activeIndex !== index, tabIndex: 0, children: item.content }, item.id)))] }));
42
+ }
43
+ //# sourceMappingURL=Tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tabs.js","sourceRoot":"","sources":["../../src/react/Tabs.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { Carousel } from "./Carousel.js";
2
+ export type { CarouselItem, CarouselProps } from "./Carousel.js";
3
+ export { Dialog } from "./Dialog.js";
4
+ export type { DialogProps } from "./Dialog.js";
5
+ export { Menu } from "./Menu.js";
6
+ export type { MenuItem, MenuProps } from "./Menu.js";
7
+ export { Tabs } from "./Tabs.js";
8
+ export type { TabItem, TabsProps } from "./Tabs.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { Carousel } from "./Carousel.js";
2
+ export { Dialog } from "./Dialog.js";
3
+ export { Menu } from "./Menu.js";
4
+ export { Tabs } from "./Tabs.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,197 @@
1
+ export type ComponentKind = "primitive" | "section" | "island" | "pattern";
2
+ export type ComponentStatus = "stable" | "experimental" | "deprecated";
3
+ export interface CatalogScenario {
4
+ id: string;
5
+ label: string;
6
+ description?: string;
7
+ }
8
+ export interface ComponentDefinition<Variant extends string = string> {
9
+ id: string;
10
+ kind: ComponentKind;
11
+ variants: readonly Variant[];
12
+ status: ComponentStatus;
13
+ provenance: string;
14
+ scenarios: readonly CatalogScenario[];
15
+ }
16
+ export interface ComponentRegistry<Definition extends ComponentDefinition = ComponentDefinition> {
17
+ readonly components: readonly Definition[];
18
+ get(id: string): Definition | undefined;
19
+ has(id: string): boolean;
20
+ require(id: string): Definition;
21
+ }
22
+ export declare function defineComponentRegistry<const Definition extends ComponentDefinition>(components: readonly Definition[]): ComponentRegistry<Definition>;
23
+ export declare const frameworkRegistry: ComponentRegistry<{
24
+ readonly id: "page-flow";
25
+ readonly kind: "primitive";
26
+ readonly variants: readonly ["main", "div"];
27
+ readonly status: "stable";
28
+ readonly provenance: "@spark-line/web-framework";
29
+ readonly scenarios: readonly [{
30
+ readonly id: "default";
31
+ readonly label: "Page flow";
32
+ }];
33
+ } | {
34
+ readonly id: "section";
35
+ readonly kind: "primitive";
36
+ readonly variants: readonly ["default", "inverse", "accent", "quiet"];
37
+ readonly status: "stable";
38
+ readonly provenance: "@spark-line/web-framework";
39
+ readonly scenarios: readonly [{
40
+ readonly id: "themes";
41
+ readonly label: "Themes";
42
+ }, {
43
+ readonly id: "spacing";
44
+ readonly label: "Spacing edges";
45
+ }];
46
+ } | {
47
+ readonly id: "section-group";
48
+ readonly kind: "primitive";
49
+ readonly variants: readonly ["joined", "overlap"];
50
+ readonly status: "stable";
51
+ readonly provenance: "@spark-line/web-framework";
52
+ readonly scenarios: readonly [{
53
+ readonly id: "modes";
54
+ readonly label: "Grouping modes";
55
+ }];
56
+ } | {
57
+ readonly id: "container";
58
+ readonly kind: "primitive";
59
+ readonly variants: readonly ["narrow", "content", "wide", "full"];
60
+ readonly status: "stable";
61
+ readonly provenance: "@spark-line/web-framework";
62
+ readonly scenarios: readonly [{
63
+ readonly id: "widths";
64
+ readonly label: "Container widths";
65
+ }];
66
+ } | {
67
+ readonly id: "stack";
68
+ readonly kind: "primitive";
69
+ readonly variants: readonly ["none", "xs", "sm", "md", "lg", "xl"];
70
+ readonly status: "stable";
71
+ readonly provenance: "@spark-line/web-framework";
72
+ readonly scenarios: readonly [{
73
+ readonly id: "gaps";
74
+ readonly label: "Vertical gaps";
75
+ }];
76
+ } | {
77
+ readonly id: "cluster";
78
+ readonly kind: "primitive";
79
+ readonly variants: readonly ["start", "center", "end", "between"];
80
+ readonly status: "stable";
81
+ readonly provenance: "@spark-line/web-framework";
82
+ readonly scenarios: readonly [{
83
+ readonly id: "alignment";
84
+ readonly label: "Wrapped alignment";
85
+ }];
86
+ } | {
87
+ readonly id: "grid";
88
+ readonly kind: "primitive";
89
+ readonly variants: readonly ["fixed", "auto-fit", "auto-fill"];
90
+ readonly status: "stable";
91
+ readonly provenance: "@spark-line/web-framework";
92
+ readonly scenarios: readonly [{
93
+ readonly id: "responsive";
94
+ readonly label: "Responsive columns";
95
+ }];
96
+ } | {
97
+ readonly id: "visual-frame";
98
+ readonly kind: "primitive";
99
+ readonly variants: readonly ["aspect-ratio", "reserved-block-size"];
100
+ readonly status: "stable";
101
+ readonly provenance: "@spark-line/web-framework";
102
+ readonly scenarios: readonly [{
103
+ readonly id: "reserved-space";
104
+ readonly label: "Reserved visual space";
105
+ }];
106
+ } | {
107
+ readonly id: "heading";
108
+ readonly kind: "primitive";
109
+ readonly variants: readonly ["display", "h1", "h2", "h3", "h4", "h5", "h6"];
110
+ readonly status: "stable";
111
+ readonly provenance: "@spark-line/web-framework";
112
+ readonly scenarios: readonly [{
113
+ readonly id: "scale";
114
+ readonly label: "Project type scale";
115
+ }];
116
+ } | {
117
+ readonly id: "text";
118
+ readonly kind: "primitive";
119
+ readonly variants: readonly ["small", "body", "lead", "muted"];
120
+ readonly status: "stable";
121
+ readonly provenance: "@spark-line/web-framework";
122
+ readonly scenarios: readonly [{
123
+ readonly id: "scale";
124
+ readonly label: "Text roles";
125
+ }];
126
+ } | {
127
+ readonly id: "action";
128
+ readonly kind: "primitive";
129
+ readonly variants: readonly ["primary", "secondary", "quiet"];
130
+ readonly status: "stable";
131
+ readonly provenance: "@spark-line/web-framework";
132
+ readonly scenarios: readonly [{
133
+ readonly id: "states";
134
+ readonly label: "Actions and focus states";
135
+ }];
136
+ } | {
137
+ readonly id: "card-shell";
138
+ readonly kind: "primitive";
139
+ readonly variants: readonly ["default", "quiet", "accent"];
140
+ readonly status: "stable";
141
+ readonly provenance: "@spark-line/web-framework";
142
+ readonly scenarios: readonly [{
143
+ readonly id: "surfaces";
144
+ readonly label: "Project card surfaces";
145
+ }];
146
+ } | {
147
+ readonly id: "disclosure";
148
+ readonly kind: "primitive";
149
+ readonly variants: readonly ["closed", "open"];
150
+ readonly status: "stable";
151
+ readonly provenance: "@spark-line/web-framework";
152
+ readonly scenarios: readonly [{
153
+ readonly id: "native";
154
+ readonly label: "Native disclosure";
155
+ }];
156
+ } | {
157
+ readonly id: "tabs";
158
+ readonly kind: "island";
159
+ readonly variants: readonly ["default"];
160
+ readonly status: "experimental";
161
+ readonly provenance: "@spark-line/web-framework";
162
+ readonly scenarios: readonly [{
163
+ readonly id: "keyboard";
164
+ readonly label: "Keyboard tabs";
165
+ }];
166
+ } | {
167
+ readonly id: "carousel";
168
+ readonly kind: "island";
169
+ readonly variants: readonly ["default"];
170
+ readonly status: "experimental";
171
+ readonly provenance: "@spark-line/web-framework";
172
+ readonly scenarios: readonly [{
173
+ readonly id: "controls";
174
+ readonly label: "Previous and next controls";
175
+ }];
176
+ } | {
177
+ readonly id: "dialog";
178
+ readonly kind: "island";
179
+ readonly variants: readonly ["modal"];
180
+ readonly status: "experimental";
181
+ readonly provenance: "@spark-line/web-framework";
182
+ readonly scenarios: readonly [{
183
+ readonly id: "native";
184
+ readonly label: "Native modal dialog";
185
+ }];
186
+ } | {
187
+ readonly id: "menu";
188
+ readonly kind: "island";
189
+ readonly variants: readonly ["links"];
190
+ readonly status: "experimental";
191
+ readonly provenance: "@spark-line/web-framework";
192
+ readonly scenarios: readonly [{
193
+ readonly id: "keyboard";
194
+ readonly label: "Keyboard menu";
195
+ }];
196
+ }>;
197
+ //# sourceMappingURL=index.d.ts.map