@macrostrat/column-views 3.10.0 → 3.12.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.
Files changed (148) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/dist/age-model/data.cjs +57 -0
  3. package/dist/age-model/data.cjs.map +1 -0
  4. package/dist/age-model/data.d.ts +29 -0
  5. package/dist/age-model/data.js +57 -0
  6. package/dist/age-model/data.js.map +1 -0
  7. package/dist/age-model/details.cjs +261 -0
  8. package/dist/age-model/details.cjs.map +1 -0
  9. package/dist/age-model/details.d.ts +39 -0
  10. package/dist/age-model/details.js +258 -0
  11. package/dist/age-model/details.js.map +1 -0
  12. package/dist/age-model/details.module.sass.cjs +42 -0
  13. package/dist/age-model/details.module.sass.cjs.map +1 -0
  14. package/dist/age-model/details.module.sass.js +40 -0
  15. package/dist/age-model/details.module.sass.js.map +1 -0
  16. package/dist/age-model/index.d.ts +5 -0
  17. package/dist/age-model/legacy.cjs +28 -0
  18. package/dist/age-model/legacy.cjs.map +1 -0
  19. package/dist/age-model/legacy.d.ts +6 -0
  20. package/dist/age-model/legacy.js +26 -0
  21. package/dist/age-model/legacy.js.map +1 -0
  22. package/dist/age-model/surfaces.cjs +355 -0
  23. package/dist/age-model/surfaces.cjs.map +1 -0
  24. package/dist/age-model/surfaces.d.ts +68 -0
  25. package/dist/age-model/surfaces.js +352 -0
  26. package/dist/age-model/surfaces.js.map +1 -0
  27. package/dist/age-model/surfaces.module.sass.cjs +45 -0
  28. package/dist/age-model/surfaces.module.sass.cjs.map +1 -0
  29. package/dist/age-model/surfaces.module.sass.js +43 -0
  30. package/dist/age-model/surfaces.module.sass.js.map +1 -0
  31. package/dist/age-model/types.cjs +229 -0
  32. package/dist/age-model/types.cjs.map +1 -0
  33. package/dist/age-model/types.d.ts +112 -0
  34. package/dist/age-model/types.js +229 -0
  35. package/dist/age-model/types.js.map +1 -0
  36. package/dist/column-views.css +398 -56
  37. package/dist/column.cjs +20 -13
  38. package/dist/column.cjs.map +1 -1
  39. package/dist/column.d.ts +21 -6
  40. package/dist/column.js +21 -14
  41. package/dist/column.js.map +1 -1
  42. package/dist/column.module.sass.cjs +19 -15
  43. package/dist/column.module.sass.cjs.map +1 -1
  44. package/dist/column.module.sass.js +19 -15
  45. package/dist/column.module.sass.js.map +1 -1
  46. package/dist/correlation-chart/main.cjs +11 -3
  47. package/dist/correlation-chart/main.cjs.map +1 -1
  48. package/dist/correlation-chart/main.d.ts +1 -1
  49. package/dist/correlation-chart/main.js +11 -3
  50. package/dist/correlation-chart/main.js.map +1 -1
  51. package/dist/data-provider/store.cjs +34 -1
  52. package/dist/data-provider/store.cjs.map +1 -1
  53. package/dist/data-provider/store.d.ts +5 -0
  54. package/dist/data-provider/store.js +35 -2
  55. package/dist/data-provider/store.js.map +1 -1
  56. package/dist/index.cjs +57 -3
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.d.ts +3 -1
  59. package/dist/index.js +57 -3
  60. package/dist/index.js.map +1 -1
  61. package/dist/notes.cjs +11 -2
  62. package/dist/notes.cjs.map +1 -1
  63. package/dist/notes.d.ts +11 -1
  64. package/dist/notes.js +11 -2
  65. package/dist/notes.js.map +1 -1
  66. package/dist/prepare-units/composite-scale.cjs +18 -16
  67. package/dist/prepare-units/composite-scale.cjs.map +1 -1
  68. package/dist/prepare-units/composite-scale.js +18 -16
  69. package/dist/prepare-units/composite-scale.js.map +1 -1
  70. package/dist/prepare-units/density.cjs +83 -0
  71. package/dist/prepare-units/density.cjs.map +1 -0
  72. package/dist/prepare-units/density.d.ts +92 -0
  73. package/dist/prepare-units/density.js +83 -0
  74. package/dist/prepare-units/density.js.map +1 -0
  75. package/dist/prepare-units/index.cjs +15 -7
  76. package/dist/prepare-units/index.cjs.map +1 -1
  77. package/dist/prepare-units/index.d.ts +1 -0
  78. package/dist/prepare-units/index.js +15 -7
  79. package/dist/prepare-units/index.js.map +1 -1
  80. package/dist/prepare-units/types.cjs.map +1 -1
  81. package/dist/prepare-units/types.d.ts +34 -13
  82. package/dist/prepare-units/types.js.map +1 -1
  83. package/dist/section.cjs +108 -24
  84. package/dist/section.cjs.map +1 -1
  85. package/dist/section.d.ts +66 -6
  86. package/dist/section.js +109 -25
  87. package/dist/section.js.map +1 -1
  88. package/dist/timescale-zoom.cjs +191 -0
  89. package/dist/timescale-zoom.cjs.map +1 -0
  90. package/dist/timescale-zoom.d.ts +74 -0
  91. package/dist/timescale-zoom.js +191 -0
  92. package/dist/timescale-zoom.js.map +1 -0
  93. package/dist/unit-details/age-range.cjs +1 -0
  94. package/dist/unit-details/age-range.cjs.map +1 -1
  95. package/dist/unit-details/age-range.d.ts +5 -1
  96. package/dist/unit-details/age-range.js +1 -0
  97. package/dist/unit-details/age-range.js.map +1 -1
  98. package/dist/unit-details/age-window-tag.cjs +68 -0
  99. package/dist/unit-details/age-window-tag.cjs.map +1 -0
  100. package/dist/unit-details/age-window-tag.d.ts +26 -0
  101. package/dist/unit-details/age-window-tag.js +66 -0
  102. package/dist/unit-details/age-window-tag.js.map +1 -0
  103. package/dist/{age-model-overlay.module.sass.cjs → unit-details/age-window-tag.module.sass.cjs} +3 -3
  104. package/dist/unit-details/age-window-tag.module.sass.cjs.map +1 -0
  105. package/dist/unit-details/age-window-tag.module.sass.js +11 -0
  106. package/dist/unit-details/age-window-tag.module.sass.js.map +1 -0
  107. package/dist/unit-details/index.d.ts +1 -0
  108. package/dist/units/composite.cjs +4 -1
  109. package/dist/units/composite.cjs.map +1 -1
  110. package/dist/units/composite.d.ts +2 -0
  111. package/dist/units/composite.js +4 -1
  112. package/dist/units/composite.js.map +1 -1
  113. package/package.json +7 -7
  114. package/src/age-model/data.ts +98 -0
  115. package/src/age-model/details.module.sass +108 -0
  116. package/src/age-model/details.ts +333 -0
  117. package/src/age-model/index.ts +5 -0
  118. package/src/age-model/legacy.ts +30 -0
  119. package/src/age-model/surfaces.module.sass +168 -0
  120. package/src/age-model/surfaces.ts +568 -0
  121. package/src/age-model/types.ts +392 -0
  122. package/src/column.module.sass +59 -8
  123. package/src/column.ts +49 -23
  124. package/src/correlation-chart/main.ts +14 -2
  125. package/src/data-provider/store.ts +50 -1
  126. package/src/index.ts +5 -1
  127. package/src/notes.ts +20 -2
  128. package/src/prepare-units/composite-scale.ts +34 -31
  129. package/src/prepare-units/density.ts +197 -0
  130. package/src/prepare-units/index.ts +25 -6
  131. package/src/prepare-units/types.ts +34 -13
  132. package/src/section.ts +219 -33
  133. package/src/timescale-zoom.ts +341 -0
  134. package/src/unit-details/age-range.ts +3 -3
  135. package/src/unit-details/age-window-tag.module.sass +10 -0
  136. package/src/unit-details/age-window-tag.ts +102 -0
  137. package/src/unit-details/index.ts +1 -0
  138. package/src/units/composite.ts +11 -0
  139. package/dist/age-model-overlay.cjs +0 -50
  140. package/dist/age-model-overlay.cjs.map +0 -1
  141. package/dist/age-model-overlay.d.ts +0 -24
  142. package/dist/age-model-overlay.js +0 -48
  143. package/dist/age-model-overlay.js.map +0 -1
  144. package/dist/age-model-overlay.module.sass.cjs.map +0 -1
  145. package/dist/age-model-overlay.module.sass.js +0 -11
  146. package/dist/age-model-overlay.module.sass.js.map +0 -1
  147. package/src/age-model-overlay.module.sass +0 -11
  148. package/src/age-model-overlay.ts +0 -96
@@ -0,0 +1,191 @@
1
+ import { useState, useMemo, useCallback } from "react";
2
+ import { useAnimatedAgeWindow } from "./animated-age-window.js";
3
+ const MIN_TIMESCALE_LEVEL = 1;
4
+ const MAX_TIMESCALE_LEVEL = 5;
5
+ const LEVEL_WINDOW = 3;
6
+ const DEFAULT_LEVEL = 3;
7
+ const SELECTED_INTERVAL_STYLE = { fontWeight: "bold" };
8
+ function useTimescaleZoom(options) {
9
+ const {
10
+ fullExtent,
11
+ enabled = true,
12
+ levelWindow = LEVEL_WINDOW,
13
+ defaultLevel = DEFAULT_LEVEL,
14
+ minLevel = MIN_TIMESCALE_LEVEL,
15
+ maxLevel = MAX_TIMESCALE_LEVEL,
16
+ duration,
17
+ selectedIntervalStyle = SELECTED_INTERVAL_STYLE
18
+ } = options;
19
+ const anim = useAnimatedAgeWindow({ fullExtent, duration });
20
+ const [intervals, setIntervals] = useState([]);
21
+ const [addedIntervals, setAddedIntervals] = useState([]);
22
+ const [selectedTimescaleID, setSelectedTimescaleID] = useState(
23
+ null
24
+ );
25
+ const selectedInterval = intervals[intervals.length - 1] ?? null;
26
+ const selectedIntervals = useMemo(() => {
27
+ if (selectedInterval == null) return addedIntervals;
28
+ return [selectedInterval, ...addedIntervals];
29
+ }, [selectedInterval, addedIntervals]);
30
+ const reset = useCallback(() => {
31
+ setIntervals([]);
32
+ setAddedIntervals([]);
33
+ setSelectedTimescaleID(null);
34
+ anim.reset();
35
+ }, [anim.reset]);
36
+ const extendToInterval = useCallback(
37
+ (interval) => {
38
+ let added = addedIntervals.filter((d) => d.oid !== interval.oid);
39
+ const wasSelected = added.length !== addedIntervals.length;
40
+ if (!wasSelected && interval.oid !== selectedInterval?.oid) {
41
+ added = [...addedIntervals, interval];
42
+ }
43
+ setAddedIntervals(added);
44
+ let selection = added;
45
+ if (selectedInterval != null) {
46
+ selection = [selectedInterval, ...added];
47
+ }
48
+ if (selection.length === 0) {
49
+ anim.reset();
50
+ return;
51
+ }
52
+ anim.zoomToWindow(intervalsWindow(selection));
53
+ },
54
+ [addedIntervals, selectedInterval, anim.zoomToWindow, anim.reset]
55
+ );
56
+ const zoomToInterval = useCallback(
57
+ (interval, timescaleID = null) => {
58
+ const containing = intervals.filter(
59
+ (d) => d.lvl < interval.lvl && d.eag >= interval.eag && d.lag <= interval.lag
60
+ );
61
+ setIntervals([...containing, interval]);
62
+ setAddedIntervals([]);
63
+ setSelectedTimescaleID(timescaleID);
64
+ anim.zoomToInterval(interval);
65
+ },
66
+ [intervals, anim.zoomToInterval]
67
+ );
68
+ const onClickTimescaleInterval = useCallback(
69
+ (event, data) => {
70
+ const interval = data?.interval;
71
+ if (interval == null || interval.lvl == null) return;
72
+ const timescaleID = data.timescaleID ?? null;
73
+ if (event?.shiftKey) {
74
+ extendToInterval(interval);
75
+ return;
76
+ }
77
+ if (interval.oid === selectedInterval?.oid && addedIntervals.length === 0) {
78
+ const next = intervals.slice(0, -1);
79
+ setIntervals(next);
80
+ setSelectedTimescaleID(null);
81
+ const parent = next[next.length - 1] ?? null;
82
+ if (parent == null) {
83
+ anim.reset();
84
+ } else {
85
+ anim.zoomToInterval(parent);
86
+ }
87
+ return;
88
+ }
89
+ zoomToInterval(interval, timescaleID);
90
+ },
91
+ [
92
+ intervals,
93
+ selectedInterval,
94
+ selectedTimescaleID,
95
+ addedIntervals,
96
+ extendToInterval,
97
+ zoomToInterval,
98
+ anim.reset
99
+ ]
100
+ );
101
+ const timescaleIntervalStyle = useCallback(
102
+ (interval) => {
103
+ if (selectedIntervals.some((d) => d.oid === interval.oid)) {
104
+ return selectedIntervalStyle;
105
+ }
106
+ return {};
107
+ },
108
+ [selectedIntervals, selectedIntervalStyle]
109
+ );
110
+ const levels = useMemo(() => {
111
+ let level = defaultLevel;
112
+ for (const interval of selectedIntervals) {
113
+ if (interval.lvl != null) level = Math.max(level, interval.lvl);
114
+ }
115
+ return levelsForSelected(level, { levelWindow, minLevel, maxLevel });
116
+ }, [selectedIntervals, defaultLevel, levelWindow, minLevel, maxLevel]);
117
+ if (!enabled) {
118
+ return {
119
+ ...disabledZoom,
120
+ selectedTimescaleID: null,
121
+ selectedIntervals: [],
122
+ timescaleLevels: levels,
123
+ reset,
124
+ zoomToInterval,
125
+ onClickTimescaleInterval,
126
+ timescaleIntervalStyle
127
+ };
128
+ }
129
+ const window = anim.window ?? fullExtent;
130
+ return {
131
+ enabled: true,
132
+ window,
133
+ intervals,
134
+ selectedInterval,
135
+ selectedTimescaleID,
136
+ selectedIntervals,
137
+ timescaleLevels: levels,
138
+ isFullExtent: anim.isFullExtent,
139
+ isAnimating: anim.isAnimating,
140
+ reset,
141
+ zoomToInterval,
142
+ onClickTimescaleInterval,
143
+ timescaleIntervalStyle,
144
+ columnProps: {
145
+ showTimescale: true,
146
+ timescaleLevels: levels,
147
+ timescaleIntervalStyle,
148
+ onClickTimescaleInterval,
149
+ t_age: window?.t_age,
150
+ b_age: window?.b_age,
151
+ isTransitioning: anim.isAnimating
152
+ }
153
+ };
154
+ }
155
+ const disabledZoom = {
156
+ enabled: false,
157
+ window: null,
158
+ intervals: [],
159
+ selectedInterval: null,
160
+ isFullExtent: true,
161
+ isAnimating: false,
162
+ columnProps: {}
163
+ };
164
+ function levelsForSelected(selectedLevel, options) {
165
+ const { levelWindow, minLevel, maxLevel } = options;
166
+ const span = Math.max(levelWindow - 1, 0);
167
+ const lo = Math.min(
168
+ Math.max(selectedLevel - 1, minLevel),
169
+ Math.max(maxLevel - span, minLevel)
170
+ );
171
+ return [lo, lo + span];
172
+ }
173
+ function intervalsWindow(intervals) {
174
+ return {
175
+ t_age: Math.min(...intervals.map((d) => d.lag)),
176
+ b_age: Math.max(...intervals.map((d) => d.eag))
177
+ };
178
+ }
179
+ function unitsAgeExtent(units) {
180
+ if (units == null || units.length === 0) return null;
181
+ return {
182
+ t_age: Math.min(...units.map((d) => d.t_age)),
183
+ b_age: Math.max(...units.map((d) => d.b_age))
184
+ };
185
+ }
186
+ export {
187
+ levelsForSelected,
188
+ unitsAgeExtent,
189
+ useTimescaleZoom
190
+ };
191
+ //# sourceMappingURL=timescale-zoom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timescale-zoom.js","sources":["../src/timescale-zoom.ts"],"sourcesContent":["/** Click-to-zoom navigation over geologic time.\n *\n * `useTimescaleZoom` turns clicks on a column's timescale into an animated\n * age window: clicking an interval zooms to it, clicking the interval you are\n * already in zooms back out a level, and the timescale shows a sliding window\n * of levels that follows the selection, so finer intervals come into reach as\n * you drill. The result spreads straight onto a `Column`.\n */\nimport { type CSSProperties, useCallback, useMemo, useState } from \"react\";\nimport type {\n Interval,\n IntervalStyleBuilder,\n TimescaleClickData,\n TimescaleClickHandler,\n} from \"@macrostrat/timescale\";\nimport { type AgeWindow, useAnimatedAgeWindow } from \"./animated-age-window\";\n\n/** Coarsest level worth showing; level 0 is \"all of geologic time\" */\nconst MIN_TIMESCALE_LEVEL = 1;\n/** Deepest level in the timescale (age/stage) */\nconst MAX_TIMESCALE_LEVEL = 5;\n/** How many levels are shown at once */\nconst LEVEL_WINDOW = 3;\n/** The level anchored on before an interval is picked. 3 (period) puts the\n * starting window at era–epoch, the levels a `Column` shows by default. */\nconst DEFAULT_LEVEL = 3;\n\nconst SELECTED_INTERVAL_STYLE: CSSProperties = { fontWeight: \"bold\" };\n\nexport interface UseTimescaleZoomOptions {\n /** The full data extent — the window zooming returns to. `null` until the\n * data (and hence the extent) is known. */\n fullExtent: AgeWindow | null;\n /** When false the hook reports no window and no column props, so a view can\n * offer zooming as an option without changing hook order (default `true`). */\n enabled?: boolean;\n /** How many timescale levels to show at once (default 3) */\n levelWindow?: number;\n /** The level to anchor the window on before an interval is picked\n * (default 3, period) */\n defaultLevel?: number;\n minLevel?: number;\n maxLevel?: number;\n /** Animation duration in ms */\n duration?: number;\n /** Style for the selected interval — the one whose click zooms out\n * (default bold) */\n selectedIntervalStyle?: CSSProperties;\n}\n\n/** Timescale and age-window props, ready to spread onto a `Column`. */\nexport interface TimescaleZoomColumnProps {\n showTimescale?: boolean;\n timescaleLevels?: [number, number];\n timescaleIntervalStyle?: IntervalStyleBuilder;\n onClickTimescaleInterval?: TimescaleClickHandler;\n t_age?: number;\n b_age?: number;\n isTransitioning?: boolean;\n}\n\nexport interface TimescaleZoom {\n enabled: boolean;\n /** The rendered age window — `null` when disabled or before the extent is\n * known */\n window: AgeWindow | null;\n /** The drill path: coarse to fine, the last entry being the selection */\n intervals: Interval[];\n selectedInterval: Interval | null;\n /** The timescale the selection was made in, when the click said so */\n selectedTimescaleID: number | null;\n /** Every interval in the selection: the one drilled to, plus any added by\n * shift-clicking. The window spans all of them. */\n selectedIntervals: Interval[];\n /** The levels the timescale should show, following the selection */\n timescaleLevels: [number, number];\n isFullExtent: boolean;\n isAnimating: boolean;\n /** Return to the full extent, clearing the drill path */\n reset(): void;\n zoomToInterval(interval: Interval): void;\n onClickTimescaleInterval: TimescaleClickHandler;\n timescaleIntervalStyle: (interval: Interval) => CSSProperties;\n columnProps: TimescaleZoomColumnProps;\n}\n\nexport function useTimescaleZoom(\n options: UseTimescaleZoomOptions,\n): TimescaleZoom {\n const {\n fullExtent,\n enabled = true,\n levelWindow = LEVEL_WINDOW,\n defaultLevel = DEFAULT_LEVEL,\n minLevel = MIN_TIMESCALE_LEVEL,\n maxLevel = MAX_TIMESCALE_LEVEL,\n duration,\n selectedIntervalStyle = SELECTED_INTERVAL_STYLE,\n } = options;\n\n const anim = useAnimatedAgeWindow({ fullExtent, duration });\n\n // The intervals drilled through; the last one is the current selection\n const [intervals, setIntervals] = useState<Interval[]>([]);\n // Intervals shift-clicked into the selection alongside it\n const [addedIntervals, setAddedIntervals] = useState<Interval[]>([]);\n // Which timescale the selection was made in. The same interval is drawn in\n // every timescale that contains it, and those copies are not the same\n // selection: clicking one in another column moves the selection there.\n const [selectedTimescaleID, setSelectedTimescaleID] = useState<number | null>(\n null,\n );\n const selectedInterval = intervals[intervals.length - 1] ?? null;\n\n const selectedIntervals = useMemo(() => {\n if (selectedInterval == null) return addedIntervals;\n return [selectedInterval, ...addedIntervals];\n }, [selectedInterval, addedIntervals]);\n\n const reset = useCallback(() => {\n setIntervals([]);\n setAddedIntervals([]);\n setSelectedTimescaleID(null);\n anim.reset();\n }, [anim.reset]);\n\n /** Take the interval clicked into (or out of) the selection, and span the\n * result — how you widen a window to the interval next door. */\n const extendToInterval = useCallback(\n (interval: Interval) => {\n let added = addedIntervals.filter((d) => d.oid !== interval.oid);\n const wasSelected = added.length !== addedIntervals.length;\n if (!wasSelected && interval.oid !== selectedInterval?.oid) {\n added = [...addedIntervals, interval];\n }\n setAddedIntervals(added);\n\n let selection = added;\n if (selectedInterval != null) {\n selection = [selectedInterval, ...added];\n }\n if (selection.length === 0) {\n anim.reset();\n return;\n }\n anim.zoomToWindow(intervalsWindow(selection));\n },\n [addedIntervals, selectedInterval, anim.zoomToWindow, anim.reset],\n );\n\n const zoomToInterval = useCallback(\n (interval: Interval, timescaleID: number | null = null) => {\n // Keep only the coarser intervals that actually contain this one, so\n // stepping sideways into a different parent (the last stage of the\n // Cambrian → the first of the Ordovician) doesn't strand the old one\n const containing = intervals.filter(\n (d) =>\n d.lvl < interval.lvl &&\n d.eag >= interval.eag &&\n d.lag <= interval.lag,\n );\n setIntervals([...containing, interval]);\n setAddedIntervals([]);\n setSelectedTimescaleID(timescaleID);\n anim.zoomToInterval(interval);\n },\n [intervals, anim.zoomToInterval],\n );\n\n const onClickTimescaleInterval = useCallback<TimescaleClickHandler>(\n (event: Event, data: TimescaleClickData & { timescaleID?: number }) => {\n const interval = data?.interval;\n if (interval == null || interval.lvl == null) return;\n\n const timescaleID = data.timescaleID ?? null;\n // A click in a different timescale is a different selection, even on the\n // same interval: it moves to that column rather than zooming back out\n const sameTimescale =\n timescaleID == null ||\n selectedTimescaleID == null ||\n timescaleID === selectedTimescaleID;\n\n // Shift-click widens the window instead of moving it, so a selection can\n // grow into the interval next door\n if ((event as MouseEvent)?.shiftKey) {\n extendToInterval(interval);\n return;\n }\n\n // Clicking the interval you are in is the way back out: pop a level, or\n // return to the full extent past the root\n if (interval.oid === selectedInterval?.oid && addedIntervals.length === 0) {\n const next = intervals.slice(0, -1);\n setIntervals(next);\n setSelectedTimescaleID(null);\n const parent = next[next.length - 1] ?? null;\n if (parent == null) {\n anim.reset();\n } else {\n anim.zoomToInterval(parent);\n }\n return;\n }\n\n // Every other click navigates *to* the interval clicked, whatever its\n // rank: a finer one drills in, a neighbor moves along the timescale, a\n // coarser one zooms out to it\n zoomToInterval(interval, timescaleID);\n },\n [\n intervals,\n selectedInterval,\n selectedTimescaleID,\n addedIntervals,\n extendToInterval,\n zoomToInterval,\n anim.reset,\n ],\n );\n\n const timescaleIntervalStyle = useCallback(\n (interval: Interval): CSSProperties => {\n if (selectedIntervals.some((d) => d.oid === interval.oid)) {\n return selectedIntervalStyle;\n }\n return {};\n },\n [selectedIntervals, selectedIntervalStyle],\n );\n\n const levels = useMemo(() => {\n let level = defaultLevel;\n for (const interval of selectedIntervals) {\n if (interval.lvl != null) level = Math.max(level, interval.lvl);\n }\n return levelsForSelected(level, { levelWindow, minLevel, maxLevel });\n }, [selectedIntervals, defaultLevel, levelWindow, minLevel, maxLevel]);\n\n if (!enabled) {\n return {\n ...disabledZoom,\n selectedTimescaleID: null,\n selectedIntervals: [],\n timescaleLevels: levels,\n reset,\n zoomToInterval,\n onClickTimescaleInterval,\n timescaleIntervalStyle,\n };\n }\n\n const window = anim.window ?? fullExtent;\n\n return {\n enabled: true,\n window,\n intervals,\n selectedInterval,\n selectedTimescaleID,\n selectedIntervals,\n timescaleLevels: levels,\n isFullExtent: anim.isFullExtent,\n isAnimating: anim.isAnimating,\n reset,\n zoomToInterval,\n onClickTimescaleInterval,\n timescaleIntervalStyle,\n columnProps: {\n showTimescale: true,\n timescaleLevels: levels,\n timescaleIntervalStyle,\n onClickTimescaleInterval,\n t_age: window?.t_age,\n b_age: window?.b_age,\n isTransitioning: anim.isAnimating,\n },\n };\n}\n\n/** What the hook reports when zooming is switched off: no window, and no\n * props to change how the column renders. */\nconst disabledZoom: Pick<\n TimescaleZoom,\n | \"enabled\"\n | \"window\"\n | \"intervals\"\n | \"selectedInterval\"\n | \"isFullExtent\"\n | \"isAnimating\"\n | \"columnProps\"\n> = {\n enabled: false,\n window: null,\n intervals: [],\n selectedInterval: null,\n isFullExtent: true,\n isAnimating: false,\n columnProps: {},\n};\n\ninterface LevelWindowOptions {\n levelWindow: number;\n minLevel: number;\n maxLevel: number;\n}\n\n/** A fixed window of timescale levels that slides with the selected level —\n * one coarser for context, the rest finer to drill into. Clamped so the\n * useless level 0 is never shown. */\nexport function levelsForSelected(\n selectedLevel: number,\n options: LevelWindowOptions,\n): [number, number] {\n const { levelWindow, minLevel, maxLevel } = options;\n const span = Math.max(levelWindow - 1, 0);\n const lo = Math.min(\n Math.max(selectedLevel - 1, minLevel),\n Math.max(maxLevel - span, minLevel),\n );\n return [lo, lo + span];\n}\n\n/** The window spanning a set of intervals. */\nfunction intervalsWindow(intervals: Interval[]): AgeWindow {\n return {\n t_age: Math.min(...intervals.map((d) => d.lag)),\n b_age: Math.max(...intervals.map((d) => d.eag)),\n };\n}\n\n/** The age extent of a set of units, in the shape the age-window props take.\n * `null` for an empty or absent set. */\nexport function unitsAgeExtent(\n units: { t_age: number; b_age: number }[] | null | undefined,\n): AgeWindow | null {\n if (units == null || units.length === 0) return null;\n return {\n t_age: Math.min(...units.map((d) => d.t_age)),\n b_age: Math.max(...units.map((d) => d.b_age)),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -191,6 +191,7 @@ exports.AgeLabel = AgeLabel;
191
191
  exports.AgeRange = AgeRange;
192
192
  exports.Duration = Duration;
193
193
  exports.IntervalProportions = IntervalProportions;
194
+ exports.Proportion = Proportion;
194
195
  exports.getAge = getAge;
195
196
  exports.getAgeRange = getAgeRange;
196
197
  //# sourceMappingURL=age-range.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"age-range.cjs","sources":["../../src/unit-details/age-range.ts"],"sourcesContent":["import {\n DataField,\n IntervalShort,\n IntervalTag,\n type IntervalTagProps,\n ItemList,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport h from \"./age-range.module.sass\";\nimport { formatProportion, formatRange } from \"./utils\";\nimport classNames from \"classnames\";\nimport { useMemo } from \"react\";\n\nexport function AgeField({ unit, children, ...rest }) {\n const [_b_age, _t_age, _unit] = getAgeRange(unit);\n\n return h(\n DataField,\n {\n label: \"Age\",\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n ...rest,\n },\n children,\n );\n}\n\nexport function AgeRange({\n data,\n className,\n}: {\n data: {\n t_age: number;\n b_age: number;\n };\n className?: string;\n}) {\n const [_b_age, _t_age, _unit] = getAgeRange(data);\n\n return h(Value, {\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n className,\n });\n}\n\nexport function AgeLabel({\n age,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n className,\n}: {\n age: number;\n className?: string;\n maximumFractionDigits?: number;\n minimumFractionDigits?: number;\n}) {\n /** Component to display a single age value with unit conversion from\n * Ma to ka or Ga as appropriate.\n */\n const [value, unit] = getAge(age);\n\n const _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit, className });\n}\n\nexport function Duration({\n value,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n}) {\n let unit = \"Myr\";\n if (value < 0.8) {\n unit = \"kyr\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Gyr\";\n value /= 1000;\n }\n\n let _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit });\n}\n\ninterface UnitIntervalConstraints {\n b_int_id?: number;\n t_int_id?: number;\n b_prop?: number;\n t_prop?: number;\n b_int_name?: string;\n t_int_name?: string;\n b_age?: number;\n t_age?: number;\n}\n\nexport interface IntervalProportionsProps extends Omit<\n IntervalTagProps,\n \"interval\"\n> {\n unit: UnitIntervalConstraints;\n showProportions?: boolean;\n calculateProportionsFromAges?: boolean;\n onClickItem?: any;\n}\n\nexport function IntervalProportions({\n unit,\n className,\n showProportions,\n calculateProportionsFromAges = true,\n ...rest\n}: IntervalProportionsProps) {\n /** Display the proportions of the unit that belong to the base and top intervals, if they are different */\n if (unit.b_int_id == null && unit.t_int_id == null) return null;\n\n let _showProps = showProportions;\n\n const i0 = unit.b_int_id;\n const i1 = unit.t_int_id;\n\n const ints = new Set([i0, i1]);\n\n /** Get interval information */\n const intervalMap = useMacrostratDefs(\"intervals\", Array.from(ints), null);\n const [int0, int1] = useMemo(() => {\n const int0 = intervalMap?.get(i0) ?? {};\n if (i0 === i1) {\n return [int0, int0];\n }\n const int1 = intervalMap?.get(i1) ?? {};\n return [int0, int1];\n }, [intervalMap, i0, i1]);\n\n const interval0: IntervalShort = {\n id: i0,\n name: unit.b_int_name,\n ...int0,\n };\n\n let b_prop = unit.b_prop;\n let t_prop = unit.t_prop;\n\n // If we have b_age and t_age, then we can calculate proportions if they are not given\n if (b_prop == null && unit.b_age != null && calculateProportionsFromAges) {\n b_prop = getProportion(unit.b_age, int0);\n }\n if (t_prop == null && unit.t_age != null && calculateProportionsFromAges) {\n t_prop = getProportion(unit.t_age, int1);\n }\n\n // If there are no proportions given and we are not explicitly directed to show them,\n // then we set them to hidden.\n if (b_prop == null && t_prop == null) {\n _showProps ??= false;\n }\n\n /*\n Set default proportions to 0 and 1 if they are not given,\n so that we can display \"base\" and \"top\" labels\n */\n b_prop ??= 0;\n t_prop ??= 1;\n\n let p0: any = null;\n let p1: any = null;\n\n if (_showProps !== false) {\n p1 = h(Proportion, { value: t_prop });\n\n if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {\n // We have a single interval with undefined proportions\n p0 = h(Proportion, { value: b_prop });\n }\n\n if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {\n p0 = h(\"span.joint-proportion\", [p0, \" \", h(\"span.sep\", \"to\"), \" \", p1]);\n }\n }\n\n return h(\n ItemList,\n { className: classNames(\"interval-proportions\", className) },\n [\n h(IntervalTag, {\n interval: interval0,\n prefix: p0,\n ...rest,\n }),\n h.if(i0 != i1)(\"span.discourage-break\", [\n h(\"span.sep\", \" to \"),\n h(IntervalTag, {\n interval: {\n id: i1,\n name: unit.t_int_name,\n ...int1,\n },\n prefix: p1,\n ...rest,\n }),\n ]),\n ],\n );\n}\n\nfunction getProportion(age: number, interval: IntervalShort): number | null {\n /** Get proportion with the age */\n return (interval.b_age - age) / (interval.b_age - interval.t_age);\n}\n\nfunction Proportion({ value }) {\n let content = null;\n if (value == 0) {\n content = \"base\";\n } else if (value == 1) {\n content = \"top\";\n } else {\n content = formatProportion(value * 100) + \"%\";\n }\n\n return h(\"span.proportion\", content);\n}\n\nexport function getAgeRange(_unit) {\n let b_age = _unit.b_age;\n let t_age = _unit.t_age;\n let unit = \"Ma\";\n\n if (b_age < 0.8 && t_age < 1.2) {\n b_age *= 1000;\n t_age *= 1000;\n unit = \"ka\";\n } else if (b_age > 800 && t_age > 1200) {\n b_age /= 1000;\n t_age /= 1000;\n unit = \"Ga\";\n }\n\n return [b_age, t_age, unit];\n}\n\nexport function getAge(value) {\n /** Get the age value in Ma, ka, or Ga as appropriate */\n let unit = \"Ma\";\n if (value < 0.8) {\n unit = \"ka\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Ga\";\n value /= 1000;\n }\n\n return [value, unit];\n}\n"],"names":["h","DataField","formatRange","Value","useMacrostratDefs","useMemo","int0","int1","ItemList","classNames","IntervalTag","formatProportion"],"mappings":"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"}
1
+ {"version":3,"file":"age-range.cjs","sources":["../../src/unit-details/age-range.ts"],"sourcesContent":["import {\n DataField,\n IntervalShort,\n IntervalTag,\n type IntervalTagProps,\n ItemList,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport h from \"./age-range.module.sass\";\nimport { formatProportion, formatRange } from \"./utils\";\nimport classNames from \"classnames\";\nimport { ReactNode, useMemo } from \"react\";\n\nexport function AgeField({ unit, children, ...rest }) {\n const [_b_age, _t_age, _unit] = getAgeRange(unit);\n\n return h(\n DataField,\n {\n label: \"Age\",\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n ...rest,\n },\n children,\n );\n}\n\nexport function AgeRange({\n data,\n className,\n}: {\n data: {\n t_age: number;\n b_age: number;\n };\n className?: string;\n}) {\n const [_b_age, _t_age, _unit] = getAgeRange(data);\n\n return h(Value, {\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n className,\n });\n}\n\nexport function AgeLabel({\n age,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n className,\n}: {\n age: number;\n className?: string;\n maximumFractionDigits?: number;\n minimumFractionDigits?: number;\n}) {\n /** Component to display a single age value with unit conversion from\n * Ma to ka or Ga as appropriate.\n */\n const [value, unit] = getAge(age);\n\n const _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit, className });\n}\n\nexport function Duration({\n value,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n}) {\n let unit = \"Myr\";\n if (value < 0.8) {\n unit = \"kyr\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Gyr\";\n value /= 1000;\n }\n\n let _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit });\n}\n\ninterface UnitIntervalConstraints {\n b_int_id?: number;\n t_int_id?: number;\n b_prop?: number;\n t_prop?: number;\n b_int_name?: string;\n t_int_name?: string;\n b_age?: number;\n t_age?: number;\n}\n\nexport interface IntervalProportionsProps extends Omit<\n IntervalTagProps,\n \"interval\"\n> {\n unit: UnitIntervalConstraints;\n showProportions?: boolean;\n calculateProportionsFromAges?: boolean;\n onClickItem?: any;\n}\n\nexport function IntervalProportions({\n unit,\n className,\n showProportions,\n calculateProportionsFromAges = true,\n ...rest\n}: IntervalProportionsProps) {\n /** Display the proportions of the unit that belong to the base and top intervals, if they are different */\n if (unit.b_int_id == null && unit.t_int_id == null) return null;\n\n let _showProps = showProportions;\n\n const i0 = unit.b_int_id;\n const i1 = unit.t_int_id;\n\n const ints = new Set([i0, i1]);\n\n /** Get interval information */\n const intervalMap = useMacrostratDefs(\"intervals\", Array.from(ints), null);\n const [int0, int1] = useMemo(() => {\n const int0 = intervalMap?.get(i0) ?? {};\n if (i0 === i1) {\n return [int0, int0];\n }\n const int1 = intervalMap?.get(i1) ?? {};\n return [int0, int1];\n }, [intervalMap, i0, i1]);\n\n const interval0: IntervalShort = {\n id: i0,\n name: unit.b_int_name,\n ...int0,\n };\n\n let b_prop = unit.b_prop;\n let t_prop = unit.t_prop;\n\n // If we have b_age and t_age, then we can calculate proportions if they are not given\n if (b_prop == null && unit.b_age != null && calculateProportionsFromAges) {\n b_prop = getProportion(unit.b_age, int0);\n }\n if (t_prop == null && unit.t_age != null && calculateProportionsFromAges) {\n t_prop = getProportion(unit.t_age, int1);\n }\n\n // If there are no proportions given and we are not explicitly directed to show them,\n // then we set them to hidden.\n if (b_prop == null && t_prop == null) {\n _showProps ??= false;\n }\n\n /*\n Set default proportions to 0 and 1 if they are not given,\n so that we can display \"base\" and \"top\" labels\n */\n b_prop ??= 0;\n t_prop ??= 1;\n\n let p0: any = null;\n let p1: any = null;\n\n if (_showProps !== false) {\n p1 = h(Proportion, { value: t_prop });\n\n if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {\n // We have a single interval with undefined proportions\n p0 = h(Proportion, { value: b_prop });\n }\n\n if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {\n p0 = h(\"span.joint-proportion\", [p0, \" \", h(\"span.sep\", \"to\"), \" \", p1]);\n }\n }\n\n return h(\n ItemList,\n { className: classNames(\"interval-proportions\", className) },\n [\n h(IntervalTag, {\n interval: interval0,\n prefix: p0,\n ...rest,\n }),\n h.if(i0 != i1)(\"span.discourage-break\", [\n h(\"span.sep\", \" to \"),\n h(IntervalTag, {\n interval: {\n id: i1,\n name: unit.t_int_name,\n ...int1,\n },\n prefix: p1,\n ...rest,\n }),\n ]),\n ],\n );\n}\n\nfunction getProportion(age: number, interval: IntervalShort): number | null {\n /** Get proportion with the age */\n return (interval.b_age - age) / (interval.b_age - interval.t_age);\n}\n\nexport function Proportion({ value }: { value: number }) {\n let content: ReactNode | null = null;\n if (value == 0) {\n content = \"base\";\n } else if (value == 1) {\n content = \"top\";\n } else {\n content = formatProportion(value * 100) + \"%\";\n }\n\n return h(\"span.proportion\", content);\n}\n\nexport function getAgeRange(_unit) {\n let b_age = _unit.b_age;\n let t_age = _unit.t_age;\n let unit = \"Ma\";\n\n if (b_age < 0.8 && t_age < 1.2) {\n b_age *= 1000;\n t_age *= 1000;\n unit = \"ka\";\n } else if (b_age > 800 && t_age > 1200) {\n b_age /= 1000;\n t_age /= 1000;\n unit = \"Ga\";\n }\n\n return [b_age, t_age, unit];\n}\n\nexport function getAge(value) {\n /** Get the age value in Ma, ka, or Ga as appropriate */\n let unit = \"Ma\";\n if (value < 0.8) {\n unit = \"ka\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Ga\";\n value /= 1000;\n }\n\n return [value, unit];\n}\n"],"names":["h","DataField","formatRange","Value","useMacrostratDefs","useMemo","int0","int1","ItemList","classNames","IntervalTag","formatProportion"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { IntervalTagProps } from '@macrostrat/data-components';
2
+ import { ReactNode } from 'react';
2
3
  export declare function AgeField({ unit, children, ...rest }: {
3
4
  [x: string]: any;
4
5
  unit: any;
@@ -63,9 +64,12 @@ export interface IntervalProportionsProps extends Omit<IntervalTagProps, "interv
63
64
  onClickItem?: any;
64
65
  }
65
66
  export declare function IntervalProportions({ unit, className, showProportions, calculateProportionsFromAges, ...rest }: IntervalProportionsProps): import('react').FunctionComponentElement<{
66
- children?: import('react').ReactNode;
67
+ children?: ReactNode;
67
68
  className: string;
68
69
  }> | null;
70
+ export declare function Proportion({ value }: {
71
+ value: number;
72
+ }): import('react').DOMElement<import('react').DOMAttributes<Element>, Element>;
69
73
  export declare function getAgeRange(_unit: any): any[];
70
74
  export declare function getAge(value: any): any[];
71
75
  export {};
@@ -188,6 +188,7 @@ export {
188
188
  AgeRange,
189
189
  Duration,
190
190
  IntervalProportions,
191
+ Proportion,
191
192
  getAge,
192
193
  getAgeRange
193
194
  };
@@ -1 +1 @@
1
- {"version":3,"file":"age-range.js","sources":["../../src/unit-details/age-range.ts"],"sourcesContent":["import {\n DataField,\n IntervalShort,\n IntervalTag,\n type IntervalTagProps,\n ItemList,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport h from \"./age-range.module.sass\";\nimport { formatProportion, formatRange } from \"./utils\";\nimport classNames from \"classnames\";\nimport { useMemo } from \"react\";\n\nexport function AgeField({ unit, children, ...rest }) {\n const [_b_age, _t_age, _unit] = getAgeRange(unit);\n\n return h(\n DataField,\n {\n label: \"Age\",\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n ...rest,\n },\n children,\n );\n}\n\nexport function AgeRange({\n data,\n className,\n}: {\n data: {\n t_age: number;\n b_age: number;\n };\n className?: string;\n}) {\n const [_b_age, _t_age, _unit] = getAgeRange(data);\n\n return h(Value, {\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n className,\n });\n}\n\nexport function AgeLabel({\n age,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n className,\n}: {\n age: number;\n className?: string;\n maximumFractionDigits?: number;\n minimumFractionDigits?: number;\n}) {\n /** Component to display a single age value with unit conversion from\n * Ma to ka or Ga as appropriate.\n */\n const [value, unit] = getAge(age);\n\n const _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit, className });\n}\n\nexport function Duration({\n value,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n}) {\n let unit = \"Myr\";\n if (value < 0.8) {\n unit = \"kyr\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Gyr\";\n value /= 1000;\n }\n\n let _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit });\n}\n\ninterface UnitIntervalConstraints {\n b_int_id?: number;\n t_int_id?: number;\n b_prop?: number;\n t_prop?: number;\n b_int_name?: string;\n t_int_name?: string;\n b_age?: number;\n t_age?: number;\n}\n\nexport interface IntervalProportionsProps extends Omit<\n IntervalTagProps,\n \"interval\"\n> {\n unit: UnitIntervalConstraints;\n showProportions?: boolean;\n calculateProportionsFromAges?: boolean;\n onClickItem?: any;\n}\n\nexport function IntervalProportions({\n unit,\n className,\n showProportions,\n calculateProportionsFromAges = true,\n ...rest\n}: IntervalProportionsProps) {\n /** Display the proportions of the unit that belong to the base and top intervals, if they are different */\n if (unit.b_int_id == null && unit.t_int_id == null) return null;\n\n let _showProps = showProportions;\n\n const i0 = unit.b_int_id;\n const i1 = unit.t_int_id;\n\n const ints = new Set([i0, i1]);\n\n /** Get interval information */\n const intervalMap = useMacrostratDefs(\"intervals\", Array.from(ints), null);\n const [int0, int1] = useMemo(() => {\n const int0 = intervalMap?.get(i0) ?? {};\n if (i0 === i1) {\n return [int0, int0];\n }\n const int1 = intervalMap?.get(i1) ?? {};\n return [int0, int1];\n }, [intervalMap, i0, i1]);\n\n const interval0: IntervalShort = {\n id: i0,\n name: unit.b_int_name,\n ...int0,\n };\n\n let b_prop = unit.b_prop;\n let t_prop = unit.t_prop;\n\n // If we have b_age and t_age, then we can calculate proportions if they are not given\n if (b_prop == null && unit.b_age != null && calculateProportionsFromAges) {\n b_prop = getProportion(unit.b_age, int0);\n }\n if (t_prop == null && unit.t_age != null && calculateProportionsFromAges) {\n t_prop = getProportion(unit.t_age, int1);\n }\n\n // If there are no proportions given and we are not explicitly directed to show them,\n // then we set them to hidden.\n if (b_prop == null && t_prop == null) {\n _showProps ??= false;\n }\n\n /*\n Set default proportions to 0 and 1 if they are not given,\n so that we can display \"base\" and \"top\" labels\n */\n b_prop ??= 0;\n t_prop ??= 1;\n\n let p0: any = null;\n let p1: any = null;\n\n if (_showProps !== false) {\n p1 = h(Proportion, { value: t_prop });\n\n if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {\n // We have a single interval with undefined proportions\n p0 = h(Proportion, { value: b_prop });\n }\n\n if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {\n p0 = h(\"span.joint-proportion\", [p0, \" \", h(\"span.sep\", \"to\"), \" \", p1]);\n }\n }\n\n return h(\n ItemList,\n { className: classNames(\"interval-proportions\", className) },\n [\n h(IntervalTag, {\n interval: interval0,\n prefix: p0,\n ...rest,\n }),\n h.if(i0 != i1)(\"span.discourage-break\", [\n h(\"span.sep\", \" to \"),\n h(IntervalTag, {\n interval: {\n id: i1,\n name: unit.t_int_name,\n ...int1,\n },\n prefix: p1,\n ...rest,\n }),\n ]),\n ],\n );\n}\n\nfunction getProportion(age: number, interval: IntervalShort): number | null {\n /** Get proportion with the age */\n return (interval.b_age - age) / (interval.b_age - interval.t_age);\n}\n\nfunction Proportion({ value }) {\n let content = null;\n if (value == 0) {\n content = \"base\";\n } else if (value == 1) {\n content = \"top\";\n } else {\n content = formatProportion(value * 100) + \"%\";\n }\n\n return h(\"span.proportion\", content);\n}\n\nexport function getAgeRange(_unit) {\n let b_age = _unit.b_age;\n let t_age = _unit.t_age;\n let unit = \"Ma\";\n\n if (b_age < 0.8 && t_age < 1.2) {\n b_age *= 1000;\n t_age *= 1000;\n unit = \"ka\";\n } else if (b_age > 800 && t_age > 1200) {\n b_age /= 1000;\n t_age /= 1000;\n unit = \"Ga\";\n }\n\n return [b_age, t_age, unit];\n}\n\nexport function getAge(value) {\n /** Get the age value in Ma, ka, or Ga as appropriate */\n let unit = \"Ma\";\n if (value < 0.8) {\n unit = \"ka\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Ga\";\n value /= 1000;\n }\n\n return [value, unit];\n}\n"],"names":["int0","int1"],"mappings":";;;;;;AAcO,SAAS,SAAS,EAAE,MAAM,UAAU,GAAG,QAAQ;AACpD,QAAM,CAAC,QAAQ,QAAQ,KAAK,IAAI,YAAY,IAAI;AAEhD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO,YAAY,QAAQ,MAAM;AAAA,MACjC,MAAM;AAAA,MACN,GAAG;AAAA,IAAA;AAAA,IAEL;AAAA,EAAA;AAEJ;AAEO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AACF,GAMG;AACD,QAAM,CAAC,QAAQ,QAAQ,KAAK,IAAI,YAAY,IAAI;AAEhD,SAAO,EAAE,OAAO;AAAA,IACd,OAAO,YAAY,QAAQ,MAAM;AAAA,IACjC,MAAM;AAAA,IACN;AAAA,EAAA,CACD;AACH;AAEO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA,wBAAwB;AAAA,EACxB,wBAAwB;AAAA,EACxB;AACF,GAKG;AAID,QAAM,CAAC,OAAO,IAAI,IAAI,OAAO,GAAG;AAEhC,QAAM,SAAS,MAAM,eAAe,SAAS;AAAA,IAC3C;AAAA,IACA;AAAA,EAAA,CACD;AAED,SAAO,EAAE,OAAO,EAAE,OAAO,QAAQ,MAAM,WAAW;AACpD;AAEO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA,wBAAwB;AAAA,EACxB,wBAAwB;AAC1B,GAAG;AACD,MAAI,OAAO;AACX,MAAI,QAAQ,KAAK;AACf,WAAO;AACP,aAAS;AACT,QAAI,QAAQ,GAAG;AACb,aAAO;AACP,eAAS;AAAA,IACX;AAAA,EACF,WAAW,QAAQ,KAAM;AACvB,WAAO;AACP,aAAS;AAAA,EACX;AAEA,MAAI,SAAS,MAAM,eAAe,SAAS;AAAA,IACzC;AAAA,IACA;AAAA,EAAA,CACD;AAED,SAAO,EAAE,OAAO,EAAE,OAAO,QAAQ,MAAM;AACzC;AAuBO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA,+BAA+B;AAAA,EAC/B,GAAG;AACL,GAA6B;AAE3B,MAAI,KAAK,YAAY,QAAQ,KAAK,YAAY,KAAM,QAAO;AAE3D,MAAI,aAAa;AAEjB,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,KAAK;AAEhB,QAAM,OAAO,oBAAI,IAAI,CAAC,IAAI,EAAE,CAAC;AAG7B,QAAM,cAAc,kBAAkB,aAAa,MAAM,KAAK,IAAI,GAAG,IAAI;AACzE,QAAM,CAAC,MAAM,IAAI,IAAI,QAAQ,MAAM;AACjC,UAAMA,QAAO,aAAa,IAAI,EAAE,KAAK,CAAA;AACrC,QAAI,OAAO,IAAI;AACb,aAAO,CAACA,OAAMA,KAAI;AAAA,IACpB;AACA,UAAMC,QAAO,aAAa,IAAI,EAAE,KAAK,CAAA;AACrC,WAAO,CAACD,OAAMC,KAAI;AAAA,EACpB,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;AAExB,QAAM,YAA2B;AAAA,IAC/B,IAAI;AAAA,IACJ,MAAM,KAAK;AAAA,IACX,GAAG;AAAA,EAAA;AAGL,MAAI,SAAS,KAAK;AAClB,MAAI,SAAS,KAAK;AAGlB,MAAI,UAAU,QAAQ,KAAK,SAAS,QAAQ,8BAA8B;AACxE,aAAS,cAAc,KAAK,OAAO,IAAI;AAAA,EACzC;AACA,MAAI,UAAU,QAAQ,KAAK,SAAS,QAAQ,8BAA8B;AACxE,aAAS,cAAc,KAAK,OAAO,IAAI;AAAA,EACzC;AAIA,MAAI,UAAU,QAAQ,UAAU,MAAM;AACpC,mBAAe;AAAA,EACjB;AAMA,aAAW;AACX,aAAW;AAEX,MAAI,KAAU;AACd,MAAI,KAAU;AAEd,MAAI,eAAe,OAAO;AACxB,SAAK,EAAE,YAAY,EAAE,OAAO,QAAQ;AAEpC,QAAI,OAAO,MAAM,WAAW,KAAK,WAAW,GAAG;AAE7C,WAAK,EAAE,YAAY,EAAE,OAAO,QAAQ;AAAA,IACtC;AAEA,QAAI,OAAO,OAAO,WAAW,KAAK,WAAW,IAAI;AAC/C,WAAK,EAAE,yBAAyB,CAAC,IAAI,KAAK,EAAE,YAAY,IAAI,GAAG,KAAK,EAAE,CAAC;AAAA,IACzE;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,EAAE,WAAW,WAAW,wBAAwB,SAAS,EAAA;AAAA,IACzD;AAAA,MACE,EAAE,aAAa;AAAA,QACb,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,GAAG;AAAA,MAAA,CACJ;AAAA,MACD,EAAE,GAAG,MAAM,EAAE,EAAE,yBAAyB;AAAA,QACtC,EAAE,YAAY,MAAM;AAAA,QACpB,EAAE,aAAa;AAAA,UACb,UAAU;AAAA,YACR,IAAI;AAAA,YACJ,MAAM,KAAK;AAAA,YACX,GAAG;AAAA,UAAA;AAAA,UAEL,QAAQ;AAAA,UACR,GAAG;AAAA,QAAA,CACJ;AAAA,MAAA,CACF;AAAA,IAAA;AAAA,EACH;AAEJ;AAEA,SAAS,cAAc,KAAa,UAAwC;AAE1E,UAAQ,SAAS,QAAQ,QAAQ,SAAS,QAAQ,SAAS;AAC7D;AAEA,SAAS,WAAW,EAAE,SAAS;AAC7B,MAAI,UAAU;AACd,MAAI,SAAS,GAAG;AACd,cAAU;AAAA,EACZ,WAAW,SAAS,GAAG;AACrB,cAAU;AAAA,EACZ,OAAO;AACL,cAAU,iBAAiB,QAAQ,GAAG,IAAI;AAAA,EAC5C;AAEA,SAAO,EAAE,mBAAmB,OAAO;AACrC;AAEO,SAAS,YAAY,OAAO;AACjC,MAAI,QAAQ,MAAM;AAClB,MAAI,QAAQ,MAAM;AAClB,MAAI,OAAO;AAEX,MAAI,QAAQ,OAAO,QAAQ,KAAK;AAC9B,aAAS;AACT,aAAS;AACT,WAAO;AAAA,EACT,WAAW,QAAQ,OAAO,QAAQ,MAAM;AACtC,aAAS;AACT,aAAS;AACT,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,OAAO,OAAO,IAAI;AAC5B;AAEO,SAAS,OAAO,OAAO;AAE5B,MAAI,OAAO;AACX,MAAI,QAAQ,KAAK;AACf,WAAO;AACP,aAAS;AACT,QAAI,QAAQ,GAAG;AACb,aAAO;AACP,eAAS;AAAA,IACX;AAAA,EACF,WAAW,QAAQ,KAAM;AACvB,WAAO;AACP,aAAS;AAAA,EACX;AAEA,SAAO,CAAC,OAAO,IAAI;AACrB;"}
1
+ {"version":3,"file":"age-range.js","sources":["../../src/unit-details/age-range.ts"],"sourcesContent":["import {\n DataField,\n IntervalShort,\n IntervalTag,\n type IntervalTagProps,\n ItemList,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport h from \"./age-range.module.sass\";\nimport { formatProportion, formatRange } from \"./utils\";\nimport classNames from \"classnames\";\nimport { ReactNode, useMemo } from \"react\";\n\nexport function AgeField({ unit, children, ...rest }) {\n const [_b_age, _t_age, _unit] = getAgeRange(unit);\n\n return h(\n DataField,\n {\n label: \"Age\",\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n ...rest,\n },\n children,\n );\n}\n\nexport function AgeRange({\n data,\n className,\n}: {\n data: {\n t_age: number;\n b_age: number;\n };\n className?: string;\n}) {\n const [_b_age, _t_age, _unit] = getAgeRange(data);\n\n return h(Value, {\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n className,\n });\n}\n\nexport function AgeLabel({\n age,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n className,\n}: {\n age: number;\n className?: string;\n maximumFractionDigits?: number;\n minimumFractionDigits?: number;\n}) {\n /** Component to display a single age value with unit conversion from\n * Ma to ka or Ga as appropriate.\n */\n const [value, unit] = getAge(age);\n\n const _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit, className });\n}\n\nexport function Duration({\n value,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n}) {\n let unit = \"Myr\";\n if (value < 0.8) {\n unit = \"kyr\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Gyr\";\n value /= 1000;\n }\n\n let _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit });\n}\n\ninterface UnitIntervalConstraints {\n b_int_id?: number;\n t_int_id?: number;\n b_prop?: number;\n t_prop?: number;\n b_int_name?: string;\n t_int_name?: string;\n b_age?: number;\n t_age?: number;\n}\n\nexport interface IntervalProportionsProps extends Omit<\n IntervalTagProps,\n \"interval\"\n> {\n unit: UnitIntervalConstraints;\n showProportions?: boolean;\n calculateProportionsFromAges?: boolean;\n onClickItem?: any;\n}\n\nexport function IntervalProportions({\n unit,\n className,\n showProportions,\n calculateProportionsFromAges = true,\n ...rest\n}: IntervalProportionsProps) {\n /** Display the proportions of the unit that belong to the base and top intervals, if they are different */\n if (unit.b_int_id == null && unit.t_int_id == null) return null;\n\n let _showProps = showProportions;\n\n const i0 = unit.b_int_id;\n const i1 = unit.t_int_id;\n\n const ints = new Set([i0, i1]);\n\n /** Get interval information */\n const intervalMap = useMacrostratDefs(\"intervals\", Array.from(ints), null);\n const [int0, int1] = useMemo(() => {\n const int0 = intervalMap?.get(i0) ?? {};\n if (i0 === i1) {\n return [int0, int0];\n }\n const int1 = intervalMap?.get(i1) ?? {};\n return [int0, int1];\n }, [intervalMap, i0, i1]);\n\n const interval0: IntervalShort = {\n id: i0,\n name: unit.b_int_name,\n ...int0,\n };\n\n let b_prop = unit.b_prop;\n let t_prop = unit.t_prop;\n\n // If we have b_age and t_age, then we can calculate proportions if they are not given\n if (b_prop == null && unit.b_age != null && calculateProportionsFromAges) {\n b_prop = getProportion(unit.b_age, int0);\n }\n if (t_prop == null && unit.t_age != null && calculateProportionsFromAges) {\n t_prop = getProportion(unit.t_age, int1);\n }\n\n // If there are no proportions given and we are not explicitly directed to show them,\n // then we set them to hidden.\n if (b_prop == null && t_prop == null) {\n _showProps ??= false;\n }\n\n /*\n Set default proportions to 0 and 1 if they are not given,\n so that we can display \"base\" and \"top\" labels\n */\n b_prop ??= 0;\n t_prop ??= 1;\n\n let p0: any = null;\n let p1: any = null;\n\n if (_showProps !== false) {\n p1 = h(Proportion, { value: t_prop });\n\n if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {\n // We have a single interval with undefined proportions\n p0 = h(Proportion, { value: b_prop });\n }\n\n if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {\n p0 = h(\"span.joint-proportion\", [p0, \" \", h(\"span.sep\", \"to\"), \" \", p1]);\n }\n }\n\n return h(\n ItemList,\n { className: classNames(\"interval-proportions\", className) },\n [\n h(IntervalTag, {\n interval: interval0,\n prefix: p0,\n ...rest,\n }),\n h.if(i0 != i1)(\"span.discourage-break\", [\n h(\"span.sep\", \" to \"),\n h(IntervalTag, {\n interval: {\n id: i1,\n name: unit.t_int_name,\n ...int1,\n },\n prefix: p1,\n ...rest,\n }),\n ]),\n ],\n );\n}\n\nfunction getProportion(age: number, interval: IntervalShort): number | null {\n /** Get proportion with the age */\n return (interval.b_age - age) / (interval.b_age - interval.t_age);\n}\n\nexport function Proportion({ value }: { value: number }) {\n let content: ReactNode | null = null;\n if (value == 0) {\n content = \"base\";\n } else if (value == 1) {\n content = \"top\";\n } else {\n content = formatProportion(value * 100) + \"%\";\n }\n\n return h(\"span.proportion\", content);\n}\n\nexport function getAgeRange(_unit) {\n let b_age = _unit.b_age;\n let t_age = _unit.t_age;\n let unit = \"Ma\";\n\n if (b_age < 0.8 && t_age < 1.2) {\n b_age *= 1000;\n t_age *= 1000;\n unit = \"ka\";\n } else if (b_age > 800 && t_age > 1200) {\n b_age /= 1000;\n t_age /= 1000;\n unit = \"Ga\";\n }\n\n return [b_age, t_age, unit];\n}\n\nexport function getAge(value) {\n /** Get the age value in Ma, ka, or Ga as appropriate */\n let unit = \"Ma\";\n if (value < 0.8) {\n unit = \"ka\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Ga\";\n value /= 1000;\n }\n\n return [value, unit];\n}\n"],"names":["int0","int1"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const core = require("@blueprintjs/core");
4
+ const dataComponents = require("@macrostrat/data-components");
5
+ const classNames = require("classnames");
6
+ const ageWindowTag_module = require("./age-window-tag.module.sass.cjs");
7
+ const ageRange = require("./age-range.cjs");
8
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
9
+ const classNames__default = /* @__PURE__ */ _interopDefault(classNames);
10
+ function intervalShortFromTimescale(interval) {
11
+ return {
12
+ id: interval.int_id ?? interval.oid,
13
+ name: interval.nam,
14
+ color: interval.col,
15
+ b_age: interval.eag,
16
+ t_age: interval.lag,
17
+ rank: interval.lvl
18
+ };
19
+ }
20
+ function AgeWindowTag(props) {
21
+ const {
22
+ interval = null,
23
+ window = null,
24
+ onClear,
25
+ size = dataComponents.TagSize.Small,
26
+ className
27
+ } = props;
28
+ if (interval == null && window == null) return null;
29
+ let tag = null;
30
+ if (interval == null) {
31
+ tag = ageWindowTag_module(dataComponents.Tag, { size, name: ageWindowTag_module(ageRange.AgeRange, { data: window }) });
32
+ } else if (window == null || windowMatchesInterval(window, interval)) {
33
+ tag = ageWindowTag_module(dataComponents.IntervalTag, { interval, showAgeRange: true, size });
34
+ } else {
35
+ tag = ageWindowTag_module(RefinedIntervalTag, { interval, window, size });
36
+ }
37
+ return ageWindowTag_module("span.age-window-tag", { className: classNames__default.default(className) }, [
38
+ tag,
39
+ ageWindowTag_module.if(onClear != null)(core.Button, {
40
+ className: "clear-button",
41
+ icon: "cross",
42
+ minimal: true,
43
+ small: true,
44
+ title: "Clear",
45
+ onClick: onClear
46
+ })
47
+ ]);
48
+ }
49
+ function RefinedIntervalTag({
50
+ interval,
51
+ window,
52
+ size
53
+ }) {
54
+ const interaction = dataComponents.useInteractionProps({ int_id: interval.id });
55
+ return ageWindowTag_module(dataComponents.Tag, {
56
+ ...interaction,
57
+ size,
58
+ name: interval.name,
59
+ color: interval.color,
60
+ details: ageWindowTag_module(ageRange.AgeRange, { data: window })
61
+ });
62
+ }
63
+ function windowMatchesInterval(window, interval) {
64
+ return window.t_age === interval.t_age && window.b_age === interval.b_age;
65
+ }
66
+ exports.AgeWindowTag = AgeWindowTag;
67
+ exports.intervalShortFromTimescale = intervalShortFromTimescale;
68
+ //# sourceMappingURL=age-window-tag.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age-window-tag.cjs","sources":["../../src/unit-details/age-window-tag.ts"],"sourcesContent":["import { Button } from \"@blueprintjs/core\";\nimport {\n IntervalShort,\n IntervalTag,\n Tag,\n TagSize,\n useInteractionProps,\n} from \"@macrostrat/data-components\";\nimport type { Interval } from \"@macrostrat/timescale\";\nimport classNames from \"classnames\";\nimport h from \"./age-window-tag.module.sass\";\nimport { AgeRange } from \"./age-range\";\nimport type { AgeWindow } from \"../animated-age-window\";\n\n/** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with\n * `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components\n * take. The id prefers the Macrostrat `int_id` when the interval tree was built\n * from the API, falling back to the interval's own `oid`. */\nexport function intervalShortFromTimescale(interval: Interval): IntervalShort {\n return {\n id: interval.int_id ?? interval.oid,\n name: interval.nam,\n color: interval.col,\n b_age: interval.eag,\n t_age: interval.lag,\n rank: interval.lvl,\n };\n}\n\nexport interface AgeWindowTagProps {\n /** The interval the window was set from, if any. */\n interval?: IntervalShort | null;\n /** The rendered window. When it differs from the interval's own span (a\n * refined window) it is shown in place of the interval's range. */\n window?: AgeWindow | null;\n /** Renders a clear button when given. */\n onClear?: () => void;\n size?: TagSize;\n className?: string;\n}\n\n/** A compact, clearable indicator of the age window a column or correlation\n * chart is focused on — an interval tag (linking to the interval, with its\n * range) or a bare age range. Renders nothing without an interval or window,\n * so it can live permanently in a chart's `axisTopContent`. */\nexport function AgeWindowTag(props: AgeWindowTagProps) {\n const {\n interval = null,\n window = null,\n onClear,\n size = TagSize.Small,\n className,\n } = props;\n if (interval == null && window == null) return null;\n\n let tag = null;\n if (interval == null) {\n tag = h(Tag, { size, name: h(AgeRange, { data: window }) });\n } else if (window == null || windowMatchesInterval(window, interval)) {\n tag = h(IntervalTag, { interval, showAgeRange: true, size });\n } else {\n tag = h(RefinedIntervalTag, { interval, window, size });\n }\n\n return h(\"span.age-window-tag\", { className: classNames(className) }, [\n tag,\n h.if(onClear != null)(Button, {\n className: \"clear-button\",\n icon: \"cross\",\n minimal: true,\n small: true,\n title: \"Clear\",\n onClick: onClear,\n }),\n ]);\n}\n\nfunction RefinedIntervalTag({\n interval,\n window,\n size,\n}: {\n interval: IntervalShort;\n window: AgeWindow;\n size: TagSize;\n}) {\n const interaction = useInteractionProps({ int_id: interval.id });\n return h(Tag, {\n ...interaction,\n size,\n name: interval.name,\n color: interval.color,\n details: h(AgeRange, { data: window }),\n });\n}\n\nfunction windowMatchesInterval(\n window: AgeWindow,\n interval: IntervalShort,\n): boolean {\n return window.t_age === interval.t_age && window.b_age === interval.b_age;\n}\n"],"names":["TagSize","h","Tag","AgeRange","IntervalTag","classNames","Button","useInteractionProps"],"mappings":";;;;;;;;;AAkBO,SAAS,2BAA2B,UAAmC;AAC5E,SAAO;AAAA,IACL,IAAI,SAAS,UAAU,SAAS;AAAA,IAChC,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,MAAM,SAAS;AAAA,EAAA;AAEnB;AAkBO,SAAS,aAAa,OAA0B;AACrD,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,SAAS;AAAA,IACT;AAAA,IACA,OAAOA,eAAAA,QAAQ;AAAA,IACf;AAAA,EAAA,IACE;AACJ,MAAI,YAAY,QAAQ,UAAU,KAAM,QAAO;AAE/C,MAAI,MAAM;AACV,MAAI,YAAY,MAAM;AACpB,UAAMC,oBAAEC,oBAAK,EAAE,MAAM,MAAMD,oBAAEE,SAAAA,UAAU,EAAE,MAAM,OAAA,CAAQ,EAAA,CAAG;AAAA,EAC5D,WAAW,UAAU,QAAQ,sBAAsB,QAAQ,QAAQ,GAAG;AACpE,UAAMF,oBAAEG,4BAAa,EAAE,UAAU,cAAc,MAAM,MAAM;AAAA,EAC7D,OAAO;AACL,UAAMH,oBAAE,oBAAoB,EAAE,UAAU,QAAQ,MAAM;AAAA,EACxD;AAEA,SAAOA,oBAAE,uBAAuB,EAAE,WAAWI,oBAAAA,QAAW,SAAS,KAAK;AAAA,IACpE;AAAA,IACAJ,oBAAE,GAAG,WAAW,IAAI,EAAEK,KAAAA,QAAQ;AAAA,MAC5B,WAAW;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IAAA,CACV;AAAA,EAAA,CACF;AACH;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,cAAcC,eAAAA,oBAAoB,EAAE,QAAQ,SAAS,IAAI;AAC/D,SAAON,oBAAEC,eAAAA,KAAK;AAAA,IACZ,GAAG;AAAA,IACH;AAAA,IACA,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,SAASD,oBAAEE,SAAAA,UAAU,EAAE,MAAM,QAAQ;AAAA,EAAA,CACtC;AACH;AAEA,SAAS,sBACP,QACA,UACS;AACT,SAAO,OAAO,UAAU,SAAS,SAAS,OAAO,UAAU,SAAS;AACtE;;;"}
@@ -0,0 +1,26 @@
1
+ import { IntervalShort, TagSize } from '@macrostrat/data-components';
2
+ import { Interval } from '@macrostrat/timescale';
3
+ import { AgeWindow } from '../animated-age-window';
4
+ /** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with
5
+ * `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components
6
+ * take. The id prefers the Macrostrat `int_id` when the interval tree was built
7
+ * from the API, falling back to the interval's own `oid`. */
8
+ export declare function intervalShortFromTimescale(interval: Interval): IntervalShort;
9
+ export interface AgeWindowTagProps {
10
+ /** The interval the window was set from, if any. */
11
+ interval?: IntervalShort | null;
12
+ /** The rendered window. When it differs from the interval's own span (a
13
+ * refined window) it is shown in place of the interval's range. */
14
+ window?: AgeWindow | null;
15
+ /** Renders a clear button when given. */
16
+ onClear?: () => void;
17
+ size?: TagSize;
18
+ className?: string;
19
+ }
20
+ /** A compact, clearable indicator of the age window a column or correlation
21
+ * chart is focused on — an interval tag (linking to the interval, with its
22
+ * range) or a bare age range. Renders nothing without an interval or window,
23
+ * so it can live permanently in a chart's `axisTopContent`. */
24
+ export declare function AgeWindowTag(props: AgeWindowTagProps): import('react').ReactElement<{
25
+ className: string;
26
+ }, string | import('react').JSXElementConstructor<any>> | null;
@@ -0,0 +1,66 @@
1
+ import { Button } from "@blueprintjs/core";
2
+ import { TagSize, Tag, IntervalTag, useInteractionProps } from "@macrostrat/data-components";
3
+ import classNames from "classnames";
4
+ import h from "./age-window-tag.module.sass.js";
5
+ import { AgeRange } from "./age-range.js";
6
+ function intervalShortFromTimescale(interval) {
7
+ return {
8
+ id: interval.int_id ?? interval.oid,
9
+ name: interval.nam,
10
+ color: interval.col,
11
+ b_age: interval.eag,
12
+ t_age: interval.lag,
13
+ rank: interval.lvl
14
+ };
15
+ }
16
+ function AgeWindowTag(props) {
17
+ const {
18
+ interval = null,
19
+ window = null,
20
+ onClear,
21
+ size = TagSize.Small,
22
+ className
23
+ } = props;
24
+ if (interval == null && window == null) return null;
25
+ let tag = null;
26
+ if (interval == null) {
27
+ tag = h(Tag, { size, name: h(AgeRange, { data: window }) });
28
+ } else if (window == null || windowMatchesInterval(window, interval)) {
29
+ tag = h(IntervalTag, { interval, showAgeRange: true, size });
30
+ } else {
31
+ tag = h(RefinedIntervalTag, { interval, window, size });
32
+ }
33
+ return h("span.age-window-tag", { className: classNames(className) }, [
34
+ tag,
35
+ h.if(onClear != null)(Button, {
36
+ className: "clear-button",
37
+ icon: "cross",
38
+ minimal: true,
39
+ small: true,
40
+ title: "Clear",
41
+ onClick: onClear
42
+ })
43
+ ]);
44
+ }
45
+ function RefinedIntervalTag({
46
+ interval,
47
+ window,
48
+ size
49
+ }) {
50
+ const interaction = useInteractionProps({ int_id: interval.id });
51
+ return h(Tag, {
52
+ ...interaction,
53
+ size,
54
+ name: interval.name,
55
+ color: interval.color,
56
+ details: h(AgeRange, { data: window })
57
+ });
58
+ }
59
+ function windowMatchesInterval(window, interval) {
60
+ return window.t_age === interval.t_age && window.b_age === interval.b_age;
61
+ }
62
+ export {
63
+ AgeWindowTag,
64
+ intervalShortFromTimescale
65
+ };
66
+ //# sourceMappingURL=age-window-tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age-window-tag.js","sources":["../../src/unit-details/age-window-tag.ts"],"sourcesContent":["import { Button } from \"@blueprintjs/core\";\nimport {\n IntervalShort,\n IntervalTag,\n Tag,\n TagSize,\n useInteractionProps,\n} from \"@macrostrat/data-components\";\nimport type { Interval } from \"@macrostrat/timescale\";\nimport classNames from \"classnames\";\nimport h from \"./age-window-tag.module.sass\";\nimport { AgeRange } from \"./age-range\";\nimport type { AgeWindow } from \"../animated-age-window\";\n\n/** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with\n * `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components\n * take. The id prefers the Macrostrat `int_id` when the interval tree was built\n * from the API, falling back to the interval's own `oid`. */\nexport function intervalShortFromTimescale(interval: Interval): IntervalShort {\n return {\n id: interval.int_id ?? interval.oid,\n name: interval.nam,\n color: interval.col,\n b_age: interval.eag,\n t_age: interval.lag,\n rank: interval.lvl,\n };\n}\n\nexport interface AgeWindowTagProps {\n /** The interval the window was set from, if any. */\n interval?: IntervalShort | null;\n /** The rendered window. When it differs from the interval's own span (a\n * refined window) it is shown in place of the interval's range. */\n window?: AgeWindow | null;\n /** Renders a clear button when given. */\n onClear?: () => void;\n size?: TagSize;\n className?: string;\n}\n\n/** A compact, clearable indicator of the age window a column or correlation\n * chart is focused on — an interval tag (linking to the interval, with its\n * range) or a bare age range. Renders nothing without an interval or window,\n * so it can live permanently in a chart's `axisTopContent`. */\nexport function AgeWindowTag(props: AgeWindowTagProps) {\n const {\n interval = null,\n window = null,\n onClear,\n size = TagSize.Small,\n className,\n } = props;\n if (interval == null && window == null) return null;\n\n let tag = null;\n if (interval == null) {\n tag = h(Tag, { size, name: h(AgeRange, { data: window }) });\n } else if (window == null || windowMatchesInterval(window, interval)) {\n tag = h(IntervalTag, { interval, showAgeRange: true, size });\n } else {\n tag = h(RefinedIntervalTag, { interval, window, size });\n }\n\n return h(\"span.age-window-tag\", { className: classNames(className) }, [\n tag,\n h.if(onClear != null)(Button, {\n className: \"clear-button\",\n icon: \"cross\",\n minimal: true,\n small: true,\n title: \"Clear\",\n onClick: onClear,\n }),\n ]);\n}\n\nfunction RefinedIntervalTag({\n interval,\n window,\n size,\n}: {\n interval: IntervalShort;\n window: AgeWindow;\n size: TagSize;\n}) {\n const interaction = useInteractionProps({ int_id: interval.id });\n return h(Tag, {\n ...interaction,\n size,\n name: interval.name,\n color: interval.color,\n details: h(AgeRange, { data: window }),\n });\n}\n\nfunction windowMatchesInterval(\n window: AgeWindow,\n interval: IntervalShort,\n): boolean {\n return window.t_age === interval.t_age && window.b_age === interval.b_age;\n}\n"],"names":[],"mappings":";;;;;AAkBO,SAAS,2BAA2B,UAAmC;AAC5E,SAAO;AAAA,IACL,IAAI,SAAS,UAAU,SAAS;AAAA,IAChC,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,MAAM,SAAS;AAAA,EAAA;AAEnB;AAkBO,SAAS,aAAa,OAA0B;AACrD,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,SAAS;AAAA,IACT;AAAA,IACA,OAAO,QAAQ;AAAA,IACf;AAAA,EAAA,IACE;AACJ,MAAI,YAAY,QAAQ,UAAU,KAAM,QAAO;AAE/C,MAAI,MAAM;AACV,MAAI,YAAY,MAAM;AACpB,UAAM,EAAE,KAAK,EAAE,MAAM,MAAM,EAAE,UAAU,EAAE,MAAM,OAAA,CAAQ,EAAA,CAAG;AAAA,EAC5D,WAAW,UAAU,QAAQ,sBAAsB,QAAQ,QAAQ,GAAG;AACpE,UAAM,EAAE,aAAa,EAAE,UAAU,cAAc,MAAM,MAAM;AAAA,EAC7D,OAAO;AACL,UAAM,EAAE,oBAAoB,EAAE,UAAU,QAAQ,MAAM;AAAA,EACxD;AAEA,SAAO,EAAE,uBAAuB,EAAE,WAAW,WAAW,SAAS,KAAK;AAAA,IACpE;AAAA,IACA,EAAE,GAAG,WAAW,IAAI,EAAE,QAAQ;AAAA,MAC5B,WAAW;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IAAA,CACV;AAAA,EAAA,CACF;AACH;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,cAAc,oBAAoB,EAAE,QAAQ,SAAS,IAAI;AAC/D,SAAO,EAAE,KAAK;AAAA,IACZ,GAAG;AAAA,IACH;AAAA,IACA,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ;AAAA,EAAA,CACtC;AACH;AAEA,SAAS,sBACP,QACA,UACS;AACT,SAAO,OAAO,UAAU,SAAS,SAAS,OAAO,UAAU,SAAS;AACtE;"}
@@ -3,10 +3,10 @@ const h$1 = require("@macrostrat/hyper");
3
3
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
4
4
  const h__default = /* @__PURE__ */ _interopDefault(h$1);
5
5
  const styles = {
6
- "boundary-age-model": "_boundary-age-model_16scl_1",
7
- "boundary-age-model-surface": "_boundary-age-model-surface_16scl_8"
6
+ "age-window-tag": "_age-window-tag_1tskh_1",
7
+ "clear-button": "_clear-button_1tskh_8"
8
8
  };
9
9
  let h = h__default.default.styled(styles);
10
10
  Object.assign(h, styles);
11
11
  module.exports = h;
12
- //# sourceMappingURL=age-model-overlay.module.sass.cjs.map
12
+ //# sourceMappingURL=age-window-tag.module.sass.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age-window-tag.module.sass.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
@@ -0,0 +1,11 @@
1
+ import h$1 from "@macrostrat/hyper";
2
+ const styles = {
3
+ "age-window-tag": "_age-window-tag_1tskh_1",
4
+ "clear-button": "_clear-button_1tskh_8"
5
+ };
6
+ let h = h$1.styled(styles);
7
+ Object.assign(h, styles);
8
+ export {
9
+ h as default
10
+ };
11
+ //# sourceMappingURL=age-window-tag.module.sass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"age-window-tag.module.sass.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
@@ -2,5 +2,6 @@ export * from './panel';
2
2
  export * from './popover';
3
3
  export * from './modal-panel';
4
4
  export * from './age-range';
5
+ export * from './age-window-tag';
5
6
  export * from './strat-names';
6
7
  export { ClickableText, Identifier, UnitIdentifier, } from '@macrostrat/data-components';
@@ -83,13 +83,15 @@ function AnnotatedUnitsColumn(props) {
83
83
  }, []);
84
84
  return null;
85
85
  }
86
+ const DEFAULT_LABEL_SUPPRESS_HEIGHT = 2;
86
87
  function SectionLabelsColumn(props) {
87
88
  const {
88
89
  width = 300,
89
90
  noteMode = "unlabeled",
90
91
  labelOffset = 30,
91
92
  noteComponent,
92
- shouldRenderNote
93
+ shouldRenderNote,
94
+ labelSuppressHeight = DEFAULT_LABEL_SUPPRESS_HEIGHT
93
95
  } = props;
94
96
  const { totalHeight, axisType } = store.useMacrostratColumnData();
95
97
  const _compositeScale = store.useCompositeScale();
@@ -117,6 +119,7 @@ function SectionLabelsColumn(props) {
117
119
  divisions: unitsToLabel,
118
120
  paddingLeft: labelOffset,
119
121
  width,
122
+ minimumHeight: labelSuppressHeight,
120
123
  noteComponent,
121
124
  shouldRenderNote,
122
125
  scale: _compositeScale,