wp-optimize
/
vendor
/
team-updraft
/
lib-onboarding-wizard
/
Wizard
/
Onboarding
/
src
/
components
/
Fields
/
CheckboxGroupInput.tsx
CheckboxGroupInput.tsx in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance trunk, at vendor/team-updraft/lib-onboarding-wizard/Wizard/Onboarding/src/components/Fields/CheckboxGroupInput.tsx
| 1 | // @ts-ignore |
| 2 | import Icon from '@/utils/Icon'; |
| 3 | import { memo, type ReactNode } from 'react'; |
| 4 | import { __ } from '@wordpress/i18n'; |
| 5 | import * as Checkbox from '@radix-ui/react-checkbox'; |
| 6 | |
| 7 | interface CheckboxGroupInputProps { |
| 8 | field: { |
| 9 | action?: string | ReactNode; |
| 10 | [key: string]: any; |
| 11 | }; |
| 12 | /** If true, the field displays an indeterminate (or overridden) state */ |
| 13 | indeterminate?: boolean; |
| 14 | /** Label for the group used in aria-label */ |
| 15 | label: string; |
| 16 | /** The current value; can be a boolean (for a single toggle) or an array for multi-selection */ |
| 17 | value: any; |
| 18 | /** Base id for the element */ |
| 19 | id: string; |
| 20 | /** Callback when the value changes */ |
| 21 | onChange: (value: any) => void; |
| 22 | /** If true, the field is required */ |
| 23 | required?: boolean; |
| 24 | /** |
| 25 | * If a boolean is provided then it disables the whole field; if an array is provided, only the matching option(s) are disabled |
| 26 | */ |
| 27 | disabled?: boolean | string[]; |
| 28 | /** A record of options in the format { optionId: optionLabel } */ |
| 29 | options: Record<string, string>; |
| 30 | } |
| 31 | |
| 32 | /** |
| 33 | * CheckboxGroupInput component |
| 34 | * |
| 35 | * Renders a group of checkboxes based on the options provided. |
| 36 | * Supports a boolean mode when one option is provided as well as a load-more functionality. |
| 37 | */ |
| 38 | const CheckboxGroupInput = ({ |
| 39 | field, |
| 40 | label, |
| 41 | value, |
| 42 | id, |
| 43 | onChange, |
| 44 | required, |
| 45 | disabled, |
| 46 | options = {}, |
| 47 | } : CheckboxGroupInputProps) => { |
| 48 | |
| 49 | // Convert incoming value to an array if not already one |
| 50 | let valueValidated: any = value; |
| 51 | if (!Array.isArray(valueValidated)) { |
| 52 | valueValidated = valueValidated === '' ? [] : [valueValidated]; |
| 53 | } |
| 54 | |
| 55 | const selected = Array.isArray(valueValidated) ? valueValidated : []; |
| 56 | |
| 57 | /** |
| 58 | * Handles a change on an individual checkbox. |
| 59 | * For boolean mode, simply toggles the value. |
| 60 | * Otherwise, adds or removes the selected option. |
| 61 | */ |
| 62 | const handleCheckboxChange = (_checked: boolean, option: string) => { |
| 63 | const newSelected = selected.includes('' + option) || selected.includes(parseInt(option)) |
| 64 | ? selected.filter((item: any) => item !== '' + option && item !== parseInt(option)) |
| 65 | : [...selected, option]; |
| 66 | onChange(newSelected); |
| 67 | |
| 68 | }; |
| 69 | |
| 70 | /** |
| 71 | * Determines if an option is considered checked. |
| 72 | */ |
| 73 | const isEnabled = (optionId: string) => { |
| 74 | return selected.includes('' + optionId) || selected.includes(parseInt(optionId)); |
| 75 | }; |
| 76 | |
| 77 | // If disabled is not an array, treat it as a boolean disabling the entire field. |
| 78 | const allDisabled = disabled && !Array.isArray(disabled) ? disabled : false; |
| 79 | |
| 80 | if (Object.keys(options).length === 0) { |
| 81 | return <>{__('No options found', 'ONBOARDING_WIZARD_TEXT_DOMAIN')}</>; |
| 82 | } |
| 83 | |
| 84 | return ( |
| 85 | <div className="flex flex-col space-y-2"> |
| 86 | {Object.entries(options).map(([key, optionLabel], i) => ( |
| 87 | <div |
| 88 | key={key} |
| 89 | className="flex items-center" |
| 90 | > |
| 91 | <Checkbox.Root |
| 92 | className="w-4 h-4 border border-gray-400 rounded flex-shrink-0 disabled:opacity-50" |
| 93 | id={`${id}_${key}`} |
| 94 | checked={isEnabled(key)} |
| 95 | aria-label={label} |
| 96 | disabled={ |
| 97 | allDisabled || |
| 98 | (Array.isArray(disabled) && (disabled as string[]).includes(key)) |
| 99 | } |
| 100 | required={required} |
| 101 | onCheckedChange={(checked) => handleCheckboxChange(!!checked, key)} |
| 102 | > |
| 103 | <Checkbox.Indicator className="flex items-center justify-center"> |
| 104 | <Icon |
| 105 | name="check" |
| 106 | size={14} |
| 107 | color="blue" |
| 108 | strokeWidth={3} |
| 109 | onClick={() => {}} |
| 110 | className="" |
| 111 | /> |
| 112 | </Checkbox.Indicator> |
| 113 | </Checkbox.Root> |
| 114 | <label className="ml-2" htmlFor={`${id}_${key}`}> |
| 115 | {optionLabel}{field.action} |
| 116 | </label> |
| 117 | </div> |
| 118 | ))} |
| 119 | </div> |
| 120 | ); |
| 121 | }; |
| 122 | |
| 123 | export default memo(CheckboxGroupInput); |