Z User commited on
Commit ·
10c5bcc
1
Parent(s): 54a7dba
sync work in progress
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitignore +0 -0
- bun.lock +0 -0
- components.json +0 -0
- eslint.config.mjs +0 -0
- examples/websocket/frontend.tsx +0 -0
- examples/websocket/server.ts +0 -0
- next.config.ts +0 -0
- package.json +0 -0
- postcss.config.mjs +0 -0
- prisma/schema.prisma +0 -0
- public/dssl/boot.js +0 -0
- public/dssl/engine.js +0 -0
- public/dssl/index.js +0 -0
- public/dssl/parser.js +0 -0
- public/dssl/resolver.js +0 -0
- public/dssl/utils.js +0 -0
- public/favicon.svg +0 -0
- public/logo.svg +0 -0
- public/robots.txt +0 -0
- public/styles/changelog.dssl +0 -0
- public/styles/docs.dssl +0 -0
- public/styles/home.dssl +0 -0
- public/styles/playground.dssl +0 -0
- public/styles/site.dssl +0 -0
- public/styles/tokens.dssl +0 -0
- scripts/dssl-debug-grid.mjs +0 -0
- scripts/dssl-smoke.mjs +0 -0
- scripts/dssl-styles-check.mjs +0 -0
- src/app/api/route.ts +0 -0
- src/app/globals.css +0 -0
- src/app/layout.tsx +30 -11
- src/app/page.tsx +0 -0
- src/components/dssl/CodeBlock.tsx +0 -0
- src/components/dssl/SiteRoot.tsx +0 -0
- src/components/dssl/highlight.ts +0 -0
- src/components/dssl/icons.tsx +0 -0
- src/components/dssl/views/ChangelogView.tsx +0 -0
- src/components/dssl/views/CheatSheetView.tsx +0 -0
- src/components/dssl/views/DocsView.tsx +58 -0
- src/components/dssl/views/HomeView.tsx +0 -0
- src/components/dssl/views/PlaygroundView.tsx +0 -0
- src/components/dssl/views/SpecView.tsx +0 -0
- src/components/ui/accordion.tsx +0 -0
- src/components/ui/alert-dialog.tsx +0 -0
- src/components/ui/alert.tsx +0 -0
- src/components/ui/aspect-ratio.tsx +0 -0
- src/components/ui/avatar.tsx +0 -0
- src/components/ui/badge.tsx +0 -0
- src/components/ui/breadcrumb.tsx +0 -0
- src/components/ui/button.tsx +0 -0
.gitignore
CHANGED
|
File without changes
|
bun.lock
CHANGED
|
File without changes
|
components.json
CHANGED
|
File without changes
|
eslint.config.mjs
CHANGED
|
File without changes
|
examples/websocket/frontend.tsx
CHANGED
|
File without changes
|
examples/websocket/server.ts
CHANGED
|
File without changes
|
next.config.ts
CHANGED
|
File without changes
|
package.json
CHANGED
|
File without changes
|
postcss.config.mjs
CHANGED
|
File without changes
|
prisma/schema.prisma
CHANGED
|
File without changes
|
public/dssl/boot.js
CHANGED
|
File without changes
|
public/dssl/engine.js
CHANGED
|
File without changes
|
public/dssl/index.js
CHANGED
|
File without changes
|
public/dssl/parser.js
CHANGED
|
File without changes
|
public/dssl/resolver.js
CHANGED
|
File without changes
|
public/dssl/utils.js
CHANGED
|
File without changes
|
public/favicon.svg
CHANGED
|
|
|
|
public/logo.svg
CHANGED
|
|
|
|
public/robots.txt
CHANGED
|
File without changes
|
public/styles/changelog.dssl
CHANGED
|
File without changes
|
public/styles/docs.dssl
CHANGED
|
File without changes
|
public/styles/home.dssl
CHANGED
|
File without changes
|
public/styles/playground.dssl
CHANGED
|
File without changes
|
public/styles/site.dssl
CHANGED
|
File without changes
|
public/styles/tokens.dssl
CHANGED
|
File without changes
|
scripts/dssl-debug-grid.mjs
CHANGED
|
File without changes
|
scripts/dssl-smoke.mjs
CHANGED
|
File without changes
|
scripts/dssl-styles-check.mjs
CHANGED
|
File without changes
|
src/app/api/route.ts
CHANGED
|
File without changes
|
src/app/globals.css
CHANGED
|
File without changes
|
src/app/layout.tsx
CHANGED
|
@@ -46,27 +46,46 @@ function dsslInlineStyles(): { name: string; src: string }[] {
|
|
| 46 |
|
| 47 |
// Dev-only interop shim: the engine styles the SSR DOM BEFORE React hydrates
|
| 48 |
// (that is the whole point — no FOUC). React 19 then logs one console.error
|
| 49 |
-
// about extra style attributes and, helpfully, does not patch them.
|
| 50 |
-
//
|
| 51 |
-
//
|
| 52 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
const hydrationShim = `
|
| 54 |
(function () {
|
| 55 |
-
var HYD = 'A tree hydrated but some attributes
|
| 56 |
-
var
|
| 57 |
-
console.error
|
|
|
|
|
|
|
| 58 |
var s = '';
|
| 59 |
for (var i = 0; i < arguments.length; i++) {
|
| 60 |
var a = arguments[i];
|
| 61 |
-
s += (typeof a === 'string' ? a :
|
| 62 |
}
|
| 63 |
-
if (s.indexOf(HYD) ==
|
| 64 |
console.info('%cDSSL%c styled this page before React hydrated. The "hydrated but some attributes didn\\u2019t match" notice is expected interop: the engine owns those style attributes, and React explicitly leaves them alone.',
|
| 65 |
'background:#b3372e;color:#fff;padding:1px 6px;border-radius:3px;font-weight:700', '');
|
| 66 |
return;
|
| 67 |
}
|
| 68 |
-
return
|
| 69 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
})();
|
| 71 |
`;
|
| 72 |
|
|
|
|
| 46 |
|
| 47 |
// Dev-only interop shim: the engine styles the SSR DOM BEFORE React hydrates
|
| 48 |
// (that is the whole point — no FOUC). React 19 then logs one console.error
|
| 49 |
+
// about extra style attributes and, helpfully, does not patch them. Next's
|
| 50 |
+
// dev overlay ALSO patches console.error (one layer around everything) and
|
| 51 |
+
// counts every error it sees into the "Issues" badge — so a plain filter
|
| 52 |
+
// installed here would sit INSIDE Next's collector and the badge would still
|
| 53 |
+
// show "1". This shim instead installs an assignment trap: the moment Next
|
| 54 |
+
// assigns its own wrapper, we capture it and re-publish OUR filter as the
|
| 55 |
+
// outermost layer. DSSL's own hydration diff is swallowed + explained; every
|
| 56 |
+
// other console.error still reaches Next's collector untouched.
|
| 57 |
const hydrationShim = `
|
| 58 |
(function () {
|
| 59 |
+
var HYD = 'A tree hydrated but some attributes';
|
| 60 |
+
var MARK = '--dssl';
|
| 61 |
+
var inner = console.error; // native, until Next assigns its wrapper
|
| 62 |
+
var trapped = false;
|
| 63 |
+
function outer() {
|
| 64 |
var s = '';
|
| 65 |
for (var i = 0; i < arguments.length; i++) {
|
| 66 |
var a = arguments[i];
|
| 67 |
+
s += (i ? ' ' : '') + (typeof a === 'string' ? a : (a && a.message ? a.message : ''));
|
| 68 |
}
|
| 69 |
+
if (s.indexOf(HYD) !== -1 && s.indexOf(MARK) !== -1) {
|
| 70 |
console.info('%cDSSL%c styled this page before React hydrated. The "hydrated but some attributes didn\\u2019t match" notice is expected interop: the engine owns those style attributes, and React explicitly leaves them alone.',
|
| 71 |
'background:#b3372e;color:#fff;padding:1px 6px;border-radius:3px;font-weight:700', '');
|
| 72 |
return;
|
| 73 |
}
|
| 74 |
+
return inner.apply(console, arguments);
|
| 75 |
+
}
|
| 76 |
+
try {
|
| 77 |
+
var desc = Object.getOwnPropertyDescriptor(console, 'error');
|
| 78 |
+
if (!desc || !desc.configurable) throw new Error('not configurable');
|
| 79 |
+
Object.defineProperty(console, 'error', {
|
| 80 |
+
configurable: true,
|
| 81 |
+
get: function () { return trapped ? outer : inner; },
|
| 82 |
+
set: function (fn) { inner = fn; trapped = true; }
|
| 83 |
+
});
|
| 84 |
+
} catch (e) {
|
| 85 |
+
// fallback: plain filter — console noise is still explained away,
|
| 86 |
+
// though the dev-overlay badge may still count the notice.
|
| 87 |
+
console.error = outer;
|
| 88 |
+
}
|
| 89 |
})();
|
| 90 |
`;
|
| 91 |
|
src/app/page.tsx
CHANGED
|
File without changes
|
src/components/dssl/CodeBlock.tsx
CHANGED
|
File without changes
|
src/components/dssl/SiteRoot.tsx
CHANGED
|
File without changes
|
src/components/dssl/highlight.ts
CHANGED
|
File without changes
|
src/components/dssl/icons.tsx
CHANGED
|
File without changes
|
src/components/dssl/views/ChangelogView.tsx
CHANGED
|
File without changes
|
src/components/dssl/views/CheatSheetView.tsx
CHANGED
|
File without changes
|
src/components/dssl/views/DocsView.tsx
CHANGED
|
@@ -17,6 +17,7 @@ const SIDE = [
|
|
| 17 |
{ head: null, id: "motion", label: "Motion" },
|
| 18 |
{ head: null, id: "errors", label: "Errors" },
|
| 19 |
{ head: null, id: "api", label: "JS API" },
|
|
|
|
| 20 |
];
|
| 21 |
|
| 22 |
export default function DocsView() {
|
|
@@ -443,6 +444,63 @@ button { use focus-ring }
|
|
| 443 |
<code><html data-dssl-reset></code> enables the small built-in reset.
|
| 444 |
</p>
|
| 445 |
</section>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
</div>
|
| 447 |
</div>
|
| 448 |
</div>
|
|
|
|
| 17 |
{ head: null, id: "motion", label: "Motion" },
|
| 18 |
{ head: null, id: "errors", label: "Errors" },
|
| 19 |
{ head: null, id: "api", label: "JS API" },
|
| 20 |
+
{ head: null, id: "interop", label: "Interop (React & co.)" },
|
| 21 |
];
|
| 22 |
|
| 23 |
export default function DocsView() {
|
|
|
|
| 444 |
<code><html data-dssl-reset></code> enables the small built-in reset.
|
| 445 |
</p>
|
| 446 |
</section>
|
| 447 |
+
|
| 448 |
+
<section className="doc-block" id="interop">
|
| 449 |
+
<h2 className="section-title">Interop — React, hydration & friends</h2>
|
| 450 |
+
<p className="doc-lead">
|
| 451 |
+
DSSL is deliberately framework-agnostic: it styles whatever DOM exists,
|
| 452 |
+
so it works under React, Vue, Svelte or plain HTML. But if you render
|
| 453 |
+
with React there is <b>one known, harmless notice</b> you should
|
| 454 |
+
understand — and this very site is the living example.
|
| 455 |
+
</p>
|
| 456 |
+
<div className="note">
|
| 457 |
+
<b>Why the notice happens.</b> The engine applies styles to the SSR DOM
|
| 458 |
+
<i> before</i> React hydrates — that is the whole anti-flash design. React
|
| 459 |
+
then compares the DOM against its virtual render, finds extra
|
| 460 |
+
<code> style="--dssl-*…"</code> attributes it did not put there, and logs
|
| 461 |
+
one hydration diff to the console. React explicitly <b>does not patch
|
| 462 |
+
them away</b> — it leaves the engine's styles alone. Nothing is wrong:
|
| 463 |
+
the styles are working exactly as intended.
|
| 464 |
+
</div>
|
| 465 |
+
<p className="doc-lead">
|
| 466 |
+
In dev builds that single notice can surface as a "1 Issue" overlay badge,
|
| 467 |
+
because Next's dev tools wrap <code>console.error</code> and count
|
| 468 |
+
everything they see. This site installs an <i>assignment trap</i>: the moment
|
| 469 |
+
Next assigns its own collector, the shim captures it and re-publishes the
|
| 470 |
+
filter as the <b>outermost</b> layer — so DSSL's own diff is swallowed
|
| 471 |
+
and re-logged as an explained info line <b>before</b> Next can count it.
|
| 472 |
+
Any genuine hydration mismatch still flows through to the collector at full
|
| 473 |
+
volume. In production React does not diff attributes at all, so the notice
|
| 474 |
+
disappears entirely; the shim is dev-only.
|
| 475 |
+
</p>
|
| 476 |
+
<CodeBlock file="dev-only console shim (this site's layout.tsx)" code={`// assignment trap: become the OUTERMOST console.error
|
| 477 |
+
// the moment Next assigns its own collector
|
| 478 |
+
let inner = console.error, trapped = false;
|
| 479 |
+
Object.defineProperty(console, 'error', {
|
| 480 |
+
configurable: true,
|
| 481 |
+
get: () => (trapped ? outer : inner),
|
| 482 |
+
set: (fn) => { inner = fn; trapped = true; }
|
| 483 |
+
});
|
| 484 |
+
function outer(...args) {
|
| 485 |
+
const s = args.map(String).join(' ');
|
| 486 |
+
// swallow ONLY the DSSL-attribute hydration diff
|
| 487 |
+
if (s.includes('A tree hydrated but some attributes')
|
| 488 |
+
&& s.includes('--dssl')) {
|
| 489 |
+
console.info('DSSL styled this page before React hydrated. Expected interop.');
|
| 490 |
+
return;
|
| 491 |
+
}
|
| 492 |
+
return inner.apply(console, args); // genuine issues flow through
|
| 493 |
+
}`} />
|
| 494 |
+
<p className="doc-lead">
|
| 495 |
+
Two more interop notes worth knowing. First, if a framework re-renders a
|
| 496 |
+
subtree and <i>removes</i> elements the engine had styled, the touched
|
| 497 |
+
registry notices the removal via MutationObserver and cleans up — no
|
| 498 |
+
leaked inline styles. Second, if your framework toggles attributes the
|
| 499 |
+
engine matches on (like <code>data-dssl-*</code> signal mirrors), change
|
| 500 |
+
them through <code>DSSL.signal()</code> rather than DOM writes, so rules
|
| 501 |
+
re-evaluate on the same tick instead of waiting for the observer.
|
| 502 |
+
</p>
|
| 503 |
+
</section>
|
| 504 |
</div>
|
| 505 |
</div>
|
| 506 |
</div>
|
src/components/dssl/views/HomeView.tsx
CHANGED
|
File without changes
|
src/components/dssl/views/PlaygroundView.tsx
CHANGED
|
File without changes
|
src/components/dssl/views/SpecView.tsx
CHANGED
|
File without changes
|
src/components/ui/accordion.tsx
CHANGED
|
File without changes
|
src/components/ui/alert-dialog.tsx
CHANGED
|
File without changes
|
src/components/ui/alert.tsx
CHANGED
|
File without changes
|
src/components/ui/aspect-ratio.tsx
CHANGED
|
File without changes
|
src/components/ui/avatar.tsx
CHANGED
|
File without changes
|
src/components/ui/badge.tsx
CHANGED
|
File without changes
|
src/components/ui/breadcrumb.tsx
CHANGED
|
File without changes
|
src/components/ui/button.tsx
CHANGED
|
File without changes
|