atoms-element v5.0.0

#js

git clone https://git.pyrossh.dev/atoms-element

A simple web component library for defining your custom elements. It works on both client and server.


examples/elements/app-counter.js
e955350 1
import { classMap, createElement, css, html } from '../../index.js';
24398b1 2
582dce0 3
// State lives only in the count attribute — no separate internal copy to
e955350 4
// keep in sync. Counter.attrs below declares count as a Number: that folds
e955350 5
// it into observedAttributes on its own (name is still destructured as a
e955350 6
// plain param since it's only ever displayed, never written), and
582dce0 7
// createElement hands count to this function already wrapped as a
e955350 8
// {value} getter/setter box, type-checked against the declared constructor.
582dce0 9
// count must be set in markup (no default) — reading count.value throws
582dce0 10
// otherwise. count.value += 1 reads the live attribute and writes straight
582dce0 11
// back via setAttribute.
e955350 12
//
e955350 13
// <output> is the element HTML actually defines for "the result of a
e955350 14
// calculation" — a live-updating count is exactly that, which is what lets
e955350 15
// the CSS below style it by tag name instead of an accessory class like the
e955350 16
// old .count.
ba74771 17
const Counter = ({ name, count }) => {
582dce0 18
  const increment = () => { count.value += 1; };
582dce0 19
  const decrement = () => { count.value -= 1; };
24398b1 20
24398b1 21
  return html`
e955350 22
    <p>Counter: ${name}</p>
e955350 23
    <div class="controls">
e955350 24
      <button type="button" aria-label="Decrement" @click=${decrement}>-</button>
e955350 25
      <output class=${classMap({ warning: count.value > 10 })}>${count.value}</output>
e955350 26
      <button type="button" aria-label="Increment" @click=${increment}>+</button>
24398b1 27
    </div>
24398b1 28
  `;
24398b1 29
};
24398b1 30
e955350 31
Counter.attrs = { count: Number };
582dce0 32
e264357 33
Counter.styles = css`
e264357 34
  :scope {
e264357 35
    display: block;
e264357 36
    margin-top: 2.5rem;
e955350 37
    color: rgb(55 65 81);
e955350 38
    --color-danger: rgb(239 68 68);
e955350 39
    --color-button-bg: rgb(209 213 219);
e955350 40
    --color-button-bg-hover: rgb(229 231 235);
e264357 41
  }
e955350 42
  p {
e955350 43
    margin: 0 0 0.5rem;
e264357 44
  }
e264357 45
  .controls {
e264357 46
    display: flex;
e264357 47
    align-items: center;
e264357 48
  }
e955350 49
  output {
e264357 50
    margin: 0 5rem;
e264357 51
    font-size: 1.875rem;
e264357 52
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
e264357 53
  }
e955350 54
  output.warning {
e955350 55
    color: var(--color-danger);
e264357 56
  }
e264357 57
  button {
e955350 58
    background-color: var(--color-button-bg);
e955350 59
    color: inherit;
e264357 60
    border-radius: 0.25rem;
e264357 61
    padding: 0.5rem 1rem;
e264357 62
    font-size: 1.875rem;
e264357 63
  }
e264357 64
  button:hover {
e955350 65
    background-color: var(--color-button-bg-hover);
e264357 66
  }
e264357 67
  button:focus {
e264357 68
    outline: none;
e264357 69
  }
e264357 70
`;
e264357 71
24398b1 72
export default createElement(import.meta, Counter);