Browse Source

feat(ui) Add a checkbox field to new forms (#28809)

Add a single checkbox field to the new form field library. This field
will help with 'confirm' inputs like the one used during organization
creation in #28773
Mark Story 3 years ago
parent
commit
16ff68a1f0

+ 17 - 0
docs-ui/stories/components/form-fields.stories.js

@@ -3,6 +3,7 @@ import {action} from '@storybook/addon-actions';
 import {Panel} from 'app/components/panels';
 import Switch from 'app/components/switchButton';
 import NewBooleanField from 'app/views/settings/components/forms/booleanField';
+import CheckboxField from 'app/views/settings/components/forms/checkboxField';
 import RadioGroup from 'app/views/settings/components/forms/controls/radioGroup';
 import RangeSlider from 'app/views/settings/components/forms/controls/rangeSlider';
 import DatePickerField from 'app/views/settings/components/forms/datePickerField';
@@ -153,6 +154,22 @@ export const __BooleanField = () => (
 
 __BooleanField.storyName = 'Boolean';
 
+export const _CheckboxField = () => (
+  <Form>
+    <CheckboxField key="agree" name="agree" id="agree" label="Do you agree?" />
+    <CheckboxField
+      key="compelled"
+      name="compelled"
+      id="compelled"
+      label="You are compelled to agree"
+      help="More content to help you decide."
+      required
+    />
+  </Form>
+);
+
+_CheckboxField.storyName = 'Checkbox';
+
 export const _DatePickerField = () => (
   <Form>
     <DatePickerField name="field" label="Date Picker Field" />

+ 104 - 0
static/app/views/settings/components/forms/checkboxField.tsx

@@ -0,0 +1,104 @@
+import styled from '@emotion/styled';
+
+import Checkbox from 'app/components/checkbox';
+import space from 'app/styles/space';
+import FieldDescription from 'app/views/settings/components/forms/field/fieldDescription';
+import FieldHelp from 'app/views/settings/components/forms/field/fieldHelp';
+import FieldLabel from 'app/views/settings/components/forms/field/fieldLabel';
+import FieldRequiredBadge from 'app/views/settings/components/forms/field/fieldRequiredBadge';
+import FormField from 'app/views/settings/components/forms/formField';
+
+type FormFieldProps = Omit<
+  React.ComponentProps<typeof FormField>,
+  'help' | 'disabled' | 'required'
+>;
+
+type Props = {
+  /**
+   * The input name
+   */
+  name: string;
+  /**
+   * User visible field label
+   */
+  label?: React.ReactNode;
+  /**
+   * Is the field disabled?
+   */
+  disabled?: boolean;
+  /**
+   * Is the field required?
+   */
+  required?: boolean;
+  /**
+   * Help or description of the field
+   */
+  help?: React.ReactNode | React.ReactElement | ((props: Props) => React.ReactNode);
+  /**
+   * The control's `id` property
+   */
+  id?: string;
+} & FormFieldProps;
+
+function CheckboxField(props: Props) {
+  const {name, disabled, stacked, id, required, label, help} = props;
+
+  const helpElement = typeof help === 'function' ? help(props) : help;
+
+  return (
+    <FormField name={name} inline={false}>
+      {({onChange, value}) => {
+        function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
+          const newValue = e.target.checked;
+          onChange?.(newValue, e);
+        }
+
+        return (
+          <FieldLayout>
+            <ControlWrapper>
+              <Checkbox
+                id={id}
+                name={name}
+                disabled={disabled}
+                checked={value === true}
+                onChange={handleChange}
+              />
+            </ControlWrapper>
+            <FieldDescription htmlFor={id}>
+              {label && (
+                <FieldLabel disabled={disabled}>
+                  <span>
+                    {label}
+                    {required && <FieldRequiredBadge />}
+                  </span>
+                </FieldLabel>
+              )}
+              {helpElement && (
+                <FieldHelp stacked={stacked} inline>
+                  {helpElement}
+                </FieldHelp>
+              )}
+            </FieldDescription>
+          </FieldLayout>
+        );
+      }}
+    </FormField>
+  );
+}
+
+const ControlWrapper = styled('span')`
+  align-self: flex-start;
+  display: flex;
+  margin-right: ${space(1)};
+
+  & input {
+    margin: 0;
+  }
+`;
+
+const FieldLayout = styled('div')`
+  display: flex;
+  flex-direction: row;
+`;
+
+export default CheckboxField;