diff --git a/config/fields/checkboxes.php b/config/fields/checkboxes.php index 00a94b83dc..4be32f5cd7 100644 --- a/config/fields/checkboxes.php +++ b/config/fields/checkboxes.php @@ -14,6 +14,13 @@ 'icon' => null, 'placeholder' => null, + /** + * Show/hide the batch select toggle + */ + 'batch' => function (bool $batch = false) { + return $batch; + }, + /** * Arranges the checkboxes in the given number of columns */ diff --git a/i18n/translations/en.json b/i18n/translations/en.json index 90e9e98b90..ff62ccc328 100644 --- a/i18n/translations/en.json +++ b/i18n/translations/en.json @@ -44,6 +44,9 @@ "delete": "Delete", "delete.all": "Delete all", + "deselect": "Deselect", + "deselect.all": "Deselect all", + "dialog.fields.empty": "This dialog has no fields", "dialog.files.empty": "No files to select", "dialog.pages.empty": "No pages to select", @@ -664,6 +667,7 @@ "security": "Security", "select": "Select", + "select.all": "Select all", "server": "Server", "settings": "Settings", "show": "Show", diff --git a/panel/public/img/icons.svg b/panel/public/img/icons.svg index 70b799e9ae..a1ae989a1b 100644 --- a/panel/public/img/icons.svg +++ b/panel/public/img/icons.svg @@ -157,6 +157,9 @@ + + + @@ -523,6 +526,9 @@ + + + diff --git a/panel/src/components/Forms/Field/CheckboxesField.vue b/panel/src/components/Forms/Field/CheckboxesField.vue index e8c9c75a45..dcc621ef93 100644 --- a/panel/src/components/Forms/Field/CheckboxesField.vue +++ b/panel/src/components/Forms/Field/CheckboxesField.vue @@ -6,6 +6,38 @@ :input="id + '-0'" :style="$attrs.style" > + + choice.value); + this.$emit("input", this.selected); } } }; diff --git a/panel/src/styles/reset/choice.css b/panel/src/styles/reset/choice.css index 4bc8a97516..85b4a66d70 100644 --- a/panel/src/styles/reset/choice.css +++ b/panel/src/styles/reset/choice.css @@ -58,7 +58,8 @@ input:where([type="checkbox"]):checked { } /** Checked state **/ -input:where([type="checkbox"], [type="radio"]):checked::after { +input:where([type="checkbox"], [type="radio"]):checked::after, +input:where([type="checkbox"]):indeterminate::after { background: var(--choice-color-checked); display: grid; } @@ -78,14 +79,33 @@ input:where([type="checkbox"], [type="radio"])[disabled] { } /** Checkbox & Toggle **/ -input[type="checkbox"]:checked::after { +input[type="checkbox"]:checked::after, +input[type="checkbox"]:indeterminate::after { content: "✓"; inset: 0; + place-items: center; font-weight: 700; color: var(--choice-color-icon); line-height: 1; } +/** Checkbox indeterminate **/ +input[type="checkbox"]:indeterminate::after { + content: ""; +} +input[type="checkbox"]:indeterminate::before { + position: absolute; + top: 50%; + left: 50%; + content: ""; + margin-top: -1px; + margin-left: -4px; + width: calc(var(--choice-height) - 8px); + height: 2px; + background: var(--choice-color-icon); + z-index: 1; +} + /** Radio **/ input[type="radio"] { --choice-rounded: 50%; diff --git a/tests/Form/Field/CheckboxesFieldTest.php b/tests/Form/Field/CheckboxesFieldTest.php index 256102ab43..4a0ec0d770 100644 --- a/tests/Form/Field/CheckboxesFieldTest.php +++ b/tests/Form/Field/CheckboxesFieldTest.php @@ -136,4 +136,18 @@ public function testRequiredValid(): void $this->assertTrue($field->isValid()); } + + public function testBatch(): void + { + $field = $this->field('checkboxes'); + + $this->assertFalse($field->batch()); + + $field = $this->field('checkboxes', [ + 'batch' => true + ]); + + $this->assertTrue($field->batch()); + } + }