diff --git a/docs/user-guide.en.md b/docs/user-guide.en.md index 500e706..c498627 100644 --- a/docs/user-guide.en.md +++ b/docs/user-guide.en.md @@ -441,7 +441,7 @@ The Component emits the next value; the caller owns the ref and supplies the cur (etaf-data-controller source :page-size 10 :auto-load t)) ``` -The controller exposes reactive refs through `etaf-data-items`, `etaf-data-status`, `etaf-data-error`, `etaf-data-total`, `etaf-data-query`, `etaf-data-page`, `etaf-data-page-size`, and `etaf-data-selection`. Use `etaf-data-load`, `etaf-data-reload`, `etaf-data-mutate`, `etaf-data-set-query`, `etaf-data-next-page`, `etaf-data-previous-page`, `etaf-data-select`, and `etaf-data-stop` for operations. +The controller exposes reactive refs through `etaf-data-items`, `etaf-data-status`, `etaf-data-error`, `etaf-data-total`, `etaf-data-query`, `etaf-data-page`, `etaf-data-page-size`, and `etaf-data-selection`. Use `etaf-data-load`, `etaf-data-reload`, `etaf-data-mutate`, `etaf-data-set-query`, `etaf-data-next-page`, `etaf-data-previous-page`, `etaf-data-select` (additive multi-select), `etaf-data-select-one` (exclusive single-select), and `etaf-data-stop` for operations. The official DataGrid is a normal Component: diff --git a/docs/user-guide.zh.md b/docs/user-guide.zh.md index 085c731..c55a5fc 100644 --- a/docs/user-guide.zh.md +++ b/docs/user-guide.zh.md @@ -440,7 +440,7 @@ Component 发出 next value;ref 由调用方拥有,并在下一次 render (etaf-data-controller source :page-size 10 :auto-load t)) ``` -Controller 通过 `etaf-data-items`、`etaf-data-status`、`etaf-data-error`、`etaf-data-total`、`etaf-data-query`、`etaf-data-page`、`etaf-data-page-size` 和 `etaf-data-selection` 暴露响应式 ref。操作使用 `etaf-data-load`、`etaf-data-reload`、`etaf-data-mutate`、`etaf-data-set-query`、`etaf-data-next-page`、`etaf-data-previous-page`、`etaf-data-select` 和 `etaf-data-stop`。 +Controller 通过 `etaf-data-items`、`etaf-data-status`、`etaf-data-error`、`etaf-data-total`、`etaf-data-query`、`etaf-data-page`、`etaf-data-page-size` 和 `etaf-data-selection` 暴露响应式 ref。操作使用 `etaf-data-load`、`etaf-data-reload`、`etaf-data-mutate`、`etaf-data-set-query`、`etaf-data-next-page`、`etaf-data-previous-page`、`etaf-data-select`(追加式多选)、`etaf-data-select-one`(互斥单选)和 `etaf-data-stop`。 官方 DataGrid 是普通 Component: diff --git a/etaf-data.el b/etaf-data.el index bdd5705..da444ce 100644 --- a/etaf-data.el +++ b/etaf-data.el @@ -417,6 +417,16 @@ When SELECTED-P is nil, remove IDENTITY from the selection." (cl-adjoin identity selection :test #'equal) (cl-remove identity selection :test #'equal))))) +;;;###autoload +(defun etaf-data-select-one (controller identity) + "Replace CONTROLLER selection with the single IDENTITY. + +Use this explicit single-selection operation for tables and list views. The +existing `etaf-data-select' API remains additive for multi-select controls." + (let ((selection-ref (etaf-data-selection controller))) + (setf (etaf-value selection-ref) + (if (null identity) nil (list identity))))) + ;;;###autoload (defun etaf-data-selected-p (controller identity) "Return non-nil when IDENTITY is selected in CONTROLLER." diff --git a/tests/etaf-data-tests.el b/tests/etaf-data-tests.el index 413b590..721384e 100644 --- a/tests/etaf-data-tests.el +++ b/tests/etaf-data-tests.el @@ -160,6 +160,22 @@ (should-not (etaf-value (etaf-data-selection controller)))) (etaf-data-stop controller)))) +(ert-deftest etaf-data-select-one-replaces-existing-selection () + "Single-selection consumers replace, rather than adjoin, identities." + (let* ((source (etaf-data-memory-source + '((:id 1) (:id 2) (:id 3)) :id-key :id)) + (controller (etaf-data-controller source :auto-load nil))) + (unwind-protect + (progn + (etaf-data-select-one controller 1) + (etaf-data-select-one controller 2) + (should (equal '(2) (etaf-value (etaf-data-selection controller)))) + (etaf-data-select-one controller 2) + (should (equal '(2) (etaf-value (etaf-data-selection controller)))) + (etaf-data-select-one controller nil) + (should-not (etaf-value (etaf-data-selection controller)))) + (etaf-data-stop controller)))) + (ert-deftest etaf-data-stop-disposes-source-and-controller () "Stop controller lifecycle resources and reject later operations." (let* ((dispose-count 0)