File size: 13,531 Bytes
e92b981 2d39154 e92b981 2d39154 e92b981 2d39154 e6c76da 2d39154 6859477 10656db 6859477 e6c76da 2d39154 0c4637f 10656db e92b981 10656db e92b981 2d39154 6859477 2d39154 6859477 2d39154 d9e058a 2d39154 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* props-docs.js - the DSSL vocabulary with one-line docs.
* Feeds completions and hovers. Semantic vocabulary entries carry real
* explanations; passthrough CSS properties get a short reminder that they
* pass through untouched. */
export const SEMANTIC = {
row: 'flex row in one line: `row: gap space.4 between center` sets display:flex, flex-direction, gap, justify-content, align-items. Warning: it writes display - put explicit display: before it, not after.',
column: 'flex column in one line: `column: gap 2`. Same display caveat as row: the shorthand wins if it comes later in the rule.',
grid: 'grid layout in one line: `grid: 3 gap 12` = 3 equal columns with a 12px gap.',
stack: 'everything stacked and centered: `stack: center`. Flex column + center on both axes.',
center: 'alignment that cannot silently no-op - the engine promotes the element to a grid formatting context when needed: `center: both`.',
size: 'width and height in one line: `size: 40 20` = 40 wide, 20 tall. `size: 40` = both.',
shadow: 'box shadow from the shadow token scale: `shadow: sm | md | lg | xl`. Custom: `shadow: 0 2 4 ink/10, 0 4 12 ink/8`.',
radius: 'border-radius, bare number or token: `radius: md`, `radius: full`, `radius: 14`.',
gradient: 'gradient as a sentence: `gradient: linear 135, color.accent -> color.ok`. Also `repeating linear 45, #fff 0 10, #000 10 20` (stripes), `linear 90 in oklch, a -> b` (blend colour space), `a -> 30% -> b` (midpoint), `a 0 30%, b 30% 100%` (hard bands), `mesh #fff4e6, #ff7a1a at 15% 20%, #3949ab at 80% 70%` (soft blobs on a base), and layers joined with ` + ` (first on top; each can end with `tile 24`, `offset 4 4`, `no-repeat`, and can be a CSS `radial-gradient(...)`). A stop that is not a color is a compile error.',
'gradient-text': 'clips the gradient grammar into the glyphs: `gradient-text: linear to right, color.accent, color.ink`.',
'gradient-flow': 'the gradient drifts forever through WAAPI: `gradient-flow: 6s alternate`. Holds still under reduced-motion.',
bend: 'bows the element in 3D. Positive tips the top away, negative leans toward you. Bare numbers are degrees. Composes into the one transform channel.',
'bend-y': 'sideways bow. `bend-y: -18`.',
'bend-up': 'rocks back on its planted bottom edge, drawbridge-style. `bend-up: 14`.',
fold: 'swings up over its top edge like a closing page. `fold: 14`.',
stretch: 'cartoon squash-and-stretch that keeps volume: `stretch: 0.94` squeezes to 0.94 wide and honestly grows to 1/0.94 tall.',
'bend-around': 'curves a container\u2019s CHILDREN along a circular arc instead of deforming one element: `bend-around: -22` opens into a smile. Caps at \u00b1170\u00b0. Children keep their own hover bends.',
animate: 'run a motion (or several: `animate: blink 300 infinite, waddle 900 infinite alternate`): `animate: name duration [easing] [delay N] [jitter N] [iterations N] [infinite] [alternate] [essential]`. Example: `animate: pulse 1600 infinite alternate`. `jitter` gives each element its own random delay, `essential` runs it even when the visitor prefers reduced motion. Works on ::before and ::after too. Run one from JS with `DSSL.play(el, name, opts)`.',
yield: 'hand properties back to plain CSS: `yield: padding-top padding-bottom`. The engine writes inline styles, which beat a stylesheet; a yielded property is not written, so your CSS decides it, with no !important. `yield: padding` covers every padding-*, `yield: none` clears it. DSSL.lint reports CSS that loses (css-loses).',
'outline-shape': 'an outline that follows the SHAPE (a sprite\u2019s alpha), not its box: `outline-shape: 3 color.ink`. Four hard drop-shadows, square corners. Uses `filter`, so it replaces another filter on the same rule. `none` clears it.',
'text-stroke': 'an outline round text, outside the letters: `text-stroke: 6 color.ink` (writes -webkit-text-stroke and paint-order: stroke fill). Add `inside` for a centred stroke, `none` to clear.',
stagger: 'choreographed children: `stagger: 70` fires each child\u2019s animation 70ms after its older sibling.',
transition: 'per-property transition: `transition: 200`, or `transition: 200 snap transform`. Honors reduced-motion.',
overlap: 'the anti-overlap policy: `auto` (engine shoves translucent elements apart), `deny` (this one never sits on anything), `allow` (exempt). Nothing below 100% opacity overlaps anything unless you say so.',
truncate: 'one-line ellipsis. Expands to overflow hidden, nowrap, text-overflow ellipsis.',
'visually-hidden': 'hidden from eyes, visible to screen readers.',
cover: 'fills the containing block absolutely.',
use: 'apply a behavior: `use focus-ring`. Behaviors are named rule groups declared with `behavior name { }`.',
glass: 'frosted glass: `glass: 18`, `glass: 24 saturate 1.8 tint white/12`. Blurs what is behind the element and adds a faint wash of the text colour. Plain CSS, so `dssl build` keeps it. `glass: none` clears it.',
tilt: 'follows the pointer in 3D: `tilt: 10`, `tilt: 12 lift 1.04 perspective 700 speed 0.2 invert glare`. Runtime only. `glare` keeps --dssl-gx and --dssl-gy pointing at the pointer so you can draw a shine. Ignores touch, flat under reduced motion.',
texture: 'a generated texture layered ON TOP of the element\u2019s own background: `texture: grain`, `texture: wood scale 6 intensity 0.8`, `texture: grain, scanlines`. 73 presets (grain, paper, marble, wood, carbon, halftone, ...) or build your own from a generator (noise, bump, lines, dots, grid, checker, weave, carbon, waves, hex) plus settings (scale, intensity, contrast, octaves, color, color2, blend, stretch, contour, ...). Wood: `texture: oak figure 0.8 knots 2 planks 120` (rings generator, ten species). `symmetrical` mirrors the tile so it never shows a seam. Open the designer to see them all.',
aura: 'light and particles around an element, with NO presets: you describe it. `aura: glow #ff7a00 30 flicker 0.3, particles #fd0 -> #f60 count 60 shape flame glowing behind`. Replaces both slots. `aura: none` clears them.',
'aura-glow': 'just the glow slot: `aura-glow: color.accent 24 pulse 1600`. Positional colour and radius, then settings (around SHAPE, inner, rays N, spin N, ripple ms, nohalo, z N, always, intensity, pulse, depth, flicker, texture(...), seed, essential). `aura-glow: none` clears only the glow.',
'aura-particle': 'just the particles slot: `aura-particle: #7cf -> transparent 40 up size 6 life 800 speed 30 from bottom`. Settings: around SHAPE (the outline `from edge` follows), palette, spin, wind, orbit, shape (heart, drop, bubble, snowflake, confetti, leaf...), z N (own canvas layer), count, size, life, speed, dir, spread, gravity, drag, turbulence, from, shape, grow, glowing, behind, blend, texture(...), seed, essential.',
'aura-particles': 'the same as `aura-particle`.',
'glow-particle': 'the particles slot with every particle glowing (additive light): `glow-particle: #fff 30 out`.',
'glow-particles': 'the same as `glow-particle`.',
'aura-glow-particle': 'both slots at once, settings shared: `aura-glow-particle: #ff7a00 28 pulse 900 count 50 up`. A glow layer AND a glowing particles layer.',
'aura-glow-particles': 'the same as `aura-glow-particle`.',
slider: 'styles `<input type="range">` through the WebKit/Blink (`::-webkit-slider-*`) and Firefox (`::-moz-range-*`) pseudo-elements at once: `slider: track 6 color.line radius full, fill color.accent, thumb 22 color.paper, ring 3 color.accent, glow color.accent 14, ticks 10`. Add `graph 20 45 70 90 60` for a histogram slider.',
seen: 'state that fires ONCE when the element first scrolls into view. Reveal-on-scroll with zero JavaScript. Composes with stagger. Cannot be combined with pseudo-elements.',
};
export const CSS = {
display: 'passthrough CSS. Note: semantic shorthands (row, column, grid, stack) also write display \u2014 order matters, and the compiler warns when a shorthand clobbers an explicit display.',
position: 'passthrough CSS: static, relative, absolute, fixed, sticky.',
width: 'passthrough CSS. Bare numbers are pixels.',
height: 'passthrough CSS. Bare numbers are pixels.',
margin: 'passthrough CSS. Shorthand with 1-4 values.',
padding: 'passthrough CSS. Shorthand with 1-4 values.',
background: 'passthrough CSS, but prefer `gradient:` sentences for gradients.',
color: 'text color. Values: token (color.ink), hex, CSS color name, alpha mix (color.ink/85).',
border: 'passthrough CSS shorthand: `border: 1 solid color.line`.',
'border-radius': 'passthrough CSS \u2014 prefer `radius:`.',
'font-size': 'passthrough CSS. Bare numbers are pixels.',
'font-family': 'passthrough CSS. Bare multi-word font names are legal since v0.5.',
'line-height': 'passthrough CSS.',
'letter-spacing': 'passthrough CSS.',
'text-align': 'passthrough CSS: left, center, right, justify.',
'text-transform': 'passthrough CSS: uppercase, lowercase, capitalize.',
'white-space': 'passthrough CSS: nowrap, pre, pre-wrap.',
opacity: 'passthrough CSS. Below 100% the overlap policy wakes up (see `overlap`).',
transform: 'passthrough CSS \u2014 deform (bend/stretch/fold) composes into this channel.',
translate: 'the transform channel the engine itself uses for overlap escapes; animating translate never fights the engine.',
rotate: 'rotation. A bare number is degrees: `rotate: 5` is 5deg. `5deg`, `0.1turn` and `x 30` pass through.',
scale: 'passthrough CSS.',
filter: 'passthrough CSS: blur(10), brightness(1.1).',
'backdrop-filter': 'passthrough CSS: blur(10).',
outline: 'passthrough CSS: `outline: 2 solid color.accent`.',
cursor: 'passthrough CSS: pointer, default, not-allowed.',
'z-index': 'passthrough CSS.',
overflow: 'passthrough CSS: hidden, auto, scroll, clip.',
'object-fit': 'passthrough CSS: cover, contain.',
gap: 'passthrough CSS \u2014 or let row:/column: set it inline.',
'flex-direction': 'passthrough CSS \u2014 row:/column: set it.',
'flex-wrap': 'passthrough CSS: wrap, nowrap.',
'justify-content': 'passthrough CSS \u2014 row:/column: can set it.',
'align-items': 'passthrough CSS \u2014 row:/column: can set it.',
'grid-template-columns': 'passthrough CSS \u2014 `grid: 3` is the sugar.',
'grid-template-rows': 'passthrough CSS.',
'align-content': 'passthrough CSS.',
'box-shadow': 'passthrough CSS \u2014 prefer `shadow:`.',
inset: 'passthrough CSS.',
'aspect-ratio': 'passthrough CSS: `aspect-ratio: 16 9`.',
'user-select': 'passthrough CSS: none stops text selection (pairs with pointer-events: none for veils).',
'pointer-events': 'passthrough CSS: none lets clicks and selection fall through overlays.',
'scrollbar-color': 'passthrough CSS for themed scrollbars.',
'scrollbar-width': 'passthrough CSS.',
'accent-color': 'passthrough CSS for native controls.',
'will-change': 'passthrough CSS.',
content: 'pseudo-element content, required for ::before/::after. Empty is auto-corrected to "".',
top: 'passthrough CSS.',
right: 'passthrough CSS.',
bottom: 'passthrough CSS.',
left: 'passthrough CSS.',
};
export const STATES = {
hover: 'engine-native hover: real events, enters and leaves, re-evaluates descendants too.',
focus: 'engine-native focus state.',
'focus-visible': 'keyboard-focus only. The focus-ring behavior\u2019s home.',
active: 'mouse/touch down.',
press: 'alias for active.',
pressed: 'alias for active.',
disabled: 'matches while the element is disabled.',
checked: 'matches while the element is checked.',
empty: 'matches an element with no children.',
target: 'matches when the element is the URL fragment target.',
seen: 'fires once, first time the element scrolls into view. Zero-JS reveal-on-scroll; composes with stagger.',
};
export const AT_RULES = {
'@media': 'conditions: `@media (max-width: 860)`, sugar forms `@media dark`, `@media light`, `@media reduced-motion`, bare widths, `<=` ranges.',
'@container': 'evaluates against the nearest ancestor (or self) with a container-type: `@container (min-width: 480)`.',
'@signal': 'the JS bridge: `@signal menuOpen { ... }` re-evaluates when DSSL.signal(\u0027menuOpen\u0027, true) fires. Mirrors onto data-dssl-signal-* attributes. Also `@signal screen in (menu, shop)`, `not in (a, b)` and `!=`. `DSSL.signal(name, value, el)` sets it for one subtree.',
'@layer': 'cascade layers: `@layer base { }`, `@layer components { }`, `@layer utilities { }`. Cascade is (layer, source order) \u2014 no specificity, no !important.',
};
export const BLOCKS = {
tokens: 'define design tokens: `tokens { color { ink: #16161d } radius { md: 14 } space { 9: 96 } }`. Numeric keys are legal. Referenced as color.ink, radius.md, space.9. Trailing /n adds alpha.',
behavior: 'a named rule group you can `use` anywhere: `behavior focus-ring { focus-visible { ... } }`.',
motion: 'a named keyframe animation, run with `animate:`: `motion pulse { from { } to { } }`.',
fonts: 'load fonts without raw CSS: `fonts { Fraunces: 500 700 800 "Hanken Grotesk": 400 700 italic Brand: from "/fonts/brand.woff2" 400 }`. Google families become a <link> (and an @import in `dssl build`); `from` writes @font-face. Settings: weights or a range (100..900), italic, display swap|block|fallback|optional.',
pin: 'must-win declarations. The cascade ranks tokens < base < components < utilities < pin. This is the ONLY way to force a win \u2014 there is no !important.',
};
export const PROPERTY_NAMES = [...Object.keys(SEMANTIC), ...Object.keys(CSS)];
|