From 37c8d0990ba60af253e18f70b807d75fcf686e40 Mon Sep 17 00:00:00 2001 From: alisaitbilgi Date: Mon, 13 Oct 2025 16:02:05 +0300 Subject: [PATCH 1/3] Extend first class chain methods' api surface by falling back to style updates for non-existing modules --- lib/chain.ts | 42 +++++++++++++++++++++++++++++++++++------- playground/tile.js | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/lib/chain.ts b/lib/chain.ts index 6cd0613..14f4926 100644 --- a/lib/chain.ts +++ b/lib/chain.ts @@ -68,6 +68,8 @@ export function createChain( const variants: VariantCSS = { ...startingValues?.variants }; const children: Record = { ...startingValues?.children }; + let self: Chain; + const chain: Chain = { extend: (newElementTag?: Tag) => { return createChain(stitches, newElementTag || elementTag, { @@ -80,7 +82,7 @@ export function createChain( // @ts-ignore select: (selector: string, subchain: CSS | Chain) => { children[selector] = subchain; - return chain; + return self; }, // In your element method: element: (rawCSS?: CSS) => { @@ -112,23 +114,49 @@ export function createChain( }, ]; } - - return chain; + return self; }, + css: (rawCSS: CSS) => { update(rawCSS); - return chain; + return self; }, }; modules.forEach((m) => m.register(addMethod)); - return chain; + const proxy = new Proxy(chain as Chain, { + get(target, propKey, receiver) { + // Default implemented methods + if (propKey in target) { + return Reflect.get(target, propKey, receiver); + } + + if (typeof propKey !== "string") { + return undefined; + } + + return (...args: any[]) => { + if (!args.length) { + return receiver; + } + + // Fallback to style property update with given key-value pairs. + update({ [propKey]: args[0] }); + + return receiver; + }; + }, + }); + + self = proxy as Chain; + + return proxy as Chain; function addMethod(name: string, fn: ChainMethod) { chain[name] = (...args: unknown[]) => { update(fn.apply(chain, [tree, ...args])); - return chain; + return self; }; } @@ -157,7 +185,7 @@ export function createChain( for (const selector in children) { output[selector] = typeof children[selector].compile === "function" - ? children[selector].compile() + ? (children[selector] as Chain).compile() : children[selector]; } diff --git a/playground/tile.js b/playground/tile.js index 0d5cd56..33db3dc 100644 --- a/playground/tile.js +++ b/playground/tile.js @@ -30,9 +30,9 @@ var Tile = (() => { )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - // node_modules/.deno/react@18.3.1/node_modules/react/cjs/react.development.js + // node_modules/react/cjs/react.development.js var require_react_development = __commonJS({ - "node_modules/.deno/react@18.3.1/node_modules/react/cjs/react.development.js"(exports, module) { + "node_modules/react/cjs/react.development.js"(exports, module) { "use strict"; if (true) { (function() { @@ -1904,9 +1904,9 @@ var Tile = (() => { } }); - // node_modules/.deno/react@18.3.1/node_modules/react/index.js + // node_modules/react/index.js var require_react = __commonJS({ - "node_modules/.deno/react@18.3.1/node_modules/react/index.js"(exports, module) { + "node_modules/react/index.js"(exports, module) { "use strict"; if (false) { module.exports = null; @@ -1931,7 +1931,7 @@ var Tile = (() => { style: () => style }); - // node_modules/.deno/@stitches+react@1.2.8/node_modules/@stitches/react/dist/index.mjs + // node_modules/@stitches/react/dist/index.mjs var import_react = __toESM(require_react(), 1); var e = "colors"; var t = "sizes"; @@ -3802,6 +3802,7 @@ var Tile = (() => { let tree = { ...startingValues?.tree }; const variants = { ...startingValues?.variants }; const children = { ...startingValues?.children }; + let self; const chain = { extend: (newElementTag) => { return createChain(stitches, newElementTag || elementTag, { @@ -3814,7 +3815,7 @@ var Tile = (() => { // @ts-ignore select: (selector, subchain) => { children[selector] = subchain; - return chain; + return self; }, // In your element method: element: (rawCSS) => { @@ -3839,19 +3840,37 @@ var Tile = (() => { } ]; } - return chain; + return self; }, css: (rawCSS) => { update(rawCSS); - return chain; + return self; } }; modules.forEach((m2) => m2.register(addMethod)); - return chain; + const proxy = new Proxy(chain, { + get(target, propKey, receiver) { + if (propKey in target) { + return Reflect.get(target, propKey, receiver); + } + if (typeof propKey !== "string") { + return void 0; + } + return (...args) => { + if (!args.length) { + return receiver; + } + update({ [propKey]: args[0] }); + return receiver; + }; + } + }); + self = proxy; + return proxy; function addMethod(name, fn) { chain[name] = (...args) => { update(fn.apply(chain, [tree, ...args])); - return chain; + return self; }; } function update(updates) { From ec7f993d8057243b26383b741a8fae406e5b65a2 Mon Sep 17 00:00:00 2001 From: alisaitbilgi Date: Mon, 13 Oct 2025 16:05:26 +0300 Subject: [PATCH 2/3] Add documentation for '.css' chain method --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index b85746d..63382ff 100644 --- a/README.md +++ b/README.md @@ -441,3 +441,38 @@ Methods: * [translate(x: string | number, y?: string | number)](./docs/transform.md#translate-x-string-number-y-string-number-) * [skew(x: string | number, y?: string | number)](./docs/transform.md#skew-x-string-number-y-string-number-) * [transform(value: string)](./docs/transform.md#transform-value-string-) + +## [CSS]() + +Method for injecting arbitrary Stitches CSS into the current chain. +Use this when you need a style that isn’t (yet) covered by the first-class chain methods, +or when you want to author nested selectors and media queries inline. + +```typescript + +import { Frame } from "tile-css"; + +const Hello = Frame() + .size(300) + .fg("white") + .mono(21, { color: "#000" }) + .css({ + border: "1px solid #000", + boxShadow: "0 10px 24px rgba(0,0,0,.18)", + textAlign: "center", + }) + .css({ + "@media (max-width: 480px)": { + width: 240, + height: 240, + fontSize: 14, + }, + }) + .element(); + +function App() { + return Hello world :); +} + +export { App } +``` From d61e7cb4d2b05dde1b2c1c1541c824ad36e672e4 Mon Sep 17 00:00:00 2001 From: alisaitbilgi Date: Mon, 13 Oct 2025 16:21:36 +0300 Subject: [PATCH 3/3] Add documentation for new 'fallback to css' api behaviour --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 63382ff..bdc4ddf 100644 --- a/README.md +++ b/README.md @@ -476,3 +476,27 @@ function App() { export { App } ``` + +## [Additional]() + +if you chain a method that isn’t provided by a built-in module, it’s treated as a **CSS property** (camelCased) or a +**Stitches util** key and merged into the style tree. This lets you use one-off properties without writing a new module. + +```typescript + +import { View } from "tile-css"; + +const Avatar = View("img") + .size(200) + .border("1px solid #000") + .round(12) + .objectFit('fill') // This doesn't exist in the first-class chain methods + .objectPosition('20% 20%') // This doesn't exist in the first-class chain methods + .element(); + +function App() { + return +} + +export { App } +```