feat(core): extract shared KbqCheckable primitive (#DS-3498) - #1883
feat(core): extract shared KbqCheckable primitive (#DS-3498)#1883NikGurev wants to merge 4 commits into
Conversation
|
Visit the preview URL for this PR (updated for commit a2d2ced): https://koobiq-next--prs-1883-s1a6lqnm.web.app (expires Fri, 14 Aug 2026 16:38:56 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: c9e37e518febda70d0317d07e8ceb35ac43c534c |
| * @docs-private | ||
| * @deprecated Use `TransitionCheckState` from `@koobiq/components/core` instead. | ||
| */ | ||
| export { TransitionCheckState }; |
There was a problem hiding this comment.
для чего нужно добавлять устаревший экспорт?
There was a problem hiding this comment.
для обратной совместимости
There was a problem hiding this comment.
так давай так в комментарии и напишем))
There was a problem hiding this comment.
вкладка с примерами выключена
может быть лучше оставить примитив приватным, не отдавать его в паблик апи, это нам развяжет руки для любого рефакторинга
There was a problem hiding this comment.
Так там рефакторить нечего, функционал тоггла и чекбокса не менялся давно.
Наоборот хотелось также показать, что можно делать кастомные компоненты без особых затруднений (был такой запрос)
| * applying it via `hostDirectives` gets `[(ngModel)]`/`formControl` support without wiring up its own. | ||
| * @docs-private | ||
| */ | ||
| export const KBQ_CHECKABLE_CONTROL_VALUE_ACCESSOR: any = { |
There was a problem hiding this comment.
| export const KBQ_CHECKABLE_CONTROL_VALUE_ACCESSOR: any = { | |
| export const KBQ_CHECKABLE_CONTROL_VALUE_ACCESSOR: Provider = { |
| @Input({ transform: booleanAttribute }) | ||
| get disabled(): boolean { | ||
| return this._disabled; | ||
| return this.checkable.disabled(); |
There was a problem hiding this comment.
некоторые вещи можно прокинуть в директиву без обработки:
hostDirectives: [{ directive: KbqCheckable, inputs: ['disabled' ] }],| exportAs: 'kbqCheckable' | ||
| }) | ||
| export class KbqCheckable implements ControlValueAccessor, OnDestroy { | ||
| private readonly focusMonitor = inject(FocusMonitor); |
There was a problem hiding this comment.
фокус монитор в данной директиве только зеркалит свои методы, может быть стоит его удалить и сосредоточится на выделении?
There was a problem hiding this comment.
давай добавим unit тесты
There was a problem hiding this comment.
Pull request overview
This PR extracts the duplicated checkbox/toggle state machine into a shared KbqCheckable host directive in @koobiq/components/core. KbqCheckable centralizes the checked/disabled/indeterminate/tabIndex signals, the click-to-toggle algorithm, ARIA-checked computation, FocusMonitor wiring, and ControlValueAccessor registration. KbqCheckbox and KbqToggleComponent are rewired onto it via hostDirectives, TransitionCheckState and the click-action token/type are promoted to core (with deprecated aliases kept in the checkbox package for compatibility), and a new "block checkbox" doc example demonstrates building a custom control on the primitive.
Changes:
- Add
KbqCheckableprimitive plusKbqCheckableClickAction,KBQ_CHECKABLE_CLICK_ACTION,KbqCheckableClickResult, and movedTransitionCheckStateto core. - Rewire
KbqCheckbox/KbqToggleComponentontoKbqCheckable, delegating state, CVA, focus, and click handling; keep public APIs stable via deprecated aliases. - Add a
block-checkboxdocs example and its registration/documentation.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
packages/components/core/common-behaviors/checkable.ts |
New shared KbqCheckable directive with state, CVA, focus, and click logic. |
packages/components/core/common-behaviors/index.ts |
Re-exports the new checkable module. |
packages/components/checkbox/checkbox.ts |
Delegates state/CVA/focus/click to KbqCheckable; deprecates old CVA token and re-exports TransitionCheckState. |
packages/components/checkbox/checkbox-config.ts |
Aliases KbqCheckboxClickAction to the core type. |
packages/components/toggle/toggle.component.ts |
Rewires toggle onto KbqCheckable; adds KbqToggleClickAction; uses the checkable click-action token with a checkbox fallback provider. |
packages/docs-examples/components/checkbox/block-checkbox/* |
New example component/styles built on KbqCheckable. |
packages/docs-examples/components/checkbox/index.ts |
Registers BlockCheckboxExample. |
packages/components-dev/checkbox/module.ts |
Adds the example to the dev app. |
packages/components/checkbox/examples.checkbox.{en,ru}.md |
Documents the block checkbox example. |
tools/public_api_guard/components/{core,checkbox,toggle}.api.md |
API snapshot updates reflecting the moved/added symbols. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| // Falls back to `KBQ_CHECKBOX_CLICK_ACTION` for backwards compatibility with apps that already | ||
| // configure it globally to control click behavior for both checkbox and toggle. | ||
| { provide: KBQ_CHECKABLE_CLICK_ACTION, useExisting: KBQ_CHECKBOX_CLICK_ACTION } |
| if (shouldToggle) { | ||
| this.checkable.toggle(); | ||
| this.checkedChange.emit(this.checkable.checked()); | ||
| } |
| writeValue(value: any) { | ||
| this.checked = !!value; | ||
| } |
Summary
Checkbox and toggle each reimplemented the same checked/disabled/indeterminate/
tabIndex state, click-to-toggle algorithm, ARIA-checked computation, FocusMonitor
wiring, and ControlValueAccessor - toggle even imported checkbox's internals
(TransitionCheckState, click-action token) to avoid re-declaring them.
KbqCheckable(@koobiq/components/core), a hostDirective centralizing allof the above, including its own ControlValueAccessor registration so any
future control built on it gets form support for free.
public API changes; toggle now depends on the generic KBQ_CHECKABLE_CLICK_ACTION
token (falling back to KBQ_CHECKBOX_CLICK_ACTION for backwards compatibility)
instead of reaching into the checkbox package.
"card" control built directly on the primitive.