Passed
Push — dev ( f7ebe6...6ec2f8 )
by
unknown
05:02
created

resources/assets/js/components/H2Components/Dialog.tsx   A

Complexity

Total Complexity 1
Complexity/F 0

Size

Lines of Code 189
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 1
eloc 144
mnd 1
bc 1
fnc 0
dl 0
loc 189
rs 10
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
1
import * as React from "react";
2
import {
3
  h2ComponentDialogLoad,
4
  h2ComponentDialogLoadResize,
5
  h2ComponentDialogEnableTrigger,
6
} from "@hydrogen-design-system/system/dist/import/latest/components/dialog/scripts/dialog";
7
import { defineMessages, useIntl } from "react-intl";
8
import { GeneralProps, GeneralBtnProps } from "./utils";
9
10
const messages = defineMessages({
11
  closeDialog: {
12
    id: "hydrogen.dialog.close",
13
    defaultMessage: "Close",
14
  },
15
});
16
17
interface DialogContext {
18
  /** The dialogs id. */
19
  id: string;
20
}
21
22
const DialogContext = React.createContext<DialogContext | undefined>(undefined);
23
24
/**
25
 * This Context hook allows our child components to easily reach
26
 * into the Tabs context and get the pieces it needs.
27
 *
28
 * Bonus: it even makes sure the component is used within a
29
 * Dialog component!
30
 */
31
const useDialogContext = (): Partial<DialogContext> => {
32
  const context = React.useContext(DialogContext);
33
  if (!context) {
34
    throw new Error("This component must be used within a <Dialog> component.");
35
  }
36
  return context;
37
};
38
39
const Actions: React.FunctionComponent<GeneralProps> = (props) => {
40
  useDialogContext(); // Ensures sub-component can only be used within the Dialog component.
41
  const { children } = props;
42
  return (
43
    <div data-h2-dialog-actions {...props}>
44
      {children}
45
    </div>
46
  );
47
};
48
49
const ActionBtn: React.FunctionComponent<GeneralBtnProps> = (props) => {
50
  const { id } = useDialogContext();
51
  const { buttonStyling, type, onClick, children } = props;
52
  const ref = React.useRef(null);
53
  React.useEffect((): void => {
54
    h2ComponentDialogEnableTrigger("latest", ref.current);
55
  });
56
  return (
57
    <button
58
      data-h2-dialog-trigger={`${id}`}
59
      data-h2-button={buttonStyling}
60
      ref={ref}
61
      type={type || "button"}
62
      onClick={onClick}
63
      {...props}
64
    >
65
      {children}
66
    </button>
67
  );
68
};
69
70
const Content: React.FunctionComponent<GeneralProps> = (props) => {
71
  const { id } = useDialogContext();
72
  const { className, children } = props;
73
  return (
74
    <div
75
      data-h2-dialog-content
76
      id={`${id}Content`}
77
      className={className}
78
      {...props}
79
    >
80
      {children}
81
    </div>
82
  );
83
};
84
85
const Header: React.FunctionComponent<GeneralProps> = (props) => {
86
  useDialogContext(); // Ensures sub-component can only be used within the Dialog component.
87
  const { className, children } = props;
88
  return (
89
    <div data-h2-dialog-title className={className} {...props}>
90
      {children}
91
    </div>
92
  );
93
};
94
95
interface OverlayProps {
96
  overlay?: string;
97
}
98
99
const Overlay: React.FunctionComponent<OverlayProps> = (props) => {
100
  const { overlay } = props;
101
  return <div data-h2-dialog-overlay={`${overlay || "black, .9"}`} />;
102
};
103
104
const Title: React.FunctionComponent<GeneralProps> = (props) => {
105
  const { id } = useDialogContext();
106
  const { className, children } = props;
107
  return (
108
    <h5 data-h2-focus id={`${id}Title`} className={className} {...props}>
109
      {children}
110
    </h5>
111
  );
112
};
113
114
interface TriggerProps extends GeneralProps, GeneralBtnProps {
115
  id: string;
116
}
117
118
/** This Trigger component opens the dialog and sits outside the main dialog component */
119
const Trigger: React.FunctionComponent<TriggerProps> = (props) => {
120
  const { id, buttonStyling, className, children } = props;
121
  const ref = React.useRef(null);
122
  React.useEffect((): void => {
123
    h2ComponentDialogEnableTrigger("latest", ref.current);
124
  });
125
  return (
126
    <button
127
      data-h2-button={buttonStyling}
128
      ref={ref}
129
      data-h2-dialog-trigger={`${id}`}
130
      type="button"
131
      className={className}
132
      {...props}
133
    >
134
      {children}
135
    </button>
136
  );
137
};
138
139
interface DialogComposition {
140
  Actions: React.FunctionComponent<GeneralProps>;
141
  ActionBtn: React.FunctionComponent<GeneralBtnProps>;
142
  Content: React.FunctionComponent<GeneralProps>;
143
  Header: React.FunctionComponent<GeneralProps>;
144
  Overlay: React.FunctionComponent<OverlayProps>;
145
  Title: React.FunctionComponent<GeneralProps>;
146
  Trigger: React.FunctionComponent<TriggerProps>;
147
}
148
149
const Dialog: React.FunctionComponent<DialogContext> & DialogComposition = (
150
  props,
151
) => {
152
  const { id, children } = props;
153
  React.useEffect(() => {
154
    h2ComponentDialogLoad();
155
    h2ComponentDialogLoadResize();
156
    h2ComponentDialogEnableTrigger();
157
  });
158
  return (
159
    <DialogContext.Provider value={props}>
160
      <div
161
        aria-hidden="true"
162
        aria-describedby={`${id}Content`}
163
        aria-labelledby={`${id}Title`}
164
        data-h2-dialog={id}
165
        tabIndex={-1}
166
        role="dialog"
167
        {...props}
168
      >
169
        <div data-h2-dialog-wrapper {...props}>
170
          {children}
171
        </div>
172
      </div>
173
    </DialogContext.Provider>
174
  );
175
};
176
177
// We expose the children components here, as properties.
178
// Using the dot notation we explicitly set the composition relationships,
179
// btw the Dialog component and its sub components.
180
Dialog.Actions = Actions;
181
Dialog.ActionBtn = ActionBtn;
182
Dialog.Content = Content;
183
Dialog.Header = Header;
184
Dialog.Overlay = Overlay;
185
Dialog.Title = Title;
186
Dialog.Trigger = Trigger;
187
188
export default Dialog;
189