gatsby-core-theme 44.4.52 → 44.5.0-poc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/.ci.yml +26 -0
  2. package/CHANGELOG.md +30 -126
  3. package/gatsby-browser.js +100 -48
  4. package/gatsby-node.mjs +21 -25
  5. package/package.json +1 -1
  6. package/release.config.js +5 -0
  7. package/src/components/atoms/author/index.js +5 -6
  8. package/src/components/atoms/collapse/collapse.test.js +26 -113
  9. package/src/components/atoms/collapse/index.js +1 -23
  10. package/src/components/molecules/comment/comment.module.scss +57 -7
  11. package/src/components/molecules/comment/index.js +79 -5
  12. package/src/components/molecules/header/variants/operator/template-one-two/index.js +3 -4
  13. package/src/components/molecules/header/variants/operator/template-one-two/template-one-two.stories.js +3 -4
  14. package/src/components/molecules/header/variants/slot/template-one/index.js +3 -4
  15. package/src/components/molecules/header/variants/slot/template-one/template-one.stories.js +3 -4
  16. package/src/components/molecules/leave-comment-form/index.js +0 -1
  17. package/src/components/organisms/anchor/template-one/anchor.module.scss +11 -19
  18. package/src/components/organisms/archive/index.js +2 -5
  19. package/src/components/organisms/comments/comment-tree/index.js +7 -8
  20. package/src/components/organisms/comments/index.js +24 -13
  21. package/src/components/organisms/cookie-consent/index.js +34 -48
  22. package/src/components/organisms/form/fields/fields.module.scss +2 -5
  23. package/src/components/organisms/form/fields/index.js +4 -2
  24. package/src/components/organisms/form/form.module.scss +39 -76
  25. package/src/components/organisms/form/index.js +1 -0
  26. package/src/constants/forms.js +1 -1
  27. package/src/helpers/tracker.mjs +2 -2
  28. package/src/resolver/redirect.mjs +0 -23
  29. package/src/resolver/redirect.test.js +1 -65
  30. package/src/components/atoms/comment-votes/comment-votes.module.scss +0 -34
  31. package/src/components/atoms/comment-votes/index.js +0 -92
  32. package/src/components/organisms/comments/comment-tree/comment-tree.module.scss +0 -47
  33. package/src/context/VotesProvider.js +0 -49
@@ -1,16 +1,15 @@
1
1
  import React from "react";
2
2
 
3
3
  import PropTypes, { arrayOf } from 'prop-types';
4
+ import keygen from '~helpers/keygen';
4
5
  import Comment from "../../../molecules/comment";
5
6
 
6
- import styles from './comment-tree.module.scss';
7
-
8
- const CommentTree = React.memo(({ pageContext, comment, authors, depth = 0 }) =>
9
- <div key={comment.comment_id} className={`${styles?.[`comment_${depth}`]} ${depth > 0 && styles.isReply}`}>
10
- <Comment pageContext={pageContext} comment={comment} authors={authors} isReply={depth > 0} />
7
+ const CommentTree = React.memo(({ pageContext, comment, authors, depth = 0, cookieComments }) =>
8
+ <div key={keygen()} style={{ marginLeft: depth * 56 }}>
9
+ <Comment pageContext={pageContext} comment={comment} authors={authors} isReply={depth > 0} userInteractions={cookieComments} />
11
10
  {comment.replies?.map(reply => (
12
11
  <CommentTree
13
- key={reply.comment_id}
12
+ key={keygen()}
14
13
  comment={reply}
15
14
  authors={authors}
16
15
  depth={depth + 1}
@@ -23,11 +22,11 @@ const CommentTree = React.memo(({ pageContext, comment, authors, depth = 0 }) =>
23
22
  CommentTree.propTypes = {
24
23
  pageContext: PropTypes.shape({}),
25
24
  comment: PropTypes.shape({
26
- replies: arrayOf(PropTypes.shape({})),
27
- comment_id: PropTypes.number
25
+ replies: arrayOf(PropTypes.shape({}))
28
26
  }),
29
27
  authors: PropTypes.shape({}),
30
28
  depth: PropTypes.number,
29
+ cookieComments: PropTypes.arrayOf(PropTypes.string)
31
30
  };
32
31
 
33
32
  export default CommentTree;
@@ -1,28 +1,39 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import CommentTree from './comment-tree';
4
4
  import LeaveCommentForm from '../../molecules/leave-comment-form';
5
- import { VotesProvider } from '../../../context/VotesProvider';
6
5
 
7
6
  const Comments = ({ pageContext }) => {
8
7
  const { comments, authors } = pageContext;
8
+ const [cookieComments, setCookieComments] = useState([]);
9
+
10
+ useEffect(() => {
11
+ const storedVotes =
12
+ document.cookie
13
+ .split('; ')
14
+ .find((row) => row.startsWith('comments='))
15
+ ?.split('=')[1]
16
+ ?.split(',')
17
+ .filter(Boolean) || [];
18
+
19
+ setCookieComments(storedVotes);
20
+ }, []);
9
21
 
10
22
  if (!comments) return null;
11
23
 
12
24
  return (
13
25
  <div>
14
26
  <LeaveCommentForm page={pageContext.page} />
15
- <VotesProvider>
16
- {comments.map((comment) => (
17
- <CommentTree
18
- key={comment.comment_id}
19
- pageContext={pageContext}
20
- comment={comment}
21
- authors={authors?.authors}
22
- depth={0}
23
- />
24
- ))}
25
- </VotesProvider>
27
+ {comments.map((comment) => (
28
+ <CommentTree
29
+ key={comment.comment_id}
30
+ pageContext={pageContext}
31
+ comment={comment}
32
+ authors={authors?.authors}
33
+ depth={0}
34
+ cookieComments={cookieComments}
35
+ />
36
+ ))}
26
37
  </div>
27
38
  );
28
39
  };
@@ -1,78 +1,70 @@
1
1
  /* eslint-disable react-hooks/exhaustive-deps */
2
2
  /* eslint-disable jsx-a11y/click-events-have-key-events */
3
3
  /* eslint-disable import/no-extraneous-dependencies */
4
- import React, { useState, useEffect, lazy, Suspense } from "react";
5
- import PropTypes from "prop-types";
4
+ import React, { useState, useEffect } from 'react';
5
+ import PropTypes from 'prop-types';
6
6
 
7
- import useTranslate from "~hooks/useTranslate/useTranslate";
8
- import { setCookie, getCookie } from "~helpers/cookies";
9
- import styles from "./cookie-consent.module.scss";
7
+ import useTranslate from '~hooks/useTranslate/useTranslate';
8
+ import { setCookie, getCookie } from '~helpers/cookies';
9
+ import CookieModal from '../../molecules/cookie-modal';
10
+ import styles from './cookie-consent.module.scss';
10
11
 
11
12
  const CookieConsent = ({
12
- acceptText = "Accept",
13
- rejectText = "Reject",
13
+ acceptText = 'Accept',
14
+ rejectText = 'Reject',
14
15
  settingsCookie,
15
16
  children,
16
- cookieName = "CookieConsent",
17
- logo = "/images/logo.svg",
17
+ cookieName = 'CookieConsent',
18
+ logo = '/images/logo.svg',
18
19
  icon = null,
19
- showRejectButton = false,
20
+ showRejectButton=false
20
21
  }) => {
21
22
  const [showModal, setShowModal] = useState(false);
22
23
 
23
24
  const [showCookieConsent, setShowCookieConsent] = useState(false);
24
25
 
25
- const CookieModal = lazy(() => import("../../molecules/cookie-modal"));
26
-
27
26
  // when user declines
28
27
  const handleDecline = () => {
29
- setCookie(cookieName, false, 365, "/");
30
- setCookie("showCookie", false, 365, "/");
28
+ setCookie(cookieName, false, 365, '/');
29
+ setCookie('showCookie', false, 365, '/');
31
30
  setShowCookieConsent(false);
32
31
  setShowModal(false);
33
- document.body.style.overflow = "auto";
32
+ document.body.style.overflow = 'auto';
34
33
  };
35
34
 
36
35
  // when user accepts
37
36
  const handleAccept = () => {
38
- setCookie(cookieName, true, 365, "/");
39
- setCookie("showCookie", false, 365, "/");
37
+ setCookie(cookieName, true, 365, '/');
38
+ setCookie('showCookie', false, 365, '/');
40
39
  setShowCookieConsent(false);
41
40
  setShowModal(false);
42
- document.body.style.overflow = "auto";
41
+ document.body.style.overflow = 'auto';
43
42
  };
44
43
 
45
44
  const handleShowModalClick = () => {
46
45
  setShowModal(!showModal);
47
- document.body.style.overflow = "hidden";
46
+ document.body.style.overflow = 'hidden';
48
47
  };
49
48
 
50
49
  const closeModal = () => {
51
50
  setShowModal(false);
52
- document.body.style.overflow = "auto";
51
+ document.body.style.overflow = 'auto';
53
52
  };
54
53
 
55
54
  useEffect(() => {
56
- if (typeof window !== `undefined` && getCookie("showCookie") !== "false") {
55
+ if (typeof window !== `undefined` && getCookie('showCookie') !== "false") {
57
56
  setShowCookieConsent(true);
58
57
  }
59
58
  }, []);
60
59
 
61
- const settingCookieText = useTranslate(
62
- "cookie_setting_button",
63
- "Cookie Setting"
64
- );
60
+ const settingCookieText = useTranslate('cookie_setting_button', 'Cookie Setting');
65
61
 
66
62
  return (
67
63
  <>
68
- <div
69
- className={`${styles.cookieConsent} ${
70
- (showCookieConsent && styles.show) || ""
71
- }`}
72
- >
73
- <div className={`${styles?.consent || ""}`}>
74
- <div className={styles?.content || ""}>{children}</div>
75
- <div className={styles?.buttonsContainer || ""}>
64
+ <div className={`${styles.cookieConsent} ${(showCookieConsent && styles.show) || ''}`}>
65
+ <div className={`${styles?.consent || ''}`}>
66
+ <div className={styles?.content || ''}>{children}</div>
67
+ <div className={styles?.buttonsContainer || ''}>
76
68
  {settingsCookie && (
77
69
  <button
78
70
  onClick={handleShowModalClick}
@@ -98,22 +90,20 @@ const CookieConsent = ({
98
90
  className="cookie-consent-gtm btn-cta"
99
91
  type="button"
100
92
  >
101
- {useTranslate("cookie_accept_button", acceptText)}
93
+ {useTranslate('cookie_accept_button', acceptText)}
102
94
  {icon && icon}
103
95
  </button>
104
96
  </div>
105
97
  </div>
106
98
  </div>
107
99
  {settingsCookie && showModal && (
108
- <Suspense fallback={null}>
109
- <CookieModal
110
- logo={logo}
111
- hide={!showModal}
112
- handleAcceptCookies={handleAccept}
113
- handleDeclineCookies={handleDecline}
114
- closeModal={closeModal}
115
- />
116
- </Suspense>
100
+ <CookieModal
101
+ logo={logo}
102
+ hide={!showModal}
103
+ handleAcceptCookies={handleAccept}
104
+ handleDeclineCookies={handleDecline}
105
+ closeModal={closeModal}
106
+ />
117
107
  )}
118
108
  </>
119
109
  );
@@ -126,11 +116,7 @@ CookieConsent.propTypes = {
126
116
  settingsCookie: PropTypes.bool,
127
117
  cookieName: PropTypes.string,
128
118
  logo: PropTypes.string,
129
- children: PropTypes.oneOfType([
130
- PropTypes.arrayOf(PropTypes.node),
131
- PropTypes.node,
132
- PropTypes.any,
133
- ]),
119
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node, PropTypes.any]),
134
120
  icon: PropTypes.node,
135
121
  };
136
122
 
@@ -29,7 +29,7 @@
29
29
  @include flex-align(flex-end, flex-start);
30
30
 
31
31
  > span {
32
- font-size: 1.2rem;
32
+ font-size: 1.4rem;
33
33
  font-weight: 400;
34
34
  line-height: 2.2rem;
35
35
  }
@@ -105,7 +105,7 @@
105
105
  cursor: pointer;
106
106
  width: 4.8rem;
107
107
  inset: 0;
108
- background-color: #AFAFB0;
108
+ background-color: #ccc;
109
109
  transition: 0.4s;
110
110
  border-radius: 3.4rem;
111
111
  height: 2.4rem;
@@ -137,9 +137,6 @@ input:checked + .slider::before {
137
137
 
138
138
  .switchLabel{
139
139
  margin-left: 4.5rem;
140
- font-size: 1.6rem;
141
- font-weight: 400;
142
- color: #3C3C40;
143
140
  }
144
141
 
145
142
  .errorMsg {
@@ -37,7 +37,7 @@ const getField = (field, handleChange, elements, state) => {
37
37
  <span>{`${elements[id].length}/${field.maxLength}`}</span>
38
38
  )}
39
39
  {field.minlength && (
40
- <span className={styles.lengthWarning}>{`Minimum ${field.minlength} chars`}</span>
40
+ <span className={styles.lengthWarning}>{`Minimum ${field.minlength} words`}</span>
41
41
  )}
42
42
  {field.errorMsg && <span className={styles.errorMsg}>{field.errorMsg}</span>}
43
43
  </div>
@@ -56,7 +56,9 @@ const getField = (field, handleChange, elements, state) => {
56
56
  required={!!option?.required}
57
57
  />
58
58
  <span
59
- className={`${styles.checkboxLabel || ''} ${styles.slider}`}
59
+ className={`${styles.checkboxLabel || ''} ${styles.slider} ${
60
+ (!state.isValid && !elements[option.id].length && styles.invalid) || ''
61
+ }`}
60
62
  />
61
63
  <span className={styles.switchLabel}>{generatePlaceholderString(
62
64
  useTranslate(option.translationKey, option.label),
@@ -228,89 +228,58 @@
228
228
  padding: 0;
229
229
  margin-top: 3.5rem;
230
230
 
231
- input:not([type="range"]),
232
- textarea,
233
- select {
234
- background: #fff !important;
235
- font-size: 1.4rem;
236
- line-height: 2.1rem;
237
- padding: 1.6rem;
238
- max-width: 100%;
239
- outline: none;
240
- border-radius: 0.8rem;
241
- border: 1px solid #E2E8F0 !important;
242
- color: #0F172A !important;
243
- }
244
-
245
-
246
231
  > form{
247
- display: flex;
248
- grid-template-columns: 1fr 1fr;
249
-
250
- @include min(tablet){
251
232
  display: grid;
252
- gap: 1.6rem;
253
- }
254
-
255
- label{
256
- font-size: 1.6rem;
257
- font-weight: 600;
258
- color: #262629;
259
- }
233
+ grid-template-columns: 1fr 1fr;
260
234
 
261
- div > input ~ span, div > textarea ~ span{
262
- display: none;
263
- }
264
-
265
- input:user-invalid{
266
- border: 1.5px solid var(--comment-input-error, #DD4B39) !important;
267
- }
235
+ div > input ~ span, div > textarea ~ span{
236
+ display: none;
237
+ }
268
238
 
269
- textarea:user-invalid{
270
- border: 1.5px solid var(--comment-input-error, #DD4B39) !important;
271
- }
239
+ input:user-invalid{
240
+ border: .15rem solid var(--comment-input-error, #DD4B39);
241
+ }
272
242
 
273
- input:user-invalid ~ span{
274
- display: block;
275
- }
243
+ textarea:user-invalid{
244
+ border: .15rem solid var(--comment-input-error, #DD4B39);
245
+ }
276
246
 
277
- textarea:user-invalid ~ span{
278
- display: block;
279
- }
247
+ input:user-invalid ~ span{
248
+ display: block;
249
+ }
280
250
 
281
- textarea:not(:placeholder-shown):invalid ~ span{
282
- display: block;
283
- }
251
+ textarea:user-invalid ~ span{
252
+ display: block;
253
+ }
284
254
 
285
- input:not([type='checkbox'], :placeholder-shown):invalid ~ span{
286
- display: block;
287
- }
255
+ textarea:not(:placeholder-shown):invalid ~ span{
256
+ display: block;
257
+ }
288
258
 
289
- input:not(:placeholder-shown):invalid, textarea:not(:placeholder-shown):invalid{
290
- border: 1.5px solid var(--comment-input-error, #DD4B39) !important;
291
- }
259
+ input:not([type='checkbox'], :placeholder-shown):invalid ~ span{
260
+ display: block;
261
+ }
292
262
 
293
- > .formButton{
294
- border: .2rem solid #161128;
295
- padding: 8px 16px !important;
296
- margin-left: auto;
297
- border-radius: 5rem;
298
- font-size: 1.4rem;
299
- font-weight: 700;
300
- background: transparent !important;
301
- text-align: center !important;
302
- line-height: 2.2rem;
303
- text-transform: capitalize;
304
- color: #161128 !important;
305
- height: 4rem !important;
306
- grid-column: 1 / -1;
307
- width: 100%;
308
- margin-bottom: 3.4rem;
263
+ input:not(:placeholder-shown):invalid, textarea:not(:placeholder-shown):invalid{
264
+ border: .15rem solid var(--comment-input-error, #DD4B39);
265
+ }
309
266
 
310
- @include min(tablet){
267
+ > .formButton{
268
+ border: .2rem solid #161128;
269
+ padding: 8px 16px !important;
311
270
  width: auto !important;
271
+ margin-left: auto;
272
+ border-radius: 5rem;
273
+ font-size: 1.4rem;
274
+ font-weight: 700;
275
+ background: transparent !important;
276
+ text-align: center !important;
277
+ line-height: 2.2rem;
278
+ text-transform: capitalize;
279
+ color: #161128 !important;
280
+ height: 4rem !important;
281
+ grid-column: 1 / -1;
312
282
  }
313
- }
314
283
  }
315
284
 
316
285
  div:has(>input[type="checkbox"] ) {
@@ -319,12 +288,6 @@
319
288
  grid-template-columns: 1.3rem 1fr;
320
289
  }
321
290
 
322
- input[type="checkbox"] + label{
323
- font-size: 1.4rem;
324
- font-weight: 400;
325
- line-height: 2.2rem;
326
- }
327
-
328
291
  .alertDanger, .alertSuccess, .alertWarning {
329
292
  background-color: var(--alert-error-bg, #FEE2E2);
330
293
  color: var(--alert-error-text, #09090B);
@@ -152,6 +152,7 @@ const FormComponent = ({
152
152
  className={formOptions.twoCol ? styles.twoCol || '' : styles.singleCol || ''}
153
153
  target="_self"
154
154
  >
155
+ {process.env.GA_TRACKING_ID}
155
156
  {formOptions.fields?.map((field) => {
156
157
  const { id, translationKey, label, validations } = field;
157
158
 
@@ -145,7 +145,7 @@ export const commentForm = {
145
145
  translationKey: 'textarea_label',
146
146
  twoCol: false,
147
147
  required: true,
148
- minlength: 50,
148
+ minlength: 15,
149
149
  errorMsg: "Please enter a comment."
150
150
  },
151
151
  {
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-nested-ternary */
2
2
  /* eslint-disable no-underscore-dangle */
3
- import { generateTrackerLink } from "./generators.mjs";
4
- import { stripSuffixSlash } from "./strings.mjs";
3
+ import { generateTrackerLink } from "~helpers/generators";
4
+ import { stripSuffixSlash } from "~helpers/strings";
5
5
 
6
6
  export function getTrackerName(operator, page, path) {
7
7
  const trackerLinks = operator ? Object.keys(operator.links) : [];
@@ -1,6 +1,5 @@
1
1
  import fs from "fs";
2
2
  import chalk from "chalk";
3
- import { getTrackerName } from '../helpers/tracker.mjs';
4
3
 
5
4
  // eslint-disable-next-line import/prefer-default-export
6
5
  export function generateRedirects(siteSettingsData) {
@@ -51,25 +50,3 @@ export function generateRedirects(siteSettingsData) {
51
50
 
52
51
  stream.end();
53
52
  }
54
-
55
- export function generatePrettyLinkRedirects( trackingPages = [] ) {
56
- if(!trackingPages.length) return;
57
-
58
- const stream = fs.createWriteStream("affiliate-rewrites.conf");
59
-
60
- // eslint-disable-next-line no-console
61
- console.log(
62
- chalk.magenta("info") + chalk.whiteBright(" creating pretty link rewrite rules")
63
- );
64
-
65
- trackingPages.filter(tracker => tracker?.operator?.status === 'active').forEach(({ path, page, operator }) => {
66
- const tracker = getTrackerName(operator, page, path);
67
-
68
- stream.write(`location ${path} {
69
- add_header X-Robots-Tag "noindex, nofollow";
70
- return 302 ${tracker.value};
71
- }\n`)
72
- })
73
-
74
- stream.end();
75
- }
@@ -1,6 +1,5 @@
1
1
  import fs from "fs";
2
- import { generateRedirects, generatePrettyLinkRedirects } from "./redirect.mjs";
3
- import { getTrackerName } from "../helpers/tracker.mjs";
2
+ import { generateRedirects } from "./redirect.mjs";
4
3
 
5
4
  jest.mock("fs", () => ({
6
5
  createWriteStream: jest.fn(() => ({
@@ -8,9 +7,6 @@ jest.mock("fs", () => ({
8
7
  end: jest.fn(),
9
8
  })),
10
9
  }));
11
- jest.mock("../helpers/tracker.mjs", () => ({
12
- getTrackerName: jest.fn(),
13
- }));
14
10
 
15
11
  describe("generateRedirects", () => {
16
12
  let siteSettingsData; let mockStream;
@@ -101,63 +97,3 @@ describe("generateRedirects", () => {
101
97
  expect(mockStream.end).toHaveBeenCalled();
102
98
  });
103
99
  });
104
-
105
- describe("generatePrettyLinkRedirects", () => {
106
- let mockStream;
107
-
108
- beforeEach(() => {
109
- mockStream = {
110
- write: jest.fn(),
111
- end: jest.fn(),
112
- };
113
-
114
- fs.createWriteStream.mockReturnValue(mockStream);
115
- jest.clearAllMocks();
116
- });
117
-
118
- it("should do nothing if trackingPages is empty", () => {
119
- generatePrettyLinkRedirects([]);
120
- expect(fs.createWriteStream).not.toHaveBeenCalled();
121
- });
122
-
123
- it("should generate pretty link redirect rules for active trackers", () => {
124
- getTrackerName.mockReturnValue({ value: "https://example.com/offer" });
125
-
126
- const trackingPages = [
127
- {
128
- path: "/goto/leovegas",
129
- page: "home",
130
- operator: { status: "active", name: "LeoVegas" },
131
- },
132
- ];
133
-
134
- generatePrettyLinkRedirects(trackingPages);
135
-
136
- expect(fs.createWriteStream).toHaveBeenCalledWith("affiliate-rewrites.conf");
137
-
138
- expect(mockStream.write).toHaveBeenCalledWith(
139
- `location /goto/leovegas {
140
- add_header X-Robots-Tag "noindex, nofollow";
141
- return 302 https://example.com/offer;
142
- }\n`
143
- );
144
-
145
- expect(mockStream.end).toHaveBeenCalled();
146
- });
147
-
148
- it("should skip trackers with inactive operator status", () => {
149
- const trackingPages = [
150
- {
151
- path: "/goto/unibet",
152
- page: "home",
153
- operator: { status: "inactive", name: "Unibet" },
154
- },
155
- ];
156
-
157
- generatePrettyLinkRedirects(trackingPages);
158
-
159
- expect(fs.createWriteStream).toHaveBeenCalledWith("affiliate-rewrites.conf");
160
- expect(mockStream.write).not.toHaveBeenCalled();
161
- expect(mockStream.end).toHaveBeenCalled();
162
- });
163
- });
@@ -1,34 +0,0 @@
1
- .buttonGroup{
2
- background: #EAE5E0;
3
- font-size: 1.2rem;
4
- padding: .5rem .8rem;
5
- height: 2.8rem;
6
- gap: .4rem;
7
- color: #0F172A;
8
-
9
- @include flex-align(center, center);
10
-
11
- &.left{
12
- border-bottom-left-radius: 5rem;
13
- border-top-left-radius: 5rem;
14
- padding-right: 0;
15
- }
16
-
17
- &.right{
18
- border-bottom-right-radius: 5rem;
19
- border-top-right-radius: 5rem;
20
- }
21
- }
22
-
23
- .buttonGroupIcon{
24
- width: 1.6rem;
25
- height: 1.6rem;
26
- }
27
-
28
- .buttonGroup[disabled]{
29
- cursor: default !important;
30
- }
31
-
32
- .disabled > *{
33
- opacity: .3;
34
- }