ronantakizawa/codereview-bench huggingface dataset:
Repository: h2oai/wave
File: ui/src/menu.tsx (TypeScript)

Code before:
  image?: S
  /** An identifying name for this component. */
  name?: Id
}

export const XMenu = ({ model }: { model: Menu }) => {
  const
    { name, items, icon, image } = model,
    ref = React.useRef<HTMLDivElement>(null),
    [isMenuHidden, setIsMenuHidden] = React.useState(true),
    toggleMenu = () => setIsMenuHidden(isHidden => !isHidden)

  return (
    // HACK: Marker css class.
    <div data-test={name} className={clas(css.card, 'w-menu')} ref={ref} onClick={toggleMenu}>
      { image && <Fluent.Persona imageUrl={image} size={Fluent.PersonaSize.size48} styles={{ details: { padding: 0 } }} />}
      { icon && <Fluent.FontIcon className={css.icon} iconName={icon} />}
      <Fluent.ContextualMenu
        items={toCommands(items)}
        target={ref}
        hidden={isMenuHidden}
        onDismiss={toggleMenu}
        isBeakVisible
        directionalHint={Fluent.DirectionalHint.bottomRightEdge}
        calloutProps={{ styles: { beak: { border: border(1, cssVar('$neutralQuaternaryAlt')) } } }}
        styles={{ list: { border: border(1, cssVar('$neutralQuaternaryAlt')), 'button': { lineHeight: '1em'} } }}
      />
      <Fluent.ActionButton iconProps={{ iconName: 'CaretSolidDown', styles: { root: { fontSize: 12 } } }} styles={{ root: { padding: 0 } }} />
    </div>
  )
}

Review comment (suggestion):
Let's be more specific here and use the class (`.ms-ContextualMenu-link` seems like a good fit) instead of targeting every button component. Why is lineHeight set to `1em`? `unset` seems like a better fit.

```suggestion
        styles={{ list: { border: border(1, cssVar('$neutralQuaternaryAlt')), 'button': { lineHeight: 'unset'} } }}
```

Code after:
  /** The card’s image, preferably user avatar. Mutually exclusive with the icon. */
  image?: S
  /** An identifying name for this component. */
  name?: Id
}

export const XMenu = ({ model }: { model: Menu }) => {
  const
    { name, items, icon, image } = model,
    ref = React.useRef<HTMLDivElement>(null),
    [isMenuHidden, setIsMenuHidden] = React.useState(true),
    toggleMenu = () => setIsMenuHidden(isHidden => !isHidden)

  return (
    // HACK: Marker css class.
    <div data-test={name} className={clas(css.card, 'w-menu')} ref={ref} onClick={toggleMenu}>
      {image && <Fluent.Persona imageUrl={image} size={Fluent.PersonaSize.size48} styles={{ details: { padding: 0 } }} />}
      {icon && <Fluent.FontIcon className={css.icon} iconName={icon} />}
      <Fluent.ContextualMenu
        items={toCommands(items)}
        target={ref}
        hidden={isMenuHidden}
        onDismiss={toggleMenu}
        isBeakVisible
        directionalHint={Fluent.DirectionalHint.bottomRightEdge}
        calloutProps={{ styles: { beak: { border: border(1, cssVar('$neutralQuaternaryAlt')) } } }}
        styles={fixMenuOverflowStyles}
      />
      <Fluent.ActionButton iconProps={{ iconName: 'CaretSolidDown', styles: { root: { fontSize: 12 } } }} styles={{ root: { padding: 0 } }} />
    </div>
  )
}
Repository: h2oai/wave
File: ui/src/menu.tsx (TypeScript)

Code before:
  const
    { name, items, icon, image } = model,
    ref = React.useRef<HTMLDivElement>(null),
    [isMenuHidden, setIsMenuHidden] = React.useState(true),
    toggleMenu = () => setIsMenuHidden(isHidden => !isHidden)

  return (
    // HACK: Marker css class.
    <div data-test={name} className={clas(css.card, 'w-menu')} ref={ref} onClick={toggleMenu}>
      { image && <Fluent.Persona imageUrl={image} size={Fluent.PersonaSize.size48} styles={{ details: { padding: 0 } }} />}
      { icon && <Fluent.FontIcon className={css.icon} iconName={icon} />}
      <Fluent.ContextualMenu
        items={toCommands(items)}
        target={ref}
        hidden={isMenuHidden}
        onDismiss={toggleMenu}
        isBeakVisible
        directionalHint={Fluent.DirectionalHint.bottomRightEdge}
        calloutProps={{ styles: { beak: { border: border(1, cssVar('$neutralQuaternaryAlt')) } } }}
        styles={
          {
            list: {
              border: border(1, cssVar('$neutralQuaternaryAlt')),
              '.ms-ContextualMenu-link': { lineHeight: 'unset' },
              '.ms-ContextualMenu-submenuIcon > span': { height: 'unset' },
              '.ms-ContextualMenu-submenuIcon > span > svg': { verticalAlign: 'unset' },
            }
          }}
      />
      <Fluent.ActionButton iconProps={{ iconName: 'CaretSolidDown', styles: { root: { fontSize: 12 } } }} styles={{ root: { padding: 0 } }} />
    </div>
  )
}

Review comment (suggestion):
Let's try to depend on the existing DOM structure as little as possible as it's very probable to break between versions.

```suggestion
              '.ms-ContextualMenu-submenuIcon': { lineHeight: 'unset', display: 'flex', alignItems: 'center' }
```

^^ This should work as well.

Code after:
export const XMenu = ({ model }: { model: Menu }) => {
  const
    { name, items, icon, image } = model,
    ref = React.useRef<HTMLDivElement>(null),
    [isMenuHidden, setIsMenuHidden] = React.useState(true),
    toggleMenu = () => setIsMenuHidden(isHidden => !isHidden)

  return (
    // HACK: Marker css class.
    <div data-test={name} className={clas(css.card, 'w-menu')} ref={ref} onClick={toggleMenu}>
      {image && <Fluent.Persona imageUrl={image} size={Fluent.PersonaSize.size48} styles={{ details: { padding: 0 } }} />}
      {icon && <Fluent.FontIcon className={css.icon} iconName={icon} />}
      <Fluent.ContextualMenu
        items={toCommands(items)}
        target={ref}
        hidden={isMenuHidden}
        onDismiss={toggleMenu}
        isBeakVisible
        directionalHint={Fluent.DirectionalHint.bottomRightEdge}
        calloutProps={{ styles: { beak: { border: border(1, cssVar('$neutralQuaternaryAlt')) } } }}
        styles={fixMenuOverflowStyles}
      />
      <Fluent.ActionButton iconProps={{ iconName: 'CaretSolidDown', styles: { root: { fontSize: 12 } } }} styles={{ root: { padding: 0 } }} />
    </div>
  )
}
Repository: h2oai/wave
File: py/examples/meta_notification_bar_closable.py (Python)

Code before:
# Meta / Notification bar / Closable
# Display a notification bar #notification_bar and detect when it's closed. #meta
# ---
from h2o_wave import main, app, Q, ui


@app('/demo')
async def serve(q: Q):
    if not q.client.initialized:
        # Create an empty meta_card to hold the notification bar
        q.page['meta'] = ui.meta_card(box='')
        # Display a button to show the notification bar
        q.page['form'] = ui.form_card(box='1 1 2 4', items=[
            ui.button(name='show_notification_bar', label='Show notification bar'),
        ])
        q.client.initialized = True

    # Was the show_notification_bar button clicked?    
    if q.args.show_notification_bar:
        # Create a notification bar
        q.page['meta'].notification_bar=ui.notification_bar(
            text='You can close me!',
            name="my_bar",
            # Get notified when the notification bar is dismissed.
            events=['dismissed'],
        )


Review comment (suggestion):
```suggestion
# Display a #notification_bar and detect when it's closed. #meta
```

Code after:
# Meta / Notification bar / Closable
# Display a #notification_bar and detect when it's closed. #meta
# ---
from h2o_wave import main, app, Q, ui


@app('/demo')
async def serve(q: Q):
    if not q.client.initialized:
        # Create an empty meta_card to hold the notification bar
        q.page['meta'] = ui.meta_card(box='')
        # Display a button to show the notification bar
        q.page['form'] = ui.form_card(box='1 1 2 4', items=[
            ui.button(name='show_notification_bar', label='Show notification bar'),
        ])
        q.client.initialized = True

    # Was the show_notification_bar button clicked?    
    if q.args.show_notification_bar:
        # Create a notification bar
        q.page['meta'].notification_bar=ui.notification_bar(
            text='You can close me!',
            name="my_bar",
            # Get notified when the notification bar is dismissed.
            events=['dismissed'],
        )
Repository: h2oai/wave
File: studio/studio.js (JavaScript)

Code before:
    scrollbar: { vertical: 'hidden' },
    overviewRulerBorder: false,
    automaticLayout: true
  })
  window.editor = editor
  window.emit_debounced = window.wave.debounce(2000, window.wave.emit)
  editor.onDidChangeModelContent(e => {
    if (e.isFlush) return
    emit_debounced('editor', 'change', editor.getValue())
  })
})

let tries = 0
const initPyodide = setInterval(async () => {
  tries++
  if (tries > 10) clearInterval(initPyodide)
  if (!loadPyodide) return
  clearInterval(initPyodide)
  window.pyodide = await loadPyodide()
  await window.pyodide.loadPackage('parso')
  await window.pyodide.loadPackage('jedi')
  await window.pyodide.runPythonAsync(`$py_content`)
}, 100)

const getIconLabel = (iconName) => {
  switch (iconName) {
    case 'css':
      return 'language-css3'
    case 'gif':
      return 'file-gif-box'
    case 'html':
      return 'language-html5'
    case 'jpeg':
    case 'jpg':
      return 'file-jpg-box'
    case 'js':
      return 'language-javascript'
    case 'json':
      return 'code-json'
    case 'md':
      return 'book-open'
    case 'png':
      return 'file-png-box'
    case 'py':
      return 'language-python'
    case 'svg':
      return 'svg'
    case 'txt':
      return 'file-document'
    case 'xml':
      return 'file-xml-box'

Review comment (suggestion):
Let's use a simple object to make this less verbose.

```js
{
    css: 'language-css3',
    ...
}

Code after:
    scrollbar: { vertical: 'hidden' },
    overviewRulerBorder: false,
    automaticLayout: true
  })
  window.editor = editor
  window.emit_debounced = window.wave.debounce(2000, window.wave.emit)
  editor.onDidChangeModelContent(e => {
    if (e.isFlush) return
    emit_debounced('editor', 'change', editor.getValue())
  })
})

let tries = 0
const initPyodide = setInterval(async () => {
  tries++
  if (tries > 10) clearInterval(initPyodide)
  if (!loadPyodide) return
  clearInterval(initPyodide)
  window.pyodide = await loadPyodide()
  await window.pyodide.loadPackage('parso')
  await window.pyodide.loadPackage('jedi')
  await window.pyodide.runPythonAsync(`$py_content`)
}, 100)

const iconLabels = {
  'css': 'language-css3',
  'gif': 'file-gif-box',
  'html': 'language-html5',
  'jpeg': 'file-jpg-box',
  'jpg': 'file-jpg-box',
  'js': 'language-javascript',
  'json': 'code-json',
  'md': 'book-open',
  'png': 'file-png-box',
  'py': 'language-python',
  'svg': 'svg',
  'txt': 'file-document',
  'xml': 'file-xml-box',
  'zip': 'folder-zip',
}

const baseUrl = '$base_url'

const store = Vue.reactive({
  activeFile: 'project/app.py'
})

const
  getIconSrc = (folder, isSubtreeOpen) => {
    if (folder.isFolder) return isSubtreeOpen ? baseUrl + 'assets/img/folder-open.svg' : baseUrl + 'assets/img/folder.svg'
    if (folder.path) return baseUrl + `assets/img/file-icons/$${iconLabels[folder.path.split('.').pop()] || 'file'}.svg`
Repository: h2oai/wave
File: studio/studio.js (JavaScript)

Code before:
        <li @click="remove" class='delete'><img class="menu-item-img" src="/assets/img/trash-can.svg" alt="Folder" />Delete</li>
      </ul>
    `}
class EventBus {
  constructor() {
    this.events = {}
  }
  on(eventName, fn) {
    this.events[eventName] = this.events[eventName] || []
    this.events[eventName].push(fn)
  }
  emit(eventName, data) {
    if (this.events[eventName]) this.events[eventName].forEach(fn => fn(data))
  }
}
const eventBus = new EventBus()
const app = Vue.createApp({
  mounted() {
    this.bus.on('folder', folder => this.folder = folder)
  },
  data() { return { folder: {} } },
  template: `
      <ul><Tree :folder="folder" /></ul>
      <Teleport to="#file-tree-menu"><Menu/></Teleport>
      `
})
app.config.globalProperties.bus = eventBus
app.component('Tree', Tree)
app.component('Menu', Menu)
app.mount('#file-tree')
document.onclick = e => eventBus.emit('documentClick', e)
eventBus.emit("folder", $folder)

const handleHorizontalResize = (element, resizer) => {
  let mouseX, elementWidth = 0
  const
    mouseMoveHandler = (e) => {
      const dx = e.clientX - mouseX
      if (elementWidth + dx > 60) element.style.width = elementWidth + dx + 'px'
    },
    mouseUpHandler = () => {
      document.removeEventListener('mousemove', mouseMoveHandler)
      document.removeEventListener('mouseup', mouseUpHandler)
    },
    mouseDownHandler = (e) => {
      mouseX = e.clientX
      const styles = window.getComputedStyle(element)
      elementWidth = parseInt(styles.width, 10)
      document.addEventListener('mousemove', mouseMoveHandler)
      document.addEventListener('mouseup', mouseUpHandler)
    }

Review comment (suggestion):
Would be good to add a comment about why the handlers are registered on document and not the resizer itself. I figured the reason is because mouseMove would not get fired if you moved the mouse too quickly, away from resizer, but was not that obvious.

Code after:
app.directive('focus', {
  mounted: (el) => el.focus()
})
document.onclick = e => eventBus.emit('documentClick', e)
eventBus.emit("folder", $folder)

const handleHorizontalResize = () => {
  let mouseX, elementWidth = 0
  const
    element = document.getElementById('explorer'),
    resizer = document.getElementById('width-resizer'),
    mouseMoveHandler = (e) => {
      const dx = e.clientX - mouseX
      if (elementWidth + dx > 60) element.style.width = elementWidth + dx + 'px'
    },
    mouseUpHandler = () => {
      // handlers registered on document - events not fired when mouse is moved too quickly while registered on resizer itself
      document.removeEventListener('mousemove', mouseMoveHandler)
      document.removeEventListener('mouseup', mouseUpHandler)
    },
    mouseDownHandler = (e) => {
      mouseX = e.clientX
      const styles = window.getComputedStyle(element)
      elementWidth = parseInt(styles.width, 10)
      document.addEventListener('mousemove', mouseMoveHandler)
      document.addEventListener('mouseup', mouseUpHandler)
    }

  resizer.addEventListener('mousedown', mouseDownHandler)
}

handleHorizontalResize()
Repository: h2oai/wave
File: ui/src/combobox.tsx (TypeScript)

Code before:
        ...(m.values || []).filter(v => !prevOptions.map(o => String(o.key)).includes(v)).map(v => ({ key: v, text: v }))
      ]
    )
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [m.values])

  return (
    <Fluent.ComboBox
      data-test={m.name}
      label={m.label}
      placeholder={m.placeholder}
      options={options}
      required={m.required}
      multiSelect
      selectedKey={selected}
      allowFreeform
      disabled={m.disabled}
      autoComplete="on"
      errorMessage={m.error}
      onChange={onChange}
    />
  )
}

const useOptions = (choices: S[] = []): [Fluent.IComboBoxOption[], React.Dispatch<React.SetStateAction<Fluent.IComboBoxOption[]>>]  => {
  const mapChoices = React.useMemo(() => (choices || []).map((text): Fluent.IComboBoxOption => ({ key: text, text })), [choices])
  const [options, setOptions] = React.useState(mapChoices)
  
  React.useEffect(() => { setOptions(mapChoices) }, [choices, mapChoices])
  
  return [options, setOptions]
}


Review comment (suggestion):
Naming:
```suggestion
  const mappedChoices = React.useMemo(() => (choices || []).map((text): Fluent.IComboBoxOption => ({ key: text, text })), [choices])
```

Code after:
          ...m.values!.filter(v => !prevOptions.some(o => o.key === v)).map(v => ({ key: v, text: v }))
        ]
      )
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [m.values])

  return (
    <Fluent.ComboBox
      data-test={m.name}
      label={m.label}
      placeholder={m.placeholder}
      options={options}
      required={m.required}
      multiSelect
      selectedKey={selected}
      allowFreeform
      disabled={m.disabled}
      autoComplete="on"
      errorMessage={m.error}
      onChange={onChange}
    />
  )
}

const useOptions = (choices: S[] = []): [Fluent.IComboBoxOption[], React.Dispatch<React.SetStateAction<Fluent.IComboBoxOption[]>>] => {
  const mappedChoices = React.useMemo(() => (choices || []).map((text): Fluent.IComboBoxOption => ({ key: text, text })), [choices])
  const [options, setOptions] = React.useState(mappedChoices)

  React.useEffect(() => { setOptions(mappedChoices) }, [choices, mappedChoices])

  return [options, setOptions]
}
Repository: h2oai/wave
File: auth.go (Go)

Code before:
	return &RefreshHandler{auth, keychain}
}

func (h *RefreshHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !h.keychain.Guard(w, r) { // API
		return
	}

	sessionID := r.Header.Get("Wave-Session-ID")
	session, ok := h.auth.get(sessionID)

	if !ok {
		echo(Log{"t": "refresh_session", "error": "session unavailable"})
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}

	token, err := h.auth.ensureValidOAuth2Token(r.Context(), session.token)
	if err != nil {
		// Purge session and reload clients if refresh not successful?
		echo(Log{"t": "refresh_session", "error": err.Error()})
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}

	session.token = token
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Wave-Access-Token", token.AccessToken)
	w.Header().Set("Wave-Refresh-Token", token.RefreshToken)
}


Review comment (bug):
I might be wrong but I'd expect to call a `h.auth.set` after changing the session after modifying it. Is it missing here?

Code after:
	return &RefreshHandler{auth, keychain}
}

func (h *RefreshHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if !h.keychain.Guard(w, r) { // API
		return
	}

	sessionID := r.Header.Get("Wave-Session-ID")
	session, ok := h.auth.get(sessionID)

	if !ok {
		echo(Log{"t": "refresh_session", "error": "session unavailable"})
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		return
	}

	token, err := h.auth.ensureValidOAuth2Token(r.Context(), session.token)
	if err != nil {
		// Purge session and reload clients if refresh not successful?
		echo(Log{"t": "refresh_session", "error": err.Error()})
		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	session.token = token
	h.auth.set(session)

	w.WriteHeader(http.StatusOK)
	w.Header().Set("Wave-Access-Token", token.AccessToken)
	w.Header().Set("Wave-Refresh-Token", token.RefreshToken)
}
Repository: h2oai/wave
File: cmd/wave/main.go (Go)

Code before:

	if auth.SessionExpiry, err = time.ParseDuration(sessionExpiry); err != nil {
		panic(err)
	}

	if auth.InactivityTimeout, err = time.ParseDuration(inactivityTimeout); err != nil {
		panic(err)
	}

	conf.WebDir, _ = filepath.Abs(conf.WebDir)
	conf.DataDir, _ = filepath.Abs(conf.DataDir)

	conf.Version = Version
	conf.BuildDate = BuildDate

	conf.Keychain = kc

	if auth.ClientID != "" && auth.ClientSecret != "" && auth.ProviderURL != "" && auth.RedirectURL != "" {
		conf.Auth = &auth
	}

	if conf.IDE {
		conf.Proxy = true // IDE won't function without proxy
	}

	if !verifyTLS {
		http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}

	wave.Run(conf)
}

func getEnv(key, value string) string {
	if v, ok := os.LookupEnv("H2O_WAVE_" + strings.ToUpper(strings.ReplaceAll(key, "-", "_"))); ok {
		return v
	}
	return value
}

func boolVar(p *bool, key string, value bool, usage string) {
	b := "0"
	if value {
		b = "1"
	}
	v, err := strconv.ParseBool(getEnv(key, b))
	if err != nil {
		v = value
	}
	flag.BoolVar(p, key, v, usage)
}


Review comment (suggestion):
This logic is better placed inside `if isTLS {` in `server.go`, because that's where the TLS-related flags are used.

Code after:
		panic(err)
	}

	if auth.InactivityTimeout, err = time.ParseDuration(inactivityTimeout); err != nil {
		panic(err)
	}

	conf.WebDir, _ = filepath.Abs(conf.WebDir)
	conf.DataDir, _ = filepath.Abs(conf.DataDir)

	conf.Version = Version
	conf.BuildDate = BuildDate

	conf.Keychain = kc

	if auth.ClientID != "" && auth.ClientSecret != "" && auth.ProviderURL != "" && auth.RedirectURL != "" {
		conf.Auth = &auth
	}

	if conf.IDE {
		conf.Proxy = true // IDE won't function without proxy
	}

	wave.Run(conf)
}

func getEnv(key, value string) string {
	if v, ok := os.LookupEnv("H2O_WAVE_" + strings.ToUpper(strings.ReplaceAll(key, "-", "_"))); ok {
		return v
	}
	return value
}

func boolVar(p *bool, key string, value bool, usage string) {
	b := "0"
	if value {
		b = "1"
	}
	v, err := strconv.ParseBool(getEnv(key, b))
	if err != nil {
		v = value
	}
	flag.BoolVar(p, key, v, usage)
}

func stringVar(p *string, key, value, usage string) {
	flag.StringVar(p, key, getEnv(key, value), usage)
}

func stringsVar(p *wave.Strings, key, usage string) {
	vs := getEnv(key, "")
Repository: h2oai/wave
File: ui/src/wide_series_stat.tsx (TypeScript)

Code before:
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { Data, F, Model, Rec, S, unpack } from 'h2o-wave'
import React from 'react'
import { stylesheet } from 'typestyle'
import { cards, Format, grid, substitute } from './layout'
import { MicroArea } from './parts/microarea'
import { MicroBars } from './parts/microbars'
import { clas, cssVar } from './theme'
import { bond } from './ui'

const
  css = stylesheet({
    card: {
      display: 'flex',
      padding: grid.gap,
    },
    plot: {
      position: 'relative',
      width: '100%',
    },
    text: {
      paddingLeft: grid.gap,
      alignSelf: 'center',
    },
    values: {
      display: 'flex',
      alignItems: 'baseline',
    },
    value: {
      lineHeight: '28px', // Override to fit inside 1 unit height in grid layout.
    },
    aux_value: {
      color: cssVar('$text7'),
      marginLeft: 5,
    }
  })

const
  MAX_CHAR_WIDTH = 14,
  MAX_CHAR_AUX_WIDTH = 9,
  MIN_CHAR_COUNT = 4

/** Create a wide stat card displaying a primary value, an auxiliary value and a series plot. */
interface State {
  /** The card's title. */
  title: S
  /** The primary value displayed. */

Review comment (suggestion):
I am thinking that centering may not be the best idea here. Wdyt?

<img width="295" alt="image" src="https://user-images.githubusercontent.com/64769322/191028195-a2f9f2e9-d2f6-446d-aba4-e8ab53a36527.png">

vs 

<img width="305" alt="image" src="https://user-images.githubusercontent.com/64769322/191028246-7f89d36f-34ba-48a9-880c-9f776c7542f4.png">


Code after:
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { Data, F, Model, Rec, S, unpack } from 'h2o-wave'
import React from 'react'
import { stylesheet } from 'typestyle'
import { cards, Format, grid, substitute } from './layout'
import { MicroArea } from './parts/microarea'
import { MicroBars } from './parts/microbars'
import { clas, cssVar } from './theme'
import { bond } from './ui'

const
  css = stylesheet({
    card: {
      display: 'flex',
      padding: grid.gap,
    },
    plot: {
      width: '100%',
    },
    text: {
      paddingLeft: grid.gap,
      alignSelf: 'center',
    },
    values: {
      display: 'flex',
      alignItems: 'baseline',
    },
    value: {
      lineHeight: '28px', // Override to fit inside 1 unit height in grid layout.
    },
    aux_value: {
      color: cssVar('$text7'),
      marginLeft: 5,
    }
  })

const
  MAX_CHAR_WIDTH = 14,
  MAX_CHAR_AUX_WIDTH = 9,
  MIN_CHAR_COUNT = 4

/** Create a wide stat card displaying a primary value, an auxiliary value and a series plot. */
interface State {
  /** The card's title. */
  title: S
  /** The primary value displayed. */
  value: S