vintage-frames 0.14.0 → 0.14.1

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.
Files changed (46) hide show
  1. package/README.md +16 -0
  2. package/custom-elements.json +177 -13
  3. package/dist/components/vf-container.d.ts +3 -1
  4. package/dist/components/vf-container.js +34 -16
  5. package/dist/components/vf-desktop.d.ts +114 -12
  6. package/dist/components/vf-desktop.js +119 -58
  7. package/dist/components/vf-icon-field.d.ts +1 -1
  8. package/dist/components/vf-icon.js +68 -61
  9. package/dist/components/vf-menu-bar.d.ts +5 -0
  10. package/dist/components/vf-menu-bar.js +67 -43
  11. package/dist/components/vf-window.d.ts +13 -0
  12. package/dist/components/vf-window.js +10 -1
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +44 -43
  15. package/dist/pattern-fill.d.ts +11 -8
  16. package/dist/pattern-fill.js +2 -4
  17. package/dist/position.d.ts +25 -7
  18. package/dist/position.js +6 -3
  19. package/dist/shell/alert.d.ts +32 -0
  20. package/dist/shell/alert.js +44 -0
  21. package/dist/shell/catalog.d.ts +168 -0
  22. package/dist/shell/catalog.js +278 -0
  23. package/dist/shell/clock.d.ts +16 -0
  24. package/dist/shell/clock.js +36 -0
  25. package/dist/shell/filing.d.ts +39 -0
  26. package/dist/shell/filing.js +68 -0
  27. package/dist/shell/finder.d.ts +116 -0
  28. package/dist/shell/finder.js +564 -0
  29. package/dist/shell/geometry.d.ts +196 -0
  30. package/dist/shell/geometry.js +241 -0
  31. package/dist/shell/index.d.ts +29 -0
  32. package/dist/shell/index.js +11 -0
  33. package/dist/shell/shell.d.ts +150 -0
  34. package/dist/shell/shell.js +213 -0
  35. package/dist/shell/state.d.ts +88 -0
  36. package/dist/shell/state.js +103 -0
  37. package/dist/shell/storage.d.ts +14 -0
  38. package/dist/shell/storage.js +41 -0
  39. package/dist/shell/windows.d.ts +215 -0
  40. package/dist/shell/windows.js +343 -0
  41. package/dist/window-chrome.d.ts +43 -0
  42. package/dist/window-chrome.js +13 -0
  43. package/docs/SPEC.md +12 -11
  44. package/editor/vscode.html-custom-data.json +9 -4
  45. package/editor/web-types.json +45 -9
  46. package/package.json +10 -2
package/dist/index.js CHANGED
@@ -31,46 +31,47 @@ import { VfDesktop as He } from "./components/vf-desktop.js";
31
31
  import { VfSized as Ue } from "./size.js";
32
32
  import { DragController as We } from "./drag.js";
33
33
  import { BLINK_FLIPS as Ge, BLINK_INTERVAL_MS as Ke, DRAG_SLOP_COARSE_PX as qe, DRAG_SLOP_PX as Je, PRESS_HOLD_MS as Ye, RENAME_DELAY_MS as Xe, TAP_PAIR_MS as Ze, TAP_PAIR_SLOP_PX as Qe, WALK_BEAT_MS as $e, WALK_STEP_MS as et, WALK_STEP_PX as tt, WINDOW_RECTS_VISIBLE as nt, WINDOW_RECT_RATIO as rt, WINDOW_RECT_STEPS as it, WINDOW_RECT_STEP_MS as at, dragSlop as ot, prefersReducedMotion as st, runOutlineTravel as ct, runSelectionBlink as lt, windowRectFraction as ut } from "./motion.js";
34
- import { ScrollStateController as dt } from "./scroll-state.js";
35
- import { CARET_DOWN as ft, CARET_DOWN_SMALL as pt, CHECKBOX_X as mt, CHECKMARK as ht, RADIO_DOT as gt, RADIO_FACE as _t, RADIO_RING as vt, RADIO_RING_PRESSED as yt, SLIDER_THUMB as bt, SLIDER_THUMB_FACE as xt, STEPPER as St, STEPPER_DOWN_FILL as Ct, STEPPER_UP_FILL as wt, glyphSvg as Tt } from "./glyphs.js";
36
- import { ScrollRailController as Et, renderScrollRail as Dt } from "./scroll-rail.js";
37
- import { VfScrollArea as Ot } from "./components/vf-scroll-area.js";
38
- import { VfWindow as kt } from "./components/vf-window.js";
39
- import { VfModalDialog as At, modalDialogStyles as jt } from "./modal-dialog.js";
40
- import { VfDialog as Mt } from "./components/vf-dialog.js";
41
- import { VfSeparator as Nt } from "./components/vf-separator.js";
42
- import { VfFormControl as Pt } from "./form-control.js";
43
- import { VfButton as Ft } from "./components/vf-button.js";
44
- import { VfButtonGroup as It } from "./components/vf-button-group.js";
45
- import { VfSwatch as Lt } from "./components/vf-swatch.js";
46
- import { VfToggleControl as Rt } from "./toggle-control.js";
47
- import { VfCheckbox as zt } from "./components/vf-checkbox.js";
48
- import { VfRadio as Bt } from "./components/vf-radio.js";
49
- import { VfRadioGroup as Vt } from "./components/vf-radio-group.js";
50
- import { FocusRuleController as Ht, focusModality as Ut, trackFocusModality as Wt } from "./focus-modality.js";
51
- import { VfTextControlBase as Gt } from "./text-control.js";
52
- import { VfTextField as Kt } from "./components/vf-text-field.js";
53
- import { VfTextArea as qt } from "./components/vf-text-area.js";
54
- import { VfNumberField as Jt } from "./components/vf-number-field.js";
55
- import { VfOption as Yt } from "./components/vf-option.js";
56
- import { VfSelect as Xt } from "./components/vf-select.js";
57
- import { TrackWidthController as Zt } from "./track-width.js";
58
- import { VfProgressBar as Qt } from "./components/vf-progress-bar.js";
59
- import { VfSlider as $t } from "./components/vf-slider.js";
60
- import { VfLabel as en } from "./components/vf-label.js";
61
- import { VfParagraph as tn } from "./components/vf-paragraph.js";
62
- import { VfImg as nn } from "./components/vf-img.js";
63
- import { VfIcon as rn } from "./components/vf-icon.js";
64
- import { VfIconField as an } from "./components/vf-icon-field.js";
65
- import { VfMenuBar as on } from "./components/vf-menu-bar.js";
66
- import { VfMenu as sn } from "./components/vf-menu.js";
67
- import { VfMenuItem as cn } from "./components/vf-menu-item.js";
68
- import { VfList as ln } from "./components/vf-list.js";
69
- import { VfListItem as un } from "./components/vf-list-item.js";
70
- import { VfFieldset as dn } from "./components/vf-fieldset.js";
71
- import { VfGrid as fn } from "./components/vf-grid.js";
72
- import { VfStack as pn } from "./components/vf-stack.js";
73
- import { VfContainer as mn } from "./components/vf-container.js";
74
- import { CURSOR_ARROW as hn, CURSOR_CROSSHAIR as gn, CURSOR_I_BEAM as _n, CURSOR_WAIT as vn } from "./cursor-art.js";
75
- import { applyCursor as yn } from "./cursor.js";
76
- export { Ge as BLINK_FLIPS, Ke as BLINK_INTERVAL_MS, Ne as BUTTON_FACE, Pe as BUTTON_FRAME, ft as CARET_DOWN, pt as CARET_DOWN_SMALL, mt as CHECKBOX_X, ht as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, hn as CURSOR_ARROW, gn as CURSOR_CROSSHAIR, _n as CURSOR_I_BEAM, vn as CURSOR_WAIT, qe as DRAG_SLOP_COARSE_PX, Je as DRAG_SLOP_PX, Me as DocumentListenersController, We as DragController, Ht as FocusRuleController, Ae as GridSnapController, $ as PATTERNS, ee as PATTERN_NAMES, te as PATTERN_SIZE, D as PIXEL_GRID_METRICS, Ye as PRESS_HOLD_MS, Oe as PatternFillController, T as PlacementController, gt as RADIO_DOT, _t as RADIO_FACE, vt as RADIO_RING, yt as RADIO_RING_PRESSED, Xe as RENAME_DELAY_MS, G as REPEAT_TILE, Fe as RING_FRAME, Ie as RING_HOLE, Le as RING_INSET, ge as RULE_EDGES, K as RepeatTileController, Re as SCREEN_CORNER, bt as SLIDER_THUMB, xt as SLIDER_THUMB_FACE, St as STEPPER, Ct as STEPPER_DOWN_FILL, wt as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, Et as ScrollRailController, dt as ScrollStateController, Ze as TAP_PAIR_MS, Qe as TAP_PAIR_SLOP_PX, R as TILE_LATTICE, Zt as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, Ft as VfButton, It as VfButtonGroup, zt as VfCheckbox, mn as VfContainer, He as VfDesktop, Mt as VfDialog, dn as VfFieldset, Pt as VfFormControl, fn as VfGrid, rn as VfIcon, an as VfIconField, nn as VfImg, en as VfLabel, ln as VfList, un as VfListItem, sn as VfMenu, on as VfMenuBar, cn as VfMenuItem, At as VfModalDialog, Jt as VfNumberField, Yt as VfOption, tn as VfParagraph, E as VfPositioned, Qt as VfProgressBar, Bt as VfRadio, Vt as VfRadioGroup, Ot as VfScrollArea, Xt as VfSelect, Nt as VfSeparator, Ue as VfSized, $t as VfSlider, pn as VfStack, Lt as VfSwatch, qt as VfTextArea, Gt as VfTextControlBase, Kt as VfTextField, Rt as VfToggleControl, kt as VfWindow, $e as WALK_BEAT_MS, et as WALK_STEP_MS, tt as WALK_STEP_PX, nt as WINDOW_RECTS_VISIBLE, rt as WINDOW_RECT_RATIO, it as WINDOW_RECT_STEPS, at as WINDOW_RECT_STEP_MS, yn as applyCursor, f as applyScale, t as defineElement, q as devicePxAt, o as devicePxPerSystemPx, ot as dragSlop, p as effectiveScale, e as emit, Ut as focusModality, m as getScale, s as getZoom, Tt as glyphSvg, jt as modalDialogStyles, h as onScaleChange, c as onZoomChange, ne as parsePattern, _e as parseRule, re as patternHex, ie as patternMotif, J as patternOverride, ae as patternRects, st as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, Dt as renderScrollRail, Y as repeatTile, je as requestGridSnap, l as resetZoomBaseline, ve as ruleClasses, ct as runOutlineTravel, lt as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, ze as steppedCornerClip, Be as steppedRectClip, Ve as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, X as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, Wt as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, pe as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, oe as vfDots, n as vfElement, Ee as vfField, Se as vfFocus, Ce as vfFocusRing, we as vfFocusUnderline, ce as vfHardShadow, le as vfHardShadowDecls, me as vfModalFrame, he as vfPanel, ke as vfPatternFill, Z as vfRepeatTileSize, ye as vfRule, De as vfScrollRail, L as vfStaticText, se as vfStripes, ue as vfStrokeDecls, de as vfStrokeInset, fe as vfStrokeShadow, Q as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, be as vfTitleBar, Te as vfToggle, xe as vfWindowWidgets, ut as windowRectFraction };
34
+ import { WINDOW_MIN_HEIGHT as dt, WINDOW_MIN_WIDTH as ft, windowChrome as pt } from "./window-chrome.js";
35
+ import { ScrollStateController as mt } from "./scroll-state.js";
36
+ import { CARET_DOWN as ht, CARET_DOWN_SMALL as gt, CHECKBOX_X as _t, CHECKMARK as vt, RADIO_DOT as yt, RADIO_FACE as bt, RADIO_RING as xt, RADIO_RING_PRESSED as St, SLIDER_THUMB as Ct, SLIDER_THUMB_FACE as wt, STEPPER as Tt, STEPPER_DOWN_FILL as Et, STEPPER_UP_FILL as Dt, glyphSvg as Ot } from "./glyphs.js";
37
+ import { ScrollRailController as kt, renderScrollRail as At } from "./scroll-rail.js";
38
+ import { VfScrollArea as jt } from "./components/vf-scroll-area.js";
39
+ import { VfWindow as Mt } from "./components/vf-window.js";
40
+ import { VfModalDialog as Nt, modalDialogStyles as Pt } from "./modal-dialog.js";
41
+ import { VfDialog as Ft } from "./components/vf-dialog.js";
42
+ import { VfSeparator as It } from "./components/vf-separator.js";
43
+ import { VfFormControl as Lt } from "./form-control.js";
44
+ import { VfButton as Rt } from "./components/vf-button.js";
45
+ import { VfButtonGroup as zt } from "./components/vf-button-group.js";
46
+ import { VfSwatch as Bt } from "./components/vf-swatch.js";
47
+ import { VfToggleControl as Vt } from "./toggle-control.js";
48
+ import { VfCheckbox as Ht } from "./components/vf-checkbox.js";
49
+ import { VfRadio as Ut } from "./components/vf-radio.js";
50
+ import { VfRadioGroup as Wt } from "./components/vf-radio-group.js";
51
+ import { FocusRuleController as Gt, focusModality as Kt, trackFocusModality as qt } from "./focus-modality.js";
52
+ import { VfTextControlBase as Jt } from "./text-control.js";
53
+ import { VfTextField as Yt } from "./components/vf-text-field.js";
54
+ import { VfTextArea as Xt } from "./components/vf-text-area.js";
55
+ import { VfNumberField as Zt } from "./components/vf-number-field.js";
56
+ import { VfOption as Qt } from "./components/vf-option.js";
57
+ import { VfSelect as $t } from "./components/vf-select.js";
58
+ import { TrackWidthController as en } from "./track-width.js";
59
+ import { VfProgressBar as tn } from "./components/vf-progress-bar.js";
60
+ import { VfSlider as nn } from "./components/vf-slider.js";
61
+ import { VfLabel as rn } from "./components/vf-label.js";
62
+ import { VfParagraph as an } from "./components/vf-paragraph.js";
63
+ import { VfImg as on } from "./components/vf-img.js";
64
+ import { VfIcon as sn } from "./components/vf-icon.js";
65
+ import { VfIconField as cn } from "./components/vf-icon-field.js";
66
+ import { VfMenuBar as ln } from "./components/vf-menu-bar.js";
67
+ import { VfMenu as un } from "./components/vf-menu.js";
68
+ import { VfMenuItem as dn } from "./components/vf-menu-item.js";
69
+ import { VfList as fn } from "./components/vf-list.js";
70
+ import { VfListItem as pn } from "./components/vf-list-item.js";
71
+ import { VfFieldset as mn } from "./components/vf-fieldset.js";
72
+ import { VfGrid as hn } from "./components/vf-grid.js";
73
+ import { VfStack as gn } from "./components/vf-stack.js";
74
+ import { VfContainer as _n } from "./components/vf-container.js";
75
+ import { CURSOR_ARROW as vn, CURSOR_CROSSHAIR as yn, CURSOR_I_BEAM as bn, CURSOR_WAIT as xn } from "./cursor-art.js";
76
+ import { applyCursor as Sn } from "./cursor.js";
77
+ export { Ge as BLINK_FLIPS, Ke as BLINK_INTERVAL_MS, Ne as BUTTON_FACE, Pe as BUTTON_FRAME, ht as CARET_DOWN, gt as CARET_DOWN_SMALL, _t as CHECKBOX_X, vt as CHECKMARK, r as CLASSIC_DPI, i as CSS_REFERENCE_DPI, vn as CURSOR_ARROW, yn as CURSOR_CROSSHAIR, bn as CURSOR_I_BEAM, xn as CURSOR_WAIT, qe as DRAG_SLOP_COARSE_PX, Je as DRAG_SLOP_PX, Me as DocumentListenersController, We as DragController, Gt as FocusRuleController, Ae as GridSnapController, $ as PATTERNS, ee as PATTERN_NAMES, te as PATTERN_SIZE, D as PIXEL_GRID_METRICS, Ye as PRESS_HOLD_MS, Oe as PatternFillController, T as PlacementController, yt as RADIO_DOT, bt as RADIO_FACE, xt as RADIO_RING, St as RADIO_RING_PRESSED, Xe as RENAME_DELAY_MS, G as REPEAT_TILE, Fe as RING_FRAME, Ie as RING_HOLE, Le as RING_INSET, ge as RULE_EDGES, K as RepeatTileController, Re as SCREEN_CORNER, Ct as SLIDER_THUMB, wt as SLIDER_THUMB_FACE, Tt as STEPPER, Et as STEPPER_DOWN_FILL, Dt as STEPPER_UP_FILL, a as SYSTEM_PX_IN_CSS_PX, d as ScaleController, kt as ScrollRailController, mt as ScrollStateController, Ze as TAP_PAIR_MS, Qe as TAP_PAIR_SLOP_PX, R as TILE_LATTICE, en as TrackWidthController, k as VF_BODY_FAMILY, M as VF_DISPLAY_FAMILY, Rt as VfButton, zt as VfButtonGroup, Ht as VfCheckbox, _n as VfContainer, He as VfDesktop, Ft as VfDialog, mn as VfFieldset, Lt as VfFormControl, hn as VfGrid, sn as VfIcon, cn as VfIconField, on as VfImg, rn as VfLabel, fn as VfList, pn as VfListItem, un as VfMenu, ln as VfMenuBar, dn as VfMenuItem, Nt as VfModalDialog, Zt as VfNumberField, Qt as VfOption, an as VfParagraph, E as VfPositioned, tn as VfProgressBar, Ut as VfRadio, Wt as VfRadioGroup, jt as VfScrollArea, $t as VfSelect, It as VfSeparator, Ue as VfSized, nn as VfSlider, gn as VfStack, Bt as VfSwatch, Xt as VfTextArea, Jt as VfTextControlBase, Yt as VfTextField, Vt as VfToggleControl, Mt as VfWindow, $e as WALK_BEAT_MS, et as WALK_STEP_MS, tt as WALK_STEP_PX, dt as WINDOW_MIN_HEIGHT, ft as WINDOW_MIN_WIDTH, nt as WINDOW_RECTS_VISIBLE, rt as WINDOW_RECT_RATIO, it as WINDOW_RECT_STEPS, at as WINDOW_RECT_STEP_MS, Sn as applyCursor, f as applyScale, t as defineElement, q as devicePxAt, o as devicePxPerSystemPx, ot as dragSlop, p as effectiveScale, e as emit, Kt as focusModality, m as getScale, s as getZoom, Ot as glyphSvg, Pt as modalDialogStyles, h as onScaleChange, c as onZoomChange, ne as parsePattern, _e as parseRule, re as patternHex, ie as patternMotif, J as patternOverride, ae as patternRects, st as prefersReducedMotion, A as registerBodyFace, N as registerDisplayFace, O as registerEmbeddedFont, At as renderScrollRail, Y as repeatTile, je as requestGridSnap, l as resetZoomBaseline, ve as ruleClasses, ct as runOutlineTravel, lt as runSelectionBlink, g as snapSys, _ as snapToDevicePx, v as snapToSystemPx, ze as steppedCornerClip, Be as steppedRectClip, Ve as steppedRingClip, y as sys, b as sysLength, x as sysLengths, S as systemPxQuantum, X as tileGrid, z as tileImage, B as tileRaster, V as tileRects, H as tileSpan, C as toSys, w as toSysExact, qt as trackFocusModality, u as truePixelRatio, I as vfBase, j as vfBodyDecls, pe as vfChromeFrame, P as vfDisplay, F as vfDisplayDecls, oe as vfDots, n as vfElement, Ee as vfField, Se as vfFocus, Ce as vfFocusRing, we as vfFocusUnderline, ce as vfHardShadow, le as vfHardShadowDecls, me as vfModalFrame, he as vfPanel, ke as vfPatternFill, Z as vfRepeatTileSize, ye as vfRule, De as vfScrollRail, L as vfStaticText, se as vfStripes, ue as vfStrokeDecls, de as vfStrokeInset, fe as vfStrokeShadow, Q as vfTileGrid, U as vfTileMaskSize, W as vfTileSize, be as vfTitleBar, Te as vfToggle, xe as vfWindowWidgets, pt as windowChrome, ut as windowRectFraction };
@@ -47,14 +47,17 @@ export declare class PatternFillController extends RepeatTileController {
47
47
  * a pattern is resolved (the component's template knows).
48
48
  *
49
49
  * Painting: the tile the controller wrote, repeated from the padding box's
50
- * corner at {@link vfRepeatTileSize}, nearest-neighbor. The paper and the
51
- * pixelation ride the `vf-patterned` state so an unpatterned box paints
52
- * exactly nothing and inherits nothing new. `image-rendering` inherits, so
53
- * the slot hands `auto` back to slotted content: a consumer's own `<img>`
54
- * renders as it would anywhere else, and a kit element that wants
55
- * nearest-neighbor (`vf-img`, a `vf-icon`) says so itself. A page that set
56
- * `pixelated` on an ancestor gets `auto` inside a patterned box — its own
57
- * declaration on the child still wins, as everywhere.
50
+ * corner at {@link vfRepeatTileSize}, nearest-neighbor. All of it rides the
51
+ * `vf-patterned` state, the image included, so an unpatterned box paints
52
+ * exactly nothing. The tile's custom property inherits like any other: a
53
+ * box that read it unpatterned would paint the tile of the nearest
54
+ * patterned box around it — a desktop's dither inside a window.
55
+ * `image-rendering` inherits too, so the slot hands `auto` back to slotted
56
+ * content: a consumer's own `<img>` renders as it would anywhere else, and a
57
+ * kit element that wants nearest-neighbor (`vf-img`, a `vf-icon`) says so
58
+ * itself. A page that set `pixelated` on an ancestor gets `auto` inside a
59
+ * patterned box — its own declaration on the child still wins, as
60
+ * everywhere.
58
61
  *
59
62
  * Forced colors: the image goes, the paper is the remapped Canvas — the
60
63
  * desktop's posture, a backdrop being decoration.
@@ -17,12 +17,10 @@ var i = /* @__PURE__ */ new WeakMap(), a = (e) => {
17
17
  });
18
18
  }
19
19
  }, s = r`
20
- .vf-pattern-fill {
20
+ .vf-pattern-fill.vf-patterned {
21
21
  background-image: var(--_vf-pattern-image, none);
22
22
  ${t}
23
23
  background-repeat: repeat;
24
- }
25
- .vf-pattern-fill.vf-patterned {
26
24
  background-color: var(--vf-white, #fff);
27
25
  image-rendering: pixelated;
28
26
  }
@@ -30,7 +28,7 @@ var i = /* @__PURE__ */ new WeakMap(), a = (e) => {
30
28
  image-rendering: auto;
31
29
  }
32
30
  @media (forced-colors: active) {
33
- .vf-pattern-fill {
31
+ .vf-pattern-fill.vf-patterned {
34
32
  background-image: none;
35
33
  }
36
34
  }
@@ -97,14 +97,17 @@ type PositionedHost = HTMLElement & {
97
97
  * re-asserts a coordinate and costs nothing.
98
98
  *
99
99
  * **Every write it makes is announced** as `vf-placement-change` (bubbles,
100
- * `composed: false`, detail `{ left, top }` — nulls on a return to flow). It
101
- * is an internal coordination event on the terms of the menu handshakes:
102
- * parent and child share one light tree, and a kit protocol must not leak out
103
- * of a consumer's shadow boundary. `vf-scroll-area` listens for it and
100
+ * `composed: false`, detail `{ left, top }` — nulls on a return to flow), so
101
+ * a page hears every move the one way: a title-bar drag's steps and its
102
+ * release (an outline drag's single write), an arrow nudge, a drop, a walk's
103
+ * landing, an `origin` re-measure, and its own property writes. Non-composed,
104
+ * because parent and child share one light tree and the event has no reason
105
+ * to leave a consumer's shadow root. It is dispatched from the host's update,
106
+ * with the new pair already on its style: a handler that writes the pair
107
+ * again takes effect on the next update. `vf-scroll-area` listens for it and
104
108
  * re-measures, because a placed child moved through `top`/`left` changes the
105
109
  * scroll range with no box changing anywhere a ResizeObserver can see — the
106
- * plane's box is never grown by an absolutely positioned child. One funnel
107
- * covers a drop, an arrow nudge and a page's own `icon.left = …` alike.
110
+ * plane's box is never grown by an absolutely positioned child.
108
111
  *
109
112
  * **`origin`** names which point of the host's own box the pair places —
110
113
  * nine keywords, vertical then horizontal (`top center`, `bottom right`,
@@ -169,11 +172,26 @@ export declare function placementIn(anchor: Element, clientX: number, clientY: n
169
172
  left: number;
170
173
  top: number;
171
174
  };
172
- /** The box a gesture is clamped into, in system px — see {@link PlacementClamp}. */
175
+ /**
176
+ * The box a gesture is clamped into, in system px — see {@link PlacementClamp}.
177
+ * `width` and `height` are the positioning parent's box; `top` is the least
178
+ * `top` a placement may take there: 0, or on a desktop's screen the bottom of
179
+ * its menu bar (`vf-desktop.workArea`).
180
+ */
173
181
  export type PlacementBounds = {
174
182
  width: number;
175
183
  height: number;
184
+ top: number;
176
185
  };
186
+ /**
187
+ * The detail of `vf-placement-bounds-request`: the handshake a moved host
188
+ * makes when its gesture measures the box it is clamped into. A
189
+ * `vf-desktop` on its light-DOM path fills `bounds` for a host placed on its
190
+ * screen. Internal to the kit's placement.
191
+ */
192
+ export interface PlacementBoundsRequest {
193
+ bounds: PlacementBounds | null;
194
+ }
177
195
  /**
178
196
  * A moved host's own containment rule, in system px, against the box measured
179
197
  * once at the start of the gesture.
package/dist/position.js CHANGED
@@ -193,10 +193,13 @@ var _ = class {
193
193
  };
194
194
  }
195
195
  #i() {
196
- let e = this.#e, t = e.offsetParent, n = t && t.clientWidth > 0 && t.clientHeight > 0 ? t : null;
196
+ let t = this.#e, n = { bounds: null };
197
+ if (e(t, "vf-placement-bounds-request", n, { composed: !1 }), n.bounds) return n.bounds;
198
+ let r = t.offsetParent, a = r && r.clientWidth > 0 && r.clientHeight > 0 ? r : null;
197
199
  return {
198
- width: i(n?.clientWidth ?? window.innerWidth, e),
199
- height: i(n?.clientHeight ?? window.innerHeight, e)
200
+ width: i(a?.clientWidth ?? window.innerWidth, t),
201
+ height: i(a?.clientHeight ?? window.innerHeight, t),
202
+ top: 0
200
203
  };
201
204
  }
202
205
  }, v = /* @__PURE__ */ new Set([
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The shell's alert: a plain-framed `vf-dialog` with the site's caution art,
3
+ * a message and a row of buttons, sized to the message — composed from kit
4
+ * elements, as every alert in the kit is.
5
+ *
6
+ * The layout follows the plain frame's body, its width and height less 10:
7
+ * the art and the message 16 in from the body's top-left, the buttons'
8
+ * bottom-right corner 16 in from the body's.
9
+ */
10
+ /** One button of an alert. */
11
+ export interface AlertButton {
12
+ label: string;
13
+ /** What the alert resolves to when it is pressed. */
14
+ value: string;
15
+ /** The default button, which Return presses. */
16
+ default?: boolean;
17
+ }
18
+ export interface AlertOptions {
19
+ /** Default: OK, the default button. */
20
+ buttons?: AlertButton[];
21
+ /** The dialog's width, system px. Default 400. */
22
+ width?: number;
23
+ /** The 32×32 art beside the message; default the shell's caution art. */
24
+ art?: string | null;
25
+ /** The dialog's accessible name. Default "Alert". */
26
+ label?: string;
27
+ }
28
+ /**
29
+ * Show an alert inside `host` (the desktop), and resolve the value of the
30
+ * button pressed — or null when it closed any other way, Escape say.
31
+ */
32
+ export declare function showAlert(host: Element, message: string, options?: AlertOptions): Promise<string | null>;
@@ -0,0 +1,44 @@
1
+ import { effectiveScale as e } from "../scale.js";
2
+ import "../index.js";
3
+ //#region src/shell/alert.ts
4
+ var t = 10, n = 16, r = 32, i = 28;
5
+ async function a(a, o, s = {}) {
6
+ let { buttons: c = [{
7
+ label: "OK",
8
+ value: "ok",
9
+ default: !0
10
+ }], width: l = 400, art: u = null, label: d = "Alert" } = s, f = document.createElement("vf-dialog");
11
+ f.frame = "plain", f.label = d, f.width = l, f.height = 120;
12
+ let p = u ? 64 : n;
13
+ if (u) {
14
+ let e = document.createElement("vf-img");
15
+ e.width = r, e.height = r, e.left = n, e.top = n;
16
+ let t = document.createElement("img");
17
+ t.src = u, t.alt = "", e.append(t), f.append(e);
18
+ }
19
+ let m = document.createElement("vf-paragraph");
20
+ m.face = "display", m.width = l - t - p - n, m.left = p, m.top = n, m.textContent = o, f.append(m);
21
+ let h = document.createElement("vf-button-group");
22
+ h.origin = "bottom right";
23
+ let g = c.map((e) => {
24
+ let t = document.createElement("vf-button");
25
+ return t.textContent = e.label, t.dataset.value = e.value, e.default && (t.variant = "default"), t;
26
+ });
27
+ h.append(...g), f.append(h), a.append(f), await Promise.all([
28
+ f.updateComplete,
29
+ m.updateComplete,
30
+ h.updateComplete
31
+ ]);
32
+ let _ = Math.ceil(m.getBoundingClientRect().height / e(m)), v = Math.max(u ? 48 : 0, n + _) + n + i + n;
33
+ return f.height = v + t, h.left = l - t - n, h.top = v - n, new Promise((e) => {
34
+ let t = null;
35
+ for (let e of g) e.addEventListener("click", () => {
36
+ t = e.dataset.value ?? null, f.close();
37
+ });
38
+ f.addEventListener("vf-close", () => {
39
+ f.remove(), e(t);
40
+ }, { once: !0 }), f.show();
41
+ });
42
+ }
43
+ //#endregion
44
+ export { a as showAlert };
@@ -0,0 +1,168 @@
1
+ /**
2
+ * The catalog: what is where. Pure and DOM-free — it runs under Node — and
3
+ * the source of truth for what a folder holds; the Finder renders it.
4
+ *
5
+ * - An item is a small record: a name, a kind, the container it sits in
6
+ * (`parent`, a folder's id, or null for the desktop) and, once placed, its
7
+ * position there in whole system px. A kind keeps small data of its own in
8
+ * `data`; a large payload stays in its application's own store, keyed by
9
+ * the item's id, and the kind's `copy` and `onRemove` keep that store in
10
+ * step.
11
+ * - Volumes are containers no one made: the Trash and a startup disk, each
12
+ * if the page wants one. They lead the listing, keep their names, and are
13
+ * never renamed, moved, copied or removed; nothing is made in the Trash.
14
+ * Deleting is a move into the Trash, and only Empty Trash removes. A
15
+ * volume's position is stored on a record of its own id.
16
+ * - A folder never goes into itself or a folder inside it. A parent with no
17
+ * record reads as the desktop.
18
+ * - An item whose kind no application registers is left out of the listing
19
+ * and kept in storage.
20
+ * - Storage is three calls over item records (list, put, remove). The
21
+ * catalog holds every record in memory, writes through to storage, and
22
+ * lists from memory; a position change writes after a short delay, since
23
+ * the resize rule moves every desktop icon on each resize event.
24
+ * - A seed runs once per storage: a persistent one stores a marker record
25
+ * (`#seeded`), so a site that starts in memory and switches its storage
26
+ * seeds once there.
27
+ */
28
+ import type { Point } from './geometry.js';
29
+ /** The Trash's id. */
30
+ export declare const TRASH = "trash";
31
+ /** The startup disk's id. */
32
+ export declare const DISK = "disk";
33
+ /** A folder's kind. */
34
+ export declare const FOLDER = "folder";
35
+ /** The name a new folder takes, counted up where it is taken. */
36
+ export declare const UNTITLED_FOLDER = "untitled folder";
37
+ /** One item of the catalog. */
38
+ export interface Item {
39
+ id: string;
40
+ name: string;
41
+ /** `folder`, a volume's (`trash`, `disk`), or a kind an application registers. */
42
+ kind: string;
43
+ /** A folder's id, a volume's, or null for the desktop. */
44
+ parent: string | null;
45
+ /** Its place in its container, whole system px; unset, the next free cell. */
46
+ left?: number;
47
+ top?: number;
48
+ createdAt: number;
49
+ modifiedAt: number;
50
+ /** The kind's own, small and serializable. */
51
+ data?: unknown;
52
+ }
53
+ /** The listing: volumes first, then every listed item by creation. */
54
+ export interface CatalogState {
55
+ /** Whether storage answers. Without it the catalog lists the volumes alone. */
56
+ available: boolean;
57
+ items: readonly Item[];
58
+ }
59
+ /** Where item records live. Any object with these three calls will do. */
60
+ export interface CatalogStorage {
61
+ list(): Promise<Item[]>;
62
+ put(item: Item): Promise<unknown>;
63
+ remove(id: string): Promise<unknown>;
64
+ }
65
+ /** What a kind tells the catalog about its items' payloads. */
66
+ export interface KindHooks {
67
+ /** Bytes, for Empty Trash's alert. */
68
+ size?(item: Item): number;
69
+ /** Copy `from`'s payload to `to`, a fresh copy of it. */
70
+ copy?(from: Item, to: Item): void | Promise<void>;
71
+ /** Empty Trash removed the item: drop its payload. */
72
+ onRemove?(item: Item): void | Promise<void>;
73
+ }
74
+ /** The volumes a page wants, by name; `false` or unset is none (the Trash defaults on). */
75
+ export interface Volumes {
76
+ trash?: string | false;
77
+ disk?: string | false;
78
+ }
79
+ export interface CatalogOptions {
80
+ storage: CatalogStorage | null;
81
+ volumes?: Volumes;
82
+ /** Whether an application registers `kind`. Folders are always listed. Default: every kind. */
83
+ listed?(kind: string): boolean;
84
+ /** A kind's payload hooks. */
85
+ hooks?(kind: string): KindHooks | undefined;
86
+ now?(): number;
87
+ newId?(): string;
88
+ /** How long a position change waits before it is written, ms. Default 400. */
89
+ placeDelay?: number;
90
+ }
91
+ /** What an operation makes: the new item, or null where it was refused. */
92
+ export interface NewItem {
93
+ name?: string;
94
+ kind?: string;
95
+ parent?: string | null;
96
+ left?: number;
97
+ top?: number;
98
+ data?: unknown;
99
+ /** The creation time, for a batch made in order. Default now. */
100
+ at?: number;
101
+ }
102
+ /** A catalog dumped or restored: its item records. */
103
+ export interface CatalogArchive {
104
+ items: Item[];
105
+ }
106
+ /** Whether `kind` holds other items: a folder or a volume. */
107
+ export declare const isContainerKind: (kind: string) => boolean;
108
+ /** Whether `id` names a volume. */
109
+ export declare const isVolume: (id: string | null | undefined) => boolean;
110
+ /** The item with `id`, or null. */
111
+ export declare function itemOf(state: CatalogState, id: string | null | undefined): Item | null;
112
+ /** The container `parent` resolves to: that container while it is listed, else the desktop (null). */
113
+ export declare function containerOf(state: CatalogState, parent: string | null | undefined): string | null;
114
+ /** The items directly in a container (null: the desktop), in listing order. */
115
+ export declare function childrenOf(state: CatalogState, parent: string | null): Item[];
116
+ /** How many items a container holds directly. */
117
+ export declare function itemCount(state: CatalogState, parent: string | null): number;
118
+ /**
119
+ * Whether `ancestor` is on `id`'s chain of containers. An item is not inside
120
+ * itself; a looping chain stops at its first repeat.
121
+ */
122
+ export declare function isInside(state: CatalogState, id: string, ancestor: string): boolean;
123
+ /**
124
+ * Container `id` and the containers around it, innermost first. The desktop
125
+ * ends the chain, and so does an id with no container; a loop stops at its
126
+ * first repeat.
127
+ */
128
+ export declare function enclosingFolders(state: CatalogState, id: string | null | undefined): string[];
129
+ /** Whether `id` is the Trash or anything inside it. */
130
+ export declare function isTrashed(state: CatalogState, id: string | null | undefined): boolean;
131
+ /** Everything under a container, each container before what it holds; a loop is walked once. */
132
+ export declare function descendantsOf(state: CatalogState, parent: string | null): Item[];
133
+ /** The first free folder name in a container: "untitled folder", "untitled folder 2", … */
134
+ export declare function nextFolderName(state: CatalogState, parent: string | null): string;
135
+ /**
136
+ * The name for a copy in a container: `name` itself while no item of its
137
+ * kind there has it, else its base (less " copy" and " copy N") plus " copy",
138
+ * then " copy 2", " copy 3", …
139
+ */
140
+ export declare function copyName(state: CatalogState, parent: string | null, name: string, kind: string): string;
141
+ /** The catalog's operations, over its listing. */
142
+ export interface Catalog {
143
+ get(): CatalogState;
144
+ subscribe(fn: (state: CatalogState) => void): () => void;
145
+ item(id: string | null | undefined): Item | null;
146
+ refresh(): Promise<void>;
147
+ seed(fn: (catalog: Catalog) => void | Promise<void>): Promise<boolean>;
148
+ create(input?: NewItem): Promise<Item | null>;
149
+ rename(id: string, name: string): Promise<boolean>;
150
+ update(id: string, data: unknown): Promise<boolean>;
151
+ move(ids: readonly string[], parent: string | null, landings?: ReadonlyMap<string, Point | null>): Promise<string[]>;
152
+ place(positions: ReadonlyMap<string, Point>): void;
153
+ flush(): Promise<void>;
154
+ copy(ids: readonly string[], parent: string | null): Promise<Item[]>;
155
+ emptyTrash(): Promise<Item[]>;
156
+ trashSize(): number;
157
+ dump(): CatalogArchive;
158
+ clear(): Promise<void>;
159
+ import(archive: CatalogArchive, options?: {
160
+ mode?: 'merge' | 'replace';
161
+ }): Promise<number>;
162
+ dispose(): Promise<void>;
163
+ }
164
+ export declare function createCatalog(options: CatalogOptions): Catalog;
165
+ /** Storage that forgets everything on a reload. Its map is exposed for tests. */
166
+ export declare function memoryStorage(initial?: readonly Item[]): CatalogStorage & {
167
+ records: Map<string, Item>;
168
+ };