schema: ai-cjm-component-contract/v1 id: filter-bar version: 1.0.0 status: stable owner: AI CJM Design purpose: Ограничивает каталог по явным критериям и показывает активный фильтр. use_when: - Каталог поддерживает skill/category filter. evidence: - id: production-style url: https://aicjm.ru/edu/teachers/teachers.css?v=20260812-unified-person-cards locator: .teacher-filter-controls, .filter-options, .filter-options button, .filter-options button:hover, .filter-options button.is-active supports: - anatomy - variant:single-select - size:default - state:default - state:hover - state:selected - id: production-dom url: https://aicjm.ru/edu/teachers/?view=skill&filter=generative-design locator: .teacher-filter-controls .filter-options and .filter-status supports: - approved-example - content anatomy: - id: label required: false role: Название группы фильтров. - id: control-list required: true role: Набор filter controls. - id: active-indicator required: true role: Дополнительный selected cue. - id: result-context required: true role: Обновлённый каталог или count. variants: - id: single-select status: stable description: Один активный фильтр. evidence_refs: - production-style - id: multi-select status: candidate description: Нормативный gap без production evidence. sizes: - id: default status: stable description: Размер определяется содержимым и перечисленными semantic/component tokens; raw dimensions запрещены. evidence_refs: - production-style states: default: status: stable basis: observed description: default is observed at the exact production locator in evidence_refs. evidence_refs: - production-style hover: status: stable basis: observed description: hover is observed at the exact production locator in evidence_refs. evidence_refs: - production-style focus-visible: status: candidate basis: normative-gap description: Proposed focus-visible contract for filter-bar; approval is required before production use. behavior: Render focus.ring without changing layout or relying on hover. semantics: Keep the native element in DOM order and expose keyboard focus visibly. token_refs: - component.filter.background - component.filter.text - component.filter.active-background transition: Enter for keyboard-origin focus and return to default on blur. acceptance: - focus-visible behavior, semantics, token refs and transition pass the filter-bar manual state check. active: status: not-applicable basis: not-applicable description: Persistent choice is owned by selected; transient press uses native button behavior. selected: status: stable basis: observed description: selected is observed at the exact production locator in evidence_refs. evidence_refs: - production-style open: status: not-applicable basis: not-applicable description: open is not owned by filter-bar. disabled: status: candidate basis: normative-gap description: Proposed disabled contract for filter-bar; approval is required before production use. behavior: Prevent activation or editing while preserving label, context and layout. semantics: Use native disabled where available; otherwise aria-disabled=true and suppress activation. token_refs: - component.filter.background - component.filter.text - component.filter.active-background transition: Enter only when the action is unavailable and return to default when it becomes available. acceptance: - disabled behavior, semantics, token refs and transition pass the filter-bar manual state check. loading: status: not-applicable basis: not-applicable description: Loading belongs to the catalog/results pattern, not filter-bar. success: status: not-applicable basis: not-applicable description: success is not owned by filter-bar. error: status: not-applicable basis: not-applicable description: error is not owned by filter-bar. empty: status: not-applicable basis: not-applicable description: Empty belongs to the catalog/results pattern, not filter-bar. responsive: mode: sticky-row-to-static-scroll-row reading_order: DOM order remains authoritative in every mode. rules: - Keep filter controls before result status and results. - Allow options to scroll horizontally without wrapping labels. - At narrow mode remove sticky positioning and place result status below the options. accessibility: pattern: toggle-button-filter semantics: - Use buttons with aria-pressed for selected options and a labelled result count. keyboard: - Tab moves between buttons; Enter/Space toggles the focused option; reset is a native button. focus: - Filtering does not move focus; after reset focus stays on reset and result count is announced. motion: - Result updates do not depend on animated rearrangement. tokens: - component.filter.background - component.filter.text - component.filter.active-background - component.filter.active-text - component.filter.active-indicator - component.filter.border - component.filter.radius - component.filter.minimum-height - focus.ring content: required: - Названия реальных категорий. constraints: - Выбранное значение сериализуется в URL или состояние. - Empty объясняет отсутствие результатов и даёт reset. do: - Дублировать selected через текст/semantics и visual cue. dont: - Не кодировать выбранность одним цветом. examples: approved: status: stable description: Компонент filter-bar в указанном scoped production locator. evidence: https://aicjm.ru/edu/teachers/?view=skill&filter=generative-design prohibited: description: Не кодировать выбранность одним цветом. acceptance: - id: filter-bar-1 criterion: Active indicator и background проходят 3:1. method: manual - id: filter-bar-2 criterion: Фильтр доступен с клавиатуры. method: manual