diff --git a/.github/workflows/release-eslint.yml b/.github/workflows/release-eslint.yml new file mode 100644 index 0000000..12b95f5 --- /dev/null +++ b/.github/workflows/release-eslint.yml @@ -0,0 +1,42 @@ +name: Release ESLint Plugin + +on: + push: + branches: + - main + paths: + - 'eslint-plugin-blits/**' + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20' + + - name: Install Dependencies + run: npm install + + - name: Install monorepo dependencies + run: npm install --workspaces + + - name: Run Tests + run: npm run test --workspace=eslint-plugin-blits + + - name: Read package.json + run: | + plugin_name=$(node -p "require('./eslint-plugin-blits/package.json').name") + plugin_version=$(node -p "require('./eslint-plugin-blits/package.json').version") + echo "PLUGIN_NAME=$plugin_name" >> $GITHUB_ENV + echo "PLUGIN_VERSION=$plugin_version" >> $GITHUB_ENV + + - name: Create GitHub Pre Release + run: | + gh auth login --with-token <<< "${{ secrets.GITHUB_TOKEN }}" + gh release create eslint-v${{ env.PLUGIN_VERSION }} --prerelease -t "eslint-plugin-blits v${{ env.PLUGIN_VERSION }}" -n "Version ${{ env.PLUGIN_VERSION }} of ${{ env.PLUGIN_NAME }}" diff --git a/eslint-plugin-blits/CHANGELOG.md b/eslint-plugin-blits/CHANGELOG.md new file mode 100644 index 0000000..9496213 --- /dev/null +++ b/eslint-plugin-blits/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +## v1.0.0 + +Initial release of `@lightningjs/eslint-plugin-blits`. + +- `valid-template-syntax` — reports mismatched tags, unclosed attributes, and other parse errors with line/column positions pointing at the exact token +- `require-single-root-element` — errors when a template has more than one root element +- `only-valid-attributes-for-tags` — errors when a built-in tag (``, ``, ``, ``, ``) receives an attribute it doesn't support, using the Blits attribute schema as the source of truth +- `valid-attribute-value` — validates static values against the attribute schema (enums, numeric ranges, positive/non-negative constraints, percentage strings, regex patterns, and object-form values like `{x: 0.5, y: 0}`) +- `configs.recommended` — ESLint 9 flat config preset with all four rules set to `error` +- ESLint 8 supported; rules work but no preset is available +- `docs/attributes/` — reference pages for all 47 Blits template attributes +- Blits v2 support — auto-detects version from `package.json`, loads matching attribute schema. Use `settings: { blits: { version: 2 } }` to pin explicitly +- `border`, `rounded`, `shadow`, `shader` added as v2-only attributes. `effects` and `wordwrap` removed in v2 +- `rounded` also accepts array form `[tl, tr, br, bl]` in v2 +- `slot` attribute added to schema +- `Layout` added to valid tags for `w`, `h`, `width`, `height`, `clipping`, `overflow` +- `valid-attribute-value` now validates object keys for attributes with a closed key set (`color`, `scale`, `mount`, `pivot`, `fit`, etc.) +- `scale` and `mount` accept any numeric value, `letterspacing` accepts negative values +- `$shallow` no longer triggers a false positive in `valid-template-syntax` diff --git a/eslint-plugin-blits/README.md b/eslint-plugin-blits/README.md new file mode 100644 index 0000000..65a9b14 --- /dev/null +++ b/eslint-plugin-blits/README.md @@ -0,0 +1,90 @@ +# @lightningjs/eslint-plugin-blits + +An ESLint plugin for Blits apps, linting Blits template syntax in JavaScript and TypeScript files. + +## Installation + +```sh +npm install @lightningjs/eslint-plugin-blits --save-dev +``` + +## Usage + +### ESLint 9 (flat config) — recommended + +```js +// eslint.config.js +import blits from '@lightningjs/eslint-plugin-blits' + +export default [ + blits.configs.recommended +] +``` + +This enables all rules for `.js` and `.ts` files. + +### ESLint 8 (legacy config) + +Rules work with ESLint 8 but there is no preset — rules must be enabled manually. + +```js +// .eslintrc.js +module.exports = { + plugins: ['@lightningjs/blits'], + overrides: [ + { + files: ['**/*.js', '**/*.ts'], + rules: { + '@lightningjs/blits/valid-template-syntax': 'error', + '@lightningjs/blits/require-single-root-element': 'error', + '@lightningjs/blits/only-valid-attributes-for-tags': 'error', + '@lightningjs/blits/valid-attribute-value': 'error', + }, + }, + ], +} +``` + +## Supported Rules + +| Rule | Description | Recommended | Fixable | +|---|---|---|---| +| [`valid-template-syntax`](./docs/rules/valid-template-syntax.md) | Disallow template syntax errors (mismatched tags, unclosed attributes, etc.) | error | — | +| [`require-single-root-element`](./docs/rules/require-single-root-element.md) | Enforce that templates have exactly one root element | error | — | +| [`only-valid-attributes-for-tags`](./docs/rules/only-valid-attributes-for-tags.md) | Disallow attributes on built-in elements that don't support them | error | — | +| [`valid-attribute-value`](./docs/rules/valid-attribute-value.md) | Enforce that static attribute values match the allowed set | error | — | + +## Blits version + +The plugin automatically detects which version of Blits your project uses by reading `package.json` and adjusts rule behavior accordingly. No configuration is needed in most cases. If Blits is not listed in `package.json`, version 2 is assumed. + +To pin explicitly (useful when the version cannot be detected or you want to be explicit): + +**ESLint 9 (flat config):** +```js +// eslint.config.js +import blits from '@lightningjs/eslint-plugin-blits' + +export default [ + { + settings: { blits: { version: 2 } }, + ...blits.configs.recommended, + } +] +``` + +**ESLint 8 (legacy config):** +```js +// .eslintrc.js +module.exports = { + settings: { blits: { version: 2 } }, + plugins: ['@lightningjs/blits'], + rules: { ... } +} +``` + +Accepted values: `1`, `2`, or `'detect'` (same as omitting — triggers auto-detection). + +## License + +Apache-2.0. See the [LICENSE](LICENSE) file for details. diff --git a/eslint-plugin-blits/data/template-attributes.json b/eslint-plugin-blits/data/template-attributes.json new file mode 100644 index 0000000..8dff555 --- /dev/null +++ b/eslint-plugin-blits/data/template-attributes.json @@ -0,0 +1,1360 @@ +{ + "x": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The x position of the Element in pixels (or percentage), relative to its parent - allows negative values and decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numericOrPercent" } + }, + "possibleValues": ["0", "100", "-50", "1920", "50%", "100%", "-10%"], + "invalidValues": [ + { "value": "50 %", "reason": "space before % sign" }, + { "value": "100px", "reason": "px suffix not accepted" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "y": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The y position of the Element in pixels (or percentage), relative to its parent - allows negative values and decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numericOrPercent" } + }, + "possibleValues": ["0", "100", "-50", "1080", "50%", "25%"], + "invalidValues": [ + { "value": "50 %", "reason": "space before % sign" }, + { "value": "100px", "reason": "px suffix not accepted" }, + { "value": "top", "reason": "non-numeric string" } + ] + }, + "z": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "The z index of the element.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numeric", "integer": true } + }, + "possibleValues": ["0", "1", "10", "-1", "100"], + "invalidValues": [ + { "value": "auto", "reason": "non-numeric string" }, + { "value": "1.5", "reason": "z-index is semantically integer-only" } + ] + }, + "w": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The width of the element in pixels or percentage (e.g., \"50%\"). Allows decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numericOrPercent" } + }, + "possibleValues": ["0", "400", "1920", "50%", "100%"], + "invalidValues": [ + { "value": "400px", "reason": "px suffix not accepted" }, + { "value": "auto", "reason": "non-numeric string" }, + { "value": "50 %", "reason": "space before % sign" } + ] + }, + "h": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The height of the element in pixels or percentage (e.g., \"50%\"). Allows decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numericOrPercent" } + }, + "possibleValues": ["0", "200", "1080", "50%", "100%"], + "invalidValues": [ + { "value": "200px", "reason": "px suffix not accepted" }, + { "value": "auto", "reason": "non-numeric string" }, + { "value": "50 %", "reason": "space before % sign" } + ] + }, + "zIndex": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "The z-index of the element. Alias for z.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numeric", "integer": true } + }, + "possibleValues": ["0", "1", "10", "-1", "100"], + "invalidValues": [ + { "value": "auto", "reason": "non-numeric string" }, + { "value": "1.5", "reason": "z-index is semantically integer-only" } + ] + }, + "width": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The width of the element in pixels or percentage. Allows negative values and decimals. Alias for w.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numericOrPercent" } + }, + "possibleValues": ["0", "400", "1920", "50%", "100%"], + "invalidValues": [ + { "value": "400px", "reason": "px suffix not accepted" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "height": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The height of the element in pixels or percentage. Alias for h.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numericOrPercent" } + }, + "possibleValues": ["0", "200", "1080", "50%", "100%"], + "invalidValues": [ + { "value": "200px", "reason": "px suffix not accepted" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "color": { + "attrType": "regular", + "types": [ + "string", + { + "type": "object", + "properties": { + "top": { + "type": "string" + }, + "bottom": { + "type": "string" + }, + "left": { + "type": "string" + }, + "right": { + "type": "string" + } + } + } + ], + "defaultValue": "transparent", + "reactive": true, + "description": "The color of the Element. Accepts hexadecimal, hex with alpha, hex shorthands, RGB, RGBA, HTML color names, or an object with top/bottom/left/right keys for linear gradients.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "noValidateReason": "Scalar color forms (hex, rgb(), rgba(), 140+ named colors) are too numerous to enumerate reliably — a named-color enum needs ~140 entries and breaks with future CSS additions. The permissive regex below documents the structure without enforcing specific formats; value correctness is deferred to runtime.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a valid color string (hex, rgb(), rgba(), or named color)." }, + "object": { + "top": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a valid color string." }, + "bottom": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a valid color string." }, + "left": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a valid color string." }, + "right": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a valid color string." } + } + }, + "possibleValues": ["#ff4433", "#55553380", "#333", "rgb(180,30,50)", "rgba(40,30,180,0.5)", "red", "transparent", "skyblue", "{top: 'red', bottom: 'blue'}", "{left: 'rgba(255,255,255,0.5)', right: '#000'}"], + "invalidValues": [ + { "value": "red-ish", "reason": "not a valid CSS color name or format" }, + { "value": "#GGHHII", "reason": "invalid hex digits" } + ] + }, + "alpha": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 1, + "reactive": true, + "description": "The alpha attribute controls the opacity of the element. Allows values between 0 (fully transparent) and 1 (fully visible).", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "range", "min": 0, "max": 1 } + }, + "possibleValues": ["0", "0.5", "1", "0.25", "0.99"], + "invalidValues": [ + { "value": "1.5", "reason": "exceeds maximum of 1" }, + { "value": "-0.1", "reason": "below minimum of 0" }, + { "value": "full", "reason": "non-numeric string" } + ] + }, + "rotation": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "Rotates the Element. Accepts positive and negative values in degrees.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numeric" } + }, + "possibleValues": ["0", "90", "180", "270", "360", "-45", "33.5"], + "invalidValues": [ + { "value": "90deg", "reason": "deg suffix not accepted" }, + { "value": "quarter turn", "reason": "non-numeric string" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "scale": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 1, + "reactive": true, + "description": "Scales the element. Accepts a single number for uniform scaling or an object {x, y} for independent axis scaling. Values below 1 scale down, above 1 scale up.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numeric" }, + "object": { + "x": { "type": "numeric" }, + "y": { "type": "numeric" } + } + }, + "possibleValues": ["1", "0.5", "2", "2.3", "0.1", "{x: 1, y: 2}", "{x: 0.5, y: 1}"], + "invalidValues": [ + { "value": "large", "reason": "non-numeric string" }, + { "value": "2x", "reason": "x suffix not accepted" } + ] + }, + "mount": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 0, + "reactive": true, + "description": "Sets the mount point of the Element. Accepts a single number or an object {x, y} with values between 0 and 1. Default {x: 0, y: 0} is the top-left corner.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "numeric" }, + "object": { + "x": { "type": "numeric" }, + "y": { "type": "numeric" } + } + }, + "possibleValues": ["0", "0.5", "1", "0.25", "{x: 0, y: 0}", "{x: 0.5, y: 0.8}", "{y: 1}"], + "invalidValues": [ + { "value": "center", "reason": "non-numeric string" }, + { "value": "top-left", "reason": "non-numeric string" } + ] + }, + "pivot": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 0.5, + "reactive": true, + "description": "Sets the pivot point for rotation and scaling. Accepts a single number or an object {x, y} with values between 0 and 1. Default {x: 0.5, y: 0.5} is the center.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "range", "min": 0, "max": 1 }, + "object": { + "x": { "type": "range", "min": 0, "max": 1 }, + "y": { "type": "range", "min": 0, "max": 1 } + } + }, + "possibleValues": ["0", "0.5", "1", "0.9", "0.25", "{x: 0.5, y: 0.5}", "{y: 1}", "{x: 0, y: 0}"], + "invalidValues": [ + { "value": "1.5", "reason": "exceeds maximum of 1" }, + { "value": "-0.1", "reason": "below minimum of 0" }, + { "value": "center", "reason": "non-numeric string" } + ] + }, + "clipping": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "false", + "reactive": true, + "description": "Clips child content to the element's width and height boundaries.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "enum", "values": ["true", "false"] } + }, + "possibleValues": ["true", "false"], + "invalidValues": [ + { "value": "yes", "reason": "only 'true' or 'false' accepted" }, + { "value": "1", "reason": "numeric string not accepted" }, + { "value": "clip", "reason": "not a valid enum value" } + ] + }, + "overflow": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "true", + "reactive": true, + "description": "Allows content to extend beyond the element's width and height. Inverse of clipping.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "enum", "values": ["true", "false"] } + }, + "possibleValues": ["true", "false"], + "invalidValues": [ + { "value": "yes", "reason": "only 'true' or 'false' accepted" }, + { "value": "visible", "reason": "CSS overflow value not accepted" }, + { "value": "hidden", "reason": "CSS overflow value not accepted" } + ] + }, + "src": { + "attrType": "regular", + "types": [ + "string", + { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "regular", + "svg", + "compressed" + ] + } + } + } + ], + "defaultValue": null, + "reactive": true, + "description": "The image source URL. Can be a string path or an object {src, type} where type is 'regular', 'svg', or 'compressed' (for cases where file type can't be derived from the file name).", + "usedIn": [ + "Element" + ], + "docRef": ["essentials/displaying_images.md"], + "noValidateReason": "The string scalar form is documented in displaying_images.md. The object form {src, type} was added in v1.44.0 (changelog confirmed) and is implemented in element.js, but is not yet reflected in the markdown docs. Both forms are fully validated — this field is retained for transparency.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a non-empty image path or URL." }, + "object": { + "src": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "'src' object must have a non-empty 'src' property." }, + "type": { "type": "enum", "values": ["regular", "svg", "compressed"] } + } + }, + "possibleValues": ["assets/logo.png", "https://example.com/img.jpg", "assets/icon.svg", "{src: 'assets/icon.svg', type: 'svg'}", "{src: 'img.compressed', type: 'compressed'}"], + "invalidValues": [ + { "value": "", "reason": "empty string is not a valid src" }, + { "value": "{type: 'png'}", "reason": "type must be 'regular', 'svg', or 'compressed'" } + ] + }, + "fit": { + "attrType": "regular", + "types": [ + "enum", + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cover", + "contain" + ] + }, + "position": { + "type": "object", + "properties": { + "x": { "type": "number" }, + "y": { "type": "number" } + } + } + } + } + ], + "values": [ + "cover", + "contain" + ], + "defaultValue": null, + "reactive": true, + "description": "Controls how an image is resized to fit the Element's dimensions. Accepts 'cover' or 'contain', or an object {type, position} where position is either a number 0–1 (applies to both axes) or {x?, y?} with values 0–1 to control the clip anchor point independently.", + "usedIn": [ + "Element" + ], + "docRef": [], + "noValidateReason": "Added in v1.4.0 (changelog confirmed), implemented in element.js, heavily used in the example app (Resize.js). Not yet in the markdown docs. The scalar enum form is strictly validated. The object form's 'position' key accepts either a plain number (sets both axes) or {x?, y?} — a nested shape that cannot be expressed in the current flat descriptor schema, so a permissive regex is used for position.", + "validate": { + "scalar": { "type": "enum", "values": ["cover", "contain"] }, + "object": { + "type": { "type": "enum", "values": ["cover", "contain"] }, + "position": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a position object with optional x and/or y keys (0–1), e.g. {x: 0.5} or {y: 1}." } + } + }, + "possibleValues": ["cover", "contain", "{type: 'cover', position: {y: 0}}", "{type: 'cover', position: {x: 0.5}}", "{type: 'cover', position: {y: 0.5, x: 0.5}}", "{type: 'contain', position: {x: 0}}", "{type: 'cover', position: 0.5}"], + "invalidValues": [ + { "value": "fill", "reason": "not a valid fit value" }, + { "value": "stretch", "reason": "not a valid fit value" }, + { "value": "none", "reason": "not a valid fit value" } + ] + }, + "rtt": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "false", + "reactive": true, + "description": "Enables render-to-texture mode, rendering the element and its children to an off-screen texture.", + "usedIn": [ + "Element" + ], + "docRef": [], + "noValidateReason": "Added in v0.9.9 (changelog confirmed), implemented in element.js. Not yet in the markdown docs. The source setter checks strict boolean equality (v === true), so this attribute is primarily intended for reactive bindings (:rtt=\"$bool\"). The 'true'/'false' string enum covers the static template use case.", + "validate": { + "scalar": { "type": "enum", "values": ["true", "false"] } + }, + "possibleValues": ["true", "false"], + "invalidValues": [ + { "value": "yes", "reason": "only 'true' or 'false' accepted" }, + { "value": "1", "reason": "numeric string not accepted" } + ] + }, + "effects": { + "attrType": "regular", + "types": [ + "array" + ], + "defaultValue": null, + "reactive": true, + "description": "Applies one or more shader effects using DynamicShader. Accepts an array of objects, each with a type and optional props (e.g., [{type: 'radius', props: {radius: 20}}]).", + "usedIn": [ + "Element" + ], + "docRef": [], + "noValidateReason": "Not yet in the markdown docs, but heavily used throughout the example app (radius, border, radialGradient, etc.). Effect types and their props are open-ended — the set of valid shader types is extensible and cannot be maintained in a static schema. The permissive regex documents the scalar form without constraining it.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected an array of effect objects (e.g., [{type: 'radius', props: {radius: 20}}])." } + }, + "possibleValues": ["[{type: 'radius', props: {radius: 20}}]", "[{type: 'border', props: {width: 4, color: '#fff'}}]", "[{type: 'radialGradient', props: {colors: ['#b43fcb', '#6150cb'], pivot: [0.5, 1.1], width: 1920, height: 800}}]", "[{type: 'radius', props: {radius: 10}}, {type: 'border', props: {width: 2, color: '#60a5fa'}}]"] + }, + "placement": { + "attrType": "regular", + "types": [ + "enum", + { + "type": "object", + "properties": { + "x": { + "type": "string", + "enum": [ + "left", + "center", + "right" + ] + }, + "y": { + "type": "string", + "enum": [ + "top", + "middle", + "bottom" + ] + } + } + } + ], + "values": [ + "left", + "center", + "right", + "top", + "middle", + "bottom" + ], + "defaultValue": null, + "reactive": true, + "description": "Predefined placement relative to the parent's dimensions. Accepts 'left', 'center', 'right', 'top', 'middle', 'bottom', or an object {x, y} for combined placement.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": ["essentials/element_attributes.md"], + "validate": { + "scalar": { "type": "enum", "values": ["left", "center", "right", "top", "middle", "bottom"] }, + "object": { + "x": { "type": "enum", "values": ["left", "center", "right"] }, + "y": { "type": "enum", "values": ["top", "middle", "bottom"] } + } + }, + "possibleValues": ["left", "center", "right", "top", "middle", "bottom", "{x: 'center', y: 'bottom'}", "{x: 'right', y: 'middle'}"], + "invalidValues": [ + { "value": "absolute", "reason": "not a valid placement value" }, + { "value": "flex", "reason": "not a valid placement value" }, + { "value": "Centre", "reason": "values are case-sensitive" }, + { "value": "start", "reason": "not a valid placement value" } + ] + }, + "inspector-data": { + "attrType": "regular", + "types": [ + { + "type": "object" + } + ], + "defaultValue": null, + "reactive": false, + "description": "Attaches custom metadata to elements for debugging and automated testing, visible in the Lightning inspector. Only processed in dev mode when inspector is enabled.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["essentials/element_attributes.md"], + "noValidateReason": "Keys and values are user-defined debug metadata with no fixed schema. The object validator below has no property rules — it documents the object form without constraining its contents.", + "validate": { + "object": {} + }, + "possibleValues": ["{testId: 'my-button'}", "{role: 'navigation', testId: 'nav'}"] + }, + "content": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": true, + "description": "The text to be displayed. Can be hardcoded text, a dynamic value, or a reactive value.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "noValidateReason": "Any string is valid by design — empty string, whitespace, unicode, numbers as text. The permissive regex below documents the scalar form without imposing constraints.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a text string." } + }, + "possibleValues": ["Hello world", "Welcome", ""] + }, + "font": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": "sans-serif", + "reactive": true, + "description": "The font family to use for text rendering.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "noValidateReason": "Font names are registered at launch time in settings.fonts and are project-specific. The plugin has no knowledge of which fonts a given app has registered. The regex below only enforces non-empty; it cannot validate against the actual registered font list.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a non-empty font family name." } + }, + "possibleValues": ["sans-serif", "lato", "raleway", "ComicSans"] + }, + "size": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 32, + "reactive": true, + "description": "The font size of a Text element in pixels.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "positive" } + }, + "possibleValues": ["12", "16", "32", "48", "64"], + "invalidValues": [ + { "value": "0", "reason": "zero makes text invisible; must be greater than 0" }, + { "value": "-12", "reason": "negative font size not accepted" }, + { "value": "large", "reason": "non-numeric string" }, + { "value": "1em", "reason": "em units not accepted" } + ] + }, + "letterspacing": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "Letter spacing in pixels. Allows any number greater than or equal to zero.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "numeric" } + }, + "possibleValues": ["0", "1", "5", "10", "0.5"], + "invalidValues": [ + { "value": "tight", "reason": "non-numeric string" }, + { "value": "normal", "reason": "non-numeric string" } + ] + }, + "align": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "left", + "right", + "center" + ], + "defaultValue": null, + "reactive": true, + "description": "The alignment of the text. Centering and right alignment require maxwidth to be set.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "enum", "values": ["left", "right", "center"] } + }, + "possibleValues": ["left", "right", "center"], + "invalidValues": [ + { "value": "justify", "reason": "not a valid align value" }, + { "value": "start", "reason": "not a valid align value" }, + { "value": "end", "reason": "not a valid align value" }, + { "value": "Centre", "reason": "values are case-sensitive" } + ] + }, + "maxwidth": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "The maximum length of a line of text in pixels. Words surpassing this length will be wrapped onto the next line.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "nonNegative", "integer": true } + }, + "possibleValues": ["0", "400", "800", "1920"], + "invalidValues": [ + { "value": "-100", "reason": "negative value not accepted" }, + { "value": "100%", "reason": "percentage not accepted" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "maxlines": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "Maximum number of lines that will be displayed.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "nonNegative", "integer": true } + }, + "possibleValues": ["0", "1", "3", "10"], + "invalidValues": [ + { "value": "-1", "reason": "negative value not accepted" }, + { "value": "1.5", "reason": "line count must be a whole number" }, + { "value": "unlimited", "reason": "non-numeric string" } + ] + }, + "maxheight": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "Maximum height of a text block in pixels. Lines exceeding this height will not be displayed.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "nonNegative", "integer": true } + }, + "possibleValues": ["0", "100", "400", "1080"], + "invalidValues": [ + { "value": "-100", "reason": "negative value not accepted" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "lineheight": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "The spacing between lines in pixels.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "nonNegative" } + }, + "possibleValues": ["0", "20", "40", "1.5"], + "invalidValues": [ + { "value": "-5", "reason": "negative line height not accepted" }, + { "value": "normal", "reason": "non-numeric string" }, + { "value": "1.5em", "reason": "em units not accepted" } + ] + }, + "contain": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "none", + "width", + "both" + ], + "defaultValue": "none", + "reactive": true, + "description": "The strategy for containing text within bounds. Usually set automatically by Blits based on other specified attributes.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "enum", "values": ["none", "width", "both"] } + }, + "possibleValues": ["none", "width", "both"], + "invalidValues": [ + { "value": "height", "reason": "not a valid contain value" }, + { "value": "all", "reason": "not a valid contain value" }, + { "value": "auto", "reason": "not a valid contain value" } + ] + }, + "textoverflow": { + "attrType": "regular", + "types": [ + "string", + "enum" + ], + "values": [ + "false" + ], + "defaultValue": "...", + "reactive": true, + "description": "The suffix added when text is cropped due to bounds limits. Defaults to '...'. Set to false or empty string for no suffix.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "noValidateReason": "Any string suffix is valid by design — there is no wrong suffix value. The special value 'false' disables the suffix entirely. Even empty string is valid. The permissive regex below documents the scalar form without constraining it.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a string suffix or 'false' to disable." } + }, + "possibleValues": ["...", "false", " read more", ""] + }, + "wordwrap": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "deprecated": true, + "description": "Deprecated - use maxwidth instead. Sets the maximum line width in pixels for text wrapping.", + "usedIn": [ + "Text" + ], + "docRef": ["essentials/displaying_text.md"], + "validate": { + "scalar": { "type": "nonNegative", "integer": true } + }, + "possibleValues": ["0", "400", "800"], + "invalidValues": [ + { "value": "-100", "reason": "negative value not accepted" }, + { "value": "100%", "reason": "percentage not accepted" }, + { "value": "auto", "reason": "non-numeric string" } + ] + }, + "direction": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "horizontal", + "vertical" + ], + "defaultValue": "horizontal", + "reactive": true, + "description": "Controls the direction of layout content arrangement.", + "usedIn": [ + "Layout" + ], + "docRef": ["built-in/layout.md"], + "validate": { + "scalar": { "type": "enum", "values": ["horizontal", "vertical"] } + }, + "possibleValues": ["horizontal", "vertical"], + "invalidValues": [ + { "value": "row", "reason": "CSS flexbox value not accepted; use 'horizontal'" }, + { "value": "column", "reason": "CSS flexbox value not accepted; use 'vertical'" }, + { "value": "ltr", "reason": "not a valid direction value" } + ] + }, + "gap": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "Controls how much space in pixels is added between each child Element or Component in a Layout.", + "usedIn": [ + "Layout" + ], + "docRef": ["built-in/layout.md"], + "validate": { + "scalar": { "type": "nonNegative" } + }, + "possibleValues": ["0", "10", "20", "50"], + "invalidValues": [ + { "value": "-10", "reason": "negative gap not accepted" }, + { "value": "medium", "reason": "non-numeric string" }, + { "value": "10px", "reason": "px suffix not accepted" } + ] + }, + "align-items": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "start", + "center", + "end" + ], + "defaultValue": "start", + "reactive": true, + "description": "Specifies how to align children on the opposite axis of the Layout direction.", + "usedIn": [ + "Layout" + ], + "docRef": ["built-in/layout.md"], + "validate": { + "scalar": { "type": "enum", "values": ["start", "center", "end"] } + }, + "possibleValues": ["start", "center", "end"], + "invalidValues": [ + { "value": "flex-start", "reason": "CSS flexbox value not accepted; use 'start'" }, + { "value": "flex-end", "reason": "CSS flexbox value not accepted; use 'end'" }, + { "value": "stretch", "reason": "not a valid align-items value" }, + { "value": "baseline", "reason": "not a valid align-items value" } + ] + }, + "padding": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "top": { + "type": "number" + }, + "bottom": { + "type": "number" + }, + "left": { + "type": "number" + }, + "right": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 0, + "reactive": true, + "description": "Adds spacing between the content and the edges of the Layout. Accepts a number for uniform padding or an object with top/bottom/left/right/x/y keys.", + "usedIn": [ + "Layout" + ], + "docRef": ["built-in/layout.md"], + "validate": { + "scalar": { "type": "nonNegative" }, + "object": { + "top": { "type": "nonNegative" }, + "bottom": { "type": "nonNegative" }, + "left": { "type": "nonNegative" }, + "right": { "type": "nonNegative" }, + "x": { "type": "nonNegative" }, + "y": { "type": "nonNegative" } + } + }, + "possibleValues": ["0", "10", "20", "{top: 10, bottom: 20}", "{x: 20, top: 30, bottom: 10}", "{left: 5, right: 5}"], + "invalidValues": [ + { "value": "-5", "reason": "negative padding not accepted" }, + { "value": "medium", "reason": "non-numeric string" }, + { "value": "10px", "reason": "px suffix not accepted" } + ] + }, + "is": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "Dynamically instantiates a Component based on a state variable or prop value.", + "usedIn": [ + "Component" + ], + "docRef": ["built-in/directives.md"], + "noValidateReason": "The referenced component is resolved at runtime from state or props. Which components are valid depends on what the app has imported and registered — a cross-file concern not resolvable in a per-file rule. The permissive regex below documents the scalar form.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a component reference (e.g., $myComponent)." } + }, + "possibleValues": ["$myComponent", "$activeView"] + }, + "ref": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "A reference identifier for the Element or Component, accessible via this.select() in the component logic.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["built-in/directives.md", "built-in/for-loop.md"], + "noValidateReason": "Any non-empty identifier is valid. Cross-referencing via this.$select() is a runtime concern — the plugin cannot know what refs are used downstream. The regex below enforces non-empty only.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]+$", "message": "Expected a non-empty ref identifier." } + }, + "possibleValues": ["myButton", "heroImage", "titleText"] + }, + "for": { + "attrType": "directive", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": true, + "description": "Directive for repeating multiple instances of an Element or Component. Uses 'item in $array' or '(item, index) in $array' syntax.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["built-in/for-loop.md"], + "validate": { + "scalar": { + "type": "regex", + "pattern": "^(\\(\\s*\\w+\\s*,\\s*\\w+\\s*\\)|\\w+)\\s+in\\s+\\$\\w+", + "message": "':for' value must follow 'item in $array' or '(item, index) in $array' syntax." + } + }, + "possibleValues": ["item in $list", "(item, index) in $items"], + "invalidValues": [ + { "value": "item of $list", "reason": "'of' is not valid; use 'in'" }, + { "value": "$list", "reason": "missing 'item in' prefix" }, + { "value": "item in list", "reason": "array variable must be prefixed with $" } + ] + }, + "$shallow": { + "attrType": "directive", + "types": [ + "string" + ], + "defaultValue": "true", + "reactive": false, + "description": "Performance modifier for ':for' loops. Controls whether child components in the loop have access to the outer scope. When omitted or 'true', the loop is shallow (faster — each item only sees its own scope). Set to 'false' to allow items to access outer scope variables.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [], + "validate": { + "scalar": { + "type": "enum", + "values": ["true", "false"] + } + }, + "possibleValues": ["false"], + "invalidValues": [] + }, + "key": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "A unique identifier for items in a for-loop, enabling efficient reuse of Element/Component instances when the array changes. Should reference a unique field (e.g., key=\"$item.id\").", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["built-in/for-loop.md"], + "noValidateReason": "Valid expressions depend on the shape of the iterated array items — a runtime data concern. The plugin cannot validate the key expression against the actual item type without cross-referencing state. The permissive regex below documents the scalar form.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a unique identifier expression (e.g., $item.id)." } + }, + "possibleValues": ["$item.id", "$item.name", "$item.hash"] + }, + "range": { + "attrType": "regular", + "types": [ + { + "type": "object", + "properties": { + "from": { + "type": "number" + }, + "to": { + "type": "number" + } + } + } + ], + "defaultValue": null, + "reactive": true, + "description": "Limits a for-loop to render only a subset of items. Accepts an object {from, to} where 'from' is inclusive and 'to' is exclusive. Items outside the range are destroyed and recreated when they re-enter.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["built-in/for-loop.md"], + "validate": { + "object": { + "from": { "type": "numeric", "integer": true }, + "to": { "type": "numeric", "integer": true } + } + }, + "possibleValues": ["{from: 0, to: 10}", "{from: 5, to: 20}"], + "invalidValues": [ + { "value": "{from: 1.5, to: 10}", "reason": "'from' must be an integer" }, + { "value": "{from: 0, to: 1.5}", "reason": "'to' must be an integer" } + ] + }, + "show": { + "attrType": "directive", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "true", + "reactive": true, + "description": "Conditionally shows or hides the Element/Component by setting alpha to 0 or restoring it.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": ["built-in/directives.md"], + "validate": { + "scalar": { "type": "enum", "values": ["true", "false"] } + }, + "possibleValues": ["true", "false"], + "invalidValues": [ + { "value": "yes", "reason": "only 'true' or 'false' accepted" }, + { "value": "1", "reason": "numeric string not accepted" }, + { "value": "hidden", "reason": "not a valid show value" }, + { "value": "visible", "reason": "not a valid show value" } + ] + }, + "slot": { + "attrType": "directive", + "types": ["string"], + "defaultValue": null, + "reactive": false, + "description": "Routes an Element or Component to a named slot in the parent component. The value must match the `ref` attribute of the target `` definition in the parent's template.", + "usedIn": ["Element", "Text", "Layout", "RouterView", "Component"], + "docRef": [], + "noValidateReason": "The slot attribute accepts any non-empty string that matches the ref attribute of a definition in the parent component. The plugin cannot statically verify that the named slot exists in the parent — that is a runtime concern.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a non-empty slot name matching a definition in the parent component." + } + }, + "possibleValues": ["first", "second", "header", "footer", "content"] + }, + "@loaded": { + "attrType": "event", + "types": [ + "string", + "function" + ], + "defaultValue": null, + "reactive": false, + "description": "Fires when an image or text element loads, providing its dimensions ({w, h}). Accepts a function reference (e.g., $handlerName) or an inline arrow function.", + "usedIn": [ + "Element", + "Text" + ], + "docRef": ["essentials/displaying_images.md", "essentials/displaying_text.md"], + "noValidateReason": "Accepts a function reference ($handlerName) or inline arrow function. Whether the referenced method exists is a component-logic concern, not an attribute-value concern. The permissive regex documents the scalar form.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a function reference (e.g., $handlerName) or inline arrow function." } + }, + "possibleValues": ["$onLoaded", "$handleImageLoad"] + }, + "@error": { + "attrType": "event", + "types": [ + "string", + "function" + ], + "defaultValue": null, + "reactive": false, + "description": "Fires when an image fails to load, passing an error message. Accepts a function reference (e.g., $handlerName) or an inline arrow function.", + "usedIn": [ + "Element", + "Text" + ], + "docRef": ["essentials/displaying_images.md"], + "noValidateReason": "Accepts a function reference ($handlerName) or inline arrow function. Whether the referenced method exists is a component-logic concern, not an attribute-value concern. The permissive regex documents the scalar form.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a function reference (e.g., $handlerName) or inline arrow function." } + }, + "possibleValues": ["$onError", "$handleImageError"] + }, + "@updated": { + "attrType": "event", + "types": [ + "string", + "function" + ], + "defaultValue": null, + "reactive": false, + "description": "Fires after each Layout children update, providing current dimensions ({w, h}). Can fire multiple times.", + "usedIn": [ + "Layout" + ], + "docRef": ["built-in/layout.md"], + "noValidateReason": "Accepts a function reference ($handlerName) or inline arrow function. Whether the referenced method exists is a component-logic concern, not an attribute-value concern. The permissive regex documents the scalar form.", + "validate": { + "scalar": { "type": "regex", "pattern": "^[\\s\\S]*$", "message": "Expected a function reference (e.g., $handlerName) or inline arrow function." } + }, + "possibleValues": ["$onLayoutUpdate", "$handleUpdate"] + } +} diff --git a/eslint-plugin-blits/data/template-attributes.v2.json b/eslint-plugin-blits/data/template-attributes.v2.json new file mode 100644 index 0000000..25994bc --- /dev/null +++ b/eslint-plugin-blits/data/template-attributes.v2.json @@ -0,0 +1,2375 @@ +{ + "x": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The x position of the Element in pixels (or percentage), relative to its parent - allows negative values and decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numericOrPercent" + } + }, + "possibleValues": [ + "0", + "100", + "-50", + "1920", + "50%", + "100%", + "-10%" + ], + "invalidValues": [ + { + "value": "50 %", + "reason": "space before % sign" + }, + { + "value": "100px", + "reason": "px suffix not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + } + ] + }, + "y": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The y position of the Element in pixels (or percentage), relative to its parent - allows negative values and decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numericOrPercent" + } + }, + "possibleValues": [ + "0", + "100", + "-50", + "1080", + "50%", + "25%" + ], + "invalidValues": [ + { + "value": "50 %", + "reason": "space before % sign" + }, + { + "value": "100px", + "reason": "px suffix not accepted" + }, + { + "value": "top", + "reason": "non-numeric string" + } + ] + }, + "z": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "The z index of the element.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numeric", + "integer": true + } + }, + "possibleValues": [ + "0", + "1", + "10", + "-1", + "100" + ], + "invalidValues": [ + { + "value": "auto", + "reason": "non-numeric string" + }, + { + "value": "1.5", + "reason": "z-index is semantically integer-only" + } + ] + }, + "w": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The width of the element in pixels or percentage (e.g., \"50%\"). Allows decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numericOrPercent" + } + }, + "possibleValues": [ + "0", + "400", + "1920", + "50%", + "100%" + ], + "invalidValues": [ + { + "value": "400px", + "reason": "px suffix not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + }, + { + "value": "50 %", + "reason": "space before % sign" + } + ] + }, + "h": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The height of the element in pixels or percentage (e.g., \"50%\"). Allows decimals.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numericOrPercent" + } + }, + "possibleValues": [ + "0", + "200", + "1080", + "50%", + "100%" + ], + "invalidValues": [ + { + "value": "200px", + "reason": "px suffix not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + }, + { + "value": "50 %", + "reason": "space before % sign" + } + ] + }, + "zIndex": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "The z-index of the element. Alias for z.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numeric", + "integer": true + } + }, + "possibleValues": [ + "0", + "1", + "10", + "-1", + "100" + ], + "invalidValues": [ + { + "value": "auto", + "reason": "non-numeric string" + }, + { + "value": "1.5", + "reason": "z-index is semantically integer-only" + } + ] + }, + "width": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The width of the element in pixels or percentage. Allows negative values and decimals. Alias for w.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numericOrPercent" + } + }, + "possibleValues": [ + "0", + "400", + "1920", + "50%", + "100%" + ], + "invalidValues": [ + { + "value": "400px", + "reason": "px suffix not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + } + ] + }, + "height": { + "attrType": "regular", + "types": [ + "number", + "string" + ], + "defaultValue": 0, + "reactive": true, + "description": "The height of the element in pixels or percentage. Alias for h.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numericOrPercent" + } + }, + "possibleValues": [ + "0", + "200", + "1080", + "50%", + "100%" + ], + "invalidValues": [ + { + "value": "200px", + "reason": "px suffix not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + } + ] + }, + "color": { + "attrType": "regular", + "types": [ + "string", + { + "type": "object", + "properties": { + "top": { + "type": "string" + }, + "bottom": { + "type": "string" + }, + "left": { + "type": "string" + }, + "right": { + "type": "string" + } + } + } + ], + "defaultValue": "transparent", + "reactive": true, + "description": "The color of the Element. Accepts hexadecimal, hex with alpha, hex shorthands, RGB, RGBA, HTML color names, or an object with top/bottom/left/right keys for linear gradients.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "noValidateReason": "Scalar color forms (hex, rgb(), rgba(), 140+ named colors) are too numerous to enumerate reliably \u2014 a named-color enum needs ~140 entries and breaks with future CSS additions. The permissive regex below documents the structure without enforcing specific formats; value correctness is deferred to runtime.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a valid color string (hex, rgb(), rgba(), or named color)." + }, + "object": { + "top": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a valid color string." + }, + "bottom": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a valid color string." + }, + "left": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a valid color string." + }, + "right": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a valid color string." + } + } + }, + "possibleValues": [ + "#ff4433", + "#55553380", + "#333", + "rgb(180,30,50)", + "rgba(40,30,180,0.5)", + "red", + "transparent", + "skyblue", + "{top: 'red', bottom: 'blue'}", + "{left: 'rgba(255,255,255,0.5)', right: '#000'}" + ], + "invalidValues": [ + { + "value": "red-ish", + "reason": "not a valid CSS color name or format" + }, + { + "value": "#GGHHII", + "reason": "invalid hex digits" + } + ] + }, + "alpha": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 1, + "reactive": true, + "description": "The alpha attribute controls the opacity of the element. Allows values between 0 (fully transparent) and 1 (fully visible).", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "range", + "min": 0, + "max": 1 + } + }, + "possibleValues": [ + "0", + "0.5", + "1", + "0.25", + "0.99" + ], + "invalidValues": [ + { + "value": "1.5", + "reason": "exceeds maximum of 1" + }, + { + "value": "-0.1", + "reason": "below minimum of 0" + }, + { + "value": "full", + "reason": "non-numeric string" + } + ] + }, + "rotation": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "Rotates the Element. Accepts positive and negative values in degrees.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numeric" + } + }, + "possibleValues": [ + "0", + "90", + "180", + "270", + "360", + "-45", + "33.5" + ], + "invalidValues": [ + { + "value": "90deg", + "reason": "deg suffix not accepted" + }, + { + "value": "quarter turn", + "reason": "non-numeric string" + }, + { + "value": "auto", + "reason": "non-numeric string" + } + ] + }, + "scale": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 1, + "reactive": true, + "description": "Scales the element. Accepts a single number for uniform scaling or an object {x, y} for independent axis scaling. Values below 1 scale down, above 1 scale up.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numeric" + }, + "object": { + "x": { + "type": "numeric" + }, + "y": { + "type": "numeric" + } + } + }, + "possibleValues": [ + "1", + "0.5", + "2", + "2.3", + "0.1", + "{x: 1, y: 2}", + "{x: 0.5, y: 1}" + ], + "invalidValues": [ + { + "value": "large", + "reason": "non-numeric string" + }, + { + "value": "2x", + "reason": "x suffix not accepted" + } + ] + }, + "mount": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 0, + "reactive": true, + "description": "Sets the mount point of the Element. Accepts a single number or an object {x, y} with values between 0 and 1. Default {x: 0, y: 0} is the top-left corner.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numeric" + }, + "object": { + "x": { + "type": "numeric" + }, + "y": { + "type": "numeric" + } + } + }, + "possibleValues": [ + "0", + "0.5", + "1", + "0.25", + "{x: 0, y: 0}", + "{x: 0.5, y: 0.8}", + "{y: 1}" + ], + "invalidValues": [ + { + "value": "center", + "reason": "non-numeric string" + }, + { + "value": "top-left", + "reason": "non-numeric string" + } + ] + }, + "pivot": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 0.5, + "reactive": true, + "description": "Sets the pivot point for rotation and scaling. Accepts a single number or an object {x, y} with values between 0 and 1. Default {x: 0.5, y: 0.5} is the center.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "range", + "min": 0, + "max": 1 + }, + "object": { + "x": { + "type": "range", + "min": 0, + "max": 1 + }, + "y": { + "type": "range", + "min": 0, + "max": 1 + } + } + }, + "possibleValues": [ + "0", + "0.5", + "1", + "0.9", + "0.25", + "{x: 0.5, y: 0.5}", + "{y: 1}", + "{x: 0, y: 0}" + ], + "invalidValues": [ + { + "value": "1.5", + "reason": "exceeds maximum of 1" + }, + { + "value": "-0.1", + "reason": "below minimum of 0" + }, + { + "value": "center", + "reason": "non-numeric string" + } + ] + }, + "clipping": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "false", + "reactive": true, + "description": "Clips child content to the element's width and height boundaries.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "true", + "false" + ] + } + }, + "possibleValues": [ + "true", + "false" + ], + "invalidValues": [ + { + "value": "yes", + "reason": "only 'true' or 'false' accepted" + }, + { + "value": "1", + "reason": "numeric string not accepted" + }, + { + "value": "clip", + "reason": "not a valid enum value" + } + ] + }, + "overflow": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "true", + "reactive": true, + "description": "Allows content to extend beyond the element's width and height. Inverse of clipping.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "true", + "false" + ] + } + }, + "possibleValues": [ + "true", + "false" + ], + "invalidValues": [ + { + "value": "yes", + "reason": "only 'true' or 'false' accepted" + }, + { + "value": "visible", + "reason": "CSS overflow value not accepted" + }, + { + "value": "hidden", + "reason": "CSS overflow value not accepted" + } + ] + }, + "src": { + "attrType": "regular", + "types": [ + "string", + { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "regular", + "svg", + "compressed" + ] + } + } + } + ], + "defaultValue": null, + "reactive": true, + "description": "The image source URL. Can be a string path or an object {src, type} where type is 'regular', 'svg', or 'compressed' (for cases where file type can't be derived from the file name).", + "usedIn": [ + "Element" + ], + "docRef": [ + "essentials/displaying_images.md" + ], + "noValidateReason": "The string scalar form is documented in displaying_images.md. The object form {src, type} was added in v1.44.0 (changelog confirmed) and is implemented in element.js, but is not yet reflected in the markdown docs. Both forms are fully validated \u2014 this field is retained for transparency.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a non-empty image path or URL." + }, + "object": { + "src": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "'src' object must have a non-empty 'src' property." + }, + "type": { + "type": "enum", + "values": [ + "regular", + "svg", + "compressed" + ] + } + } + }, + "possibleValues": [ + "assets/logo.png", + "https://example.com/img.jpg", + "assets/icon.svg", + "{src: 'assets/icon.svg', type: 'svg'}", + "{src: 'img.compressed', type: 'compressed'}" + ], + "invalidValues": [ + { + "value": "", + "reason": "empty string is not a valid src" + }, + { + "value": "{type: 'png'}", + "reason": "type must be 'regular', 'svg', or 'compressed'" + } + ] + }, + "fit": { + "attrType": "regular", + "types": [ + "enum", + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cover", + "contain" + ] + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + } + } + ], + "values": [ + "cover", + "contain" + ], + "defaultValue": null, + "reactive": true, + "description": "Controls how an image is resized to fit the Element's dimensions. Accepts 'cover' or 'contain', or an object {type, position} where position is either a number 0\u20131 (applies to both axes) or {x?, y?} with values 0\u20131 to control the clip anchor point independently.", + "usedIn": [ + "Element" + ], + "docRef": [], + "noValidateReason": "Added in v1.4.0 (changelog confirmed), implemented in element.js, heavily used in the example app (Resize.js). Not yet in the markdown docs. The scalar enum form is strictly validated. The object form's 'position' key accepts either a plain number (sets both axes) or {x?, y?} \u2014 a nested shape that cannot be expressed in the current flat descriptor schema, so a permissive regex is used for position.", + "validate": { + "scalar": { + "type": "enum", + "values": [ + "cover", + "contain" + ] + }, + "object": { + "type": { + "type": "enum", + "values": [ + "cover", + "contain" + ] + }, + "position": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a position object with optional x and/or y keys (0\u20131), e.g. {x: 0.5} or {y: 1}." + } + } + }, + "possibleValues": [ + "cover", + "contain", + "{type: 'cover', position: {y: 0}}", + "{type: 'cover', position: {x: 0.5}}", + "{type: 'cover', position: {y: 0.5, x: 0.5}}", + "{type: 'contain', position: {x: 0}}", + "{type: 'cover', position: 0.5}" + ], + "invalidValues": [ + { + "value": "fill", + "reason": "not a valid fit value" + }, + { + "value": "stretch", + "reason": "not a valid fit value" + }, + { + "value": "none", + "reason": "not a valid fit value" + } + ] + }, + "rtt": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "false", + "reactive": true, + "description": "Enables render-to-texture mode, rendering the element and its children to an off-screen texture.", + "usedIn": [ + "Element" + ], + "docRef": [], + "noValidateReason": "Added in v0.9.9 (changelog confirmed), implemented in element.js. Not yet in the markdown docs. The source setter checks strict boolean equality (v === true), so this attribute is primarily intended for reactive bindings (:rtt=\"$bool\"). The 'true'/'false' string enum covers the static template use case.", + "validate": { + "scalar": { + "type": "enum", + "values": [ + "true", + "false" + ] + } + }, + "possibleValues": [ + "true", + "false" + ], + "invalidValues": [ + { + "value": "yes", + "reason": "only 'true' or 'false' accepted" + }, + { + "value": "1", + "reason": "numeric string not accepted" + } + ] + }, + "border": { + "attrType": "regular", + "types": [ + "number", + "object" + ], + "defaultValue": "undefined", + "reactive": true, + "description": "Apply an inner border to an Element. Accepts a width number or an object with keys: w, top, right, bottom, left, color.", + "usedIn": [ + "Element", + "Layout" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "numeric" + }, + "object": { + "w": { + "type": "numeric" + }, + "top": { + "type": "numeric" + }, + "right": { + "type": "numeric" + }, + "bottom": { + "type": "numeric" + }, + "left": { + "type": "numeric" + }, + "color": {} + } + }, + "possibleValues": [ + "20", + "{w: 4, color: '#fff'}", + "{top: 2, bottom: 2, color: '#60a5fa'}" + ], + "invalidValues": [ + { + "value": "solid", + "reason": "Must be a number or object, not a bare string." + } + ] + }, + "rounded": { + "attrType": "regular", + "types": [ + "number", + "array", + "object" + ], + "defaultValue": "undefined", + "reactive": true, + "description": "Round the corners of an Element. Accepts a single radius number, an array of four corner radii [top-left, top-right, bottom-right, bottom-left], or a per-corner object.", + "usedIn": [ + "Element", + "Layout" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": [ + { + "type": "numeric" + }, + { + "type": "regex", + "pattern": "^\\[\\s*\\d+(?:\\.\\d+)?(?:\\s*,\\s*\\d+(?:\\.\\d+)?)*\\s*\\]$", + "message": "'rounded' must be a number, an array of numbers (e.g. [10,10,0,0]), or an object with corner keys." + } + ], + "object": { + "radius": { + "type": "numeric" + }, + "top-left": { + "type": "numeric" + }, + "top-right": { + "type": "numeric" + }, + "bottom-right": { + "type": "numeric" + }, + "bottom-left": { + "type": "numeric" + } + } + }, + "possibleValues": [ + "10", + "[10, 10, 0, 0]", + "{radius: 10}", + "{top-left: 10, top-right: 10, bottom-right: 0, bottom-left: 0}" + ], + "invalidValues": [ + { + "value": "round", + "reason": "Must be a number, array, or object — not a bare string." + } + ] + }, + "shadow": { + "attrType": "regular", + "types": [ + "object" + ], + "defaultValue": "undefined", + "reactive": true, + "description": "Apply a box shadow behind an Element. Accepts an object with keys: x, y, blur, spread, color.", + "usedIn": [ + "Element", + "Layout" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "object": { + "x": { + "type": "numeric" + }, + "y": { + "type": "numeric" + }, + "blur": { + "type": "numeric" + }, + "spread": { + "type": "numeric" + }, + "color": {} + } + }, + "possibleValues": [ + "{x: 2, y: 2, blur: 8, color: '#000'}", + "{x: 0, y: 4, blur: 12, spread: 2, color: 'rgba(0,0,0,0.5)'}" + ], + "invalidValues": [] + }, + "shader": { + "attrType": "regular", + "types": [ + "string", + "object" + ], + "defaultValue": null, + "reactive": true, + "description": "Apply a custom shader to an Element. Accepts a shader name string or an object with type and props. Mutually exclusive with rounded, border, and shadow.", + "usedIn": [ + "Element", + "Layout" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "noValidateReason": "Shader names and props are open-ended \u2014 cannot be statically validated.", + "validate": {}, + "possibleValues": [ + "'RoundedRectangle'", + "{type: 'holePunch', x: 100, y: 200, width: 100, height: 100}" + ], + "invalidValues": [] + }, + "placement": { + "attrType": "regular", + "types": [ + "enum", + { + "type": "object", + "properties": { + "x": { + "type": "string", + "enum": [ + "left", + "center", + "right" + ] + }, + "y": { + "type": "string", + "enum": [ + "top", + "middle", + "bottom" + ] + } + } + } + ], + "values": [ + "left", + "center", + "right", + "top", + "middle", + "bottom" + ], + "defaultValue": null, + "reactive": true, + "description": "Predefined placement relative to the parent's dimensions. Accepts 'left', 'center', 'right', 'top', 'middle', 'bottom', or an object {x, y} for combined placement.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "left", + "center", + "right", + "top", + "middle", + "bottom" + ] + }, + "object": { + "x": { + "type": "enum", + "values": [ + "left", + "center", + "right" + ] + }, + "y": { + "type": "enum", + "values": [ + "top", + "middle", + "bottom" + ] + } + } + }, + "possibleValues": [ + "left", + "center", + "right", + "top", + "middle", + "bottom", + "{x: 'center', y: 'bottom'}", + "{x: 'right', y: 'middle'}" + ], + "invalidValues": [ + { + "value": "absolute", + "reason": "not a valid placement value" + }, + { + "value": "flex", + "reason": "not a valid placement value" + }, + { + "value": "Centre", + "reason": "values are case-sensitive" + }, + { + "value": "start", + "reason": "not a valid placement value" + } + ] + }, + "inspector-data": { + "attrType": "regular", + "types": [ + { + "type": "object" + } + ], + "defaultValue": null, + "reactive": false, + "description": "Attaches custom metadata to elements for debugging and automated testing, visible in the Lightning inspector. Only processed in dev mode when inspector is enabled.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "essentials/element_attributes.md" + ], + "noValidateReason": "Keys and values are user-defined debug metadata with no fixed schema. The object validator below has no property rules \u2014 it documents the object form without constraining its contents.", + "validate": { + "object": {} + }, + "possibleValues": [ + "{testId: 'my-button'}", + "{role: 'navigation', testId: 'nav'}" + ] + }, + "content": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": true, + "description": "The text to be displayed. Can be hardcoded text, a dynamic value, or a reactive value.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "noValidateReason": "Any string is valid by design \u2014 empty string, whitespace, unicode, numbers as text. The permissive regex below documents the scalar form without imposing constraints.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a text string." + } + }, + "possibleValues": [ + "Hello world", + "Welcome", + "" + ] + }, + "font": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": "sans-serif", + "reactive": true, + "description": "The font family to use for text rendering.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "noValidateReason": "Font names are registered at launch time in settings.fonts and are project-specific. The plugin has no knowledge of which fonts a given app has registered. The regex below only enforces non-empty; it cannot validate against the actual registered font list.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a non-empty font family name." + } + }, + "possibleValues": [ + "sans-serif", + "lato", + "raleway", + "ComicSans" + ] + }, + "size": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 32, + "reactive": true, + "description": "The font size of a Text element in pixels.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "positive" + } + }, + "possibleValues": [ + "12", + "16", + "32", + "48", + "64" + ], + "invalidValues": [ + { + "value": "0", + "reason": "zero makes text invisible; must be greater than 0" + }, + { + "value": "-12", + "reason": "negative font size not accepted" + }, + { + "value": "large", + "reason": "non-numeric string" + }, + { + "value": "1em", + "reason": "em units not accepted" + } + ] + }, + "letterspacing": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "Letter spacing in pixels. Allows any number greater than or equal to zero.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "numeric" + } + }, + "possibleValues": [ + "0", + "1", + "5", + "10", + "0.5" + ], + "invalidValues": [ + { + "value": "tight", + "reason": "non-numeric string" + }, + { + "value": "normal", + "reason": "non-numeric string" + } + ] + }, + "align": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "left", + "right", + "center" + ], + "defaultValue": null, + "reactive": true, + "description": "The alignment of the text. Centering and right alignment require maxwidth to be set.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "left", + "right", + "center" + ] + } + }, + "possibleValues": [ + "left", + "right", + "center" + ], + "invalidValues": [ + { + "value": "justify", + "reason": "not a valid align value" + }, + { + "value": "start", + "reason": "not a valid align value" + }, + { + "value": "end", + "reason": "not a valid align value" + }, + { + "value": "Centre", + "reason": "values are case-sensitive" + } + ] + }, + "maxwidth": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "The maximum length of a line of text in pixels. Words surpassing this length will be wrapped onto the next line.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "nonNegative", + "integer": true + } + }, + "possibleValues": [ + "0", + "400", + "800", + "1920" + ], + "invalidValues": [ + { + "value": "-100", + "reason": "negative value not accepted" + }, + { + "value": "100%", + "reason": "percentage not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + } + ] + }, + "maxlines": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "Maximum number of lines that will be displayed.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "nonNegative", + "integer": true + } + }, + "possibleValues": [ + "0", + "1", + "3", + "10" + ], + "invalidValues": [ + { + "value": "-1", + "reason": "negative value not accepted" + }, + { + "value": "1.5", + "reason": "line count must be a whole number" + }, + { + "value": "unlimited", + "reason": "non-numeric string" + } + ] + }, + "maxheight": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "Maximum height of a text block in pixels. Lines exceeding this height will not be displayed.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "nonNegative", + "integer": true + } + }, + "possibleValues": [ + "0", + "100", + "400", + "1080" + ], + "invalidValues": [ + { + "value": "-100", + "reason": "negative value not accepted" + }, + { + "value": "auto", + "reason": "non-numeric string" + } + ] + }, + "lineheight": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": null, + "reactive": true, + "description": "The spacing between lines in pixels.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "nonNegative" + } + }, + "possibleValues": [ + "0", + "20", + "40", + "1.5" + ], + "invalidValues": [ + { + "value": "-5", + "reason": "negative line height not accepted" + }, + { + "value": "normal", + "reason": "non-numeric string" + }, + { + "value": "1.5em", + "reason": "em units not accepted" + } + ] + }, + "contain": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "none", + "width", + "both", + "height" + ], + "defaultValue": "none", + "reactive": true, + "description": "The strategy for containing text within bounds. Usually set automatically by Blits based on other specified attributes. In v2, \"height\" is also valid (auto-applied when maxheight is set).", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "none", + "width", + "both", + "height" + ] + } + }, + "possibleValues": [ + "none", + "width", + "both", + "height" + ], + "invalidValues": [ + { + "value": "all", + "reason": "not a valid contain value" + }, + { + "value": "auto", + "reason": "not a valid contain value" + } + ] + }, + "textoverflow": { + "attrType": "regular", + "types": [ + "string", + "enum" + ], + "values": [ + "false" + ], + "defaultValue": "...", + "reactive": true, + "description": "The suffix added when text is cropped due to bounds limits. Defaults to '...'. Set to false or empty string for no suffix.", + "usedIn": [ + "Text" + ], + "docRef": [ + "essentials/displaying_text.md" + ], + "noValidateReason": "Any string suffix is valid by design \u2014 there is no wrong suffix value. The special value 'false' disables the suffix entirely. Even empty string is valid. The permissive regex below documents the scalar form without constraining it.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a string suffix or 'false' to disable." + } + }, + "possibleValues": [ + "...", + "false", + " read more", + "" + ] + }, + "direction": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "horizontal", + "vertical" + ], + "defaultValue": "horizontal", + "reactive": true, + "description": "Controls the direction of layout content arrangement.", + "usedIn": [ + "Layout" + ], + "docRef": [ + "built-in/layout.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "horizontal", + "vertical" + ] + } + }, + "possibleValues": [ + "horizontal", + "vertical" + ], + "invalidValues": [ + { + "value": "row", + "reason": "CSS flexbox value not accepted; use 'horizontal'" + }, + { + "value": "column", + "reason": "CSS flexbox value not accepted; use 'vertical'" + }, + { + "value": "ltr", + "reason": "not a valid direction value" + } + ] + }, + "gap": { + "attrType": "regular", + "types": [ + "number" + ], + "defaultValue": 0, + "reactive": true, + "description": "Controls how much space in pixels is added between each child Element or Component in a Layout.", + "usedIn": [ + "Layout" + ], + "docRef": [ + "built-in/layout.md" + ], + "validate": { + "scalar": { + "type": "nonNegative" + } + }, + "possibleValues": [ + "0", + "10", + "20", + "50" + ], + "invalidValues": [ + { + "value": "-10", + "reason": "negative gap not accepted" + }, + { + "value": "medium", + "reason": "non-numeric string" + }, + { + "value": "10px", + "reason": "px suffix not accepted" + } + ] + }, + "align-items": { + "attrType": "regular", + "types": [ + "enum" + ], + "values": [ + "start", + "center", + "end" + ], + "defaultValue": "start", + "reactive": true, + "description": "Specifies how to align children on the opposite axis of the Layout direction.", + "usedIn": [ + "Layout" + ], + "docRef": [ + "built-in/layout.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "start", + "center", + "end" + ] + } + }, + "possibleValues": [ + "start", + "center", + "end" + ], + "invalidValues": [ + { + "value": "flex-start", + "reason": "CSS flexbox value not accepted; use 'start'" + }, + { + "value": "flex-end", + "reason": "CSS flexbox value not accepted; use 'end'" + }, + { + "value": "stretch", + "reason": "not a valid align-items value" + }, + { + "value": "baseline", + "reason": "not a valid align-items value" + } + ] + }, + "padding": { + "attrType": "regular", + "types": [ + "number", + { + "type": "object", + "properties": { + "top": { + "type": "number" + }, + "bottom": { + "type": "number" + }, + "left": { + "type": "number" + }, + "right": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + } + } + ], + "defaultValue": 0, + "reactive": true, + "description": "Adds spacing between the content and the edges of the Layout. Accepts a number for uniform padding or an object with top/bottom/left/right/x/y keys.", + "usedIn": [ + "Layout" + ], + "docRef": [ + "built-in/layout.md" + ], + "validate": { + "scalar": { + "type": "nonNegative" + }, + "object": { + "top": { + "type": "nonNegative" + }, + "bottom": { + "type": "nonNegative" + }, + "left": { + "type": "nonNegative" + }, + "right": { + "type": "nonNegative" + }, + "x": { + "type": "nonNegative" + }, + "y": { + "type": "nonNegative" + } + } + }, + "possibleValues": [ + "0", + "10", + "20", + "{top: 10, bottom: 20}", + "{x: 20, top: 30, bottom: 10}", + "{left: 5, right: 5}" + ], + "invalidValues": [ + { + "value": "-5", + "reason": "negative padding not accepted" + }, + { + "value": "medium", + "reason": "non-numeric string" + }, + { + "value": "10px", + "reason": "px suffix not accepted" + } + ] + }, + "is": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "Dynamically instantiates a Component based on a state variable or prop value.", + "usedIn": [ + "Component" + ], + "docRef": [ + "built-in/directives.md" + ], + "noValidateReason": "The referenced component is resolved at runtime from state or props. Which components are valid depends on what the app has imported and registered \u2014 a cross-file concern not resolvable in a per-file rule. The permissive regex below documents the scalar form.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a component reference (e.g., $myComponent)." + } + }, + "possibleValues": [ + "$myComponent", + "$activeView" + ] + }, + "ref": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "A reference identifier for the Element or Component, accessible via this.select() in the component logic.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "built-in/directives.md", + "built-in/for-loop.md" + ], + "noValidateReason": "Any non-empty identifier is valid. Cross-referencing via this.$select() is a runtime concern \u2014 the plugin cannot know what refs are used downstream. The regex below enforces non-empty only.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a non-empty ref identifier." + } + }, + "possibleValues": [ + "myButton", + "heroImage", + "titleText" + ] + }, + "for": { + "attrType": "directive", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": true, + "description": "Directive for repeating multiple instances of an Element or Component. Uses 'item in $array' or '(item, index) in $array' syntax.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "built-in/for-loop.md" + ], + "validate": { + "scalar": { + "type": "regex", + "pattern": "^(\\(\\s*\\w+\\s*,\\s*\\w+\\s*\\)|\\w+)\\s+in\\s+\\$\\w+", + "message": "':for' value must follow 'item in $array' or '(item, index) in $array' syntax." + } + }, + "possibleValues": [ + "item in $list", + "(item, index) in $items" + ], + "invalidValues": [ + { + "value": "item of $list", + "reason": "'of' is not valid; use 'in'" + }, + { + "value": "$list", + "reason": "missing 'item in' prefix" + }, + { + "value": "item in list", + "reason": "array variable must be prefixed with $" + } + ] + }, + "$shallow": { + "attrType": "directive", + "types": [ + "string" + ], + "defaultValue": "true", + "reactive": false, + "description": "Performance modifier for ':for' loops. Controls whether child components in the loop have access to the outer scope. When omitted or 'true', the loop is shallow (faster — each item only sees its own scope). Set to 'false' to allow items to access outer scope variables.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [], + "validate": { + "scalar": { + "type": "enum", + "values": ["true", "false"] + } + }, + "possibleValues": ["false"], + "invalidValues": [] + }, + "key": { + "attrType": "regular", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "A unique identifier for items in a for-loop, enabling efficient reuse of Element/Component instances when the array changes. Should reference a unique field (e.g., key=\"$item.id\").", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "built-in/for-loop.md" + ], + "noValidateReason": "Valid expressions depend on the shape of the iterated array items \u2014 a runtime data concern. The plugin cannot validate the key expression against the actual item type without cross-referencing state. The permissive regex below documents the scalar form.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a unique identifier expression (e.g., $item.id)." + } + }, + "possibleValues": [ + "$item.id", + "$item.name", + "$item.hash" + ] + }, + "range": { + "attrType": "regular", + "types": [ + { + "type": "object", + "properties": { + "from": { + "type": "number" + }, + "to": { + "type": "number" + } + } + } + ], + "defaultValue": null, + "reactive": true, + "description": "Limits a for-loop to render only a subset of items. Accepts an object {from, to} where 'from' is inclusive and 'to' is exclusive. Items outside the range are destroyed and recreated when they re-enter.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "built-in/for-loop.md" + ], + "validate": { + "object": { + "from": { + "type": "numeric", + "integer": true + }, + "to": { + "type": "numeric", + "integer": true + } + } + }, + "possibleValues": [ + "{from: 0, to: 10}", + "{from: 5, to: 20}" + ], + "invalidValues": [ + { + "value": "{from: 1.5, to: 10}", + "reason": "'from' must be an integer" + }, + { + "value": "{from: 0, to: 1.5}", + "reason": "'to' must be an integer" + } + ] + }, + "show": { + "attrType": "directive", + "types": [ + "enum" + ], + "values": [ + "true", + "false" + ], + "defaultValue": "true", + "reactive": true, + "description": "Conditionally shows or hides the Element/Component by setting alpha to 0 or restoring it.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [ + "built-in/directives.md" + ], + "validate": { + "scalar": { + "type": "enum", + "values": [ + "true", + "false" + ] + } + }, + "possibleValues": [ + "true", + "false" + ], + "invalidValues": [ + { + "value": "yes", + "reason": "only 'true' or 'false' accepted" + }, + { + "value": "1", + "reason": "numeric string not accepted" + }, + { + "value": "hidden", + "reason": "not a valid show value" + }, + { + "value": "visible", + "reason": "not a valid show value" + } + ] + }, + "slot": { + "attrType": "directive", + "types": [ + "string" + ], + "defaultValue": null, + "reactive": false, + "description": "Routes an Element or Component to a named slot in the parent component. The value must match the `ref` attribute of the target `` definition in the parent's template.", + "usedIn": [ + "Element", + "Text", + "Layout", + "RouterView", + "Component" + ], + "docRef": [], + "noValidateReason": "The slot attribute accepts any non-empty string that matches the ref attribute of a definition in the parent component. The plugin cannot statically verify that the named slot exists in the parent \u2014 that is a runtime concern.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]+$", + "message": "Expected a non-empty slot name matching a definition in the parent component." + } + }, + "possibleValues": [ + "first", + "second", + "header", + "footer", + "content" + ] + }, + "@loaded": { + "attrType": "event", + "types": [ + "string", + "function" + ], + "defaultValue": null, + "reactive": false, + "description": "Fires when an image or text element loads, providing its dimensions ({w, h}). Accepts a function reference (e.g., $handlerName) or an inline arrow function.", + "usedIn": [ + "Element", + "Text" + ], + "docRef": [ + "essentials/displaying_images.md", + "essentials/displaying_text.md" + ], + "noValidateReason": "Accepts a function reference ($handlerName) or inline arrow function. Whether the referenced method exists is a component-logic concern, not an attribute-value concern. The permissive regex documents the scalar form.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a function reference (e.g., $handlerName) or inline arrow function." + } + }, + "possibleValues": [ + "$onLoaded", + "$handleImageLoad" + ] + }, + "@error": { + "attrType": "event", + "types": [ + "string", + "function" + ], + "defaultValue": null, + "reactive": false, + "description": "Fires when an image fails to load, passing an error message. Accepts a function reference (e.g., $handlerName) or an inline arrow function.", + "usedIn": [ + "Element", + "Text" + ], + "docRef": [ + "essentials/displaying_images.md" + ], + "noValidateReason": "Accepts a function reference ($handlerName) or inline arrow function. Whether the referenced method exists is a component-logic concern, not an attribute-value concern. The permissive regex documents the scalar form.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a function reference (e.g., $handlerName) or inline arrow function." + } + }, + "possibleValues": [ + "$onError", + "$handleImageError" + ] + }, + "@updated": { + "attrType": "event", + "types": [ + "string", + "function" + ], + "defaultValue": null, + "reactive": false, + "description": "Fires after each Layout children update, providing current dimensions ({w, h}). Can fire multiple times.", + "usedIn": [ + "Layout" + ], + "docRef": [ + "built-in/layout.md" + ], + "noValidateReason": "Accepts a function reference ($handlerName) or inline arrow function. Whether the referenced method exists is a component-logic concern, not an attribute-value concern. The permissive regex documents the scalar form.", + "validate": { + "scalar": { + "type": "regex", + "pattern": "^[\\s\\S]*$", + "message": "Expected a function reference (e.g., $handlerName) or inline arrow function." + } + }, + "possibleValues": [ + "$onLayoutUpdate", + "$handleUpdate" + ] + } +} diff --git a/eslint-plugin-blits/docs/attributes/$shallow.md b/eslint-plugin-blits/docs/attributes/$shallow.md new file mode 100644 index 0000000..e58d7c7 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/$shallow.md @@ -0,0 +1,62 @@ +# $shallow + +Performance modifier for `:for` loops. Controls whether child components in the loop have access to outer scope variables. + +**Directive** · Static only + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | +| `` | | +| `` | Any user-defined PascalCase component | + +Must be used on an element that also has a `:for` attribute. + +--- + +## Accepted values + +| Value | Behaviour | +|---|---| +| omitted | Shallow mode — default, fastest | +| `"true"` | Explicit shallow mode — same as omitting | +| `"false"` | Deep mode — outer scope variables accessible inside the loop | + +--- + +## How it works + +By default, each item rendered inside a `:for` loop only has access to its own scope (the loop item and index). This is the **shallow** mode and is the most performant option. + +Setting `$shallow="false"` switches to **deep** mode: the loop merges the outer component scope into each item's scope using `Object.assign`. This allows expressions inside the loop to reference state, props, or computed values from the parent component directly. + +Only use `$shallow="false"` when you genuinely need outer scope access inside the loop. The performance cost comes from the extra `Object.assign` call on every render cycle of the list. + +--- + +## Examples + +```blits + + + + + + + + +``` + +--- + +## Reference + +*`$shallow` is an internal Blits directive with no public documentation page. It was introduced in Blits v1.3.0 (August 2024). The only external reference is the changelog entry: "Added `$shallow`-modifier to for-loop".* + +*Source: `blits/src/lib/codegenerator/generator.js`* diff --git a/eslint-plugin-blits/docs/attributes/align-items.md b/eslint-plugin-blits/docs/attributes/align-items.md new file mode 100644 index 0000000..4eff72d --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/align-items.md @@ -0,0 +1,60 @@ +# align-items + +Specifies how to align children on the opposite axis of the Layout direction. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**Enum:** `start`, `center`, `end` + +--- + +## Examples + +```blits + + + + + + + + + + + +``` + +--- + +## What is not validated + +Reactive bindings are not validated by the enum rule: + +```blits + + +``` + +--- + +## Reference + +**Blits docs — [Layout - Aligning items](https://lightning-js.github.io/blits/#/built-in/layout)** + +> "The layout component positions its children based on the provided direction (`horizontal` or `vertical`). With the `align-items`-attribute, you can specify how to align the children on the opposite axis: +> +> - `start` (the default value) - aligns the children at the _top_ for horizontal layouts and on the _left_ for vertical layouts +> - `center` - align the children in the center +> - `end` - aligns the children in the _bottom_ for horizontal layouts, and on the _right_ for vertical layouts" diff --git a/eslint-plugin-blits/docs/attributes/align.md b/eslint-plugin-blits/docs/attributes/align.md new file mode 100644 index 0000000..ee5e57f --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/align.md @@ -0,0 +1,58 @@ +# align + +The alignment of the text. Centering and right alignment require `maxwidth` to be set. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**Enum:** `left`, `right`, `center` + +--- + +## Examples + +```blits + + + + + + + +``` + +--- + +## Note on maxwidth + +When aligning text to the `center` or `right`, the `maxwidth` attribute must also be specified so the renderer knows the boundaries of the text box to align within. This constraint is enforced by the `text-align-requires-maxwidth` rule. + +--- + +## What is not validated + +Reactive bindings are not validated by the enum rule: + +```blits + + +``` + +--- + +## Reference + +**Blits docs — [Displaying Text](https://lightning-js.github.io/blits/#/essentials/displaying_text)** + +> "`align` - the alignment of the text, can be `left`, `right`, or `center`, defaults to `left`. Centering text and aligning text to the right requires the `maxwidth` attribute to be set as well." diff --git a/eslint-plugin-blits/docs/attributes/alpha.md b/eslint-plugin-blits/docs/attributes/alpha.md new file mode 100644 index 0000000..e9552b5 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/alpha.md @@ -0,0 +1,81 @@ +# alpha + +Controls the opacity of the element and all its children. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | +| `` | | +| `` | Any user-defined PascalCase component | + +--- + +## Accepted values + +A number between `0` and `1` (inclusive). + +| Value | Effect | +|---|---| +| `0` | Fully transparent | +| `0.5` | 50% opacity | +| `1` | Fully opaque (default) | + +**Default:** `1` + +--- + +## Examples + +```xml + + + + + + + + + + + + + + +``` + +--- + +## Important: alpha applies recursively + +Setting `alpha` on an element applies to all its children. In this example the inner red element effectively renders at `0.8 × 0.3 = 0.24` opacity: + +```xml + + + +``` + +To make only a background semi-transparent without affecting children, set the alpha channel in `color` instead of using the `alpha` attribute. + +--- + +## What is not validated + +- **Reactive bindings** (`:alpha="$opacity"`) — value is resolved at runtime, not checked +- **Dollar-prefixed values** (`alpha="$var"`) — treated as a variable reference, not checked + +--- + +## Reference + +**Blits docs — [Element attributes — Alpha and visibility](https://lightning-js.github.io/blits/#/essentials/element_attributes)** + +> "The opacity of an Element can be controlled by setting the `alpha` attribute. This attribute accepts a value between `0` (fully transparent) and `1` (completely visible). The value of alpha is also applied recursively to the children of the Element that has its alpha set. If you just want the background color of an Element to be semi-transparent, you should set the alpha channel in the `color` instead of applying the `alpha` attribute." diff --git a/eslint-plugin-blits/docs/attributes/border.md b/eslint-plugin-blits/docs/attributes/border.md new file mode 100644 index 0000000..fddf18a --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/border.md @@ -0,0 +1,68 @@ +# border + +Apply an inner border to an Element. + +**Attribute** · Reactive · **Blits version:** v2+ + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +A number (border width applied to all sides) or an object: + +| Key | Type | Description | +|---|---|---| +| `w` | number | Width applied to all sides | +| `top` | number | Top border width | +| `right` | number | Right border width | +| `bottom` | number | Bottom border width | +| `left` | number | Left border width | +| `color` | color string | Border color | + +--- + +## Examples + +```xml + + + + + + + + + + + +``` + +--- + +## Note on shader conflict + +`border` uses the built-in shader system internally. It cannot be combined with the `shader` +attribute on the same element — using both simultaneously is unsupported. + +It can be combined with `rounded` and `shadow`. + +--- + +## What is not validated + +- **Reactive bindings** (`:border="$config"`) — value is resolved at runtime +- **`color` key** — accepts any value; color format is not validated + +--- + +## Reference + +**Blits docs — [Element attributes — Shaders](https://lightning-js.github.io/blits/#/essentials/element_attributes)** diff --git a/eslint-plugin-blits/docs/attributes/clipping.md b/eslint-plugin-blits/docs/attributes/clipping.md new file mode 100644 index 0000000..da1b765 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/clipping.md @@ -0,0 +1,54 @@ +# clipping + +Clips child content to the element's width and height boundaries. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | + +--- + +## Accepted values + +**Enum:** `true`, `false` + +--- + +## Examples + +```blits + + + + + + + +``` + +--- + +## What is not validated + +Reactive bindings are not validated by the rule: + +```blits + + +``` + +--- + +## Reference + +**Blits docs — [Element attributes - Clipping / overflow](https://lightning-js.github.io/blits/#/essentials/element_attributes)** + +> "In order to contain / cut off the content inside an Element's `w` and `h`, you can add the `clipping=\"true\"`-attribute. Setting `clipping` to `false` restores the default behaviour of content overflowing." diff --git a/eslint-plugin-blits/docs/attributes/color.md b/eslint-plugin-blits/docs/attributes/color.md new file mode 100644 index 0000000..489b223 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/color.md @@ -0,0 +1,64 @@ +# color + +The color of the Element. Accepts hexadecimal, hex with alpha, hex shorthands, RGB, RGBA, HTML color names, or an object with `top`/`bottom`/`left`/`right` keys for linear gradients. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | +| `` | | + +--- + +## Accepted values + +- **hexadecimal** (e.g. `#ff4433`) +- **hexadecimal with alpha channel** (e.g. `#55553380`) +- **hexadecimal shorthands** (e.g. `#333`) +- **rgb** (e.g. `rgb(180, 30, 50)`) +- **rgba** (e.g. `rgba(40, 30, 180, 0.5)`) +- **html color names** (e.g. `red`, `blue`, `skyblue`, `tomato`) +- **object literal** for linear gradients with `top`, `bottom`, `left`, `right` keys (e.g. `{top: 'red', bottom: 'blue'}`) + +--- + +## Examples + +```blits + + + + + + + + + + + +``` + +--- + +## What is not validated + +Color values are too varied to enumerate reliably (~140 named colors, hex, rgb, rgba). The schema regex checks structural shape only; specific color correctness is left to the runtime. + +--- + +## Reference + +**Blits docs — [Element attributes - Colors](https://lightning-js.github.io/blits/#/essentials/element_attributes)** + +> "By default, Elements have a transparent background color. The `color` attribute can be used to give an Element a color. In Blits, you can specify colors as you are used to in HTML and CSS." + +**Blits docs — [Element attributes - Basic linear gradients](https://lightning-js.github.io/blits/#/essentials/element_attributes)** + +> "The color attribute can also be used to specify basic linear gradients. A linear gradient can be defined by specifying an _object literal_ as the `color` attribute instead of a single color." diff --git a/eslint-plugin-blits/docs/attributes/contain.md b/eslint-plugin-blits/docs/attributes/contain.md new file mode 100644 index 0000000..2408dee --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/contain.md @@ -0,0 +1,59 @@ +# contain + +The strategy for containing text within bounds. Usually set automatically by Blits based on other specified attributes. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**Enum:** `none`, `width`, `both` + +> **Blits v2:** The `height` value is also accepted in Blits v2 — `none`, `width`, `both`, `height`. + +--- + +## Examples + +```blits + + + + + + +``` + +--- + +## Note on maxwidth + +Setting `contain='width'` without providing a `maxwidth` is a common mistake that prevents the text from actually being contained. + +--- + +## What is not validated + +Reactive bindings are not validated by the enum rule: + +```blits + + +``` + +--- + +## Reference + +**Blits docs — [Displaying Text](https://lightning-js.github.io/blits/#/essentials/displaying_text)** + +> "`contain` - the strategy for containing text within the bounds, can be `none` (default), `width`, or `both`. In most cases, the value of this attribute will automatically be set by Blits, based on the other specified attributes" diff --git a/eslint-plugin-blits/docs/attributes/content.md b/eslint-plugin-blits/docs/attributes/content.md new file mode 100644 index 0000000..514640c --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/content.md @@ -0,0 +1,47 @@ +# content + +The text to be displayed. Can be hardcoded text, a dynamic value, or a reactive value. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**String**, empty string, whitespace, unicode, or numbers as text. + +--- + +## Examples + +```blits + + + + + + + +``` + +--- + +## What is not validated + +Any string is valid. The schema only checks that the attribute is a non-empty string. + +--- + +## Reference + +**Blits docs — [Displaying Text](https://lightning-js.github.io/blits/#/essentials/displaying_text)** + +> "`content` - the text to be displayed. Can be a hardcoded text, a dynamic value, or a reactive value" diff --git a/eslint-plugin-blits/docs/attributes/direction.md b/eslint-plugin-blits/docs/attributes/direction.md new file mode 100644 index 0000000..d3a7711 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/direction.md @@ -0,0 +1,58 @@ +# direction + +Controls the direction of layout content arrangement. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**Enum:** `horizontal`, `vertical` + +--- + +## Examples + +```blits + + + + + + + + + + + +``` + +--- + +## What is not validated + +Reactive bindings are not validated by the enum rule: + +```blits + + +``` + +--- + +## Reference + +**Blits docs — [Layout - Horizontal and vertical layout](https://lightning-js.github.io/blits/#/built-in/layout)** + +> "By default, the Layout component lays out its contents _horizontally_. The Layout component accepts a `direction` attribute that allows you to control the direction. +> +> In order to align vertically, use ``. And use `` to explicitly apply the default horizontal layout." diff --git a/eslint-plugin-blits/docs/attributes/effects.md b/eslint-plugin-blits/docs/attributes/effects.md new file mode 100644 index 0000000..c605a57 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/effects.md @@ -0,0 +1,52 @@ +# effects + +Applies one or more shader effects using the `DynamicShader`. Accepts an array of objects, each with a type and optional props. + +**Attribute** · Reactive · **Blits version:** v1 only + +> **Removed in Blits v2.** The `effects` attribute is not available in Blits v2. Use the `shader`, `border`, `rounded`, or `shadow` attributes instead. + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**Array literal** containing objects. Each object must define at minimum a `type` string (e.g. `'radius'`, `'border'`), and may optionally include a `props` object. + +--- + +## Examples + +```blits + + + + + + + + + + + + +``` + +--- + +## What is not validated + +The schema only enforces that the attribute contains an array-like structure. Shader types (`radius`, `border`, `radialGradient`, etc.) and their `props` are open-ended, so specific contents are not validated. Reactive bindings are not statically validated. + +--- + +## Reference + +*The `effects` attribute (leveraging the `DynamicShader` functionality in the renderer) is currently lightly documented in the official Blits framework documentation but is heavily used throughout the Blits example App and UI components for rounded corners, borders, and gradients.* diff --git a/eslint-plugin-blits/docs/attributes/event-error.md b/eslint-plugin-blits/docs/attributes/event-error.md new file mode 100644 index 0000000..b9fe292 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/event-error.md @@ -0,0 +1,58 @@ +# @error + +Fires when an image fails to load, passing an error message explaining the failure. + +**Event** · Static + +--- + +## Used in + +| Tag | | +|---|---| +| `` | When combined with a `src` attribute | + +--- + +## Accepted values + +- **string** (a reference to a component method, e.g. `"$handlerName"`) +- **inline arrow function** (e.g. `"(err) => $handlerName(err)"`) + +--- + +## Examples + +```blits + + + + + +``` + +```javascript +// Component methods +methods: { + showFallback(error) { + this.$log.error('Image failed to load', error) + this.showBackupImage() + } +} +``` + +--- + +## What is not validated + +Event attributes (prefixed with `@`) expect function references or inline arrow functions. This attribute is not currently validated by the `valid-attribute-value` rule because verifying the existence of the referenced method requires cross-component or script-block analysis, and inline arrow functions are arbitrary JavaScript expressions. + +--- + +## Reference + +**Blits docs — [Displaying Images - Asynchronous Loading](https://lightning-js.github.io/blits/#/essentials/displaying_images)** + +> "Blits allows you to easily hook into the `loaded` and `error` events of image Elements. You can use this, for example, to only make something visible once an image is fully loaded. Or to display a fallback image when a remote image can't be retrieved." +> +> "the `error` event receives an error message explaining the failure." diff --git a/eslint-plugin-blits/docs/attributes/event-loaded.md b/eslint-plugin-blits/docs/attributes/event-loaded.md new file mode 100644 index 0000000..e107b5b --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/event-loaded.md @@ -0,0 +1,70 @@ +# @loaded + +Fires when an image or text element finishes loading and rendering, providing its generated texture dimensions (`{w, h}`). + +**Event** · Static + +--- + +## Used in + +| Tag | | +|---|---| +| `` | When combined with a `src` attribute | +| `` | | + +--- + +## Accepted values + +- **string** (a reference to a component method, e.g. `"$handlerName"`) +- **inline arrow function** (e.g. `"(dimensions) => $handlerName(dimensions)"`) + +--- + +## Examples + +```blits + + + + + + + + +``` + +```javascript +// Component methods +methods: { + handleImageLoaded(dimensions) { + this.$log.info('Image dimensions', dimensions.w, dimensions.h) + this.show = true + }, + handleTextLoaded(dimensions) { + // position an underline matching the exact text width + this.underlineWidth = dimensions.w + } +} +``` + +--- + +## What is not validated + +Event attributes (prefixed with `@`) expect function references or inline arrow functions. This attribute is not currently validated by the `valid-attribute-value` rule because verifying the existence of the referenced method requires cross-component or script-block analysis, and inline arrow functions are arbitrary JavaScript expressions. + +--- + +## Reference + +**Blits docs — [Displaying Images - Asynchronous Loading](https://lightning-js.github.io/blits/#/essentials/displaying_images)** + +> "All images are loaded asynchronously (and can possibly fail to load), even those local to your App. Blits allows you to easily hook into the `loaded` and `error` events of image Elements." +> +> "The `loaded` event receives image dimensions as its argument" + +**Blits docs — [Displaying Text - Text dimensions](https://lightning-js.github.io/blits/#/essentials/displaying_text)** + +> "Similar to the Image element (i.e. an Element with a `src`), Text elements also accept the `@loaded` attribute. This event is called, as soon as the text is rendered, and passes in the dimensions of the generated text texture." diff --git a/eslint-plugin-blits/docs/attributes/event-updated.md b/eslint-plugin-blits/docs/attributes/event-updated.md new file mode 100644 index 0000000..4426d23 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/event-updated.md @@ -0,0 +1,59 @@ +# @updated + +Fires after each Layout children update, providing current dimensions (`{w, h}`). Can fire multiple times. + +**Event** · Static + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +- **string** (a reference to a component method, e.g. `"$handlerName"`) +- **inline arrow function** (e.g. `"(dimensions, el) => $handlerName(dimensions, el)"`) + +--- + +## Examples + +```blits + + + + + + + +``` + +```javascript +// Component methods +methods: { + layoutUpdate(dimensions, el) { + console.log(`Layout (${el.nodeId}) dimensions updated! Width: ${dimensions.w}, Height: ${dimensions.h}`) + } +} +``` + +--- + +## What is not validated + +Event attributes (prefixed with `@`) expect function references or inline arrow functions. This attribute is not currently validated by the `valid-attribute-value` rule because verifying the existence of the referenced method requires cross-component or script-block analysis, and inline arrow functions are arbitrary JavaScript expressions. + +--- + +## Reference + +**Blits docs — [Layout - Updated event](https://lightning-js.github.io/blits/#/built-in/layout)** + +> "The ``-tag automatically updates its dimensions based on the dimensions of its children. After each update in the children, an `updated`-event is emitted on the ``-tag. It will receive the current dimensions of the layout. +> +> You can tap into this event by adding an `@updated`-attribute to the ``-tag and refer to a method in your Component logic." diff --git a/eslint-plugin-blits/docs/attributes/fit.md b/eslint-plugin-blits/docs/attributes/fit.md new file mode 100644 index 0000000..81ed44b --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/fit.md @@ -0,0 +1,53 @@ +# fit + +Controls how an image is resized to fit the Element's dimensions. Accepts 'cover', 'contain', or an object `{type, position}` for fine-grained control over clip position. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +- **enum:** `cover`, `contain` +- **object literal** with `type` (string: `cover`, `contain`), `position` (number 0-1, or object with `x` and `y` keys 0-1) + +--- + +## Examples + +```blits + + + + + + + + + + +``` + +--- + +## What is not validated + +The object form's `position` key accepts either a plain number (sets both axes) or `{x?, y?}`. Because this nested shape cannot be strictly expressed in the flat description schema without rejecting valid cases, a permissive regex is used for `position`, deferring its correctness to runtime. + +Reactive bindings are not validated by the rule. + +--- + +## Reference + +**Blits docs — [Displaying Images](https://lightning-js.github.io/blits/#/essentials/displaying_images)** + +> The `fit` attribute was added in v1.4.0 to control image resizing behavior. diff --git a/eslint-plugin-blits/docs/attributes/font.md b/eslint-plugin-blits/docs/attributes/font.md new file mode 100644 index 0000000..0af612d --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/font.md @@ -0,0 +1,50 @@ +# font + +The font family to use for text rendering. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**String** (name of the registered font). + +--- + +## Examples + +```blits + + + + + + +``` + +--- + +## What is not validated + +Font names are registered at launch time in `settings.fonts` and are project-specific. The plugin has no knowledge of which fonts a given app has registered. The validation regex only enforces that the attribute is a non-empty string; it cannot validate against the actual list of registered fonts. + +--- + +## Reference + +**Blits docs — [Displaying Text](https://lightning-js.github.io/blits/#/essentials/displaying_text)** + +> "`font` - the font family, defaults to `sans-serif`, or the default font specified in the launch settings" + +**Blits docs — [Displaying Text - Using custom fonts](https://lightning-js.github.io/blits/#/essentials/displaying_text)** + +> "The `font`-attribute on the ``-tag is used to define which font family should be used for a certain piece of text. [...] First, you'll need to place a `.ttf`, `.woff` or `.otf` version of your font in the `public` folder [...] Then you'll need to register the custom font in the Launch settings of your app" diff --git a/eslint-plugin-blits/docs/attributes/for.md b/eslint-plugin-blits/docs/attributes/for.md new file mode 100644 index 0000000..ecd61e1 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/for.md @@ -0,0 +1,58 @@ +# for + +Directive for repeating multiple instances of an Element or Component based on an array. Uses `item in $array` or `(item, index) in $array` syntax. + +**Directive** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | +| `` | | +| `` | Any user-defined PascalCase component | + +--- + +## Accepted values + +**String** (the iteration expression). + +--- + +## Examples + +```blits + + + + + + +``` + +--- + +## Note on performance and keys + +When using a for-loop, also provide a `key` attribute. This lets Blits track element identity and update only what changed, rather than tearing down and recreating the whole list. + +--- + +## What is not validated + +The iteration expression (e.g., `item in $items`) is parsed and evaluated by the Blits template compiler. The validation schema regex only enforces that the attribute contains a non-empty string. It does not validate the syntax of the expression itself. + +--- + +## Reference + +**Blits docs — [For loop](https://lightning-js.github.io/blits/#/built-in/for-loop)** + +> "The for loop takes an `Array` of data, loops over it and for each Array-item an Element or Component is created. The `Array` can be a fixed one, but it can also dynamically be filled or modified and have it's changes reflect in the rendered result." +> +> "The for-loop directive should be added as an attribute on the Element or Component that you want to repeat for each item in your Array. In the template syntax a `for ... in` construct is used." diff --git a/eslint-plugin-blits/docs/attributes/gap.md b/eslint-plugin-blits/docs/attributes/gap.md new file mode 100644 index 0000000..d917b03 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/gap.md @@ -0,0 +1,52 @@ +# gap + +Controls how much space in pixels is added between each child Element or Component in a Layout. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | + +--- + +## Accepted values + +**Number** (must be 0 or higher). + +--- + +## Examples + +```blits + + + + + + + + + + + + +``` + +--- + +## What is not validated + +Reactive bindings and dollar-prefixed variables are not validated. + +--- + +## Reference + +**Blits docs — [Layout - Spacing between children](https://lightning-js.github.io/blits/#/built-in/layout)** + +> "By default, the Layout-component places each Element directly besides (or below) the previous one. By adding the `gap`-attribute, you can control how much space will be added between each Element or Component. The `gap`-attribute accepts a number in pixels." diff --git a/eslint-plugin-blits/docs/attributes/h.md b/eslint-plugin-blits/docs/attributes/h.md new file mode 100644 index 0000000..f533379 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/h.md @@ -0,0 +1,62 @@ +# h + +The height of the element in pixels or percentage (e.g., "50%"). Allows decimals. + +*Note: `height` is a valid alias for `h`.* + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | + +--- + +## Accepted values + +**Number** or **string** (can be a raw number or a percentage). + +--- + +## Examples + +```blits + + + + + + + + + + + + + + + + +``` + +--- + +## What is not validated + +Reactive bindings and dollar-prefixed variables are not validated. + +--- + +## Reference + +**Blits docs — [Element attributes - Positioning and dimensions](https://lightning-js.github.io/blits/#/essentials/element_attributes)** + +> "You can specify the dimensions of an Element by passing the `w` attribute for the width and the `h` attribute for the height." +> +> "Same as with the coordinates, you can pass decimal values, or a percentage." diff --git a/eslint-plugin-blits/docs/attributes/height.md b/eslint-plugin-blits/docs/attributes/height.md new file mode 100644 index 0000000..c6fc9ba --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/height.md @@ -0,0 +1,29 @@ +# height + +The height of the element in pixels or percentage. Alias for `h`. + +**Attribute** · Reactive + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | + +--- + +## Examples & Validation + +`height` behaves exactly the same as the `h` attribute and shares all of its validation rules. For full examples and details, please see the [h documentation](./h.md). + +--- + +## Reference + +**Blits docs — [Element attributes - Positioning and dimensions](https://lightning-js.github.io/blits/#/essentials/element_attributes)** + +> "You can specify the dimensions of an Element by passing the `w` attribute for the width and the `h` attribute for the height." diff --git a/eslint-plugin-blits/docs/attributes/index.md b/eslint-plugin-blits/docs/attributes/index.md new file mode 100644 index 0000000..a376b12 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/index.md @@ -0,0 +1,59 @@ +# Blits Template Attributes + +All attributes available in Blits component templates, sourced from `data/template-attributes.json` (v1) and `data/template-attributes.v2.json` (v2). + +| Attribute | Used in | Reactive | Types | Version | +|---|---|---|---|---| +| [`$shallow`](./$shallow.md) | all | — | directive: `true`, `false` | Both | +| [`align`](./align.md) | `` | ✓ | enum: `left`, `right`, `center` | Both | +| [`align-items`](./align-items.md) | `` | ✓ | enum: `start`, `center`, `end` | Both | +| [`alpha`](./alpha.md) | ``, ``, ``, ``, component | ✓ | number | Both | +| [`border`](./border.md) | `` | ✓ | number, object | v2+ | +| [`clipping`](./clipping.md) | ``, ``, `` | ✓ | enum: `true`, `false` | Both | +| [`color`](./color.md) | ``, ``, ``, `` | ✓ | string, object | Both | +| [`contain`](./contain.md) | `` | ✓ | enum: `none`, `width`, `both` (v1) / `+height` (v2) | Both | +| [`content`](./content.md) | `` | ✓ | string | Both | +| [`direction`](./direction.md) | `` | ✓ | enum: `horizontal`, `vertical` | Both | +| [`effects`](./effects.md) | `` | ✓ | array | v1 only | +| [`fit`](./fit.md) | `` | ✓ | enum: `cover`, `contain`, object | Both | +| [`font`](./font.md) | `` | ✓ | string | Both | +| [`for`](./for.md) | all | ✓ | directive | Both | +| [`gap`](./gap.md) | `` | ✓ | number | Both | +| [`h`](./h.md) | ``, ``, `` | ✓ | number, string | Both | +| [`height`](./height.md) | ``, ``, `` | ✓ | number, string (alias for `h`) | Both | +| [`inspector-data`](./inspector-data.md) | all | — | object | Both | +| [`is`](./is.md) | component | — | string | Both | +| [`key`](./key.md) | all | — | string | Both | +| [`letterspacing`](./letterspacing.md) | `` | ✓ | number | Both | +| [`lineheight`](./lineheight.md) | `` | ✓ | number | Both | +| [`maxheight`](./maxheight.md) | `` | ✓ | number | Both | +| [`maxlines`](./maxlines.md) | `` | ✓ | number | Both | +| [`maxwidth`](./maxwidth.md) | `` | ✓ | number | Both | +| [`mount`](./mount.md) | ``, ``, ``, `` | ✓ | number, object | Both | +| [`overflow`](./overflow.md) | ``, `` | ✓ | enum: `true`, `false` | Both | +| [`padding`](./padding.md) | `` | ✓ | number, object | Both | +| [`pivot`](./pivot.md) | ``, ``, ``, `` | ✓ | number, object | Both | +| [`placement`](./placement.md) | ``, ``, ``, `` | ✓ | enum: `left`, `center`, `right`, `top`, `middle`, `bottom`, object | Both | +| [`range`](./range.md) | all | ✓ | object `{from, to}` | Both | +| [`ref`](./ref.md) | all | — | string | Both | +| [`rotation`](./rotation.md) | ``, ``, ``, `` | ✓ | number | Both | +| [`rounded`](./rounded.md) | `` | ✓ | number, array, object | v2+ | +| [`rtt`](./rtt.md) | `` | ✓ | enum: `true`, `false` | Both | +| [`scale`](./scale.md) | ``, ``, ``, ``, component | ✓ | number, object | Both | +| [`shader`](./shader.md) | `` | ✓ | string, object | v2+ | +| [`shadow`](./shadow.md) | `` | ✓ | object | v2+ | +| [`show`](./show.md) | all | ✓ | directive: `true`, `false` | Both | +| [`size`](./size.md) | `` | ✓ | number | Both | +| [`slot`](./slot.md) | ``, ``, ``, ``, component | — | string | Both | +| [`src`](./src.md) | `` | ✓ | string, object | Both | +| [`textoverflow`](./textoverflow.md) | `` | ✓ | string, enum | Both | +| [`w`](./w.md) | ``, ``, `` | ✓ | number, string | Both | +| [`width`](./width.md) | ``, ``, `` | ✓ | number, string (alias for `w`) | Both | +| [`wordwrap`](./wordwrap.md) | `` | ✓ | number | v1 only | +| [`x`](./x.md) | ``, ``, ``, ``, component | ✓ | number, string | Both | +| [`y`](./y.md) | ``, ``, ``, ``, component | ✓ | number, string | Both | +| [`z`](./z.md) | ``, ``, ``, `` | ✓ | number | Both | +| [`zIndex`](./zIndex.md) | ``, ``, ``, `` | ✓ | number (alias for `z`) | Both | +| [`@error`](./event-error.md) | ``, `` | — | event | Both | +| [`@loaded`](./event-loaded.md) | ``, `` | — | event | Both | +| [`@updated`](./event-updated.md) | `` | — | event | Both | diff --git a/eslint-plugin-blits/docs/attributes/inspector-data.md b/eslint-plugin-blits/docs/attributes/inspector-data.md new file mode 100644 index 0000000..aa3fa64 --- /dev/null +++ b/eslint-plugin-blits/docs/attributes/inspector-data.md @@ -0,0 +1,50 @@ +# inspector-data + +Attaches custom metadata to elements for debugging and automated testing, visible in the Lightning inspector. Only processed in dev mode when inspector is enabled. + +**Attribute** · Static + +--- + +## Used in + +| Tag | | +|---|---| +| `` | | +| `` | | +| `` | | +| `` | | +| `` | Any user-defined PascalCase component | + +--- + +## Accepted values + +**Object literal** with any key-value pairs. + +--- + +## Examples + +```blits + + +