@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,cAAc,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB,CAChC,UAAU,SAAS,mBAAmB,GAAG,mBAAmB;IAE5D,QAAQ,CAAC,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC;IAC3C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACxC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC;CACjC;AAED,wBAAgB,uBAAuB,CACrC,KAAK,CAAC,UAAU,SAAS,mBAAmB,EAC5C,UAAU,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,CA6BlE;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4InB,CAAC"}
@@ -0,0 +1,170 @@
1
+ export function defineComponentRegistry(components) {
2
+ const byId = new Map();
3
+ for (const component of components) {
4
+ if (byId.has(component.id)) {
5
+ throw new Error(`Duplicate component id: ${component.id}`);
6
+ }
7
+ if (component.scenarios.length === 0) {
8
+ throw new Error(`Component ${component.id} needs at least one catalog scenario`);
9
+ }
10
+ byId.set(component.id, Object.freeze(component));
11
+ }
12
+ const frozenComponents = Object.freeze([...components]);
13
+ return Object.freeze({
14
+ components: frozenComponents,
15
+ get(id) {
16
+ return byId.get(id);
17
+ },
18
+ has(id) {
19
+ return byId.has(id);
20
+ },
21
+ require(id) {
22
+ const component = byId.get(id);
23
+ if (!component)
24
+ throw new Error(`Unknown component id: ${id}`);
25
+ return component;
26
+ }
27
+ });
28
+ }
29
+ export const frameworkRegistry = defineComponentRegistry([
30
+ {
31
+ id: "page-flow",
32
+ kind: "primitive",
33
+ variants: ["main", "div"],
34
+ status: "stable",
35
+ provenance: "@spark-line/web-framework",
36
+ scenarios: [{ id: "default", label: "Page flow" }]
37
+ },
38
+ {
39
+ id: "section",
40
+ kind: "primitive",
41
+ variants: ["default", "inverse", "accent", "quiet"],
42
+ status: "stable",
43
+ provenance: "@spark-line/web-framework",
44
+ scenarios: [
45
+ { id: "themes", label: "Themes" },
46
+ { id: "spacing", label: "Spacing edges" }
47
+ ]
48
+ },
49
+ {
50
+ id: "section-group",
51
+ kind: "primitive",
52
+ variants: ["joined", "overlap"],
53
+ status: "stable",
54
+ provenance: "@spark-line/web-framework",
55
+ scenarios: [{ id: "modes", label: "Grouping modes" }]
56
+ },
57
+ {
58
+ id: "container",
59
+ kind: "primitive",
60
+ variants: ["narrow", "content", "wide", "full"],
61
+ status: "stable",
62
+ provenance: "@spark-line/web-framework",
63
+ scenarios: [{ id: "widths", label: "Container widths" }]
64
+ },
65
+ {
66
+ id: "stack",
67
+ kind: "primitive",
68
+ variants: ["none", "xs", "sm", "md", "lg", "xl"],
69
+ status: "stable",
70
+ provenance: "@spark-line/web-framework",
71
+ scenarios: [{ id: "gaps", label: "Vertical gaps" }]
72
+ },
73
+ {
74
+ id: "cluster",
75
+ kind: "primitive",
76
+ variants: ["start", "center", "end", "between"],
77
+ status: "stable",
78
+ provenance: "@spark-line/web-framework",
79
+ scenarios: [{ id: "alignment", label: "Wrapped alignment" }]
80
+ },
81
+ {
82
+ id: "grid",
83
+ kind: "primitive",
84
+ variants: ["fixed", "auto-fit", "auto-fill"],
85
+ status: "stable",
86
+ provenance: "@spark-line/web-framework",
87
+ scenarios: [{ id: "responsive", label: "Responsive columns" }]
88
+ },
89
+ {
90
+ id: "visual-frame",
91
+ kind: "primitive",
92
+ variants: ["aspect-ratio", "reserved-block-size"],
93
+ status: "stable",
94
+ provenance: "@spark-line/web-framework",
95
+ scenarios: [{ id: "reserved-space", label: "Reserved visual space" }]
96
+ },
97
+ {
98
+ id: "heading",
99
+ kind: "primitive",
100
+ variants: ["display", "h1", "h2", "h3", "h4", "h5", "h6"],
101
+ status: "stable",
102
+ provenance: "@spark-line/web-framework",
103
+ scenarios: [{ id: "scale", label: "Project type scale" }]
104
+ },
105
+ {
106
+ id: "text",
107
+ kind: "primitive",
108
+ variants: ["small", "body", "lead", "muted"],
109
+ status: "stable",
110
+ provenance: "@spark-line/web-framework",
111
+ scenarios: [{ id: "scale", label: "Text roles" }]
112
+ },
113
+ {
114
+ id: "action",
115
+ kind: "primitive",
116
+ variants: ["primary", "secondary", "quiet"],
117
+ status: "stable",
118
+ provenance: "@spark-line/web-framework",
119
+ scenarios: [{ id: "states", label: "Actions and focus states" }]
120
+ },
121
+ {
122
+ id: "card-shell",
123
+ kind: "primitive",
124
+ variants: ["default", "quiet", "accent"],
125
+ status: "stable",
126
+ provenance: "@spark-line/web-framework",
127
+ scenarios: [{ id: "surfaces", label: "Project card surfaces" }]
128
+ },
129
+ {
130
+ id: "disclosure",
131
+ kind: "primitive",
132
+ variants: ["closed", "open"],
133
+ status: "stable",
134
+ provenance: "@spark-line/web-framework",
135
+ scenarios: [{ id: "native", label: "Native disclosure" }]
136
+ },
137
+ {
138
+ id: "tabs",
139
+ kind: "island",
140
+ variants: ["default"],
141
+ status: "experimental",
142
+ provenance: "@spark-line/web-framework",
143
+ scenarios: [{ id: "keyboard", label: "Keyboard tabs" }]
144
+ },
145
+ {
146
+ id: "carousel",
147
+ kind: "island",
148
+ variants: ["default"],
149
+ status: "experimental",
150
+ provenance: "@spark-line/web-framework",
151
+ scenarios: [{ id: "controls", label: "Previous and next controls" }]
152
+ },
153
+ {
154
+ id: "dialog",
155
+ kind: "island",
156
+ variants: ["modal"],
157
+ status: "experimental",
158
+ provenance: "@spark-line/web-framework",
159
+ scenarios: [{ id: "native", label: "Native modal dialog" }]
160
+ },
161
+ {
162
+ id: "menu",
163
+ kind: "island",
164
+ variants: ["links"],
165
+ status: "experimental",
166
+ provenance: "@spark-line/web-framework",
167
+ scenarios: [{ id: "keyboard", label: "Keyboard menu" }]
168
+ }
169
+ ]);
170
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ export type SectionTheme = "default" | "inverse" | "accent" | "quiet";
2
+ export type SectionSpace = "none" | "xs" | "sm" | "md" | "lg" | "xl";
3
+ export interface SanitySectionRecord {
4
+ _type: string;
5
+ _key?: string;
6
+ theme?: SectionTheme;
7
+ spaceTop?: SectionSpace;
8
+ spaceBottom?: SectionSpace;
9
+ layout?: string;
10
+ [field: string]: unknown;
11
+ }
12
+ export interface SectionRegistration {
13
+ type: string;
14
+ componentId: string;
15
+ layouts?: readonly string[];
16
+ themes?: readonly SectionTheme[];
17
+ spaces?: readonly SectionSpace[];
18
+ defaults?: {
19
+ layout?: string;
20
+ theme?: SectionTheme;
21
+ spaceTop?: SectionSpace;
22
+ spaceBottom?: SectionSpace;
23
+ };
24
+ }
25
+ export interface SectionRegistry {
26
+ readonly sections: readonly SectionRegistration[];
27
+ get(type: string): SectionRegistration | undefined;
28
+ require(type: string): SectionRegistration;
29
+ }
30
+ export interface NormalizedSection {
31
+ key: string;
32
+ type: string;
33
+ componentId: string | null;
34
+ props: SanitySectionRecord;
35
+ source: SanitySectionRecord;
36
+ known: boolean;
37
+ }
38
+ export type UnknownSectionPolicy = "omit" | "preserve" | "throw";
39
+ export declare function defineSectionRegistry(sections: readonly SectionRegistration[]): SectionRegistry;
40
+ export declare function normalizePageSections(records: readonly SanitySectionRecord[], registry: SectionRegistry, options?: {
41
+ onUnknown?: UnknownSectionPolicy;
42
+ }): NormalizedSection[];
43
+ export interface SectionSchemaOptions {
44
+ name: string;
45
+ title: string;
46
+ sectionTypes: readonly string[];
47
+ themes?: readonly SectionTheme[];
48
+ spaces?: readonly SectionSpace[];
49
+ layouts?: readonly string[];
50
+ }
51
+ export declare function defineSectionSchema(options: SectionSchemaOptions): {
52
+ readonly name: string;
53
+ readonly title: string;
54
+ readonly type: "object";
55
+ readonly fields: Record<string, unknown>[];
56
+ };
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sanity/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AACtE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE;QACT,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,YAAY,CAAC;QACrB,QAAQ,CAAC,EAAE,YAAY,CAAC;QACxB,WAAW,CAAC,EAAE,YAAY,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAClD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAAC;IACnD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAAC;CAC5C;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjE,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,GACvC,eAAe,CAsBjB;AAsBD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,QAAQ,EAAE,eAAe,EACzB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,oBAAoB,CAAA;CAAO,GACjD,iBAAiB,EAAE,CA4CrB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACjC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB;;;;;EA2ChE"}
@@ -0,0 +1,117 @@
1
+ export function defineSectionRegistry(sections) {
2
+ const byType = new Map();
3
+ for (const section of sections) {
4
+ if (byType.has(section.type)) {
5
+ throw new Error(`Duplicate Sanity section type: ${section.type}`);
6
+ }
7
+ byType.set(section.type, Object.freeze({ ...section }));
8
+ }
9
+ const frozenSections = Object.freeze([...byType.values()]);
10
+ return Object.freeze({
11
+ sections: frozenSections,
12
+ get(type) {
13
+ return byType.get(type);
14
+ },
15
+ require(type) {
16
+ const section = byType.get(type);
17
+ if (!section)
18
+ throw new Error(`Unknown Sanity section type: ${type}`);
19
+ return section;
20
+ }
21
+ });
22
+ }
23
+ function assertAllowed(section, field, value) {
24
+ if (value === undefined)
25
+ return;
26
+ const allowed = field === "layout"
27
+ ? section.layouts
28
+ : field === "theme"
29
+ ? section.themes
30
+ : section.spaces;
31
+ if (allowed && !allowed.includes(value)) {
32
+ throw new Error(`Invalid ${field} "${value}" for ${section.type}; expected ${allowed.join(", ")}`);
33
+ }
34
+ }
35
+ export function normalizePageSections(records, registry, options = {}) {
36
+ const policy = options.onUnknown ?? "omit";
37
+ const normalized = [];
38
+ records.forEach((record, index) => {
39
+ const registration = registry.get(record._type);
40
+ if (!registration) {
41
+ if (policy === "throw") {
42
+ throw new Error(`Unknown Sanity section type: ${record._type}`);
43
+ }
44
+ if (policy === "preserve") {
45
+ normalized.push({
46
+ key: record._key ?? `${record._type}-${index}`,
47
+ type: record._type,
48
+ componentId: null,
49
+ props: { ...record },
50
+ source: record,
51
+ known: false
52
+ });
53
+ }
54
+ return;
55
+ }
56
+ const props = {
57
+ ...registration.defaults,
58
+ ...record
59
+ };
60
+ assertAllowed(registration, "layout", props.layout);
61
+ assertAllowed(registration, "theme", props.theme);
62
+ assertAllowed(registration, "spaceTop", props.spaceTop);
63
+ assertAllowed(registration, "spaceBottom", props.spaceBottom);
64
+ normalized.push({
65
+ key: record._key ?? `${record._type}-${index}`,
66
+ type: record._type,
67
+ componentId: registration.componentId,
68
+ props,
69
+ source: record,
70
+ known: true
71
+ });
72
+ });
73
+ return normalized;
74
+ }
75
+ export function defineSectionSchema(options) {
76
+ const fields = [
77
+ {
78
+ name: "sections",
79
+ title: "Sections",
80
+ type: "array",
81
+ of: options.sectionTypes.map((type) => ({ type }))
82
+ }
83
+ ];
84
+ if (options.themes?.length) {
85
+ fields.push({
86
+ name: "theme",
87
+ title: "Theme",
88
+ type: "string",
89
+ options: { list: options.themes }
90
+ });
91
+ }
92
+ if (options.spaces?.length) {
93
+ for (const edge of ["spaceTop", "spaceBottom"]) {
94
+ fields.push({
95
+ name: edge,
96
+ title: edge === "spaceTop" ? "Space above" : "Space below",
97
+ type: "string",
98
+ options: { list: options.spaces }
99
+ });
100
+ }
101
+ }
102
+ if (options.layouts?.length) {
103
+ fields.push({
104
+ name: "layout",
105
+ title: "Layout",
106
+ type: "string",
107
+ options: { list: options.layouts }
108
+ });
109
+ }
110
+ return {
111
+ name: options.name,
112
+ title: options.title,
113
+ type: "object",
114
+ fields
115
+ };
116
+ }
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sanity/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@spark-line/web-framework",
3
+ "version": "0.1.0",
4
+ "description": "Structural UI contracts and accessible primitives for Astro, optional React islands, and optional Sanity section data.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "sideEffects": [
8
+ "./styles/*.css"
9
+ ],
10
+ "files": [
11
+ "dist/",
12
+ "src/astro/",
13
+ "styles/",
14
+ "starter/",
15
+ "skills/",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "exports": {
20
+ "./astro": {
21
+ "types": "./src/astro/index.d.ts",
22
+ "import": "./dist/astro/index.js",
23
+ "default": "./dist/astro/index.js"
24
+ },
25
+ "./react": {
26
+ "types": "./dist/react/index.d.ts",
27
+ "import": "./dist/react/index.js",
28
+ "default": "./dist/react/index.js"
29
+ },
30
+ "./sanity": {
31
+ "types": "./dist/sanity/index.d.ts",
32
+ "import": "./dist/sanity/index.js",
33
+ "default": "./dist/sanity/index.js"
34
+ },
35
+ "./registry": {
36
+ "types": "./dist/registry/index.d.ts",
37
+ "import": "./dist/registry/index.js",
38
+ "default": "./dist/registry/index.js"
39
+ },
40
+ "./styles/foundation.css": "./styles/foundation.css",
41
+ "./package.json": "./package.json"
42
+ },
43
+ "scripts": {
44
+ "build": "npm run clean && tsc -p tsconfig.build.json && node scripts/build.mjs",
45
+ "check": "tsc -p tsconfig.build.json --noEmit && node scripts/validate-package.mjs",
46
+ "clean": "node scripts/clean.mjs",
47
+ "test": "npm run build && node --test tests/*.test.mjs",
48
+ "pack:artifact": "node scripts/create-pack.mjs",
49
+ "test:fixtures": "node scripts/test-packed-fixtures.mjs",
50
+ "test:browser": "node scripts/test-browser.mjs",
51
+ "pack:inspect": "node scripts/inspect-pack.mjs",
52
+ "prepack": "npm run build && npm run check && npm test"
53
+ },
54
+ "peerDependencies": {
55
+ "astro": ">=5 <8",
56
+ "react": ">=18 <20",
57
+ "react-dom": ">=18 <20",
58
+ "sanity": ">=3 <5"
59
+ },
60
+ "peerDependenciesMeta": {
61
+ "react": {
62
+ "optional": true
63
+ },
64
+ "react-dom": {
65
+ "optional": true
66
+ },
67
+ "sanity": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "devDependencies": {
72
+ "@axe-core/playwright": "^4.10.2",
73
+ "@playwright/test": "^1.54.2",
74
+ "@types/react": "^19.1.8",
75
+ "@types/react-dom": "^19.1.6",
76
+ "astro": "^7.0.3",
77
+ "react": "^19.2.7",
78
+ "react-dom": "^19.2.7",
79
+ "typescript": "^5.9.2"
80
+ },
81
+ "engines": {
82
+ "node": ">=20"
83
+ },
84
+ "publishConfig": {
85
+ "access": "public",
86
+ "provenance": true
87
+ },
88
+ "repository": {
89
+ "type": "git",
90
+ "url": "git+https://github.com/McTavin/spark-line-web-framework.git"
91
+ },
92
+ "bugs": {
93
+ "url": "https://github.com/McTavin/spark-line-web-framework/issues"
94
+ },
95
+ "homepage": "https://github.com/McTavin/spark-line-web-framework#readme"
96
+ }
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: spark-line-web-framework
3
+ description: Inspect, reuse, create, refactor, and verify Spark Line interfaces built with Astro, optional Sanity content, and React islands using the @spark-line/web-framework contracts. Use for page or section design changes, component creation, screenshot or source-faithful implementation, responsive layout corrections, component-gallery work, section adjacency bugs, or frontend architecture decisions in this stack.
4
+ ---
5
+
6
+ # Spark Line Web Framework
7
+
8
+ Use `@spark-line/web-framework` for structural contracts. Keep project identity,
9
+ content, and approved visual decisions in the project's v14.23 context.
10
+
11
+ ## Start with governed context
12
+
13
+ 1. Read the repository instructions and `v1423.project.json` when present.
14
+ 2. Follow the repository's required v14.23 handshake exactly.
15
+ 3. Request `context_modules: ["design_authoring", "web_framework"]` for visual
16
+ or copy work. Request `["web_framework"]` for purely structural frontend work.
17
+ 4. Treat framework-version drift as advisory. Never edit dependencies
18
+ automatically.
19
+ 5. If governed context is unavailable, record the repo-visible fallback required
20
+ by the repository instructions and continue from local evidence.
21
+
22
+ Do not create a competing design-canon file.
23
+
24
+ ## Inspect before designing
25
+
26
+ Before editing:
27
+
28
+ 1. Inspect the actual rendered interface, repository implementation, supplied
29
+ export, and component registry.
30
+ 2. Open the component gallery when it exists.
31
+ 3. Identify the target section plus its immediate predecessor and successor.
32
+ 4. Record the target contract:
33
+ - theme;
34
+ - container width;
35
+ - top and bottom spacing;
36
+ - layout variant;
37
+ - reserved visual dimensions;
38
+ - Astro, Sanity, and React ownership boundaries.
39
+
40
+ When a reference points to an existing site component, use its real structure
41
+ and approved tokens. Do not approximate it from memory.
42
+
43
+ ## Source components in this order
44
+
45
+ 1. Reuse an exact registered component.
46
+ 2. Add a typed variant when structure, semantics, and behavior are unchanged.
47
+ 3. Compose registered primitives.
48
+ 4. Create a component only for genuinely new structure or behavior.
49
+ 5. Register every new component with ID, kind, approved variants, status,
50
+ provenance, and at least one catalog scenario.
51
+ 6. Add every meaningful state to the component gallery.
52
+
53
+ Read [contracts.md](references/contracts.md) before changing section composition.
54
+ Read [stack-boundaries.md](references/stack-boundaries.md) when Sanity or React
55
+ is involved.
56
+
57
+ ## Implement within ownership boundaries
58
+
59
+ - Let Astro own page composition, sections, surfaces, containers, spacing, and
60
+ presentational markup.
61
+ - Let React own interactive state only. Pass serializable data and keep the
62
+ island inside an Astro-owned frame.
63
+ - Let Sanity store content and controlled variant values. Do not store arbitrary
64
+ CSS classes or page markup.
65
+ - Use project-supplied semantic tokens. Do not introduce a package palette.
66
+ - Use `VisualFrame` for floating or absolutely positioned visuals and reserve
67
+ their dimensions before they load.
68
+ - Use `SectionGroup` for intentional joined seams or overlaps.
69
+ - Preserve native semantics, keyboard behavior, visible focus, and reduced
70
+ motion.
71
+
72
+ ## Verify the changed neighborhood
73
+
74
+ Run the checklist in [qa-checklist.md](references/qa-checklist.md). At minimum:
75
+
76
+ 1. Inspect the changed section and both adjacent sections at desktop, tablet,
77
+ and narrow mobile widths.
78
+ 2. Check seam, gap, overlap, overflow, theme inheritance, DOM order, anchor
79
+ behavior, and hydration boundaries.
80
+ 3. Confirm the changed section may move its successor in normal flow but does
81
+ not style or reposition it.
82
+ 4. Run existing builds and tests plus the repository's browser checks.
83
+ 5. Run `scripts/audit_layout.mjs <paths...>` as an advisory static scan.
84
+ 6. Report any deviation; do not silently reinterpret it as an exception.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Spark Line Web Framework"
3
+ short_description: "Build and audit Astro, Sanity, and React island interfaces"
4
+ default_prompt: "Use the Spark Line web framework to inspect, reuse, create, and verify this interface without breaking adjacent sections."
@@ -0,0 +1,75 @@
1
+ # Structural contracts
2
+
3
+ ## Component lookup
4
+
5
+ Use this decision sequence:
6
+
7
+ 1. Exact registry match.
8
+ 2. Typed variant of the same semantics and behavior.
9
+ 3. Composition from primitives.
10
+ 4. New registered component.
11
+
12
+ A visual resemblance alone does not justify a new component. A new semantic
13
+ role, DOM structure, interaction model, or content contract does.
14
+
15
+ ## Section boundary
16
+
17
+ `PageFlow` introduces no implicit section gap.
18
+
19
+ Each `Section` owns:
20
+
21
+ - its background and semantic theme;
22
+ - its top and bottom internal spacing;
23
+ - its optional contained or full-width presentation;
24
+ - its anchor identifier.
25
+
26
+ `Container` owns maximum width, centering, and inline gutters. Child layout
27
+ components own internal grid or flex behavior only.
28
+
29
+ Do not put external block margins on a section root. Do not use sibling
30
+ selectors to reach from one section into another. Do not use ordinary negative
31
+ margins to repair page flow.
32
+
33
+ Changing a section may change its height and move subsequent content naturally.
34
+ It must not change the next section's theme, spacing, width, grid, or stacking
35
+ order.
36
+
37
+ ## Joined compositions
38
+
39
+ Use `SectionGroup` when two or more sections deliberately:
40
+
41
+ - share a background;
42
+ - overlap;
43
+ - visually join without an independent seam;
44
+ - participate in one sticky or pinned composition.
45
+
46
+ Review every grouped member together. Do not simulate a group by reaching into
47
+ siblings from page-level CSS.
48
+
49
+ ## Floating visuals
50
+
51
+ Use `VisualFrame` around absolutely positioned, floating, animated, or
52
+ late-loading artwork.
53
+
54
+ Provide one of:
55
+
56
+ - an aspect ratio;
57
+ - a minimum reserved block size;
58
+ - a project component that establishes both dimensions.
59
+
60
+ The frame owns clipping and container-query context. The visual cannot create
61
+ unreserved document height or cover the following section by accident.
62
+
63
+ ## Registry record
64
+
65
+ Register:
66
+
67
+ - stable component ID;
68
+ - `primitive`, `section`, `island`, or `pattern` kind;
69
+ - approved variants;
70
+ - `stable`, `experimental`, or `deprecated` status;
71
+ - provenance;
72
+ - at least one component-gallery scenario.
73
+
74
+ Do not call a component reusable until its relevant responsive, focus, empty,
75
+ loading, error, and reduced-motion states are represented where applicable.