@glossarist/concept-browser 0.7.85 → 0.7.86

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.
@@ -26,6 +26,7 @@ import { useI18n } from '../i18n';
26
26
 
27
27
  const { t, locale } = useI18n();
28
28
  import type { Concept, Manifest, GraphEdge, PartitiveRelationWire } from '../adapters/types';
29
+ import { rakeStrokeStyle, type PartitiveMultiplicity } from '../utils/partitive-multiplicity';
29
30
  import { conceptUri } from '../adapters/model-bridge';
30
31
 
31
32
  const props = defineProps<{
@@ -760,41 +761,33 @@ function drawEdges(cx: number, cy: number) {
760
761
  }
761
762
 
762
763
  /**
763
- * Render PartitiveRelations as ISO 704 right-angle rake brackets.
764
+ * Render PartitiveRelations as ISO 704:2022 rake brackets in the sphere.
764
765
  *
765
- * Each relation renders as a true bracket with 90° angles:
766
+ * Each relation renders as a right-angle bracket with stem + spine + drops
767
+ * (geometry described in detail above). Stem and spine are the structural
768
+ * frame — always single solid at FRAME_STROKE_WIDTH.
766
769
  *
767
- * [comprehensive]
768
- * │
769
- * │ ← stem (along stem-axis)
770
- * │
771
- * ┌──────────●──────────┐ ← spine (perpendicular to stem-axis; right angle at junction)
772
- * │ │ │
773
- * │ │ │ ← drops (parallel to stem-axis; right angle at each tooth)
774
- * [p1] [p2] [p3]
770
+ * Per-member multiplicity + is_delimiting is encoded on each DROP via
771
+ * rakeStrokeStyle() (see utils/partitive-multiplicity.ts):
775
772
  *
776
- * Geometry:
777
- * 1. stem-axis = direction from comprehensive to centroid of partitives
778
- * 2. spine-axis = perpendicular to stem-axis
779
- * 3. spine-center = point along stem-axis at SPINE_FRACTION (60%) from comp
780
- * 4. For each partitive Pi:
781
- * - Project Pi onto spine-axis → tooth position
782
- * - Drop goes from tooth straight to Pi (parallel to stem-axis by construction)
773
+ * multiplicity is_delimiting drop visual
774
+ * ------------------- -------------- --------------------------------
775
+ * compulsory false 1 solid @ 1.5px
776
+ * compulsory true 1 solid @ 4.5px (3× bold)
777
+ * optional false 1 dashed @ 1.5px
778
+ * optional true 1 dashed @ 4.5px
779
+ * compulsory_multiple false 2 solid @ 1.5px
780
+ * compulsory_multiple true 2 solid @ 4.5px
781
+ * optional_multiple false 2 dashed @ 1.5px
782
+ * optional_multiple true 2 dashed @ 4.5px
783
+ * compulsory_at_least_one false 1 solid + 1 dashed @ 1.5px
784
+ * compulsory_at_least_one true 1 solid + 1 dashed @ 4.5px
783
785
  *
784
- * All bends are exactly 90° because tooth_i is the foot of perpendicular
785
- * from Pi to the spine line.
786
- *
787
- * ISO 704 line conventions:
788
- * - default : single solid line per segment
789
- * - plurality.isShared && !isUncertain : TWO parallel solid lines (close-set)
790
- * - plurality.isShared && isUncertain : one solid + one dashed line
791
- * - completeness === 'partial' : spine extends past last tooth
792
- * (continued backline — "more exist")
793
- *
794
- * Per-member certainty 'possible' → that drop is dashed + reduced opacity
795
- * (stem and spine keep relation style).
786
+ * completeness === 'partial' : spine extends past last tooth (continued
787
+ * backline — "more exist but not shown")
796
788
  *
797
789
  * Diamond marker at the comprehensive end signals the hyperedge origin.
790
+ * Junction marker at the spine midpoint signals the right-angle corner.
798
791
  */
799
792
  function drawRakeBundles(
800
793
  svg: SVGSVGElement,
@@ -806,6 +799,7 @@ function drawRakeBundles(
806
799
  const color = uiStore.isDark ? '#2dd4bf' : '#0d9488';
807
800
  const DOUBLE_GAP = 4;
808
801
  const DASH = '4 3';
802
+ const FRAME_STROKE_WIDTH = 1.4;
809
803
  const SPINE_FRACTION = 0.55; // spine sits 55% from comp toward centroid
810
804
  const PARTIAL_TAIL = 28; // px extension for completeness: 'partial'
811
805
 
@@ -824,7 +818,7 @@ function drawRakeBundles(
824
818
  const p = pos.get(nid);
825
819
  return p ? { member, pos: p } : null;
826
820
  })
827
- .filter((x): x is { member: { uri: string; certainty: 'confirmed' | 'possible' }; pos: {x: number; y: number} } => x !== null);
821
+ .filter((x): x is { member: { uri: string; multiplicity: PartitiveMultiplicity; isDelimiting: boolean }; pos: {x: number; y: number} } => x !== null);
828
822
 
829
823
  if (memberPositions.length === 0) continue;
830
824
 
@@ -850,7 +844,14 @@ function drawRakeBundles(
850
844
  const along = vx * spineDirX + vy * spineDirY;
851
845
  const toothX = spineCx + spineDirX * along;
852
846
  const toothY = spineCy + spineDirY * along;
853
- return { member, partitivePos: pPos, toothX, toothY, along };
847
+ return {
848
+ member,
849
+ partitivePos: pPos,
850
+ toothX,
851
+ toothY,
852
+ along,
853
+ style: rakeStrokeStyle(member.multiplicity, member.isDelimiting),
854
+ };
854
855
  });
855
856
 
856
857
  // 4. Spine extents (leftmost to rightmost tooth along spine-axis)
@@ -867,23 +868,22 @@ function drawRakeBundles(
867
868
  const spineEndX = spineCx + spineDirX * maxAlong;
868
869
  const spineEndY = spineCy + spineDirY * maxAlong;
869
870
 
870
- const isShared = !!rel.plurality?.isShared;
871
- const isUncertain = !!rel.plurality?.isUncertain;
872
-
873
871
  /**
874
- * Draw a single straight segment with optional parallel offset
875
- * (used to render the close-set double line) and dash style.
872
+ * Draw a single straight segment.
873
+ *
874
+ * Stem + spine use FRAME_STROKE_WIDTH (single solid frame).
875
+ * Drops use the per-member multiplicity + delimiting style from
876
+ * rakeStrokeStyle().
876
877
  */
877
878
  const drawSegment = (
878
879
  ax: number, ay: number, bx: number, by: number,
879
- opts: { offset?: number; dashed?: boolean; opacity?: number } = {},
880
+ opts: { width: number; dashed?: boolean; offset?: number; opacity?: number },
880
881
  ) => {
882
+ const opacity = opts.opacity ?? 0.85;
881
883
  const offset = opts.offset ?? 0;
882
884
  const dashed = opts.dashed ?? false;
883
- const opacity = opts.opacity ?? 0.85;
884
885
  const dx = bx - ax, dy = by - ay;
885
886
  const len = Math.hypot(dx, dy) || 1;
886
- // Perpendicular to THIS segment (not the spine-axis) for parallel offset
887
887
  const px = -dy / len, py = dx / len;
888
888
  const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
889
889
  line.setAttribute('class', 'rake-seg');
@@ -892,50 +892,35 @@ function drawRakeBundles(
892
892
  line.setAttribute('x2', String(bx + px * offset));
893
893
  line.setAttribute('y2', String(by + py * offset));
894
894
  line.setAttribute('stroke', color);
895
- line.setAttribute('stroke-width', '1.6');
895
+ line.setAttribute('stroke-width', String(opts.width));
896
896
  line.setAttribute('opacity', String(opacity));
897
- line.setAttribute('stroke-linecap', 'square'); // sharp corners at right angles
897
+ line.setAttribute('stroke-linecap', 'square');
898
898
  if (dashed) line.setAttribute('stroke-dasharray', DASH);
899
899
  svg.appendChild(line);
900
900
  };
901
901
 
902
- /**
903
- * Draw a segment with the relation's plurality style.
904
- * Single solid (default), double solid (isShared),
905
- * or solid + dashed (isShared + isUncertain).
906
- */
907
- const drawSegmentWithPlurality = (
908
- ax: number, ay: number, bx: number, by: number,
909
- opts: { opacity?: number; perMemberPossible?: boolean } = {},
910
- ) => {
911
- const opacity = opts.opacity ?? 0.85;
912
- if (!isShared) {
913
- drawSegment(ax, ay, bx, by, { opacity, dashed: opts.perMemberPossible });
914
- } else {
915
- drawSegment(ax, ay, bx, by, { offset: -DOUBLE_GAP / 2, opacity });
916
- drawSegment(ax, ay, bx, by, {
917
- offset: DOUBLE_GAP / 2,
918
- opacity,
919
- dashed: isUncertain || opts.perMemberPossible,
920
- });
921
- }
922
- };
923
-
924
- // 5. Stem: comp → spine center (along stem-axis)
925
- drawSegmentWithPlurality(compPos.x, compPos.y, spineCx, spineCy);
902
+ // 5. Stem: comp → spine center (frame — single solid)
903
+ drawSegment(compPos.x, compPos.y, spineCx, spineCy, { width: FRAME_STROKE_WIDTH });
926
904
 
927
- // 6. Spine: leftmost tooth → rightmost tooth (along spine-axis)
928
- // (skip if only one tooth — no horizontal extent)
905
+ // 6. Spine: leftmost tooth → rightmost tooth (frame — single solid)
929
906
  if (Math.abs(maxAlong - minAlong) > 1) {
930
- drawSegmentWithPlurality(spineStartX, spineStartY, spineEndX, spineEndY);
907
+ drawSegment(spineStartX, spineStartY, spineEndX, spineEndY, { width: FRAME_STROKE_WIDTH });
931
908
  }
932
909
 
933
- // 7. Drops: tooth → partitive (parallel to stem-axis by construction)
910
+ // 7. Drops: tooth → partitive (per-member multiplicity + delimiting)
911
+ // Draw 1 or 2 parallel lines per the style.
934
912
  for (const tooth of teeth) {
935
- drawSegmentWithPlurality(tooth.toothX, tooth.toothY, tooth.partitivePos.x, tooth.partitivePos.y, {
936
- opacity: tooth.member.certainty === 'possible' ? 0.5 : 0.85,
937
- perMemberPossible: tooth.member.certainty === 'possible',
913
+ drawSegment(tooth.toothX, tooth.toothY, tooth.partitivePos.x, tooth.partitivePos.y, {
914
+ width: tooth.style.strokeWidth,
915
+ dashed: tooth.style.primaryDashed,
938
916
  });
917
+ if (tooth.style.lineCount === 2) {
918
+ drawSegment(tooth.toothX, tooth.toothY, tooth.partitivePos.x, tooth.partitivePos.y, {
919
+ width: tooth.style.strokeWidth,
920
+ dashed: tooth.style.secondaryDashed,
921
+ offset: DOUBLE_GAP,
922
+ });
923
+ }
939
924
  }
940
925
 
941
926
  // 8. Junction marker at spine center (the right-angle corner)
@@ -1,19 +1,18 @@
1
1
  import { computed, type ComputedRef } from 'vue';
2
2
  import type { Router } from 'vue-router';
3
+ // glossarist 0.4.24's top-level d.ts is incomplete for v3 model fields
4
+ // (multiplicity + is_delimiting). Import the v3-augmented types from
5
+ // glossarist/models (extended by src/adapters/non-verbal/glossarist-augment.d.ts).
6
+ import type { Concept, RelatedConcept, ConceptRef } from 'glossarist';
3
7
  import type {
4
- Concept,
5
- RelatedConcept,
6
8
  PartitiveRelation as GlsPartitiveRelation,
7
9
  PartitiveMember as GlsPartitiveMember,
8
- TypeSharedPlurality as GlsTypeSharedPlurality,
9
- ConceptRef,
10
- } from 'glossarist';
10
+ } from 'glossarist/models';
11
11
  import type {
12
12
  Manifest,
13
13
  GraphEdge,
14
14
  PartitiveRelationWire,
15
15
  PartitiveMemberWire,
16
- TypeSharedPluralityWire,
17
16
  } from '../adapters/types';
18
17
  import { getFactory } from '../adapters/factory';
19
18
  import { conceptUri } from '../adapters/model-bridge';
@@ -24,6 +23,7 @@ import { categorizeRelationship, relationshipLabel, INVERSE_RELATIONSHIPS } from
24
23
  import { langLabel } from '../utils/lang';
25
24
  import { escapeAttr } from '../utils/escape';
26
25
  import { useI18n } from '../i18n';
26
+ import type { PartitiveMultiplicity } from '../utils/partitive-multiplicity';
27
27
 
28
28
  export interface EdgeDisplay {
29
29
  uri: string;
@@ -190,7 +190,11 @@ export function useConceptEdges(
190
190
  .map((m: GlsPartitiveMember): PartitiveMemberWire | null => {
191
191
  const uri = resolveConceptRefUri(m.ref);
192
192
  if (!uri || uri === source) return null;
193
- return { uri, certainty: m.certainty };
193
+ return {
194
+ uri,
195
+ multiplicity: readMultiplicity(m),
196
+ isDelimiting: readIsDelimiting(m),
197
+ };
194
198
  })
195
199
  .filter((m: PartitiveMemberWire | null): m is PartitiveMemberWire => m !== null);
196
200
  if (partitives.length === 0) return null;
@@ -200,7 +204,6 @@ export function useConceptEdges(
200
204
  comprehensive,
201
205
  partitives,
202
206
  completeness: rel.completeness,
203
- plurality: projectPlurality(rel.plurality),
204
207
  criterion: rel.criterion ?? undefined,
205
208
  register: registerId.value,
206
209
  };
@@ -208,24 +211,21 @@ export function useConceptEdges(
208
211
  .filter((r: PartitiveRelationWire | null): r is PartitiveRelationWire => r !== null);
209
212
  });
210
213
 
211
- function projectPlurality(p: GlsTypeSharedPlurality | null): TypeSharedPluralityWire | null {
212
- if (!p) return null;
213
- const sharedTypeRef: ConceptRef | null = p.sharedType;
214
- const sharedType = sharedTypeRef
215
- ? [sharedTypeRef.source, sharedTypeRef.id].filter(Boolean).join(':') || null
216
- : null;
217
- return {
218
- isShared: p.isShared,
219
- isUncertain: p.isUncertain,
220
- sharedType,
221
- };
222
- }
223
-
224
214
  function resolveConceptRefUri(ref: ConceptRef | null): string | null {
225
215
  if (!ref) return null;
226
216
  return resolveRefUri({ source: ref.source ?? null, id: ref.id ?? null });
227
217
  }
228
218
 
219
+ // glossarist 0.4.24 carries multiplicity + is_delimiting natively on
220
+ // PartitiveMember. Read them directly — no migration adapter needed.
221
+ function readMultiplicity(m: GlsPartitiveMember): PartitiveMultiplicity {
222
+ return m.multiplicity;
223
+ }
224
+
225
+ function readIsDelimiting(m: GlsPartitiveMember): boolean {
226
+ return m.is_delimiting;
227
+ }
228
+
229
229
  function resolveRefUri(ref: { source: string | null; id: string | null } | null): string | null {
230
230
  const target = resolveRelatedRef(ref);
231
231
  if (!target) return null;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * ISO 704:2022 §5.5.4.2 — partitive multiplicity + delimiting model.
3
+ *
4
+ * Multiplicity (5 values) encodes part-count semantics:
5
+ * - compulsory : exactly one, required
6
+ * - optional : zero or one
7
+ * - compulsory_multiple : two or more, required
8
+ * - optional_multiple : zero or more
9
+ * - compulsory_at_least_one : one or more (required, count unknown)
10
+ *
11
+ * Delimiting (boolean) is orthogonal — a delimiting part behaves like a
12
+ * delimiting characteristic in generic relations: it distinguishes the
13
+ * comprehensive concept from coordinate concepts. Visual encoding:
14
+ * 3× stroke width (4.5 px vs 1.5 px).
15
+ *
16
+ * Adding a new multiplicity value = add one entry to PARTITIVE_MULTIPLICITY.
17
+ * Renderers consume RakeStrokeStyle via rakeStrokeStyle(); never inspect
18
+ * the raw multiplicity string. OCP + MECE + DRY.
19
+ */
20
+
21
+ export const PARTITIVE_MULTIPLICITY = {
22
+ compulsory: { lines: 1, pattern: 'solid', label: 'Compulsory' },
23
+ optional: { lines: 1, pattern: 'dashed', label: 'Optional' },
24
+ compulsory_multiple: { lines: 2, pattern: 'solid', label: 'Compulsory multiple' },
25
+ optional_multiple: { lines: 2, pattern: 'dashed', label: 'Optional multiple' },
26
+ compulsory_at_least_one: { lines: 2, pattern: 'mixed', label: 'At least one' },
27
+ } as const;
28
+
29
+ export type PartitiveMultiplicity = keyof typeof PARTITIVE_MULTIPLICITY;
30
+
31
+ export const PARTITIVE_MULTIPLICITY_VALUES: readonly PartitiveMultiplicity[] =
32
+ Object.keys(PARTITIVE_MULTIPLICITY) as PartitiveMultiplicity[];
33
+
34
+ export function isPartitiveMultiplicity(value: unknown): value is PartitiveMultiplicity {
35
+ return typeof value === 'string' && value in PARTITIVE_MULTIPLICITY;
36
+ }
37
+
38
+ export type LinePattern = 'solid' | 'dashed' | 'mixed';
39
+
40
+ export interface MultiplicityDefinition {
41
+ /** Number of parallel lines used to render the multiplicity. */
42
+ readonly lines: 1 | 2;
43
+ /** Dash pattern: solid, dashed, or mixed (one solid + one dashed). */
44
+ readonly pattern: LinePattern;
45
+ /** Human-readable label for legends and badges. */
46
+ readonly label: string;
47
+ }
48
+
49
+ export function multiplicityDefinition(m: PartitiveMultiplicity): MultiplicityDefinition {
50
+ return PARTITIVE_MULTIPLICITY[m];
51
+ }
52
+
53
+ // ── RakeStrokeStyle — the render-ready form consumed by all renderers ────
54
+
55
+ export interface RakeStrokeStyle {
56
+ /** 1 or 2 parallel lines. */
57
+ readonly lineCount: 1 | 2;
58
+ /** Primary (always-present) line dash. */
59
+ readonly primaryDashed: boolean;
60
+ /** Secondary line dash (only meaningful when lineCount === 2). */
61
+ readonly secondaryDashed: boolean;
62
+ /** Stroke width in px. 1.5 normal, 4.5 (3×) when is_delimiting. */
63
+ readonly strokeWidth: number;
64
+ }
65
+
66
+ export const NORMAL_STROKE_WIDTH = 1.5;
67
+ export const DELIMITING_STROKE_WIDTH = 4.5; // 3× normal per ISO 704
68
+
69
+ /**
70
+ * Compute the render-ready stroke style for a partitive member.
71
+ *
72
+ * Pure function — same inputs always yield the same RakeStrokeStyle.
73
+ * Consumed by both the sidebar rake diagram (PartitiveRelationDiagram)
74
+ * and the sphere rake bundles (RelationSphere.drawRakeBundles).
75
+ */
76
+ export function rakeStrokeStyle(
77
+ multiplicity: PartitiveMultiplicity,
78
+ isDelimiting: boolean,
79
+ ): RakeStrokeStyle {
80
+ const def = PARTITIVE_MULTIPLICITY[multiplicity];
81
+ return {
82
+ lineCount: def.lines,
83
+ primaryDashed: def.pattern === 'dashed',
84
+ secondaryDashed: def.pattern === 'dashed' || def.pattern === 'mixed',
85
+ strokeWidth: isDelimiting ? DELIMITING_STROKE_WIDTH : NORMAL_STROKE_WIDTH,
86
+ };
87
+ }
88
+
89
+ // ── Migration from glossarist 0.4.20 certainty → ISO 704 multiplicity ────
90
+
91
+ /**
92
+ * glossarist 0.4.20 carries per-member `certainty: 'confirmed' | 'possible'`
93
+ * (a v0.4 abstraction that conflated "this member exists" with "we're sure
94
+ * about it"). ISO 704:2022 replaces that with the multiplicity enum.
95
+ *
96
+ * Until glossarist publishes native multiplicity support, this helper maps
97
+ * the legacy field to the closest ISO 704 multiplicity:
98
+ * - confirmed → compulsory
99
+ * - possible → optional
100
+ *
101
+ * Once glossarist publishes multiplicity natively, the bridge can read
102
+ * it directly and this helper can be deleted.
103
+ */
104
+ export function multiplicityFromCertainty(certainty: 'confirmed' | 'possible' | null | undefined): PartitiveMultiplicity {
105
+ return certainty === 'possible' ? 'optional' : 'compulsory';
106
+ }
@@ -1,23 +1,28 @@
1
1
  /**
2
- * Partitive relation styling — colors for one-to-many decompositions.
2
+ * Partitive relation styling — colors and labels for one-to-many
3
+ * partitive decompositions.
3
4
  *
4
5
  * Independent of relationship-categories.ts (which handles binary edges).
5
- * Partitive relations have their own visual language:
6
- * - completeness (complete/partial) affects opacity
7
- * - plurality (type-shared, uncertain) adds accent badges
6
+ * The visual encoding for PartitiveRelation comes from two orthogonal
7
+ * axes per ISO 704:2022:
8
8
  *
9
- * v2 redesign: replaces v1 hyperedge-styling.ts per
10
- * concept-model/TODO.partitive-relation-v2.
9
+ * 1. completeness (complete / partial) — relation-level metadata,
10
+ * affects overall opacity. Partial relations have a continued
11
+ * backline ("more exist but aren't shown").
12
+ * 2. multiplicity + is_delimiting (per-member) — see
13
+ * partitive-multiplicity.ts for the registry + rakeStrokeStyle().
14
+ *
15
+ * This module owns:
16
+ * - relation-level color/badge (completeness-driven)
17
+ * - human-readable labels for badges
18
+ *
19
+ * It does NOT encode multiplicity visuals — those live in
20
+ * partitive-multiplicity.ts (separated so renderers can consume the
21
+ * pure rakeStrokeStyle() helper without pulling badge strings).
11
22
  */
12
23
 
13
- import type { TypeSharedPluralityWire } from '../adapters/types';
14
-
15
24
  const BASE_LIGHT = '#0d9488';
16
25
  const BASE_DARK = '#2dd4bf';
17
- const ACCENT_SHARED_LIGHT = '#3b82f6';
18
- const ACCENT_SHARED_DARK = '#60a5fa';
19
- const ACCENT_UNCERTAIN_LIGHT = '#f59e0b';
20
- const ACCENT_UNCERTAIN_DARK = '#fbbf24';
21
26
 
22
27
  export interface PartitiveRelationStyle {
23
28
  color: string;
@@ -25,38 +30,24 @@ export interface PartitiveRelationStyle {
25
30
  opacity: number;
26
31
  }
27
32
 
33
+ /**
34
+ * Relation-level style (color + opacity) driven by completeness.
35
+ *
36
+ * Per-member multiplicity + delimiting rendering is via
37
+ * `rakeStrokeStyle()` from partitive-multiplicity.ts, not here —
38
+ * this helper is for the relation's overall frame + header badges.
39
+ */
28
40
  export function partitiveRelationStyle(
29
41
  completeness: 'complete' | 'partial',
30
- plurality: TypeSharedPluralityWire | null,
31
42
  isDark: boolean,
32
43
  ): PartitiveRelationStyle {
33
- const base = isDark ? BASE_DARK : BASE_LIGHT;
34
- const opacity = completeness === 'partial' ? 0.6 : 1.0;
35
-
36
- let badgeClass = 'badge-teal';
37
- if (plurality?.isShared) {
38
- badgeClass = 'badge-blue';
39
- if (plurality.isUncertain) {
40
- badgeClass = 'badge-yellow';
41
- }
42
- }
43
-
44
- return { color: base, badgeClass, opacity };
45
- }
46
-
47
- export function pluralityColor(
48
- plurality: TypeSharedPluralityWire,
49
- isDark: boolean,
50
- ): string {
51
- if (plurality.isUncertain) return isDark ? ACCENT_UNCERTAIN_DARK : ACCENT_UNCERTAIN_LIGHT;
52
- if (plurality.isShared) return isDark ? ACCENT_SHARED_DARK : ACCENT_SHARED_LIGHT;
53
- return isDark ? BASE_DARK : BASE_LIGHT;
44
+ return {
45
+ color: isDark ? BASE_DARK : BASE_LIGHT,
46
+ badgeClass: 'badge-teal',
47
+ opacity: completeness === 'partial' ? 0.6 : 1.0,
48
+ };
54
49
  }
55
50
 
56
51
  export function completenessLabel(completeness: 'complete' | 'partial'): string {
57
52
  return completeness === 'partial' ? 'Partial' : 'Complete';
58
53
  }
59
-
60
- export function certaintyLabel(certainty: 'confirmed' | 'possible'): string {
61
- return certainty === 'possible' ? 'Possible' : 'Confirmed';
62
- }
@@ -5,6 +5,8 @@ import { useVocabularyStore } from '../stores/vocabulary';
5
5
  import { conceptUri } from '../adapters/model-bridge';
6
6
  import { UriRouter } from '../adapters/UriRouter';
7
7
  import type { PartitiveRelationWire, PartitiveMemberWire } from '../adapters/types';
8
+ import type { PartitiveMember } from 'glossarist/models';
9
+ import type { PartitiveMultiplicity } from '../utils/partitive-multiplicity';
8
10
  import ConceptDetail from '../components/ConceptDetail.vue';
9
11
  import RelationSphere from '../components/RelationSphere.vue';
10
12
  import ShortcutsModal from '../components/ShortcutsModal.vue';
@@ -80,15 +82,14 @@ const partitiveRelationsForSphere = computed<PartitiveRelationWire[]>(() => {
80
82
  : null;
81
83
  if (!compRef.id || !compTarget) continue;
82
84
  const partitives: PartitiveMemberWire[] = rel.partitives
83
- .map(member => {
85
+ .map((member): PartitiveMemberWire | null => {
84
86
  const ref = member.ref;
85
87
  if (!ref?.id) return null;
86
- const targetRegister = store.manifests.has(activeRegisterId.value)
87
- ? activeRegisterId.value
88
- : activeRegisterId.value;
89
- const uri = UriRouter.buildConceptUri(m.uriBase, targetRegister, ref.id);
88
+ const uri = UriRouter.buildConceptUri(m.uriBase, activeRegisterId.value, ref.id);
90
89
  if (uri === sourceUri) return null;
91
- return { uri, certainty: member.certainty };
90
+ const multiplicity: PartitiveMultiplicity = member.multiplicity;
91
+ const isDelimiting = member.isDelimiting;
92
+ return { uri, multiplicity, isDelimiting };
92
93
  })
93
94
  .filter((x): x is PartitiveMemberWire => x !== null);
94
95
  if (partitives.length === 0) continue;
@@ -97,13 +98,6 @@ const partitiveRelationsForSphere = computed<PartitiveRelationWire[]>(() => {
97
98
  comprehensive: compTarget,
98
99
  partitives,
99
100
  completeness: rel.completeness,
100
- plurality: rel.plurality
101
- ? {
102
- isShared: rel.plurality.isShared,
103
- isUncertain: rel.plurality.isUncertain,
104
- sharedType: null,
105
- }
106
- : null,
107
101
  register: activeRegisterId.value,
108
102
  });
109
103
  }