fernwell 0.1.0 → 0.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/CHANGELOG.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/).
4
4
 
5
- ## [Unreleased]
5
+ ## [0.2.0] — 2026-09-14
6
6
 
7
7
  ### Changed (breaking)
8
+
8
9
  - **Colour tokens renamed from the default palette to semantic roles**, so a consumer never has to rename a token to retheme it. `src/tokens/tokens.json` and every component now speak in roles; the shipped values are unchanged, just renamed:
9
10
  - `--fw-ink` → `--fw-text`, `--fw-ink-soft` → `--fw-text-soft`, `--fw-ink-fixed` → `--fw-on-primary`
10
11
  - `--fw-cloud` → `--fw-bg`, `--fw-cloud-dim` → `--fw-bg-dim`
@@ -22,6 +23,15 @@ All notable changes to this project are documented here. The format follows [Kee
22
23
  - `src/tokens/tokens.json` schema changed: `color.light` / `color.dark` (and `shadow.light` / `shadow.dark`) collapsed into one entry per token, `{ value }` (same both themes) or `{ light, dark? }`. A value can reference another token in the same group with `{name}`.
23
24
 
24
25
  ### Added
26
+
27
+ - **Table component** (`src/css/components/table.css`): a native `<table>` inside a scrolling card (`.fw-table-wrap`), with `.fw-table-striped`, `.fw-table-compact`, a sticky header (`.fw-table-sticky` on the wrapper, height via `--fw-table-max-height`), mono/right-aligned numeric cells (`.fw-table-num`), action and checkbox columns (`.fw-table-actions`, `.fw-table-select`), empty and loading rows (`.fw-table-empty`, `.fw-table-loading`, `[aria-busy="true"]`), and sort indicators driven purely by `aria-sort` on the `<th>`.
28
+ - **`table` JS enhancer** (`table[data-fw-table]`): client-side column sorting on `th[data-fw-sort]` (`td[data-fw-sort-value]` overrides cell text for numbers and dates), row selection via `[data-fw-select-row]` with a `[data-fw-select-all]` header checkbox that tracks checked / indeterminate state; exports `table.sort()`, `table.getSelected()`, `table.setRowSelected()`, `table.selectAll()` and the `SortDirection` / `SortDetail` / `SelectDetail` types; emits `fw:sort` and `fw:select`.
29
+ - **Collapsible menu component** (`src/css/components/menu.css`): a nestable menu built on native `<details>`/`<summary>` that reads as a nav tree or, with `.fw-menu-accordion`, as an accordion. `.fw-menu` > `.fw-menu-list` > `.fw-menu-item` rows are `.fw-menu-link` (`[aria-current="page"]` tint) or `details.fw-menu-group` > `.fw-menu-summary` (CSS-mask chevron, rotates on `[open]`); nested lists hang off an indent rail; `.fw-menu-split` puts a link and an icon-only toggle (`.fw-menu-summary-icon`) in one row so a parent can navigate *and* expand; `.fw-menu-panel` holds free-form accordion bodies. Config via `--fw-menu-indent` and `--fw-menu-row-h`. Works without JS.
30
+ - **`menu` JS enhancer** (`.fw-menu[data-fw-menu]`): opens every ancestor group of an `[aria-current]` link on init and marks a collapsed branch that holds it with `.is-current`; `data-fw-menu-exclusive` closes sibling groups when one opens; arrow-key navigation (↑ ↓ between visible rows, → opens / enters a group or jumps from a split link to its toggle, ← closes / returns to the parent, Home / End) without touching Tab order; exports `menu.open()`, `close()`, `toggle()`, `reveal()`, `expandAll()`, `collapseAll()` and the `ToggleDetail` type; emits `fw:toggle`.
31
+ - Docs: new **Collapsible menu** section (07e) with a three-level nav tree (split row, auto-revealed current page) and an exclusive FAQ accordion.
32
+ - Docs: an on-page navigation tree (`#kit-toc`, `docs/index.html`) built at runtime from the page's own `<h2>` sections, nesting the `<h3>` install methods as children — dogfoods the new `.fw-menu` component and calls `menu.init()` directly. Pinned open beside `.kit-wrap` on wide viewports (`min-width: 1600px`); below that it's an off-canvas drawer opened by a chevron `.kit-toc-toggle` button fixed to the left edge, reusing the `nav` enhancer (`data-fw-nav-toggle`) for outside-click / Escape / `aria-expanded`. Smooth-scrolls to the target heading (`docs/styles/index.css`, respects `prefers-reduced-motion`).
33
+ - `.fw-checkbox` now styles the `:indeterminate` state (a dash on Primary), so a select-all checkbox reads correctly when only some rows are ticked.
34
+ - Docs: new **Table** section (07d) with a sortable, selectable invoices table, a compact sticky-header table, and an empty state.
25
35
  - **Derived tokens**: `--fw-primary-hover`, `--fw-primary-soft`, `--fw-secondary-hover`, `--fw-secondary-bg`, `--fw-success-bg`, `--fw-warning-bg`, `--fw-danger-bg`, `--fw-info-bg`, `--fw-on-secondary-soft/-fill/-line`, `--fw-focus-ring` and `--fw-shadow-primary/-success` are now computed from their seed colour with `color-mix()` instead of being separately hand-tuned hex/rgba values — override the seed (e.g. `--fw-primary`) and every derived token follows, in both themes, without needing to be redeclared.
26
36
  - New `--fw-warning` / `--fw-warning-bg` tokens (the old `marigold-dk` pending accent, now independent of Primary).
27
37
  - Generated `src/css/tokens.css` now wraps its rules in `@layer fw-tokens`, so a plain (unlayered) consumer override always wins over Fernwell's own `[data-theme="dark"]` re-declaration, regardless of selector specificity or source order — previously a `:root` override had to be repeated for `[data-theme="dark"]` or it was clobbered on theme toggle.
@@ -35,6 +45,7 @@ All notable changes to this project are documented here. The format follows [Kee
35
45
  First standalone release. Extracted from the HunnyDo marketing site and app, where the system previously lived as two hand-synced copies.
36
46
 
37
47
  ### Added
48
+
38
49
  - Design tokens as `--fw-*` custom properties (light + `[data-theme="dark"]`), generated from `src/tokens/tokens.json`, also shipped as `fernwell/tokens.json`.
39
50
  - Components: button, icon button, card, tag/pill, eyebrow, field, checkbox/radio/toggle, combobox, alert, progress, spinner, nav, stat, empty state, modal, drawer, toast, list row, disclosure, pagination, layout helpers, opt-in `.fw-root` page defaults.
40
51
  - JS enhancers (ESM, CJS, IIFE): `theme`, `combobox`, `modal` (modals + drawers), `nav`, `loading`, `toast`, and an idempotent `init()`.
@@ -42,6 +53,7 @@ First standalone release. Extracted from the HunnyDo marketing site and app, whe
42
53
  - Token lint (`npm run lint`) that rejects raw colours, unprefixed variables and off-scale pixel values in component CSS.
43
54
 
44
55
  ### Changed (vs. the marketing/app copies)
56
+
45
57
  - All tokens renamed with the `--fw-` prefix; `--white` → `--fw-surface`.
46
58
  - All classes renamed with the `fw-` prefix; state classes are `is-*` (`.open` → `.is-open`, `.error` → `.is-error`, `.active` → `.is-active`).
47
59
  - Checkbox checkmark is drawn with a CSS mask — no inline SVG needed in the markup.
package/README.md CHANGED
@@ -167,7 +167,7 @@ All class names are prefixed `fw-`; state classes are `is-*`. Each stylesheet in
167
167
  | Tag | `.fw-tag` + `-live` `-pending` `-error` `-info` `-secondary`; `.fw-tag-pill` (compact, untilted) |
168
168
  | Eyebrow | `.fw-eyebrow` |
169
169
  | Field | `.fw-field` (`.fw-field-full`), `.fw-label`, `.fw-input`, `.fw-hint`, `.fw-error-msg`, `.fw-required`; `.is-error`, `.is-disabled` |
170
- | Selection | `.fw-checkbox` / `.fw-radio` (`<input>` + `.fw-box`), `.fw-toggle` (`<input>` + `.fw-track > .fw-thumb`), `.fw-option-group` (`-inline`) |
170
+ | Selection | `.fw-checkbox` / `.fw-radio` (`<input>` + `.fw-box`; checkbox styles `:indeterminate`), `.fw-toggle` (`<input>` + `.fw-track > .fw-thumb`), `.fw-option-group` (`-inline`) |
171
171
  | Combobox | `.fw-combobox` wrapper, `input[data-fw-combobox][list]` + `<datalist>` |
172
172
  | Alert | `.fw-alert` + `-success` `-error` `-pending` `-info` `-with-action`; `.fw-alert-dot` `-title` `-body` |
173
173
  | Progress | `.fw-progress` (`-sm`, `.is-indeterminate`, `.is-success`) > `.fw-progress-fill`; `.fw-progress-label` |
@@ -181,6 +181,8 @@ All class names are prefixed `fw-`; state classes are `is-*`. Each stylesheet in
181
181
  | List row | `.fw-list-row` (`.is-locked`), `-main`, `-title`, `-meta`; `.fw-sub-list` |
182
182
  | Disclosure | `details.fw-disclosure`, `-chevron`, `-count`, `-body` |
183
183
  | Pagination | `.fw-pagination`, `.fw-pag-info`, `.fw-pag-controls`, `.fw-pag-label`, `.fw-btn-page` |
184
+ | Table | `.fw-table-wrap` (`.fw-table-sticky` + `--fw-table-max-height`) > `.fw-table` (`-striped`, `-compact`); cells `.fw-table-num`, `.fw-table-actions`, `.fw-table-select`; `th[aria-sort] > .fw-table-sort`; rows `.fw-table-empty`, `.fw-table-loading`, `.is-selected`; `[aria-busy="true"]` dims the body |
185
+ | Collapsible menu | `.fw-menu` (`-accordion`) > `.fw-menu-list` > `.fw-menu-item` (`.fw-menu-split`) > `.fw-menu-link` or `details.fw-menu-group` > `.fw-menu-summary` (`-icon`, `.is-current`) + nested `.fw-menu-list` or `.fw-menu-panel`; `[aria-current="page"]` marks the current link; `--fw-menu-indent`, `--fw-menu-row-h` |
184
186
  | Layout | `.fw-wrap`, `.fw-row`, `.fw-grid-2`, `.fw-sr-only` |
185
187
 
186
188
  ## JavaScript
@@ -195,11 +197,13 @@ Everything is progressive enhancement over plain HTML. `init(root?)` is idempote
195
197
  | `[data-fw-open-drawer="id"]` / `[data-fw-close-drawer]` / `[data-fw-drawer-overlay="id"]` | same for drawers |
196
198
  | `[data-fw-nav-toggle][aria-controls]` | dropdown open/close, outside-click and Escape |
197
199
  | `form[data-fw-loading]` | submit button gets a spinner + `data-fw-loading-text` label on submit |
200
+ | `table[data-fw-table]` with `th[data-fw-sort]`, `input[data-fw-select-all]` / `[data-fw-select-row]` | client-side column sort (cycles `aria-sort`, honours `td[data-fw-sort-value]`), row selection with select-all + indeterminate, `.is-selected` / `aria-selected` on rows |
201
+ | `.fw-menu[data-fw-menu]` (+ `data-fw-menu-exclusive`) | nestable `<details>` menu: opens the ancestors of `[aria-current]` on init, `.is-current` on a collapsed branch holding it, ↑ ↓ → ← Home End between rows, exclusive mode closes sibling groups |
198
202
 
199
203
  Programmatic API:
200
204
 
201
205
  ```js
202
- import { theme, combobox, modal, nav, loading, toast } from 'fernwell';
206
+ import { theme, combobox, modal, nav, loading, toast, table, menu } from 'fernwell';
203
207
 
204
208
  theme.get();
205
209
  theme.set('dark');
@@ -219,9 +223,15 @@ modal.close('confirm'); // works for drawers too
219
223
  loading.setButtonLoading(btn, 'Sending…');
220
224
  loading.resetButtonLoading(btn);
221
225
  toast.show('That card was declined', { variant: 'error', duration: 6000 });
226
+ table.sort(tableEl, 2, 'descending'); // column index, 'ascending' | 'descending'
227
+ table.getSelected(tableEl); // HTMLTableRowElement[]
228
+ table.selectAll(tableEl, false);
229
+ menu.open(groupEl); menu.close(groupEl); menu.toggle(groupEl); // groupEl = details.fw-menu-group
230
+ menu.reveal(linkEl); // open every ancestor group of an element
231
+ menu.expandAll(menuEl); menu.collapseAll(menuEl);
222
232
  ```
223
233
 
224
- Events: `fw:themechange` on `document` (detail: `'light' | 'dark'`), `fw:open` / `fw:close` bubbling from the modal or drawer.
234
+ Events: `fw:themechange` on `document` (detail: `'light' | 'dark'`), `fw:open` / `fw:close` bubbling from the modal or drawer, `fw:sort` (detail: `{ column, direction, th }`) and `fw:select` (detail: `{ rows, all }`) bubbling from the table, `fw:toggle` (detail: `{ group, open }`) bubbling from a `.fw-menu-group`.
225
235
 
226
236
  ## Principles
227
237
 
@@ -254,6 +264,23 @@ Semantic versioning, strictly: **major** for any rename or removal of a token, c
254
264
 
255
265
  **Deprecation policy (from 1.0):** a token or class slated for removal keeps working for at least one minor release, with a `/* @deprecated */` note in the CSS and an entry in the changelog naming the replacement. It's removed in the next major.
256
266
 
267
+ ## Releasing to npm
268
+
269
+ Publishing a GitHub Release triggers [`.github/workflows/publish-npm.yml`](.github/workflows/publish-npm.yml), which builds the package and runs `npm publish --provenance` via npm's OIDC trusted publishing (no token stored in the repo). To ship a new version:
270
+
271
+ 1. Bump `version` in `package.json`.
272
+ 2. Move the `## [Unreleased]` section in `CHANGELOG.md` to a new dated heading, e.g. `## [0.2.0] — 2026-09-14`.
273
+ 3. Commit both and merge into `main` branch.
274
+ 4. Create a GitHub Release tagged `vX.Y.Z` (matching the version from step 1) targeting `main`:
275
+
276
+ ```bash
277
+ gh release create v0.2.0 --title v0.2.0 --notes-from-tag
278
+ ```
279
+
280
+ or via the GitHub UI: **Releases → Draft a new release**, tag `vX.Y.Z`, target `main`, then **Publish release**.
281
+
282
+ Publishing the release fires the workflow, which checks the tag matches `package.json`'s version and that the version isn't already on the registry before publishing. Mark a release **pre-release** to cut a tag without triggering an npm publish. The workflow can also be run manually from the Actions tab (`workflow_dispatch`), which defaults to a `npm publish --dry-run` so the pipeline can be sanity-checked without shipping anything.
283
+
257
284
  ## License
258
285
 
259
286
  MIT
package/dist/fernwell.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! fernwell v0.1.0 | MIT | https://github.com/JacobKnaack/fernwell */
2
- "use strict";var q=Object.defineProperty;var Oe=Object.getOwnPropertyDescriptor;var Se=Object.getOwnPropertyNames;var Be=Object.prototype.hasOwnProperty;var m=(e,t)=>{for(var n in t)q(e,n,{get:t[n],enumerable:!0})},Ce=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Se(t))!Be.call(e,s)&&s!==n&&q(e,s,{get:()=>t[s],enumerable:!(o=Oe(t,s))||o.enumerable});return e};var Ne=e=>Ce(q({},"__esModule",{value:!0}),e);var Ye={};m(Ye,{combobox:()=>A,default:()=>Ue,init:()=>Me,loading:()=>C,modal:()=>O,nav:()=>B,theme:()=>H,toast:()=>N,version:()=>ye});module.exports=Ne(Ye);var H={};m(H,{get:()=>P,getToken:()=>De,init:()=>D,resetTokens:()=>Pe,set:()=>M,setTokens:()=>je,toggle:()=>fe});var I="fw-theme",$e="fw:themechange",qe="--fw-",ce="data-fw-tokens";function j(){try{return window.localStorage}catch{return null}}function P(){var t;let e=document.documentElement.getAttribute("data-theme");return e==="dark"||e==="light"?e:(t=window.matchMedia)!=null&&t.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light"}function M(e,{persist:t=!0}={}){var n;document.documentElement.setAttribute("data-theme",e),t&&((n=j())==null||n.setItem(I,e)),document.querySelectorAll("[data-fw-theme-toggle]").forEach(o=>me(o,e)),document.dispatchEvent(new CustomEvent($e,{detail:e}))}function fe(){let e=P()==="dark"?"light":"dark";return M(e),e}function me(e,t){e.setAttribute("aria-pressed",String(t==="dark"));let n=t==="dark"?e.dataset.fwThemeLabelDark:e.dataset.fwThemeLabelLight;n!==void 0&&(e.textContent=n)}function D(e=document){var o,s,i,a;let t=(o=j())==null?void 0:o.getItem(I),n=t==="dark"||t==="light"?t:P();M(n,{persist:!1}),e.querySelectorAll("[data-fw-theme-toggle]").forEach(u=>{u.dataset.fwBound||(u.dataset.fwBound="1",me(u,n),u.addEventListener("click",()=>fe()))}),(a=(s=window.matchMedia)==null?void 0:(i=s.call(window,"(prefers-color-scheme: dark)")).addEventListener)==null||a.call(i,"change",u=>{var w;(w=j())!=null&&w.getItem(I)||M(u.matches?"dark":"light",{persist:!1})})}var L=new Map;function pe(e){return e.startsWith("--")?e:`${qe}${e}`}function Ie(e){return Object.values(e).some(t=>t!==null&&typeof t=="object")}function de(e){return Object.entries(e).map(([t,n])=>`${pe(t)}:${n};`).join("")}function ue(e){let t=document.head.querySelector(`style[${ce}]`);if(t||!e)return t;let n=document.createElement("style");return n.setAttribute(ce,""),document.head.appendChild(n),n}function ve(){var t;if(L.size===0){(t=ue(!1))==null||t.remove();return}let e=[];L.forEach(({light:n,dark:o},s)=>{if(Object.keys(n).length&&e.push(`${s}{${de(n)}}`),Object.keys(o).length){let i=s===":root"?'[data-theme="dark"]':`[data-theme="dark"] ${s}, ${s}[data-theme="dark"]`;e.push(`${i}{${de(o)}}`)}}),ue(!0).textContent=e.join(`
3
- `)}function je(e,t={}){var s,i;let n=(s=t.scope)!=null?s:":root",o=(i=L.get(n))!=null?i:{light:{},dark:{}};Ie(e)?(Object.assign(o.light,e.light),Object.assign(o.dark,e.dark)):(Object.assign(o.light,e),Object.assign(o.dark,e)),L.set(n,o),ve()}function Pe(e){e?L.delete(e):L.clear(),ve()}function De(e,t=document.documentElement){return getComputedStyle(t).getPropertyValue(pe(e)).trim()}var A={};m(A,{combobox:()=>Ee,init:()=>F});var Fe=0;function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function Ee(e,t={}){var re,ie,ae,le;let n=(re=t.filter)!=null?re:((r,l)=>r.toLowerCase().includes(l)),o=(ie=t.emptyText)!=null?ie:"No matches",s=(ae=t.options)!=null?ae:Ke(e),i=[],a=-1,u=!1,w=e.getAttribute("list");w&&(e.dataset.fwList=w,e.removeAttribute("list"));let J=(le=e.closest(".fw-combobox"))!=null?le:Ve(e),c=document.createElement("ul"),$=`fw-combobox-${++Fe}`;c.className="fw-combobox-list",c.id=$,c.setAttribute("role","listbox"),J.appendChild(c),e.setAttribute("role","combobox"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("aria-expanded","false"),e.setAttribute("aria-controls",$),e.autocomplete="off";function He(r){i=r,a=-1;let l=e.value.trim().toLowerCase();if(r.length===0){c.innerHTML=`<li class="fw-combobox-empty">${x(o)}</li>`;return}c.innerHTML=r.map((f,b)=>{let g=l?f.toLowerCase().indexOf(l):-1,Ae=g>-1?`${x(f.slice(0,g))}<b>${x(f.slice(g,g+l.length))}</b>${x(f.slice(g+l.length))}`:x(f);return`<li class="fw-combobox-option" role="option" id="${$}-${b}" data-index="${b}" aria-selected="false">${Ae}</li>`}).join("")}function h(){let r=e.value.trim().toLowerCase();He(r?s.filter(l=>n(l,r)):s),c.classList.add("is-open"),e.setAttribute("aria-expanded","true")}function y(){c.classList.remove("is-open"),e.setAttribute("aria-expanded","false"),e.removeAttribute("aria-activedescendant"),a=-1}function Q(r){let l=c.querySelectorAll(".fw-combobox-option");l.forEach(b=>{b.classList.remove("is-active"),b.setAttribute("aria-selected","false")});let f=l[r];f&&(f.classList.add("is-active"),f.setAttribute("aria-selected","true"),f.scrollIntoView({block:"nearest"}),e.setAttribute("aria-activedescendant",f.id)),a=r}function Z(r){var l;e.value=r,y(),u=!0,e.focus(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),u=!1,(l=t.onSelect)==null||l.call(t,r)}let ee=()=>{u||h()},te=()=>{u||h()},ne=r=>{r.key==="ArrowDown"?(r.preventDefault(),c.classList.contains("is-open")||h(),Q(Math.min(a+1,i.length-1))):r.key==="ArrowUp"?(r.preventDefault(),Q(Math.max(a-1,0))):r.key==="Enter"?a>-1&&i[a]!==void 0&&(r.preventDefault(),Z(i[a])):r.key==="Escape"&&y()},oe=r=>{let l=r.target.closest(".fw-combobox-option");l&&(r.preventDefault(),Z(i[Number(l.dataset.index)]))},se=r=>{J.contains(r.target)||y()};return e.addEventListener("input",ee),e.addEventListener("focus",te),e.addEventListener("keydown",ne),c.addEventListener("mousedown",oe),document.addEventListener("click",se),{open:h,close:y,setOptions(r){s=r,c.classList.contains("is-open")&&h()},destroy(){e.removeEventListener("input",ee),e.removeEventListener("focus",te),e.removeEventListener("keydown",ne),c.removeEventListener("mousedown",oe),document.removeEventListener("click",se),c.remove(),e.dataset.fwList&&e.setAttribute("list",e.dataset.fwList),delete e.dataset.fwBound}}}function Ke(e){var o;let t=(o=e.getAttribute("list"))!=null?o:e.dataset.fwList,n=t?document.getElementById(t):null;return n?Array.from(n.querySelectorAll("option")).map(s=>s.value||s.textContent||""):[]}function Ve(e){var n;let t=document.createElement("div");return t.className="fw-combobox",(n=e.parentNode)==null||n.insertBefore(t,e),t.appendChild(e),t}function F(e=document){e.querySelectorAll("input[data-fw-combobox]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",Ee(t))})}var O={};m(O,{bindOutsideClickToClose:()=>V,close:()=>p,init:()=>z,open:()=>W,toggle:()=>_e});var v="is-open",Te="fw-scroll-lock",E=[],K=new WeakMap,Re='a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function R(e){return typeof e=="string"?document.getElementById(e):e}function _(e){if(e.classList.contains("fw-modal-overlay"))return e;let t=e.id?document.querySelector(`[data-fw-drawer-overlay="${e.id}"]`):null;if(t)return t;let n=e.previousElementSibling;return n instanceof HTMLElement&&n.classList.contains("fw-drawer-overlay")?n:null}function W(e,t=(n=>(n=document.activeElement)!=null?n:null)()){var i;let o=R(e);if(!o||o.classList.contains(v))return;o.classList.add(v),(i=_(o))==null||i.classList.add(v),K.set(o,t),E.push(o),document.body.classList.add(Te),o.dispatchEvent(new CustomEvent("fw:open",{bubbles:!0}));let s=o.querySelector(Re);s?s.focus({preventScroll:!0}):(o.hasAttribute("tabindex")||o.setAttribute("tabindex","-1"),o.focus({preventScroll:!0}))}function p(e){var o,s,i;let t=R(e);if(!t||!t.classList.contains(v))return;t.classList.remove(v),(o=_(t))==null||o.classList.remove(v);let n=E.indexOf(t);n>-1&&E.splice(n,1),E.length===0&&document.body.classList.remove(Te),t.dispatchEvent(new CustomEvent("fw:close",{bubbles:!0})),(i=(s=K.get(t))==null?void 0:s.focus)==null||i.call(s,{preventScroll:!0}),K.delete(t)}function _e(e){let t=R(e);t&&(t.classList.contains(v)?p:W)(t)}function V(e,t){let n=!1;e.addEventListener("mousedown",o=>{n=o.target===e}),e.addEventListener("click",o=>{o.target===e&&n&&t()})}var Le=!1;function z(e=document){e.querySelectorAll("[data-fw-open-modal], [data-fw-open-drawer]").forEach(t=>{var o,s;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=(s=(o=t.dataset.fwOpenModal)!=null?o:t.dataset.fwOpenDrawer)!=null?s:"";t.addEventListener("click",()=>W(n,t))}),e.querySelectorAll(".fw-modal-overlay").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",V(t,()=>p(t)),t.querySelectorAll("[data-fw-close-modal]").forEach(n=>n.addEventListener("click",()=>p(t))))}),e.querySelectorAll(".fw-drawer").forEach(t=>{if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=_(t);n&&V(n,()=>p(t)),t.querySelectorAll("[data-fw-close-drawer]").forEach(o=>o.addEventListener("click",()=>p(t)))}),Le||(Le=!0,document.addEventListener("keydown",t=>{t.key==="Escape"&&E.length&&p(E[E.length-1])}))}var B={};m(B,{close:()=>S,init:()=>Y,open:()=>we});var G="is-open";function we(e){let t=U(e);t&&(t.classList.add(G),e.setAttribute("aria-expanded","true"))}function S(e){let t=U(e);t&&(t.classList.remove(G),e.setAttribute("aria-expanded","false"))}function U(e){let t=e.getAttribute("aria-controls");return t?document.getElementById(t):null}function Y(e=document){e.querySelectorAll("[data-fw-nav-toggle]").forEach(t=>{var s,i;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=U(t);if(!n)return;let o=(i=(s=t.closest(".fw-nav"))!=null?s:t.parentElement)!=null?i:t;t.addEventListener("click",a=>{a.stopPropagation(),(n.classList.contains(G)?S:we)(t)}),document.addEventListener("click",a=>{!o.contains(a.target)&&!n.contains(a.target)&&S(t)}),document.addEventListener("keydown",a=>{a.key==="Escape"&&S(t)})})}var C={};m(C,{init:()=>X,resetAll:()=>xe,resetButtonLoading:()=>ge,setButtonLoading:()=>be});var k="fw-btn-loading";function be(e,t){var o,s;if(!e||e.classList.contains(k))return;e.dataset.fwOriginalHtml=e.innerHTML,e.disabled=!0,e.setAttribute("aria-busy","true"),e.classList.add(k);let n=(s=(o=t!=null?t:e.dataset.fwLoadingText)!=null?o:e.textContent)!=null?s:"";e.innerHTML='<span class="fw-spinner fw-spinner-sm" aria-hidden="true"></span>',e.appendChild(document.createTextNode(n))}function ge(e){!e||!e.classList.contains(k)||(e.disabled=!1,e.removeAttribute("aria-busy"),e.classList.remove(k),e.dataset.fwOriginalHtml!==void 0&&(e.innerHTML=e.dataset.fwOriginalHtml,delete e.dataset.fwOriginalHtml))}function xe(e=document){e.querySelectorAll(`.${k}`).forEach(ge)}var he=!1;function X(e=document){e.querySelectorAll("form[data-fw-loading]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",t.addEventListener("submit",()=>{let n=t.querySelector('button[type="submit"], button:not([type])');be(n)}))}),he||(he=!0,window.addEventListener("pageshow",t=>{t.persisted&&xe()}))}var N={};m(N,{hide:()=>ke,show:()=>ze});var d=null,T=null;function We(){return d&&d.isConnected||(d=document.createElement("div"),d.className="fw-toast",d.setAttribute("role","status"),d.setAttribute("aria-live","polite"),d.innerHTML='<span class="fw-toast-dot" aria-hidden="true"></span><span class="fw-toast-text"></span>',document.body.appendChild(d)),d}function ze(e,{variant:t="success",duration:n=4e3}={}){let o=We();return o.className=`fw-toast${t==="success"?"":` fw-toast-${t}`}`,o.querySelector(".fw-toast-text").textContent=e,T&&clearTimeout(T),o.classList.remove("is-show"),o.offsetWidth,o.classList.add("is-show"),n>0&&(T=setTimeout(ke,n)),o}function ke(){d==null||d.classList.remove("is-show"),T&&clearTimeout(T),T=null}var ye="0.1.0";function Me(e=document){D(e),F(e),z(e),Y(e),X(e)}var Ge={version:ye,init:Me,theme:H,combobox:A,modal:O,nav:B,loading:C,toast:N},Ue=Ge;
1
+ /*! fernwell v0.2.0 | MIT | https://github.com/JacobKnaack/fernwell */
2
+ "use strict";var V=Object.defineProperty;var Ze=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var T=(e,t)=>{for(var n in t)V(e,n,{get:t[n],enumerable:!0})},nt=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of et(t))!tt.call(e,r)&&r!==n&&V(e,r,{get:()=>t[r],enumerable:!(o=Ze(t,r))||o.enumerable});return e};var ot=e=>nt(V({},"__esModule",{value:!0}),e);var Ot={};T(Ot,{combobox:()=>C,default:()=>St,init:()=>Xe,loading:()=>N,menu:()=>K,modal:()=>D,nav:()=>B,table:()=>R,theme:()=>O,toast:()=>I,version:()=>Ye});module.exports=ot(Ot);var O={};T(O,{get:()=>W,getToken:()=>ct,init:()=>_,resetTokens:()=>at,set:()=>S,setTokens:()=>lt,toggle:()=>xe});var G="fw-theme",rt="fw:themechange",st="--fw-",Me="data-fw-tokens";function U(){try{return window.localStorage}catch{return null}}function W(){var t;let e=document.documentElement.getAttribute("data-theme");return e==="dark"||e==="light"?e:(t=window.matchMedia)!=null&&t.call(window,"(prefers-color-scheme: dark)").matches?"dark":"light"}function S(e,{persist:t=!0}={}){var n;document.documentElement.setAttribute("data-theme",e),t&&((n=U())==null||n.setItem(G,e)),document.querySelectorAll("[data-fw-theme-toggle]").forEach(o=>ke(o,e)),document.dispatchEvent(new CustomEvent(rt,{detail:e}))}function xe(){let e=W()==="dark"?"light":"dark";return S(e),e}function ke(e,t){e.setAttribute("aria-pressed",String(t==="dark"));let n=t==="dark"?e.dataset.fwThemeLabelDark:e.dataset.fwThemeLabelLight;n!==void 0&&(e.textContent=n)}function _(e=document){var o,r,s,l;let t=(o=U())==null?void 0:o.getItem(G),n=t==="dark"||t==="light"?t:W();S(n,{persist:!1}),e.querySelectorAll("[data-fw-theme-toggle]").forEach(d=>{d.dataset.fwBound||(d.dataset.fwBound="1",ke(d,n),d.addEventListener("click",()=>xe()))}),(l=(r=window.matchMedia)==null?void 0:(s=r.call(window,"(prefers-color-scheme: dark)")).addEventListener)==null||l.call(s,"change",d=>{var f;(f=U())!=null&&f.getItem(G)||S(d.matches?"dark":"light",{persist:!1})})}var b=new Map;function Ae(e){return e.startsWith("--")?e:`${st}${e}`}function it(e){return Object.values(e).some(t=>t!==null&&typeof t=="object")}function He(e){return Object.entries(e).map(([t,n])=>`${Ae(t)}:${n};`).join("")}function ye(e){let t=document.head.querySelector(`style[${Me}]`);if(t||!e)return t;let n=document.createElement("style");return n.setAttribute(Me,""),document.head.appendChild(n),n}function Se(){var t;if(b.size===0){(t=ye(!1))==null||t.remove();return}let e=[];b.forEach(({light:n,dark:o},r)=>{if(Object.keys(n).length&&e.push(`${r}{${He(n)}}`),Object.keys(o).length){let s=r===":root"?'[data-theme="dark"]':`[data-theme="dark"] ${r}, ${r}[data-theme="dark"]`;e.push(`${s}{${He(o)}}`)}}),ye(!0).textContent=e.join(`
3
+ `)}function lt(e,t={}){var r,s;let n=(r=t.scope)!=null?r:":root",o=(s=b.get(n))!=null?s:{light:{},dark:{}};it(e)?(Object.assign(o.light,e.light),Object.assign(o.dark,e.dark)):(Object.assign(o.light,e),Object.assign(o.dark,e)),b.set(n,o),Se()}function at(e){e?b.delete(e):b.clear(),Se()}function ct(e,t=document.documentElement){return getComputedStyle(t).getPropertyValue(Ae(e)).trim()}var C={};T(C,{combobox:()=>Oe,init:()=>z});var dt=0;function x(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}function Oe(e,t={}){var ve,he,be,ge;let n=(ve=t.filter)!=null?ve:((i,c)=>i.toLowerCase().includes(c)),o=(he=t.emptyText)!=null?he:"No matches",r=(be=t.options)!=null?be:ut(e),s=[],l=-1,d=!1,f=e.getAttribute("list");f&&(e.dataset.fwList=f,e.removeAttribute("list"));let u=(ge=e.closest(".fw-combobox"))!=null?ge:ft(e),a=document.createElement("ul"),F=`fw-combobox-${++dt}`;a.className="fw-combobox-list",a.id=F,a.setAttribute("role","listbox"),u.appendChild(a),e.setAttribute("role","combobox"),e.setAttribute("aria-autocomplete","list"),e.setAttribute("aria-expanded","false"),e.setAttribute("aria-controls",F),e.autocomplete="off";function Je(i){s=i,l=-1;let c=e.value.trim().toLowerCase();if(i.length===0){a.innerHTML=`<li class="fw-combobox-empty">${x(o)}</li>`;return}a.innerHTML=i.map((E,H)=>{let y=c?E.toLowerCase().indexOf(c):-1,Qe=y>-1?`${x(E.slice(0,y))}<b>${x(E.slice(y,y+c.length))}</b>${x(E.slice(y+c.length))}`:x(E);return`<li class="fw-combobox-option" role="option" id="${F}-${H}" data-index="${H}" aria-selected="false">${Qe}</li>`}).join("")}function M(){let i=e.value.trim().toLowerCase();Je(i?r.filter(c=>n(c,i)):r),a.classList.add("is-open"),e.setAttribute("aria-expanded","true")}function A(){a.classList.remove("is-open"),e.setAttribute("aria-expanded","false"),e.removeAttribute("aria-activedescendant"),l=-1}function fe(i){let c=a.querySelectorAll(".fw-combobox-option");c.forEach(H=>{H.classList.remove("is-active"),H.setAttribute("aria-selected","false")});let E=c[i];E&&(E.classList.add("is-active"),E.setAttribute("aria-selected","true"),E.scrollIntoView({block:"nearest"}),e.setAttribute("aria-activedescendant",E.id)),l=i}function me(i){var c;e.value=i,A(),d=!0,e.focus(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),d=!1,(c=t.onSelect)==null||c.call(t,i)}let Ee=()=>{d||M()},pe=()=>{d||M()},Te=i=>{i.key==="ArrowDown"?(i.preventDefault(),a.classList.contains("is-open")||M(),fe(Math.min(l+1,s.length-1))):i.key==="ArrowUp"?(i.preventDefault(),fe(Math.max(l-1,0))):i.key==="Enter"?l>-1&&s[l]!==void 0&&(i.preventDefault(),me(s[l])):i.key==="Escape"&&A()},Le=i=>{let c=i.target.closest(".fw-combobox-option");c&&(i.preventDefault(),me(s[Number(c.dataset.index)]))},we=i=>{u.contains(i.target)||A()};return e.addEventListener("input",Ee),e.addEventListener("focus",pe),e.addEventListener("keydown",Te),a.addEventListener("mousedown",Le),document.addEventListener("click",we),{open:M,close:A,setOptions(i){r=i,a.classList.contains("is-open")&&M()},destroy(){e.removeEventListener("input",Ee),e.removeEventListener("focus",pe),e.removeEventListener("keydown",Te),a.removeEventListener("mousedown",Le),document.removeEventListener("click",we),a.remove(),e.dataset.fwList&&e.setAttribute("list",e.dataset.fwList),delete e.dataset.fwBound}}}function ut(e){var o;let t=(o=e.getAttribute("list"))!=null?o:e.dataset.fwList,n=t?document.getElementById(t):null;return n?Array.from(n.querySelectorAll("option")).map(r=>r.value||r.textContent||""):[]}function ft(e){var n;let t=document.createElement("div");return t.className="fw-combobox",(n=e.parentNode)==null||n.insertBefore(t,e),t.appendChild(e),t}function z(e=document){e.querySelectorAll("input[data-fw-combobox]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",Oe(t))})}var D={};T(D,{bindOutsideClickToClose:()=>X,close:()=>L,init:()=>ee,open:()=>Z,toggle:()=>Et});var w="is-open",De="fw-scroll-lock",v=[],Y=new WeakMap,mt='a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function J(e){return typeof e=="string"?document.getElementById(e):e}function Q(e){if(e.classList.contains("fw-modal-overlay"))return e;let t=e.id?document.querySelector(`[data-fw-drawer-overlay="${e.id}"]`):null;if(t)return t;let n=e.previousElementSibling;return n instanceof HTMLElement&&n.classList.contains("fw-drawer-overlay")?n:null}function Z(e,t=(n=>(n=document.activeElement)!=null?n:null)()){var s;let o=J(e);if(!o||o.classList.contains(w))return;o.classList.add(w),(s=Q(o))==null||s.classList.add(w),Y.set(o,t),v.push(o),document.body.classList.add(De),o.dispatchEvent(new CustomEvent("fw:open",{bubbles:!0}));let r=o.querySelector(mt);r?r.focus({preventScroll:!0}):(o.hasAttribute("tabindex")||o.setAttribute("tabindex","-1"),o.focus({preventScroll:!0}))}function L(e){var o,r,s;let t=J(e);if(!t||!t.classList.contains(w))return;t.classList.remove(w),(o=Q(t))==null||o.classList.remove(w);let n=v.indexOf(t);n>-1&&v.splice(n,1),v.length===0&&document.body.classList.remove(De),t.dispatchEvent(new CustomEvent("fw:close",{bubbles:!0})),(s=(r=Y.get(t))==null?void 0:r.focus)==null||s.call(r,{preventScroll:!0}),Y.delete(t)}function Et(e){let t=J(e);t&&(t.classList.contains(w)?L:Z)(t)}function X(e,t){let n=!1;e.addEventListener("mousedown",o=>{n=o.target===e}),e.addEventListener("click",o=>{o.target===e&&n&&t()})}var Ce=!1;function ee(e=document){e.querySelectorAll("[data-fw-open-modal], [data-fw-open-drawer]").forEach(t=>{var o,r;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=(r=(o=t.dataset.fwOpenModal)!=null?o:t.dataset.fwOpenDrawer)!=null?r:"";t.addEventListener("click",()=>Z(n,t))}),e.querySelectorAll(".fw-modal-overlay").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",X(t,()=>L(t)),t.querySelectorAll("[data-fw-close-modal]").forEach(n=>n.addEventListener("click",()=>L(t))))}),e.querySelectorAll(".fw-drawer").forEach(t=>{if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=Q(t);n&&X(n,()=>L(t)),t.querySelectorAll("[data-fw-close-drawer]").forEach(o=>o.addEventListener("click",()=>L(t)))}),Ce||(Ce=!0,document.addEventListener("keydown",t=>{t.key==="Escape"&&v.length&&L(v[v.length-1])}))}var B={};T(B,{close:()=>q,init:()=>oe,open:()=>qe});var te="is-open";function qe(e){let t=ne(e);t&&(t.classList.add(te),e.setAttribute("aria-expanded","true"))}function q(e){let t=ne(e);t&&(t.classList.remove(te),e.setAttribute("aria-expanded","false"))}function ne(e){let t=e.getAttribute("aria-controls");return t?document.getElementById(t):null}function oe(e=document){e.querySelectorAll("[data-fw-nav-toggle]").forEach(t=>{var r,s;if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=ne(t);if(!n)return;let o=(s=(r=t.closest(".fw-nav"))!=null?r:t.parentElement)!=null?s:t;t.addEventListener("click",l=>{l.stopPropagation(),(n.classList.contains(te)?q:qe)(t)}),document.addEventListener("click",l=>{!o.contains(l.target)&&!n.contains(l.target)&&q(t)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&q(t)})})}var N={};T(N,{init:()=>re,resetAll:()=>$e,resetButtonLoading:()=>Ie,setButtonLoading:()=>Ne});var k="fw-btn-loading";function Ne(e,t){var o,r;if(!e||e.classList.contains(k))return;e.dataset.fwOriginalHtml=e.innerHTML,e.disabled=!0,e.setAttribute("aria-busy","true"),e.classList.add(k);let n=(r=(o=t!=null?t:e.dataset.fwLoadingText)!=null?o:e.textContent)!=null?r:"";e.innerHTML='<span class="fw-spinner fw-spinner-sm" aria-hidden="true"></span>',e.appendChild(document.createTextNode(n))}function Ie(e){!e||!e.classList.contains(k)||(e.disabled=!1,e.removeAttribute("aria-busy"),e.classList.remove(k),e.dataset.fwOriginalHtml!==void 0&&(e.innerHTML=e.dataset.fwOriginalHtml,delete e.dataset.fwOriginalHtml))}function $e(e=document){e.querySelectorAll(`.${k}`).forEach(Ie)}var Be=!1;function re(e=document){e.querySelectorAll("form[data-fw-loading]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",t.addEventListener("submit",()=>{let n=t.querySelector('button[type="submit"], button:not([type])');Ne(n)}))}),Be||(Be=!0,window.addEventListener("pageshow",t=>{t.persisted&&$e()}))}var I={};T(I,{hide:()=>Re,show:()=>Tt});var m=null,g=null;function pt(){return m&&m.isConnected||(m=document.createElement("div"),m.className="fw-toast",m.setAttribute("role","status"),m.setAttribute("aria-live","polite"),m.innerHTML='<span class="fw-toast-dot" aria-hidden="true"></span><span class="fw-toast-text"></span>',document.body.appendChild(m)),m}function Tt(e,{variant:t="success",duration:n=4e3}={}){let o=pt();return o.className=`fw-toast${t==="success"?"":` fw-toast-${t}`}`,o.querySelector(".fw-toast-text").textContent=e,g&&clearTimeout(g),o.classList.remove("is-show"),o.offsetWidth,o.classList.add("is-show"),n>0&&(g=setTimeout(Re,n)),o}function Re(){m==null||m.classList.remove("is-show"),g&&clearTimeout(g),g=null}var R={};T(R,{getSelected:()=>ce,init:()=>de,selectAll:()=>Ve,setRowSelected:()=>Fe,sort:()=>se});var Lt="is-selected";function ie(e,t,n){e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:n}))}function Pe(e,t){var o,r,s;let n=e.cells[t];return(s=(r=n==null?void 0:n.dataset.fwSortValue)!=null?r:(o=n==null?void 0:n.textContent)==null?void 0:o.trim())!=null?s:""}function wt(e,t){let n=Number(e),o=Number(t);return e!==""&&t!==""&&Number.isFinite(n)&&Number.isFinite(o)?n-o:e.localeCompare(t,void 0,{numeric:!0,sensitivity:"base"})}function Ke(e){var t,n;return Array.from((n=(t=e.tHead)==null?void 0:t.querySelectorAll("th[data-fw-sort]"))!=null?n:[])}function je(e){return e.getAttribute("aria-sort")==="ascending"?"descending":"ascending"}function se(e,t,n){let o=e.tBodies[0];if(!o)return;let r=Array.from(o.rows),s=r.filter(u=>u.cells.length>t),l=r.filter(u=>u.cells.length<=t),d=n==="ascending"?1:-1;s.sort((u,a)=>d*wt(Pe(u,t),Pe(a,t))),[...s,...l].forEach(u=>o.appendChild(u));let f=null;Ke(e).forEach(u=>{let a=u.cellIndex===t;u.setAttribute("aria-sort",a?n:"none"),a&&(f=u)}),f&&ie(e,"fw:sort",{column:t,direction:n,th:f})}function $(e){return Array.from(e.querySelectorAll("tbody input[data-fw-select-row]"))}function le(e,t){e.classList.toggle(Lt,t),e.setAttribute("aria-selected",t?"true":"false")}function ae(e){let t=e.querySelector("[data-fw-select-all]");if(!t)return;let n=$(e),o=n.filter(r=>r.checked).length;t.checked=o>0&&o===n.length,t.indeterminate=o>0&&o<n.length}function ce(e){return $(e).filter(t=>t.checked).map(t=>t.closest("tr")).filter(t=>t!==null)}function Fe(e,t){let n=e.querySelector("input[data-fw-select-row]");n&&(n.checked=t),le(e,t);let o=e.closest("table");o&&(ae(o),ie(o,"fw:select",{rows:ce(o),all:!1}))}function Ve(e,t){$(e).forEach(n=>{n.checked=t;let o=n.closest("tr");o&&le(o,t)}),ae(e),ie(e,"fw:select",{rows:ce(e),all:!0})}function de(e=document){e.querySelectorAll("table[data-fw-table]").forEach(t=>{t.dataset.fwBound||(t.dataset.fwBound="1",Ke(t).forEach(n=>{n.hasAttribute("aria-sort")||n.setAttribute("aria-sort","none")}),t.addEventListener("click",n=>{let o=n.target.closest("th[data-fw-sort]");o&&t.contains(o)&&se(t,o.cellIndex,je(o))}),t.addEventListener("keydown",n=>{if(n.key!=="Enter"&&n.key!==" ")return;let o=n.target;if(!o.matches("th[data-fw-sort], th[data-fw-sort] .fw-table-sort"))return;let r=o.closest("th[data-fw-sort]");r&&(n.preventDefault(),se(t,r.cellIndex,je(r)))}),t.addEventListener("change",n=>{let o=n.target;if(o.matches("[data-fw-select-all]"))Ve(t,o.checked);else if(o.matches("[data-fw-select-row]")){let r=o.closest("tr");r&&Fe(r,o.checked)}}),$(t).forEach(n=>{let o=n.closest("tr");o&&n.checked&&le(o,!0)}),ae(t))})}var K={};T(K,{close:()=>j,collapseAll:()=>Mt,expandAll:()=>gt,init:()=>ue,open:()=>P,reveal:()=>We,toggle:()=>bt});var p=".fw-menu-group",Ue=".fw-menu-link, .fw-menu-summary",vt="is-current";function ht(e,t){e.dispatchEvent(new CustomEvent("fw:toggle",{bubbles:!0,detail:t}))}function P(e){e.open=!0}function j(e){e.open=!1}function bt(e,t){e.open=t!=null?t:!e.open}function gt(e){e.querySelectorAll(p).forEach(P)}function Mt(e){e.querySelectorAll(p).forEach(j)}function We(e){var n,o,r,s;let t=(o=(n=e.parentElement)==null?void 0:n.closest(p))!=null?o:null;for(;t;)P(t),t=(s=(r=t.parentElement)==null?void 0:r.closest(p))!=null?s:null}function Ge(e){e.querySelectorAll(p).forEach(t=>{let n=t.querySelector(":scope > .fw-menu-summary");if(!n)return;let o=!t.open&&t.querySelector("[aria-current]")!==null;n.classList.toggle(vt,o)})}function _e(e){return e.matches(".fw-menu-summary")?e.closest(p):null}function ze(e){var n,o,r;return(r=(o=((n=_e(e))!=null?n:e).parentElement)==null?void 0:o.closest(p))!=null?r:null}function Ht(e){var t,n;for(let o=ze(e);o;o=(n=(t=o.parentElement)==null?void 0:t.closest(p))!=null?n:null)if(!o.open)return!1;return!0}function yt(e){return Array.from(e.querySelectorAll(Ue)).filter(Ht)}function h(e){return e?(e.focus(),!0):!1}function xt(e){var n;let t=e.closest(".fw-menu-split");return(n=t==null?void 0:t.querySelector(":scope > .fw-menu-group > .fw-menu-summary"))!=null?n:null}function kt(e,t){var d;if(t.altKey||t.ctrlKey||t.metaKey||t.shiftKey)return;let n=t.target instanceof HTMLElement&&t.target.matches(Ue)?t.target:null;if(!n||!e.contains(n))return;let o=yt(e),r=o.indexOf(n),s=_e(n),l=!0;switch(t.key){case"ArrowDown":h(o[r+1]);break;case"ArrowUp":h(o[r-1]);break;case"Home":h(o[0]);break;case"End":h(o[o.length-1]);break;case"ArrowRight":s?s.open?s.contains((d=o[r+1])!=null?d:e)&&h(o[r+1]):P(s):h(xt(n));break;case"ArrowLeft":if(s!=null&&s.open)j(s);else{let f=ze(n);h(f==null?void 0:f.querySelector(":scope > .fw-menu-summary"))}break;default:l=!1}l&&t.preventDefault()}function ue(e=document){e.querySelectorAll("[data-fw-menu]").forEach(t=>{if(t.dataset.fwBound)return;t.dataset.fwBound="1";let n=t.hasAttribute("data-fw-menu-exclusive");t.addEventListener("toggle",o=>{let r=o.target;!(r instanceof HTMLDetailsElement)||!r.matches(p)||(n&&r.open&&r.parentElement&&Array.from(r.parentElement.children).forEach(s=>{s!==r&&s instanceof HTMLDetailsElement&&s.matches(p)&&j(s)}),Ge(t),ht(r,{group:r,open:r.open}))},!0),t.addEventListener("keydown",o=>kt(t,o)),t.querySelectorAll("[aria-current]").forEach(We),Ge(t)})}var Ye="0.2.0";function Xe(e=document){_(e),z(e),ee(e),oe(e),re(e),de(e),ue(e)}var At={version:Ye,init:Xe,theme:O,combobox:C,modal:D,nav:B,loading:N,toast:I,table:R,menu:K},St=At;
4
4
  //# sourceMappingURL=fernwell.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/js/index.ts", "../src/js/theme.ts", "../src/js/combobox.ts", "../src/js/modal.ts", "../src/js/nav.ts", "../src/js/loading.ts", "../src/js/toast.ts"],
4
- "sourcesContent": ["/**\n * Fernwell \u2014 vanilla JS enhancers for the Fernwell design system.\n *\n * ESM / CJS: import { init, theme, toast } from 'fernwell'; init();\n * <script>: <script src=\"https://unpkg.com/fernwell/dist/fernwell.iife.js\"></script>\n * \u2192 window.Fernwell, auto-initialised on DOMContentLoaded\n * (add data-fw-no-init to the <script> tag to opt out).\n */\nimport * as theme from './theme';\nimport * as combobox from './combobox';\nimport * as modal from './modal';\nimport * as nav from './nav';\nimport * as loading from './loading';\nimport * as toast from './toast';\n\nexport { theme, combobox, modal, nav, loading, toast };\nexport type { Theme, TokenOverrides, TokenThemeOverrides } from './theme';\nexport type { ComboboxOptions, ComboboxInstance } from './combobox';\nexport type { ToastVariant, ToastOptions } from './toast';\n\nexport const version = \"0.1.0\";\n\n/**\n * Wire every `data-fw-*` hook under `root`. Safe to call more than once \u2014\n * already-bound elements are skipped \u2014 so call it again after injecting\n * markup (e.g. after an HTMX / Turbo swap).\n */\nexport function init(root: ParentNode = document): void {\n theme.init(root);\n combobox.init(root);\n modal.init(root);\n nav.init(root);\n loading.init(root);\n}\n\nconst Fernwell = { version, init, theme, combobox, modal, nav, loading, toast };\nexport default Fernwell;\n", "/**\n * Theme \u2014 toggles `data-theme=\"dark\"` on <html>, remembers the choice, and\n * falls back to the OS preference. Also carries the runtime token API\n * (`setTokens` / `resetTokens` / `getToken`) for retheming Fernwell's colour\n * tokens on the fly \u2014 per-tenant branding, a user-picked accent, a live\n * preview \u2014 without touching a stylesheet.\n *\n * <button class=\"fw-btn fw-btn-ghost\" data-fw-theme-toggle\n * data-fw-theme-label-dark=\"\u2600\uFE0F Light\" data-fw-theme-label-light=\"\uD83C\uDF19 Dark\">\uD83C\uDF19 Dark</button>\n *\n * To avoid a flash of the wrong theme on load, inline this before your CSS:\n * <script>document.documentElement.dataset.theme=localStorage.getItem('fw-theme')||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light')</script>\n */\nexport type Theme = 'light' | 'dark';\n\nconst STORAGE_KEY = 'fw-theme';\nconst EVENT = 'fw:themechange';\nconst TOKEN_PREFIX = '--fw-';\nconst TOKEN_STYLE_ATTR = 'data-fw-tokens';\n\nfunction store(): Storage | null {\n try {\n return window.localStorage;\n } catch {\n return null;\n }\n}\n\n/** The theme currently applied to <html>, or the system preference if none is set. */\nexport function get(): Theme {\n const attr = document.documentElement.getAttribute('data-theme');\n if (attr === 'dark' || attr === 'light') return attr;\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\n/** Apply a theme, persist it, and update every toggle button on the page. */\nexport function set(theme: Theme, { persist = true }: { persist?: boolean } = {}): void {\n document.documentElement.setAttribute('data-theme', theme);\n if (persist) store()?.setItem(STORAGE_KEY, theme);\n document.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => syncToggle(btn, theme));\n document.dispatchEvent(new CustomEvent<Theme>(EVENT, { detail: theme }));\n}\n\nexport function toggle(): Theme {\n const next: Theme = get() === 'dark' ? 'light' : 'dark';\n set(next);\n return next;\n}\n\nfunction syncToggle(btn: HTMLElement, theme: Theme): void {\n btn.setAttribute('aria-pressed', String(theme === 'dark'));\n const label = theme === 'dark' ? btn.dataset.fwThemeLabelDark : btn.dataset.fwThemeLabelLight;\n if (label !== undefined) btn.textContent = label;\n}\n\n/** Apply the stored / system theme and wire every `[data-fw-theme-toggle]` under `root`. */\nexport function init(root: ParentNode = document): void {\n const stored = store()?.getItem(STORAGE_KEY);\n const current: Theme = stored === 'dark' || stored === 'light' ? stored : get();\n set(current, { persist: false });\n\n root.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n syncToggle(btn, current);\n btn.addEventListener('click', () => toggle());\n });\n\n // Follow the OS only while the user hasn't chosen explicitly.\n window.matchMedia?.('(prefers-color-scheme: dark)').addEventListener?.('change', (e) => {\n if (!store()?.getItem(STORAGE_KEY)) set(e.matches ? 'dark' : 'light', { persist: false });\n });\n}\n\n/* ---------------------------------------------------------------------- *\n * Runtime tokens \u2014 override any --fw-* custom property from JS, in both\n * themes or per-theme, scoped to :root or to any selector. Overrides render\n * into one <style data-fw-tokens> appended to <head>: being unlayered and\n * last, it wins over Fernwell's own @layer fw-tokens *and* any earlier\n * static override in the consumer's stylesheet.\n * ---------------------------------------------------------------------- */\n\n/** Token name \u2192 CSS value. Bare names (`primary`) and full names (`--fw-primary`) both work. */\nexport type TokenOverrides = Record<string, string>;\n\n/** Split form: set different values per theme instead of both at once. */\nexport interface TokenThemeOverrides {\n light?: TokenOverrides;\n dark?: TokenOverrides;\n}\n\ninterface ScopeTokens {\n light: TokenOverrides;\n dark: TokenOverrides;\n}\n\nconst tokenScopes = new Map<string, ScopeTokens>();\n\nfunction normalizeTokenName(name: string): string {\n return name.startsWith('--') ? name : `${TOKEN_PREFIX}${name}`;\n}\n\nfunction isThemeSplit(tokens: TokenOverrides | TokenThemeOverrides): tokens is TokenThemeOverrides {\n // A token's own value is always a CSS string \u2014 so any object-valued entry\n // means this is the { light, dark } split form, not a flat token map.\n return Object.values(tokens).some((v) => v !== null && typeof v === 'object');\n}\n\nfunction declBlock(tokens: TokenOverrides): string {\n return Object.entries(tokens)\n .map(([name, value]) => `${normalizeTokenName(name)}:${value};`)\n .join('');\n}\n\nfunction tokenStyleEl(create: boolean): HTMLStyleElement | null {\n const existing = document.head.querySelector<HTMLStyleElement>(`style[${TOKEN_STYLE_ATTR}]`);\n if (existing || !create) return existing;\n const el = document.createElement('style');\n el.setAttribute(TOKEN_STYLE_ATTR, '');\n document.head.appendChild(el);\n return el;\n}\n\nfunction renderTokens(): void {\n if (tokenScopes.size === 0) {\n tokenStyleEl(false)?.remove();\n return;\n }\n const rules: string[] = [];\n tokenScopes.forEach(({ light, dark }, scope) => {\n if (Object.keys(light).length) rules.push(`${scope}{${declBlock(light)}}`);\n if (Object.keys(dark).length) {\n const darkSelector =\n scope === ':root' ? '[data-theme=\"dark\"]' : `[data-theme=\"dark\"] ${scope}, ${scope}[data-theme=\"dark\"]`;\n rules.push(`${darkSelector}{${declBlock(dark)}}`);\n }\n });\n tokenStyleEl(true)!.textContent = rules.join('\\n');\n}\n\n/**\n * Override Fernwell design tokens at runtime \u2014 every derived token (hovers,\n * tints, focus ring, glows) follows automatically, in both themes:\n *\n * theme.setTokens({ primary: '#2266ff' });\n *\n * Pass `{ light, dark }` to set different values per theme, and `scope` to\n * theme a subtree instead of the whole page:\n *\n * theme.setTokens({ light: { primary: '#2266ff' }, dark: { primary: '#5c9dff' } });\n * theme.setTokens({ secondary: '#a33' }, { scope: '.tenant-acme' });\n *\n * Calls accumulate (merge into whatever overrides are already set for that\n * scope) \u2014 call `resetTokens()` to clear them.\n */\nexport function setTokens(tokens: TokenOverrides | TokenThemeOverrides, opts: { scope?: string } = {}): void {\n const scope = opts.scope ?? ':root';\n const entry = tokenScopes.get(scope) ?? { light: {}, dark: {} };\n if (isThemeSplit(tokens)) {\n Object.assign(entry.light, tokens.light);\n Object.assign(entry.dark, tokens.dark);\n } else {\n Object.assign(entry.light, tokens);\n Object.assign(entry.dark, tokens);\n }\n tokenScopes.set(scope, entry);\n renderTokens();\n}\n\n/** Clear runtime token overrides \u2014 for one `scope`, or every scope if omitted. */\nexport function resetTokens(scope?: string): void {\n if (scope) tokenScopes.delete(scope);\n else tokenScopes.clear();\n renderTokens();\n}\n\n/** The live, resolved value of a token (e.g. `getToken('primary')` \u2192 `'#ffc145'`), including runtime overrides. */\nexport function getToken(name: string, el: Element = document.documentElement): string {\n return getComputedStyle(el).getPropertyValue(normalizeTokenName(name)).trim();\n}\n", "/**\n * Combobox / typeahead \u2014 progressive enhancement over an <input> + <datalist>.\n *\n * <div class=\"fw-combobox\">\n * <input class=\"fw-input\" data-fw-combobox list=\"cities\" placeholder=\"Start typing\u2026\">\n * <datalist id=\"cities\"><option value=\"Seattle\"></option>\u2026</datalist>\n * </div>\n *\n * Or programmatically: combobox(input, { options: ['Seattle', \u2026], onSelect })\n */\nexport interface ComboboxOptions {\n /** Static option list. Defaults to the <datalist> the input's `list` attribute points at. */\n options?: string[];\n /** Filter function; default is case-insensitive substring match. */\n filter?: (option: string, query: string) => boolean;\n /** Text shown when nothing matches. */\n emptyText?: string;\n onSelect?: (value: string) => void;\n}\n\nexport interface ComboboxInstance {\n open(): void;\n close(): void;\n setOptions(options: string[]): void;\n destroy(): void;\n}\n\nlet uid = 0;\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c] as string);\n}\n\nexport function combobox(input: HTMLInputElement, opts: ComboboxOptions = {}): ComboboxInstance {\n const filter = opts.filter ?? ((o, q) => o.toLowerCase().includes(q));\n const emptyText = opts.emptyText ?? 'No matches';\n let options = opts.options ?? readDatalist(input);\n let current: string[] = [];\n let activeIndex = -1;\n let selecting = false;\n\n // The native datalist would double up with our list \u2014 detach it but keep\n // the options readable for setOptions()/no-JS fallbacks.\n const listId = input.getAttribute('list');\n if (listId) {\n input.dataset.fwList = listId;\n input.removeAttribute('list');\n }\n\n const wrap = input.closest('.fw-combobox') ?? wrapInput(input);\n const list = document.createElement('ul');\n const id = `fw-combobox-${++uid}`;\n list.className = 'fw-combobox-list';\n list.id = id;\n list.setAttribute('role', 'listbox');\n wrap.appendChild(list);\n\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', id);\n input.autocomplete = 'off';\n\n function render(matches: string[]): void {\n current = matches;\n activeIndex = -1;\n const q = input.value.trim().toLowerCase();\n if (matches.length === 0) {\n list.innerHTML = `<li class=\"fw-combobox-empty\">${escapeHtml(emptyText)}</li>`;\n return;\n }\n list.innerHTML = matches\n .map((opt, i) => {\n const idx = q ? opt.toLowerCase().indexOf(q) : -1;\n const label =\n idx > -1\n ? `${escapeHtml(opt.slice(0, idx))}<b>${escapeHtml(opt.slice(idx, idx + q.length))}</b>${escapeHtml(opt.slice(idx + q.length))}`\n : escapeHtml(opt);\n return `<li class=\"fw-combobox-option\" role=\"option\" id=\"${id}-${i}\" data-index=\"${i}\" aria-selected=\"false\">${label}</li>`;\n })\n .join('');\n }\n\n function open(): void {\n const q = input.value.trim().toLowerCase();\n render(q ? options.filter((o) => filter(o, q)) : options);\n list.classList.add('is-open');\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close(): void {\n list.classList.remove('is-open');\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n activeIndex = -1;\n }\n\n function highlight(i: number): void {\n const items = list.querySelectorAll<HTMLElement>('.fw-combobox-option');\n items.forEach((el) => {\n el.classList.remove('is-active');\n el.setAttribute('aria-selected', 'false');\n });\n const el = items[i];\n if (el) {\n el.classList.add('is-active');\n el.setAttribute('aria-selected', 'true');\n el.scrollIntoView({ block: 'nearest' });\n input.setAttribute('aria-activedescendant', el.id);\n }\n activeIndex = i;\n }\n\n function select(value: string): void {\n input.value = value;\n close();\n // The synthetic events below would re-open the list via onInput/onFocus.\n selecting = true;\n input.focus();\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n selecting = false;\n opts.onSelect?.(value);\n }\n\n const onInput = () => {\n if (!selecting) open();\n };\n const onFocus = () => {\n if (!selecting) open();\n };\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (!list.classList.contains('is-open')) open();\n highlight(Math.min(activeIndex + 1, current.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n highlight(Math.max(activeIndex - 1, 0));\n } else if (e.key === 'Enter') {\n if (activeIndex > -1 && current[activeIndex] !== undefined) {\n e.preventDefault();\n select(current[activeIndex]);\n }\n } else if (e.key === 'Escape') {\n close();\n }\n };\n const onListMousedown = (e: MouseEvent) => {\n const opt = (e.target as HTMLElement).closest<HTMLElement>('.fw-combobox-option');\n if (opt) {\n e.preventDefault(); // keep focus on the input\n select(current[Number(opt.dataset.index)]);\n }\n };\n const onDocClick = (e: MouseEvent) => {\n if (!wrap.contains(e.target as Node)) close();\n };\n\n input.addEventListener('input', onInput);\n input.addEventListener('focus', onFocus);\n input.addEventListener('keydown', onKeydown);\n list.addEventListener('mousedown', onListMousedown);\n document.addEventListener('click', onDocClick);\n\n return {\n open,\n close,\n setOptions(next) {\n options = next;\n if (list.classList.contains('is-open')) open();\n },\n destroy() {\n input.removeEventListener('input', onInput);\n input.removeEventListener('focus', onFocus);\n input.removeEventListener('keydown', onKeydown);\n list.removeEventListener('mousedown', onListMousedown);\n document.removeEventListener('click', onDocClick);\n list.remove();\n if (input.dataset.fwList) input.setAttribute('list', input.dataset.fwList);\n delete input.dataset.fwBound;\n },\n };\n}\n\nfunction readDatalist(input: HTMLInputElement): string[] {\n const id = input.getAttribute('list') ?? input.dataset.fwList;\n const dl = id ? document.getElementById(id) : null;\n return dl ? Array.from(dl.querySelectorAll('option')).map((o) => o.value || o.textContent || '') : [];\n}\n\nfunction wrapInput(input: HTMLInputElement): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'fw-combobox';\n input.parentNode?.insertBefore(wrap, input);\n wrap.appendChild(input);\n return wrap;\n}\n\n/** Enhance every `[data-fw-combobox]` input under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLInputElement>('input[data-fw-combobox]').forEach((input) => {\n if (input.dataset.fwBound) return;\n input.dataset.fwBound = '1';\n combobox(input);\n });\n}\n", "/**\n * Modal & drawer overlays.\n *\n * <button data-fw-open-modal=\"confirm\">\u2026</button>\n * <div class=\"fw-modal-overlay\" id=\"confirm\" role=\"dialog\" aria-modal=\"true\"><div class=\"fw-modal\">\u2026 <button data-fw-close-modal>Cancel</button></div></div>\n *\n * <button data-fw-open-drawer=\"details\">\u2026</button>\n * <div class=\"fw-drawer-overlay\" data-fw-drawer-overlay=\"details\"></div>\n * <aside class=\"fw-drawer\" id=\"details\" role=\"dialog\" aria-modal=\"true\">\u2026 <button data-fw-close-drawer>\u00D7</button></aside>\n *\n * Closes on backdrop click (guarded \u2014 a text-selection drag that ends on the\n * backdrop does NOT close it), on Escape, and returns focus to the opener.\n */\nconst OPEN = 'is-open';\nconst LOCK = 'fw-scroll-lock';\nconst openStack: HTMLElement[] = [];\nconst openers = new WeakMap<HTMLElement, HTMLElement | null>();\n\nconst FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction resolve(target: string | HTMLElement): HTMLElement | null {\n return typeof target === 'string' ? document.getElementById(target) : target;\n}\n\n/** The backdrop element paired with a drawer (via `data-fw-drawer-overlay=\"<id>\"`), if any. */\nfunction backdropFor(el: HTMLElement): HTMLElement | null {\n if (el.classList.contains('fw-modal-overlay')) return el;\n const explicit = el.id ? document.querySelector<HTMLElement>(`[data-fw-drawer-overlay=\"${el.id}\"]`) : null;\n if (explicit) return explicit;\n const prev = el.previousElementSibling;\n return prev instanceof HTMLElement && prev.classList.contains('fw-drawer-overlay') ? prev : null;\n}\n\nexport function open(target: string | HTMLElement, opener: HTMLElement | null = (document.activeElement as HTMLElement) ?? null): void {\n const el = resolve(target);\n if (!el || el.classList.contains(OPEN)) return;\n el.classList.add(OPEN);\n backdropFor(el)?.classList.add(OPEN);\n openers.set(el, opener);\n openStack.push(el);\n document.body.classList.add(LOCK);\n el.dispatchEvent(new CustomEvent('fw:open', { bubbles: true }));\n // Focus the first control inside; fall back to the panel itself.\n const first = el.querySelector<HTMLElement>(FOCUSABLE);\n if (first) first.focus({ preventScroll: true });\n else {\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n el.focus({ preventScroll: true });\n }\n}\n\nexport function close(target: string | HTMLElement): void {\n const el = resolve(target);\n if (!el || !el.classList.contains(OPEN)) return;\n el.classList.remove(OPEN);\n backdropFor(el)?.classList.remove(OPEN);\n const i = openStack.indexOf(el);\n if (i > -1) openStack.splice(i, 1);\n if (openStack.length === 0) document.body.classList.remove(LOCK);\n el.dispatchEvent(new CustomEvent('fw:close', { bubbles: true }));\n openers.get(el)?.focus?.({ preventScroll: true });\n openers.delete(el);\n}\n\nexport function toggle(target: string | HTMLElement): void {\n const el = resolve(target);\n if (el) (el.classList.contains(OPEN) ? close : open)(el);\n}\n\n/**\n * Click-outside-to-close, guarded against a classic false positive: a\n * browser's `click` fires on the nearest common ancestor of mousedown and\n * mouseup. A drag that starts inside the panel and ends on the backdrop has\n * the overlay as that ancestor, so a naive `e.target === overlay` check would\n * close the modal mid-selection. Close only when BOTH landed on the backdrop.\n */\nexport function bindOutsideClickToClose(backdrop: HTMLElement, onClose: () => void): void {\n let downOnBackdrop = false;\n backdrop.addEventListener('mousedown', (e) => {\n downOnBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && downOnBackdrop) onClose();\n });\n}\n\nlet keyBound = false;\n\n/** Wire every trigger, overlay and close button under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-open-modal], [data-fw-open-drawer]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n const id = btn.dataset.fwOpenModal ?? btn.dataset.fwOpenDrawer ?? '';\n btn.addEventListener('click', () => open(id, btn));\n });\n\n root.querySelectorAll<HTMLElement>('.fw-modal-overlay').forEach((overlay) => {\n if (overlay.dataset.fwBound) return;\n overlay.dataset.fwBound = '1';\n bindOutsideClickToClose(overlay, () => close(overlay));\n overlay.querySelectorAll<HTMLElement>('[data-fw-close-modal]').forEach((btn) =>\n btn.addEventListener('click', () => close(overlay)),\n );\n });\n\n root.querySelectorAll<HTMLElement>('.fw-drawer').forEach((drawer) => {\n if (drawer.dataset.fwBound) return;\n drawer.dataset.fwBound = '1';\n const backdrop = backdropFor(drawer);\n if (backdrop) bindOutsideClickToClose(backdrop, () => close(drawer));\n drawer.querySelectorAll<HTMLElement>('[data-fw-close-drawer]').forEach((btn) =>\n btn.addEventListener('click', () => close(drawer)),\n );\n });\n\n if (!keyBound) {\n keyBound = true;\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && openStack.length) close(openStack[openStack.length - 1]);\n });\n }\n}\n", "/**\n * Nav dropdown \u2014 the hamburger toggle in `.fw-nav` (and any other\n * button-controls-panel pair).\n *\n * <button data-fw-nav-toggle aria-controls=\"menu\" aria-expanded=\"false\">\u2026</button>\n * <div class=\"fw-nav-dropdown\" id=\"menu\">\u2026</div>\n *\n * Closes on outside click and Escape.\n */\nconst OPEN = 'is-open';\n\nexport function open(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.add(OPEN);\n toggle.setAttribute('aria-expanded', 'true');\n}\n\nexport function close(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.remove(OPEN);\n toggle.setAttribute('aria-expanded', 'false');\n}\n\nfunction panelFor(toggle: HTMLElement): HTMLElement | null {\n const id = toggle.getAttribute('aria-controls');\n return id ? document.getElementById(id) : null;\n}\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-nav-toggle]').forEach((toggle) => {\n if (toggle.dataset.fwBound) return;\n toggle.dataset.fwBound = '1';\n const panel = panelFor(toggle);\n if (!panel) return;\n const container = toggle.closest<HTMLElement>('.fw-nav') ?? toggle.parentElement ?? toggle;\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n (panel.classList.contains(OPEN) ? close : open)(toggle);\n });\n document.addEventListener('click', (e) => {\n if (!container.contains(e.target as Node) && !panel.contains(e.target as Node)) close(toggle);\n });\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') close(toggle);\n });\n });\n}\n", "/**\n * Loading states.\n *\n * loading.setButtonLoading(btn, 'Sending\u2026'); // disables, swaps in a spinner\n * loading.resetButtonLoading(btn); // restores original markup\n *\n * Or declaratively: any <form data-fw-loading> puts its submit button into the\n * loading state on submit (label from `data-fw-loading-text` on the button).\n */\nconst LOADING = 'fw-btn-loading';\n\nexport function setButtonLoading(btn: HTMLButtonElement | null, loadingText?: string): void {\n if (!btn || btn.classList.contains(LOADING)) return;\n btn.dataset.fwOriginalHtml = btn.innerHTML;\n btn.disabled = true;\n btn.setAttribute('aria-busy', 'true');\n btn.classList.add(LOADING);\n const label = loadingText ?? btn.dataset.fwLoadingText ?? btn.textContent ?? '';\n btn.innerHTML = '<span class=\"fw-spinner fw-spinner-sm\" aria-hidden=\"true\"></span>';\n btn.appendChild(document.createTextNode(label));\n}\n\nexport function resetButtonLoading(btn: HTMLButtonElement | null): void {\n if (!btn || !btn.classList.contains(LOADING)) return;\n btn.disabled = false;\n btn.removeAttribute('aria-busy');\n btn.classList.remove(LOADING);\n // Restore markup, not just text, so buttons with an icon keep it.\n if (btn.dataset.fwOriginalHtml !== undefined) {\n btn.innerHTML = btn.dataset.fwOriginalHtml;\n delete btn.dataset.fwOriginalHtml;\n }\n}\n\n/** Reset every loading button \u2014 e.g. after a bfcache restore. */\nexport function resetAll(root: ParentNode = document): void {\n root.querySelectorAll<HTMLButtonElement>(`.${LOADING}`).forEach(resetButtonLoading);\n}\n\nlet pageshowBound = false;\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLFormElement>('form[data-fw-loading]').forEach((form) => {\n if (form.dataset.fwBound) return;\n form.dataset.fwBound = '1';\n form.addEventListener('submit', () => {\n const btn = form.querySelector<HTMLButtonElement>('button[type=\"submit\"], button:not([type])');\n setButtonLoading(btn);\n });\n });\n\n // Browsers restore pages from the back-forward cache without re-running JS,\n // so a spinner painted right before navigating away would come back stuck.\n if (!pageshowBound) {\n pageshowBound = true;\n window.addEventListener('pageshow', (e) => {\n if (e.persisted) resetAll();\n });\n }\n}\n", "/**\n * Toast \u2014 a single, reused, bottom-right notice.\n *\n * toast.show('Invoice sent');\n * toast.show('That card was declined', { variant: 'error', duration: 6000 });\n */\nexport type ToastVariant = 'success' | 'error' | 'info' | 'pending';\n\nexport interface ToastOptions {\n variant?: ToastVariant;\n /** ms before it hides; 0 keeps it until `hide()` or the next `show()`. */\n duration?: number;\n}\n\nlet el: HTMLElement | null = null;\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensure(): HTMLElement {\n if (el && el.isConnected) return el;\n el = document.createElement('div');\n el.className = 'fw-toast';\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n el.innerHTML = '<span class=\"fw-toast-dot\" aria-hidden=\"true\"></span><span class=\"fw-toast-text\"></span>';\n document.body.appendChild(el);\n return el;\n}\n\nexport function show(message: string, { variant = 'success', duration = 4000 }: ToastOptions = {}): HTMLElement {\n const node = ensure();\n node.className = `fw-toast${variant === 'success' ? '' : ` fw-toast-${variant}`}`;\n (node.querySelector('.fw-toast-text') as HTMLElement).textContent = message;\n if (timer) clearTimeout(timer);\n // Re-trigger the transition even if it's already showing.\n node.classList.remove('is-show');\n void node.offsetWidth;\n node.classList.add('is-show');\n if (duration > 0) timer = setTimeout(hide, duration);\n return node;\n}\n\nexport function hide(): void {\n el?.classList.remove('is-show');\n if (timer) clearTimeout(timer);\n timer = null;\n}\n"],
5
- "mappings": "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",
6
- "names": ["index_exports", "__export", "combobox_exports", "index_default", "init", "loading_exports", "modal_exports", "nav_exports", "theme_exports", "toast_exports", "version", "__toCommonJS", "theme_exports", "__export", "get", "getToken", "init", "resetTokens", "set", "setTokens", "toggle", "STORAGE_KEY", "EVENT", "TOKEN_PREFIX", "TOKEN_STYLE_ATTR", "store", "_a", "attr", "theme", "persist", "btn", "syncToggle", "next", "label", "root", "_b", "_c", "_d", "stored", "current", "e", "tokenScopes", "normalizeTokenName", "name", "isThemeSplit", "tokens", "v", "declBlock", "value", "tokenStyleEl", "create", "existing", "el", "renderTokens", "rules", "light", "dark", "scope", "darkSelector", "opts", "entry", "combobox_exports", "__export", "combobox", "init", "uid", "escapeHtml", "s", "c", "input", "opts", "_a", "_b", "_c", "_d", "filter", "o", "q", "emptyText", "options", "readDatalist", "current", "activeIndex", "selecting", "listId", "wrap", "wrapInput", "list", "id", "render", "matches", "opt", "i", "idx", "label", "open", "close", "highlight", "items", "el", "select", "value", "onInput", "onFocus", "onKeydown", "e", "onListMousedown", "onDocClick", "next", "dl", "root", "modal_exports", "__export", "bindOutsideClickToClose", "close", "init", "open", "toggle", "OPEN", "LOCK", "openStack", "openers", "FOCUSABLE", "resolve", "target", "backdropFor", "el", "explicit", "prev", "opener", "_a", "first", "_b", "_c", "i", "backdrop", "onClose", "downOnBackdrop", "e", "keyBound", "root", "btn", "id", "overlay", "drawer", "nav_exports", "__export", "close", "init", "open", "OPEN", "toggle", "panel", "panelFor", "id", "root", "_a", "_b", "container", "e", "loading_exports", "__export", "init", "resetAll", "resetButtonLoading", "setButtonLoading", "LOADING", "btn", "loadingText", "_a", "_b", "label", "root", "pageshowBound", "form", "e", "toast_exports", "__export", "hide", "show", "el", "timer", "ensure", "message", "variant", "duration", "node", "version", "init", "root", "Fernwell", "theme_exports", "combobox_exports", "modal_exports", "nav_exports", "loading_exports", "toast_exports", "index_default"]
3
+ "sources": ["../src/js/index.ts", "../src/js/theme.ts", "../src/js/combobox.ts", "../src/js/modal.ts", "../src/js/nav.ts", "../src/js/loading.ts", "../src/js/toast.ts", "../src/js/table.ts", "../src/js/menu.ts"],
4
+ "sourcesContent": ["/**\n * Fernwell \u2014 vanilla JS enhancers for the Fernwell design system.\n *\n * ESM / CJS: import { init, theme, toast } from 'fernwell'; init();\n * <script>: <script src=\"https://unpkg.com/fernwell/dist/fernwell.iife.js\"></script>\n * \u2192 window.Fernwell, auto-initialised on DOMContentLoaded\n * (add data-fw-no-init to the <script> tag to opt out).\n */\nimport * as theme from './theme';\nimport * as combobox from './combobox';\nimport * as modal from './modal';\nimport * as nav from './nav';\nimport * as loading from './loading';\nimport * as toast from './toast';\nimport * as table from './table';\nimport * as menu from './menu';\n\nexport { theme, combobox, modal, nav, loading, toast, table, menu };\nexport type { Theme, TokenOverrides, TokenThemeOverrides } from './theme';\nexport type { ComboboxOptions, ComboboxInstance } from './combobox';\nexport type { ToastVariant, ToastOptions } from './toast';\nexport type { SortDirection, SortDetail, SelectDetail } from './table';\nexport type { ToggleDetail } from './menu';\n\nexport const version = \"0.2.0\";\n\n/**\n * Wire every `data-fw-*` hook under `root`. Safe to call more than once \u2014\n * already-bound elements are skipped \u2014 so call it again after injecting\n * markup (e.g. after an HTMX / Turbo swap).\n */\nexport function init(root: ParentNode = document): void {\n theme.init(root);\n combobox.init(root);\n modal.init(root);\n nav.init(root);\n loading.init(root);\n table.init(root);\n menu.init(root);\n}\n\nconst Fernwell = { version, init, theme, combobox, modal, nav, loading, toast, table, menu };\nexport default Fernwell;\n", "/**\n * Theme \u2014 toggles `data-theme=\"dark\"` on <html>, remembers the choice, and\n * falls back to the OS preference. Also carries the runtime token API\n * (`setTokens` / `resetTokens` / `getToken`) for retheming Fernwell's colour\n * tokens on the fly \u2014 per-tenant branding, a user-picked accent, a live\n * preview \u2014 without touching a stylesheet.\n *\n * <button class=\"fw-btn fw-btn-ghost\" data-fw-theme-toggle\n * data-fw-theme-label-dark=\"\u2600\uFE0F Light\" data-fw-theme-label-light=\"\uD83C\uDF19 Dark\">\uD83C\uDF19 Dark</button>\n *\n * To avoid a flash of the wrong theme on load, inline this before your CSS:\n * <script>document.documentElement.dataset.theme=localStorage.getItem('fw-theme')||(matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light')</script>\n */\nexport type Theme = 'light' | 'dark';\n\nconst STORAGE_KEY = 'fw-theme';\nconst EVENT = 'fw:themechange';\nconst TOKEN_PREFIX = '--fw-';\nconst TOKEN_STYLE_ATTR = 'data-fw-tokens';\n\nfunction store(): Storage | null {\n try {\n return window.localStorage;\n } catch {\n return null;\n }\n}\n\n/** The theme currently applied to <html>, or the system preference if none is set. */\nexport function get(): Theme {\n const attr = document.documentElement.getAttribute('data-theme');\n if (attr === 'dark' || attr === 'light') return attr;\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\n/** Apply a theme, persist it, and update every toggle button on the page. */\nexport function set(theme: Theme, { persist = true }: { persist?: boolean } = {}): void {\n document.documentElement.setAttribute('data-theme', theme);\n if (persist) store()?.setItem(STORAGE_KEY, theme);\n document.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => syncToggle(btn, theme));\n document.dispatchEvent(new CustomEvent<Theme>(EVENT, { detail: theme }));\n}\n\nexport function toggle(): Theme {\n const next: Theme = get() === 'dark' ? 'light' : 'dark';\n set(next);\n return next;\n}\n\nfunction syncToggle(btn: HTMLElement, theme: Theme): void {\n btn.setAttribute('aria-pressed', String(theme === 'dark'));\n const label = theme === 'dark' ? btn.dataset.fwThemeLabelDark : btn.dataset.fwThemeLabelLight;\n if (label !== undefined) btn.textContent = label;\n}\n\n/** Apply the stored / system theme and wire every `[data-fw-theme-toggle]` under `root`. */\nexport function init(root: ParentNode = document): void {\n const stored = store()?.getItem(STORAGE_KEY);\n const current: Theme = stored === 'dark' || stored === 'light' ? stored : get();\n set(current, { persist: false });\n\n root.querySelectorAll<HTMLElement>('[data-fw-theme-toggle]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n syncToggle(btn, current);\n btn.addEventListener('click', () => toggle());\n });\n\n // Follow the OS only while the user hasn't chosen explicitly.\n window.matchMedia?.('(prefers-color-scheme: dark)').addEventListener?.('change', (e) => {\n if (!store()?.getItem(STORAGE_KEY)) set(e.matches ? 'dark' : 'light', { persist: false });\n });\n}\n\n/* ---------------------------------------------------------------------- *\n * Runtime tokens \u2014 override any --fw-* custom property from JS, in both\n * themes or per-theme, scoped to :root or to any selector. Overrides render\n * into one <style data-fw-tokens> appended to <head>: being unlayered and\n * last, it wins over Fernwell's own @layer fw-tokens *and* any earlier\n * static override in the consumer's stylesheet.\n * ---------------------------------------------------------------------- */\n\n/** Token name \u2192 CSS value. Bare names (`primary`) and full names (`--fw-primary`) both work. */\nexport type TokenOverrides = Record<string, string>;\n\n/** Split form: set different values per theme instead of both at once. */\nexport interface TokenThemeOverrides {\n light?: TokenOverrides;\n dark?: TokenOverrides;\n}\n\ninterface ScopeTokens {\n light: TokenOverrides;\n dark: TokenOverrides;\n}\n\nconst tokenScopes = new Map<string, ScopeTokens>();\n\nfunction normalizeTokenName(name: string): string {\n return name.startsWith('--') ? name : `${TOKEN_PREFIX}${name}`;\n}\n\nfunction isThemeSplit(tokens: TokenOverrides | TokenThemeOverrides): tokens is TokenThemeOverrides {\n // A token's own value is always a CSS string \u2014 so any object-valued entry\n // means this is the { light, dark } split form, not a flat token map.\n return Object.values(tokens).some((v) => v !== null && typeof v === 'object');\n}\n\nfunction declBlock(tokens: TokenOverrides): string {\n return Object.entries(tokens)\n .map(([name, value]) => `${normalizeTokenName(name)}:${value};`)\n .join('');\n}\n\nfunction tokenStyleEl(create: boolean): HTMLStyleElement | null {\n const existing = document.head.querySelector<HTMLStyleElement>(`style[${TOKEN_STYLE_ATTR}]`);\n if (existing || !create) return existing;\n const el = document.createElement('style');\n el.setAttribute(TOKEN_STYLE_ATTR, '');\n document.head.appendChild(el);\n return el;\n}\n\nfunction renderTokens(): void {\n if (tokenScopes.size === 0) {\n tokenStyleEl(false)?.remove();\n return;\n }\n const rules: string[] = [];\n tokenScopes.forEach(({ light, dark }, scope) => {\n if (Object.keys(light).length) rules.push(`${scope}{${declBlock(light)}}`);\n if (Object.keys(dark).length) {\n const darkSelector =\n scope === ':root' ? '[data-theme=\"dark\"]' : `[data-theme=\"dark\"] ${scope}, ${scope}[data-theme=\"dark\"]`;\n rules.push(`${darkSelector}{${declBlock(dark)}}`);\n }\n });\n tokenStyleEl(true)!.textContent = rules.join('\\n');\n}\n\n/**\n * Override Fernwell design tokens at runtime \u2014 every derived token (hovers,\n * tints, focus ring, glows) follows automatically, in both themes:\n *\n * theme.setTokens({ primary: '#2266ff' });\n *\n * Pass `{ light, dark }` to set different values per theme, and `scope` to\n * theme a subtree instead of the whole page:\n *\n * theme.setTokens({ light: { primary: '#2266ff' }, dark: { primary: '#5c9dff' } });\n * theme.setTokens({ secondary: '#a33' }, { scope: '.tenant-acme' });\n *\n * Calls accumulate (merge into whatever overrides are already set for that\n * scope) \u2014 call `resetTokens()` to clear them.\n */\nexport function setTokens(tokens: TokenOverrides | TokenThemeOverrides, opts: { scope?: string } = {}): void {\n const scope = opts.scope ?? ':root';\n const entry = tokenScopes.get(scope) ?? { light: {}, dark: {} };\n if (isThemeSplit(tokens)) {\n Object.assign(entry.light, tokens.light);\n Object.assign(entry.dark, tokens.dark);\n } else {\n Object.assign(entry.light, tokens);\n Object.assign(entry.dark, tokens);\n }\n tokenScopes.set(scope, entry);\n renderTokens();\n}\n\n/** Clear runtime token overrides \u2014 for one `scope`, or every scope if omitted. */\nexport function resetTokens(scope?: string): void {\n if (scope) tokenScopes.delete(scope);\n else tokenScopes.clear();\n renderTokens();\n}\n\n/** The live, resolved value of a token (e.g. `getToken('primary')` \u2192 `'#ffc145'`), including runtime overrides. */\nexport function getToken(name: string, el: Element = document.documentElement): string {\n return getComputedStyle(el).getPropertyValue(normalizeTokenName(name)).trim();\n}\n", "/**\n * Combobox / typeahead \u2014 progressive enhancement over an <input> + <datalist>.\n *\n * <div class=\"fw-combobox\">\n * <input class=\"fw-input\" data-fw-combobox list=\"cities\" placeholder=\"Start typing\u2026\">\n * <datalist id=\"cities\"><option value=\"Seattle\"></option>\u2026</datalist>\n * </div>\n *\n * Or programmatically: combobox(input, { options: ['Seattle', \u2026], onSelect })\n */\nexport interface ComboboxOptions {\n /** Static option list. Defaults to the <datalist> the input's `list` attribute points at. */\n options?: string[];\n /** Filter function; default is case-insensitive substring match. */\n filter?: (option: string, query: string) => boolean;\n /** Text shown when nothing matches. */\n emptyText?: string;\n onSelect?: (value: string) => void;\n}\n\nexport interface ComboboxInstance {\n open(): void;\n close(): void;\n setOptions(options: string[]): void;\n destroy(): void;\n}\n\nlet uid = 0;\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[c] as string);\n}\n\nexport function combobox(input: HTMLInputElement, opts: ComboboxOptions = {}): ComboboxInstance {\n const filter = opts.filter ?? ((o, q) => o.toLowerCase().includes(q));\n const emptyText = opts.emptyText ?? 'No matches';\n let options = opts.options ?? readDatalist(input);\n let current: string[] = [];\n let activeIndex = -1;\n let selecting = false;\n\n // The native datalist would double up with our list \u2014 detach it but keep\n // the options readable for setOptions()/no-JS fallbacks.\n const listId = input.getAttribute('list');\n if (listId) {\n input.dataset.fwList = listId;\n input.removeAttribute('list');\n }\n\n const wrap = input.closest('.fw-combobox') ?? wrapInput(input);\n const list = document.createElement('ul');\n const id = `fw-combobox-${++uid}`;\n list.className = 'fw-combobox-list';\n list.id = id;\n list.setAttribute('role', 'listbox');\n wrap.appendChild(list);\n\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', id);\n input.autocomplete = 'off';\n\n function render(matches: string[]): void {\n current = matches;\n activeIndex = -1;\n const q = input.value.trim().toLowerCase();\n if (matches.length === 0) {\n list.innerHTML = `<li class=\"fw-combobox-empty\">${escapeHtml(emptyText)}</li>`;\n return;\n }\n list.innerHTML = matches\n .map((opt, i) => {\n const idx = q ? opt.toLowerCase().indexOf(q) : -1;\n const label =\n idx > -1\n ? `${escapeHtml(opt.slice(0, idx))}<b>${escapeHtml(opt.slice(idx, idx + q.length))}</b>${escapeHtml(opt.slice(idx + q.length))}`\n : escapeHtml(opt);\n return `<li class=\"fw-combobox-option\" role=\"option\" id=\"${id}-${i}\" data-index=\"${i}\" aria-selected=\"false\">${label}</li>`;\n })\n .join('');\n }\n\n function open(): void {\n const q = input.value.trim().toLowerCase();\n render(q ? options.filter((o) => filter(o, q)) : options);\n list.classList.add('is-open');\n input.setAttribute('aria-expanded', 'true');\n }\n\n function close(): void {\n list.classList.remove('is-open');\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n activeIndex = -1;\n }\n\n function highlight(i: number): void {\n const items = list.querySelectorAll<HTMLElement>('.fw-combobox-option');\n items.forEach((el) => {\n el.classList.remove('is-active');\n el.setAttribute('aria-selected', 'false');\n });\n const el = items[i];\n if (el) {\n el.classList.add('is-active');\n el.setAttribute('aria-selected', 'true');\n el.scrollIntoView({ block: 'nearest' });\n input.setAttribute('aria-activedescendant', el.id);\n }\n activeIndex = i;\n }\n\n function select(value: string): void {\n input.value = value;\n close();\n // The synthetic events below would re-open the list via onInput/onFocus.\n selecting = true;\n input.focus();\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n selecting = false;\n opts.onSelect?.(value);\n }\n\n const onInput = () => {\n if (!selecting) open();\n };\n const onFocus = () => {\n if (!selecting) open();\n };\n const onKeydown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n if (!list.classList.contains('is-open')) open();\n highlight(Math.min(activeIndex + 1, current.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n highlight(Math.max(activeIndex - 1, 0));\n } else if (e.key === 'Enter') {\n if (activeIndex > -1 && current[activeIndex] !== undefined) {\n e.preventDefault();\n select(current[activeIndex]);\n }\n } else if (e.key === 'Escape') {\n close();\n }\n };\n const onListMousedown = (e: MouseEvent) => {\n const opt = (e.target as HTMLElement).closest<HTMLElement>('.fw-combobox-option');\n if (opt) {\n e.preventDefault(); // keep focus on the input\n select(current[Number(opt.dataset.index)]);\n }\n };\n const onDocClick = (e: MouseEvent) => {\n if (!wrap.contains(e.target as Node)) close();\n };\n\n input.addEventListener('input', onInput);\n input.addEventListener('focus', onFocus);\n input.addEventListener('keydown', onKeydown);\n list.addEventListener('mousedown', onListMousedown);\n document.addEventListener('click', onDocClick);\n\n return {\n open,\n close,\n setOptions(next) {\n options = next;\n if (list.classList.contains('is-open')) open();\n },\n destroy() {\n input.removeEventListener('input', onInput);\n input.removeEventListener('focus', onFocus);\n input.removeEventListener('keydown', onKeydown);\n list.removeEventListener('mousedown', onListMousedown);\n document.removeEventListener('click', onDocClick);\n list.remove();\n if (input.dataset.fwList) input.setAttribute('list', input.dataset.fwList);\n delete input.dataset.fwBound;\n },\n };\n}\n\nfunction readDatalist(input: HTMLInputElement): string[] {\n const id = input.getAttribute('list') ?? input.dataset.fwList;\n const dl = id ? document.getElementById(id) : null;\n return dl ? Array.from(dl.querySelectorAll('option')).map((o) => o.value || o.textContent || '') : [];\n}\n\nfunction wrapInput(input: HTMLInputElement): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'fw-combobox';\n input.parentNode?.insertBefore(wrap, input);\n wrap.appendChild(input);\n return wrap;\n}\n\n/** Enhance every `[data-fw-combobox]` input under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLInputElement>('input[data-fw-combobox]').forEach((input) => {\n if (input.dataset.fwBound) return;\n input.dataset.fwBound = '1';\n combobox(input);\n });\n}\n", "/**\n * Modal & drawer overlays.\n *\n * <button data-fw-open-modal=\"confirm\">\u2026</button>\n * <div class=\"fw-modal-overlay\" id=\"confirm\" role=\"dialog\" aria-modal=\"true\"><div class=\"fw-modal\">\u2026 <button data-fw-close-modal>Cancel</button></div></div>\n *\n * <button data-fw-open-drawer=\"details\">\u2026</button>\n * <div class=\"fw-drawer-overlay\" data-fw-drawer-overlay=\"details\"></div>\n * <aside class=\"fw-drawer\" id=\"details\" role=\"dialog\" aria-modal=\"true\">\u2026 <button data-fw-close-drawer>\u00D7</button></aside>\n *\n * Closes on backdrop click (guarded \u2014 a text-selection drag that ends on the\n * backdrop does NOT close it), on Escape, and returns focus to the opener.\n */\nconst OPEN = 'is-open';\nconst LOCK = 'fw-scroll-lock';\nconst openStack: HTMLElement[] = [];\nconst openers = new WeakMap<HTMLElement, HTMLElement | null>();\n\nconst FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction resolve(target: string | HTMLElement): HTMLElement | null {\n return typeof target === 'string' ? document.getElementById(target) : target;\n}\n\n/** The backdrop element paired with a drawer (via `data-fw-drawer-overlay=\"<id>\"`), if any. */\nfunction backdropFor(el: HTMLElement): HTMLElement | null {\n if (el.classList.contains('fw-modal-overlay')) return el;\n const explicit = el.id ? document.querySelector<HTMLElement>(`[data-fw-drawer-overlay=\"${el.id}\"]`) : null;\n if (explicit) return explicit;\n const prev = el.previousElementSibling;\n return prev instanceof HTMLElement && prev.classList.contains('fw-drawer-overlay') ? prev : null;\n}\n\nexport function open(target: string | HTMLElement, opener: HTMLElement | null = (document.activeElement as HTMLElement) ?? null): void {\n const el = resolve(target);\n if (!el || el.classList.contains(OPEN)) return;\n el.classList.add(OPEN);\n backdropFor(el)?.classList.add(OPEN);\n openers.set(el, opener);\n openStack.push(el);\n document.body.classList.add(LOCK);\n el.dispatchEvent(new CustomEvent('fw:open', { bubbles: true }));\n // Focus the first control inside; fall back to the panel itself.\n const first = el.querySelector<HTMLElement>(FOCUSABLE);\n if (first) first.focus({ preventScroll: true });\n else {\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n el.focus({ preventScroll: true });\n }\n}\n\nexport function close(target: string | HTMLElement): void {\n const el = resolve(target);\n if (!el || !el.classList.contains(OPEN)) return;\n el.classList.remove(OPEN);\n backdropFor(el)?.classList.remove(OPEN);\n const i = openStack.indexOf(el);\n if (i > -1) openStack.splice(i, 1);\n if (openStack.length === 0) document.body.classList.remove(LOCK);\n el.dispatchEvent(new CustomEvent('fw:close', { bubbles: true }));\n openers.get(el)?.focus?.({ preventScroll: true });\n openers.delete(el);\n}\n\nexport function toggle(target: string | HTMLElement): void {\n const el = resolve(target);\n if (el) (el.classList.contains(OPEN) ? close : open)(el);\n}\n\n/**\n * Click-outside-to-close, guarded against a classic false positive: a\n * browser's `click` fires on the nearest common ancestor of mousedown and\n * mouseup. A drag that starts inside the panel and ends on the backdrop has\n * the overlay as that ancestor, so a naive `e.target === overlay` check would\n * close the modal mid-selection. Close only when BOTH landed on the backdrop.\n */\nexport function bindOutsideClickToClose(backdrop: HTMLElement, onClose: () => void): void {\n let downOnBackdrop = false;\n backdrop.addEventListener('mousedown', (e) => {\n downOnBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && downOnBackdrop) onClose();\n });\n}\n\nlet keyBound = false;\n\n/** Wire every trigger, overlay and close button under `root`. */\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-open-modal], [data-fw-open-drawer]').forEach((btn) => {\n if (btn.dataset.fwBound) return;\n btn.dataset.fwBound = '1';\n const id = btn.dataset.fwOpenModal ?? btn.dataset.fwOpenDrawer ?? '';\n btn.addEventListener('click', () => open(id, btn));\n });\n\n root.querySelectorAll<HTMLElement>('.fw-modal-overlay').forEach((overlay) => {\n if (overlay.dataset.fwBound) return;\n overlay.dataset.fwBound = '1';\n bindOutsideClickToClose(overlay, () => close(overlay));\n overlay.querySelectorAll<HTMLElement>('[data-fw-close-modal]').forEach((btn) =>\n btn.addEventListener('click', () => close(overlay)),\n );\n });\n\n root.querySelectorAll<HTMLElement>('.fw-drawer').forEach((drawer) => {\n if (drawer.dataset.fwBound) return;\n drawer.dataset.fwBound = '1';\n const backdrop = backdropFor(drawer);\n if (backdrop) bindOutsideClickToClose(backdrop, () => close(drawer));\n drawer.querySelectorAll<HTMLElement>('[data-fw-close-drawer]').forEach((btn) =>\n btn.addEventListener('click', () => close(drawer)),\n );\n });\n\n if (!keyBound) {\n keyBound = true;\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && openStack.length) close(openStack[openStack.length - 1]);\n });\n }\n}\n", "/**\n * Nav dropdown \u2014 the hamburger toggle in `.fw-nav` (and any other\n * button-controls-panel pair).\n *\n * <button data-fw-nav-toggle aria-controls=\"menu\" aria-expanded=\"false\">\u2026</button>\n * <div class=\"fw-nav-dropdown\" id=\"menu\">\u2026</div>\n *\n * Closes on outside click and Escape.\n */\nconst OPEN = 'is-open';\n\nexport function open(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.add(OPEN);\n toggle.setAttribute('aria-expanded', 'true');\n}\n\nexport function close(toggle: HTMLElement): void {\n const panel = panelFor(toggle);\n if (!panel) return;\n panel.classList.remove(OPEN);\n toggle.setAttribute('aria-expanded', 'false');\n}\n\nfunction panelFor(toggle: HTMLElement): HTMLElement | null {\n const id = toggle.getAttribute('aria-controls');\n return id ? document.getElementById(id) : null;\n}\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-nav-toggle]').forEach((toggle) => {\n if (toggle.dataset.fwBound) return;\n toggle.dataset.fwBound = '1';\n const panel = panelFor(toggle);\n if (!panel) return;\n const container = toggle.closest<HTMLElement>('.fw-nav') ?? toggle.parentElement ?? toggle;\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n (panel.classList.contains(OPEN) ? close : open)(toggle);\n });\n document.addEventListener('click', (e) => {\n if (!container.contains(e.target as Node) && !panel.contains(e.target as Node)) close(toggle);\n });\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') close(toggle);\n });\n });\n}\n", "/**\n * Loading states.\n *\n * loading.setButtonLoading(btn, 'Sending\u2026'); // disables, swaps in a spinner\n * loading.resetButtonLoading(btn); // restores original markup\n *\n * Or declaratively: any <form data-fw-loading> puts its submit button into the\n * loading state on submit (label from `data-fw-loading-text` on the button).\n */\nconst LOADING = 'fw-btn-loading';\n\nexport function setButtonLoading(btn: HTMLButtonElement | null, loadingText?: string): void {\n if (!btn || btn.classList.contains(LOADING)) return;\n btn.dataset.fwOriginalHtml = btn.innerHTML;\n btn.disabled = true;\n btn.setAttribute('aria-busy', 'true');\n btn.classList.add(LOADING);\n const label = loadingText ?? btn.dataset.fwLoadingText ?? btn.textContent ?? '';\n btn.innerHTML = '<span class=\"fw-spinner fw-spinner-sm\" aria-hidden=\"true\"></span>';\n btn.appendChild(document.createTextNode(label));\n}\n\nexport function resetButtonLoading(btn: HTMLButtonElement | null): void {\n if (!btn || !btn.classList.contains(LOADING)) return;\n btn.disabled = false;\n btn.removeAttribute('aria-busy');\n btn.classList.remove(LOADING);\n // Restore markup, not just text, so buttons with an icon keep it.\n if (btn.dataset.fwOriginalHtml !== undefined) {\n btn.innerHTML = btn.dataset.fwOriginalHtml;\n delete btn.dataset.fwOriginalHtml;\n }\n}\n\n/** Reset every loading button \u2014 e.g. after a bfcache restore. */\nexport function resetAll(root: ParentNode = document): void {\n root.querySelectorAll<HTMLButtonElement>(`.${LOADING}`).forEach(resetButtonLoading);\n}\n\nlet pageshowBound = false;\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLFormElement>('form[data-fw-loading]').forEach((form) => {\n if (form.dataset.fwBound) return;\n form.dataset.fwBound = '1';\n form.addEventListener('submit', () => {\n const btn = form.querySelector<HTMLButtonElement>('button[type=\"submit\"], button:not([type])');\n setButtonLoading(btn);\n });\n });\n\n // Browsers restore pages from the back-forward cache without re-running JS,\n // so a spinner painted right before navigating away would come back stuck.\n if (!pageshowBound) {\n pageshowBound = true;\n window.addEventListener('pageshow', (e) => {\n if (e.persisted) resetAll();\n });\n }\n}\n", "/**\n * Toast \u2014 a single, reused, bottom-right notice.\n *\n * toast.show('Invoice sent');\n * toast.show('That card was declined', { variant: 'error', duration: 6000 });\n */\nexport type ToastVariant = 'success' | 'error' | 'info' | 'pending';\n\nexport interface ToastOptions {\n variant?: ToastVariant;\n /** ms before it hides; 0 keeps it until `hide()` or the next `show()`. */\n duration?: number;\n}\n\nlet el: HTMLElement | null = null;\nlet timer: ReturnType<typeof setTimeout> | null = null;\n\nfunction ensure(): HTMLElement {\n if (el && el.isConnected) return el;\n el = document.createElement('div');\n el.className = 'fw-toast';\n el.setAttribute('role', 'status');\n el.setAttribute('aria-live', 'polite');\n el.innerHTML = '<span class=\"fw-toast-dot\" aria-hidden=\"true\"></span><span class=\"fw-toast-text\"></span>';\n document.body.appendChild(el);\n return el;\n}\n\nexport function show(message: string, { variant = 'success', duration = 4000 }: ToastOptions = {}): HTMLElement {\n const node = ensure();\n node.className = `fw-toast${variant === 'success' ? '' : ` fw-toast-${variant}`}`;\n (node.querySelector('.fw-toast-text') as HTMLElement).textContent = message;\n if (timer) clearTimeout(timer);\n // Re-trigger the transition even if it's already showing.\n node.classList.remove('is-show');\n void node.offsetWidth;\n node.classList.add('is-show');\n if (duration > 0) timer = setTimeout(hide, duration);\n return node;\n}\n\nexport function hide(): void {\n el?.classList.remove('is-show');\n if (timer) clearTimeout(timer);\n timer = null;\n}\n", "/**\n * Table \u2014 client-side column sorting and row selection for `.fw-table`.\n *\n * <table class=\"fw-table\" data-fw-table>\n * <thead><tr>\n * <th class=\"fw-table-select\"><label class=\"fw-checkbox\"><input type=\"checkbox\" data-fw-select-all>\u2026</label></th>\n * <th scope=\"col\" aria-sort=\"none\" data-fw-sort><button type=\"button\" class=\"fw-table-sort\">Client</button></th>\n * </tr></thead>\n * <tbody><tr>\n * <td class=\"fw-table-select\"><label class=\"fw-checkbox\"><input type=\"checkbox\" data-fw-select-row>\u2026</label></td>\n * <td data-fw-sort-value=\"1250\">$1,250.00</td>\n * </tr></tbody>\n * </table>\n *\n * Clicking a `th[data-fw-sort]` cycles aria-sort (none \u2192 ascending \u2192 descending \u2192 \u2026)\n * and reorders the first <tbody>. `data-fw-sort-value` on a cell overrides its\n * text for comparison (numbers, ISO dates). Rows without a cell in the sorted\n * column (e.g. a colspan empty row) stay at the bottom.\n *\n * Row checkboxes toggle `.is-selected` / aria-selected on their row and keep the\n * select-all checkbox in sync (checked / indeterminate).\n *\n * Events (bubbling, on the <table>): `fw:sort` { column, direction, th } and\n * `fw:select` { rows, all }.\n */\nexport type SortDirection = 'ascending' | 'descending';\n\nexport interface SortDetail {\n column: number;\n direction: SortDirection;\n th: HTMLTableCellElement;\n}\n\nexport interface SelectDetail {\n rows: HTMLTableRowElement[];\n all: boolean;\n}\n\nconst SELECTED = 'is-selected';\n\nfunction emit(table: HTMLTableElement, name: string, detail: SortDetail | SelectDetail): void {\n table.dispatchEvent(new CustomEvent(name, { bubbles: true, detail }));\n}\n\n/* ---- sorting ---- */\n\nfunction cellValue(row: HTMLTableRowElement, column: number): string {\n const cell = row.cells[column];\n return cell?.dataset.fwSortValue ?? cell?.textContent?.trim() ?? '';\n}\n\nfunction compare(a: string, b: string): number {\n const na = Number(a);\n const nb = Number(b);\n if (a !== '' && b !== '' && Number.isFinite(na) && Number.isFinite(nb)) return na - nb;\n return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });\n}\n\nfunction sortHeaders(table: HTMLTableElement): HTMLTableCellElement[] {\n return Array.from(table.tHead?.querySelectorAll<HTMLTableCellElement>('th[data-fw-sort]') ?? []);\n}\n\nfunction nextDirection(th: HTMLTableCellElement): SortDirection {\n return th.getAttribute('aria-sort') === 'ascending' ? 'descending' : 'ascending';\n}\n\nexport function sort(table: HTMLTableElement, column: number, direction: SortDirection): void {\n const tbody = table.tBodies[0];\n if (!tbody) return;\n\n const rows = Array.from(tbody.rows);\n // A colspan row (empty / loading) has no cell at `column` \u2014 keep it last.\n const sortable = rows.filter((r) => r.cells.length > column);\n const rest = rows.filter((r) => r.cells.length <= column);\n const sign = direction === 'ascending' ? 1 : -1;\n sortable.sort((a, b) => sign * compare(cellValue(a, column), cellValue(b, column)));\n [...sortable, ...rest].forEach((r) => tbody.appendChild(r));\n\n let active: HTMLTableCellElement | null = null;\n sortHeaders(table).forEach((th) => {\n const isTarget = th.cellIndex === column;\n th.setAttribute('aria-sort', isTarget ? direction : 'none');\n if (isTarget) active = th;\n });\n if (active) emit(table, 'fw:sort', { column, direction, th: active });\n}\n\n/* ---- selection ---- */\n\nfunction rowInputs(table: HTMLTableElement): HTMLInputElement[] {\n return Array.from(table.querySelectorAll<HTMLInputElement>('tbody input[data-fw-select-row]'));\n}\n\nfunction applyRowState(row: HTMLTableRowElement, on: boolean): void {\n row.classList.toggle(SELECTED, on);\n row.setAttribute('aria-selected', on ? 'true' : 'false');\n}\n\nfunction syncSelectAll(table: HTMLTableElement): void {\n const all = table.querySelector<HTMLInputElement>('[data-fw-select-all]');\n if (!all) return;\n const inputs = rowInputs(table);\n const n = inputs.filter((i) => i.checked).length;\n all.checked = n > 0 && n === inputs.length;\n all.indeterminate = n > 0 && n < inputs.length;\n}\n\nexport function getSelected(table: HTMLTableElement): HTMLTableRowElement[] {\n return rowInputs(table)\n .filter((i) => i.checked)\n .map((i) => i.closest('tr'))\n .filter((r): r is HTMLTableRowElement => r !== null);\n}\n\nexport function setRowSelected(row: HTMLTableRowElement, on: boolean): void {\n const input = row.querySelector<HTMLInputElement>('input[data-fw-select-row]');\n if (input) input.checked = on;\n applyRowState(row, on);\n const table = row.closest('table');\n if (!table) return;\n syncSelectAll(table);\n emit(table, 'fw:select', { rows: getSelected(table), all: false });\n}\n\nexport function selectAll(table: HTMLTableElement, on: boolean): void {\n rowInputs(table).forEach((input) => {\n input.checked = on;\n const row = input.closest('tr');\n if (row) applyRowState(row, on);\n });\n syncSelectAll(table);\n emit(table, 'fw:select', { rows: getSelected(table), all: true });\n}\n\n/* ---- init ---- */\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLTableElement>('table[data-fw-table]').forEach((table) => {\n if (table.dataset.fwBound) return;\n table.dataset.fwBound = '1';\n\n sortHeaders(table).forEach((th) => {\n if (!th.hasAttribute('aria-sort')) th.setAttribute('aria-sort', 'none');\n });\n\n table.addEventListener('click', (e) => {\n const th = (e.target as Element).closest<HTMLTableCellElement>('th[data-fw-sort]');\n if (th && table.contains(th)) sort(table, th.cellIndex, nextDirection(th));\n });\n\n // Enter / Space on the sort button (or on a tabindex'd <th> without one).\n // preventDefault stops the button's native activation so it can't sort twice.\n table.addEventListener('keydown', (e) => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n const target = e.target as Element;\n if (!target.matches('th[data-fw-sort], th[data-fw-sort] .fw-table-sort')) return;\n const th = target.closest<HTMLTableCellElement>('th[data-fw-sort]');\n if (!th) return;\n e.preventDefault();\n sort(table, th.cellIndex, nextDirection(th));\n });\n\n table.addEventListener('change', (e) => {\n const input = e.target as HTMLInputElement;\n if (input.matches('[data-fw-select-all]')) {\n selectAll(table, input.checked);\n } else if (input.matches('[data-fw-select-row]')) {\n const row = input.closest('tr');\n if (row) setRowSelected(row, input.checked);\n }\n });\n\n // Honour server-rendered checked state.\n rowInputs(table).forEach((input) => {\n const row = input.closest('tr');\n if (row && input.checked) applyRowState(row, true);\n });\n syncSelectAll(table);\n });\n}\n", "/**\n * Menu \u2014 a nestable collapsible menu (nav tree or accordion) built on\n * native <details>/<summary>, enhanced for `.fw-menu[data-fw-menu]`.\n *\n * <nav class=\"fw-menu\" aria-label=\"Docs\" data-fw-menu>\n * <ul class=\"fw-menu-list\">\n * <li class=\"fw-menu-item\"><a class=\"fw-menu-link\" href=\"/\" aria-current=\"page\">Overview</a></li>\n * <li class=\"fw-menu-item\">\n * <details class=\"fw-menu-group\">\n * <summary class=\"fw-menu-summary\">Billing</summary>\n * <ul class=\"fw-menu-list\">\n * <li class=\"fw-menu-item fw-menu-split\">\n * <a class=\"fw-menu-link\" href=\"/billing/plans\">Plans</a>\n * <details class=\"fw-menu-group\">\n * <summary class=\"fw-menu-summary fw-menu-summary-icon\"><span class=\"fw-sr-only\">Toggle Plans</span></summary>\n * <ul class=\"fw-menu-list\">\u2026</ul>\n * </details>\n * </li>\n * </ul>\n * </details>\n * </li>\n * </ul>\n * </nav>\n *\n * The `open` attribute on each `.fw-menu-group` is the state \u2014 server-rendered\n * state is honoured, and the menu still expands/collapses without JS.\n *\n * The enhancer adds:\n * - auto-reveal: every ancestor group of an `[aria-current]` link is opened on\n * init, and a collapsed summary whose branch holds the current page gets `.is-current`\n * - `data-fw-menu-exclusive`: opening a group closes its siblings (accordion)\n * - keyboard: ArrowUp/ArrowDown move between visible rows, ArrowRight opens /\n * enters a group, ArrowLeft closes / goes to the parent, Home/End jump.\n * Tab order is untouched \u2014 every row stays natively tabbable.\n *\n * Events (bubbling, from the <details>): `fw:toggle` { group, open }.\n */\nexport interface ToggleDetail {\n group: HTMLDetailsElement;\n open: boolean;\n}\n\nconst GROUP = '.fw-menu-group';\nconst ROW = '.fw-menu-link, .fw-menu-summary';\nconst CURRENT = 'is-current';\n\nfunction emit(group: HTMLDetailsElement, detail: ToggleDetail): void {\n group.dispatchEvent(new CustomEvent('fw:toggle', { bubbles: true, detail }));\n}\n\n/* ---- open / close ---- */\n\nexport function open(group: HTMLDetailsElement): void {\n group.open = true;\n}\n\nexport function close(group: HTMLDetailsElement): void {\n group.open = false;\n}\n\nexport function toggle(group: HTMLDetailsElement, force?: boolean): void {\n group.open = force ?? !group.open;\n}\n\nexport function expandAll(root: ParentNode): void {\n root.querySelectorAll<HTMLDetailsElement>(GROUP).forEach(open);\n}\n\nexport function collapseAll(root: ParentNode): void {\n root.querySelectorAll<HTMLDetailsElement>(GROUP).forEach(close);\n}\n\n/** Open every ancestor group of `el` so it is visible. */\nexport function reveal(el: Element): void {\n let group = el.parentElement?.closest<HTMLDetailsElement>(GROUP) ?? null;\n while (group) {\n open(group);\n group = group.parentElement?.closest<HTMLDetailsElement>(GROUP) ?? null;\n }\n}\n\n/* ---- current-page hinting ---- */\n\nfunction syncCurrent(menu: HTMLElement): void {\n menu.querySelectorAll<HTMLDetailsElement>(GROUP).forEach((group) => {\n const summary = group.querySelector<HTMLElement>(':scope > .fw-menu-summary');\n if (!summary) return;\n const holdsCurrent = !group.open && group.querySelector('[aria-current]') !== null;\n summary.classList.toggle(CURRENT, holdsCurrent);\n });\n}\n\n/* ---- keyboard ---- */\n\n/** The group this row summarises (a summary), or null for a link. */\nfunction ownGroup(row: HTMLElement): HTMLDetailsElement | null {\n return row.matches('.fw-menu-summary') ? row.closest<HTMLDetailsElement>(GROUP) : null;\n}\n\n/** The group that contains this row (not the one it summarises). */\nfunction parentGroup(row: HTMLElement): HTMLDetailsElement | null {\n const start = ownGroup(row) ?? row;\n return start.parentElement?.closest<HTMLDetailsElement>(GROUP) ?? null;\n}\n\nfunction isVisible(row: HTMLElement): boolean {\n for (let g = parentGroup(row); g; g = g.parentElement?.closest<HTMLDetailsElement>(GROUP) ?? null) {\n if (!g.open) return false;\n }\n return true;\n}\n\nfunction visibleRows(menu: HTMLElement): HTMLElement[] {\n return Array.from(menu.querySelectorAll<HTMLElement>(ROW)).filter(isVisible);\n}\n\nfunction focusRow(row: HTMLElement | null | undefined): boolean {\n if (!row) return false;\n row.focus();\n return true;\n}\n\n/** The icon-only summary sitting beside a split-row link, if any. */\nfunction splitToggleFor(link: HTMLElement): HTMLElement | null {\n const item = link.closest<HTMLElement>('.fw-menu-split');\n return item?.querySelector<HTMLElement>(':scope > .fw-menu-group > .fw-menu-summary') ?? null;\n}\n\nfunction onKeydown(menu: HTMLElement, e: KeyboardEvent): void {\n if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;\n const row = e.target instanceof HTMLElement && e.target.matches(ROW) ? e.target : null;\n if (!row || !menu.contains(row)) return;\n\n const rows = visibleRows(menu);\n const i = rows.indexOf(row);\n const group = ownGroup(row);\n let handled = true;\n\n switch (e.key) {\n case 'ArrowDown':\n focusRow(rows[i + 1]);\n break;\n case 'ArrowUp':\n focusRow(rows[i - 1]);\n break;\n case 'Home':\n focusRow(rows[0]);\n break;\n case 'End':\n focusRow(rows[rows.length - 1]);\n break;\n case 'ArrowRight':\n if (group) {\n // An open group's first row is simply the next visible one.\n if (!group.open) open(group);\n else if (group.contains(rows[i + 1] ?? menu)) focusRow(rows[i + 1]);\n } else {\n focusRow(splitToggleFor(row));\n }\n break;\n case 'ArrowLeft':\n if (group?.open) {\n close(group);\n } else {\n const parent = parentGroup(row);\n focusRow(parent?.querySelector<HTMLElement>(':scope > .fw-menu-summary'));\n }\n break;\n default:\n handled = false;\n }\n if (handled) e.preventDefault();\n}\n\n/* ---- init ---- */\n\nexport function init(root: ParentNode = document): void {\n root.querySelectorAll<HTMLElement>('[data-fw-menu]').forEach((menu) => {\n if (menu.dataset.fwBound) return;\n menu.dataset.fwBound = '1';\n const exclusive = menu.hasAttribute('data-fw-menu-exclusive');\n\n // Native `toggle` doesn't bubble \u2014 catch it in the capture phase.\n menu.addEventListener(\n 'toggle',\n (e) => {\n const group = e.target;\n if (!(group instanceof HTMLDetailsElement) || !group.matches(GROUP)) return;\n if (exclusive && group.open && group.parentElement) {\n Array.from(group.parentElement.children).forEach((sibling) => {\n if (sibling !== group && sibling instanceof HTMLDetailsElement && sibling.matches(GROUP)) close(sibling);\n });\n }\n syncCurrent(menu);\n emit(group, { group, open: group.open });\n },\n true,\n );\n\n menu.addEventListener('keydown', (e) => onKeydown(menu, e));\n\n // Honour server-rendered state: make the current page visible on load.\n menu.querySelectorAll('[aria-current]').forEach(reveal);\n syncCurrent(menu);\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["index_exports", "__export", "combobox_exports", "index_default", "init", "loading_exports", "menu_exports", "modal_exports", "nav_exports", "table_exports", "theme_exports", "toast_exports", "version", "__toCommonJS", "theme_exports", "__export", "get", "getToken", "init", "resetTokens", "set", "setTokens", "toggle", "STORAGE_KEY", "EVENT", "TOKEN_PREFIX", "TOKEN_STYLE_ATTR", "store", "_a", "attr", "theme", "persist", "btn", "syncToggle", "next", "label", "root", "_b", "_c", "_d", "stored", "current", "e", "tokenScopes", "normalizeTokenName", "name", "isThemeSplit", "tokens", "v", "declBlock", "value", "tokenStyleEl", "create", "existing", "el", "renderTokens", "rules", "light", "dark", "scope", "darkSelector", "opts", "entry", "combobox_exports", "__export", "combobox", "init", "uid", "escapeHtml", "s", "c", "input", "opts", "_a", "_b", "_c", "_d", "filter", "o", "q", "emptyText", "options", "readDatalist", "current", "activeIndex", "selecting", "listId", "wrap", "wrapInput", "list", "id", "render", "matches", "opt", "i", "idx", "label", "open", "close", "highlight", "items", "el", "select", "value", "onInput", "onFocus", "onKeydown", "e", "onListMousedown", "onDocClick", "next", "dl", "root", "modal_exports", "__export", "bindOutsideClickToClose", "close", "init", "open", "toggle", "OPEN", "LOCK", "openStack", "openers", "FOCUSABLE", "resolve", "target", "backdropFor", "el", "explicit", "prev", "opener", "_a", "first", "_b", "_c", "i", "backdrop", "onClose", "downOnBackdrop", "e", "keyBound", "root", "btn", "id", "overlay", "drawer", "nav_exports", "__export", "close", "init", "open", "OPEN", "toggle", "panel", "panelFor", "id", "root", "_a", "_b", "container", "e", "loading_exports", "__export", "init", "resetAll", "resetButtonLoading", "setButtonLoading", "LOADING", "btn", "loadingText", "_a", "_b", "label", "root", "pageshowBound", "form", "e", "toast_exports", "__export", "hide", "show", "el", "timer", "ensure", "message", "variant", "duration", "node", "table_exports", "__export", "getSelected", "init", "selectAll", "setRowSelected", "sort", "SELECTED", "emit", "table", "name", "detail", "cellValue", "row", "column", "_a", "_b", "_c", "cell", "compare", "a", "b", "na", "nb", "sortHeaders", "nextDirection", "th", "direction", "tbody", "rows", "sortable", "r", "rest", "sign", "active", "isTarget", "rowInputs", "applyRowState", "on", "syncSelectAll", "all", "inputs", "n", "i", "input", "root", "e", "target", "menu_exports", "__export", "close", "collapseAll", "expandAll", "init", "open", "reveal", "toggle", "GROUP", "ROW", "CURRENT", "emit", "group", "detail", "force", "root", "el", "_a", "_b", "_c", "_d", "syncCurrent", "menu", "summary", "holdsCurrent", "ownGroup", "row", "parentGroup", "isVisible", "g", "visibleRows", "focusRow", "splitToggleFor", "link", "item", "onKeydown", "e", "rows", "i", "handled", "parent", "exclusive", "sibling", "version", "init", "root", "Fernwell", "theme_exports", "combobox_exports", "modal_exports", "nav_exports", "loading_exports", "toast_exports", "table_exports", "menu_exports", "index_default"]
7
7
  }