@use "/shell" as *; @use "quark:list" as list; #release-notice { /* opens once: sheet re-runs restart a delay, so gate it on the fact it writes */ &:not([data-did-open]) { @delay 7000 { is-open: ""; data-did-open: ""; } } /* prevent clicks from bubbling to the sheet */ @on mouseup, click (stop-propagation); } provider-fetch[api-url*="package-metas/index.json"][is-success] { $package-indices: prop("provision").body; /* `excom.navGroup` moves a package out of its type's list, into that group */ $ungrouped: list.reject($package-indices.packages, "navGroup"); .package-links { [bind-elements] ul:not(ul ul) { content: iterate(getPackagesByType($ungrouped, "kit-element")); } [bind-element-bases] ul:not(ul ul) { content: iterate(getPackagesByType($ungrouped, "element-base")); } [bind-tools] ul:not(ul ul) { content: iterate(getPackagesByType($ungrouped, "tool")); } /* the standalone libraries: same rows, rendered flat (shell.css) */ [bind-libraries] ul:not(ul ul) { content: iterate(getPackagesByType($ungrouped, "library")); } [bind-library-group] ul:not(ul ul) { content: iterate(list.filter($package-indices.packages, "navGroup", "libraries")); } ul:not(ul ul) > li { $pkg: item.shortName; > spa-a { route-href: "/packages/#{item.shortName}"; } } /* one `content` rule per link: a second one would rewrite the first's text on every pass */ ul:not(ul ul, [bind-libraries] ul) > li > spa-a { content: item.shortName; } [bind-libraries] ul:not(ul ul) > li > spa-a { content: displayName(item.shortName); } /* packages whose docs span several pages: one collapsible group per section */ [bind-sections] { content: iterate(item.docSections); summary { content: item.title; } details > ul { content: iterate(item.docs); spa-a { route-href: "/packages/#{$pkg}/#{item.name}"; content: item.title; } } details:not(:has(spa-a[is-active])) { open: none; } } } /* page titles: the page, then the site. The docs home keeps the title in the document head; the other routes carry theirs in markup */ spa-route[is-active] { /* a site guide */ &[route-href$=":name"] { $title-guide: list.find($package-indices.docs, "name", $route.params.name); document-title: "#{$title-guide.title or $route.params.name} · Nucleus · docs"; } /* a package README */ &[route-href$=":packageName"] { document-title: "#{displayName($route.params.packageName)} · Nucleus · docs"; } /* one page of a package's docs */ &[route-href$=":docName"] { $title-package: list.find($package-indices.packages, "shortName", $route.params.packageName); document-title: "#{docTitle($title-package, $route.params.docName)} · #{displayName($route.params.packageName)} · Nucleus · docs"; } } /* the page's markdown file, for the footer link: the docs home and each guide the index lists, and a package's page whose index entry says `markdown` (build-docs-index sets it; the dev server's index has none, so no link there). siteDocHref and the path check say which URL is the page's own: the 404 and a package's doc pages have none */ > spa-manager[active-url] { $page-path: attr("active-url").split("#").at(0).split("?").at(0); $page-name: if($page-path == SITE_HOME: SITE_HOME_DOC; else: $page-path.split("/").at(-1)); $page-guide: list.find($package-indices.docs, "name", $page-name); $page-package: list.find($package-indices.packages, "shortName", $page-name); $page-markdown: if($page-guide and siteDocHref($page-guide.name) == $page-path: "/docs/#{$page-guide.name}.md"; $page-package.markdown and "#{SITE_BASE}/packages/#{$page-package.shortName}" == $page-path: "/#{$page-package.shortName}.md"); footer [bind-page-markdown] { href: $page-markdown; content: ternary($page-markdown, "Markdown version of this page"); } } } spa-route { $route: prop("provision"); /* paramless routes name their guide in markup (the docs home, `/`); /docs/:name gets it from params */ $route-doc-name: attr("data-doc-name"); } /* the desktop aside and the mobile sheet stamp the same nav template */ [data-site-nav] { details:has(spa-a[is-active]) { /* not kosher */ open: ""; } spa-a[is-active] { aria-current: ""; } spa-a:not([is-active]) { aria-current: none; } } /* mobile sheet: Escape / back gesture while open; a tapped link closes it */ #site-menu { &[is-open] dismiss-watcher { is-active: ""; } &:not([is-open]) dismiss-watcher { is-active: none; } @on click (target: "spa-a") { is-open: none; } } #site-menu-gesture { &:has(> #site-menu[is-open]) { progress-offset: 1; } &:not(:has(> #site-menu[is-open])) { progress-offset: 0; } @on gesture-handler-start { #site-menu { is-scrubbing: ""; } } @on gesture-handler-end { #site-menu { is-open: event.detail.snap == 1; is-scrubbing: none; } } } main { @on copy-source (handle: copySource); } #search-dialog[open] { > include-content { is-active: ""; /* for some reason this is necessary on first render */ @on include-content-did-render (handle: focusInput); } input[type="search"] { /* works on all subsequent opens */ autofocus: ""; } } #search-dialog:not([open]) input[type="search"] { autofocus: none; }

quark-sheet

Drop a Quark sheet next to your markup — bind, render, and react without a component runtime.

Features

  • Sibling scope Sheet + targets share a parent — Quark watches that host
  • Global sheets is-global runs top-level rules document-wide
  • Inline or remote Paste Quark in the element, or load src-url
  • Lifecycle state is-loading / is-success / is-error + matching events (from loadable-element)
  • Reload The --reload command drops the shared cache entry for src-url and fetches again
  • Auto (un)register Connect registers; disconnect tears down cleanly

Installation

This package is available in the NucleusKit. Or it can be used by itself:

CDN Package Manager
<script src="https://unpkg.com/@excom/kit-utils@0.3.0/dist/index.umd.min.js"></script>
<script src="https://unpkg.com/@excom/neutron@0.2.0/dist/index.umd.min.js"></script>
<script src="https://unpkg.com/@excom/quark-sheet@0.2.1/dist/index.umd.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@excom/quark-sheet@0.2.1/dist/index.css">
npm install @excom/quark-sheet
HTML Imports JS / CSS Imports
<!-- import path to `node_modules` will depend on your build setup -->
<script type="module" src="/node_modules/@excom/quark-sheet"></script>
<link rel="stylesheet" href="/node_modules/@excom/quark-sheet">
import "@excom/quark-sheet";
@import "@excom/quark-sheet/index.css";
Peer dependencies (0)

Packages a consumer must install alongside this one. Workspace deps are bundled.

Package Version
View Dist Files

All exports:

.
  • types: ./dist/index.d.ts
  • import: ./dist/index.js
  • default: ./dist/index.js
./index
  • types: ./dist/index.d.ts
  • import: ./dist/index.js
  • default: ./dist/index.js
./index.bundle.min.css
  • default: ./dist/index.bundle.min.css
./index.css
  • default: ./dist/index.css
./index.js
  • types: ./dist/index.d.ts
  • import: ./dist/index.js
  • default: ./dist/index.js
./index.min
  • types: ./dist/index.d.ts
  • import: ./dist/index.min.js
  • default: ./dist/index.min.js
./index.min.css
  • default: ./dist/index.min.css
./index.min.js
  • types: ./dist/index.d.ts
  • import: ./dist/index.min.js
  • default: ./dist/index.min.js
./index.umd.min
  • types: ./dist/index.d.ts
  • default: ./dist/index.umd.min.js
./index.umd.min.js
  • types: ./dist/index.d.ts
  • default: ./dist/index.umd.min.js
./quark-sheet
  • types: ./dist/quark-sheet.d.ts
  • import: ./dist/quark-sheet.js
  • default: ./dist/quark-sheet.js
./quark-sheet.js
  • types: ./dist/quark-sheet.d.ts
  • import: ./dist/quark-sheet.js
  • default: ./dist/quark-sheet.js
./quark-sheet.min
  • types: ./dist/quark-sheet.d.ts
  • import: ./dist/quark-sheet.min.js
  • default: ./dist/quark-sheet.min.js
./quark-sheet.min.js
  • types: ./dist/quark-sheet.d.ts
  • import: ./dist/quark-sheet.min.js
  • default: ./dist/quark-sheet.min.js
./quark-sheet.umd.min
  • types: ./dist/quark-sheet.d.ts
  • default: ./dist/quark-sheet.umd.min.js
./quark-sheet.umd.min.js
  • types: ./dist/quark-sheet.d.ts
  • default: ./dist/quark-sheet.umd.min.js
./server
  • types: ./dist/server.d.ts
  • import: ./dist/server.js
  • default: ./dist/server.js
./server.js
  • types: ./dist/server.d.ts
  • import: ./dist/server.js
  • default: ./dist/server.js
./server.min
  • types: ./dist/server.d.ts
  • import: ./dist/server.min.js
  • default: ./dist/server.min.js
./server.min.js
  • types: ./dist/server.d.ts
  • import: ./dist/server.min.js
  • default: ./dist/server.min.js

Usage

Place <quark-sheet> under the same parent as the elements it should orchestrate. Inline Quark text is enough for most apps. An inline sheet reads its text when it connects, so load the scripts with defer, as a module script, or after the markup (end of <body>); a plain <script src> in <head> leaves it dead. A src-url sheet is not affected.

<section>
  <quark-sheet>
    details[open] summary { content: "Panel Open"; }
    details:not([open]) summary { content: "Panel Closed"; }
  </quark-sheet>
  <details>
    <summary></summary>
    <p>This is the panel content.</p>
  </details>
</section>

By default the sheet is scoped to its parent. Add is-global to run top-level rules in the root context (e.g. reading a provider above the host); rules inside an explicit @scope { } block stay host-scoped either way. Language details live in the quark docs.

An inline sheet is HTML content: a browser reads < followed by a letter, /, ! or ? as markup, in a sheet comment or string too, and a <title> or <textarea> there takes the rest of the page as its text (the sheet fails with a parse error far from the cause). Keep such text out of an inline sheet, or load the sheet with src-url.

For prerendering, @excom/quark-sheet/server exports settle, the hook that holds a page until its sheets are quiet. @excom/nucleus-kit/server already has it.

API Reference

quark-sheet

Attributes (10) Role — option is configurable, state is managed by the element (read-only), or hybrid which is both. Role Attribute Type Values Prop Default option is-global
Run top-level rules in the root context (the whole document) instead of implicitly wrapping the sheet in @scope { }. Rules nested inside an explicit @scope { } block remain scoped to the host either way. isGlobal
boolean false
option src-url
URL of a remote .quark / text sheet. When set, contents are fetched into the live sheet (replacing inline text). srcUrl
string <URL> null
state did-load
Work has succeeded and no failure followed. Stays set while a refresh loads, so content can stay on screen (stale-while-revalidate): gate it on [did-load] rather than [is-success]. Cleared on error. didLoad loadable-element
boolean false
state is-error
Fetch or Quark parse/register failed. isError
boolean false
state is-error
The most recent work failed. Mutually exclusive with is-loading and is-success. isError loadable-element
boolean false
state is-loading
Fetch in progress. isLoading
boolean false
state is-loading
Work is in flight. isLoading loadable-element
boolean false
state is-success
Sheet parsed and registered on the host. isSuccess
boolean false
state is-success
The most recent work finished successfully. Mutually exclusive with is-loading and is-error. isSuccess loadable-element
boolean false
state quark-instance
Live Quark instance while registered. quarkInstance
Quark null
Provision (1) This provision property lives on the DOM node. Read / watch it with Quark’s prop("provision"), or listen for the neutron-provision event from app JS. Property Type provision
The result of the most recent work on success, or the error payload on failure. Shape is defined by the composing element. Not reflected as an attribute. provision loadable-element
unknown
Events (7)
Dispatches — events that quark-sheet fires and their default actions. Dispatch Default Action
A "default action" is subsequent logic executed by the element if e.preventDefault() is not synchronously called on the event.
Name quark-sheet-error
After parse / fetch failure (is-error). event.detail is the error.

Type QuarkSheetErrorEvent
Name quark-sheet-error
After is-error is set. event.detail is the error payload (also stored as provision). loadable-element

Type LoadableErrorEvent
Name quark-sheet-loading
After is-loading becomes true (fetch in flight).

Type QuarkSheetLoadingEvent
Name quark-sheet-loading
After is-loading is set (work started). loadable-element

Type LoadableLoadingEvent
Name quark-sheet-success
After the sheet parses and registers successfully (is-success).

Type QuarkSheetSuccessEvent
Name quark-sheet-success
After is-success is set. event.detail is the new provision. loadable-element

Type LoadableSuccessEvent
Listeners — events that quark-sheet listens for which will trigger subsequent actions. Listener Type Action
Commands — verbs quark-sheet accepts as a command event (HTML Command API): from a <button command commandfor>, an <event-handler command-name>, or a CommandEvent. Command Action --reload Drops the shared text cache entry for src-url and fetches the sheet again (the cache is page-wide: every element loading the same URL shares it). No-op without src-url.
Recognized Elements (0) Child or descendant elements are recognized by quark-sheet and relevant to its functionality. Element Relationship Required
Styles (1)
Classes — optional classes that change the appearance of quark-sheet. Class Description
Variables — public CSS variables for theming quark-sheet. Opt-out:
If you wish to opt-out of these styles on a case-to-case basis, use property all: revert-layer. Valence.css ships this as .unstyled and .unstyled-all for the entire tree.
Variable Syntax Default
Aliases — @custom-selector synonyms so custom elements can share semantic styles. Element aliases match the host tag / .tag-* class; state aliases match attributes (nested under the element alias). Alias Kind Matches :--quark-sheet element quark-sheet, .tag-quark-sheet
Release notes (2)

0.2.0

  • Add @excom/quark-sheet/server, which exports settle: the prerender hook that holds a page until its sheets are quiet, without the 1 s limit of Quark.whenSettled()

0.1.1

  • Ship only dist (and declared extras) in the npm tarball; drop build logs, tests and sources
View Source

Examples

Provider data

prop("provision") reads a <provider-fetch> provision on success and fills a title.

Beta. The Nucleus Stack is in beta for a few weeks until features are stabilized and optimized.

Thanks — we'll email you when it ships.

Something went wrong. Please try again.