@harmonia-core/ui 1.2.3 → 1.2.4

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.
@@ -1,4 +1,5 @@
1
- import { createContext, useState, useRef, useEffect, useCallback, useContext } from 'react';
1
+ "use client";
2
+ import { createContext, useState, useRef, useEffect, useMemo, useCallback, useContext } from 'react';
2
3
  import { jsx } from 'react/jsx-runtime';
3
4
 
4
5
  var __defProp = Object.defineProperty;
@@ -41,6 +42,53 @@ var __async = (__this, __arguments, generator) => {
41
42
  });
42
43
  };
43
44
 
45
+ // lib/capacity/validation.ts
46
+ function detectConflicts(field) {
47
+ var _a;
48
+ const conflicts = [];
49
+ const arousal = (_a = field.arousal) != null ? _a : 0.5;
50
+ if (field.emotional < 0.15 && arousal > 0.65) {
51
+ conflicts.push({
52
+ id: "dead-pace",
53
+ severity: "info",
54
+ label: "Pace has no effect",
55
+ message: "Arousal is high (pace: activated) but emotional capacity has disabled all animations. The pace multiplier runs on nothing.",
56
+ affectedTokens: ["motion", "pace"],
57
+ suggestion: "Lower arousal below 0.65, or raise emotional capacity above 0.15 to let pace take effect."
58
+ });
59
+ }
60
+ if (arousal > 0.7 && field.emotional < 0.3 && !conflicts.find((c) => c.id === "dead-pace")) {
61
+ conflicts.push({
62
+ id: "anxiety-pattern",
63
+ severity: "warning",
64
+ label: "Anxiety pattern detected",
65
+ message: "High arousal with low emotional capacity signals an overwhelm/anxiety state. The UI is protective (slow or static motion) but internal pace is fast \u2014 these work against each other.",
66
+ affectedTokens: ["motion", "pace"],
67
+ suggestion: "Lower arousal to match emotional capacity, or raise emotional capacity if the high energy is intentional."
68
+ });
69
+ }
70
+ if (field.cognitive > 0.75 && field.temporal < 0.2) {
71
+ conflicts.push({
72
+ id: "density-choice-inversion",
73
+ severity: "info",
74
+ label: "Dense content, minimal choices",
75
+ message: "High cognitive capacity requests full information density, but low temporal capacity minimises available choices. Content will be rich but most actions will be hidden.",
76
+ affectedTokens: ["density", "choiceLoad", "guidance"]
77
+ });
78
+ }
79
+ if (field.valence > 0.5 && field.emotional < 0.15) {
80
+ conflicts.push({
81
+ id: "mute-expressiveness",
82
+ severity: "info",
83
+ label: "Positive tone, no motion",
84
+ message: "Emotional valence is strongly positive, but emotional capacity has disabled all animations. The expressive tone cannot be conveyed through motion.",
85
+ affectedTokens: ["motion", "contrast"],
86
+ suggestion: "Raise emotional capacity above 0.15 to allow at least soothing motion."
87
+ });
88
+ }
89
+ return conflicts;
90
+ }
91
+
44
92
  // lib/capacity/constants.ts
45
93
  var PHI = 1.618033988749895;
46
94
  var PHI_INVERSE = 0.618033988749895;
@@ -883,6 +931,29 @@ function CapacityProvider({ children }) {
883
931
  }
884
932
  };
885
933
  }, [isAutoMode]);
934
+ const conflicts = useMemo(() => {
935
+ const field = {
936
+ cognitive: context.userCapacity.cognitive,
937
+ temporal: context.userCapacity.temporal,
938
+ emotional: context.userCapacity.emotional,
939
+ valence: context.emotionalState.valence,
940
+ arousal: context.emotionalState.arousal
941
+ };
942
+ const detected = detectConflicts(field);
943
+ if (process.env.NODE_ENV !== "production" && detected.length > 0) {
944
+ detected.forEach(
945
+ (c) => console.warn(`[CapacityProvider] ${c.severity.toUpperCase()} \u2014 ${c.label}: ${c.message}`)
946
+ );
947
+ }
948
+ return detected;
949
+ }, [context.userCapacity, context.emotionalState]);
950
+ useEffect(() => {
951
+ var _a;
952
+ if (typeof document === "undefined") return;
953
+ const arousal = (_a = context.emotionalState.arousal) != null ? _a : 0.5;
954
+ const multiplier = arousal < 0.35 ? 1.5 : arousal > 0.65 ? 0.65 : 1;
955
+ document.documentElement.style.setProperty("--capacity-pace-multiplier", String(multiplier));
956
+ }, [context.emotionalState.arousal]);
886
957
  const updateCapacity = useCallback((capacity) => {
887
958
  if (isAutoMode) {
888
959
  setIsAutoMode(false);
@@ -918,7 +989,8 @@ function CapacityProvider({ children }) {
918
989
  hapticEnabled,
919
990
  sonicEnabled,
920
991
  setHapticEnabled,
921
- setSonicEnabled
992
+ setSonicEnabled,
993
+ conflicts
922
994
  }, children });
923
995
  }
924
996
  function useCapacityContext() {
@@ -941,12 +1013,13 @@ function useEmotionalValenceField() {
941
1013
  return context.emotionalValence;
942
1014
  }
943
1015
  function useFieldControls() {
944
- const { updateCapacity, updateEmotionalState, isAutoMode, toggleAutoMode, updateCapacityField } = useCapacityContext();
945
- return { updateCapacity, updateEmotionalState, isAutoMode, toggleAutoMode, updateCapacityField };
1016
+ const { updateCapacity, updateEmotionalState, isAutoMode, toggleAutoMode, updateCapacityField, conflicts } = useCapacityContext();
1017
+ return { updateCapacity, updateEmotionalState, isAutoMode, toggleAutoMode, updateCapacityField, conflicts };
946
1018
  }
947
1019
  function usePrefersReducedMotion() {
948
1020
  const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);
949
1021
  useEffect(() => {
1022
+ if (typeof window === "undefined") return;
950
1023
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
951
1024
  setPrefersReducedMotion(mediaQuery.matches);
952
1025
  const handleChange = (event) => {
@@ -1262,6 +1335,6 @@ var SIGNAL_TYPES = {
1262
1335
  A11Y_FOCUS_TRAP: "a11y:focus:trap"
1263
1336
  };
1264
1337
 
1265
- export { CapacityProvider, DEFAULT_COMPONENT_RESPONSE, FEEDBACK_FREQUENCIES, FIBONACCI, FieldManager, HAPTIC_PATTERNS, MOTION_TOKENS, PHI, PHI_INVERSE, SIGNAL_TYPES, SPACING_SCALE, SignalBus, ambientClass, deriveMode, deriveModeLabel, entranceClass, focusBeaconClass, focusTextClass, getFluidFontSize, getFontSize, getFontWeight, getFrequencyForPace, getLetterSpacing, getLineHeight, getModeBadgeColor, getProportionalSpacing, getSpacing, getTypographyStyles, hoverClass, listItemClass, modularScale, phiRatio, playPacedSonic, playSonicFeedback, triggerHaptic, useAttentionField, useCapacityContext, useDerivedMode, useEffectiveMotion, useEmotionalValenceField, useEnergyField, useFeedback, useFieldControls, usePacedMotionTokens, usePrefersReducedMotion };
1338
+ export { CapacityProvider, DEFAULT_COMPONENT_RESPONSE, FEEDBACK_FREQUENCIES, FIBONACCI, FieldManager, HAPTIC_PATTERNS, MOTION_TOKENS, PHI, PHI_INVERSE, SIGNAL_TYPES, SPACING_SCALE, SignalBus, ambientClass, deriveMode, deriveModeLabel, detectConflicts, entranceClass, focusBeaconClass, focusTextClass, getFluidFontSize, getFontSize, getFontWeight, getFrequencyForPace, getLetterSpacing, getLineHeight, getModeBadgeColor, getProportionalSpacing, getSpacing, getTypographyStyles, hoverClass, listItemClass, modularScale, phiRatio, playPacedSonic, playSonicFeedback, triggerHaptic, useAttentionField, useCapacityContext, useDerivedMode, useEffectiveMotion, useEmotionalValenceField, useEnergyField, useFeedback, useFieldControls, usePacedMotionTokens, usePrefersReducedMotion };
1266
1339
  //# sourceMappingURL=index.mjs.map
1267
1340
  //# sourceMappingURL=index.mjs.map