Quellcode durchsuchen

Native toggle component (#3209)

Jaco Greeff vor 4 Jahren
Ursprung
Commit
0c5f2754cf

+ 2 - 2
packages/apps/webpack.base.config.js

@@ -157,13 +157,13 @@ function createWebpack (ENV, context) {
             chunks: 'initial',
             enforce: true,
             name: 'other.01',
-            test: /node_modules\/(@babel|ansi-styles|asn1|browserify-|chalk|color|color-|crypto-browserify|des\.js|diffie-hellman|elliptic|hash|hmac-drbg|js-sha3|lodash|md5|memoizee|miller-rabin|object-|path-|parse-asn1|pbkdf2|process|public-encrypt|query-string|ripemd160|readable-stream|regenerator-runtime|rtcpeerconnection-shim|stream-browserify|store|timers-browserify|tslib|unified|unist-util|util|vfile|vm-browserify|webrtc-adapter|whatwg-fetch|xxhashjs)/
+            test: /node_modules\/(@babel|ansi-styles|asn1|browserify-|chalk|color|color-|crypto-browserify|des\.js|diffie-hellman|elliptic|event-emitter|events|eventemitter3|hash|hmac-drbg|js-sha3|lodash|md5|memoizee|miller-rabin|object-|path-|parse-asn1|pbkdf2|process|public-encrypt|query-string|ripemd160|readable-stream|regenerator-runtime|rtcpeerconnection-shim|stream-browserify|store|timers-browserify|tslib|unified|unist-util|util|vfile|vm-browserify|webrtc-adapter|whatwg-fetch|xxhashjs)/
           },
           vendor02: {
             chunks: 'initial',
             enforce: true,
             name: 'other.02',
-            test: /node_modules\/(attr-accept|base-x|base64-js|blakejs|bip39|bip66|bn\.js|brorand|buffer|camelcase|cipher-base|core-js|core-util|create-|cuint|decode-uri|deep-equal|define-properties|detect-browser|es-abstract|es5-ext|es6-symbol|event-emitter|events|eventemitter3|extend|function-bind|has-symbols|history|html-parse|ieee754|ip-|is-|minimalistic-crypto-utils|moment|next-tick|node-libs-browser|randombytes|randomfill|regexp|rxjs|safe-buffer|scheduler|sdp|secp256k1|setimmediate|sha\.js|through)/
+            test: /node_modules\/(attr-accept|base-x|base64-js|blakejs|bip39|bip66|bn\.js|brorand|buffer|camelcase|cipher-base|core-js|core-util|create-|cuint|decode-uri|deep-equal|define-properties|detect-browser|es-abstract|es5-ext|es6-symbol|extend|function-bind|has-symbols|history|html-parse|ieee754|ip-|is-|minimalistic-crypto-utils|moment|next-tick|node-libs-browser|randombytes|randomfill|regexp|rxjs|safe-buffer|scheduler|sdp|secp256k1|setimmediate|sha\.js|through)/
           }
         }
       }

+ 1 - 1
packages/page-js/src/constants.tsx

@@ -2,7 +2,7 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import { StrictLabelProps } from 'semantic-ui-react/dist/commonjs/elements/Label';
+import type { StrictLabelProps } from 'semantic-ui-react/dist/commonjs/elements/Label';
 
 export const STORE_EXAMPLES = 'polkadot-app-js-examples';
 export const STORE_SELECTED = 'polkadot-app-js-selected';

+ 2 - 2
packages/page-js/src/types.ts

@@ -2,8 +2,8 @@
 // This software may be modified and distributed under the terms
 // of the Apache-2.0 license. See the LICENSE file for details.
 
-import { SemanticShorthandItem } from 'semantic-ui-react/dist/commonjs/generic';
-import { LabelProps } from 'semantic-ui-react/dist/commonjs/elements/Label';
+import type { SemanticShorthandItem } from 'semantic-ui-react/dist/commonjs/generic';
+import type { LabelProps } from 'semantic-ui-react/dist/commonjs/elements/Label';
 
 export type LogType = 'error' | 'log';
 

+ 3 - 4
packages/page-settings/src/SelectUrl.tsx

@@ -75,13 +75,12 @@ function SelectUrl ({ className = '', onChange }: Props): React.ReactElement<Pro
   }, [info]);
 
   const _onChangeUrl = useCallback(
-    (url: string): void =>
-      setInfo((info: State) => ({ ...info, ...makeUrl(url) })),
+    (url: string) => setInfo((info: State) => ({ ...info, ...makeUrl(url) })),
     []
   );
 
   const _onChangeCustom = useCallback(
-    (isCustom: boolean): void => setInfo({
+    (isCustom: boolean) => setInfo({
       ...makeUrl(
         isCustom
           ? info.url
@@ -116,9 +115,9 @@ function SelectUrl ({ className = '', onChange }: Props): React.ReactElement<Pro
       }</div>
       <Toggle
         className='settings--customToggle'
-        defaultValue={isCustom}
         label={t<string>('custom endpoint')}
         onChange={_onChangeCustom}
+        value={isCustom}
       />
     </div>
   );

+ 2 - 3
packages/page-staking/src/Targets/Validator.tsx

@@ -7,7 +7,7 @@ import { ValidatorInfo } from '../types';
 
 import React, { useCallback, useEffect, useState } from 'react';
 import { ApiPromise } from '@polkadot/api';
-import { AddressSmall, Badge, Icon, Toggle } from '@polkadot/react-components';
+import { AddressSmall, Badge, Checkbox, Icon } from '@polkadot/react-components';
 import { FormatBalance } from '@polkadot/react-query';
 import { useApi, useCall } from '@polkadot/react-hooks';
 import { formatNumber } from '@polkadot/util';
@@ -125,8 +125,7 @@ function Validator ({ canSelect, filterName, info, isNominated, isSelected, togg
       <td className='number together'>{!rewardPayout.isZero() && <FormatBalance value={rewardPayout} />}</td>
       <td>
         {(canSelect || isSelected) && (
-          <Toggle
-            asSwitch={false}
+          <Checkbox
             onChange={_toggleSelected}
             value={isSelected}
           />

+ 63 - 0
packages/react-components/src/Checkbox.tsx

@@ -0,0 +1,63 @@
+// Copyright 2017-2020 @polkadot/react-components authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import React, { useCallback } from 'react';
+import styled from 'styled-components';
+
+import Icon from './Icon';
+
+interface Props {
+  className?: string;
+  isDisabled?: boolean;
+  label: React.ReactNode;
+  onChange?: (isChecked: boolean) => void;
+  value?: boolean;
+}
+
+function Checkbox ({ className = '', isDisabled, label, onChange, value }: Props): React.ReactElement<Props> {
+  const _onClick = useCallback(
+    (): void => {
+      !isDisabled && onChange && onChange(!value);
+    },
+    [isDisabled, onChange, value]
+  );
+
+  return (
+    <div className={`ui--Checkbox${isDisabled ? ' isDisabled' : ''} ${className}`}>
+      <Icon
+        color={value ? 'normal' : 'transparent'}
+        icon='check'
+        onClick={_onClick}
+      />
+      {label && <label>{label}</label>}
+    </div>
+  );
+}
+
+export default React.memo(styled(Checkbox)`
+  &.isDisabled {
+    opacity: 0.5;
+  }
+
+  &:not(.isDisabled) {
+    cursor: pointer;
+  }
+
+  > label {
+    color: rgba(78, 78, 78, 0.75);
+    display: inline-block;
+    margin: 0 0.5rem;
+    opacity: 1;
+  }
+
+  > label,
+  > .ui--Icon {
+    vertical-align: middle;
+  }
+
+  .ui--Icon {
+    border: 1px solid rgba(34, 36, 38, 0.15);
+    border-radius: 0.125rem;
+  }
+`);

+ 5 - 1
packages/react-components/src/Icon.tsx

@@ -10,7 +10,7 @@ import styled from 'styled-components';
 
 interface Props {
   className?: string;
-  color?: 'gray' | 'green' | 'normal' | 'orange' | 'red';
+  color?: 'gray' | 'green' | 'normal' | 'orange' | 'red' | 'transparent';
   icon: IconName;
   isSpinning?: boolean;
   onClick?: () => void;
@@ -58,4 +58,8 @@ export default React.memo(styled(Icon)`
   &.redColor {
     color: darkred;
   }
+
+  &.transparentColor {
+    color: transparent;
+  }
 `);

+ 52 - 26
packages/react-components/src/Toggle.tsx

@@ -3,13 +3,10 @@
 // of the Apache-2.0 license. See the LICENSE file for details.
 
 import React, { useCallback } from 'react';
-import SUICheckbox from 'semantic-ui-react/dist/commonjs/modules/Checkbox';
 import styled from 'styled-components';
 
 interface Props {
-  asSwitch?: boolean;
   className?: string;
-  defaultValue?: boolean;
   isDisabled?: boolean;
   label: React.ReactNode;
   onChange?: (isChecked: boolean) => void;
@@ -17,49 +14,78 @@ interface Props {
   value?: boolean;
 }
 
-function Toggle ({ asSwitch = true, className = '', defaultValue, isDisabled, label, onChange, preventDefault, value }: Props): React.ReactElement<Props> {
-  const _onChange = useCallback(
-    (event: React.FormEvent<HTMLInputElement>, { checked }: any): void => {
-      if (preventDefault) {
-        event.preventDefault();
-        event.stopPropagation();
-      }
+function Toggle ({ className = '', isDisabled, label, onChange, preventDefault, value }: Props): React.ReactElement<Props> {
+  const _onClick = useCallback(
+    (event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
+      if (!isDisabled) {
+        if (preventDefault) {
+          event.preventDefault();
+          event.stopPropagation();
+        }
 
-      onChange && onChange(checked);
+        onChange && onChange(!value);
+      }
     },
-    [onChange, preventDefault]
+    [isDisabled, onChange, preventDefault, value]
   );
 
   return (
-    <div className={`ui--Toggle ${asSwitch ? 'isToggle' : 'isCheckbox'} ${className}`}>
-      <label>{label}</label>
-      <SUICheckbox
-        checked={value}
-        defaultChecked={defaultValue}
-        disabled={isDisabled}
-        onChange={_onChange}
-        toggle={asSwitch}
-      />
+    <div
+      className={`ui--Toggle${value ? ' isChecked' : ''}${isDisabled ? ' isDisabled' : ''} ${className}`}
+      onClick={_onClick}
+    >
+      {label && <label>{label}</label>}
+      <div className='ui--Toggle-Slider' />
     </div>
   );
 }
 
 export default React.memo(styled(Toggle)`
   > label {
+    color: rgba(78, 78, 78, 0.75);
     display: inline-block;
     margin: 0 0.5rem;
   }
 
   > label,
-  > .ui.checkbox {
+  > div {
     vertical-align: middle;
   }
 
-  .ui.checkbox + label {
-    color: rgba(78, 78, 78, 0.75);
+  .ui--Toggle-Slider {
+    border-radius: 1.5rem;
+    display: inline-block;
+    position: relative;
+    cursor: pointer;
+    background-color: #eee;
+    width: 3rem;
+    height: 1.5rem;
+
+    &::before {
+      border: 0.125rem solid #eee;
+      border-radius: 50%;
+      position: absolute;
+      content: "";
+      height: 1.5rem;
+      width: 1.5rem;
+      left: 0;
+      top: 0rem;
+      background-color: white;
+    }
+  }
+
+  &.not(.isDisabled) .ui--Toggle-Slider {
+    cursor: pointer;
   }
 
-  &.isCheckbox label {
-    opacity: 1 !important;
+  &.isChecked {
+    .ui--Toggle-Slider {
+      background: #2196F3;
+
+      &:before {
+        border-color: #2196F3;
+        transform: translateX(1.5rem);
+      }
+    }
   }
 `);

+ 1 - 0
packages/react-components/src/index.tsx

@@ -27,6 +27,7 @@ export { default as CardSummary } from './CardSummary';
 export { default as ChainImg } from './ChainImg';
 export { default as ChainLock } from './ChainLock';
 export { default as Chart } from './Chart';
+export { default as Checkbox } from './Checkbox';
 export { default as Columar } from './Columar';
 export { default as Column } from './Column';
 export { default as ConvictionDropdown } from './ConvictionDropdown';

+ 5 - 11
packages/react-components/src/styles/index.ts

@@ -92,10 +92,11 @@ export default createGlobalStyle<Props>`
       }
     }
 
-    .ui.toggle.checkbox {
-      input:checked~.box:before,
-      input:checked~label:before {
-        background-color: ${getHighlight} !important;
+    .ui--Toggle.isChecked .ui--Toggle-Slider {
+      background-color: ${getHighlight} !important;
+
+      &:before {
+        border-color: ${getHighlight} !important;
       }
     }
   }
@@ -126,13 +127,6 @@ export default createGlobalStyle<Props>`
         color: #555 !important;
       }
 
-      .ui.toggle.checkbox {
-        input:checked~.box:before,
-        input:checked~label:before {
-          background-color: #eee !important;
-        }
-      }
-
       .ui.button.show-on-hover {
         visibility: hidden;
       }