Atomico a micro-library for creating webcomponents using only functions, hooks and virtual-dom.

Overview

Atomico Atomico

twitter discord documentation discord

npm gzip

Atomico simplifies learning, workflow and maintenance when creating webcomponents.

  1. Scalable and reusable interfaces: with Atomico the code is simpler and you can apply practices that facilitate the reuse of your code.
  2. Open communication: with Atomico you can communicate states by events, properties or methods.
  3. Agnostic: your custom element will work in any web-compatible library, eg React, Vue, Svelte or Angular.
  4. Performance: Atomico has a comparative performance at Svelte levels, winning the third position in performance according to webcomponents.dev in a comparison of 55 libraries among which is React, Vue, Stencil and Lit.

Atomico is simple and the result will always be a standard and optimized webcomponent.

a1 a2

b1 b2

c1 c2

d1 d2

Guides

k1 k3 k2 k4

Sponsors

sponsors Nicholas Frush sponsor

Summary

Atomico is a modern syntax micro-library created by Matias Trujillo alias @UpperCod, which simplifies the creation of webcomponents by replacing the need to use classes and contexts by functions and scope to support logic, attributes, properties, methods and events.

Comments
  • Types of hooks broken

    Types of hooks broken

    Describe the bug Since Atomico 1.62.0 many types of hooks are broken. Some errors:

    useCallback:

    const isYearDisabled = useCallback((dateToValidate: Date) => {
        // ...
      },
      [minDate, maxDate],
    );
    

    Argument of type '(dateToValidate: Date) => boolean' is not assignable to parameter of type '() => any'.ts(2345)

    useProp does not accept callbacks anymore:

    const [expanded, setExpanded] = useProp<boolean>('expanded');
    
    // ...
    
    setExpanded((prevExpanded) => !prevExpanded);
    

    Argument of type '(prevExpanded: any) => boolean' is not assignable to parameter of type 'boolean'.ts(2345)

    To Reproduce Steps to reproduce the behavior:

    1. Install TypeScript and Atomic 1.62.0
    2. Try one of the code snippets above in VSCode
    3. See error

    Expected behavior No TypeScript errors.

    Additional context I checked you types for the hooks and what you have changed.

    // hooks.d.ts
    export type UseCallback = <CallbackMemo extends () => any>(
        callback: CallbackMemo,
        args?: any[]
    ) => CallbackMemo;
    
    // core.d.ts
    export const useCallback: Hooks.UseCallback;
    

    With the assignment the CallbackMemo gets lost, though useCallback is of type useCallback<() => any>(callback: () => any, args?: any[] | undefined): () => any

    bug 
    opened by efoken 10
  • useEffect(fn) does not run multiple times

    useEffect(fn) does not run multiple times

    Faced that issue in debugging unihooks. Could not create a sandbox due to #23, so just show the code here.

    import { h, customElement, useEffect, useState } from "atomico";
    
    let log = []
    
    function X() {
      // this effect is run only once
      useEffect(() => log.push(1))
    
      let [s, setS] = useState(0)
      useEffect(() => setS(1), [])
      useEffect(() => setS(2), [])
    
      return null
    }
    
    customElement('x-x', X);
    document.body.appendChild(document.createElement("x-x"));
    

    This code runs first useEffect only once.

    opened by dy 10
  • Does not work with detached custom elements

    Does not work with detached custom elements

    If we'd like to create and run custom element in detached tree, it is impossible to run atomico handler with it.

    import { customElement, useState } from 'atomico'
    function MyTag() {
      let [ count, setCount ] = useState(0)
      setTimeout(() => {
        console.log(count)
        setCount(++count)
      }, 1000)
      return {nodeType: 'host'}
    }
    customElement("my-tag", MyTag);
    let el = document.createElement('my-tag')
    

    This just silently ignores the component.

    If we try to render the old scool react way

    import { ... , render } from 'atomico'
    ...
    render(MyTag, document.createDocumentFragment())
    

    It gives error - hooks are not supported.

    haunted doesn't have that drawback. Any plans to catch up?

    opened by dy 10
  • (Suggestion) Use XHTM instead of HTM for HTML parsing

    (Suggestion) Use XHTM instead of HTM for HTML parsing

    Example repo

    https://github.com/lokimckay-references/atomico-html2jsx

    Screenshot 2021-10-26 011725

    Motivation

    As an atomico user, I want to grab regular HTML elements from the "light DOM" and render them in my web component (including HTML5 void elements)

    According to the docs, the way to do that is like this:

    import { c, html } from "https://unpkg.com/atomico";
    
    function component({ name }) {
      return html`<host shadowDom>Hello, ${name}</host>`;
    }
    ...
    

    ..but atomico uses "htm" (htm) which is not intended to be an HTML parser, and does not support HTML5 void elements

    As a result of this, the following snippet will not work in atomico:

    import { c, html } from "https://unpkg.com/atomico";
    
    function component({ name }) {
      return html`<host shadowDom>
          <img src="https://placekitten.com/64">
        </host>`;
    }
    ...
    

    Workaround

    Use the xhtm module instead

    import { h } from "atomico";
    import xhtm from "xhtm";
    const xhtml = xhtm.bind(h);
    
    function MyComponent() {
      return (
        <host shadowDom>
          {xhtml`<img src="https://placekitten.com/64">`}
        </host>
      );
    }
    ...
    
    opened by lokimckay 7
  • How to test for browser compatibility?

    How to test for browser compatibility?

    Is there a simple function I can use like isBrowserAtomicoCompatible that I can call on any page to warn the user that my site/page may not work in case their browser is too old to support Atomico?

    opened by shah 6
  • CommonJS entry

    CommonJS entry

    Optional module detection is only possible via require mechanism: https://stackoverflow.com/questions/33987742/optional-imports-in-es2015-node-js That is used by any-hooks and unihooks. The problem is that with ES modules support in node https://nodejs.org/api/esm.html, the atomico exports nothing, being imported as commonjs:

    let atomico = require('atomico')
    // {} - empty object here
    

    That makes it impossible to test/run in nodejs.

    That would be useful to provide a separate commonjs entry, eg as showed here.

    opened by dy 6
  • Creation of exclusive hooks for web-components

    Creation of exclusive hooks for web-components

    Atomico currently has a React-based hook approach, basic support covers, useState, useEffect, useMemo, useRef and useReducer.

    Now I'm looking to introduce exclusive hooks to work with web-components.

    useHost

    returns a ref, whose current is a getter that points to the current DOM container, the goal is simple to remove the host, example the same web-component, whether to issue events or create other hooks

    Actual state

    import { h, customElement, useRef } from "atomico";
    
    function WC() {
    	let ref = useRef();
    	useEffect(() => {
    		console.log({
    			state: "mounted",
    			target: ref.current
    		});
    	}, []);
    	return <host ref={ref} />;
    }
    
    customElement("w-c", WC);
    
    

    the problem with this is that network, must be transmitted between hooks, to create effects., use Host avoids the need to transmit the reference

    import { h, customElement, useHost } from "atomico";
    
    function useLogMounted() {
    	let ref = useHost();
    	useEffect(() => {
    		console.log({
    			state: "mounted",
    			target: ref.current
    		});
    	}, []);
    }
    
    function WC() {
    	useLogMounted();
    	return <host />;
    }
    
    customElement("w-c", WC);
    

    improve shared logic.

    Other hooks in development

    useProps

    thanks to useHost, you can easily interact with a property of web-component observables.

    let [ value, setValue] = useObservable("value");
    

    useEvent

    allows to create an event to be dispatched by the web-component.

    let emitMyEvent = useEvent("my-event",{bubble:true});
    

    useChannel

    allows to create a unique context based on customEvent, useful for communication between web-components.

    let [message, setMessage] = useChannel(GlobalSymbol);
    

    This issuu is open to add logic in the form of hooks that enhance the creation and reuse of logic between web-components

    opened by UpperCod 6
  • Add support for function components

    Add support for function components

    I added the check below let raw to avoid checking type.prototype instanceof HTMLElement twice. So when it is not an instance of HTMLElement raw equals false.

    TypeScript for component props in JSX is already working without any changes 😄

    opened by efoken 5
  • Fragments not working

    Fragments not working

    Describe the bug I always wanted to report this since a long time. Fragments cannot be used in JSX like they can in React.

    Example:

    <>
      <div>Fragment example</div>
    </>
    

    See: https://reactjs.org/docs/fragments.html

    I guess the JSX runtime needs to export a Fragment symbol to make this work.

    To Reproduce Steps to reproduce the behavior:

    1. Setup an Atomico project with TypeScript
    2. Try to use fragments <> in JSX

    Expected behavior Fragments can be used in JSX. And maybe context Providers can render a fragment instead of an element?

    Additional context We currently always use <div> elements with style={{ display: 'contents' }} to work around this.

    bug 
    opened by efoken 5
  • Support setting a Host return type in Component contract

    Support setting a Host return type in Component contract

    IMO the Component type should also support defining a ReturnType, like we can do when using function componentName(props: Props<typeof props>): Host<{}>

    Should be something like this:

    export type Component<props = null, meta = any> = props extends null
      ? {
          (props: FillObject): Host<meta>;
          props?: SchemaProps;
          styles?: Sheets;
        }
      : {
          (props: DOMProps<props>): Host<meta>;
          props: SchemaInfer<props> & MetaProps<Partial<props>>;
          styles?: Sheets;
        };
    
    opened by efoken 5
  • How to expose props and observable props?

    How to expose props and observable props?

    Hi,

    I'm trying to use atomico with frintjs, ie to allow easy rendering atomico components as Micro Frontends. Here is my repo frint-atomico

    The contract is as follows:

    export default {
      render,
      hydrate,
      streamProps,
      isObservable,
    
      getMountableComponent,
      observe,
      Region,
      Provider,
    
      RegionService,
    
      ReactHandler,
    };
    

    render is the render function, naturally, so I would expect I just need to export a function that calls html<component name> or?

    streamProps is a stream of the props? as far I can see, the props are not currently exposed in atomico? I guess I could tweak atomico or define a wrapper or sth?

    hydrate is for SSR and not important at this point.

    observe is ` function to observe the component props I believe.

    Region is a class responsible for drawing the component in a FrintJS region and communicating props to/from the app. Here is the vue example.

    import composeHandlers from 'frint-component-utils/lib/composeHandlers';
    import RegionHandler from 'frint-component-handlers/lib/RegionHandler';
    
    export default {
      name: 'Region',
      inject: ['app'],
      props: [
        'name',
        'uniqueKey',
        'data',
      ],
      beforeCreate() {
        this._handler = composeHandlers(
          VueHandler,
          RegionHandler,
          {
            component: this,
          },
        );
      },
      data() {
        return this._handler.getInitialData();
      },
      updated() {
        this._handler.afterUpdate();
      },
      beforeMount() {
        this._handler.app = this.app; // context is resolved only now
        this._handler.beforeMount();
      },
      beforeDestroy() {
        this._handler.beforeDestroy();
      },
      render(h) { // eslint-disable-line
        if (this.listForRendering.length === 0) {
          return null;
        }
    
        return (
          <div>
            {this.listForRendering.map((item) => {
              const { Component, name } = item; // eslint-disable-line
              return (
                <Component key={`app-${name}`} />
              );
            })}
          </div>
        );
      }
    };
    

    listForRendering is the list of apps (components) to be rendered in the region. The life cycle methods are not essential, but beforeMount could perhaps be linked to the custom element internal connectedCallback method?

    Is it possible to do sth like the following to dynamically render the right app component by name?

    html`<app-${name}></app-${name}>`
    

    I will link this issue on an issue in the frint repo to get some advice from that end as well.

    I wonder if I can do sth like this:

    import html from "atomico/html";
    import { customElement } from "atomico";
    import { from } from 'rxjs';
    
    const MyTag = (props) => html`<h1>Hi! ${props.value}</h1>`;
    
    const MyTagComponent = (props) => ({
      render(props) => MyTag(props),
      props,
      props$: from(props)
    }
    
    MyTag.props = {
      value: { type: String, value: "Atomico" }
    };
    
    customElement("my-tag", MyTag);
    

    Cheers ;)

    opened by kristianmandrup 5
  • Context does not work with SSR

    Context does not work with SSR

    Describe the bug When using createContext, SSR is broken for me. I'm getting this errors in the console when starting Next.js:

    ReferenceError: CustomEvent is not defined
         at dispatchEvent (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/element/set-prototype.js:95:50)
         at ref.<computed> (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/hooks/custom-hooks/use-event.js:11:13)
         at detectContext (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/context.js:21:9)
         at load (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/hooks/hooks.js:19:56)
         at file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/hooks/hooks.js:21:24
         at useHook (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/hooks/create-hooks.js:14:15)
         at useState (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/hooks/hooks.js:17:12)
         at useContext (file:///Users/eike.foken/Code/test-ui/node_modules/.pnpm/[email protected]/node_modules/atomico/src/context.js:35:49)
         at useTheme (webpack-internal:///../packages/styles/src/theme/theme-provider.ts:19:68)
    

    And also later on (if I polyfill CustomEvent with an empty function):

    TypeError: node.dispatchEvent is not a function
    

    Expected behavior No errors in console

    *SSR/SSG environment (Optional, required if the problem is caused by using SSR/SSG, please complete the following information):

    bug 
    opened by efoken 0
  • Passing callbacks as styles to components

    Passing callbacks as styles to components

    Is your feature request related to a problem? Please describe. Now that the Context API is available in Atomico, it would be very nice to be able to pass callbacks to component.styles.

    Describe the solution you'd like I would like to support the following:

    const Button: Component = () => {
      // ...
    }
    
    Button.styles = [
      ({ theme }) => css`
        :host {
          color: ${theme.colors.brand};
        }
      `,
    ];
    

    I know there are CSS variables, but as we share our theme with React Native components we cannot use CSS variables. And besides that our theme contains a lot more than just colors, there are even objects containing text styles or shadows.

    The question is, how to tell the Button component above to use ThemeContext?!

    Maybe:

    Button.context = ThemeContext;
    

    or even:

    Button.styles = [
      ThemeContext,
      ({ theme }) => css`
        ...
      `,
    ];
    
    enhancement 
    opened by efoken 5
  • Template syntax alternative

    Template syntax alternative

    Is your feature request related to a problem? Please describe.

    JSX/Lit/Uhtml/etc all look and act basically the same. For those that care about the very very subtle differences between them, it is nice to have those options, but another template syntax should be supported that differs more greatly to appeal to those coming from frameworks other than React.

    Describe the solution you'd like

    Dynamic attributes:

    Dynamic attributes, or props, should be discerned by prefixing the attribute with a colon.

    <a :href="someValue">Text</a>
    <img
      :alt="'Avatar for ' + user.name"
      :src="'/avatars/' + user.id + '.jpg'"
    />
    

    Boolean Attributes

    Some HTML attributes are considered boolean attributes. Meaning they don't require a value to be valid, and their existence represents value. For example disabled, required, checked, etc.

    In these cases, the syntax should accept a variable, and if truthy, it will append the attribute in the DOM.

    <input :required="isRequired">
    <!-- will produce one of the following -->
    <input required>
    <input>
    

    Special attribute syntax for "class"

    The most commonly used attribute in all of HTML, by a landslide, is class. Because it is so common, and has some common dynamic uses, we should support a few special syntax's to make life more convenient.

    <!-- Works the same as all other dynamic attributes -->
    <div :class="'card ' + favoriteColor"></div>
    <div :class="success ? 'green' : 'red'"></div>
    
    <!-- If an object is passed in, the key is considered a class, and only applied if the value is truthy -->
    <div :class="{ 'is-active': someBoolean }"></div>
    
    <!-- If an array is passed in, each item is evaluated to a class name, falsy items are filtered out -->
    <div :class="[ 'card', favoriteColor, 'pt-lg', { 'is-active': isOnline } ]"></div>
    

    Event Bindings:

    Dynamic event bindings should be discerned by replacing the "on" prefix with an at-sign.

    <button @click="someFunction">Click me</button>
    

    Event Modifiers:

    Several event modifiers should be supported to improve code readability. At the very least prevent and stop. For example

    BAD:

    <button @click="handleClick">Text</button>
    
    function handleClick (evt) {
      evt.preventDefault();
      loadUserAvatar();
    }
    

    Can become the far more readable: GOOD:

    <button @click.prevent="loadUserAvatar">Text</button>
    

    In Vue, "Handle X" is considered an anti-pattern, because the framework can handle most events for you, and it obscures the actual functionality being performed.

    Inline expressions

    Double curlies should be used to indicate a text node be created with the evaluated result of an expression.

    <div>{{ someValue.toUpperCase() }}</div>
    

    Two-Way data binding (text)

    Two-way data binding is a common feature of framworks, like Polymer, Vue, and many others. This could be handled via an a-model attribute.

    <input a-model="someValue">
    

    This will set the value attribute of the input any time the someValue variable is modified. It would also add an event listener to the element for input events, retrieve the event.currentTarget.value and use that to update the value of the someValue variable.

    This approach would be the same as doing:

    <input :value="someValue" @input="(evt) => { someValue = evt.currentTarget.value }">
    

    This matches the intuitive approach used by Vue 2. In Vue 3 it was changed to a less intuitive approach, in which it sets modelValue instead of value and expects update:modelValue instead of input. This change was made to allow applying multiple v-model's on an element. Something not possible in Vue 2, but also, not really needed, as you could emit an object if needed.

    This would work on <input> elements with no type attribute (since it defaults to text) and most other input types (like type="email" or type="password", etc).

    Two-way data binding (Boolean)

    <input v-model="someValue" type="checkbox"> would be equivalent to

    <input
      type="checkbox"
      :checked="someValue"
      @input="(evt) => { someValue = evt.currentTarget.checked }"
    >
    

    The 5 basic directives

    You should be able to add a simple directive to your template to control common flow logic.

    • a-model
    • a-if
    • a-for
    • a-html
    • a-text
    • and a-show isn't needed but is cleaner than doing by hand

    Examples:

    • <input a-model="value"> - See the two-way data binding section above
    • <div a-if="someBool"></div> - If someBool is false, this element is removed from the DOM. Can be performant by removing a large set of DOM nodes from memory when not needed.
    • <div a-show="someBool"></div> - If someBool is false, this attribute is given style="display: none". Can be more performant if toggling visibility on a lot of DOM nodes often
    • <div a-for="(item, index) in items"></div> - Creates an element (div in this case) for every item in the items array. item and index can be renamed to anything.
    • <div a-for="(value, key) in item"></div> - Creates an element for every key in the item object. value and key can be renamed to anything.
    • <div a-html="'<strong>Text</strong>'"></div> - Applies innerHTML, can be dangerous if it contains any data supplied by a user or network request, but also useful when the value is generated internally
    • <a a-text="'text'"></a> - Applies innerText, can be useful when you don't want additional whitespace that could occur when using returns and indentation in your code.

    I probably should have started this ~wishlist~ issue with "Dear Santa,".

    enhancement 
    opened by TheJaredWilcurt 2
  • New api for Store based on Hooks

    New api for Store based on Hooks

    Describe the solution you'd like

    What if we use hooks inside a state manager? 🤔... Imagine reusing custom Hooks even in the Store, example:

    import { createStore } from "@atomico/hooks/store";
    import { usePromise } from "@atomico/hooks/use-promise";
    
    const store = createStore(
      {
        products: {},
      },
      {
        getProducts(store) {
          const [result, status] = usePromise(() => myApi(`/products`));
          
          return {
            products: {
              result,
              status,
            },
          };
        },
      }
    );
    
    store.actions.getProducts();
    
    const { result, status } = store.state.products;
    

    Additional context

    The goal of this API is to reuse customHooks to compose states at the Store level.

    ✍️ All positive or negative opinions about this proposal are welcome.

    enhancement 
    opened by UpperCod 0
  • Add new hooks from React 18

    Add new hooks from React 18

    React 18 introduced 5 new hooks which should be added to Atomico:

    • useTransition
    • useDeferredValue
    • useId
    • useSyncExternalStore
    • useInsertionEffect

    As we share some code between React Native and Atomico, it would be nice to have the new hooks available. At least I wanted to use useId and useInsertionEffect which should be pretty easy to add I guess.

    enhancement 
    opened by efoken 1
  • a package possibly imitating atomico

    a package possibly imitating atomico

    Hi, my name is Tamir and I'm a security researcher at Mend.io

    I have noticed something strange, I would be happy to get clarifications from you.

    the package https://www.npmjs.com/package/atomico-base is pretending to be atomico, while also pretending to be @UpperCod , the creator of Atomico.

    image

    the npm user also does not match https://www.npmjs.com/~uppercod

    Thanks in advance!

    enhancement 
    opened by galaktipus 2
Releases(1.68.0)
  • 1.68.0(Nov 9, 2022)

    This PR refactors part of the Atomico code, to introduce new features and maintenance improvements.

    new features.

    1. The hooks api has been refactored to now allow hooks to be tagged, thanks to this tag in the future it will be possible to filter the execution of hooks and improve their inspection, currently this functionality is being used by the new useInsertionEffect hook.
    2. in the previous version it introduced use Promise as an advance to asynchronous handling within the core, this hook has allowed us to add in this version 2 new hooks useAsync and useSuspense.
    3. se agrega useId, con soporte tanto al usar SSR o Browser.

    useInsertionEffect

    copy of React's useInsertionEffect, similar to useEffect, but this hook is executed before rendering the DOM, this hook is useful for 3rd party apis looking to manipulate the DOM before rendering the component's DOM.

    useId

    copy of React's useId, creates a unique ID for the Atomico context, the generated ID will depend on the origin, whether it is SSR or Client.

    SSR ID Example: s0-1. CLIENT ID Example: c0-1.

    useAsync y useSuspense

    useAsync: this hook is a step before the adoption of React's use hook, it allows to suspend the rendering execution of the webcomponent and to communicate to useSuspense the execution suspension.

    const getUser = (id: number): Promise<{ name: string }> =>
      fetch(`user/${id}`).then((res) => res.json());
    
    function component({ id }) {
      const user = useAsync(getUser, [id]);
      return <host>{user.name}</host>;
    }
    

    Nota 1: This hook conditions the execution of the promise according to a list of optional arguments, which allows the promise to be regenerated every time the list changes.

    Nota 2: useAsync suspends rendering execution and resumes it only if the promise has been resolved or rejected.

    useSuspense: captures all nested executions that have been paused, it returns an object that defines the state of the executions.

    function component() {
      const status = useSuspense();
      return (
        <host shadowDom>
          {status.pending ? "Loading..." : status.fulfilled ? "Done!" : "Error!"}~
          <slot />
        </host>
      );
    }
    

    Maintenance improvements

    1. migration of the use of let by const, to improve the maintenance syntax within core.
    2. deleveraging of the context api internally.
    3. migration of types from JSDOC to JSDOC with TS.

    Warnings

    This new change has generated modifications to the core at the level of hooks, currently the changes have passed all the tests without complications, we will be attentive to any bug or unexpected behavior.

    For creators of third party APIs based on createHooks, cleanEffects now has 3 execution steps:

    1. The first run clears the effects of useInsertionEffects.
    2. The second run clears the effects of useLayoutEffects.
    3. The third and last run clears the effects of useEffect. You should update your tests by adding the third run to clean up the useEffect, example:
    hooks.cleanEffects()()();
    
    Source code(tar.gz)
    Source code(zip)
  • 1.67.0(Nov 5, 2022)

    usePromise

    This hook allows us to observe the resolution of a promise, with this hook we seek to provide a utility at the core level to work with asynchronous tasks

    Syntax

    import { usePromise } from "atomico";
    
    const callback = (id: number)=>Promise.resolve(id);
    const args:Parameters<typeof callback> = [1];
    const autorun = true;
    
    const promise = usePromise( callback, args, autorun );
    

    where:

    • callback : asynchronous function.
    • args: arguments that callback requires.
    • autorun: by default true, it automatically executes the promise, if it is false the execution of the promise is suspended.
    • promise: return object, at the type level it defines the following properties:
      • pending: boolean, defines if the promise is executed but pending resolution.
      • fulfilled: boolean , defines if the promise has been fulfilled
      • result: result of the promise.
      • rejected: boolean, defines if the promise has been rejected.

    Example

    import { usePromise } from "atomico";
    
    const getUsers = (id: number) => Promise.resolve({ id, name: "Atomico" });
    
    function component() {
      const promise = usePromise(getUsers, [1]);
    
      return (
        <host>
          {promise.fulfilled ? (
            <h1>Done!</h1>
          ) : promise.pending ? (
            <h1>Loading...</h1>
          ) : (
            <h1>Error!</h1>
          )}
        </host>
      );
    }
    

    Note: At the type level, autocompletion is conditional on the state you are looking to observe.

    Source code(tar.gz)
    Source code(zip)
  • 1.66.4(Nov 2, 2022)

  • 1.66.1(Oct 26, 2022)

    Atomico through TS declarations extracted all the global constructors available in Window, sometimes these constructors were modified by third-party libraries, which could cause the props to not be inferred correctly.

    This version limits the declared types ( If you are a user of any global type not considered, attach it to an issue to add it to the allowed types )

    Source code(tar.gz)
    Source code(zip)
  • 1.66.0(Oct 16, 2022)

  • 1.65.1(Oct 12, 2022)

  • 1.65.0(Oct 6, 2022)

    Thanks to @efoken, [email protected] now allows stateless function instances in JSX🎉, for example:

    // Just a plain function, no Custom Element...
    const CloseIcon = (props) => (
      <svg viewBox="0 0 16 16" width="16" height="16" {...props}>...</svg>
    );
    
    // ... can be re-used in JSX like this:
    function button() {
      return (
        <host shadowDom>
          <button>
            <CloseIcon aria-hidden="true" />
          </button>
        </host>
      );
    }
    
    Source code(tar.gz)
    Source code(zip)
  • 1.64.0(Sep 23, 2022)

  • 1.63.0(Sep 14, 2022)

    Add support for fragments

    You can now use the <></> fragment tag through jsx-runtime.

    Improve the use of props

    Previously null values were kept as null, this did not favor the use of default parameters when destructing the props object or defining a default prop when using a callback as a value reducer, example:

    function component({ value = 100 }: Props<typeof component>) {
        return <host>{value}</host>;
    }
    
    component.props = { value: Number };
    

    If prop is defined as null, value will be equal to null. but since [email protected] any value declared as null will be defined as undefined in the component's prop object, so value will be defined as undefined

    Source code(tar.gz)
    Source code(zip)
  • 1.62.3(Aug 31, 2022)

  • 1.62.2(Aug 29, 2022)

  • 1.62.1(Aug 24, 2022)

    This context synchronization error occurs when mounting the components directly in the HTML, now atomico synchronizes the contexts in non-parallel mounting situations.

    Source code(tar.gz)
    Source code(zip)
  • 1.62.0(Aug 21, 2022)

    The new Context api is introduced and internal and external improvements are added at the type level

    1. rewrite Atomico virtualDOM and hook types for better internal maintainability: Now Atomico's internal api shares the exposed type api, which improves maintainability as they are now directly related.
    2. Now the pipeline before test validates Atomico typing internally, externally and tsx through Typescript.
    3. Add context as part of the core.

    New context api

    This new api facilitates communication between components, example:

    Paso 1: declarar el contexto y consumirlo.

    import { createContext, useContext, c } from "atomico";
    
    export const Provider = createContext({ value: 0 });
    
    function component() {
      const { value } = useContext(Provider);
    
      return <host>{value}</host>;
    }
    
    export const Component = c(component);
    

    Paso 2: Instantiate the context, The <Provider> component allows to define the value for the components nested inside the <Provider/>

    import { Provider, Component } from "./component";
    
    <Provider value={{ value: "New value!" }}>
      <div>
        <div>
          <Component></Component>
        </div>
      </div>
    </Provider>;
    
    Source code(tar.gz)
    Source code(zip)
  • 1.61.1(Jul 18, 2022)

    This fixes type validation when using the Component type, correctly completing meta props

    https://github.com/atomicojs/atomico/issues/82#issuecomment-1187687609

    Source code(tar.gz)
    Source code(zip)
  • 1.61.0(Jul 16, 2022)

    Now the Component type allows, through a second parameter, to define meta types, such as methods and events:

    import { Component, useEvent } from "atomico";
    
    interface Props {
      checked: boolean;
    }
    
    interface MetaProps {
      onChange: Event;
    }
    
    const myComponent: Component<Props, MetaProps> = ({ checked }) => {
      const dispatchChange = useEvent("Change");
      return (
        <host>
          <input checked={checked} onchange={dispatchChange} />
        </host>
      );
    };
    
    myComponent.props = {
      checked: Boolean,
    };
    
    export const MyComponent = c(myComponent);
    

    Meta Props are only declared for JSX(Atomico, Preact and React), example:

    <MyComponent  onChange={(event)=>{
        event.currentTarget.checked // TS: boolean
    }}/>
    
    Source code(tar.gz)
    Source code(zip)
  • 1.60.0(Jul 3, 2022)

  • 1.59.1(Jun 5, 2022)

    Fix fixture type for TS

    now the return of the instance is correctly inferred

    const element = fixture<typeof MyElement>(<MyElement/>)
    

    update README.md

    adaptability in npm is improved and more sponsors are added

    Source code(tar.gz)
    Source code(zip)
  • 1.59.0(May 17, 2022)

    this changes the rendering process of Atomico, Atomico used to individualize the text nodes, now it concatenates them to facilitate hydration from the SSR.

    this allows improvements at the level of DOM analysis, since now Atomico reduces the DOM nodes of the Text type, example:

    // Before, in this case atomic generated 6 nodes
    [1,2,3,4] // Mark,Text(1), Text(2), Text(3), Text(4), Mark
    
    // After, Now atomico spawns only 3 nodes
    [1,2,3,4] // Mark,Text(1234), Mark
    
    Source code(tar.gz)
    Source code(zip)
  • 1.58.0(May 14, 2022)

    useHook

    This hook is used internally to know the render cycle state of the hooks, this update exposes this hook to be used by third parties. The usage references are in the same Atomico core in the following hooks, useState, useMemo, useEffect, useLayouteEffect and useRef

    Source code(tar.gz)
    Source code(zip)
  • 1.57.0(May 11, 2022)

    This enhancement exposes on return as String, the type, attributes, and innerHTML properties.

    this is meta information needed to extend SSR to other environments, example Next js

    Source code(tar.gz)
    Source code(zip)
Owner
Atomico
Atomico is a library for the creation of interfaces only using functions.
Atomico
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Micro.publish is an Obsidian plugin to publish notes directly to Micro.blog, written in TypeScript

Micro.publish Micro.publish is a community maintained plugin for Obsidian to publish notes to a Micro.blog blog. Installing This plugin will be availa

Otavio Cordeiro 14 Dec 9, 2022
Pure and simple virtual DOM library

Maquette Maquette is a Javascript utility which makes it easy to synchronize the DOM tree in the browser with your data. It uses a technique called 'V

AFAS Software 736 Jan 4, 2023
Builds components using a simple and explicit API around virtual-dom

Etch is a library for writing HTML-based user interface components that provides the convenience of a virtual DOM, while at the same time striving to

Atom 553 Dec 15, 2022
minimalist virtual dom library

petit-dom A minimalist virtual DOM library. Supports HTML & SVG elements. Supports Render functions and Fragments. Custom components allows to build y

Yassine Elouafi 485 Dec 12, 2022
A small javascript DOM manipulation library based on Jquery's syntax. Acts as a small utility library with the most common functions.

Quantdom JS Quantdom is a very small (about 600 bytes when ran through terser & gzipped) dom danipulation library that uuses a Jquery like syntax and

Sean McQuaid 7 Aug 16, 2022
Million is a lightweight (<1kb) Virtual DOM. It's really fast and makes it easy to create user interfaces.

?? Watch Video ?? Read the docs ?? Join our Discord What is Million? Million is a lightweight (<1kb) Virtual DOM. It's really fast and makes it easy t

Derek Jones 5 Aug 24, 2022
A Fast & Light Virtual DOM Alternative

hyper(HTML) ?? Community Announcement Please ask questions in the dedicated discussions repository, to help the community around this project grow ♥ A

Andrea Giammarchi 3k Dec 30, 2022
Component oriented framework with Virtual dom (fast, stable, with tooling)

Bobril Main site bobril.com Changelog of npm version: https://github.com/Bobris/Bobril/blob/master/CHANGELOG.md Component oriented framework inspired

Boris Letocha 359 Dec 4, 2022
Functions Recipes is a library of examples to help you getting started with Salesforce Functions and get used to their main features.

Functions Recipes Introduction Salesforce Functions lets you use the Salesforce Platform for building event-driven, elastically scalable apps and expe

Trailhead Apps 172 Dec 29, 2022
Easily create key board shortcuts for your JS functions. Built using JS only with no other dependency. Inspired from MacOS spotlight

floodlightjs Inspired from macOS spotlight, floodlight is simple JS library that will show a search area. How the search is handled is completely on y

Raj Nandan Sharma 6 Aug 12, 2022
Custom Vitest matchers to test the state of the DOM, forked from jest-dom.

vitest-dom Custom Vitest matchers to test the state of the DOM This library is a fork of @testing-library/jest-dom. It shares that library's implement

Chance Strickland 14 Dec 16, 2022
A little JavaScript plugin to generate PDF, XLS, CSV and DOC from JavaScript Object or DOM element only from the frontend!

?? JavaScript Object to csv, xls, pdf, doc and DOM to html generator ?? A little JavaScript plugin to generate PDF, XLS, CSV and DOC from JavaScript O

null 61 Jan 7, 2023
🌈 GitHub following, followers, only-following, only-follower tracker 🌈

github-following-tracker GitHub following, followers, only-following, only-follower tracker ?? Just enter your GitHub name and track your followings!

Youngkwon Kim 10 Jun 15, 2022
Simple format that serves it's one and only purpose and that's creating simple task list everywhere where you can write plain text

SWTF (Simple Worklog Task Format) Simple format that serves it's one and only purpose and that's creating simple task list everywhere where you can wr

null 4 Apr 4, 2022
Making(Creating , Modifying , Deleting) Lists you have to do 😎 Built Only with Html, JavaScript, Css

To-Do_App Live Demo You Can See The Project Live On: Here Description A Simple To-Do App Mainly Written In Javascript The project structure is kinda l

null 6 Nov 2, 2022
JavaScript micro-library: pass in an element and a callback and this will trigger when you click anywhere other than the element

Add a click listener to fire a callback for everywhere on the window except your chosen element. Installation run npm install @lukeboyle/when-clicked-

Boyleing Point 5 May 13, 2021