@nymbalhq/web-components 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/astro/NymbalElement.astro +19 -0
- package/dist/base-element-CPMgAdyQ.d.ts +91 -0
- package/dist/chunk-2TPQNQYO.js +155 -0
- package/dist/chunk-2TPQNQYO.js.map +1 -0
- package/dist/chunk-2XXBQPDB.js +113 -0
- package/dist/chunk-2XXBQPDB.js.map +1 -0
- package/dist/chunk-42SSME5H.js +84 -0
- package/dist/chunk-42SSME5H.js.map +1 -0
- package/dist/chunk-4COVK727.js +204 -0
- package/dist/chunk-4COVK727.js.map +1 -0
- package/dist/chunk-5VWZ2U5K.js +149 -0
- package/dist/chunk-5VWZ2U5K.js.map +1 -0
- package/dist/chunk-6XCCAAMF.js +656 -0
- package/dist/chunk-6XCCAAMF.js.map +1 -0
- package/dist/chunk-7JAAOVCE.js +114 -0
- package/dist/chunk-7JAAOVCE.js.map +1 -0
- package/dist/chunk-B73QVSA5.js +206 -0
- package/dist/chunk-B73QVSA5.js.map +1 -0
- package/dist/chunk-DR5QB5VN.js +17 -0
- package/dist/chunk-DR5QB5VN.js.map +1 -0
- package/dist/chunk-DXWMNB5F.js +70 -0
- package/dist/chunk-DXWMNB5F.js.map +1 -0
- package/dist/chunk-EBMA7JGV.js +130 -0
- package/dist/chunk-EBMA7JGV.js.map +1 -0
- package/dist/chunk-EYDMJNNK.js +176 -0
- package/dist/chunk-EYDMJNNK.js.map +1 -0
- package/dist/chunk-FIF6GQ6U.js +141 -0
- package/dist/chunk-FIF6GQ6U.js.map +1 -0
- package/dist/chunk-GHXTJ2CF.js +109 -0
- package/dist/chunk-GHXTJ2CF.js.map +1 -0
- package/dist/chunk-H3ZBYNHV.js +153 -0
- package/dist/chunk-H3ZBYNHV.js.map +1 -0
- package/dist/chunk-HPBC3OG7.js +174 -0
- package/dist/chunk-HPBC3OG7.js.map +1 -0
- package/dist/chunk-IYT7VXFS.js +105 -0
- package/dist/chunk-IYT7VXFS.js.map +1 -0
- package/dist/chunk-LHYXNQWY.js +105 -0
- package/dist/chunk-LHYXNQWY.js.map +1 -0
- package/dist/chunk-LO2EW5YP.js +25 -0
- package/dist/chunk-LO2EW5YP.js.map +1 -0
- package/dist/chunk-LSQPUZK6.js +291 -0
- package/dist/chunk-LSQPUZK6.js.map +1 -0
- package/dist/chunk-N4Y5DI4X.js +82 -0
- package/dist/chunk-N4Y5DI4X.js.map +1 -0
- package/dist/chunk-NE6UHTOT.js +148 -0
- package/dist/chunk-NE6UHTOT.js.map +1 -0
- package/dist/chunk-NW47OJVN.js +138 -0
- package/dist/chunk-NW47OJVN.js.map +1 -0
- package/dist/chunk-O2YKCDR2.js +77 -0
- package/dist/chunk-O2YKCDR2.js.map +1 -0
- package/dist/chunk-PN6QKYE4.js +71 -0
- package/dist/chunk-PN6QKYE4.js.map +1 -0
- package/dist/chunk-RAOGZH3Z.js +188 -0
- package/dist/chunk-RAOGZH3Z.js.map +1 -0
- package/dist/chunk-RVSKX2RX.js +11 -0
- package/dist/chunk-RVSKX2RX.js.map +1 -0
- package/dist/chunk-RZVFA3N5.js +154 -0
- package/dist/chunk-RZVFA3N5.js.map +1 -0
- package/dist/chunk-SM7TASEW.js +135 -0
- package/dist/chunk-SM7TASEW.js.map +1 -0
- package/dist/chunk-U2PU4CWB.js +124 -0
- package/dist/chunk-U2PU4CWB.js.map +1 -0
- package/dist/chunk-UCEVCLQ7.js +5 -0
- package/dist/chunk-UCEVCLQ7.js.map +1 -0
- package/dist/chunk-UYSZOEOA.js +32 -0
- package/dist/chunk-UYSZOEOA.js.map +1 -0
- package/dist/chunk-V55K2CS5.js +126 -0
- package/dist/chunk-V55K2CS5.js.map +1 -0
- package/dist/chunk-VTQVGNVC.js +346 -0
- package/dist/chunk-VTQVGNVC.js.map +1 -0
- package/dist/chunk-W23P7SI4.js +239 -0
- package/dist/chunk-W23P7SI4.js.map +1 -0
- package/dist/chunk-W7D3STJH.js +279 -0
- package/dist/chunk-W7D3STJH.js.map +1 -0
- package/dist/chunk-WEEHXWM3.js +172 -0
- package/dist/chunk-WEEHXWM3.js.map +1 -0
- package/dist/chunk-WTEVTCIL.js +128 -0
- package/dist/chunk-WTEVTCIL.js.map +1 -0
- package/dist/chunk-XE6IWISA.js +137 -0
- package/dist/chunk-XE6IWISA.js.map +1 -0
- package/dist/elements/nymbal-add-to-cart.d.ts +14 -0
- package/dist/elements/nymbal-add-to-cart.js +10 -0
- package/dist/elements/nymbal-add-to-cart.js.map +1 -0
- package/dist/elements/nymbal-address-book.d.ts +30 -0
- package/dist/elements/nymbal-address-book.js +13 -0
- package/dist/elements/nymbal-address-book.js.map +1 -0
- package/dist/elements/nymbal-address-form.d.ts +29 -0
- package/dist/elements/nymbal-address-form.js +12 -0
- package/dist/elements/nymbal-address-form.js.map +1 -0
- package/dist/elements/nymbal-breadcrumb.d.ts +15 -0
- package/dist/elements/nymbal-breadcrumb.js +11 -0
- package/dist/elements/nymbal-breadcrumb.js.map +1 -0
- package/dist/elements/nymbal-cart-drawer.d.ts +24 -0
- package/dist/elements/nymbal-cart-drawer.js +11 -0
- package/dist/elements/nymbal-cart-drawer.js.map +1 -0
- package/dist/elements/nymbal-cart-page.d.ts +20 -0
- package/dist/elements/nymbal-cart-page.js +14 -0
- package/dist/elements/nymbal-cart-page.js.map +1 -0
- package/dist/elements/nymbal-category-nav.d.ts +15 -0
- package/dist/elements/nymbal-category-nav.js +11 -0
- package/dist/elements/nymbal-category-nav.js.map +1 -0
- package/dist/elements/nymbal-checkout.d.ts +77 -0
- package/dist/elements/nymbal-checkout.js +15 -0
- package/dist/elements/nymbal-checkout.js.map +1 -0
- package/dist/elements/nymbal-image-gallery.d.ts +19 -0
- package/dist/elements/nymbal-image-gallery.js +10 -0
- package/dist/elements/nymbal-image-gallery.js.map +1 -0
- package/dist/elements/nymbal-login-form.d.ts +17 -0
- package/dist/elements/nymbal-login-form.js +12 -0
- package/dist/elements/nymbal-login-form.js.map +1 -0
- package/dist/elements/nymbal-mini-cart.d.ts +17 -0
- package/dist/elements/nymbal-mini-cart.js +10 -0
- package/dist/elements/nymbal-mini-cart.js.map +1 -0
- package/dist/elements/nymbal-order-summary.d.ts +20 -0
- package/dist/elements/nymbal-order-summary.js +11 -0
- package/dist/elements/nymbal-order-summary.js.map +1 -0
- package/dist/elements/nymbal-payment-element.d.ts +4 -0
- package/dist/elements/nymbal-payment-element.js +10 -0
- package/dist/elements/nymbal-payment-element.js.map +1 -0
- package/dist/elements/nymbal-product-card.d.ts +4 -0
- package/dist/elements/nymbal-product-card.js +12 -0
- package/dist/elements/nymbal-product-card.js.map +1 -0
- package/dist/elements/nymbal-product-filter.d.ts +32 -0
- package/dist/elements/nymbal-product-filter.js +10 -0
- package/dist/elements/nymbal-product-filter.js.map +1 -0
- package/dist/elements/nymbal-product-grid.d.ts +24 -0
- package/dist/elements/nymbal-product-grid.js +14 -0
- package/dist/elements/nymbal-product-grid.js.map +1 -0
- package/dist/elements/nymbal-product-price.d.ts +18 -0
- package/dist/elements/nymbal-product-price.js +12 -0
- package/dist/elements/nymbal-product-price.js.map +1 -0
- package/dist/elements/nymbal-profile-form.d.ts +19 -0
- package/dist/elements/nymbal-profile-form.js +12 -0
- package/dist/elements/nymbal-profile-form.js.map +1 -0
- package/dist/elements/nymbal-quantity-selector.d.ts +20 -0
- package/dist/elements/nymbal-quantity-selector.js +10 -0
- package/dist/elements/nymbal-quantity-selector.js.map +1 -0
- package/dist/elements/nymbal-register-form.d.ts +17 -0
- package/dist/elements/nymbal-register-form.js +12 -0
- package/dist/elements/nymbal-register-form.js.map +1 -0
- package/dist/elements/nymbal-review-form.d.ts +17 -0
- package/dist/elements/nymbal-review-form.js +12 -0
- package/dist/elements/nymbal-review-form.js.map +1 -0
- package/dist/elements/nymbal-review-list.d.ts +14 -0
- package/dist/elements/nymbal-review-list.js +10 -0
- package/dist/elements/nymbal-review-list.js.map +1 -0
- package/dist/elements/nymbal-search-bar.d.ts +19 -0
- package/dist/elements/nymbal-search-bar.js +10 -0
- package/dist/elements/nymbal-search-bar.js.map +1 -0
- package/dist/elements/nymbal-search-results.d.ts +29 -0
- package/dist/elements/nymbal-search-results.js +14 -0
- package/dist/elements/nymbal-search-results.js.map +1 -0
- package/dist/elements/nymbal-site-footer.d.ts +15 -0
- package/dist/elements/nymbal-site-footer.js +11 -0
- package/dist/elements/nymbal-site-footer.js.map +1 -0
- package/dist/elements/nymbal-site-header.d.ts +19 -0
- package/dist/elements/nymbal-site-header.js +11 -0
- package/dist/elements/nymbal-site-header.js.map +1 -0
- package/dist/elements/nymbal-sort-dropdown.d.ts +28 -0
- package/dist/elements/nymbal-sort-dropdown.js +10 -0
- package/dist/elements/nymbal-sort-dropdown.js.map +1 -0
- package/dist/elements/nymbal-stock-badge.d.ts +16 -0
- package/dist/elements/nymbal-stock-badge.js +11 -0
- package/dist/elements/nymbal-stock-badge.js.map +1 -0
- package/dist/elements/nymbal-toast.d.ts +18 -0
- package/dist/elements/nymbal-toast.js +10 -0
- package/dist/elements/nymbal-toast.js.map +1 -0
- package/dist/elements/nymbal-variant-selector.d.ts +16 -0
- package/dist/elements/nymbal-variant-selector.js +10 -0
- package/dist/elements/nymbal-variant-selector.js.map +1 -0
- package/dist/form-element-C-qo3gpD.d.ts +25 -0
- package/dist/hydrate-support.d.ts +2 -0
- package/dist/hydrate-support.js +3 -0
- package/dist/hydrate-support.js.map +1 -0
- package/dist/index.d.ts +37 -105
- package/dist/index.js +130 -1098
- package/dist/index.js.map +1 -1
- package/dist/nymbal-payment-element-Bt8EF42T.d.ts +51 -0
- package/dist/nymbal-product-card-C8HkE_rG.d.ts +47 -0
- package/dist/register-components.d.ts +46 -0
- package/dist/register-components.js +48 -0
- package/dist/register-components.js.map +1 -0
- package/dist/selected-variant-Dym0shlJ.d.ts +23 -0
- package/dist/ssr/index.d.ts +30 -0
- package/dist/ssr/index.js +143 -0
- package/dist/ssr/index.js.map +1 -0
- package/package.json +33 -6
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
// One Nymbal element rendered on the server: the tag with its attributes, its declarative shadow root, then the slot's
|
|
3
|
+
// content as its light DOM. The browser parses the template into the element's shadow root, and the element, once
|
|
4
|
+
// defined, takes that markup over. A project's own class under the tag renders instead when its elements entry
|
|
5
|
+
// registered it (registerServerElements).
|
|
6
|
+
import { renderElement } from '../dist/ssr/index.js'
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
tag: string
|
|
10
|
+
/** The host's attributes; a JSON attribute's value is its JSON text. */
|
|
11
|
+
attributes?: Record<string, string>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { tag, attributes } = Astro.props
|
|
15
|
+
const children = Astro.slots.has('default') ? await Astro.slots.render('default') : ''
|
|
16
|
+
const html = renderElement(tag, { attributes, children })
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<Fragment set:html={html} />
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
2
|
+
import { NymbalClient } from '@nymbalhq/sdk';
|
|
3
|
+
|
|
4
|
+
/** A Nymbal element class, as `define` takes it. */
|
|
5
|
+
interface NymbalElementClass extends CustomElementConstructor {
|
|
6
|
+
schema: ElementSchema;
|
|
7
|
+
/** The Nymbal elements it renders in its own shadow root, which must be defined for it to work. */
|
|
8
|
+
uses?: readonly NymbalElementClass[];
|
|
9
|
+
/** What the element needs registered before it runs; called whether or not its tag is still free. */
|
|
10
|
+
beforeDefine?(): void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Defines each element under its schema's tag, with the elements it renders, except a tag that is already defined:
|
|
14
|
+
* an element the project defined first under a Nymbal tag wins.
|
|
15
|
+
*/
|
|
16
|
+
declare function define(...elements: NymbalElementClass[]): void;
|
|
17
|
+
|
|
18
|
+
/** How an attribute's value reads: the React wrapper types its prop from this, and JSON travels stringified. */
|
|
19
|
+
type ElementAttributeType = 'string' | 'number' | 'boolean' | 'json';
|
|
20
|
+
/**
|
|
21
|
+
* An element's public interface, declared once on the class. Its Lit properties are derived from `attributes`, and the
|
|
22
|
+
* React wrappers are generated from it, so neither can disagree with the element.
|
|
23
|
+
*/
|
|
24
|
+
interface ElementSchema {
|
|
25
|
+
tag: string;
|
|
26
|
+
/** The React wrapper's component name. */
|
|
27
|
+
reactName: string;
|
|
28
|
+
/** `name` is the HTML attribute, `prop` the React prop and the Lit property. */
|
|
29
|
+
attributes: Array<{
|
|
30
|
+
name: string;
|
|
31
|
+
prop: string;
|
|
32
|
+
type: ElementAttributeType;
|
|
33
|
+
}>;
|
|
34
|
+
/** `name` is the DOM event, `prop` the React handler, `detail` the TypeScript type of its detail. */
|
|
35
|
+
events: Array<{
|
|
36
|
+
name: string;
|
|
37
|
+
prop: string;
|
|
38
|
+
detail: string;
|
|
39
|
+
}>;
|
|
40
|
+
/** Every `part` the element renders, for `::part()` styling. */
|
|
41
|
+
parts: string[];
|
|
42
|
+
/** Every named `slot` it renders, each with its default content as the fallback. */
|
|
43
|
+
slots: string[];
|
|
44
|
+
/** Whether the React wrapper passes children through. */
|
|
45
|
+
children: boolean;
|
|
46
|
+
}
|
|
47
|
+
interface Subscribable {
|
|
48
|
+
subscribe(fn: () => void): () => void;
|
|
49
|
+
getState(): unknown;
|
|
50
|
+
}
|
|
51
|
+
declare abstract class NymbalElement extends LitElement {
|
|
52
|
+
static schema: ElementSchema;
|
|
53
|
+
/** Defines this element, and those it renders, unless its tag is already defined (see `define`). */
|
|
54
|
+
static define(this: NymbalElementClass): void;
|
|
55
|
+
private _unsubs;
|
|
56
|
+
/** Set while the element's first render takes over a server's shadow root (see `readsStores`). */
|
|
57
|
+
private _serverRender;
|
|
58
|
+
protected get client(): NymbalClient;
|
|
59
|
+
/** Whether a client is registered: never on a server. Without one the element subscribes to no store. */
|
|
60
|
+
protected get hasClient(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Whether this render reads the client's stores. Not on a server, and not in the first render of an element taking
|
|
63
|
+
* over a server's shadow root: hydration needs the server's render (a store still loading would change it), so that
|
|
64
|
+
* render is the server's, and the element renders again from its stores straight after.
|
|
65
|
+
*/
|
|
66
|
+
protected get readsStores(): boolean;
|
|
67
|
+
/** The SDK stores the element renders from; it re-renders on each change while connected. */
|
|
68
|
+
protected stores(): Subscribable[];
|
|
69
|
+
/**
|
|
70
|
+
* A store `stores()` named has settled (an update that is not `loading`): the properties a server rendered this
|
|
71
|
+
* element from give way to it. An update while loading leaves them showing, so a count does not flip to 0 and back.
|
|
72
|
+
*/
|
|
73
|
+
protected storeSettled(_store: Subscribable): void;
|
|
74
|
+
connectedCallback(): void;
|
|
75
|
+
/**
|
|
76
|
+
* A store that settled before this element connected sends it no update, so the properties a server gave (a page
|
|
77
|
+
* restored from a router's cache after the cart changed elsewhere) give way to it here.
|
|
78
|
+
*/
|
|
79
|
+
private takeSettledStores;
|
|
80
|
+
/**
|
|
81
|
+
* React inserts a soft navigation's server HTML with `innerHTML`, which leaves the declarative shadow root an unparsed
|
|
82
|
+
* template: it becomes this element's shadow root here, before Lit looks for one, so the element hydrates it rather
|
|
83
|
+
* than rendering a second. A parsed declarative shadow root (a full load) is already `shadowRoot`.
|
|
84
|
+
*/
|
|
85
|
+
protected createRenderRoot(): HTMLElement | DocumentFragment;
|
|
86
|
+
protected update(changed: PropertyValues): void;
|
|
87
|
+
disconnectedCallback(): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { NymbalElement as N, define as d };
|
|
91
|
+
export type { ElementAttributeType as E, Subscribable as S, ElementSchema as a, NymbalElementClass as b };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
|
|
2
|
+
import {
|
|
3
|
+
NymbalElement,
|
|
4
|
+
baseStyles,
|
|
5
|
+
propertiesOf
|
|
6
|
+
} from "./chunk-EYDMJNNK.js";
|
|
7
|
+
|
|
8
|
+
// src/components/toast.ts
|
|
9
|
+
import { css, html } from "lit";
|
|
10
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
11
|
+
var SCHEMA = {
|
|
12
|
+
tag: "nymbal-toast",
|
|
13
|
+
reactName: "Toast",
|
|
14
|
+
attributes: [
|
|
15
|
+
{ name: "position", prop: "position", type: "string" },
|
|
16
|
+
{ name: "duration-ms", prop: "durationMs", type: "number" }
|
|
17
|
+
],
|
|
18
|
+
events: [],
|
|
19
|
+
parts: ["item", "message", "close"],
|
|
20
|
+
slots: [],
|
|
21
|
+
children: false
|
|
22
|
+
};
|
|
23
|
+
var nextId = 0;
|
|
24
|
+
var NymbalToast = class extends NymbalElement {
|
|
25
|
+
static schema = SCHEMA;
|
|
26
|
+
static properties = propertiesOf(SCHEMA);
|
|
27
|
+
static styles = [
|
|
28
|
+
baseStyles,
|
|
29
|
+
css`
|
|
30
|
+
:host {
|
|
31
|
+
position: fixed;
|
|
32
|
+
z-index: var(--nymbal-z-toast, 300);
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: var(--nymbal-spacing-sm, 0.5rem);
|
|
36
|
+
pointer-events: none;
|
|
37
|
+
font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);
|
|
38
|
+
}
|
|
39
|
+
:host([position='top-right']),
|
|
40
|
+
:host(:not([position])) {
|
|
41
|
+
top: var(--nymbal-spacing-lg, 1.5rem);
|
|
42
|
+
right: var(--nymbal-spacing-lg, 1.5rem);
|
|
43
|
+
}
|
|
44
|
+
:host([position='top-left']) {
|
|
45
|
+
top: var(--nymbal-spacing-lg, 1.5rem);
|
|
46
|
+
left: var(--nymbal-spacing-lg, 1.5rem);
|
|
47
|
+
}
|
|
48
|
+
:host([position='bottom-right']) {
|
|
49
|
+
bottom: var(--nymbal-spacing-lg, 1.5rem);
|
|
50
|
+
right: var(--nymbal-spacing-lg, 1.5rem);
|
|
51
|
+
}
|
|
52
|
+
:host([position='bottom-left']) {
|
|
53
|
+
bottom: var(--nymbal-spacing-lg, 1.5rem);
|
|
54
|
+
left: var(--nymbal-spacing-lg, 1.5rem);
|
|
55
|
+
}
|
|
56
|
+
[part~='item'] {
|
|
57
|
+
pointer-events: auto;
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: var(--nymbal-spacing-sm, 0.5rem);
|
|
61
|
+
padding: var(--nymbal-spacing-sm, 0.5rem) var(--nymbal-spacing-md, 1rem);
|
|
62
|
+
border-radius: var(--nymbal-radius-md, 0.375rem);
|
|
63
|
+
box-shadow: var(--nymbal-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));
|
|
64
|
+
font-size: var(--nymbal-font-size-sm, 0.875rem);
|
|
65
|
+
background: var(--nymbal-color-surface, #ffffff);
|
|
66
|
+
color: var(--nymbal-color-text, #18181b);
|
|
67
|
+
border: 1px solid var(--nymbal-color-border, #e4e4e7);
|
|
68
|
+
animation: nymbal-toast-in var(--nymbal-transition-normal, 200ms ease) forwards;
|
|
69
|
+
max-width: 360px;
|
|
70
|
+
}
|
|
71
|
+
[part~='item'][data-type='success'] {
|
|
72
|
+
border-left: 3px solid var(--nymbal-color-success, #16a34a);
|
|
73
|
+
}
|
|
74
|
+
[part~='item'][data-type='error'] {
|
|
75
|
+
border-left: 3px solid var(--nymbal-color-error, #dc2626);
|
|
76
|
+
}
|
|
77
|
+
[part~='item'][data-type='warning'] {
|
|
78
|
+
border-left: 3px solid var(--nymbal-color-warning, #d97706);
|
|
79
|
+
}
|
|
80
|
+
[part~='item'][data-type='info'] {
|
|
81
|
+
border-left: 3px solid var(--nymbal-color-accent, #2563eb);
|
|
82
|
+
}
|
|
83
|
+
[part~='close'] {
|
|
84
|
+
background: none;
|
|
85
|
+
border: none;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
color: var(--nymbal-color-text-muted, #71717a);
|
|
88
|
+
font-size: var(--nymbal-font-size-base, 1rem);
|
|
89
|
+
padding: 0;
|
|
90
|
+
margin-left: auto;
|
|
91
|
+
}
|
|
92
|
+
@keyframes nymbal-toast-in {
|
|
93
|
+
from {
|
|
94
|
+
opacity: 0;
|
|
95
|
+
transform: translateY(-8px);
|
|
96
|
+
}
|
|
97
|
+
to {
|
|
98
|
+
opacity: 1;
|
|
99
|
+
transform: translateY(0);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
`
|
|
103
|
+
];
|
|
104
|
+
_items = [];
|
|
105
|
+
connectedCallback() {
|
|
106
|
+
super.connectedCallback();
|
|
107
|
+
this.setAttribute("data-testid", "toast");
|
|
108
|
+
}
|
|
109
|
+
show(message, type = "info") {
|
|
110
|
+
const durationMs = Number(this.getAttribute("duration-ms")) || 4e3;
|
|
111
|
+
const item = { id: ++nextId, message, type };
|
|
112
|
+
this._items = [...this._items, item];
|
|
113
|
+
this.requestUpdate();
|
|
114
|
+
setTimeout(() => this.dismiss(item.id), durationMs);
|
|
115
|
+
}
|
|
116
|
+
dismiss(id) {
|
|
117
|
+
const remaining = this._items.filter((i) => i.id !== id);
|
|
118
|
+
if (remaining.length === this._items.length) return;
|
|
119
|
+
this._items = remaining;
|
|
120
|
+
this.requestUpdate();
|
|
121
|
+
}
|
|
122
|
+
render() {
|
|
123
|
+
return repeat(
|
|
124
|
+
this._items,
|
|
125
|
+
(item) => item.id,
|
|
126
|
+
(item) => html`
|
|
127
|
+
<div part="item" class="nymbal-toast-item" data-type=${item.type} role="alert">
|
|
128
|
+
<span part="message">${item.message}</span>
|
|
129
|
+
<button
|
|
130
|
+
type="button"
|
|
131
|
+
part="close"
|
|
132
|
+
class="nymbal-toast-close"
|
|
133
|
+
aria-label="Dismiss"
|
|
134
|
+
@click=${() => this.dismiss(item.id)}
|
|
135
|
+
>
|
|
136
|
+
×
|
|
137
|
+
</button>
|
|
138
|
+
</div>
|
|
139
|
+
`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
static showGlobal(message, type = "info") {
|
|
143
|
+
let toastEl = document.querySelector("nymbal-toast");
|
|
144
|
+
if (!toastEl) {
|
|
145
|
+
toastEl = document.createElement("nymbal-toast");
|
|
146
|
+
document.body.appendChild(toastEl);
|
|
147
|
+
}
|
|
148
|
+
toastEl.show(message, type);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export {
|
|
153
|
+
NymbalToast
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=chunk-2TPQNQYO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/toast.ts"],"sourcesContent":["import { css, html } from 'lit'\nimport { repeat } from 'lit/directives/repeat.js'\nimport { baseStyles, NymbalElement, propertiesOf, type ElementSchema } from '../base-element.js'\n\ntype ToastType = 'success' | 'error' | 'warning' | 'info'\n\ninterface ToastItem {\n id: number\n message: string\n type: ToastType\n}\n\nconst SCHEMA: ElementSchema = {\n tag: 'nymbal-toast',\n reactName: 'Toast',\n attributes: [\n { name: 'position', prop: 'position', type: 'string' },\n { name: 'duration-ms', prop: 'durationMs', type: 'number' },\n ],\n events: [],\n parts: ['item', 'message', 'close'],\n slots: [],\n children: false,\n}\n\nlet nextId = 0\n\nexport class NymbalToast extends NymbalElement {\n static override schema = SCHEMA\n static override properties = propertiesOf(SCHEMA)\n\n static override styles = [\n baseStyles,\n css`\n :host {\n position: fixed;\n z-index: var(--nymbal-z-toast, 300);\n display: flex;\n flex-direction: column;\n gap: var(--nymbal-spacing-sm, 0.5rem);\n pointer-events: none;\n font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);\n }\n :host([position='top-right']),\n :host(:not([position])) {\n top: var(--nymbal-spacing-lg, 1.5rem);\n right: var(--nymbal-spacing-lg, 1.5rem);\n }\n :host([position='top-left']) {\n top: var(--nymbal-spacing-lg, 1.5rem);\n left: var(--nymbal-spacing-lg, 1.5rem);\n }\n :host([position='bottom-right']) {\n bottom: var(--nymbal-spacing-lg, 1.5rem);\n right: var(--nymbal-spacing-lg, 1.5rem);\n }\n :host([position='bottom-left']) {\n bottom: var(--nymbal-spacing-lg, 1.5rem);\n left: var(--nymbal-spacing-lg, 1.5rem);\n }\n [part~='item'] {\n pointer-events: auto;\n display: flex;\n align-items: center;\n gap: var(--nymbal-spacing-sm, 0.5rem);\n padding: var(--nymbal-spacing-sm, 0.5rem) var(--nymbal-spacing-md, 1rem);\n border-radius: var(--nymbal-radius-md, 0.375rem);\n box-shadow: var(--nymbal-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n font-size: var(--nymbal-font-size-sm, 0.875rem);\n background: var(--nymbal-color-surface, #ffffff);\n color: var(--nymbal-color-text, #18181b);\n border: 1px solid var(--nymbal-color-border, #e4e4e7);\n animation: nymbal-toast-in var(--nymbal-transition-normal, 200ms ease) forwards;\n max-width: 360px;\n }\n [part~='item'][data-type='success'] {\n border-left: 3px solid var(--nymbal-color-success, #16a34a);\n }\n [part~='item'][data-type='error'] {\n border-left: 3px solid var(--nymbal-color-error, #dc2626);\n }\n [part~='item'][data-type='warning'] {\n border-left: 3px solid var(--nymbal-color-warning, #d97706);\n }\n [part~='item'][data-type='info'] {\n border-left: 3px solid var(--nymbal-color-accent, #2563eb);\n }\n [part~='close'] {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--nymbal-color-text-muted, #71717a);\n font-size: var(--nymbal-font-size-base, 1rem);\n padding: 0;\n margin-left: auto;\n }\n @keyframes nymbal-toast-in {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n `,\n ]\n\n private _items: ToastItem[] = []\n\n override connectedCallback(): void {\n super.connectedCallback()\n this.setAttribute('data-testid', 'toast')\n }\n\n show(message: string, type: ToastType = 'info'): void {\n const durationMs = Number(this.getAttribute('duration-ms')) || 4000\n const item: ToastItem = { id: ++nextId, message, type }\n this._items = [...this._items, item]\n this.requestUpdate()\n setTimeout(() => this.dismiss(item.id), durationMs)\n }\n\n private dismiss(id: number): void {\n const remaining = this._items.filter((i) => i.id !== id)\n if (remaining.length === this._items.length) return\n this._items = remaining\n this.requestUpdate()\n }\n\n protected override render() {\n return repeat(\n this._items,\n (item) => item.id,\n (item) => html`\n <div part=\"item\" class=\"nymbal-toast-item\" data-type=${item.type} role=\"alert\">\n <span part=\"message\">${item.message}</span>\n <button\n type=\"button\"\n part=\"close\"\n class=\"nymbal-toast-close\"\n aria-label=\"Dismiss\"\n @click=${() => this.dismiss(item.id)}\n >\n ×\n </button>\n </div>\n `,\n )\n }\n\n static showGlobal(message: string, type: ToastType = 'info'): void {\n let toastEl = document.querySelector('nymbal-toast') as NymbalToast | null\n if (!toastEl) {\n toastEl = document.createElement('nymbal-toast') as NymbalToast\n document.body.appendChild(toastEl)\n }\n toastEl.show(message, type)\n }\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,KAAK,YAAY;AAC1B,SAAS,cAAc;AAWvB,IAAM,SAAwB;AAAA,EAC5B,KAAK;AAAA,EACL,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,MAAM,YAAY,MAAM,YAAY,MAAM,SAAS;AAAA,IACrD,EAAE,MAAM,eAAe,MAAM,cAAc,MAAM,SAAS;AAAA,EAC5D;AAAA,EACA,QAAQ,CAAC;AAAA,EACT,OAAO,CAAC,QAAQ,WAAW,OAAO;AAAA,EAClC,OAAO,CAAC;AAAA,EACR,UAAU;AACZ;AAEA,IAAI,SAAS;AAEN,IAAM,cAAN,cAA0B,cAAc;AAAA,EAC7C,OAAgB,SAAS;AAAA,EACzB,OAAgB,aAAa,aAAa,MAAM;AAAA,EAEhD,OAAgB,SAAS;AAAA,IACvB;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0EF;AAAA,EAEQ,SAAsB,CAAC;AAAA,EAEtB,oBAA0B;AACjC,UAAM,kBAAkB;AACxB,SAAK,aAAa,eAAe,OAAO;AAAA,EAC1C;AAAA,EAEA,KAAK,SAAiB,OAAkB,QAAc;AACpD,UAAM,aAAa,OAAO,KAAK,aAAa,aAAa,CAAC,KAAK;AAC/D,UAAM,OAAkB,EAAE,IAAI,EAAE,QAAQ,SAAS,KAAK;AACtD,SAAK,SAAS,CAAC,GAAG,KAAK,QAAQ,IAAI;AACnC,SAAK,cAAc;AACnB,eAAW,MAAM,KAAK,QAAQ,KAAK,EAAE,GAAG,UAAU;AAAA,EACpD;AAAA,EAEQ,QAAQ,IAAkB;AAChC,UAAM,YAAY,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AACvD,QAAI,UAAU,WAAW,KAAK,OAAO,OAAQ;AAC7C,SAAK,SAAS;AACd,SAAK,cAAc;AAAA,EACrB;AAAA,EAEmB,SAAS;AAC1B,WAAO;AAAA,MACL,KAAK;AAAA,MACL,CAAC,SAAS,KAAK;AAAA,MACf,CAAC,SAAS;AAAA,+DAC+C,KAAK,IAAI;AAAA,iCACvC,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAMxB,MAAM,KAAK,QAAQ,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAM5C;AAAA,EACF;AAAA,EAEA,OAAO,WAAW,SAAiB,OAAkB,QAAc;AACjE,QAAI,UAAU,SAAS,cAAc,cAAc;AACnD,QAAI,CAAC,SAAS;AACZ,gBAAU,SAAS,cAAc,cAAc;AAC/C,eAAS,KAAK,YAAY,OAAO;AAAA,IACnC;AACA,YAAQ,KAAK,SAAS,IAAI;AAAA,EAC5B;AACF;","names":[]}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
|
|
2
|
+
import {
|
|
3
|
+
NymbalElement,
|
|
4
|
+
baseStyles,
|
|
5
|
+
propertiesOf
|
|
6
|
+
} from "./chunk-EYDMJNNK.js";
|
|
7
|
+
|
|
8
|
+
// src/components/mini-cart.ts
|
|
9
|
+
import { css, html, nothing } from "lit";
|
|
10
|
+
var SCHEMA = {
|
|
11
|
+
tag: "nymbal-mini-cart",
|
|
12
|
+
reactName: "MiniCart",
|
|
13
|
+
// The cart's item count a server read, shown until the cart store settles.
|
|
14
|
+
attributes: [{ name: "count", prop: "count", type: "number" }],
|
|
15
|
+
events: [{ name: "nymbal:mini-cart:clicked", prop: "onClick", detail: "void" }],
|
|
16
|
+
parts: ["button", "icon", "badge"],
|
|
17
|
+
slots: ["icon"],
|
|
18
|
+
children: false
|
|
19
|
+
};
|
|
20
|
+
var NymbalMiniCart = class extends NymbalElement {
|
|
21
|
+
static schema = SCHEMA;
|
|
22
|
+
static properties = propertiesOf(SCHEMA);
|
|
23
|
+
static styles = [
|
|
24
|
+
baseStyles,
|
|
25
|
+
css`
|
|
26
|
+
:host {
|
|
27
|
+
display: inline-block;
|
|
28
|
+
position: relative;
|
|
29
|
+
}
|
|
30
|
+
[part~='button'] {
|
|
31
|
+
background: none;
|
|
32
|
+
border: none;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
position: relative;
|
|
35
|
+
padding: var(--nymbal-spacing-sm, 0.5rem);
|
|
36
|
+
font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);
|
|
37
|
+
color: var(--nymbal-color-text, #18181b);
|
|
38
|
+
}
|
|
39
|
+
[part~='icon'] {
|
|
40
|
+
display: block;
|
|
41
|
+
width: 24px;
|
|
42
|
+
height: 24px;
|
|
43
|
+
}
|
|
44
|
+
[part~='badge'] {
|
|
45
|
+
position: absolute;
|
|
46
|
+
top: 0;
|
|
47
|
+
right: 0;
|
|
48
|
+
background: var(--nymbal-color-accent, #2563eb);
|
|
49
|
+
color: var(--nymbal-color-text-inverse, #ffffff);
|
|
50
|
+
font-size: var(--nymbal-font-size-xs, 0.75rem);
|
|
51
|
+
font-weight: var(--nymbal-font-weight-bold, 700);
|
|
52
|
+
min-width: 18px;
|
|
53
|
+
height: 18px;
|
|
54
|
+
border-radius: var(--nymbal-radius-full, 9999px);
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
line-height: 1;
|
|
59
|
+
}
|
|
60
|
+
[part~='badge']:empty {
|
|
61
|
+
display: none;
|
|
62
|
+
}
|
|
63
|
+
`
|
|
64
|
+
];
|
|
65
|
+
stores() {
|
|
66
|
+
return [this.client.cart];
|
|
67
|
+
}
|
|
68
|
+
storeSettled() {
|
|
69
|
+
this.count = void 0;
|
|
70
|
+
}
|
|
71
|
+
itemCount() {
|
|
72
|
+
if (typeof this.count === "number" && Number.isFinite(this.count)) return this.count;
|
|
73
|
+
return this.readsStores ? this.client.cart.getState().itemCount : 0;
|
|
74
|
+
}
|
|
75
|
+
render() {
|
|
76
|
+
const itemCount = this.itemCount();
|
|
77
|
+
return html`<button
|
|
78
|
+
type="button"
|
|
79
|
+
part="button"
|
|
80
|
+
data-testid="mini-cart"
|
|
81
|
+
aria-label="Cart (${itemCount} items)"
|
|
82
|
+
@click=${this.handleClick}
|
|
83
|
+
>
|
|
84
|
+
<slot name="icon"
|
|
85
|
+
><svg
|
|
86
|
+
part="icon"
|
|
87
|
+
viewBox="0 0 24 24"
|
|
88
|
+
fill="none"
|
|
89
|
+
stroke="currentColor"
|
|
90
|
+
stroke-width="2"
|
|
91
|
+
stroke-linecap="round"
|
|
92
|
+
stroke-linejoin="round"
|
|
93
|
+
>
|
|
94
|
+
<circle cx="9" cy="21" r="1" />
|
|
95
|
+
<circle cx="20" cy="21" r="1" />
|
|
96
|
+
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" /></svg
|
|
97
|
+
></slot>
|
|
98
|
+
<span part="badge" class="nymbal-mini-cart-badge" data-testid="mini-cart-badge"
|
|
99
|
+
>${itemCount > 0 ? itemCount : nothing}</span
|
|
100
|
+
>
|
|
101
|
+
</button>`;
|
|
102
|
+
}
|
|
103
|
+
handleClick = () => {
|
|
104
|
+
this.dispatchEvent(
|
|
105
|
+
new CustomEvent("nymbal:mini-cart:clicked", { bubbles: true, composed: true })
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export {
|
|
111
|
+
NymbalMiniCart
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=chunk-2XXBQPDB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/mini-cart.ts"],"sourcesContent":["import { css, html, nothing } from 'lit'\nimport { baseStyles, NymbalElement, propertiesOf, type ElementSchema } from '../base-element.js'\n\nconst SCHEMA: ElementSchema = {\n tag: 'nymbal-mini-cart',\n reactName: 'MiniCart',\n // The cart's item count a server read, shown until the cart store settles.\n attributes: [{ name: 'count', prop: 'count', type: 'number' }],\n events: [{ name: 'nymbal:mini-cart:clicked', prop: 'onClick', detail: 'void' }],\n parts: ['button', 'icon', 'badge'],\n slots: ['icon'],\n children: false,\n}\n\nexport class NymbalMiniCart extends NymbalElement {\n static override schema = SCHEMA\n static override properties = propertiesOf(SCHEMA)\n\n static override styles = [\n baseStyles,\n css`\n :host {\n display: inline-block;\n position: relative;\n }\n [part~='button'] {\n background: none;\n border: none;\n cursor: pointer;\n position: relative;\n padding: var(--nymbal-spacing-sm, 0.5rem);\n font-family: var(--nymbal-font-family, system-ui, -apple-system, sans-serif);\n color: var(--nymbal-color-text, #18181b);\n }\n [part~='icon'] {\n display: block;\n width: 24px;\n height: 24px;\n }\n [part~='badge'] {\n position: absolute;\n top: 0;\n right: 0;\n background: var(--nymbal-color-accent, #2563eb);\n color: var(--nymbal-color-text-inverse, #ffffff);\n font-size: var(--nymbal-font-size-xs, 0.75rem);\n font-weight: var(--nymbal-font-weight-bold, 700);\n min-width: 18px;\n height: 18px;\n border-radius: var(--nymbal-radius-full, 9999px);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n }\n [part~='badge']:empty {\n display: none;\n }\n `,\n ]\n\n declare count: number | undefined\n\n protected override stores() {\n return [this.client.cart]\n }\n\n protected override storeSettled(): void {\n this.count = undefined\n }\n\n private itemCount(): number {\n if (typeof this.count === 'number' && Number.isFinite(this.count)) return this.count\n return this.readsStores ? this.client.cart.getState().itemCount : 0\n }\n\n protected override render() {\n const itemCount = this.itemCount()\n // An empty badge is `nothing`, not '': Lit's hydration records a server-rendered '' as a committed text node the\n // server never wrote, so the first count after it (a header mounted once the cart has loaded) lands in the part's\n // end marker and the badge stays empty.\n return html`<button\n type=\"button\"\n part=\"button\"\n data-testid=\"mini-cart\"\n aria-label=\"Cart (${itemCount} items)\"\n @click=${this.handleClick}\n >\n <slot name=\"icon\"\n ><svg\n part=\"icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"9\" cy=\"21\" r=\"1\" />\n <circle cx=\"20\" cy=\"21\" r=\"1\" />\n <path d=\"M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6\" /></svg\n ></slot>\n <span part=\"badge\" class=\"nymbal-mini-cart-badge\" data-testid=\"mini-cart-badge\"\n >${itemCount > 0 ? itemCount : nothing}</span\n >\n </button>`\n }\n\n private handleClick = (): void => {\n this.dispatchEvent(\n new CustomEvent('nymbal:mini-cart:clicked', { bubbles: true, composed: true }),\n )\n }\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,KAAK,MAAM,eAAe;AAGnC,IAAM,SAAwB;AAAA,EAC5B,KAAK;AAAA,EACL,WAAW;AAAA;AAAA,EAEX,YAAY,CAAC,EAAE,MAAM,SAAS,MAAM,SAAS,MAAM,SAAS,CAAC;AAAA,EAC7D,QAAQ,CAAC,EAAE,MAAM,4BAA4B,MAAM,WAAW,QAAQ,OAAO,CAAC;AAAA,EAC9E,OAAO,CAAC,UAAU,QAAQ,OAAO;AAAA,EACjC,OAAO,CAAC,MAAM;AAAA,EACd,UAAU;AACZ;AAEO,IAAM,iBAAN,cAA6B,cAAc;AAAA,EAChD,OAAgB,SAAS;AAAA,EACzB,OAAgB,aAAa,aAAa,MAAM;AAAA,EAEhD,OAAgB,SAAS;AAAA,IACvB;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuCF;AAAA,EAImB,SAAS;AAC1B,WAAO,CAAC,KAAK,OAAO,IAAI;AAAA,EAC1B;AAAA,EAEmB,eAAqB;AACtC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,YAAoB;AAC1B,QAAI,OAAO,KAAK,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,EAAG,QAAO,KAAK;AAC/E,WAAO,KAAK,cAAc,KAAK,OAAO,KAAK,SAAS,EAAE,YAAY;AAAA,EACpE;AAAA,EAEmB,SAAS;AAC1B,UAAM,YAAY,KAAK,UAAU;AAIjC,WAAO;AAAA;AAAA;AAAA;AAAA,0BAIe,SAAS;AAAA,eACpB,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAiBpB,YAAY,IAAI,YAAY,OAAO;AAAA;AAAA;AAAA,EAG5C;AAAA,EAEQ,cAAc,MAAY;AAChC,SAAK;AAAA,MACH,IAAI,YAAY,4BAA4B,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,IAC/E;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import '@lit-labs/ssr-client/lit-element-hydrate-support.js'
|
|
2
|
+
import {
|
|
3
|
+
NymbalFormElement,
|
|
4
|
+
renderField
|
|
5
|
+
} from "./chunk-PN6QKYE4.js";
|
|
6
|
+
import {
|
|
7
|
+
buttonStyles,
|
|
8
|
+
fieldStyles
|
|
9
|
+
} from "./chunk-GHXTJ2CF.js";
|
|
10
|
+
import {
|
|
11
|
+
baseStyles,
|
|
12
|
+
propertiesOf
|
|
13
|
+
} from "./chunk-EYDMJNNK.js";
|
|
14
|
+
|
|
15
|
+
// src/components/login-form.ts
|
|
16
|
+
import { html } from "lit";
|
|
17
|
+
var SCHEMA = {
|
|
18
|
+
tag: "nymbal-login-form",
|
|
19
|
+
reactName: "LoginForm",
|
|
20
|
+
attributes: [],
|
|
21
|
+
events: [
|
|
22
|
+
{
|
|
23
|
+
name: "nymbal:auth:signed-in",
|
|
24
|
+
prop: "onSignedIn",
|
|
25
|
+
detail: "{ customer: unknown }"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
parts: ["form", "field", "label", "input", "error", "submit"],
|
|
29
|
+
slots: ["submit-label"],
|
|
30
|
+
children: false
|
|
31
|
+
};
|
|
32
|
+
var NymbalLoginForm = class extends NymbalFormElement {
|
|
33
|
+
static schema = SCHEMA;
|
|
34
|
+
static properties = propertiesOf(SCHEMA);
|
|
35
|
+
static styles = [baseStyles, buttonStyles, fieldStyles];
|
|
36
|
+
// The page leaves on success; a second sign-in while it does would only race the redirect.
|
|
37
|
+
lockOnSuccess = true;
|
|
38
|
+
async send() {
|
|
39
|
+
await this.client.auth.login(this.value("email"), this.value("password"));
|
|
40
|
+
this.emit("nymbal:auth:signed-in", { customer: this.client.auth.getState().customer });
|
|
41
|
+
}
|
|
42
|
+
failureText(err) {
|
|
43
|
+
return err instanceof Error && err.message !== "" ? err.message : "Invalid email or password.";
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
return html`
|
|
47
|
+
${this.renderError()}
|
|
48
|
+
<form part="form" data-testid="login-form" @submit=${this.onSubmit}>
|
|
49
|
+
${renderField({
|
|
50
|
+
id: "login-email",
|
|
51
|
+
name: "email",
|
|
52
|
+
label: "Email",
|
|
53
|
+
type: "email",
|
|
54
|
+
autocomplete: "email",
|
|
55
|
+
required: true,
|
|
56
|
+
placeholder: "you@example.com"
|
|
57
|
+
})}
|
|
58
|
+
${renderField({
|
|
59
|
+
id: "login-password",
|
|
60
|
+
name: "password",
|
|
61
|
+
label: "Password",
|
|
62
|
+
type: "password",
|
|
63
|
+
autocomplete: "current-password",
|
|
64
|
+
required: true,
|
|
65
|
+
placeholder: "Your password"
|
|
66
|
+
})}
|
|
67
|
+
<button
|
|
68
|
+
type="submit"
|
|
69
|
+
part="submit"
|
|
70
|
+
class="btn btn-primary"
|
|
71
|
+
data-testid="login-submit"
|
|
72
|
+
?disabled=${this.pending}
|
|
73
|
+
>
|
|
74
|
+
${this.pending ? "Signing in..." : html`<slot name="submit-label">Sign In</slot>`}
|
|
75
|
+
</button>
|
|
76
|
+
</form>
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
NymbalLoginForm
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=chunk-42SSME5H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/login-form.ts"],"sourcesContent":["import { html } from 'lit'\nimport { baseStyles, propertiesOf, type ElementSchema } from '../base-element.js'\nimport { NymbalFormElement, renderField } from '../form-element.js'\nimport { buttonStyles, fieldStyles } from '../view-styles.js'\n\nconst SCHEMA: ElementSchema = {\n tag: 'nymbal-login-form',\n reactName: 'LoginForm',\n attributes: [],\n events: [\n {\n name: 'nymbal:auth:signed-in',\n prop: 'onSignedIn',\n detail: '{ customer: unknown }',\n },\n ],\n parts: ['form', 'field', 'label', 'input', 'error', 'submit'],\n slots: ['submit-label'],\n children: false,\n}\n\n/** Signs the shopper in; the page decides where they go next (`nymbal:auth:signed-in`). */\nexport class NymbalLoginForm extends NymbalFormElement {\n static override schema = SCHEMA\n static override properties = propertiesOf(SCHEMA)\n static override styles = [baseStyles, buttonStyles, fieldStyles]\n\n // The page leaves on success; a second sign-in while it does would only race the redirect.\n protected override readonly lockOnSuccess = true\n\n protected override async send(): Promise<void> {\n await this.client.auth.login(this.value('email'), this.value('password'))\n this.emit('nymbal:auth:signed-in', { customer: this.client.auth.getState().customer })\n }\n\n protected override failureText(err: unknown): string {\n return err instanceof Error && err.message !== '' ? err.message : 'Invalid email or password.'\n }\n\n protected override render() {\n return html`\n ${this.renderError()}\n <form part=\"form\" data-testid=\"login-form\" @submit=${this.onSubmit}>\n ${renderField({\n id: 'login-email',\n name: 'email',\n label: 'Email',\n type: 'email',\n autocomplete: 'email',\n required: true,\n placeholder: 'you@example.com',\n })}\n ${renderField({\n id: 'login-password',\n name: 'password',\n label: 'Password',\n type: 'password',\n autocomplete: 'current-password',\n required: true,\n placeholder: 'Your password',\n })}\n <button\n type=\"submit\"\n part=\"submit\"\n class=\"btn btn-primary\"\n data-testid=\"login-submit\"\n ?disabled=${this.pending}\n >\n ${this.pending ? 'Signing in...' : html`<slot name=\"submit-label\">Sign In</slot>`}\n </button>\n </form>\n `\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA,SAAS,YAAY;AAKrB,IAAM,SAAwB;AAAA,EAC5B,KAAK;AAAA,EACL,WAAW;AAAA,EACX,YAAY,CAAC;AAAA,EACb,QAAQ;AAAA,IACN;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF;AAAA,EACA,OAAO,CAAC,QAAQ,SAAS,SAAS,SAAS,SAAS,QAAQ;AAAA,EAC5D,OAAO,CAAC,cAAc;AAAA,EACtB,UAAU;AACZ;AAGO,IAAM,kBAAN,cAA8B,kBAAkB;AAAA,EACrD,OAAgB,SAAS;AAAA,EACzB,OAAgB,aAAa,aAAa,MAAM;AAAA,EAChD,OAAgB,SAAS,CAAC,YAAY,cAAc,WAAW;AAAA;AAAA,EAGnC,gBAAgB;AAAA,EAE5C,MAAyB,OAAsB;AAC7C,UAAM,KAAK,OAAO,KAAK,MAAM,KAAK,MAAM,OAAO,GAAG,KAAK,MAAM,UAAU,CAAC;AACxE,SAAK,KAAK,yBAAyB,EAAE,UAAU,KAAK,OAAO,KAAK,SAAS,EAAE,SAAS,CAAC;AAAA,EACvF;AAAA,EAEmB,YAAY,KAAsB;AACnD,WAAO,eAAe,SAAS,IAAI,YAAY,KAAK,IAAI,UAAU;AAAA,EACpE;AAAA,EAEmB,SAAS;AAC1B,WAAO;AAAA,QACH,KAAK,YAAY,CAAC;AAAA,2DACiC,KAAK,QAAQ;AAAA,UAC9D,YAAY;AAAA,MACZ,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,MACd,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC,CAAC;AAAA,UACA,YAAY;AAAA,MACZ,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,MACd,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAMY,KAAK,OAAO;AAAA;AAAA,YAEtB,KAAK,UAAU,kBAAkB,8CAA8C;AAAA;AAAA;AAAA;AAAA,EAIzF;AACF;","names":[]}
|