Coder Social home page Coder Social logo

component-register's People

Contributors

creativetechguy avatar jurijzahn8019 avatar ryansolid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

component-register's Issues

Do not stringify string values on reflection

Hi There,

In case a prop should be reflected and has a string value,
JSON.stringify produces quoted result, which end quoted in the attribute value.

It would be better, stringigfy is not used for strings.

let reflect = JSON.stringify(value);

I know, the behaviour is harmless for parsing, but it kinda breaks with CSS selectors

image

Question: how to handle reconnect properly?

Standard web component has 3 key lifecycle point: create(constructor), connected, disconnected. This is because an element may be remove from dom and added back again and again. With these hooks, we could create something in constructure but reuse them from time to time.

But lifecycles defined by this repo are only create and release, which means we have to recreate all thing after reconnecting.

Am I missing something? Or how could we handle this?

Polyfill: Regex Parsing :Host Incorrectly

Polyfill not properly parsing :host styling.

Input:

:host(.light)
  ::slotted(a:active)
    color:#1a1a1a

Output:
:host(.light) example_component slot > a:active{color:#1a1a1a;}

Use default value if attribute has been removed

Hi there,

I have a situation where I have defined a property with a default/initial value,
which is a "thrithy" value

Now the consumer adds/defines the attribute and provides a "falsy" value for this,
and after a while, the attribute gets removed again.

I know this is nothing that should happen, but in our demo system, it is the case.

Now according to this statement:

      if (name in propDefinition) {
        if (newVal == null && !this[name]) return;
        this[name] = propDefinition[name].parse ? parseAttributeValue(newVal) : newVal;
      }

Processing of the attribute change stops du to the fact the value is falsy.
But I need it to be the default again.

I have tried to use attribute changed callback, to add my own logic, but unfortunately
this is not called, since it is only called after the attribute has been successfully changed.

Would it be possible to either:

  • Add a config based process to update the value to its default value
  • Call a callback function which could provide such a value?

In general, it would be very nice to provide custom value parser to the prop by config.

I don't mind to make a PR if you agree with this request.

Thanks in Advance ๐Ÿ˜„

SSR story?

Does this library support SSR?

I'm kinda working on a new approach to micro frobtends

I want to avoid webpack and module federation

I'll probably use vanilla js with jsdoc type defs

The goal is to create a sort of iframe that isn't: I'm thinking of calling it "FakeFrame" it just fetches the html for another app, and injects it into this shadow dom container.

It could use solid but probably shouldn't because it's not necessary.

When rendering server side, it would make the same request for an apps html. If that app gave us server side rendered html, all the better, if not, the scripts will render client side, as that app expects.

String with only numbers is erroneously parsed as integer

Hello Ryan!

I'm making a web component that displays information about a Discord ID, meaning someone could use <discord-user user-id="210246661446959104" /> and it would display its username and more information. Unfortunately, due to this line ( https://github.com/ryansolid/component-register/blob/master/src/utils.ts#L118 ) the Discord ID gets converted to a number which breaks it because that converts it to 210246661446959100.
image

In my humble opinion, automatic parsing should not be done on incoming argument values, as is made evident here.

ability to expose methods on web component

Hi, is it possible to expose custom methods on the final web component object? I would need a way to expose some api from the component (think of a player play(), pause()).

Expose utils.PropDefinition type definition

I have built a generic wrapper to create custom elements.

And I would like to reuse PropDefinition<T> type in my code.

At the moment I do this ugly stuff in order to acquire the type:

... PropsDefinitionInput<{ [PP in P]: T[PP] | undefined | null }>[P];

Thanks in advance ๐Ÿ˜„

Question: docs about `noShadowDOM`?

How to create a custom elements without shadow dom? The readme didn't talk about that. After searching I found there is a noShadowDOM function and I tried to call it in the hoc, it seems take effect but I am not sure if it will affect other creations which didn't call it (which should have the shadow dom).

Context consumers do not work inside an anchor element.

I've been working on a vanilla js implementation of a web component for a shopify store. Weirdly enough... only when the web component is nested within an anchor tag does the following functionality error.

Is there something I'm doing wrong here?

import {
  createEffect,
  createMemo,
  createRoot,
  createSignal,
  onCleanup,
  on,
  For,
  Show,
} from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
import { insert } from 'https://cdn.jsdelivr.net/npm/[email protected]/web/+esm';
import html from 'https://cdn.jsdelivr.net/npm/[email protected]/html/+esm';
import {
  register,
  createContext,
  withProvider,
  withConsumer,
  compose,
} from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';

// Utility custom element functions

function getContext(element) {
  const elementContextSymbol = Object.getOwnPropertySymbols(element).find((s) => s.description === 'element-context');
  const contextSymbol = Object.getOwnPropertySymbols(element[elementContextSymbol]).find(
    (s) => s.description === 'context'
  );
  return element[elementContextSymbol][contextSymbol];
}

function createProps(raw) {
  const keys = Object.keys(raw);
  const props = {};
  for (let i = 0; i < keys.length; i++) {
    const [get, set] = createSignal(raw[keys[i]]);
    Object.defineProperty(props, keys[i], {
      get() {
        return get();
      },
      set(v) {
        set(() => v);
      },
    });
  }
  return props;
}

function lookupContext(el) {
  if (el.assignedSlot && el.assignedSlot._$owner) return el.assignedSlot._$owner;
  let next = el.parentNode;
  while (next && !next._$owner && !(next.assignedSlot && next.assignedSlot._$owner)) next = next.parentNode;
  return next && next.assignedSlot ? next.assignedSlot._$owner : el._$owner;
}

function withSolid(ComponentType) {
  return (rawProps, options) => {
    const { element } = options;
    return createRoot((dispose) => {
      const props = createProps(rawProps);
      element.addPropertyChangedCallback((key, val) => (props[key] = val));
      element.addReleaseCallback(() => {
        element.renderRoot.textContent = '';
        dispose();
      });
      const comp = ComponentType(props, options);
      return insert(element.renderRoot, comp);
    }, lookupContext(element));
  };
}

function withNoShadowDOM(ComponentType = (props, options) => {}) {
  return (props, options) => {
    const { element } = options;
    element.renderRoot = element;
    return ComponentType(props, options);
  };
}

const customShadowlessElement = (tagName, props = {}, Component = (props, options) => {}, ...rest) =>
  compose(register(tagName, props), withNoShadowDOM, withSolid, ...rest)(Component);

const ItemContext = createContext((index = 0) => {
  const [idx, setIdx] = createSignal(index);
  const item = createMemo(() => Shopify.StorefrontCart.cart().items[idx()]);
  return [item, setIdx];
});

function CartItemContext(props, { element }) {
  const [item, setIdx] = getContext(element);
  createEffect(on(item, (item) => console.log(item, 'TESTING')));
  createEffect(
    on(
      () => props.position,
      (position) => setIdx(position)
    )
  );
}

function CartItems(props, { element }) {
  const itemTMPL = element.querySelector('template');
  if (!itemTMPL) return;

  return html`
    <${Show} when=${() => Shopify.StorefrontCart.cart() && Shopify.StorefrontCart.cart().items.length > 0}>
      <${For} each=${() => Shopify.StorefrontCart.cart().items}>
        ${(_, idx) => html` <cart-item-context position=${() => idx()}
          >${() => itemTMPL.content.cloneNode(true)}</cart-item-context
        >`}
      <//>
    <//>
  `;
}

function CartItem(props, { element, itemContext }) {
  console.log(Object.entries(element), 'TESTING');
  const [item] = itemContext;

  const value = createMemo(() => {
    const i = item();
    console.log(i);
    const keys = props.propertyName.split('.').filter((key) => key.length > 0);
    const v = keys.reduce((acc, key) => acc[key], i);
    switch (props.format) {
      case 'currency':
        return Shopify.formatMoney(v);
      case 'number':
        return v;
      case 'link':
        const tmpl = element.querySelector('template');
        return html`<a
          class=${element.getAttribute('class') || ''}
          style=${element.getAttribute('style') || ''}
          href=${v}
          >${tmpl.content.cloneNode(true)}</a
        >`;
      default:
        return v;
    }
  });

  return html` <${Show} when=${value}> ${value} <//> `;
}

customShadowlessElement('cart-items', {}, CartItems);
customShadowlessElement(
  'cart-item',
  { propertyName: '', format: 'none' },
  CartItem,
  withConsumer(ItemContext, 'itemContext')
);
customShadowlessElement('cart-item-context', { position: 0 }, CartItemContext, withProvider(ItemContext));

Here's an idea of how I'm using these web components:

  <cart-items>
      <template>
          <div>
              <cart-item property-name="url" format="link">
                  <cart-item property-name="title"></cart-item>
              </cart-item>
              <a href="#">
                  <cart-item property-name="title"></cart-item>
              </a>
              <cart-item property-name="quantity"></cart-item>
          </div>
      </template>
  </cart-items>

Here's how the code is rendered in the dom:

    <cart-items>
      <template>
          <div>
              <cart-item property-name="url" format="link">
                  <cart-item property-name="title"></cart-item>
              </cart-item>
              <a href="#">
                  <cart-item property-name="title"></cart-item>
              </a>
              <cart-item property-name="quantity"></cart-item>
          </div>
      </template>
      <cart-item-context>
          <div>
              <!-- This works and renders an a tag--->
              <cart-item property-name="url" format="link">
                  <a href="/products/testing" class="" style="">
                      <!-- Error creating component CartItem: TypeError: itemContext is not iterable --->
                      <cart-item property-name="title"></cart-item>
                   </a>
              </cart-item>
              <a href="#">
                  <!-- Error creating component CartItem: TypeError: itemContext is not iterable --->
                  <cart-item property-name="title">Testing</cart-item>
              </a>
              <!-- This works and renders the quantity --->
              <cart-item property-name="quantity">1</cart-item>
          </div>
      </cart-item-context>
  </cart-items>

Error: "Error creating component CartItem: TypeError: itemContext is not iterable"

Any help here would be greatly appreciated! Thanks ahead of time!

missing type DocumentAndElementEventHandlers from elements.d.ts

I tried to use solid-element to setup a web component library project, but for some reason when trying to generate types during build, it throws error

../../node_modules/component-register/types/element.d.ts:185:26 - error TS2304: Cannot find name 'DocumentAndElementEventHandlers'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.