@macrostrat/column-views 3.11.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 (130) hide show
  1. package/CHANGELOG.md +169 -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 +389 -57
  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/data-provider/store.cjs +34 -1
  47. package/dist/data-provider/store.cjs.map +1 -1
  48. package/dist/data-provider/store.d.ts +5 -0
  49. package/dist/data-provider/store.js +35 -2
  50. package/dist/data-provider/store.js.map +1 -1
  51. package/dist/index.cjs +54 -3
  52. package/dist/index.cjs.map +1 -1
  53. package/dist/index.d.ts +3 -1
  54. package/dist/index.js +54 -3
  55. package/dist/index.js.map +1 -1
  56. package/dist/notes.cjs +11 -2
  57. package/dist/notes.cjs.map +1 -1
  58. package/dist/notes.d.ts +11 -1
  59. package/dist/notes.js +11 -2
  60. package/dist/notes.js.map +1 -1
  61. package/dist/prepare-units/composite-scale.cjs +18 -16
  62. package/dist/prepare-units/composite-scale.cjs.map +1 -1
  63. package/dist/prepare-units/composite-scale.js +18 -16
  64. package/dist/prepare-units/composite-scale.js.map +1 -1
  65. package/dist/prepare-units/density.cjs +83 -0
  66. package/dist/prepare-units/density.cjs.map +1 -0
  67. package/dist/prepare-units/density.d.ts +92 -0
  68. package/dist/prepare-units/density.js +83 -0
  69. package/dist/prepare-units/density.js.map +1 -0
  70. package/dist/prepare-units/index.cjs +15 -7
  71. package/dist/prepare-units/index.cjs.map +1 -1
  72. package/dist/prepare-units/index.d.ts +1 -0
  73. package/dist/prepare-units/index.js +15 -7
  74. package/dist/prepare-units/index.js.map +1 -1
  75. package/dist/prepare-units/types.cjs.map +1 -1
  76. package/dist/prepare-units/types.d.ts +34 -13
  77. package/dist/prepare-units/types.js.map +1 -1
  78. package/dist/section.cjs +108 -24
  79. package/dist/section.cjs.map +1 -1
  80. package/dist/section.d.ts +66 -6
  81. package/dist/section.js +109 -25
  82. package/dist/section.js.map +1 -1
  83. package/dist/timescale-zoom.cjs +191 -0
  84. package/dist/timescale-zoom.cjs.map +1 -0
  85. package/dist/timescale-zoom.d.ts +74 -0
  86. package/dist/timescale-zoom.js +191 -0
  87. package/dist/timescale-zoom.js.map +1 -0
  88. package/dist/unit-details/age-range.cjs +1 -0
  89. package/dist/unit-details/age-range.cjs.map +1 -1
  90. package/dist/unit-details/age-range.d.ts +5 -1
  91. package/dist/unit-details/age-range.js +1 -0
  92. package/dist/unit-details/age-range.js.map +1 -1
  93. package/dist/units/composite.cjs +4 -1
  94. package/dist/units/composite.cjs.map +1 -1
  95. package/dist/units/composite.d.ts +2 -0
  96. package/dist/units/composite.js +4 -1
  97. package/dist/units/composite.js.map +1 -1
  98. package/package.json +7 -7
  99. package/src/age-model/data.ts +98 -0
  100. package/src/age-model/details.module.sass +108 -0
  101. package/src/age-model/details.ts +333 -0
  102. package/src/age-model/index.ts +5 -0
  103. package/src/age-model/legacy.ts +30 -0
  104. package/src/age-model/surfaces.module.sass +168 -0
  105. package/src/age-model/surfaces.ts +568 -0
  106. package/src/age-model/types.ts +392 -0
  107. package/src/column.module.sass +59 -8
  108. package/src/column.ts +49 -23
  109. package/src/data-provider/store.ts +50 -1
  110. package/src/index.ts +5 -1
  111. package/src/notes.ts +20 -2
  112. package/src/prepare-units/composite-scale.ts +34 -31
  113. package/src/prepare-units/density.ts +197 -0
  114. package/src/prepare-units/index.ts +25 -6
  115. package/src/prepare-units/types.ts +34 -13
  116. package/src/section.ts +219 -33
  117. package/src/timescale-zoom.ts +341 -0
  118. package/src/unit-details/age-range.ts +3 -3
  119. package/src/units/composite.ts +11 -0
  120. package/dist/age-model-overlay.cjs +0 -50
  121. package/dist/age-model-overlay.cjs.map +0 -1
  122. package/dist/age-model-overlay.d.ts +0 -24
  123. package/dist/age-model-overlay.js +0 -48
  124. package/dist/age-model-overlay.js.map +0 -1
  125. package/dist/age-model-overlay.module.sass.cjs +0 -12
  126. package/dist/age-model-overlay.module.sass.cjs.map +0 -1
  127. package/dist/age-model-overlay.module.sass.js +0 -11
  128. package/dist/age-model-overlay.module.sass.js.map +0 -1
  129. package/src/age-model-overlay.module.sass +0 -11
  130. package/src/age-model-overlay.ts +0 -96
package/CHANGELOG.md CHANGED
@@ -1,5 +1,174 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.12.0] - 2026-09-21 [_changes_](https://github.com/UW-Macrostrat/web-components/compare/@macrostrat/column-views-v3.11.0...@macrostrat/column-views-v3.12.0)
4
+
5
+ ### Minor Changes
6
+
7
+ - Reduce the options that set how tall a column draws to the few that say
8
+ [0614432f](https://github.com/UW-Macrostrat/web-components/commit/0614432fe94bfd2c222375b9add8f7ac100e33c3)
9
+ different things. They all resolve to one quantity — density, the pixels given
10
+ to one unit of the axis.
11
+
12
+ `targetUnitHeight` is the usual knob: room for a typical unit, now the
13
+ geometric mean of the visible units' extents rather than their arithmetic
14
+ mean, which a few long units skew far above anything on screen.
15
+ `minSectionHeight` and `minPixelScale` floor it for legibility. `pixelScale`
16
+ is the alternative: a density stated outright, which is then the density — the
17
+ floors no longer apply to it, since they would undo the scale you stated, and
18
+ `Column` no longer adjusts them behind the scenes. It is quoted in whatever
19
+ the axis measures, so `pixelsPerMyr` and `pixelsPerMeter` spell it per axis,
20
+ the way `t_age` and `t_pos` already do for the window: both can be held at
21
+ once and the axis picks, since useful values for the two differ by orders of
22
+ magnitude. `sectionOptions` decides any of these per section, given what the
23
+ section holds.
24
+
25
+ `heightMultiplier` is gone — asking for more room per unit is the same
26
+ control, and leaves the legibility floors where they belong — as is the
27
+ internal `visibleWindow`, which only restated `t_age`/`b_age`.
28
+
29
+ - Add a surfaces view for a column's age model. `ColumnSurfaces`, dropped into a
30
+ [ea700ff1](https://github.com/UW-Macrostrat/web-components/commit/ea700ff1e7725703d971e3cac440fad0f7540a65)
31
+ `Column` as a child, draws the column's calibration surfaces from the
32
+ `/age_model` route as lines across the units (`ColumnSurfaceLines`) and as a
33
+ collision-avoiding notes column of labels beside them (`ColumnSurfaceLabels`),
34
+ styled by `boundary_status` and `boundary_type`, with hover and selection.
35
+ Labels use the standard `IntervalTag` for the calibration interval (with the
36
+ position within it) over the modeled age, are drawn by default only for the
37
+ tie points where the age model was constrained (absolute, relative, spike,
38
+ imposed — `labelStatuses` widens this), and take the label column over from
39
+ the unit labels while mounted (`useClaimLabelColumn`, a new way for a column's
40
+ children to claim that space). `SurfaceDetailsPanel` inspects a selected
41
+ surface — model age, calibration interval and position within it, the units it
42
+ separates, provenance — and `SurfaceStatusLegend` explains the line styles.
43
+
44
+ The view is data-agnostic: `useColumnAgeModel` fetches boundaries through the
45
+ `MacrostratDataProvider` base URL (the old overlay hardcoded the dev server),
46
+ `surfacesFromBoundaries` maps them to `ColumnSurface` records, and
47
+ `surfacesFromUnits` derives surfaces from unit tops and bottoms as the
48
+ fallback for columns without `unit_boundaries` (or for an editor's own state).
49
+ `BoundaryAgeModelOverlay` and `ComputedSurfacesOverlay` remain as deprecated
50
+ wrappers. `ColumnNotes` gains `onClickNote` and `className` passthroughs.
51
+
52
+ `@macrostrat/api-types` gains `AgeModelBoundary` and the `BoundaryStatus` /
53
+ `BoundaryType` vocabularies, mirroring the database enums.
54
+
55
+ - Draw several timescales beside a column. A new `timescales` prop takes them in
56
+ [1b694ccf](https://github.com/UW-Macrostrat/web-components/commit/1b694ccfcc40321a6edc609b8c07106a87164a3b)
57
+ order, each a Macrostrat timescale ID or a timescale carrying its own
58
+ intervals, levels and label — the international timescale is one of these
59
+ rather than a special case. Clicks and per-interval styles report which
60
+ timescale they came from, so the same interval drawn in two of them can be
61
+ told apart, and `useTimescaleZoom` treats a click in another timescale as
62
+ moving the selection rather than zooming out. Timescales are fetched in one
63
+ place rather than once per section.
64
+ - Suppress unit labels below a pixel height, rather than labeling units too thin
65
+ [0614432f](https://github.com/UW-Macrostrat/web-components/commit/0614432fe94bfd2c222375b9add8f7ac100e33c3)
66
+ to see: `labelSuppressHeight` on `Column`, 2px by default. A gap between
67
+ sections is also labeled in the units of the axis, so a drill core reads
68
+ metres rather than Myr.
69
+ - One selection color across a column: `--column-selection-color` (the accent
70
+ [1b694ccf](https://github.com/UW-Macrostrat/web-components/commit/1b694ccfcc40321a6edc609b8c07106a87164a3b)
71
+ color, purple) drives both the unit selection overlay — now a box with an
72
+ outline and a light wash, rather than a heavy red fill — and the surface
73
+ selection.
74
+
75
+ Surface lines are drawn at a constant weight; status shows in the dash pattern
76
+ and color. A selected surface is outlined as a box, keeping its interval color
77
+ inside, and a selected label bolds its interval tag rather than sitting in a
78
+ card.
79
+
80
+ `useTimescaleZoom`: shift-clicking a timescale interval widens the window to
81
+ take it in, instead of moving the window to it. `selectedIntervals` reports
82
+ everything in the selection; all of them are styled as selected.
83
+
84
+ `CompositeTimescale` takes a `timescaleID` (which timescale the leveled column
85
+ draws) and `additionalTimescales` (further timescales drawn as extra level
86
+ columns beside it, against the same section scales), and is exported. `Column`
87
+ passes `additionalTimescales` through: narrow `timescaleLevels` by as many to
88
+ swap the finest international level for a regional one rather than widen the
89
+ timescale.
90
+
91
+ `heightMultiplier` on `Column` multiplies the heights the layout works out by
92
+ a fixed factor. The scaling approach is unchanged — density still comes from
93
+ `targetUnitHeight` and the section floors — so sections keep their proportions
94
+ and only the size changes; unconformity gaps and `windowPadding`, being chrome
95
+ rather than scale, stay put.
96
+
97
+ - Infer `relative` status for age-model surfaces that cannot have been
98
+ [c17e6379](https://github.com/UW-Macrostrat/web-components/commit/c17e637909bbff76f7bbf4366134b0ba5c5f59ef)
99
+ interpolated: those sitting on the base or top of their calibration interval,
100
+ and the edges of gap-bound packages (the youngest surface in a section with no
101
+ unit above, or the oldest with none below). `boundary_status` records many of
102
+ these as `modeled`, so filtering to the tie-point statuses was hiding real tie
103
+ points. `inferTiePointStatuses` promotes them client-side and marks the result
104
+ `statusInferred`, which `SurfaceStatusTag` shows. On by default;
105
+ `inferTiePoints: false` on `ColumnSurfaces`, `useColumnSurfaces` or
106
+ `surfacesFromBoundaries` takes the data as recorded.
107
+
108
+ Fix surface lines drifting out of alignment with the units column: the overlay
109
+ measured its position once and only re-measured on its own resize, so a
110
+ sibling changing width — the timescale, once its intervals load — left it
111
+ stale.
112
+
113
+ - Color age-model surfaces by the interval they are calibrated against: the
114
+ [acc9f478](https://github.com/UW-Macrostrat/web-components/commit/acc9f4782cbae65bfe017aa195e1b51456871822)
115
+ surface line and its label's leader line both take the interval's color, and
116
+ the lines are drawn a little heavier. The label's endpoint marker is gone —
117
+ the leader now runs into the surface line itself.
118
+
119
+ `SurfaceDetailsPanel` accepts a `null` surface and renders an empty state, so
120
+ a panel bound to a selection doesn't have to be guarded by its caller.
121
+
122
+ - Add `useTimescaleZoom`: click-to-zoom navigation over geologic time, extracted
123
+ [af6d14e1](https://github.com/UW-Macrostrat/web-components/commit/af6d14e1da59af8d09712ed5cb750b1b6bca7cc8)
124
+ from the Interval zoom story. Clicking a timescale interval animates the
125
+ rendered age window to it, clicking the interval you are in zooms back out a
126
+ level, and the timescale's level window slides with the selection so finer
127
+ intervals come into reach as you drill. `columnProps` spreads the window, the
128
+ levels, the click handler and the selected-interval styling onto a `Column`.
129
+ `unitsAgeExtent` derives the full extent from a set of units.
130
+
131
+ ### Patch Changes
132
+
133
+ - Notes columns re-run their force layout once the notes' rendered heights have
134
+ [7252f222](https://github.com/UW-Macrostrat/web-components/commit/7252f22207f63d57ef91172cf898f6b27c38725a)
135
+ been measured. The first layout ran on a 10px guess per note and was never
136
+ revisited, so notes taller than that (interval tags, two-line labels)
137
+ overlapped their neighbors. `ColumnNotes` also passes `forceOptions` through
138
+ to the layout.
139
+ - Treat an unset age or depth bound as unbounded rather than as a real one. A
140
+ [0614432f](https://github.com/UW-Macrostrat/web-components/commit/0614432fe94bfd2c222375b9add8f7ac100e33c3)
141
+ `null` `t_age` is the ordinary way to say "no window" — it is what clearing a
142
+ window leaves behind — and columns laid out with a hybrid scale, which clip
143
+ before laying out, were dropping every unit when they saw one.
144
+ - Judge an unconformity against the finer of the two scales it falls between,
145
+ [aa4fda55](https://github.com/UW-Macrostrat/web-components/commit/aa4fda557137cdb652cb3ddce98d1b5dae8109ef)
146
+ rather than the coarser one. A gap has no density of its own, and taking the
147
+ smaller estimate let a sparse neighbor speak for one the other neighbor would
148
+ have drawn many times larger — a 16 Myr hiatus read as 26px against one
149
+ section and 166px against the other, and collapsed.
150
+ - Updated dependencies
151
+ [ea700ff1](https://github.com/UW-Macrostrat/web-components/commit/ea700ff1e7725703d971e3cac440fad0f7540a65)
152
+ - Updated dependencies
153
+ [1b694ccf](https://github.com/UW-Macrostrat/web-components/commit/1b694ccfcc40321a6edc609b8c07106a87164a3b)
154
+ - Updated dependencies
155
+ [1b694ccf](https://github.com/UW-Macrostrat/web-components/commit/1b694ccfcc40321a6edc609b8c07106a87164a3b)
156
+ - Updated dependencies
157
+ [acc9f478](https://github.com/UW-Macrostrat/web-components/commit/acc9f4782cbae65bfe017aa195e1b51456871822)
158
+ - Updated dependencies
159
+ [aa4fda55](https://github.com/UW-Macrostrat/web-components/commit/aa4fda557137cdb652cb3ddce98d1b5dae8109ef)
160
+ - Updated dependencies
161
+ [af6d14e1](https://github.com/UW-Macrostrat/web-components/commit/af6d14e1da59af8d09712ed5cb750b1b6bca7cc8)
162
+ - Updated dependencies
163
+ [7252f222](https://github.com/UW-Macrostrat/web-components/commit/7252f22207f63d57ef91172cf898f6b27c38725a)
164
+ - Updated dependencies
165
+ [1b694ccf](https://github.com/UW-Macrostrat/web-components/commit/1b694ccfcc40321a6edc609b8c07106a87164a3b)
166
+ - @macrostrat/api-types@1.4.0
167
+ - @macrostrat/data-provider@1.3.1
168
+ - @macrostrat/timescale@3.3.0
169
+ - @macrostrat/column-components@2.2.0
170
+ - @macrostrat/stratigraphy-utils@1.4.2
171
+
3
172
  ## [3.11.0] - 2026-09-04 [_changes_](https://github.com/UW-Macrostrat/web-components/compare/@macrostrat/column-views-v3.10.0...@macrostrat/column-views-v3.11.0)
4
173
 
5
174
  ### Minor Changes
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const React = require("react");
4
+ const uiComponents = require("@macrostrat/ui-components");
5
+ const dataProvider = require("@macrostrat/data-provider");
6
+ const types = require("./types.cjs");
7
+ const store = require("../data-provider/store.cjs");
8
+ const AGE_MODEL_ROUTE = "/age_model";
9
+ function useColumnAgeModel(col_id) {
10
+ const baseURL = dataProvider.useMacrostratBaseURL();
11
+ const params = React.useMemo(() => ({ col_id }), [col_id]);
12
+ let route = null;
13
+ if (col_id != null) {
14
+ route = baseURL + AGE_MODEL_ROUTE;
15
+ }
16
+ return uiComponents.useAPIResult(route, params, unwrapAgeModel) ?? null;
17
+ }
18
+ function unwrapAgeModel(res) {
19
+ return res?.success?.data ?? [];
20
+ }
21
+ function useColumnSurfaces(options = {}) {
22
+ const {
23
+ surfaces: provided,
24
+ col_id,
25
+ fallbackToUnits = true,
26
+ inferTiePoints = true
27
+ } = options;
28
+ const units = store.useMacrostratUnits();
29
+ const { axisType } = store.useMacrostratColumnData();
30
+ let fetchID = null;
31
+ if (provided == null) {
32
+ fetchID = col_id ?? units?.[0]?.col_id ?? null;
33
+ }
34
+ const boundaries = useColumnAgeModel(fetchID);
35
+ const fromAgeModel = React.useMemo(
36
+ () => types.surfacesFromBoundaries(boundaries, { inferTiePoints }),
37
+ [boundaries, inferTiePoints]
38
+ );
39
+ const derived = React.useMemo(() => {
40
+ if (!fallbackToUnits) return [];
41
+ return types.surfacesFromUnits(units, { axisType });
42
+ }, [units, axisType, fallbackToUnits]);
43
+ if (provided != null) {
44
+ return { surfaces: provided, source: "provided" };
45
+ }
46
+ if (fetchID != null && boundaries == null) {
47
+ return { surfaces: [], source: "loading" };
48
+ }
49
+ if (fromAgeModel.length > 0) {
50
+ return { surfaces: fromAgeModel, source: "age-model" };
51
+ }
52
+ return { surfaces: derived, source: "derived" };
53
+ }
54
+ exports.AGE_MODEL_ROUTE = AGE_MODEL_ROUTE;
55
+ exports.useColumnAgeModel = useColumnAgeModel;
56
+ exports.useColumnSurfaces = useColumnSurfaces;
57
+ //# sourceMappingURL=data.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.cjs","sources":["../../src/age-model/data.ts"],"sourcesContent":["/** Data hooks for a column's age model. */\nimport { useMemo } from \"react\";\nimport { useAPIResult } from \"@macrostrat/ui-components\";\nimport { useMacrostratBaseURL } from \"@macrostrat/data-provider\";\nimport type { UnitLong } from \"@macrostrat/api-types\";\nimport { useMacrostratColumnData, useMacrostratUnits } from \"../data-provider\";\nimport {\n type AgeModelBoundary,\n type ColumnSurface,\n surfacesFromBoundaries,\n surfacesFromUnits,\n} from \"./types\";\n\nexport const AGE_MODEL_ROUTE = \"/age_model\";\n\n/** The age-model boundaries of a column, from `/age_model?col_id=` on the\n * API the enclosing `MacrostratDataProvider` points at (production when there\n * is none). `null` while loading or when `col_id` is not set. */\nexport function useColumnAgeModel(\n col_id: number | null | undefined,\n): AgeModelBoundary[] | null {\n const baseURL = useMacrostratBaseURL();\n const params = useMemo(() => ({ col_id }), [col_id]);\n let route: string | null = null;\n if (col_id != null) {\n route = baseURL + AGE_MODEL_ROUTE;\n }\n return useAPIResult(route, params, unwrapAgeModel) ?? null;\n}\n\nfunction unwrapAgeModel(res: any): AgeModelBoundary[] {\n return res?.success?.data ?? [];\n}\n\n/** Where a column's surfaces came from */\nexport type SurfacesSource = \"provided\" | \"age-model\" | \"derived\" | \"loading\";\n\nexport interface UseColumnSurfacesOptions {\n /** Surfaces to show. When given, nothing is fetched. */\n surfaces?: ColumnSurface[] | null;\n /** The column whose age model to fetch. Defaults to the column being\n * rendered (read from its units). */\n col_id?: number | null;\n /** When the age model has no boundaries, derive surfaces from the units\n * instead (default `true`). */\n fallbackToUnits?: boolean;\n /** Promote `modeled` surfaces that must in fact constrain the age model to\n * `relative` (default `true`) — see `inferTiePointStatuses`. */\n inferTiePoints?: boolean;\n}\n\nexport interface ColumnSurfacesData {\n surfaces: ColumnSurface[];\n source: SurfacesSource;\n}\n\n/** Resolve the surfaces to show for the enclosing `Column`: the ones passed\n * in, else the column's age model, else (optionally) surfaces derived from\n * its units. Must be used inside a `Column`. */\nexport function useColumnSurfaces(\n options: UseColumnSurfacesOptions = {},\n): ColumnSurfacesData {\n const {\n surfaces: provided,\n col_id,\n fallbackToUnits = true,\n inferTiePoints = true,\n } = options;\n const units = useMacrostratUnits() as UnitLong[] | undefined;\n const { axisType } = useMacrostratColumnData();\n\n let fetchID: number | null = null;\n if (provided == null) {\n fetchID = col_id ?? units?.[0]?.col_id ?? null;\n }\n const boundaries = useColumnAgeModel(fetchID);\n\n const fromAgeModel = useMemo(\n () => surfacesFromBoundaries(boundaries, { inferTiePoints }),\n [boundaries, inferTiePoints],\n );\n\n const derived = useMemo(() => {\n if (!fallbackToUnits) return [];\n return surfacesFromUnits(units, { axisType });\n }, [units, axisType, fallbackToUnits]);\n\n if (provided != null) {\n return { surfaces: provided, source: \"provided\" };\n }\n if (fetchID != null && boundaries == null) {\n return { surfaces: [], source: \"loading\" };\n }\n if (fromAgeModel.length > 0) {\n return { surfaces: fromAgeModel, source: \"age-model\" };\n }\n return { surfaces: derived, source: \"derived\" };\n}\n"],"names":["useMacrostratBaseURL","useMemo","useAPIResult","useMacrostratUnits","useMacrostratColumnData","surfacesFromBoundaries","surfacesFromUnits"],"mappings":";;;;;;;AAaO,MAAM,kBAAkB;AAKxB,SAAS,kBACd,QAC2B;AAC3B,QAAM,UAAUA,aAAAA,qBAAA;AAChB,QAAM,SAASC,MAAAA,QAAQ,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC;AACnD,MAAI,QAAuB;AAC3B,MAAI,UAAU,MAAM;AAClB,YAAQ,UAAU;AAAA,EACpB;AACA,SAAOC,aAAAA,aAAa,OAAO,QAAQ,cAAc,KAAK;AACxD;AAEA,SAAS,eAAe,KAA8B;AACpD,SAAO,KAAK,SAAS,QAAQ,CAAA;AAC/B;AA2BO,SAAS,kBACd,UAAoC,IAChB;AACpB,QAAM;AAAA,IACJ,UAAU;AAAA,IACV;AAAA,IACA,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EAAA,IACf;AACJ,QAAM,QAAQC,MAAAA,mBAAA;AACd,QAAM,EAAE,SAAA,IAAaC,8BAAA;AAErB,MAAI,UAAyB;AAC7B,MAAI,YAAY,MAAM;AACpB,cAAU,UAAU,QAAQ,CAAC,GAAG,UAAU;AAAA,EAC5C;AACA,QAAM,aAAa,kBAAkB,OAAO;AAE5C,QAAM,eAAeH,MAAAA;AAAAA,IACnB,MAAMI,6BAAuB,YAAY,EAAE,gBAAgB;AAAA,IAC3D,CAAC,YAAY,cAAc;AAAA,EAAA;AAG7B,QAAM,UAAUJ,MAAAA,QAAQ,MAAM;AAC5B,QAAI,CAAC,gBAAiB,QAAO,CAAA;AAC7B,WAAOK,wBAAkB,OAAO,EAAE,UAAU;AAAA,EAC9C,GAAG,CAAC,OAAO,UAAU,eAAe,CAAC;AAErC,MAAI,YAAY,MAAM;AACpB,WAAO,EAAE,UAAU,UAAU,QAAQ,WAAA;AAAA,EACvC;AACA,MAAI,WAAW,QAAQ,cAAc,MAAM;AACzC,WAAO,EAAE,UAAU,IAAI,QAAQ,UAAA;AAAA,EACjC;AACA,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO,EAAE,UAAU,cAAc,QAAQ,YAAA;AAAA,EAC3C;AACA,SAAO,EAAE,UAAU,SAAS,QAAQ,UAAA;AACtC;;;;"}
@@ -0,0 +1,29 @@
1
+ import { AgeModelBoundary, ColumnSurface } from './types';
2
+ export declare const AGE_MODEL_ROUTE = "/age_model";
3
+ /** The age-model boundaries of a column, from `/age_model?col_id=` on the
4
+ * API the enclosing `MacrostratDataProvider` points at (production when there
5
+ * is none). `null` while loading or when `col_id` is not set. */
6
+ export declare function useColumnAgeModel(col_id: number | null | undefined): AgeModelBoundary[] | null;
7
+ /** Where a column's surfaces came from */
8
+ export type SurfacesSource = "provided" | "age-model" | "derived" | "loading";
9
+ export interface UseColumnSurfacesOptions {
10
+ /** Surfaces to show. When given, nothing is fetched. */
11
+ surfaces?: ColumnSurface[] | null;
12
+ /** The column whose age model to fetch. Defaults to the column being
13
+ * rendered (read from its units). */
14
+ col_id?: number | null;
15
+ /** When the age model has no boundaries, derive surfaces from the units
16
+ * instead (default `true`). */
17
+ fallbackToUnits?: boolean;
18
+ /** Promote `modeled` surfaces that must in fact constrain the age model to
19
+ * `relative` (default `true`) — see `inferTiePointStatuses`. */
20
+ inferTiePoints?: boolean;
21
+ }
22
+ export interface ColumnSurfacesData {
23
+ surfaces: ColumnSurface[];
24
+ source: SurfacesSource;
25
+ }
26
+ /** Resolve the surfaces to show for the enclosing `Column`: the ones passed
27
+ * in, else the column's age model, else (optionally) surfaces derived from
28
+ * its units. Must be used inside a `Column`. */
29
+ export declare function useColumnSurfaces(options?: UseColumnSurfacesOptions): ColumnSurfacesData;
@@ -0,0 +1,57 @@
1
+ import { useMemo } from "react";
2
+ import { useAPIResult } from "@macrostrat/ui-components";
3
+ import { useMacrostratBaseURL } from "@macrostrat/data-provider";
4
+ import { surfacesFromBoundaries, surfacesFromUnits } from "./types.js";
5
+ import { useMacrostratUnits, useMacrostratColumnData } from "../data-provider/store.js";
6
+ const AGE_MODEL_ROUTE = "/age_model";
7
+ function useColumnAgeModel(col_id) {
8
+ const baseURL = useMacrostratBaseURL();
9
+ const params = useMemo(() => ({ col_id }), [col_id]);
10
+ let route = null;
11
+ if (col_id != null) {
12
+ route = baseURL + AGE_MODEL_ROUTE;
13
+ }
14
+ return useAPIResult(route, params, unwrapAgeModel) ?? null;
15
+ }
16
+ function unwrapAgeModel(res) {
17
+ return res?.success?.data ?? [];
18
+ }
19
+ function useColumnSurfaces(options = {}) {
20
+ const {
21
+ surfaces: provided,
22
+ col_id,
23
+ fallbackToUnits = true,
24
+ inferTiePoints = true
25
+ } = options;
26
+ const units = useMacrostratUnits();
27
+ const { axisType } = useMacrostratColumnData();
28
+ let fetchID = null;
29
+ if (provided == null) {
30
+ fetchID = col_id ?? units?.[0]?.col_id ?? null;
31
+ }
32
+ const boundaries = useColumnAgeModel(fetchID);
33
+ const fromAgeModel = useMemo(
34
+ () => surfacesFromBoundaries(boundaries, { inferTiePoints }),
35
+ [boundaries, inferTiePoints]
36
+ );
37
+ const derived = useMemo(() => {
38
+ if (!fallbackToUnits) return [];
39
+ return surfacesFromUnits(units, { axisType });
40
+ }, [units, axisType, fallbackToUnits]);
41
+ if (provided != null) {
42
+ return { surfaces: provided, source: "provided" };
43
+ }
44
+ if (fetchID != null && boundaries == null) {
45
+ return { surfaces: [], source: "loading" };
46
+ }
47
+ if (fromAgeModel.length > 0) {
48
+ return { surfaces: fromAgeModel, source: "age-model" };
49
+ }
50
+ return { surfaces: derived, source: "derived" };
51
+ }
52
+ export {
53
+ AGE_MODEL_ROUTE,
54
+ useColumnAgeModel,
55
+ useColumnSurfaces
56
+ };
57
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sources":["../../src/age-model/data.ts"],"sourcesContent":["/** Data hooks for a column's age model. */\nimport { useMemo } from \"react\";\nimport { useAPIResult } from \"@macrostrat/ui-components\";\nimport { useMacrostratBaseURL } from \"@macrostrat/data-provider\";\nimport type { UnitLong } from \"@macrostrat/api-types\";\nimport { useMacrostratColumnData, useMacrostratUnits } from \"../data-provider\";\nimport {\n type AgeModelBoundary,\n type ColumnSurface,\n surfacesFromBoundaries,\n surfacesFromUnits,\n} from \"./types\";\n\nexport const AGE_MODEL_ROUTE = \"/age_model\";\n\n/** The age-model boundaries of a column, from `/age_model?col_id=` on the\n * API the enclosing `MacrostratDataProvider` points at (production when there\n * is none). `null` while loading or when `col_id` is not set. */\nexport function useColumnAgeModel(\n col_id: number | null | undefined,\n): AgeModelBoundary[] | null {\n const baseURL = useMacrostratBaseURL();\n const params = useMemo(() => ({ col_id }), [col_id]);\n let route: string | null = null;\n if (col_id != null) {\n route = baseURL + AGE_MODEL_ROUTE;\n }\n return useAPIResult(route, params, unwrapAgeModel) ?? null;\n}\n\nfunction unwrapAgeModel(res: any): AgeModelBoundary[] {\n return res?.success?.data ?? [];\n}\n\n/** Where a column's surfaces came from */\nexport type SurfacesSource = \"provided\" | \"age-model\" | \"derived\" | \"loading\";\n\nexport interface UseColumnSurfacesOptions {\n /** Surfaces to show. When given, nothing is fetched. */\n surfaces?: ColumnSurface[] | null;\n /** The column whose age model to fetch. Defaults to the column being\n * rendered (read from its units). */\n col_id?: number | null;\n /** When the age model has no boundaries, derive surfaces from the units\n * instead (default `true`). */\n fallbackToUnits?: boolean;\n /** Promote `modeled` surfaces that must in fact constrain the age model to\n * `relative` (default `true`) — see `inferTiePointStatuses`. */\n inferTiePoints?: boolean;\n}\n\nexport interface ColumnSurfacesData {\n surfaces: ColumnSurface[];\n source: SurfacesSource;\n}\n\n/** Resolve the surfaces to show for the enclosing `Column`: the ones passed\n * in, else the column's age model, else (optionally) surfaces derived from\n * its units. Must be used inside a `Column`. */\nexport function useColumnSurfaces(\n options: UseColumnSurfacesOptions = {},\n): ColumnSurfacesData {\n const {\n surfaces: provided,\n col_id,\n fallbackToUnits = true,\n inferTiePoints = true,\n } = options;\n const units = useMacrostratUnits() as UnitLong[] | undefined;\n const { axisType } = useMacrostratColumnData();\n\n let fetchID: number | null = null;\n if (provided == null) {\n fetchID = col_id ?? units?.[0]?.col_id ?? null;\n }\n const boundaries = useColumnAgeModel(fetchID);\n\n const fromAgeModel = useMemo(\n () => surfacesFromBoundaries(boundaries, { inferTiePoints }),\n [boundaries, inferTiePoints],\n );\n\n const derived = useMemo(() => {\n if (!fallbackToUnits) return [];\n return surfacesFromUnits(units, { axisType });\n }, [units, axisType, fallbackToUnits]);\n\n if (provided != null) {\n return { surfaces: provided, source: \"provided\" };\n }\n if (fetchID != null && boundaries == null) {\n return { surfaces: [], source: \"loading\" };\n }\n if (fromAgeModel.length > 0) {\n return { surfaces: fromAgeModel, source: \"age-model\" };\n }\n return { surfaces: derived, source: \"derived\" };\n}\n"],"names":[],"mappings":";;;;;AAaO,MAAM,kBAAkB;AAKxB,SAAS,kBACd,QAC2B;AAC3B,QAAM,UAAU,qBAAA;AAChB,QAAM,SAAS,QAAQ,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC;AACnD,MAAI,QAAuB;AAC3B,MAAI,UAAU,MAAM;AAClB,YAAQ,UAAU;AAAA,EACpB;AACA,SAAO,aAAa,OAAO,QAAQ,cAAc,KAAK;AACxD;AAEA,SAAS,eAAe,KAA8B;AACpD,SAAO,KAAK,SAAS,QAAQ,CAAA;AAC/B;AA2BO,SAAS,kBACd,UAAoC,IAChB;AACpB,QAAM;AAAA,IACJ,UAAU;AAAA,IACV;AAAA,IACA,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EAAA,IACf;AACJ,QAAM,QAAQ,mBAAA;AACd,QAAM,EAAE,SAAA,IAAa,wBAAA;AAErB,MAAI,UAAyB;AAC7B,MAAI,YAAY,MAAM;AACpB,cAAU,UAAU,QAAQ,CAAC,GAAG,UAAU;AAAA,EAC5C;AACA,QAAM,aAAa,kBAAkB,OAAO;AAE5C,QAAM,eAAe;AAAA,IACnB,MAAM,uBAAuB,YAAY,EAAE,gBAAgB;AAAA,IAC3D,CAAC,YAAY,cAAc;AAAA,EAAA;AAG7B,QAAM,UAAU,QAAQ,MAAM;AAC5B,QAAI,CAAC,gBAAiB,QAAO,CAAA;AAC7B,WAAO,kBAAkB,OAAO,EAAE,UAAU;AAAA,EAC9C,GAAG,CAAC,OAAO,UAAU,eAAe,CAAC;AAErC,MAAI,YAAY,MAAM;AACpB,WAAO,EAAE,UAAU,UAAU,QAAQ,WAAA;AAAA,EACvC;AACA,MAAI,WAAW,QAAQ,cAAc,MAAM;AACzC,WAAO,EAAE,UAAU,IAAI,QAAQ,UAAA;AAAA,EACjC;AACA,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO,EAAE,UAAU,cAAc,QAAQ,YAAA;AAAA,EAC3C;AACA,SAAO,EAAE,UAAU,SAAS,QAAQ,UAAA;AACtC;"}
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const h$1 = require("@macrostrat/hyper");
4
+ const classNames = require("classnames");
5
+ const React = require("react");
6
+ const core = require("@blueprintjs/core");
7
+ const dataComponents = require("@macrostrat/data-components");
8
+ const dataProvider = require("@macrostrat/data-provider");
9
+ const ageRange = require("../unit-details/age-range.cjs");
10
+ const panel = require("../unit-details/panel.cjs");
11
+ const surfaces = require("./surfaces.cjs");
12
+ const surfaces_module = require("./surfaces.module.sass.cjs");
13
+ const details_module = require("./details.module.sass.cjs");
14
+ const types = require("./types.cjs");
15
+ const store = require("../data-provider/store.cjs");
16
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
17
+ const h__default = /* @__PURE__ */ _interopDefault(h$1);
18
+ const classNames__default = /* @__PURE__ */ _interopDefault(classNames);
19
+ const h = h__default.default.styled({ ...surfaces_module.default, ...details_module.default });
20
+ function SurfaceDetailsPanel(props) {
21
+ const {
22
+ surface,
23
+ onClose,
24
+ onSelectUnit,
25
+ actions,
26
+ positionLabel = "Position",
27
+ className
28
+ } = props;
29
+ if (surface == null) {
30
+ return h(
31
+ "div.surface-details-panel.no-surface",
32
+ { className },
33
+ h("p.placeholder", "No surface selected.")
34
+ );
35
+ }
36
+ let closeButton = null;
37
+ if (onClose != null) {
38
+ closeButton = h(core.Button, {
39
+ icon: "cross",
40
+ variant: "minimal",
41
+ size: "small",
42
+ onClick: onClose,
43
+ "aria-label": "Close"
44
+ });
45
+ }
46
+ let positionField = null;
47
+ if (surface.position != null) {
48
+ positionField = h(dataComponents.DataField, {
49
+ label: positionLabel,
50
+ value: surface.position.toLocaleString("en-US", {
51
+ maximumFractionDigits: 2
52
+ }),
53
+ unit: "m"
54
+ });
55
+ }
56
+ let sectionField = null;
57
+ if (surface.section_id != null) {
58
+ sectionField = h(
59
+ dataComponents.DataField,
60
+ { label: "Section" },
61
+ h(dataComponents.Identifier, { id: surface.section_id })
62
+ );
63
+ }
64
+ let refsField = null;
65
+ if (surface.ref_id != null) {
66
+ refsField = h(panel.ReferencesField, { refs: [surface.ref_id] });
67
+ }
68
+ return h(
69
+ "div.surface-details-panel",
70
+ { className: classNames__default.default(className, surfaces.surfaceClasses(surface)) },
71
+ [
72
+ h("div.surface-details-header", [
73
+ h("h3.surface-details-title", [
74
+ "Surface ",
75
+ h(SurfaceIdentifier, { id: surface.id })
76
+ ]),
77
+ h("div.surface-details-tags", [
78
+ h(SurfaceStatusTag, {
79
+ status: surface.status,
80
+ inferred: surface.statusInferred
81
+ }),
82
+ h(SurfaceTypeTag, { type: surface.type })
83
+ ]),
84
+ h("div.spacer"),
85
+ actions,
86
+ closeButton
87
+ ]),
88
+ h("div.surface-details-content", [
89
+ h(dataComponents.DataField, { label: "Model age" }, h(ageRange.AgeLabel, { age: surface.age })),
90
+ h(SurfaceCalibrationField, { surface }),
91
+ positionField,
92
+ h(SurfaceUnitsField, {
93
+ label: "Unit above",
94
+ unitIDs: surface.unitsAbove,
95
+ onSelectUnit
96
+ }),
97
+ h(SurfaceUnitsField, {
98
+ label: "Unit below",
99
+ unitIDs: surface.unitsBelow,
100
+ onSelectUnit
101
+ }),
102
+ sectionField,
103
+ refsField
104
+ ])
105
+ ]
106
+ );
107
+ }
108
+ function SurfaceIdentifier({ id }) {
109
+ if (typeof id === "number") {
110
+ return h(dataComponents.Identifier, { id });
111
+ }
112
+ return h("code.surface-id", String(id));
113
+ }
114
+ function SurfaceCalibrationField({ surface }) {
115
+ const { calibration, proportion } = surface;
116
+ const ids = React.useMemo(() => {
117
+ if (calibration == null) return [];
118
+ return [calibration.id];
119
+ }, [calibration?.id]);
120
+ const intervalMap = dataProvider.useMacrostratDefs("intervals", ids, null);
121
+ if (calibration == null) {
122
+ return h(dataComponents.DataField, {
123
+ label: "Calibration",
124
+ value: "None",
125
+ className: "no-calibration"
126
+ });
127
+ }
128
+ const def = intervalMap?.get(calibration.id);
129
+ const interval = {
130
+ id: calibration.id,
131
+ name: calibration.name,
132
+ b_age: calibration.b_age,
133
+ t_age: calibration.t_age,
134
+ color: def?.color,
135
+ rank: def?.rank
136
+ };
137
+ return h(dataComponents.DataField, { label: "Calibration" }, [
138
+ h(
139
+ "div.calibration-interval",
140
+ h(dataComponents.IntervalTag, {
141
+ interval,
142
+ prefix: h(ageRange.Proportion, { value: proportion })
143
+ })
144
+ )
145
+ ]);
146
+ }
147
+ function SurfaceUnitsField({
148
+ label,
149
+ unitIDs,
150
+ onSelectUnit
151
+ }) {
152
+ const unitsMap = store.useColumnUnitsMap();
153
+ if (unitIDs.length === 0) {
154
+ return h(dataComponents.DataField, { label, value: "None", className: "no-units" });
155
+ }
156
+ return h(
157
+ dataComponents.DataField,
158
+ { label, className: "surface-units-field" },
159
+ h(
160
+ "ul.surface-units-list",
161
+ unitIDs.map((unitID) => {
162
+ const unit = unitsMap?.get(unitID);
163
+ let onClick = void 0;
164
+ if (onSelectUnit != null) {
165
+ onClick = () => onSelectUnit(unitID);
166
+ }
167
+ return h(
168
+ "li",
169
+ { key: unitID },
170
+ h(dataComponents.UnitIdentifier, {
171
+ unitID,
172
+ colID: unit?.col_id,
173
+ name: unit?.unit_name,
174
+ onClick
175
+ })
176
+ );
177
+ })
178
+ )
179
+ );
180
+ }
181
+ function SurfaceStatusTag({
182
+ status,
183
+ inferred = false,
184
+ className
185
+ }) {
186
+ let label = types.surfaceStatusLabels[status] ?? status;
187
+ let title = types.surfaceStatusDescriptions[status];
188
+ if (inferred) {
189
+ label = [label, h("span.inferred-marker", "*")];
190
+ title = INFERRED_STATUS_DESCRIPTION;
191
+ }
192
+ return h(
193
+ core.Tag,
194
+ {
195
+ variant: "minimal",
196
+ className: classNames__default.default(
197
+ "surface-tag",
198
+ className,
199
+ surfaces.surfaceClasses({ status }),
200
+ { inferred }
201
+ ),
202
+ title
203
+ },
204
+ label
205
+ );
206
+ }
207
+ const INFERRED_STATUS_DESCRIPTION = "Recorded as modeled, but this surface cannot have been interpolated — it sits on the base or top of its interval, or is the edge of a gap-bound package — so it constrains the age model rather than falling out of it";
208
+ function SurfaceTypeTag({
209
+ type,
210
+ className
211
+ }) {
212
+ if (type == null || type === "") return null;
213
+ return h(
214
+ core.Tag,
215
+ {
216
+ variant: "minimal",
217
+ className: classNames__default.default("surface-tag", "surface-type-tag", className)
218
+ },
219
+ type
220
+ );
221
+ }
222
+ function SurfaceStatusLegend(props) {
223
+ const {
224
+ statuses = types.surfaceStatuses,
225
+ showDescriptions = false,
226
+ className
227
+ } = props;
228
+ return h(
229
+ "ul.surface-status-legend",
230
+ {
231
+ className: classNames__default.default(className, {
232
+ "with-descriptions": showDescriptions
233
+ })
234
+ },
235
+ statuses.map((status) => {
236
+ let description = null;
237
+ if (showDescriptions) {
238
+ description = h(
239
+ "div.legend-description",
240
+ types.surfaceStatusDescriptions[status]
241
+ );
242
+ }
243
+ return h(
244
+ "li.legend-item",
245
+ { key: status, className: surfaces.surfaceClasses({ status }) },
246
+ [
247
+ h("div.surface-label-marker"),
248
+ h("div.legend-text", [
249
+ h("div.legend-label", types.surfaceStatusLabels[status]),
250
+ description
251
+ ])
252
+ ]
253
+ );
254
+ })
255
+ );
256
+ }
257
+ exports.SurfaceDetailsPanel = SurfaceDetailsPanel;
258
+ exports.SurfaceStatusLegend = SurfaceStatusLegend;
259
+ exports.SurfaceStatusTag = SurfaceStatusTag;
260
+ exports.SurfaceTypeTag = SurfaceTypeTag;
261
+ //# sourceMappingURL=details.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"details.cjs","sources":["../../src/age-model/details.ts"],"sourcesContent":["/** The inspector for a selected surface, and the small tags and legend that\n * explain surface statuses and types. */\nimport hyper from \"@macrostrat/hyper\";\nimport classNames from \"classnames\";\nimport { type ReactNode, useMemo } from \"react\";\nimport { Button, Tag } from \"@blueprintjs/core\";\nimport {\n DataField,\n Identifier,\n type IntervalShort,\n IntervalTag,\n UnitIdentifier,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport type { UnitLong } from \"@macrostrat/api-types\";\nimport { useColumnUnitsMap } from \"../data-provider\";\nimport { AgeLabel, Proportion } from \"../unit-details/age-range\";\nimport { formatRange } from \"../unit-details/utils\";\nimport { ReferencesField } from \"../unit-details/panel\";\nimport { surfaceClasses } from \"./surfaces\";\nimport surfaceStyles from \"./surfaces.module.sass\";\nimport styles from \"./details.module.sass\";\nimport {\n type BoundaryType,\n type ColumnSurface,\n type SurfaceStatus,\n formatProportion,\n surfaceStatuses,\n surfaceStatusDescriptions,\n surfaceStatusLabels,\n} from \"./types\";\n\nconst h = hyper.styled({ ...surfaceStyles, ...styles });\n\nexport interface SurfaceDetailsPanelProps {\n /** The surface to inspect; `null` renders the panel's empty state */\n surface: ColumnSurface | null;\n onClose?: () => void;\n /** Called when a unit above or below the surface is clicked */\n onSelectUnit?: (unitID: number) => void;\n /** Extra controls for the header */\n actions?: ReactNode;\n /** Label for the measured-position field (\"Height\" or \"Depth\") */\n positionLabel?: string;\n className?: string;\n}\n\n/** Details of one surface: its age, calibration, the units it separates, and\n * provenance. A companion to `UnitDetailsPanel`. */\nexport function SurfaceDetailsPanel(props: SurfaceDetailsPanelProps) {\n const {\n surface,\n onClose,\n onSelectUnit,\n actions,\n positionLabel = \"Position\",\n className,\n } = props;\n\n // A selection that hasn't been made yet is an ordinary state for a panel\n // bound to one, not a caller error\n if (surface == null) {\n return h(\n \"div.surface-details-panel.no-surface\",\n { className },\n h(\"p.placeholder\", \"No surface selected.\"),\n );\n }\n\n let closeButton: ReactNode = null;\n if (onClose != null) {\n closeButton = h(Button, {\n icon: \"cross\",\n variant: \"minimal\",\n size: \"small\",\n onClick: onClose,\n \"aria-label\": \"Close\",\n });\n }\n\n let positionField: ReactNode = null;\n if (surface.position != null) {\n positionField = h(DataField, {\n label: positionLabel,\n value: surface.position.toLocaleString(\"en-US\", {\n maximumFractionDigits: 2,\n }),\n unit: \"m\",\n });\n }\n\n let sectionField: ReactNode = null;\n if (surface.section_id != null) {\n sectionField = h(\n DataField,\n { label: \"Section\" },\n h(Identifier, { id: surface.section_id }),\n );\n }\n\n let refsField: ReactNode = null;\n if (surface.ref_id != null) {\n refsField = h(ReferencesField, { refs: [surface.ref_id] });\n }\n\n return h(\n \"div.surface-details-panel\",\n { className: classNames(className, surfaceClasses(surface)) },\n [\n h(\"div.surface-details-header\", [\n h(\"h3.surface-details-title\", [\n \"Surface \",\n h(SurfaceIdentifier, { id: surface.id }),\n ]),\n h(\"div.surface-details-tags\", [\n h(SurfaceStatusTag, {\n status: surface.status,\n inferred: surface.statusInferred,\n }),\n h(SurfaceTypeTag, { type: surface.type }),\n ]),\n h(\"div.spacer\"),\n actions,\n closeButton,\n ]),\n h(\"div.surface-details-content\", [\n h(DataField, { label: \"Model age\" }, h(AgeLabel, { age: surface.age })),\n h(SurfaceCalibrationField, { surface }),\n positionField,\n h(SurfaceUnitsField, {\n label: \"Unit above\",\n unitIDs: surface.unitsAbove,\n onSelectUnit,\n }),\n h(SurfaceUnitsField, {\n label: \"Unit below\",\n unitIDs: surface.unitsBelow,\n onSelectUnit,\n }),\n sectionField,\n refsField,\n ]),\n ],\n );\n}\n\nfunction SurfaceIdentifier({ id }: { id: ColumnSurface[\"id\"] }) {\n if (typeof id === \"number\") {\n return h(Identifier, { id });\n }\n return h(\"code.surface-id\", String(id));\n}\n\n/** The calibration interval as a colored tag, with the surface's position in\n * it: \"Calymmian (1600–1400 Ma), 85% above base\". */\nfunction SurfaceCalibrationField({ surface }: { surface: ColumnSurface }) {\n const { calibration, proportion } = surface;\n const ids = useMemo(() => {\n if (calibration == null) return [];\n return [calibration.id];\n }, [calibration?.id]);\n // Interval colors come from the definitions table; the age model itself\n // doesn't carry them\n const intervalMap = useMacrostratDefs(\"intervals\", ids, null);\n\n if (calibration == null) {\n return h(DataField, {\n label: \"Calibration\",\n value: \"None\",\n className: \"no-calibration\",\n });\n }\n\n const def = intervalMap?.get(calibration.id);\n const interval: IntervalShort = {\n id: calibration.id,\n name: calibration.name,\n b_age: calibration.b_age,\n t_age: calibration.t_age,\n color: def?.color,\n rank: def?.rank,\n };\n\n return h(DataField, { label: \"Calibration\" }, [\n h(\n \"div.calibration-interval\",\n h(IntervalTag, {\n interval,\n prefix: h(Proportion, { value: proportion }),\n }),\n ),\n ]);\n}\n\nfunction SurfaceUnitsField({\n label,\n unitIDs,\n onSelectUnit,\n}: {\n label: string;\n unitIDs: number[];\n onSelectUnit?: (unitID: number) => void;\n}) {\n const unitsMap = useColumnUnitsMap();\n if (unitIDs.length === 0) {\n return h(DataField, { label, value: \"None\", className: \"no-units\" });\n }\n return h(\n DataField,\n { label, className: \"surface-units-field\" },\n h(\n \"ul.surface-units-list\",\n unitIDs.map((unitID) => {\n const unit = unitsMap?.get(unitID) as UnitLong | undefined;\n let onClick: (() => void) | undefined = undefined;\n if (onSelectUnit != null) {\n onClick = () => onSelectUnit(unitID);\n }\n return h(\n \"li\",\n { key: unitID },\n h(UnitIdentifier, {\n unitID,\n colID: unit?.col_id,\n name: unit?.unit_name,\n onClick,\n }),\n );\n }),\n ),\n );\n}\n\nexport function SurfaceStatusTag({\n status,\n inferred = false,\n className,\n}: {\n status: SurfaceStatus;\n /** The status was inferred rather than recorded (see\n * `inferTiePointStatuses`); the tag says so. */\n inferred?: boolean;\n className?: string;\n}) {\n let label: ReactNode = surfaceStatusLabels[status] ?? status;\n let title = surfaceStatusDescriptions[status];\n if (inferred) {\n label = [label, h(\"span.inferred-marker\", \"*\")];\n title = INFERRED_STATUS_DESCRIPTION;\n }\n\n return h(\n Tag,\n {\n variant: \"minimal\",\n className: classNames(\n \"surface-tag\",\n className,\n surfaceClasses({ status }),\n { inferred },\n ),\n title,\n },\n label,\n );\n}\n\nconst INFERRED_STATUS_DESCRIPTION =\n \"Recorded as modeled, but this surface cannot have been interpolated — it \" +\n \"sits on the base or top of its interval, or is the edge of a gap-bound \" +\n \"package — so it constrains the age model rather than falling out of it\";\n\nexport function SurfaceTypeTag({\n type,\n className,\n}: {\n type: BoundaryType | null | undefined;\n className?: string;\n}) {\n if (type == null || type === \"\") return null;\n return h(\n Tag,\n {\n variant: \"minimal\",\n className: classNames(\"surface-tag\", \"surface-type-tag\", className),\n },\n type,\n );\n}\n\nexport interface SurfaceStatusLegendProps {\n statuses?: SurfaceStatus[];\n showDescriptions?: boolean;\n className?: string;\n}\n\n/** A legend of surface line styles, one entry per boundary status. */\nexport function SurfaceStatusLegend(props: SurfaceStatusLegendProps) {\n const {\n statuses = surfaceStatuses,\n showDescriptions = false,\n className,\n } = props;\n return h(\n \"ul.surface-status-legend\",\n {\n className: classNames(className, {\n \"with-descriptions\": showDescriptions,\n }),\n },\n statuses.map((status) => {\n let description: ReactNode = null;\n if (showDescriptions) {\n description = h(\n \"div.legend-description\",\n surfaceStatusDescriptions[status],\n );\n }\n return h(\n \"li.legend-item\",\n { key: status, className: surfaceClasses({ status }) },\n [\n h(\"div.surface-label-marker\"),\n h(\"div.legend-text\", [\n h(\"div.legend-label\", surfaceStatusLabels[status]),\n description,\n ]),\n ],\n );\n }),\n );\n}\n"],"names":["hyper","surfaceStyles","styles","Button","DataField","Identifier","ReferencesField","classNames","surfaceClasses","AgeLabel","useMemo","useMacrostratDefs","IntervalTag","Proportion","useColumnUnitsMap","UnitIdentifier","surfaceStatusLabels","surfaceStatusDescriptions","Tag","surfaceStatuses"],"mappings":"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"}