rafters 0.0.47 → 0.0.49

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 CHANGED
@@ -68,25 +68,47 @@ pnpm dlx rafters studio
68
68
 
69
69
  Four tools give AI agents complete design system access:
70
70
 
71
- ### `rafters_vocabulary`
71
+ ### `rafters_composite`
72
72
 
73
- System overview. Colors, spacing, typography, components, cognitive loads, and available patterns. Call this first to orient.
73
+ Query composites by ID, search term, or category. Returns designer intent (solves, appliesWhen, do/never), I/O rules for chaining, and block structure.
74
+
75
+ ```json
76
+ { "id": "heading" } // Get specific composite
77
+ { "query": "form" } // Fuzzy search
78
+ { "category": "typography" } // Filter by category
79
+ ```
74
80
 
75
81
  ### `rafters_pattern`
76
82
 
77
- Deep guidance for specific UI scenarios. Returns which components to use, which tokens to apply, accessibility requirements, and do/never rules.
83
+ Design pattern guidance by querying composites. Search by what the pattern solves or use fuzzy search.
84
+
85
+ ```json
86
+ { "solves": "hierarchy" } // Find patterns for document hierarchy
87
+ { "solves": "authentication" } // Find patterns for auth flows
88
+ { "query": "form" } // Fuzzy search across composites
89
+ ```
78
90
 
79
- **Available patterns:** `destructive-action`, `form-validation`, `empty-state`, `loading-state`, `navigation-hierarchy`, `data-table`, `modal-dialog`, `tooltip-guidance`, `card-layout`, `dropdown-actions`
91
+ Returns composites with usagePatterns (do/never rules), cognitive load, and designer intent.
80
92
 
81
- ### `rafters_component`
93
+ ### `rafters_rule`
82
94
 
83
- Full intelligence for a specific component. Cognitive load rating, attention economics, accessibility requirements, trust-building patterns, variants, sizes, and primitives.
95
+ Query validation rules or create new ones. Rules are named validation patterns that composites can apply.
84
96
 
85
- ### `rafters_token`
97
+ ```json
98
+ {} // List all rules
99
+ { "name": "email" } // Get specific rule
100
+ { "query": "pass" } // Search rules
101
+ ```
102
+
103
+ **Built-in rules:** `required`, `email`, `password`, `url`, `credentials`
104
+
105
+ ### `rafters_component`
86
106
 
87
- Token dependency graph, derivation rules, and human override context. Returns how a token is computed, what it depends on, and whether a designer manually overrode it (with their reasoning).
107
+ Full intelligence for a specific component. Cognitive load rating, attention economics, accessibility requirements, trust-building patterns, variants, sizes, and primitives.
88
108
 
89
- **Derivation rules:** `calc()`, `state:hover`, `scale:600`, `contrast:auto`, `invert`
109
+ ```json
110
+ { "name": "button" }
111
+ ```
90
112
 
91
113
  ## How It Works
92
114
 
@@ -0,0 +1,8 @@
1
+ import {
2
+ calc_default
3
+ } from "./chunk-2RHKE2AP.js";
4
+ import "./chunk-WG6NCWQ2.js";
5
+ import "./chunk-R5U7XKVJ.js";
6
+ export {
7
+ calc_default as default
8
+ };
@@ -0,0 +1,344 @@
1
+ import {
2
+ definePlugin,
3
+ external_exports
4
+ } from "./chunk-WG6NCWQ2.js";
5
+
6
+ // ../math-utils/src/constants.ts
7
+ var MUSICAL_RATIOS = {
8
+ "minor-second": 1.067,
9
+ // 16:15 ratio - tight, subtle progression
10
+ "major-second": 1.125,
11
+ // 9:8 ratio - gentle, natural progression
12
+ "minor-third": 1.2,
13
+ // 6:5 ratio - moderate, balanced progression
14
+ "major-third": 1.25,
15
+ // 5:4 ratio - strong, noticeable progression
16
+ "perfect-fourth": 1.333,
17
+ // 4:3 ratio - bold, architectural progression
18
+ "augmented-fourth": Math.SQRT2,
19
+ // √2 ratio (tritone) - dramatic, modern
20
+ "perfect-fifth": 1.5
21
+ // 3:2 ratio - classical, powerful progression
22
+ };
23
+ var MATHEMATICAL_CONSTANTS = {
24
+ // Golden Ratio - appears in nature, art, and classical architecture
25
+ golden: 1.618033988749,
26
+ // φ (phi) - most pleasing proportion to human eye
27
+ "golden-ratio": 1.618033988749,
28
+ // Alternative name
29
+ // Square Root Ratios
30
+ sqrt2: Math.SQRT2,
31
+ // √2 ≈ 1.414 - A4 paper ratio, diagonal harmony
32
+ sqrt3: Math.sqrt(3),
33
+ // √3 ≈ 1.732 - equilateral triangle ratio
34
+ sqrt5: Math.sqrt(5),
35
+ // √5 ≈ 2.236 - related to golden ratio
36
+ // Mathematical Constants
37
+ e: Math.E,
38
+ // Euler's number ≈ 2.718 - natural exponential
39
+ pi: Math.PI,
40
+ // π ≈ 3.142 - circular proportions
41
+ // Common Design Ratios
42
+ silver: 1 + Math.SQRT2
43
+ // Silver ratio ≈ 2.414 - alternative to golden
44
+ };
45
+ var ALL_RATIOS = {
46
+ ...MUSICAL_RATIOS,
47
+ ...MATHEMATICAL_CONSTANTS
48
+ };
49
+ var AVAILABLE_RATIOS_STRING = Object.keys(ALL_RATIOS).join(", ");
50
+ function getRatio(name) {
51
+ const ratio = ALL_RATIOS[name];
52
+ if (ratio === void 0) {
53
+ throw new Error(`Unknown ratio: ${name}. Available ratios: ${AVAILABLE_RATIOS_STRING}`);
54
+ }
55
+ return ratio;
56
+ }
57
+
58
+ // ../math-utils/src/calculations.ts
59
+ function tokenize(expr) {
60
+ const tokens = [];
61
+ let current = "";
62
+ for (let i = 0; i < expr.length; i++) {
63
+ const char = expr[i];
64
+ if (!char) continue;
65
+ if (char === " ") {
66
+ continue;
67
+ }
68
+ if ("+-*/()".includes(char)) {
69
+ if (current) {
70
+ const num = parseFloat(current);
71
+ if (!Number.isNaN(num)) {
72
+ tokens.push(num);
73
+ }
74
+ current = "";
75
+ }
76
+ tokens.push(char);
77
+ } else if (char) {
78
+ current += char;
79
+ }
80
+ }
81
+ if (current) {
82
+ const num = parseFloat(current);
83
+ if (!Number.isNaN(num)) {
84
+ tokens.push(num);
85
+ }
86
+ }
87
+ return tokens;
88
+ }
89
+ var ExpressionParser = class {
90
+ tokens;
91
+ position;
92
+ constructor(tokens) {
93
+ this.tokens = tokens;
94
+ this.position = 0;
95
+ }
96
+ current() {
97
+ return this.tokens[this.position];
98
+ }
99
+ consume() {
100
+ return this.tokens[this.position++];
101
+ }
102
+ parse() {
103
+ const result = this.expression();
104
+ if (this.position < this.tokens.length) {
105
+ throw new Error("Unexpected token after expression");
106
+ }
107
+ return result;
108
+ }
109
+ expression() {
110
+ let left = this.term();
111
+ while (this.current() === "+" || this.current() === "-") {
112
+ const op = this.consume();
113
+ const right = this.term();
114
+ if (op === "+") {
115
+ left = left + right;
116
+ } else {
117
+ left = left - right;
118
+ }
119
+ }
120
+ return left;
121
+ }
122
+ term() {
123
+ let left = this.factor();
124
+ while (this.current() === "*" || this.current() === "/") {
125
+ const op = this.consume();
126
+ const right = this.factor();
127
+ if (op === "*") {
128
+ left = left * right;
129
+ } else {
130
+ if (right === 0) {
131
+ throw new Error("Division by zero");
132
+ }
133
+ left = left / right;
134
+ }
135
+ }
136
+ return left;
137
+ }
138
+ factor() {
139
+ const token = this.current();
140
+ if (typeof token === "number") {
141
+ this.consume();
142
+ return token;
143
+ }
144
+ if (token === "(") {
145
+ this.consume();
146
+ const result = this.expression();
147
+ if (this.current() !== ")") {
148
+ throw new Error("Missing closing parenthesis");
149
+ }
150
+ this.consume();
151
+ return result;
152
+ }
153
+ if (token === "-") {
154
+ this.consume();
155
+ return -this.factor();
156
+ }
157
+ throw new Error(`Unexpected token: ${token}`);
158
+ }
159
+ };
160
+ function evaluateExpression(expression, variables = {}) {
161
+ let processedExpression = expression.trim();
162
+ for (const [varName, varValue] of Object.entries(variables)) {
163
+ const bracedVarRegex = new RegExp(`\\{${varName.replace("-", "\\-")}\\}`, "g");
164
+ processedExpression = processedExpression.replace(bracedVarRegex, String(varValue));
165
+ }
166
+ for (const [ratioName, ratioValue] of Object.entries(ALL_RATIOS)) {
167
+ const ratioRegex = new RegExp(`\\b${ratioName.replace("-", "\\-")}\\b`, "g");
168
+ processedExpression = processedExpression.replace(ratioRegex, String(ratioValue));
169
+ }
170
+ for (const [varName, varValue] of Object.entries(variables)) {
171
+ const varRegex = new RegExp(`\\b${varName.replace("-", "\\-")}\\b`, "g");
172
+ processedExpression = processedExpression.replace(varRegex, String(varValue));
173
+ }
174
+ try {
175
+ const tokens = tokenize(processedExpression);
176
+ const parser = new ExpressionParser(tokens);
177
+ const result = parser.parse();
178
+ if (typeof result !== "number" || !Number.isFinite(result)) {
179
+ throw new Error(`Invalid calculation result: ${result}`);
180
+ }
181
+ return result;
182
+ } catch (error) {
183
+ throw new Error(`Cannot evaluate expression: ${expression} - ${error}`);
184
+ }
185
+ }
186
+
187
+ // ../math-utils/src/progressions.ts
188
+ function createProgression(type) {
189
+ if (type === "linear") {
190
+ return {
191
+ type,
192
+ ratio: 1,
193
+ compute(base, step) {
194
+ return base * (step + 1);
195
+ },
196
+ generateSequence(base, steps, options = {}) {
197
+ const { includeZero = false, startStep = 0 } = options;
198
+ const result = [];
199
+ for (let i = 0; i < steps; i++) {
200
+ const step = startStep + i;
201
+ if (i === 0 && includeZero) {
202
+ result.push(0);
203
+ } else {
204
+ result.push(base * (step + 1));
205
+ }
206
+ }
207
+ return result;
208
+ }
209
+ };
210
+ }
211
+ if (type === "exponential") {
212
+ const defaultMultiplier = 1.25;
213
+ return {
214
+ type,
215
+ ratio: defaultMultiplier,
216
+ compute(base, step) {
217
+ return base * defaultMultiplier ** step;
218
+ },
219
+ generateSequence(base, steps, options = {}) {
220
+ const { includeZero = false, startStep = 0 } = options;
221
+ const result = [];
222
+ for (let i = 0; i < steps; i++) {
223
+ const step = startStep + i;
224
+ if (i === 0 && includeZero) {
225
+ result.push(0);
226
+ } else {
227
+ result.push(base * defaultMultiplier ** step);
228
+ }
229
+ }
230
+ return result;
231
+ }
232
+ };
233
+ }
234
+ const ratio = getRatio(type);
235
+ return {
236
+ type,
237
+ ratio,
238
+ compute(base, step) {
239
+ return base * ratio ** step;
240
+ },
241
+ generateSequence(base, steps, options = {}) {
242
+ const { includeZero = false, startStep = 0 } = options;
243
+ const result = [];
244
+ for (let i = 0; i < steps; i++) {
245
+ const step = startStep + i;
246
+ if (i === 0 && includeZero) {
247
+ result.push(0);
248
+ } else {
249
+ result.push(base * ratio ** step);
250
+ }
251
+ }
252
+ return result;
253
+ }
254
+ };
255
+ }
256
+ function generateProgression(type, options) {
257
+ const { baseValue, steps, multiplier = 1.25, includeZero = false } = options;
258
+ const result = [];
259
+ let cachedRatio;
260
+ for (let i = 0; i < steps; i++) {
261
+ let value;
262
+ switch (type) {
263
+ case "linear":
264
+ value = i === 0 && includeZero ? 0 : baseValue * (includeZero ? i : i + 1);
265
+ break;
266
+ case "exponential":
267
+ value = i === 0 && includeZero ? 0 : baseValue * multiplier ** (includeZero ? i - 1 : i);
268
+ break;
269
+ default:
270
+ try {
271
+ if (!cachedRatio) {
272
+ cachedRatio = getRatio(type);
273
+ }
274
+ value = i === 0 && includeZero ? 0 : baseValue * cachedRatio ** (includeZero ? i - 1 : i);
275
+ } catch (error) {
276
+ throw new Error(`Invalid progression type: ${type}`, { cause: error });
277
+ }
278
+ }
279
+ result.push(value);
280
+ }
281
+ return result;
282
+ }
283
+ function generateModularScale(ratio, baseSize, steps = 5) {
284
+ const ratioValue = typeof ratio === "number" ? ratio : getRatio(ratio);
285
+ const smaller = [];
286
+ const larger = [];
287
+ for (let i = 1; i <= steps; i++) {
288
+ smaller.unshift(baseSize / ratioValue ** i);
289
+ }
290
+ for (let i = 1; i <= steps; i++) {
291
+ larger.push(baseSize * ratioValue ** i);
292
+ }
293
+ return {
294
+ smaller,
295
+ base: baseSize,
296
+ larger
297
+ };
298
+ }
299
+
300
+ // ../design-tokens/src/plugins/calc.ts
301
+ var CalcInputSchema = external_exports.object({
302
+ expression: external_exports.string(),
303
+ tokenValues: external_exports.record(external_exports.string(), external_exports.string())
304
+ });
305
+ var calc_default = definePlugin({
306
+ id: "calc",
307
+ input: CalcInputSchema,
308
+ output: external_exports.string(),
309
+ transform(input) {
310
+ let expression = input.expression;
311
+ let detectedUnit = "";
312
+ const numericValues = {};
313
+ for (const [tokenName, tokenValue] of Object.entries(input.tokenValues)) {
314
+ const numericValue = parseFloat(tokenValue);
315
+ if (Number.isNaN(numericValue)) {
316
+ throw new Error(`Token ${tokenName} value "${tokenValue}" is not numeric`);
317
+ }
318
+ if (!detectedUnit) {
319
+ const unitMatch = tokenValue.match(/([a-z%]+)$/i);
320
+ if (unitMatch?.[1]) {
321
+ detectedUnit = unitMatch[1];
322
+ }
323
+ }
324
+ numericValues[tokenName] = numericValue;
325
+ expression = expression.replace(new RegExp(`\\{${tokenName}\\}`, "g"), String(numericValue));
326
+ }
327
+ if (!detectedUnit) {
328
+ const literalUnitMatch = expression.match(/\d+([a-z%]+)/i);
329
+ if (literalUnitMatch?.[1]) {
330
+ detectedUnit = literalUnitMatch[1];
331
+ }
332
+ }
333
+ const result = evaluateExpression(expression);
334
+ return detectedUnit ? `${result}${detectedUnit}` : String(result);
335
+ }
336
+ });
337
+
338
+ export {
339
+ getRatio,
340
+ createProgression,
341
+ generateProgression,
342
+ generateModularScale,
343
+ calc_default
344
+ };
@@ -0,0 +1,21 @@
1
+ import {
2
+ definePlugin,
3
+ external_exports
4
+ } from "./chunk-WG6NCWQ2.js";
5
+
6
+ // ../design-tokens/src/plugins/example.ts
7
+ var ExampleInputSchema = external_exports.object({
8
+ tokenName: external_exports.string()
9
+ });
10
+ var example_default = definePlugin({
11
+ id: "example",
12
+ input: ExampleInputSchema,
13
+ output: external_exports.string(),
14
+ transform(input) {
15
+ return `example-result-for-${input.tokenName}`;
16
+ }
17
+ });
18
+
19
+ export {
20
+ example_default
21
+ };
@@ -0,0 +1,33 @@
1
+ import {
2
+ ColorReferenceSchema,
3
+ ColorValueSchema,
4
+ INDEX_TO_POSITION,
5
+ definePlugin,
6
+ external_exports
7
+ } from "./chunk-WG6NCWQ2.js";
8
+
9
+ // ../design-tokens/src/plugins/scale.ts
10
+ var ScalePositionInputSchema = external_exports.object({
11
+ familyColorValue: ColorValueSchema,
12
+ familyName: external_exports.string(),
13
+ scalePosition: external_exports.number().int().min(0).max(10)
14
+ });
15
+ var scale_default = definePlugin({
16
+ id: "scale-position",
17
+ input: ScalePositionInputSchema,
18
+ output: ColorReferenceSchema,
19
+ transform(input) {
20
+ const position = INDEX_TO_POSITION[input.scalePosition];
21
+ if (position === void 0) {
22
+ throw new Error(`Invalid scale position index: ${input.scalePosition}`);
23
+ }
24
+ return {
25
+ family: input.familyName,
26
+ position
27
+ };
28
+ }
29
+ });
30
+
31
+ export {
32
+ scale_default
33
+ };
@@ -0,0 +1,44 @@
1
+ import {
2
+ ColorReferenceSchema,
3
+ ColorValueSchema,
4
+ INDEX_TO_POSITION,
5
+ definePlugin,
6
+ external_exports
7
+ } from "./chunk-WG6NCWQ2.js";
8
+
9
+ // ../design-tokens/src/plugins/state.ts
10
+ var StateInputSchema = external_exports.object({
11
+ familyColorValue: ColorValueSchema,
12
+ familyName: external_exports.string(),
13
+ basePosition: external_exports.number().int().min(0).max(10),
14
+ stateType: external_exports.enum(["hover", "active", "focus", "disabled"])
15
+ });
16
+ var STATE_OFFSETS = {
17
+ hover: 1,
18
+ active: 2,
19
+ focus: 1,
20
+ disabled: -2
21
+ };
22
+ var state_default = definePlugin({
23
+ id: "state",
24
+ input: StateInputSchema,
25
+ output: ColorReferenceSchema,
26
+ transform(input) {
27
+ const colorValue = input.familyColorValue;
28
+ const precomputed = colorValue.stateReferences?.[input.stateType];
29
+ if (precomputed) {
30
+ return {
31
+ family: precomputed.family,
32
+ position: String(precomputed.position)
33
+ };
34
+ }
35
+ const offset = STATE_OFFSETS[input.stateType];
36
+ const adjustedIndex = Math.max(0, Math.min(10, input.basePosition + offset));
37
+ const position = INDEX_TO_POSITION[adjustedIndex] ?? "500";
38
+ return { family: input.familyName, position };
39
+ }
40
+ });
41
+
42
+ export {
43
+ state_default
44
+ };
@@ -0,0 +1,80 @@
1
+ import {
2
+ ColorReferenceSchema,
3
+ ColorValueSchema,
4
+ INDEX_TO_POSITION,
5
+ definePlugin,
6
+ external_exports
7
+ } from "./chunk-WG6NCWQ2.js";
8
+
9
+ // ../design-tokens/src/plugins/contrast.ts
10
+ var ContrastInputSchema = external_exports.object({
11
+ familyColorValue: ColorValueSchema,
12
+ familyName: external_exports.string(),
13
+ basePosition: external_exports.number().int().min(0).max(10),
14
+ neutralFamilyName: external_exports.string().optional(),
15
+ neutralColorValue: ColorValueSchema.optional()
16
+ });
17
+ function findPartnerInPairs(pairs, basePosition) {
18
+ for (const [p1, p2] of pairs) {
19
+ if (p1 === basePosition) return p2;
20
+ if (p2 === basePosition) return p1;
21
+ }
22
+ return void 0;
23
+ }
24
+ var contrast_default = definePlugin({
25
+ id: "contrast",
26
+ input: ContrastInputSchema,
27
+ output: ColorReferenceSchema,
28
+ transform(input) {
29
+ const colorValue = input.familyColorValue;
30
+ if (colorValue.foregroundReferences?.auto) {
31
+ const ref = colorValue.foregroundReferences.auto;
32
+ return { family: ref.family, position: ref.position };
33
+ }
34
+ const basePosition = input.basePosition;
35
+ if (colorValue.accessibility) {
36
+ const wcagAAA = colorValue.accessibility.wcagAAA?.normal ?? [];
37
+ const wcagAA = colorValue.accessibility.wcagAA?.normal ?? [];
38
+ const contrastPosition = findPartnerInPairs(wcagAAA, basePosition) ?? findPartnerInPairs(wcagAA, basePosition);
39
+ if (contrastPosition !== void 0) {
40
+ return {
41
+ family: input.familyName,
42
+ position: INDEX_TO_POSITION[contrastPosition] ?? "500"
43
+ };
44
+ }
45
+ }
46
+ if (input.neutralFamilyName && input.neutralColorValue) {
47
+ const neutralValue = input.neutralColorValue;
48
+ if (neutralValue.accessibility?.onWhite?.aaa && neutralValue.accessibility.onWhite.aaa.length > 0) {
49
+ const bestPosition = neutralValue.accessibility.onWhite.aaa[0];
50
+ if (bestPosition !== void 0) {
51
+ return {
52
+ family: input.neutralFamilyName,
53
+ position: INDEX_TO_POSITION[bestPosition] ?? "500"
54
+ };
55
+ }
56
+ }
57
+ if (neutralValue.accessibility?.onWhite?.aa && neutralValue.accessibility.onWhite.aa.length > 0) {
58
+ const bestPosition = neutralValue.accessibility.onWhite.aa[0];
59
+ if (bestPosition !== void 0) {
60
+ return {
61
+ family: input.neutralFamilyName,
62
+ position: INDEX_TO_POSITION[bestPosition] ?? "500"
63
+ };
64
+ }
65
+ }
66
+ return {
67
+ family: input.neutralFamilyName,
68
+ position: basePosition <= 5 ? "900" : "100"
69
+ };
70
+ }
71
+ return {
72
+ family: input.familyName,
73
+ position: basePosition <= 5 ? "900" : "100"
74
+ };
75
+ }
76
+ });
77
+
78
+ export {
79
+ contrast_default
80
+ };
@@ -0,0 +1,32 @@
1
+ import {
2
+ ColorReferenceSchema,
3
+ ColorValueSchema,
4
+ INDEX_TO_POSITION,
5
+ definePlugin,
6
+ external_exports,
7
+ findDarkCounterpartIndex
8
+ } from "./chunk-WG6NCWQ2.js";
9
+
10
+ // ../design-tokens/src/plugins/invert.ts
11
+ var InvertInputSchema = external_exports.object({
12
+ familyColorValue: ColorValueSchema,
13
+ familyName: external_exports.string(),
14
+ basePosition: external_exports.number().int().min(0).max(10)
15
+ });
16
+ var invert_default = definePlugin({
17
+ id: "invert",
18
+ input: InvertInputSchema,
19
+ output: ColorReferenceSchema,
20
+ transform(input) {
21
+ const darkIndex = findDarkCounterpartIndex(input.basePosition, input.familyColorValue);
22
+ const darkPosition = INDEX_TO_POSITION[darkIndex];
23
+ if (!darkPosition) {
24
+ throw new Error(`Invalid dark index ${darkIndex} for base position: ${input.basePosition}`);
25
+ }
26
+ return { family: input.familyName, position: darkPosition };
27
+ }
28
+ });
29
+
30
+ export {
31
+ invert_default
32
+ };