Browse Source

ref(js): mv components/form/{field,fieldGroup} (#42852)

Evan Purkhiser 2 years ago
parent
commit
a548b8f427

+ 1 - 1
docs-ui/stories/components/panels.stories.js

@@ -1,7 +1,7 @@
 import {Fragment} from 'react';
 import {Fragment} from 'react';
 
 
 import Button from 'sentry/components/button';
 import Button from 'sentry/components/button';
-import FieldGroup from 'sentry/components/forms/field';
+import FieldGroup from 'sentry/components/forms/fieldGroup';
 import {
 import {
   Panel,
   Panel,
   PanelAlert,
   PanelAlert,

+ 1 - 1
static/app/components/confirmDelete.tsx

@@ -2,7 +2,7 @@ import {Fragment} from 'react';
 
 
 import Alert from 'sentry/components/alert';
 import Alert from 'sentry/components/alert';
 import Confirm from 'sentry/components/confirm';
 import Confirm from 'sentry/components/confirm';
-import FieldGroup from 'sentry/components/forms/field';
+import FieldGroup from 'sentry/components/forms/fieldGroup';
 import Input from 'sentry/components/input';
 import Input from 'sentry/components/input';
 import {t} from 'sentry/locale';
 import {t} from 'sentry/locale';
 
 

+ 1 - 1
static/app/components/featureFeedback/feedbackModal.tsx

@@ -16,7 +16,7 @@ import Alert from 'sentry/components/alert';
 import Button from 'sentry/components/button';
 import Button from 'sentry/components/button';
 import ButtonBar from 'sentry/components/buttonBar';
 import ButtonBar from 'sentry/components/buttonBar';
 import Textarea from 'sentry/components/forms/controls/textarea';
 import Textarea from 'sentry/components/forms/controls/textarea';
-import FieldGroup from 'sentry/components/forms/field';
+import FieldGroup from 'sentry/components/forms/fieldGroup';
 import SelectField from 'sentry/components/forms/fields/selectField';
 import SelectField from 'sentry/components/forms/fields/selectField';
 import {Data} from 'sentry/components/forms/types';
 import {Data} from 'sentry/components/forms/types';
 import ExternalLink from 'sentry/components/links/externalLink';
 import ExternalLink from 'sentry/components/links/externalLink';

+ 1 - 1
static/app/components/forms/fieldFromConfig.tsx

@@ -1,4 +1,4 @@
-import {FieldGroupProps} from 'sentry/components/forms/field/types';
+import {FieldGroupProps} from 'sentry/components/forms/fieldGroup/types';
 import SeparatorField from 'sentry/components/forms/fields/separatorField';
 import SeparatorField from 'sentry/components/forms/fields/separatorField';
 import {Field} from 'sentry/components/forms/types';
 import {Field} from 'sentry/components/forms/types';
 import {Scope} from 'sentry/types';
 import {Scope} from 'sentry/types';

+ 84 - 0
static/app/components/forms/fieldGroup/controlState.tsx

@@ -0,0 +1,84 @@
+import {Fragment} from 'react';
+import styled from '@emotion/styled';
+
+import Spinner from 'sentry/components/forms/spinner';
+import Tooltip from 'sentry/components/tooltip';
+import {IconCheckmark, IconWarning} from 'sentry/icons';
+import {fadeOut, pulse} from 'sentry/styles/animations';
+import space from 'sentry/styles/space';
+
+export interface ControlStateProps {
+  /**
+   * Display the  error indicator
+   */
+  error?: string | boolean;
+  /**
+   * Should hide error message?
+   */
+  hideErrorMessage?: boolean;
+  /**
+   * Display the "was just saved" state
+   */
+  isSaved?: boolean;
+  /**
+   * Display the saving state
+   */
+  isSaving?: boolean;
+}
+
+/**
+ * ControlState (i.e. loading/error icons) for form fields
+ */
+const ControlState = ({
+  isSaving,
+  isSaved,
+  error,
+  hideErrorMessage,
+}: ControlStateProps) => (
+  <Fragment>
+    {isSaving ? (
+      <ControlStateWrapper>
+        <FormSpinner data-test-id="saving" />
+      </ControlStateWrapper>
+    ) : isSaved ? (
+      <ControlStateWrapper>
+        <StyledIconCheckmark color="success" size="sm" />
+      </ControlStateWrapper>
+    ) : null}
+
+    {error ? (
+      <ControlStateWrapper>
+        <Tooltip
+          position="bottom"
+          offset={8}
+          title={!hideErrorMessage && error}
+          forceVisible
+          skipWrapper
+        >
+          <StyledIconWarning color="error" size="sm" />
+        </Tooltip>
+      </ControlStateWrapper>
+    ) : null}
+  </Fragment>
+);
+
+const ControlStateWrapper = styled('div')`
+  display: grid;
+  grid-auto-flow: column;
+  align-items: center;
+  gap: ${space(0.5)};
+`;
+
+const StyledIconCheckmark = styled(IconCheckmark)`
+  animation: ${fadeOut} 0.3s ease 2s 1 forwards;
+`;
+
+const StyledIconWarning = styled(IconWarning)`
+  animation: ${() => pulse(1.15)} 1s ease infinite;
+`;
+
+const FormSpinner = styled(Spinner)`
+  margin-left: 0;
+`;
+
+export default ControlState;

+ 53 - 0
static/app/components/forms/fieldGroup/fieldControl.tsx

@@ -0,0 +1,53 @@
+import styled from '@emotion/styled';
+
+import space from 'sentry/styles/space';
+
+import FieldControlState from './fieldControlState';
+import {FieldGroupProps} from './types';
+
+type FieldControlProps = Pick<
+  FieldGroupProps,
+  | 'alignRight'
+  | 'controlState'
+  | 'flexibleControlStateSize'
+  | 'hideControlState'
+  | 'inline'
+> & {
+  children: React.ReactNode;
+};
+
+const FieldControl = ({
+  inline,
+  alignRight,
+  controlState,
+  children,
+  hideControlState,
+  flexibleControlStateSize,
+}: FieldControlProps) => (
+  <FieldControlWrapper inline={inline}>
+    <FieldControlStyled alignRight={alignRight}>{children}</FieldControlStyled>
+
+    {!hideControlState && (
+      <FieldControlState flexibleControlStateSize={!!flexibleControlStateSize}>
+        {controlState}
+      </FieldControlState>
+    )}
+  </FieldControlWrapper>
+);
+
+export default FieldControl;
+
+const FieldControlWrapper = styled('div')<{inline?: boolean}>`
+  display: flex;
+  flex: 1;
+  ${p => p.inline && `padding-left: ${space(2)}`};
+`;
+
+const FieldControlStyled = styled('div')<{alignRight?: boolean}>`
+  display: flex;
+  flex: 1;
+  flex-direction: column;
+  position: relative;
+  max-width: 100%;
+  ${p => (p.alignRight ? 'align-items: flex-end;' : '')};
+`;

+ 22 - 0
static/app/components/forms/fieldGroup/fieldControlState.tsx

@@ -0,0 +1,22 @@
+import styled from '@emotion/styled';
+
+import space from 'sentry/styles/space';
+
+import {FieldGroupProps} from './types';
+
+type FieldControlStateProps = Pick<FieldGroupProps, 'flexibleControlStateSize'>;
+
+const FieldControlState = styled('div')<FieldControlStateProps>`
+  display: flex;
+  position: relative;
+  flex-shrink: 0;
+  justify-content: end;
+  align-items: center;
+
+  ${p =>
+    p.flexibleControlStateSize
+      ? `&:not(:empty) { margin-left: ${space(1.5)} }`
+      : `width: 24px; margin-left: ${space(0.5)};`};
+`;
+
+export default FieldControlState;

+ 28 - 0
static/app/components/forms/fieldGroup/fieldDescription.tsx

@@ -0,0 +1,28 @@
+import {css} from '@emotion/react';
+import styled from '@emotion/styled';
+
+import space from 'sentry/styles/space';
+
+import {FieldGroupProps} from './types';
+
+type FieldDescriptionProps = Pick<FieldGroupProps, 'inline'>;
+
+const inlineStyle = (p: FieldDescriptionProps) =>
+  p.inline
+    ? css`
+        width: 50%;
+        padding-right: 10px;
+        flex-shrink: 0;
+      `
+    : css`
+        margin-bottom: ${space(1)};
+      `;
+
+const FieldDescription = styled('label')<FieldDescriptionProps>`
+  font-weight: normal;
+  margin-bottom: 0;
+
+  ${inlineStyle};
+`;
+
+export default FieldDescription;

+ 16 - 0
static/app/components/forms/fieldGroup/fieldHelp.tsx

@@ -0,0 +1,16 @@
+import styled from '@emotion/styled';
+
+import space from 'sentry/styles/space';
+
+import {FieldGroupProps} from './types';
+
+type FieldHelpProps = Pick<FieldGroupProps, 'inline' | 'stacked'>;
+
+const FieldHelp = styled('div')<FieldHelpProps>`
+  color: ${p => p.theme.subText};
+  font-size: ${p => p.theme.fontSizeSmall};
+  margin-top: ${p => (p.stacked && !p.inline ? 0 : space(0.5))};
+  line-height: 1.4;
+`;
+
+export default FieldHelp;

+ 19 - 0
static/app/components/forms/fieldGroup/fieldLabel.tsx

@@ -0,0 +1,19 @@
+import isPropValid from '@emotion/is-prop-valid';
+import styled from '@emotion/styled';
+
+import space from 'sentry/styles/space';
+
+import {FieldGroupProps} from './types';
+
+type FieldLabelProps = Pick<FieldGroupProps, 'disabled'>;
+
+const shouldForwardProp = p => p !== 'disabled' && isPropValid(p);
+
+const FieldLabel = styled('div', {shouldForwardProp})<FieldLabelProps>`
+  color: ${p => (!p.disabled ? p.theme.textColor : p.theme.disabled)};
+  display: flex;
+  gap: ${space(0.5)};
+  line-height: 16px;
+`;
+
+export default FieldLabel;

Some files were not shown because too many files changed in this diff