Files
ersatztv/design-system/_adherence.oxlintrc.json
T
2026-07-02 07:37:00 +02:00

470 lines
17 KiB
JSON

{
"plugins": [
"react",
"import"
],
"rules": {
"react/forbid-elements": [
"warn",
{
"forbid": []
}
],
"no-restricted-imports": [
"warn",
{
"patterns": [
{
"group": [
"components/data-display/**",
"components/feedback/**",
"components/forms/**",
"components/navigation/**",
"design_handoff_channel_builder/**"
],
"message": "Import design-system components from 'index.js', not component internals."
}
]
}
],
"no-restricted-syntax": [
"warn",
{
"selector": "Literal[value=/#[0-9a-fA-F]{3,8}\\b/]",
"message": "Raw hex color — use a design-system color token via var()."
},
{
"selector": "Literal[value=/\\b\\d+px\\b/]",
"message": "Raw px value — use a design-system spacing token via var()."
},
{
"selector": "Literal[value=/font-family\\s*:\\s*(?!['\\\"]?(?:Geist|Geist Mono))/i]",
"message": "Font not provided by the design system. Available: Geist, Geist Mono."
},
{
"selector": "JSXOpeningElement[name.name='Badge'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|tone|solid|dot|style|key|ref|className|style|children)$/]",
"message": "<Badge> doesn't accept that prop. Declared props: children, tone, solid, dot, style."
},
{
"selector": "JSXOpeningElement[name.name='Badge'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:neutral|accent|ok|warn|error)$/]",
"message": "<Badge> tone must be one of 'neutral' | 'accent' | 'ok' | 'warn' | 'error'."
},
{
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|variant|size|startIcon|endIcon|disabled|loading|fullWidth|type|onClick|style|key|ref|className|style|children)$/]",
"message": "<Button> doesn't accept that prop. Declared props: children, variant, size, startIcon, endIcon, disabled, loading, fullWidth, type, onClick, style."
},
{
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:primary|secondary|ghost|danger)$/]",
"message": "<Button> variant must be one of 'primary' | 'secondary' | 'ghost' | 'danger'."
},
{
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md)$/]",
"message": "<Button> size must be one of 'sm' | 'md'."
},
{
"selector": "JSXOpeningElement[name.name='Button'] > JSXAttribute[name.name='type'] > Literal[value!=/^(?:button|submit|reset)$/]",
"message": "<Button> type must be one of 'button' | 'submit' | 'reset'."
},
{
"selector": "JSXOpeningElement[name.name='Card'] > JSXAttribute > JSXIdentifier[name!=/^(?:title|subtitle|actions|children|padded|inset|style|key|ref|className|style|children)$/]",
"message": "<Card> doesn't accept that prop. Declared props: title, subtitle, actions, children, padded, inset, style."
},
{
"selector": "JSXOpeningElement[name.name='ChannelLogo'] > JSXAttribute > JSXIdentifier[name!=/^(?:name|src|size|radius|style|key|ref|className|style|children)$/]",
"message": "<ChannelLogo> doesn't accept that prop. Declared props: name, src, size, radius, style."
},
{
"selector": "JSXOpeningElement[name.name='Checkbox'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|label|indeterminate|disabled|style|key|ref|className|style|children)$/]",
"message": "<Checkbox> doesn't accept that prop. Declared props: checked, onChange, label, indeterminate, disabled, style."
},
{
"selector": "JSXOpeningElement[name.name='IconButton'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|size|variant|active|disabled|title|onClick|style|key|ref|className|style|children)$/]",
"message": "<IconButton> doesn't accept that prop. Declared props: children, size, variant, active, disabled, title, onClick, style."
},
{
"selector": "JSXOpeningElement[name.name='IconButton'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md)$/]",
"message": "<IconButton> size must be one of 'sm' | 'md'."
},
{
"selector": "JSXOpeningElement[name.name='IconButton'] > JSXAttribute[name.name='variant'] > Literal[value!=/^(?:ghost|solid)$/]",
"message": "<IconButton> variant must be one of 'ghost' | 'solid'."
},
{
"selector": "JSXOpeningElement[name.name='Input'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|value|onChange|placeholder|leadingIcon|trailing|error|disabled|size|type|fullWidth|style|key|ref|className|style|children)$/]",
"message": "<Input> doesn't accept that prop. Declared props: label, value, onChange, placeholder, leadingIcon, trailing, error, disabled, size, type, fullWidth, style."
},
{
"selector": "JSXOpeningElement[name.name='Input'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md)$/]",
"message": "<Input> size must be one of 'sm' | 'md'."
},
{
"selector": "JSXOpeningElement[name.name='NavItem'] > JSXAttribute > JSXIdentifier[name!=/^(?:icon|label|active|badge|badgeTone|href|onClick|style|key|ref|className|style|children)$/]",
"message": "<NavItem> doesn't accept that prop. Declared props: icon, label, active, badge, badgeTone, href, onClick, style."
},
{
"selector": "JSXOpeningElement[name.name='NavItem'] > JSXAttribute[name.name='badgeTone'] > Literal[value!=/^(?:warn|error|accent)$/]",
"message": "<NavItem> badgeTone must be one of 'warn' | 'error' | 'accent'."
},
{
"selector": "JSXOpeningElement[name.name='ProgressBar'] > JSXAttribute > JSXIdentifier[name!=/^(?:value|tone|height|showLabel|style|key|ref|className|style|children)$/]",
"message": "<ProgressBar> doesn't accept that prop. Declared props: value, tone, height, showLabel, style."
},
{
"selector": "JSXOpeningElement[name.name='ProgressBar'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:accent|ok|warn|error)$/]",
"message": "<ProgressBar> tone must be one of 'accent' | 'ok' | 'warn' | 'error'."
},
{
"selector": "JSXOpeningElement[name.name='SelectOption'] > JSXAttribute > JSXIdentifier[name!=/^(?:value|label|key|ref|className|style|children)$/]",
"message": "<SelectOption> doesn't accept that prop. Declared props: value, label."
},
{
"selector": "JSXOpeningElement[name.name='Spinner'] > JSXAttribute > JSXIdentifier[name!=/^(?:size|tone|stroke|style|key|ref|className|style|children)$/]",
"message": "<Spinner> doesn't accept that prop. Declared props: size, tone, stroke, style."
},
{
"selector": "JSXOpeningElement[name.name='Spinner'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:accent|muted|ok)$/]",
"message": "<Spinner> tone must be one of 'accent' | 'muted' | 'ok'."
},
{
"selector": "JSXOpeningElement[name.name='Stat'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|value|unit|delta|deltaTone|icon|style|key|ref|className|style|children)$/]",
"message": "<Stat> doesn't accept that prop. Declared props: label, value, unit, delta, deltaTone, icon, style."
},
{
"selector": "JSXOpeningElement[name.name='Stat'] > JSXAttribute[name.name='deltaTone'] > Literal[value!=/^(?:up|down|neutral)$/]",
"message": "<Stat> deltaTone must be one of 'up' | 'down' | 'neutral'."
},
{
"selector": "JSXOpeningElement[name.name='StatusDot'] > JSXAttribute > JSXIdentifier[name!=/^(?:status|pulse|size|label|style|key|ref|className|style|children)$/]",
"message": "<StatusDot> doesn't accept that prop. Declared props: status, pulse, size, label, style."
},
{
"selector": "JSXOpeningElement[name.name='StatusDot'] > JSXAttribute[name.name='status'] > Literal[value!=/^(?:live|ok|warn|error|idle)$/]",
"message": "<StatusDot> status must be one of 'live' | 'ok' | 'warn' | 'error' | 'idle'."
},
{
"selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute > JSXIdentifier[name!=/^(?:checked|onChange|label|disabled|size|style|key|ref|className|style|children)$/]",
"message": "<Switch> doesn't accept that prop. Declared props: checked, onChange, label, disabled, size, style."
},
{
"selector": "JSXOpeningElement[name.name='Switch'] > JSXAttribute[name.name='size'] > Literal[value!=/^(?:sm|md)$/]",
"message": "<Switch> size must be one of 'sm' | 'md'."
},
{
"selector": "JSXOpeningElement[name.name='TabItem'] > JSXAttribute > JSXIdentifier[name!=/^(?:value|label|icon|count|key|ref|className|style|children)$/]",
"message": "<TabItem> doesn't accept that prop. Declared props: value, label, icon, count."
},
{
"selector": "JSXOpeningElement[name.name='Tag'] > JSXAttribute > JSXIdentifier[name!=/^(?:children|onRemove|icon|tone|style|key|ref|className|style|children)$/]",
"message": "<Tag> doesn't accept that prop. Declared props: children, onRemove, icon, tone, style."
},
{
"selector": "JSXOpeningElement[name.name='Tag'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:neutral|accent)$/]",
"message": "<Tag> tone must be one of 'neutral' | 'accent'."
},
{
"selector": "JSXOpeningElement[name.name='Toast'] > JSXAttribute > JSXIdentifier[name!=/^(?:tone|title|message|onClose|style|key|ref|className|style|children)$/]",
"message": "<Toast> doesn't accept that prop. Declared props: tone, title, message, onClose, style."
},
{
"selector": "JSXOpeningElement[name.name='Toast'] > JSXAttribute[name.name='tone'] > Literal[value!=/^(?:info|ok|warn|error)$/]",
"message": "<Toast> tone must be one of 'info' | 'ok' | 'warn' | 'error'."
},
{
"selector": "JSXOpeningElement[name.name='Tooltip'] > JSXAttribute > JSXIdentifier[name!=/^(?:label|placement|children|style|key|ref|className|style|children)$/]",
"message": "<Tooltip> doesn't accept that prop. Declared props: label, placement, children, style."
},
{
"selector": "JSXOpeningElement[name.name='Tooltip'] > JSXAttribute[name.name='placement'] > Literal[value!=/^(?:top|bottom|left|right)$/]",
"message": "<Tooltip> placement must be one of 'top' | 'bottom' | 'left' | 'right'."
}
]
},
"overrides": [
{
"files": [
"**/index.js"
],
"rules": {
"no-restricted-imports": "off"
}
}
],
"x-omelette": {
"components": {
"Badge": {
"replaces": []
},
"Button": {
"replaces": []
},
"Card": {
"replaces": []
},
"ChannelLogo": {
"replaces": []
},
"Checkbox": {
"replaces": []
},
"IconButton": {
"replaces": []
},
"Input": {
"replaces": []
},
"NavItem": {
"replaces": []
},
"ProgressBar": {
"replaces": []
},
"SelectOption": {
"replaces": []
},
"Spinner": {
"replaces": []
},
"Stat": {
"replaces": []
},
"StatusDot": {
"replaces": []
},
"Switch": {
"replaces": []
},
"TabItem": {
"replaces": []
},
"Tag": {
"replaces": []
},
"Toast": {
"replaces": []
},
"Tooltip": {
"replaces": []
}
},
"tokens": [
"--action-primary",
"--action-primary-hover",
"--action-primary-press",
"--border-control",
"--border-hairline",
"--control-h",
"--control-h-sm",
"--ctv-accent",
"--ctv-accent-hover",
"--ctv-accent-press",
"--ctv-accent-ring",
"--ctv-accent-soft",
"--ctv-bg",
"--ctv-bg-sunken",
"--ctv-border",
"--ctv-border-strong",
"--ctv-error",
"--ctv-error-soft",
"--ctv-live",
"--ctv-live-soft",
"--ctv-ok",
"--ctv-ok-soft",
"--ctv-secondary",
"--ctv-secondary-soft",
"--ctv-surface",
"--ctv-surface-2",
"--ctv-surface-3",
"--ctv-text",
"--ctv-text-faint",
"--ctv-text-muted",
"--ctv-warn",
"--ctv-warn-soft",
"--dur-base",
"--dur-fast",
"--dur-slow",
"--ease-out",
"--ease-standard",
"--focus-ring",
"--font-mono",
"--font-sans",
"--gap-inline",
"--leading-normal",
"--leading-snug",
"--leading-tight",
"--numeric-feature",
"--pad-card",
"--pad-cell-x",
"--pad-cell-y",
"--pad-control-x",
"--pad-control-y",
"--pad-page",
"--radius-lg",
"--radius-md",
"--radius-pill",
"--radius-sm",
"--radius-xs",
"--ring-focus",
"--row-h",
"--shadow-lg",
"--shadow-md",
"--shadow-none",
"--shadow-pop",
"--shadow-sm",
"--sidebar-w",
"--space-0",
"--space-1",
"--space-10",
"--space-11",
"--space-12",
"--space-2",
"--space-3",
"--space-4",
"--space-5",
"--space-6",
"--space-7",
"--space-8",
"--space-9",
"--status-error",
"--status-live",
"--status-ok",
"--status-warn",
"--surface-app",
"--surface-card",
"--surface-raised",
"--surface-selected",
"--text-2xl",
"--text-2xs",
"--text-3xl",
"--text-disabled",
"--text-lg",
"--text-md",
"--text-on-accent",
"--text-primary",
"--text-secondary",
"--text-sm",
"--text-xl",
"--text-xs",
"--topbar-h",
"--tracking-caps",
"--tracking-normal",
"--tracking-tight",
"--tracking-wide",
"--weight-bold",
"--weight-medium",
"--weight-normal",
"--weight-semibold"
],
"tokenKinds": {
"--ctv-bg": "color",
"--ctv-bg-sunken": "color",
"--ctv-surface": "color",
"--ctv-surface-2": "color",
"--ctv-surface-3": "color",
"--ctv-border": "color",
"--ctv-border-strong": "color",
"--ctv-text": "font",
"--ctv-text-muted": "font",
"--ctv-text-faint": "font",
"--ctv-accent": "color",
"--ctv-accent-hover": "color",
"--ctv-accent-press": "color",
"--ctv-accent-soft": "color",
"--ctv-accent-ring": "color",
"--ctv-secondary": "color",
"--ctv-secondary-soft": "color",
"--ctv-ok": "color",
"--ctv-ok-soft": "color",
"--ctv-warn": "color",
"--ctv-warn-soft": "color",
"--ctv-error": "color",
"--ctv-error-soft": "color",
"--ctv-live": "color",
"--ctv-live-soft": "color",
"--surface-app": "color",
"--surface-card": "color",
"--surface-raised": "color",
"--surface-selected": "color",
"--border-hairline": "color",
"--border-control": "color",
"--text-primary": "font",
"--text-secondary": "font",
"--text-disabled": "font",
"--text-on-accent": "font",
"--action-primary": "color",
"--action-primary-hover": "color",
"--action-primary-press": "color",
"--focus-ring": "color",
"--status-ok": "color",
"--status-warn": "color",
"--status-error": "color",
"--status-live": "color",
"--font-sans": "font",
"--font-mono": "font",
"--text-2xs": "font",
"--text-xs": "font",
"--text-sm": "font",
"--text-md": "font",
"--text-lg": "font",
"--text-xl": "font",
"--text-2xl": "font",
"--text-3xl": "font",
"--weight-normal": "font",
"--weight-medium": "font",
"--weight-semibold": "font",
"--weight-bold": "font",
"--leading-tight": "font",
"--leading-snug": "font",
"--leading-normal": "font",
"--tracking-tight": "font",
"--tracking-normal": "font",
"--tracking-wide": "font",
"--tracking-caps": "font",
"--numeric-feature": "other",
"--space-0": "spacing",
"--space-1": "spacing",
"--space-2": "spacing",
"--space-3": "spacing",
"--space-4": "spacing",
"--space-5": "spacing",
"--space-6": "spacing",
"--space-7": "spacing",
"--space-8": "spacing",
"--space-9": "spacing",
"--space-10": "spacing",
"--space-11": "spacing",
"--space-12": "spacing",
"--gap-inline": "spacing",
"--pad-control-x": "spacing",
"--pad-control-y": "spacing",
"--pad-card": "spacing",
"--pad-cell-x": "spacing",
"--pad-cell-y": "spacing",
"--pad-page": "spacing",
"--sidebar-w": "spacing",
"--topbar-h": "spacing",
"--row-h": "spacing",
"--control-h": "spacing",
"--control-h-sm": "spacing",
"--radius-xs": "radius",
"--radius-sm": "radius",
"--radius-md": "radius",
"--radius-lg": "radius",
"--radius-pill": "radius",
"--shadow-none": "shadow",
"--shadow-sm": "shadow",
"--shadow-md": "shadow",
"--shadow-lg": "shadow",
"--shadow-pop": "shadow",
"--ring-focus": "color",
"--ease-standard": "other",
"--ease-out": "other",
"--dur-fast": "other",
"--dur-base": "other",
"--dur-slow": "other"
},
"fontFamilies": [
"Geist",
"Geist Mono"
]
}
}