gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: modal, popover and portal for


From: gnunet
Subject: [taler-wallet-core] branch master updated: modal, popover and portal for select input
Date: Tue, 16 Aug 2022 02:37:44 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 0798aa5c modal, popover and portal for select input
0798aa5c is described below

commit 0798aa5cedad2a599829f2b13d4573c64a081c29
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Aug 15 21:36:53 2022 -0300

    modal, popover and portal for select input
---
 .../taler-wallet-webextension/src/mui/Modal.tsx    | 132 +++++++++
 .../src/mui/ModalManager.ts                        | 310 +++++++++++++++++++++
 .../taler-wallet-webextension/src/mui/Popover.tsx  |  59 ++++
 .../taler-wallet-webextension/src/mui/Portal.tsx   | 113 ++++++++
 .../src/mui/TextField.stories.tsx                  |  18 +-
 .../src/mui/input/SelectStandard.tsx               | 164 ++++++++++-
 .../taler-wallet-webextension/src/mui/style.tsx    |  11 +
 packages/taler-wallet-webextension/src/stories.tsx |   1 +
 8 files changed, 782 insertions(+), 26 deletions(-)

diff --git a/packages/taler-wallet-webextension/src/mui/Modal.tsx 
b/packages/taler-wallet-webextension/src/mui/Modal.tsx
new file mode 100644
index 00000000..5a30bcf2
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/Modal.tsx
@@ -0,0 +1,132 @@
+import { css } from "@linaria/core";
+import { h, JSX, VNode, ComponentChildren } from "preact";
+import { useCallback, useEffect, useRef, useState } from "preact/hooks";
+// eslint-disable-next-line import/extensions
+import { alpha } from "./colors/manipulation";
+import { ModalManager } from "./ModalManager";
+import { Portal } from "./Portal.js";
+// eslint-disable-next-line import/extensions
+import { theme } from "./style";
+
+const baseStyle = css`
+  position: fixed;
+  z-index: ${theme.zIndex.modal};
+  right: 0px;
+  bottom: 0px;
+  top: 0px;
+  left: 0px;
+`;
+
+interface Props {
+  class: string;
+  children: ComponentChildren;
+  open?: boolean;
+  exited?: boolean;
+  container?: HTMLElement;
+}
+
+const defaultManager = new ModalManager();
+const manager = defaultManager;
+
+export function Modal({
+  open,
+  // exited,
+  class: _class,
+  children,
+
+  container,
+  ...rest
+}: Props): VNode {
+  const [exited, setExited] = useState(true);
+  const mountNodeRef = useRef<HTMLElement | undefined>(undefined);
+
+  const isTopModal = useCallback(
+    () => manager.isTopModal(getModal()),
+    [manager],
+  );
+
+  const handlePortalRef = useEventCallback<HTMLElement[], void>((node) => {
+    mountNodeRef.current = node;
+
+    if (!node) {
+      return;
+    }
+
+    if (open && isTopModal()) {
+      handleMounted();
+    } else {
+      ariaHidden(modalRef.current, true);
+    }
+  });
+
+  return (
+    <Portal
+      ref={handlePortalRef}
+      container={container}
+      disablePortal={disablePortal}
+    >
+      <div
+        class={[_class, baseStyle].join(" ")}
+        style={{
+          visibility: !open && exited ? "hidden" : "visible",
+        }}
+      >
+        {children}
+      </div>
+    </Portal>
+  );
+}
+
+function getOffsetTop(rect: any, vertical: any): number {
+  let offset = 0;
+
+  if (typeof vertical === "number") {
+    offset = vertical;
+  } else if (vertical === "center") {
+    offset = rect.height / 2;
+  } else if (vertical === "bottom") {
+    offset = rect.height;
+  }
+
+  return offset;
+}
+
+function getOffsetLeft(rect: any, horizontal: any): number {
+  let offset = 0;
+
+  if (typeof horizontal === "number") {
+    offset = horizontal;
+  } else if (horizontal === "center") {
+    offset = rect.width / 2;
+  } else if (horizontal === "right") {
+    offset = rect.width;
+  }
+
+  return offset;
+}
+
+function getTransformOriginValue(transformOrigin): string {
+  return [transformOrigin.horizontal, transformOrigin.vertical]
+    .map((n) => (typeof n === "number" ? `${n}px` : n))
+    .join(" ");
+}
+
+function resolveAnchorEl(anchorEl: any): any {
+  return typeof anchorEl === "function" ? anchorEl() : anchorEl;
+}
+
+function useEventCallback<Args extends unknown[], Return>(
+  fn: (...args: Args) => Return,
+): (...args: Args) => Return {
+  const ref = useRef(fn);
+  useEffect(() => {
+    ref.current = fn;
+  });
+  return useCallback(
+    (...args: Args) =>
+      // @ts-expect-error hide `this`
+      // tslint:disable-next-line:ban-comma-operator
+      (0, ref.current!)(...args),
+    [],
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/mui/ModalManager.ts 
b/packages/taler-wallet-webextension/src/mui/ModalManager.ts
new file mode 100644
index 00000000..2894ffa7
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/ModalManager.ts
@@ -0,0 +1,310 @@
+////////////////////
+function ownerDocument(node: Node | null | undefined): Document {
+  return (node && node.ownerDocument) || document;
+}
+function ownerWindow(node: Node | undefined): Window {
+  const doc = ownerDocument(node);
+  return doc.defaultView || window;
+}
+// A change of the browser zoom change the scrollbar size.
+// Credit 
https://github.com/twbs/bootstrap/blob/488fd8afc535ca3a6ad4dc581f5e89217b6a36ac/js/src/util/scrollbar.js#L14-L18
+function getScrollbarSize(doc: Document): number {
+  // 
https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
+  const documentWidth = doc.documentElement.clientWidth;
+  return Math.abs(window.innerWidth - documentWidth);
+}
+
+/////////////////////
+
+export interface ManagedModalProps {
+  disableScrollLock?: boolean;
+}
+
+// Is a vertical scrollbar displayed?
+function isOverflowing(container: Element): boolean {
+  const doc = ownerDocument(container);
+
+  if (doc.body === container) {
+    return ownerWindow(container).innerWidth > doc.documentElement.clientWidth;
+  }
+
+  return container.scrollHeight > container.clientHeight;
+}
+
+export function ariaHidden(element: Element, show: boolean): void {
+  if (show) {
+    element.setAttribute("aria-hidden", "true");
+  } else {
+    element.removeAttribute("aria-hidden");
+  }
+}
+
+function getPaddingRight(element: Element): number {
+  return (
+    parseInt(ownerWindow(element).getComputedStyle(element).paddingRight, 10) 
||
+    0
+  );
+}
+
+function ariaHiddenSiblings(
+  container: Element,
+  mountElement: Element,
+  currentElement: Element,
+  elementsToExclude: readonly Element[] = [],
+  show: boolean,
+): void {
+  const blacklist = [mountElement, currentElement, ...elementsToExclude];
+  const blacklistTagNames = ["TEMPLATE", "SCRIPT", "STYLE"];
+
+  [].forEach.call(container.children, (element: Element) => {
+    if (
+      blacklist.indexOf(element) === -1 &&
+      blacklistTagNames.indexOf(element.tagName) === -1
+    ) {
+      ariaHidden(element, show);
+    }
+  });
+}
+
+function findIndexOf<T>(
+  items: readonly T[],
+  callback: (item: T) => boolean,
+): number {
+  let idx = -1;
+  items.some((item, index) => {
+    if (callback(item)) {
+      idx = index;
+      return true;
+    }
+    return false;
+  });
+  return idx;
+}
+
+function handleContainer(containerInfo: Container, props: ManagedModalProps) {
+  const restoreStyle: Array<{
+    /**
+     * CSS property name (HYPHEN CASE) to be modified.
+     */
+    property: string;
+    el: HTMLElement | SVGElement;
+    value: string;
+  }> = [];
+  const container = containerInfo.container;
+
+  if (!props.disableScrollLock) {
+    if (isOverflowing(container)) {
+      // Compute the size before applying overflow hidden to avoid any scroll 
jumps.
+      const scrollbarSize = getScrollbarSize(ownerDocument(container));
+
+      restoreStyle.push({
+        value: container.style.paddingRight,
+        property: "padding-right",
+        el: container,
+      });
+      // Use computed style, here to get the real padding to add our scrollbar 
width.
+      container.style.paddingRight = `${getPaddingRight(container) + 
scrollbarSize
+        }px`;
+
+      // .mui-fixed is a global helper.
+      const fixedElements =
+        ownerDocument(container).querySelectorAll(".mui-fixed");
+      [].forEach.call(fixedElements, (element: HTMLElement | SVGElement) => {
+        restoreStyle.push({
+          value: element.style.paddingRight,
+          property: "padding-right",
+          el: element,
+        });
+        element.style.paddingRight = `${getPaddingRight(element) + 
scrollbarSize
+          }px`;
+      });
+    }
+
+    // Improve Gatsby support
+    // https://css-tricks.com/snippets/css/force-vertical-scrollbar/
+    const parent = container.parentElement;
+    const containerWindow = ownerWindow(container);
+    const scrollContainer =
+      parent?.nodeName === "HTML" &&
+        containerWindow.getComputedStyle(parent).overflowY === "scroll"
+        ? parent
+        : container;
+
+    // Block the scroll even if no scrollbar is visible to account for mobile 
keyboard
+    // screensize shrink.
+    restoreStyle.push(
+      {
+        value: scrollContainer.style.overflow,
+        property: "overflow",
+        el: scrollContainer,
+      },
+      {
+        value: scrollContainer.style.overflowX,
+        property: "overflow-x",
+        el: scrollContainer,
+      },
+      {
+        value: scrollContainer.style.overflowY,
+        property: "overflow-y",
+        el: scrollContainer,
+      },
+    );
+
+    scrollContainer.style.overflow = "hidden";
+  }
+
+  const restore = () => {
+    restoreStyle.forEach(({ value, el, property }) => {
+      if (value) {
+        el.style.setProperty(property, value);
+      } else {
+        el.style.removeProperty(property);
+      }
+    });
+  };
+
+  return restore;
+}
+
+function getHiddenSiblings(container: Element) {
+  const hiddenSiblings: Element[] = [];
+  [].forEach.call(container.children, (element: Element) => {
+    if (element.getAttribute("aria-hidden") === "true") {
+      hiddenSiblings.push(element);
+    }
+  });
+  return hiddenSiblings;
+}
+
+interface Modal {
+  mount: Element;
+  modalRef: Element;
+}
+
+interface Container {
+  container: HTMLElement;
+  hiddenSiblings: Element[];
+  modals: Modal[];
+  restore: null | (() => void);
+}
+
+export class ModalManager {
+  private containers: Container[];
+
+  private modals: Modal[];
+
+  constructor() {
+    this.modals = [];
+    this.containers = [];
+  }
+
+  add(modal: Modal, container: HTMLElement): number {
+    let modalIndex = this.modals.indexOf(modal);
+    if (modalIndex !== -1) {
+      return modalIndex;
+    }
+
+    modalIndex = this.modals.length;
+    this.modals.push(modal);
+
+    // If the modal we are adding is already in the DOM.
+    if (modal.modalRef) {
+      ariaHidden(modal.modalRef, false);
+    }
+
+    const hiddenSiblings = getHiddenSiblings(container);
+    ariaHiddenSiblings(
+      container,
+      modal.mount,
+      modal.modalRef,
+      hiddenSiblings,
+      true,
+    );
+
+    const containerIndex = findIndexOf(
+      this.containers,
+      (item) => item.container === container,
+    );
+    if (containerIndex !== -1) {
+      this.containers[containerIndex].modals.push(modal);
+      return modalIndex;
+    }
+
+    this.containers.push({
+      modals: [modal],
+      container,
+      restore: null,
+      hiddenSiblings,
+    });
+
+    return modalIndex;
+  }
+
+  mount(modal: Modal, props: ManagedModalProps): void {
+    const containerIndex = findIndexOf(
+      this.containers,
+      (item) => item.modals.indexOf(modal) !== -1,
+    );
+    const containerInfo = this.containers[containerIndex];
+
+    if (!containerInfo.restore) {
+      containerInfo.restore = handleContainer(containerInfo, props);
+    }
+  }
+
+  remove(modal: Modal): number {
+    const modalIndex = this.modals.indexOf(modal);
+
+    if (modalIndex === -1) {
+      return modalIndex;
+    }
+
+    const containerIndex = findIndexOf(
+      this.containers,
+      (item) => item.modals.indexOf(modal) !== -1,
+    );
+    const containerInfo = this.containers[containerIndex];
+
+    containerInfo.modals.splice(containerInfo.modals.indexOf(modal), 1);
+    this.modals.splice(modalIndex, 1);
+
+    // If that was the last modal in a container, clean up the container.
+    if (containerInfo.modals.length === 0) {
+      // The modal might be closed before it had the chance to be mounted in 
the DOM.
+      if (containerInfo.restore) {
+        containerInfo.restore();
+      }
+
+      if (modal.modalRef) {
+        // In case the modal wasn't in the DOM yet.
+        ariaHidden(modal.modalRef, true);
+      }
+
+      ariaHiddenSiblings(
+        containerInfo.container,
+        modal.mount,
+        modal.modalRef,
+        containerInfo.hiddenSiblings,
+        false,
+      );
+      this.containers.splice(containerIndex, 1);
+    } else {
+      // Otherwise make sure the next top modal is visible to a screen reader.
+      const nextTop = containerInfo.modals[containerInfo.modals.length - 1];
+      // as soon as a modal is adding its modalRef is undefined. it can't set
+      // aria-hidden because the dom element doesn't exist either
+      // when modal was unmounted before modalRef gets null
+      if (nextTop.modalRef) {
+        ariaHidden(nextTop.modalRef, false);
+      }
+    }
+
+    return modalIndex;
+  }
+
+  isTopModal(modal: Modal): boolean {
+    return (
+      this.modals.length > 0 && this.modals[this.modals.length - 1] === modal
+    );
+  }
+}
diff --git a/packages/taler-wallet-webextension/src/mui/Popover.tsx 
b/packages/taler-wallet-webextension/src/mui/Popover.tsx
new file mode 100644
index 00000000..408f8798
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/Popover.tsx
@@ -0,0 +1,59 @@
+import { css } from "@linaria/core";
+import { h, JSX, VNode, ComponentChildren } from "preact";
+// eslint-disable-next-line import/extensions
+import { alpha } from "./colors/manipulation";
+// eslint-disable-next-line import/extensions
+import { theme } from "./style";
+
+const baseStyle = css``;
+
+interface Props {
+  class: string;
+  children: ComponentChildren;
+}
+
+export function Popover({ class: _class, children, ...rest }: Props): VNode {
+  return (
+    <div class={[_class, baseStyle].join(" ")} style={{}} {...rest}>
+      {children}
+    </div>
+  );
+}
+
+function getOffsetTop(rect: any, vertical: any): number {
+  let offset = 0;
+
+  if (typeof vertical === "number") {
+    offset = vertical;
+  } else if (vertical === "center") {
+    offset = rect.height / 2;
+  } else if (vertical === "bottom") {
+    offset = rect.height;
+  }
+
+  return offset;
+}
+
+function getOffsetLeft(rect: any, horizontal: any): number {
+  let offset = 0;
+
+  if (typeof horizontal === "number") {
+    offset = horizontal;
+  } else if (horizontal === "center") {
+    offset = rect.width / 2;
+  } else if (horizontal === "right") {
+    offset = rect.width;
+  }
+
+  return offset;
+}
+
+function getTransformOriginValue(transformOrigin): string {
+  return [transformOrigin.horizontal, transformOrigin.vertical]
+    .map((n) => (typeof n === "number" ? `${n}px` : n))
+    .join(" ");
+}
+
+function resolveAnchorEl(anchorEl: any): any {
+  return typeof anchorEl === "function" ? anchorEl() : anchorEl;
+}
diff --git a/packages/taler-wallet-webextension/src/mui/Portal.tsx 
b/packages/taler-wallet-webextension/src/mui/Portal.tsx
new file mode 100644
index 00000000..828a574f
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/mui/Portal.tsx
@@ -0,0 +1,113 @@
+import { css } from "@linaria/core";
+import { createPortal, forwardRef } from "preact/compat";
+import {
+  h,
+  JSX,
+  VNode,
+  ComponentChildren,
+  RefObject,
+  isValidElement,
+  cloneElement,
+  Fragment,
+} from "preact";
+import { Ref, useEffect, useMemo, useState } from "preact/hooks";
+// eslint-disable-next-line import/extensions
+import { alpha } from "./colors/manipulation";
+// eslint-disable-next-line import/extensions
+import { theme } from "./style";
+
+const baseStyle = css`
+  position: fixed;
+  z-index: ${theme.zIndex.modal};
+  right: 0px;
+  bottom: 0px;
+  top: 0px;
+  left: 0px;
+`;
+
+interface Props {
+  class: string;
+  children: ComponentChildren;
+  disablePortal?: boolean;
+  container?: VNode;
+}
+
+export const Portal = forwardRef(function Portal(
+  { container, disablePortal, children }: Props,
+  ref: Ref<any>,
+): VNode {
+  const [mountNode, setMountNode] = useState<HTMLElement | undefined>(
+    undefined,
+  );
+  const handleRef = useForkRef(
+    isValidElement(children) ? children.ref : null,
+    ref,
+  );
+
+  useEffect(() => {
+    if (!disablePortal) {
+      setMountNode(getContainer(container) || document.body);
+    }
+  }, [container, disablePortal]);
+
+  useEffect(() => {
+    if (mountNode && !disablePortal) {
+      setRef(ref, mountNode);
+      return () => {
+        setRef(ref, null);
+      };
+    }
+
+    return undefined;
+  }, [ref, mountNode, disablePortal]);
+
+  if (disablePortal) {
+    if (isValidElement(children)) {
+      return cloneElement(children, {
+        ref: handleRef,
+      });
+    }
+    return <Fragment>{children}</Fragment>;
+  }
+
+  return mountNode ? (
+    createPortal(<Fragment>{children}</Fragment>, mountNode)
+  ) : (
+    <Fragment />
+  );
+});
+
+function getContainer(container: any): any {
+  return typeof container === "function" ? container() : container;
+}
+
+function useForkRef<Instance>(
+  refA: React.Ref<Instance> | null | undefined,
+  refB: React.Ref<Instance> | null | undefined,
+): React.Ref<Instance> | null {
+  /**
+   * This will create a new function if the ref props change and are defined.
+   * This means react will call the old forkRef with `null` and the new forkRef
+   * with the ref. Cleanup naturally emerges from this behavior.
+   */
+  return useMemo(() => {
+    if (refA == null && refB == null) {
+      return null;
+    }
+    return (refValue) => {
+      setRef(refA, refValue);
+      setRef(refB, refValue);
+    };
+  }, [refA, refB]);
+}
+
+function setRef<T>(
+  ref: RefObject<T | null> | ((instance: T | null) => void) | null | undefined,
+  value: T | null,
+): void {
+  if (typeof ref === "function") {
+    ref(value);
+  } else if (ref) {
+    ref.current = value;
+  }
+}
diff --git a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx 
b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
index fb044acb..a409f09f 100644
--- a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
+++ b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
@@ -118,20 +118,20 @@ const Multiline = (variant: Props["variant"]): VNode => {
         label="Multiline"
         variant={variant}
         multiline
+        maxRows={4}
       />
       <TextField
         {...{ value, onChange }}
         label="Max row 4"
         variant={variant}
         multiline
-        maxRows={4}
+        rows={10}
       />
       <TextField
         {...{ value, onChange }}
         label="Row 10"
         variant={variant}
         multiline
-        rows={10}
       />
     </Container>
   );
@@ -145,19 +145,7 @@ export const Select = (): VNode => {
     <Container>
       <TextField
         {...{ value, onChange }}
-        label="Multiline"
-        variant="standard"
-        select
-      />
-      <TextField
-        {...{ value, onChange }}
-        label="Max row 4"
-        variant="standard"
-        select
-      />
-      <TextField
-        {...{ value, onChange }}
-        label="Row 10"
+        label="select"
         variant="standard"
         select
       />
diff --git 
a/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx 
b/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx
index 6fb2823c..b0474a80 100644
--- a/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/SelectStandard.tsx
@@ -15,6 +15,12 @@
  */
 import { css } from "@linaria/core";
 import { h, VNode, Fragment } from "preact";
+import { useRef } from "preact/hooks";
+import { Paper } from "../Paper.js";
+
+function hasValue(value: any): boolean {
+  return value != null && !(Array.isArray(value) && value.length === 0);
+}
 
 const SelectSelect = css`
   height: "auto";
@@ -36,23 +42,159 @@ const SelectNativeInput = css`
   box-sizing: border-box;
 `;
 
-export function SelectStandard({ value }: any): VNode {
+// export function SelectStandard({ value }: any): VNode {
+//   return (
+//     <Fragment>
+//       <div class={SelectSelect} role="button">
+//         {!value ? (
+//           // notranslate needed while Google Translate will not fix 
zero-width space issue
+//           <span className="notranslate">&#8203;</span>
+//         ) : (
+//           value
+//         )}
+//         <input
+//           class={SelectNativeInput}
+//           aria-hidden
+//           tabIndex={-1}
+//           value={Array.isArray(value) ? value.join(",") : value}
+//         />
+//       </div>
+//     </Fragment>
+//   );
+// }
+function isFilled(obj: any, SSR = false): boolean {
+  return (
+    obj &&
+    ((hasValue(obj.value) && obj.value !== "") ||
+      (SSR && hasValue(obj.defaultValue) && obj.defaultValue !== ""))
+  );
+}
+function isEmpty(display: any): boolean {
+  return display == null || (typeof display === "string" && !display.trim());
+}
+
+export function SelectStandard({
+  value,
+  multiple,
+  displayEmpty,
+  onBlur,
+  onChange,
+  onClose,
+  onFocus,
+  onOpen,
+  renderValue,
+  menuMinWidthState,
+}: any): VNode {
+  const inputRef = useRef(null);
+  const displayRef = useRef(null);
+
+  let display;
+  let computeDisplay = false;
+  let foundMatch = false;
+  let displaySingle;
+  const displayMultiple: any[] = [];
+  if (isFilled({ value }) || displayEmpty) {
+    if (renderValue) {
+      display = renderValue(value);
+    } else {
+      computeDisplay = true;
+    }
+  }
+  if (computeDisplay) {
+    if (multiple) {
+      if (displayMultiple.length === 0) {
+        display = null;
+      } else {
+        display = displayMultiple.reduce((output, child, index) => {
+          output.push(child);
+          if (index < displayMultiple.length - 1) {
+            output.push(", ");
+          }
+          return output;
+        }, []);
+      }
+    } else {
+      display = displaySingle;
+    }
+  }
+
+  // Avoid performing a layout computation in the render method.
+  let menuMinWidth = menuMinWidthState;
+
+  // if (!autoWidth && isOpenControlled && displayNode) {
+  //   menuMinWidth = displayNode.clientWidth;
+  // }
+
+  // let tabIndex;
+  // if (typeof tabIndexProp !== "undefined") {
+  //   tabIndex = tabIndexProp;
+  // } else {
+  //   tabIndex = disabled ? null : 0;
+  // }
+  const update = (open: any, event: any) => {
+    if (open) {
+      if (onOpen) {
+        onOpen(event);
+      }
+    } else if (onClose) {
+      onClose(event);
+    }
+
+    // if (!isOpenControlled) {
+    //   setMenuMinWidthState(autoWidth ? null : displayNode.clientWidth);
+    //   setOpenState(open);
+    // }
+  };
+
+  const handleMouseDown = (event: any) => {
+    // Ignore everything but left-click
+    if (event.button !== 0) {
+      return;
+    }
+    // Hijack the default focus behavior.
+    event.preventDefault();
+    // displayRef.current.focus();
+
+    update(true, event);
+  };
   return (
     <Fragment>
-      <div class={SelectSelect} role="button">
-        {!value ? (
+      <div
+        class={css`
+          height: auto;
+          min-height: 14375em;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+        `}
+      >
+        {isEmpty(display) ? (
           // notranslate needed while Google Translate will not fix zero-width 
space issue
-          <span className="notranslate">&#8203;</span>
+          <span class="notranslate">&#8203;</span>
         ) : (
-          value
+          display
         )}
-        <input
-          class={SelectNativeInput}
-          aria-hidden
-          tabIndex={-1}
-          value={Array.isArray(value) ? value.join(",") : value}
-        />
       </div>
+      <input
+        class={css`
+          bottom: 0px;
+          left: 0px;
+          position: "absolute";
+          opacity: 0;
+          pointer-events: none;
+          width: 100%;
+          box-sizing: border-box;
+        `}
+      />
+      <svg />
     </Fragment>
   );
 }
+
+// function Popover(): VNode {
+//   return;
+// }
+
+// function Menu(): VNode {
+//   return <Paper></Paper>;
+// }
diff --git a/packages/taler-wallet-webextension/src/mui/style.tsx 
b/packages/taler-wallet-webextension/src/mui/style.tsx
index 32fa412e..c3071b31 100644
--- a/packages/taler-wallet-webextension/src/mui/style.tsx
+++ b/packages/taler-wallet-webextension/src/mui/style.tsx
@@ -58,6 +58,16 @@ export interface Spacing {
 
 export const theme = createTheme();
 
+const zIndex = {
+  mobileStepper: 1000,
+  speedDial: 1050,
+  appBar: 1100,
+  drawer: 1200,
+  modal: 1300,
+  snackbar: 1400,
+  tooltip: 1500,
+};
+
 export const ripple = css`
   background-position: center;
 
@@ -859,5 +869,6 @@ function createTheme() {
     breakpoints,
     spacing,
     pxToRem,
+    zIndex,
   };
 }
diff --git a/packages/taler-wallet-webextension/src/stories.tsx 
b/packages/taler-wallet-webextension/src/stories.tsx
index 4a090e52..b4c209a5 100644
--- a/packages/taler-wallet-webextension/src/stories.tsx
+++ b/packages/taler-wallet-webextension/src/stories.tsx
@@ -223,6 +223,7 @@ function ExampleList({
                         e.preventDefault();
                         location.hash = `#${eId}`;
                         onSelectStory(r, eId);
+                        history.pushState({}, "", `#${eId}`);
                       }}
                     >
                       {r.name}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]