@humanforest/frames 0.3.7 → 0.5.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 +87 -0
- package/package.json +1 -1
- package/src/FFitFrame.vue +11 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,93 @@
|
|
|
2
2
|
|
|
3
3
|
Every @humanforest package shares one version, so one entry covers all seven packages. Newest first.
|
|
4
4
|
|
|
5
|
+
## 0.5.0 — 2026-10-25
|
|
6
|
+
|
|
7
|
+
### Breaking changes
|
|
8
|
+
|
|
9
|
+
- **ui**: let a sidebar nav item carry its own badge
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- **ui**: let a HUD card centre between its band's rails
|
|
14
|
+
|
|
15
|
+
### Fixes
|
|
16
|
+
|
|
17
|
+
- **ui**: keep `center` off the HUD's bottom card
|
|
18
|
+
- **ui**: drop the page-level scrollbar gutter
|
|
19
|
+
- **ui**: the map search glyph is sized, not padded
|
|
20
|
+
|
|
21
|
+
## 0.4.0 — 2026-09-15
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- **docs**: the llms mirror prints a section kicker under its heading
|
|
26
|
+
- **frames**: FFitFrame fits a slot that sizes itself
|
|
27
|
+
- **charts**: a sparkline's area fades from its line to the floor
|
|
28
|
+
- **charts**: the calendar month rule boxes each month in a toned line
|
|
29
|
+
- **docs**: the llms mirror heads a non-prop table by its own column
|
|
30
|
+
- **docs**: the llms mirror names the module a page destructures
|
|
31
|
+
- **docs**: the llms mirror renders section loops
|
|
32
|
+
- **docs**: the llms mirror resolves plain strings a page imports
|
|
33
|
+
- **docs**: DemoStage puts a demo's controls above the specimen
|
|
34
|
+
- **docs**: the llms mirror names each code tab in a ProseCodeGroup
|
|
35
|
+
- **docs**: the llms mirror renders guidance cards and imported arrays
|
|
36
|
+
|
|
37
|
+
### Fixes
|
|
38
|
+
|
|
39
|
+
- **ui**: the scroll fade follows content that changes after mount
|
|
40
|
+
- **ui**: map drawing places a corner only for a press on the map
|
|
41
|
+
- **ui**: the scale bar measures at the centre and hides off the globe
|
|
42
|
+
- **ui**: geolocate stays active through a location error while tracking
|
|
43
|
+
- **ui**: map search names only a rendered row in aria-activedescendant
|
|
44
|
+
- **ui**: a context menu that reopens elsewhere takes focus again
|
|
45
|
+
- **ui**: map overlays add layers after the frame, not during placement
|
|
46
|
+
- **ui**: the map context menu wires nothing on a non-interactive map
|
|
47
|
+
- **ui**: map search rings kept focus and never sends a pair to suggest
|
|
48
|
+
- **ui**: fullscreen reads nothing without a fullscreen API
|
|
49
|
+
- **ui**: geolocate is a plain action with track off
|
|
50
|
+
- **ui**: coordinates read Mapbox's 512px world and name the copied pair
|
|
51
|
+
- **docs**: chord, treemap and sankey demos keep their heights
|
|
52
|
+
- **charts**: resolveVar leaves the document alone without a DOM
|
|
53
|
+
- **docs**: the battery-swap stage keeps its start edge reachable
|
|
54
|
+
- **docs**: foundations and layout diagrams fit a phone
|
|
55
|
+
- **docs**: device frames scale down to fit a phone's pane
|
|
56
|
+
- **docs**: component specimens fit a phone's preview pane
|
|
57
|
+
- **filter**: the chip's number segments drop their steppers
|
|
58
|
+
- **docs**: the table page's pager drops its arrows on a phone
|
|
59
|
+
- **filter**: a chip wider than its bar wraps its segments
|
|
60
|
+
- **tokens**: the display role steps down to 4xl below 40rem
|
|
61
|
+
- **tokens**: long inline code wraps instead of overflowing its column
|
|
62
|
+
- **docs**: long inline code and prop types wrap instead of widening main
|
|
63
|
+
- **ui**: a vehicle mark's badge outline follows its edge
|
|
64
|
+
- **ui**: ramp swatches abut and round only the ramp's ends
|
|
65
|
+
- **docs**: a context switch keeps a page's live demos mounted
|
|
66
|
+
- **ui**: a bound popup closes on a second click and unbinds on unmount
|
|
67
|
+
- **ui**: a marker is a button only when it acts as one
|
|
68
|
+
- **ui**: FMap applies every padding side and logs each map error
|
|
69
|
+
- **ui**: a track slice no longer bridges a signal gap
|
|
70
|
+
- **ui**: track playback keeps the playhead when the speed changes
|
|
71
|
+
- **ui**: balance maps paint by magnitude, and legends label exactly
|
|
72
|
+
- **charts**: the tooltip snap looks for its panel on pointer entry
|
|
73
|
+
- **ui**: unavailable reasons name a state by its label
|
|
74
|
+
- **ui**: zones ignore a kind they do not know
|
|
75
|
+
- **ui**: a selected vehicle takes its new state on resync
|
|
76
|
+
- **docs**: a cross-page anchored link lands on its target
|
|
77
|
+
- **ui**: useMapReady never runs for a caller that has unmounted
|
|
78
|
+
- **tokens**: area fills keep their opacity under data-theme dark
|
|
79
|
+
- **charts**: crosshair dots sit on stacked band tops
|
|
80
|
+
- **charts**: a fitted London map labels only the areas it draws
|
|
81
|
+
- **charts**: a missing reading breaks a line sparkline
|
|
82
|
+
- **charts**: a dotted map's missing values add nothing
|
|
83
|
+
- **charts**: a selectable London map is reachable at every size
|
|
84
|
+
- **charts**: cell tracks and grids take one Tab stop, props read live
|
|
85
|
+
- **docs**: urgent vehicles draw on top of the fleet
|
|
86
|
+
- **ui**: alt shortcuts select, and deleted features leave the selection
|
|
87
|
+
- **ui**: a crossing edit springs back, and a drag reports once
|
|
88
|
+
- **ui**: selected markers rise, popups are named, one button opens them
|
|
89
|
+
- **ui**: the coordinate tile stays copyable as the pointer moves onto it
|
|
90
|
+
- **ui**: the scale bar's fill is as long as the distance it names
|
|
91
|
+
|
|
5
92
|
## 0.3.7 — 2026-09-13
|
|
6
93
|
|
|
7
94
|
### Features
|
package/package.json
CHANGED
package/src/FFitFrame.vue
CHANGED
|
@@ -18,8 +18,9 @@ import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
|
|
18
18
|
|
|
19
19
|
const props = withDefaults(
|
|
20
20
|
defineProps<{
|
|
21
|
-
/** Logical width the slot lays out at, whatever the space available.
|
|
22
|
-
|
|
21
|
+
/** Logical width the slot lays out at, whatever the space available. Omit it for a slot with a
|
|
22
|
+
* fixed size of its own, such as a device frame, and its measured width is used. */
|
|
23
|
+
width?: number;
|
|
23
24
|
/** Largest scale to draw at, so a wide page does not render the specimen at 1:1. */
|
|
24
25
|
maxScale?: number;
|
|
25
26
|
}>(),
|
|
@@ -33,6 +34,7 @@ const PAD_BOTTOM = 24;
|
|
|
33
34
|
|
|
34
35
|
const inner = ref<HTMLElement | null>(null);
|
|
35
36
|
const wrapper = ref<HTMLElement | null>(null);
|
|
37
|
+
const naturalW = ref(0);
|
|
36
38
|
const naturalH = ref(0);
|
|
37
39
|
const availW = ref(0);
|
|
38
40
|
|
|
@@ -40,7 +42,7 @@ const availW = ref(0);
|
|
|
40
42
|
// component's mounted hook runs, and a missed attach leaves the wrapper unsized with no visible error.
|
|
41
43
|
// No loop between the two: the slot's unscaled height is fixed by its own content, and the wrapper's
|
|
42
44
|
// width is its block width — neither depends on the scale derived from them.
|
|
43
|
-
const innerRO = new ResizeObserver(([e]) => { naturalH.value = e!.contentRect.height; });
|
|
45
|
+
const innerRO = new ResizeObserver(([e]) => { naturalW.value = e!.contentRect.width; naturalH.value = e!.contentRect.height; });
|
|
44
46
|
const wrapRO = new ResizeObserver(([e]) => { availW.value = e!.contentRect.width; });
|
|
45
47
|
watch(inner, (el) => { innerRO.disconnect(); if (el) innerRO.observe(el); }, { immediate: true, flush: 'post' });
|
|
46
48
|
watch(wrapper, (el) => { wrapRO.disconnect(); if (el) wrapRO.observe(el); }, { immediate: true, flush: 'post' });
|
|
@@ -48,7 +50,12 @@ onBeforeUnmount(() => { innerRO.disconnect(); wrapRO.disconnect(); });
|
|
|
48
50
|
|
|
49
51
|
// ★ SCALE TO FIT, capped. A fixed factor overflows its container the moment the page is narrower than
|
|
50
52
|
// width × scale — the slot's layout width never changes, so nothing else absorbs it.
|
|
51
|
-
|
|
53
|
+
// The wrapper needs a width of its own to fit into: inside a shrink-to-fit parent it takes the slot's
|
|
54
|
+
// width, and the frame never scales.
|
|
55
|
+
const fit = computed(() => {
|
|
56
|
+
const w = props.width ?? naturalW.value;
|
|
57
|
+
return availW.value && w ? Math.min(props.maxScale, availW.value / w) : props.maxScale;
|
|
58
|
+
});
|
|
52
59
|
|
|
53
60
|
// Height the scaled frame actually takes on the page. 0 until measured, so nothing jumps.
|
|
54
61
|
const reservedH = computed(() =>
|